Browse Source

initial commit

pull/1/head
Illya Byelkin 3 years ago
commit
9f3868ffbe

+ 117
- 0
pom.xml View File

@@ -0,0 +1,117 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project xmlns="http://maven.apache.org/POM/4.0.0"
3
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5
+    <modelVersion>4.0.0</modelVersion>
6
+
7
+    <groupId>org.mariadb</groupId>
8
+    <artifactId>dynamicColumn</artifactId>
9
+    <version>0.1-SNAPSHOT</version>
10
+
11
+    <properties>
12
+        <checkstyleVersion>6.13</checkstyleVersion>
13
+        <checkstyle.plugin.version>2.17</checkstyle.plugin.version>
14
+    </properties>
15
+
16
+
17
+    <licenses>
18
+        <license>
19
+            <name>LGPL-2.1</name>
20
+        </license>
21
+    </licenses>
22
+
23
+
24
+    <developers>
25
+        <developer>
26
+            <id>ilya</id>
27
+            <name>ilya byelkin</name>
28
+            <email>xxx@xxx.com</email>
29
+        </developer>
30
+    </developers>
31
+
32
+
33
+    <build>
34
+        <plugins>
35
+             <!-- checkstyle validate that code respect some standard -->
36
+            <plugin>
37
+                <groupId>org.apache.maven.plugins</groupId>
38
+                <artifactId>maven-checkstyle-plugin</artifactId>
39
+                <version>${checkstyle.plugin.version}</version>
40
+                <dependencies>
41
+                    <dependency>
42
+                        <groupId>com.puppycrawl.tools</groupId>
43
+                        <artifactId>checkstyle</artifactId>
44
+                        <version>${checkstyleVersion}</version>
45
+                    </dependency>
46
+                </dependencies>
47
+                <executions>
48
+                    <execution>
49
+                        <id>process-test-resources</id>
50
+                        <phase>prepare-package</phase>
51
+                        <configuration>
52
+                            <includeTestSourceDirectory>true</includeTestSourceDirectory>
53
+                            <configLocation>src/test/resources/style.xml</configLocation>
54
+                            <encoding>UTF-8</encoding>
55
+                            <consoleOutput>true</consoleOutput>
56
+                            <failsOnError>true</failsOnError>
57
+                        </configuration>
58
+                        <goals>
59
+                            <goal>check</goal>
60
+                        </goals>
61
+                    </execution>
62
+                </executions>
63
+            </plugin>
64
+
65
+            <!--plugin compiler : permit to tell java source level to developp and target compile version-->
66
+            <plugin>
67
+                <groupId>org.apache.maven.plugins</groupId>
68
+                <artifactId>maven-compiler-plugin</artifactId>
69
+                <version>3.3</version>
70
+                <configuration>
71
+                    <source>1.7</source>
72
+                    <target>1.7</target>
73
+                </configuration>
74
+            </plugin>
75
+            <!---->
76
+            <!--<plugin>-->
77
+                <!--<groupId>org.apache.maven.plugins</groupId>-->
78
+                <!--<artifactId>maven-source-plugin</artifactId>-->
79
+                <!--<version>2.4</version>-->
80
+                <!--<executions>-->
81
+                    <!--<execution>-->
82
+                        <!--<goals>-->
83
+                            <!--<goal>jar</goal>-->
84
+                        <!--</goals>-->
85
+                    <!--</execution>-->
86
+                <!--</executions>-->
87
+            <!--</plugin>-->
88
+
89
+            <!--Generate javadoc -->
90
+            <plugin>
91
+                <groupId>org.apache.maven.plugins</groupId>
92
+                <artifactId>maven-javadoc-plugin</artifactId>
93
+                <version>2.10.3</version>
94
+                <executions>
95
+                    <execution>
96
+                        <id>attach-javadocs</id>
97
+                        <phase>prepare-package</phase>
98
+                        <goals>
99
+                            <goal>jar</goal>
100
+                        </goals>
101
+                    </execution>
102
+                </executions>
103
+            </plugin>
104
+
105
+        </plugins>
106
+    </build>
107
+
108
+    <dependencies>
109
+        <dependency>
110
+            <groupId>junit</groupId>
111
+            <artifactId>junit</artifactId>
112
+            <version>4.12</version>
113
+            <scope>test</scope>
114
+        </dependency>
115
+    </dependencies>
116
+
117
+</project>

+ 641
- 0
src/org/mariadb/dyncol/DynCol.java View File

@@ -0,0 +1,641 @@
1
+package org.mariadb.dyncol;
2
+
3
+import java.util.HashMap;
4
+import java.util.Map;
5
+import java.util.Map.Entry;
6
+
7
+import org.mariadb.dyncol.blob.Blob;
8
+import org.mariadb.dyncol.data.DynamicType;
9
+import org.mariadb.dyncol.data.Member;
10
+import org.mariadb.dyncol.util.Util;
11
+
12
+import java.io.UnsupportedEncodingException;
13
+import java.sql.SQLException;
14
+
15
+/*
16
+ MariaDB Dynamic column java plugin
17
+ Copyright (c) 2016 MariaDB.
18
+ ...
19
+ ...
20
+ */
21
+public class DynCol {
22
+
23
+    public DynamicType recordTypes;
24
+    Map<String, Member> data = new HashMap<String, Member>();
25
+    boolean strType = false; // true - Columns with names, false - Numeric format
26
+    int errorIndex = 0;
27
+    Blob blb = new Blob();
28
+    public Util utils = new Util(blb, strType, data);
29
+
30
+    /**
31
+     * Add the member to the DynCol.
32
+     * 
33
+     * @param name
34
+     *            Name of member
35
+     * @param value
36
+     *            Value of member
37
+     */
38
+    public void setInt(String name, long value) {
39
+        data.put(name, new Member());
40
+        if (!strType) {
41
+            utils.strType = strType = utils.getStrType(name);
42
+        }
43
+        Member mem = data.get(name);
44
+        mem.recordType = DynamicType.INT;
45
+        mem.setInt(value);
46
+    }
47
+
48
+    /**
49
+     * Add the member to the DynCol.
50
+     * 
51
+     * @param name
52
+     *            Name of member
53
+     * @param value
54
+     *            Value of member
55
+     * @throws Exception illegal argument
56
+     */
57
+    public void setUint(String name, long value) throws Exception {
58
+        if (!strType) {
59
+            utils.strType = strType = utils.getStrType(name);
60
+        }
61
+        if (value < 0) {
62
+            throw new Exception("value " + value + " is illegal");
63
+        } else {
64
+            data.put(name, new Member());
65
+            Member mem = data.get(name);
66
+            mem.recordType = DynamicType.UINT;
67
+            mem.setUint(value);
68
+        }
69
+    }
70
+
71
+    /**
72
+     * Add the member to the DynCol.
73
+     * 
74
+     * @param name
75
+     *            Name of member
76
+     * @param value
77
+     *            Value of member
78
+     */
79
+    public void setString(String name, String value) {
80
+        if (value == null) {
81
+            if (data.containsKey(name)) {
82
+                data.remove(name);
83
+            }
84
+        } else {
85
+            if (!strType) {
86
+                utils.strType = strType = utils.getStrType(name);
87
+            }
88
+            data.put(name, new Member());
89
+            Member mem = data.get(name);
90
+            mem.recordType = DynamicType.STRING;
91
+            mem.setString(value);
92
+        }
93
+    }
94
+
95
+    /**
96
+     * Add the member to the DynCol.
97
+     * 
98
+     * @param name
99
+     *            Name of member
100
+     * @param value
101
+     *            Value of member
102
+     */
103
+    public void setDouble(String name, double value) {
104
+        if (!strType) {
105
+            utils.strType = strType = utils.getStrType(name);
106
+        }
107
+        data.put(name, new Member());
108
+        Member mem = data.get(name);
109
+        mem.recordType = DynamicType.DOUBLE;
110
+        mem.setDouble(value);
111
+    }
112
+
113
+    /**
114
+     * Add the member to the DynCol.
115
+     * 
116
+     * @param name
117
+     *            Name of member
118
+     * @param value
119
+     *            Value of member
120
+     * @throws Exception
121
+     *             Dynamic type is unknown and UnsupportedEncodingException
122
+     */
123
+    public void setDynCol(String name, DynCol value) throws Exception {
124
+        if (value == null) {
125
+            if (data.containsKey(name)) {
126
+                data.remove(name);
127
+            }
128
+        } else {
129
+            DynCol tempd = new DynCol();
130
+            tempd.setBlob(value.getBlob());
131
+            utils.strType = strType = true;
132
+            data.put(name, new Member());
133
+            Member mem = data.get(name);
134
+            mem.recordType = DynamicType.DYNCOL;
135
+            mem.setDynCol(tempd);
136
+        }
137
+    }
138
+
139
+    /**
140
+     * Delete the member from DynCol.
141
+     * 
142
+     * @param name
143
+     *            name of the member
144
+     */
145
+    public void remove(String name) {
146
+        data.remove(name);
147
+    }
148
+
149
+    /**
150
+     * Conversion a type of the member.
151
+     * 
152
+     * @param name
153
+     *            name of the member
154
+     * @return value
155
+     * @throws SQLException Parameter unknown and Invalid parameter type
156
+     * @throws NumberFormatException if something wrong with a number format
157
+     * @throws UnsupportedEncodingException if encoding is wrong
158
+     */
159
+    public long getInt(String name) throws SQLException, NumberFormatException, UnsupportedEncodingException {
160
+        Member mem = data.get(name);
161
+        if (mem == null) {
162
+            throw new SQLException("Parameter '" + name + "' unknown", "07002");
163
+        }
164
+        switch (mem.recordType) {
165
+            case INT:
166
+                return mem.getInt();
167
+            case UINT:
168
+                return mem.getUint();
169
+            case DOUBLE:
170
+                return (long) mem.getDouble();
171
+            case STRING:
172
+                return Long.parseLong(mem.getString());
173
+            default:
174
+                throw new SQLException("Invalid parameter type : asking fpr getInt on a " + mem.recordType + " type", "HY105");
175
+        }
176
+    }
177
+
178
+    /**
179
+     * Conversion a type of the member.
180
+     * 
181
+     * @param name
182
+     *            name of the member
183
+     * @return value
184
+     * @throws SQLException Parameter unknown and Invalid parameter type
185
+     * @throws NumberFormatException if something wrong with a number format
186
+     * @throws UnsupportedEncodingException if encoding is wrong
187
+     */
188
+    public long getUint(String name) throws SQLException, NumberFormatException, UnsupportedEncodingException {
189
+        Member mem = data.get(name);
190
+        if (mem == null) {
191
+            throw new SQLException("Parameter '" + name + "' unknown", "07002");
192
+        }
193
+        switch (mem.recordType) {
194
+            case INT:
195
+                return mem.getInt();
196
+            case UINT:
197
+                return mem.getUint();
198
+            case DOUBLE:
199
+                return (long) mem.getDouble();
200
+            case STRING:
201
+                return Long.parseLong(mem.getString());
202
+            default:
203
+                throw new SQLException("Invalid parameter type : asking fpr getUint on a " + mem.recordType + " type", "HY105");
204
+        }
205
+    }
206
+
207
+    /**
208
+     * Conversion a type of the member.
209
+     * 
210
+     * @param name
211
+     *            name of the member
212
+     * @return value
213
+     * @throws SQLException Parameter unknown and Invalid parameter type
214
+     * @throws NumberFormatException if something wrong with a number format
215
+     * @throws UnsupportedEncodingException if encoding is wrong
216
+     */
217
+    public String getString(String name) throws SQLException, UnsupportedEncodingException {
218
+        Member mem = data.get(name);
219
+        if (mem == null) {
220
+            throw new SQLException("Parameter '" + name + "' unknown", "07002");
221
+        }
222
+        switch (mem.recordType) {
223
+            case INT:
224
+                return "" + mem.getInt();
225
+            case UINT:
226
+                return "" + mem.getUint();
227
+            case DOUBLE:
228
+                return "" + mem.getDouble();
229
+            case STRING:
230
+                return mem.getString();
231
+            default:
232
+                throw new SQLException("Invalid parameter type : asking fpr getString on a " + mem.recordType + " type", "HY105");
233
+        }
234
+    }
235
+
236
+    /**
237
+     * Conversion a type of the member.
238
+     * 
239
+     * @param name
240
+     *            name of the member
241
+     * @return value
242
+     * @throws SQLException Parameter unknown and Invalid parameter type
243
+     * @throws NumberFormatException if something wrong with a number format
244
+     * @throws UnsupportedEncodingException if encoding is wrong
245
+     */
246
+    public double getDouble(String name) throws SQLException, NumberFormatException, UnsupportedEncodingException {
247
+        Member mem = data.get(name);
248
+        if (mem == null) {
249
+            throw new SQLException("Parameter '" + name + "' unknown", "07002");
250
+        }
251
+        switch (mem.recordType) {
252
+            case INT:
253
+                return (double) mem.getInt();
254
+            case UINT:
255
+                return (double) mem.getUint();
256
+            case DOUBLE:
257
+                return mem.getDouble();
258
+            case STRING:
259
+                return Long.parseLong(mem.getString());
260
+            default:
261
+                throw new SQLException("Invalid parameter type : asking fpr getDouble on a " + mem.recordType + " type", "HY105");
262
+        }
263
+    }
264
+
265
+    /**
266
+     * Conversion a type of the member.
267
+     * 
268
+     * @param name
269
+     *            name of the member
270
+     * @return value
271
+     * @throws Exception Dynamic type is unknown and UnsupportedEncodingException
272
+     */
273
+    public DynCol getDynCol(String name) throws Exception {
274
+        Member mem = data.get(name);
275
+        if (mem == null) {
276
+            throw new SQLException("Parameter '" + name + "' unknown", "07002");
277
+        }
278
+        switch (mem.recordType) {
279
+            case DYNCOL:
280
+                return mem.getDynCol();
281
+            default:
282
+                throw new SQLException("Invalid parameter type : asking fpr getDouble on a " + mem.recordType + " type", "HY105");
283
+        }
284
+    }
285
+
286
+    /**
287
+     * 
288
+     * @param name.
289
+     *            name of the member
290
+     * @return type of the member
291
+     */
292
+    public DynamicType getRecodFormat(String name) {
293
+        Member mem = data.get(name);
294
+        return mem.recordType;
295
+    }
296
+
297
+    /**
298
+     * Clear the old DynCol (if it was) and save Json string in DynamicColumn format.
299
+     * 
300
+     * @param sstr
301
+     *            Json string
302
+     * @throws Exception Dynamic type is unknown and UnsupportedEncodingException
303
+     */
304
+    public void setJson(String sstr) throws Exception {
305
+        if (sstr == null) {
306
+            throw new NullPointerException();
307
+        }
308
+        data.clear();
309
+        if (!utils.parseJson(sstr, data)) {
310
+            data.clear();
311
+            throw new SQLException("syntax error", "22000");
312
+        } else {
313
+            utils.strType = strType = utils.strType;
314
+        }
315
+    }
316
+
317
+    /**
318
+     * Save Json string in DynamicColumn format.
319
+     * 
320
+     * @throws Exception Dynamic type is unknown and UnsupportedEncodingException
321
+     */
322
+    public void addJson(String sstr) throws Exception {
323
+        if (sstr == null) {
324
+            throw new SQLException("no data", "02000");
325
+        }
326
+        Map<String, Member> data = new HashMap<String, Member>();
327
+        if (!utils.parseJson(sstr, data)) {
328
+            data.clear();
329
+            throw new SQLException("syntax error", "22000");
330
+        } else {
331
+            utils.strType = strType = utils.strType;
332
+            this.data.putAll(data);
333
+        }
334
+    }
335
+
336
+    /**
337
+     * Convert DynamycColumn format to Json string.
338
+     * 
339
+     * @return Json string
340
+     * @throws Exception Dynamic type is unknown and UnsupportedEncodingException
341
+     */
342
+    public String getJson() throws Exception {
343
+        String result = "{";
344
+        if (data.size() == 0) {
345
+            result = "{}";
346
+            return result;
347
+        }
348
+        boolean isFirst = true;
349
+        for (Entry<String, Member> entry : data.entrySet()) {
350
+            if (!isFirst) {
351
+                result += ',';
352
+            } else {
353
+                isFirst = false;
354
+            }
355
+            result += "\"" + entry.getKey() + "\":";
356
+            switch (entry.getValue().recordType) {
357
+                case NULL:
358
+                    result += "null";
359
+                    break;
360
+                case INT:
361
+                    result += entry.getValue().getInt();
362
+                    break;
363
+                case UINT:
364
+                    result += entry.getValue().getUint();
365
+                    break;
366
+                case DOUBLE:
367
+                    result += entry.getValue().getDouble();
368
+                    break;
369
+                case STRING:
370
+                    result += "\"" + entry.getValue().getString() + "\"";
371
+                    break;
372
+                case DATETIME:
373
+                case DATE:
374
+                case TIME:
375
+                    result += "\"" + entry.getValue().getString() + "\"";
376
+                    break;
377
+                case DYNCOL:
378
+                    result += entry.getValue().getDynCol().getJson();
379
+                    break;
380
+                default:
381
+                    throw new Exception("Dynamic type " + entry.getValue().recordType + " is unknown.");
382
+            }
383
+        }
384
+        result += '}';
385
+        return result;
386
+    }
387
+
388
+    /**
389
+     * save the DynCol.
390
+     * 
391
+     * @param blob
392
+     *            DynamicColums
393
+     * @throws Exception Dynamic type is unknown and UnsupportedEncodingException
394
+     */
395
+    public void setBlob(byte[] blob) throws Exception {
396
+        if (blob == null) {
397
+            throw new NullPointerException();
398
+        } else if (blob.length == 3 || blob.length == 5) {
399
+            data.clear();
400
+        } else {
401
+            errorIndex = 0;
402
+            data.clear();
403
+            blb = new Blob();
404
+            blb.blobSize = blob.length;
405
+            // if 2nd bit is 1, then type of string is named
406
+            if (((blob[0] & 4) >>> 2) == 1) {
407
+                utils.strType = strType = true;
408
+            } else {
409
+                utils.strType = strType = false;
410
+            }
411
+            utils = new Util(blb, strType, data);
412
+            // read the offset size from first 2 bits
413
+            blb.offsetSize = (blob[0] & 3) + (strType ? 2 : 1);
414
+            int columnCount = data.size();
415
+            // read the column count from 1st and 2nd bytes
416
+            columnCount = ((blob[2] & 0xFF) << 8) | (blob[1] & 0xFF);
417
+            // calculating offset of all the header
418
+            blb.headerOffset = (strType ? 5 : 3) + columnCount * (2 + blb.offsetSize);
419
+            if (strType) {
420
+                // read name pool size from bytes #3 and 4
421
+                blb.nmpoolSize = ((blob[4] & 0xFF) << 8) | (blob[3] & 0xFF);
422
+                String name;
423
+                Member rc = new Member();
424
+                int realOffset = 5;
425
+                int nextOffsetName = 0;
426
+                int realOffsetName = 0;
427
+                int nextOffsetValue = 0;
428
+                // read offset of the name, from beginning of name pool
429
+                realOffsetName = (blob[realOffset] & 0xFF) | ((blob[realOffset + 1] & 0xFF) << 8);
430
+                realOffset += 2;
431
+                // read the record type
432
+                rc.recordType = DynamicType.get((blob[realOffset] & 15) + 1);
433
+                int realOffsetValue = 0;
434
+                // read offset of the value, from beginning of the data pool
435
+                realOffsetValue = (blob[realOffset] & 0xFF) >>> 4;
436
+                realOffset++;
437
+                if (blb.offsetSize > 1) {
438
+                    realOffsetValue = realOffsetValue | ((blob[realOffset] & 0xFF) << 4);
439
+                    realOffset++;
440
+                }
441
+                for (int index = 2; index < blb.offsetSize; index++) {
442
+                    realOffsetValue = realOffsetValue | (blob[realOffset] & 0xFF) << (4 + 8 * (index - 1));
443
+                    realOffset++;
444
+                }
445
+                for (int i = 0; i < columnCount; i++) {
446
+                    // the next record type
447
+                    int recordType = 0;
448
+                    // if it isn't the last column
449
+                    if (i != columnCount - 1) {
450
+                        // reading the next name offset
451
+                        nextOffsetName = (blob[realOffset] & 0xFF) | ((blob[realOffset + 1] & 0xFF) << 8);
452
+                        realOffset += 2;
453
+                        // reading the next record type
454
+                        recordType = (blob[realOffset] & 15) + 1;
455
+                        // reading the next value offset
456
+                        nextOffsetValue = (blob[realOffset] & 0xFF) >>> 4;
457
+                        realOffset++;
458
+                        if (blb.offsetSize > 1) {
459
+                            nextOffsetValue = nextOffsetValue | (blob[realOffset] & 0xFF) << (4);
460
+                            realOffset++;
461
+                        }
462
+                        for (int index = 2; index < blb.offsetSize; index++) {
463
+                            nextOffsetValue = nextOffsetValue | (blob[realOffset] & 0xFF) << (4 + 8 * (index - 1));
464
+                            realOffset++;
465
+                        }
466
+                    } else {
467
+                        nextOffsetName = blb.nmpoolSize;
468
+                        nextOffsetValue = blb.blobSize - blb.headerOffset - blb.nmpoolSize;
469
+                    }
470
+                    // calculating the name size
471
+                    int byteLong = nextOffsetName - realOffsetName;
472
+                    // read the name
473
+                    byte[] arrayByte = new byte[byteLong];
474
+                    for (int index = 0; index < byteLong; index++) {
475
+                        arrayByte[index] = blob[blb.headerOffset + realOffsetName + index];
476
+                    }
477
+                    name = new String(arrayByte, "UTF-8");
478
+                    realOffsetName = nextOffsetName;
479
+                    // read the values
480
+                    utils.saveValue(blob, rc, realOffsetValue, nextOffsetValue - realOffsetValue);
481
+                    data.put(name, rc);
482
+                    realOffsetValue = nextOffsetValue;
483
+                    rc = new Member();
484
+                    rc.recordType = DynamicType.get(recordType);
485
+                }
486
+            } else {
487
+                String name;
488
+                String nextName;
489
+                Member rc = new Member();
490
+                int realOffset = 3;
491
+                int nextOffsetValue = 0;
492
+                
493
+                // read the name
494
+                name = "" + ((blob[realOffset] & 0xFF) | ((blob[realOffset + 1] & 0xFF) << 8));
495
+                realOffset += 2;
496
+                // read the record type
497
+                rc.recordType = DynamicType.get((blob[realOffset] & 7) + 1);
498
+                int realOffsetValue = 0;
499
+                // read offset of the value, from beginning of the data pool
500
+                realOffsetValue = (blob[realOffset] & 0xFF) >>> 3;
501
+                realOffset++;
502
+                if (blb.offsetSize > 1) {
503
+                    realOffsetValue = realOffsetValue | ((blob[realOffset] & 0xFF) << 3);
504
+                    realOffset++;
505
+                }
506
+                for (int index = 2; index < blb.offsetSize; index++) {
507
+                    realOffsetValue = realOffsetValue | (blob[realOffset] & 0xFF) << (3 + 8 * (index - 1));
508
+                    realOffset++;
509
+                }
510
+                for (int i = 0; i < columnCount; i++) {
511
+                    // the next record type
512
+                    int recordType = 0;
513
+                    // if it isn't the last column
514
+                    if (i != columnCount - 1) {
515
+                        nextName = "" + ((blob[realOffset] & 0xFF) | ((blob[realOffset + 1] & 0xFF) << 8));
516
+                        realOffset += 2;
517
+                        // reading the next record type
518
+                        recordType = (blob[realOffset] & 7) + 1;
519
+                        // reading the next value offset
520
+                        nextOffsetValue = (blob[realOffset] & 0xFF) >>> 3;
521
+                        realOffset++;
522
+                        if (blb.offsetSize > 1) {
523
+                            nextOffsetValue = nextOffsetValue | (blob[realOffset] & 0xFF) << (3);
524
+                            realOffset++;
525
+                        }
526
+                        for (int index = 2; index < blb.offsetSize; index++) {
527
+                            nextOffsetValue = nextOffsetValue | (blob[realOffset] & 0xFF) << (3 + 8 * (index - 1));
528
+                            realOffset++;
529
+                        }
530
+                    } else {
531
+                        nextName = null;
532
+                        nextOffsetValue = blb.blobSize - blb.headerOffset;
533
+                    }
534
+                    // read the values
535
+                    utils.saveValue(blob, rc, realOffsetValue, nextOffsetValue - realOffsetValue);
536
+                    data.put(name, rc);
537
+                    name = nextName;
538
+                    realOffsetValue = nextOffsetValue;
539
+                    rc = new Member();
540
+                    rc.recordType = DynamicType.get(recordType);
541
+                }
542
+            }
543
+        }
544
+    }
545
+
546
+    /**
547
+     * Create the Blob.
548
+     * 
549
+     * @return the DynCol
550
+     * @throws SQLException SQLException Unsupported data length
551
+     */
552
+    public byte[] getBlob() throws SQLException {
553
+        byte[] blob;
554
+        int columnCount = data.size();
555
+        if (columnCount == 0) {
556
+            blob = new byte[3];
557
+            return blob;
558
+        }
559
+        int blbSize = utils.getBlobLength();
560
+        blob = new byte[(blb.blobSize = blbSize)];
561
+        // put the flags
562
+        blob[0] = (byte) (((blb.offsetSize - (strType ? 2 : 1)) & 3) | (strType ? 4 : 0));
563
+        // put column count
564
+        blob[1] = (byte) (columnCount & 0xFF);
565
+        blob[2] = (byte) ((columnCount >>> 8) & 0xFF);
566
+        // offset of
567
+        /*
568
+         * offset is offset of header entry header entry is column number or string pointer + offset & type
569
+         */
570
+        int offset = 0;
571
+        // offset from beginning of the data pool
572
+        int dataOffset = 0;
573
+        if (strType) {
574
+            String[] keyarray = new String[columnCount];
575
+            // put the length of name pool
576
+            blob[3] = (byte) (blb.nmpoolSize & 0xFF);
577
+            blob[4] = (byte) ((blb.nmpoolSize >>> 8) & 0xFF);
578
+            int inex = 0;
579
+            for (String key : data.keySet()) {
580
+                keyarray[inex] = key;
581
+                inex++;
582
+            }
583
+            // sort the names
584
+            utils.quSort(keyarray, 0, columnCount - 1);
585
+            offset = 5;// flag byte + number of columns 2 bytes + name pool length 2 bytes = 5 bytes
586
+            // offset from beginning of the name pool
587
+            int nameOffset = 0;
588
+            for (inex = 0; inex < columnCount; inex++) {
589
+                // put offset of the name
590
+                blob[offset] = (byte) (nameOffset & 0xFF);
591
+                blob[offset + 1] = (byte) ((nameOffset >>> 8) & 0xFF);
592
+                offset += 2;
593
+                Member rec = data.get("" + keyarray[inex]);
594
+                // put offset of the data + 4 byte data type
595
+                blob[offset] = (byte) ((rec.recordType.ordinal() - 1) | ((dataOffset & 15) << 4));
596
+                int tdataOffset = dataOffset >>> 4;
597
+                for (int j = 1; j < blb.offsetSize; j++) {
598
+                    blob[offset + j] = (byte) ((tdataOffset & 0xFF));
599
+                    tdataOffset = dataOffset >>> 8;
600
+                }
601
+                offset += blb.offsetSize;
602
+                // put the name
603
+                byte[] name = keyarray[inex].getBytes();
604
+                for (int ind = 0; ind < name.length; ind++) {
605
+                    blob[blb.headerOffset + nameOffset + ind] = name[ind];
606
+                }
607
+                nameOffset += name.length;
608
+                // put the data
609
+                dataOffset += utils.putValue(blob, rec, blb.headerOffset + blb.nmpoolSize + dataOffset);
610
+            }
611
+        } else {
612
+            int[] keyarray = new int[columnCount];
613
+            int index = 0;
614
+            for (String key : data.keySet()) {
615
+                keyarray[index] = Integer.parseInt(key);
616
+                index++;
617
+            }
618
+            // sort the names
619
+            utils.quSort(keyarray, 0, columnCount - 1);
620
+            offset = 3;// flag byte + number of columns 2 bytes = 3 bytes
621
+            for (index = 0; index < columnCount; index++) {
622
+                // put the name
623
+                blob[offset] = (byte) (keyarray[index] & 0xFF);
624
+                blob[offset + 1] = (byte) ((keyarray[index] >>> 8) & 0xFF);
625
+                offset += 2;
626
+                Member rec = data.get("" + keyarray[index]);
627
+                // put offset of the data + 3 byte data type
628
+                blob[offset] = (byte) ((rec.recordType.ordinal() - 1) | ((dataOffset & 31) << 3));
629
+                int tdataOffset = dataOffset >>> 5;
630
+                for (int j = 1; j < blb.offsetSize; j++) {
631
+                    blob[offset + j] = (byte) ((tdataOffset & 0xFF));
632
+                    tdataOffset = dataOffset >>> 8;
633
+                }
634
+                offset += blb.offsetSize;
635
+                // put the data
636
+                dataOffset += utils.putValue(blob, rec, blb.headerOffset + dataOffset);
637
+            }
638
+        }
639
+        return blob;
640
+    }
641
+}

+ 15
- 0
src/org/mariadb/dyncol/blob/Blob.java View File

@@ -0,0 +1,15 @@
1
+package org.mariadb.dyncol.blob;
2
+
3
+/*
4
+ MariaDB Dynamic column java plugin
5
+ Copyright (c) 2016 MariaDB.
6
+ ...
7
+ ...
8
+ */
9
+
10
+public class Blob {
11
+    public int offsetSize;
12
+    public int nmpoolSize = 0;
13
+    public int blobSize = 0;
14
+    public int headerOffset = 0;
15
+}

+ 35
- 0
src/org/mariadb/dyncol/data/DynamicType.java View File

@@ -0,0 +1,35 @@
1
+package org.mariadb.dyncol.data;
2
+
3
+/*
4
+MariaDB Dynamic column java plugin
5
+Copyright (c) 2016 MariaDB.
6
+...
7
+...
8
+ */
9
+public enum DynamicType {
10
+    NULL, INT, UINT, DOUBLE, STRING, DECIMAL, DATETIME, DATE, TIME, DYNCOL;
11
+    
12
+    /**
13
+     * choose the type of member by the index of the type.
14
+     * @param type index of the type
15
+     * @return type of member
16
+     * @throws Exception unknown type
17
+     */
18
+    public static DynamicType get(int type) throws Exception {
19
+        switch (type) {
20
+            case 0 : return NULL;
21
+            case 1 : return INT;
22
+            case 2 : return UINT;
23
+            case 3 : return DOUBLE;
24
+            case 4 : return STRING;
25
+            case 5 : return DECIMAL;
26
+            case 6 : return DATETIME;
27
+            case 7 : return DATE;
28
+            case 8 : return TIME;
29
+            case 9:
30
+                return DYNCOL;
31
+            default:
32
+                throw new Exception("Dynamic type " + type + " is unknown.");
33
+        }
34
+    }
35
+}

+ 160
- 0
src/org/mariadb/dyncol/data/Member.java View File

@@ -0,0 +1,160 @@
1
+package org.mariadb.dyncol.data;
2
+
3
+import java.io.UnsupportedEncodingException;
4
+import java.util.Arrays;
5
+
6
+import org.mariadb.dyncol.DynCol;
7
+
8
+/*
9
+ MariaDB Dynamic column java plugin.
10
+ Copyright (c) 2016 MariaDB.
11
+ ...
12
+ ...
13
+ */
14
+public class Member {
15
+    public final static String UTF_8 = "UTF-8";
16
+    public DynamicType recordType;
17
+    public byte[] value;
18
+
19
+    /**
20
+     * Decode the value.
21
+     * 
22
+     * @return decoded value
23
+     */
24
+    public long getUint() {
25
+        long val = 0;
26
+        for (int index = 0; index < value.length; index++) {
27
+            val = val | ((long) (value[index] & 0xFF) << (8 * index));
28
+        }
29
+        return val;
30
+    }
31
+
32
+    /**
33
+     * Decode the value.
34
+     * 
35
+     * @return decoded value
36
+     */
37
+    public long getInt() {
38
+        long val = 0;
39
+        for (int index = 0; index < value.length; index++) {
40
+            val = val | ((long) (value[index] & 0xFF) << (8 * index));
41
+        }
42
+        if ((val & 1) != 0) {
43
+            val = (val >>> 1) ^ (-1);
44
+        } else {
45
+            val >>>= 1;
46
+        }
47
+        return val;
48
+    }
49
+
50
+    /**
51
+     * Decode the value.
52
+     * 
53
+     * @return decoded value
54
+     */
55
+    public double getDouble() {
56
+        return Double.longBitsToDouble(getUint());
57
+    }
58
+
59
+    /**
60
+     * Decode the value.
61
+     * 
62
+     * @return decoded value
63
+     */
64
+    public String getString() throws UnsupportedEncodingException {
65
+        String str = new String(Arrays.copyOfRange(value, 1, value.length), UTF_8);
66
+        return str;
67
+    }
68
+
69
+    /**
70
+     * Decode the value.
71
+     * 
72
+     * @return decoded value
73
+     * @throws Exception
74
+     *             Dynamic type is unknown and UnsupportedEncodingException
75
+     */
76
+    public DynCol getDynCol() throws Exception {
77
+        DynCol val = new DynCol();
78
+        val.setBlob(value);
79
+        return val;
80
+    }
81
+
82
+    /**
83
+     * save value in byte form.
84
+     * 
85
+     * @param val
86
+     *            value that should be saved
87
+     */
88
+    public void setUint(long val) {
89
+        value = new byte[uintBytes(val)];
90
+        for (int i = 0; val != 0; i++) {
91
+            value[i] = (byte) (val & 0xFF);
92
+            val >>>= 8;
93
+        }
94
+    }
95
+
96
+    /**
97
+     * save value in byte form.
98
+     * 
99
+     * @param val
100
+     *            value that should be saved
101
+     */
102
+    public void setInt(long val) {
103
+        val = (val << 1) ^ (val < 0 ? (-1) : 0);
104
+        setUint(val);
105
+    }
106
+
107
+    /**
108
+     * save value in byte form.
109
+     * 
110
+     * @param val
111
+     *            value that should be saved
112
+     */
113
+    public void setDouble(double val) {
114
+        value = new byte[8];
115
+        long longValue = Double.doubleToRawLongBits(val);
116
+        for (int i = 0; longValue != 0; i++) {
117
+            value[i] = (byte) (longValue & 0xFF);
118
+            longValue >>>= 8;
119
+        }
120
+    }
121
+
122
+    /**
123
+     * save value in byte form.
124
+     * 
125
+     * @param val
126
+     *            value that should be saved
127
+     */
128
+    public void setString(String val) {
129
+        value = new byte[val.length() + 1];
130
+        value[0] = 45;// UTF8
131
+        byte[] bytes = val.getBytes();
132
+        for (int i = 0; i < bytes.length; i++) {
133
+            value[1 + i] = bytes[i];
134
+        }
135
+    }
136
+
137
+    /**
138
+     * save value in byte form.
139
+     * 
140
+     * @param val
141
+     *            value that should be saved
142
+     */
143
+    public void setDynCol(DynCol val) throws Exception {
144
+        value = val.getBlob();
145
+    }
146
+
147
+    /**
148
+     * Calculate uint size.
149
+     * 
150
+     * @param val
151
+     *            value
152
+     * @return size of value
153
+     */
154
+    public int uintBytes(long val) {
155
+        int len;
156
+        for (len = 0; val != 0; val >>>= 8, len++) {
157
+        }
158
+        return len;
159
+    }
160
+}

+ 661
- 0
src/org/mariadb/dyncol/util/Util.java View File

@@ -0,0 +1,661 @@
1
+package org.mariadb.dyncol.util;
2
+
3
+import java.io.UnsupportedEncodingException;
4
+import java.sql.SQLException;
5
+import java.util.Map;
6
+
7
+import org.mariadb.dyncol.DynCol;
8
+import org.mariadb.dyncol.blob.Blob;
9
+import org.mariadb.dyncol.data.DynamicType;
10
+import org.mariadb.dyncol.data.Member;
11
+
12
+/*
13
+ MariaDB Dynamic column java plugin
14
+ Copyright (c) 2016 MariaDB.
15
+ ...
16
+ ...
17
+ */
18
+public class Util {
19
+
20
+    public final static String UTF_8 = "UTF-8";
21
+    public final static String EUC_JP = "euc_jp";
22
+    public final static String GB2312 = "gb2312";
23
+    public final static String EUC_KR = "euc_kr";
24
+    public final static String CP850 = "cp850";
25
+    public final static String CP852 = "cp852";
26
+    public final static String CP866 = "cp66";
27
+    public final static String LATIN1 = "latin1";
28
+    public final static String LATIN2 = "latin2";
29
+    public final static String GREEK = "greek";
30
+    public final static String HEBREW = "hebrew";
31
+    public final static String LATIN5 = "latin5";
32
+    public final static String KOI8_R = "koi8_r";
33
+    public final static String KOI8_U = "koi8_u";
34
+    public final static String SJIS = "sjis";
35
+    public final static String TIS620 = "tis620";
36
+    public final static String ASCII = "ASCII";
37
+    public final static String UTF16 = "utf16";
38
+    public final static String ISO_10646_UCS_2 = "ISO-10646-UCS-2";
39
+    public final static String UTF_16LE = "UTF_16LE";
40
+    public final static String UTF32 = "UTF32";
41
+    public final static String CP1250 = "cp1250";
42
+    public final static String CP1251 = "cp1251";
43
+    public final static String CP1256 = "cp1256";
44
+    public final static String CP1257 = "cp1257";
45
+    public final static String MACROMAN = "MacRoman";
46
+    Blob blb;
47
+    public boolean strType;
48
+    Map<String, Member> data;
49
+
50
+    /**
51
+     * Util constructor.
52
+     * 
53
+     * @param blb
54
+     *            information about DynamycColums
55
+     * @param strType
56
+     *            type of this DynamycColums
57
+     * @param data
58
+     *            class with data
59
+     */
60
+    public Util(Blob blb, boolean strType, Map<String, Member> data) {
61
+        this.blb = blb;
62
+        this.strType = strType;
63
+        this.data = data;
64
+    }
65
+
66
+    /**
67
+     * Decide witch type of string would be, if you add this member.
68
+     * 
69
+     * @param name
70
+     *            the name of member
71
+     * @return the type of DynamycColums true - named type, false - numeric
72
+     */
73
+    public boolean getStrType(String name) {
74
+        if (!isNum(name)) {
75
+            return true;
76
+        }
77
+        return false;
78
+    }
79
+
80
+    /**
81
+     * Check the Json, Save Json It use Finite-state machine.
82
+     * 
83
+     * @param sstr
84
+     *            is Json string
85
+     * @param data
86
+     *            is Map where data will store
87
+     * @return true - success false - mistake
88
+     * @throws Exception
89
+     *             Dynamic type is unknown
90
+     */
91
+    public boolean parseJson(String sstr, Map<String, Member> data) throws Exception {
92
+        boolean result = false;
93
+        int testTable[][] = { { 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, -1, -1, 2, -1, -1, 7, -1, -1, -1, -1, -1 },
94
+                { 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2 }, { 3, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1 },
95
+                { 4, 1, 5, 8, -1, -1, -1, -1, -1, 10, 6, -1 }, { 6, -1, 5, -1, -1, -1, 7, 1, -1, -1, -1, 5 },
96
+                { 6, -1, -1, -1, -1, -1, 7, 1, -1, -1, -1, -1 }, { 7, -1, -1, -1, -1, -1, 7, 1, -1, -1, -1, -1 },
97
+                { 8, 8, 11, 9, 8, 8, 8, 8, 8, 8, 8, 8 }, { 9, -1, -1, -1, -1, -1, 7, 1, -1, -1, -1, -1 },
98
+                { -1, -1, 5, -1, -1, -1, 7, 1, -1, -1, -1, -1 }, { 8, 8, 11, 9, 12, 8, 8, 8, 8, 15, 8, 8 }, { 8, 8, 12, 9, 13, 8, 8, 8, 8, 8, 8, 8 },
99
+                { 8, 8, 13, 9, 14, 8, 8, 8, 8, 8, 8, 8 }, { 8, 8, 14, 9, 8, 8, 8, 8, 8, 8, 8, 8 }, { 17, 8, 15, 9, 8, 8, 8, 8, 8, 16, 8, 8 },
100
+                { 17, 8, 16, 9, 8, 8, 8, 8, 8, 8, 8, 8 }, { 8, 8, 11, 9, 8, 8, 8, 8, 8, 8, 8, 8 } };
101
+        char character;
102
+        int abscissa = 0;
103
+        int ordinate = 0;
104
+        boolean nested = false;
105
+        boolean dateTime = false;
106
+        String string = "";
107
+        String name = "";
108
+        int braces = 0;
109
+        for (int i = 0; i < sstr.length(); i++) {
110
+            character = sstr.charAt(i);
111
+            switch (character) {
112
+                case '{':
113
+                    abscissa = 1;
114
+                    break;
115
+                case '"':
116
+                    abscissa = 3;
117
+                    break;
118
+                case ':':
119
+                    abscissa = 4;
120
+                    break;
121
+                case '\\':
122
+                    abscissa = 5;
123
+                    break;
124
+                case '}':
125
+                    abscissa = 6;
126
+                    break;
127
+                case ',':
128
+                    abscissa = 7;
129
+                    break;
130
+                case '-':
131
+                    abscissa = 9;
132
+                    break;
133
+                case '.':
134
+                    abscissa = 11;
135
+                    break;
136
+                case 'n':
137
+                    if (sstr.substring(i, i + 4).equals("null")) {
138
+                        abscissa = 10;
139
+                        i += 3;
140
+                    } else {
141
+                        abscissa = 8;
142
+                    }
143
+                    break;
144
+                default:
145
+                    if (character == ' ' || character == '	') {
146
+                        abscissa = 0;
147
+                    } else if (character >= '0' && character <= '9') {
148
+                        abscissa = 2;
149
+                    } else {
150
+                        abscissa = 8;
151
+                    }
152
+                    break;
153
+            }
154
+            if (testTable[ordinate][abscissa] < 0) {
155
+                return false;
156
+            } /*if nested Json*/ else if (ordinate == 4 && abscissa == 1) {
157
+                nested = true;
158
+                strType = true;
159
+                braces++;
160
+                int coma = sstr.indexOf(",", i);
161
+                if (coma < 0) {
162
+                    coma = sstr.lastIndexOf("}");
163
+                }
164
+                int end = sstr.lastIndexOf('}', coma - 1);
165
+                string = sstr.substring(i, end + 1);
166
+                Member mem = data.get(name);
167
+                mem.recordType = DynamicType.get(9);
168
+                DynCol tempDynCol = new DynCol();
169
+                try {
170
+                    tempDynCol.setJson(string);
171
+                    mem.setDynCol(tempDynCol);
172
+                } catch (Exception e) {
173
+                    e.printStackTrace();
174
+                }
175
+                i = end;
176
+                ordinate = 7;
177
+                abscissa = 6;
178
+            }
179
+            // if string continuing
180
+            if (ordinate == 7) {
181
+                result = false;
182
+            } /*if inside the name characters*/ else if (((ordinate == 2
183
+                    && (abscissa == 0 || abscissa == 1 || abscissa == 4 || abscissa == 5 || abscissa == 6 || abscissa == 7
184
+                    || abscissa == 8 || abscissa == 9 || abscissa == 10 || abscissa == 11)))
185
+                    && (!nested)) {
186
+                strType = true;
187
+            }
188
+            // if inside the string back slash
189
+            if ((ordinate == 2 || ordinate == 8 || ordinate == 11 || ordinate == 12 || ordinate == 13 || ordinate == 14 || ordinate == 15
190
+                    || ordinate == 16 || ordinate == 17)
191
+                    && abscissa == 5) {
192
+                i++;
193
+            }
194
+            // if nested string is ended
195
+            if (abscissa == 6 && (ordinate == 1 || ordinate == 5 || ordinate == 6 || ordinate == 7 || ordinate == 9)) {
196
+                braces--;
197
+                result = true;
198
+                nested = false;
199
+            }
200
+            // if new name starting, clear the name string
201
+            if (ordinate == 1 && abscissa == 3) {
202
+                name = "";
203
+            } /*if inside the string name back slash, write next symbol*/ else if ((ordinate == 2) && abscissa == 5) {
204
+                name = name + sstr.charAt(i);
205
+            } /*if string name ended, save name*/ else if ((ordinate == 2) && abscissa == 3) {
206
+                data.put(name, new Member());
207
+            } else if (ordinate == 2) {
208
+                name = name + character;
209
+            } /*if character is ':' clear value string*/ else if (ordinate == 3 && abscissa == 4) {
210
+                string = "";
211
+            } /*if value string ended save it*/ else if ((ordinate == 8 || ordinate == 11 || ordinate == 17) && abscissa == 3) {
212
+                Member mem = data.get(name);
213
+                mem.recordType = DynamicType.get(4);
214
+                mem.setString(string);
215
+            } else if ((ordinate == 12 || ordinate == 13 || ordinate == 14) && abscissa == 3) {
216
+                Member mem = data.get(name);
217
+                mem.recordType = DynamicType.get((dateTime ? 6 : 8));
218
+                mem.setString(string);
219
+                dateTime = false;
220
+            } else if ((ordinate == 15 || ordinate == 16) && abscissa == 3) {
221
+                Member mem = data.get(name);
222
+                mem.recordType = DynamicType.get(7);
223
+                mem.setString(string);
224
+            } else if (ordinate == 17 && abscissa == 2) {
225
+                dateTime = true;
226
+                string += character;
227
+            } else if (ordinate >= 11 && ordinate <= 17) {
228
+                string += character;
229
+            } /*if inside the value string back slash, write next symbol*/ else if ((ordinate == 8 
230
+                    || ordinate == 11 
231
+                    || ordinate == 12 
232
+                    || ordinate == 13 
233
+                    || ordinate == 14 
234
+                    || ordinate == 15 
235
+                    || ordinate == 16 
236
+                    || ordinate == 17)
237
+                    && abscissa == 5) {
238
+                string = string + sstr.charAt(i);
239
+            } /*Just write value string*/ else if (ordinate == 8) {
240
+                string = string + character;
241
+            } /*if first symbol of value is numeral*/ else if (ordinate == 4 && abscissa == 2) {
242
+                data.get(name).recordType = DynamicType.get(2);
243
+                string += character;
244
+            } /*if first symbol of value is minus*/ else if (ordinate == 4 && abscissa == 9) {
245
+                data.get(name).recordType = DynamicType.get(1);
246
+                string += character;
247
+            } /*if numeral continue*/ else if ((ordinate == 5 || ordinate == 10) && abscissa == 2) {
248
+                string += character;
249
+            } /*if punkt*/ else if (ordinate == 5 && abscissa == 11) {
250
+                data.get(name).recordType = DynamicType.get(3);
251
+                string += character;
252
+            } /*if number is ended, save it*/ else if (ordinate == 5) {
253
+                Member mem = data.get(name);
254
+                // if double
255
+                if (mem.recordType == DynamicType.DOUBLE) {
256
+                    mem.setDouble(Double.parseDouble(string));
257
+                } else if (mem.recordType == DynamicType.INT) {
258
+                    mem.setInt(Long.parseLong(string));
259
+                } else {
260
+                    mem.setUint(Long.parseLong(string));
261
+                }
262
+            } /*if null, delete column*/ else if (ordinate == 4 && abscissa == 10) {
263
+                data.remove(name);
264
+            }
265
+            ordinate = testTable[ordinate][abscissa];
266
+
267
+        }
268
+        // because first '{' was not reading
269
+        braces++;
270
+        if (!result || braces != 0) {
271
+            result = false;
272
+        }
273
+        return result;
274
+    }
275
+
276
+    /**
277
+     * Check is string s a number.
278
+     * 
279
+     * @param sstr
280
+     *            string to test
281
+     * @return true if inside the string is a number false if not
282
+     */
283
+    public boolean isNum(String sstr) {
284
+        if ((sstr.charAt(0) == '-' && sstr.length() > 1) || !(sstr.charAt(0) >= '0' && sstr.charAt(0) <= '9')) {
285
+            return false;
286
+        }
287
+        for (int i = 1; i < sstr.length(); i++) {
288
+            if (!(sstr.charAt(i) >= '0' && sstr.charAt(i) <= '9')) {
289
+                return false;
290
+            }
291
+        }
292
+        return true;
293
+    }
294
+
295
+    /**
296
+     * Calculate size of the blob.
297
+     * 
298
+     * @return length of the blob
299
+     * @throws SQLException Unsupported data length
300
+     */
301
+    public int getBlobLength() throws SQLException {
302
+        int columnCount = data.size();
303
+        int res = 0;
304
+        blb.nmpoolSize = 0;
305
+        for (String key : data.keySet()) {
306
+            Member rec = data.get(key);
307
+            res += rec.value.length;
308
+            if (strType) {
309
+                blb.nmpoolSize += key.getBytes().length;
310
+            }
311
+        }
312
+        blb.offsetSize = offsetBytes(res);
313
+        if (strType) {
314
+            blb.headerOffset = columnCount * (2 /* 2 bytes offset from the name pool */ + blb.offsetSize) + 5; /*length of fixed string header with
315
+             * names 1 byte - flags, 2 bytes - columns
316
+             * counter, 2 bytes - name pool size
317
+             */
318
+        } else {
319
+            blb.headerOffset = columnCount * (2 /* 2 bytes offset from the name pool */ + blb.offsetSize) + 3;
320
+            // length of fixed string header 1 byte -
321
+            // flags, 2 bytes - columns counter
322
+        }
323
+        res += blb.nmpoolSize;
324
+        res += blb.headerOffset;
325
+        return res;
326
+    }
327
+
328
+    /**
329
+     * Calculate size of the offset pool.
330
+     * 
331
+     * @param dataLength
332
+     *            is length of data
333
+     * @return size of the offset pool
334
+     * @throws SQLException Unsupported data length
335
+     */
336
+    public int offsetBytes(int dataLength) throws SQLException {
337
+        if (strType) {
338
+            if (dataLength < 0xfff) /* all 1 value is reserved */ {
339
+                return 2;
340
+            }
341
+            if (dataLength < 0xfffff) /* all 1 value is reserved */ {
342
+                return 3;
343
+            }
344
+            if (dataLength < 0xfffffff) /* all 1 value is reserved */ {
345
+                return 4;
346
+            }
347
+            // without if (dataLength < 0xfffffffff), because of max array index is signed int
348
+            throw new SQLException("Unsupported data length", "22000");
349
+        } else {
350
+            if (dataLength < 0x1f) /* all 1 value is reserved */ {
351
+                return 1;
352
+            }
353
+            if (dataLength < 0x1fff) /* all 1 value is reserved */ {
354
+                return 2;
355
+            }
356
+            if (dataLength < 0x1fffff) /* all 1 value is reserved */ {
357
+                return 3;
358
+            }
359
+            if (dataLength < 0x1fffffff) /* all 1 value is reserved */ {
360
+                return 4;
361
+            }
362
+            throw new SQLException("Unsupported data length", "22000");
363
+        }
364
+    }
365
+
366
+    /**
367
+     * Calculate how many bytes do you need to store this unsignet int.
368
+     * 
369
+     * @param val
370
+     *            is value
371
+     * @return how many bytes do you need to store this unsignet int
372
+     */
373
+    public int uintBytes(long val) {
374
+        int len;
375
+        for (len = 0; val != 0; val >>>= 8, len++) {}
376
+        return len;
377
+    }
378
+
379
+    /**
380
+     * Calculate how many bytes do you need to store this int.
381
+     * 
382
+     * @param val
383
+     *            is value
384
+     * @return how many bytes do you need to store this int
385
+     */
386
+    public int sintBytes(long val) {
387
+        return uintBytes((val << 1) ^ (val < 0 ? (-1) : 0));
388
+    }
389
+
390
+    /**
391
+     * Sort members by the name.
392
+     * 
393
+     * @param array
394
+     *            is array that should be sorting
395
+     * @param low
396
+     *            is index of first element
397
+     * @param high
398
+     *            is index of last element
399
+     */
400
+    public void quSort(int[] array, int low, int high) {
401
+        int iiAxis = low;
402
+        int jjAxis = high;
403
+        int middle = array[(low + high) / 2];
404
+        do {
405
+            while (array[iiAxis] < middle) {
406
+                ++iiAxis;
407
+            }
408
+            while (array[jjAxis] > middle) {
409
+                --jjAxis;
410
+            }
411
+            if (iiAxis <= jjAxis) {
412
+                int tmp = array[iiAxis];
413
+                array[iiAxis] = array[jjAxis];
414
+                array[jjAxis] = tmp;
415
+                iiAxis++;
416
+                jjAxis--;
417
+            }
418
+        } while (iiAxis <= jjAxis);
419
+        if (low < jjAxis) {
420
+            quSort(array, low, jjAxis);
421
+        }
422
+        if (iiAxis < high) {
423
+            quSort(array, iiAxis, high);
424
+        }
425
+    }
426
+
427
+    /**
428
+     * Sort array of strings: first sort by the length, then sort strings with the same length by symbols.
429
+     * 
430
+     * @param array
431
+     *            is array that should be sorting
432
+     * @param low
433
+     *            is index of first element
434
+     * @param high
435
+     *            is index of last element
436
+     */
437
+    public void quSort(String[] array, int low, int high) {
438
+        int iiAxis = low;
439
+        int jjAxis = high;
440
+        String middle = array[(low + high) / 2];
441
+        do {
442
+            while (compareStr(array[iiAxis], middle) < 0) {
443
+                ++iiAxis;
444
+            }
445
+            while (compareStr(array[jjAxis], middle) > 0) {
446
+                --jjAxis;
447
+            }
448
+            if (iiAxis <= jjAxis) {
449
+                String tmp = array[iiAxis];
450
+                array[iiAxis] = array[jjAxis];
451
+                array[jjAxis] = tmp;
452
+                iiAxis++;
453
+                jjAxis--;
454
+            }
455
+        } while (iiAxis <= jjAxis);
456
+        if (low < jjAxis) {
457
+            quSort(array, low, jjAxis);
458
+        }
459
+        if (iiAxis < high) {
460
+            quSort(array, iiAxis, high);
461
+        }
462
+    }
463
+
464
+    /**
465
+     * Compare string.
466
+     * 
467
+     * @param s1
468
+     *            string #1
469
+     * @param s2
470
+     *            string #2
471
+     * @return 0 if strings are the same, < 0 if string #1 is smaller then string #2, > 0 if string #1 is bigger then string #2
472
+     */
473
+    public int compareStr(String s1, String s2) {
474
+        int res = (s1.length() > s2.length() ? 1 : (s1.length() < s2.length() ? -1 : 0));
475
+        if (res == 0) {
476
+            res = s1.compareTo(s2);
477
+        }
478
+        return res;
479
+    }
480
+
481
+    /**
482
+     * Change the encoding of the string to UTF-8.
483
+     * 
484
+     * @param arrayByte
485
+     *            string in old encoding
486
+     * @param encoding
487
+     *            number of encoding
488
+     * @return string in UTF-8 encoding
489
+     * @throws UnsupportedEncodingException
490
+     *             if encoding is wrong
491
+     */
492
+    public String parseStr(byte[] arrayByte, int encoding) throws UnsupportedEncodingException {
493
+        String res;
494
+        String encodingstr;
495
+        switch (encoding) {
496
+            case 33:
497
+            case 223:
498
+            case 83:
499
+            case 254:
500
+            case 45:
501
+            case 46:
502
+                encodingstr = UTF_8;
503
+                break;
504
+            case 97:
505
+            case 98:
506
+                encodingstr = EUC_JP;
507
+                break;
508
+            case 24:
509
+            case 86:
510
+                encodingstr = GB2312;
511
+                break;
512
+            case 19:
513
+            case 85:
514
+                encodingstr = EUC_KR;
515
+                break;
516
+            case 4:
517
+            case 80:
518
+                encodingstr = CP850;
519
+                break;
520
+            case 40:
521
+            case 81:
522
+                encodingstr = CP852;
523
+                break;
524
+            case 36:
525
+            case 68:
526
+                encodingstr = CP866;
527
+                break;
528
+            case 5:
529
+            case 8:
530
+            case 15:
531
+            case 31:
532
+            case 47:
533
+            case 48:
534
+            case 49:
535
+            case 94:
536
+                encodingstr = LATIN1;
537
+                break;
538
+            case 2:
539
+            case 9:
540
+            case 21:
541
+            case 27:
542
+            case 77:
543
+                encodingstr = LATIN2;
544
+                break;
545
+            case 25:
546
+            case 70:
547
+                encodingstr = GREEK;
548
+                break;
549
+            case 16:
550
+            case 71:
551
+                encodingstr = HEBREW;
552
+                break;
553
+            case 30:
554
+            case 78:
555
+                encodingstr = LATIN5;
556
+                break;
557
+            case 7:
558
+            case 74:
559
+                encodingstr = KOI8_R;
560
+                break;
561
+            case 22:
562
+            case 75:
563
+                encodingstr = KOI8_U;
564
+                break;
565
+            case 13:
566
+            case 88:
567
+                encodingstr = SJIS;
568
+                break;
569
+            case 18:
570
+            case 89:
571
+                encodingstr = TIS620;
572
+                break;
573
+            case 11:
574
+            case 65:
575
+                encodingstr = ASCII;
576
+                break;
577
+            case 54:
578
+            case 55:
579
+                encodingstr = UTF16;
580
+                break;
581
+            case 35:
582
+            case 159:
583
+            case 90:
584
+                encodingstr = ISO_10646_UCS_2;
585
+                break;
586
+            case 56:
587
+            case 62:
588
+                encodingstr = UTF_16LE;
589
+                break;
590
+            case 60:
591
+            case 61:
592
+                encodingstr = UTF32;
593
+                break;
594
+            case 26:
595
+            case 34:
596
+            case 44:
597
+            case 66:
598
+            case 99:
599
+                encodingstr = CP1250;
600
+                break;
601
+            case 14:
602
+            case 23:
603
+            case 50:
604
+            case 51:
605
+            case 52:
606
+                encodingstr = CP1251;
607
+                break;
608
+            case 57:
609
+            case 67:
610
+                encodingstr = CP1256;
611
+                break;
612
+            case 29:
613
+            case 58:
614
+            case 59:
615
+                encodingstr = CP1257;
616
+                break;
617
+            case 39:
618
+            case 53:
619
+                encodingstr = MACROMAN;
620
+                break;
621
+            default:
622
+                throw new UnsupportedEncodingException();
623
+        }
624
+        res = new String(arrayByte, encodingstr);
625
+        return res;
626
+    }
627
+
628
+    /**
629
+     * Put the value in the DynCol.
630
+     * @param blob
631
+     *            DynamicColumns
632
+     * @param rc
633
+     *            member
634
+     * @param offset
635
+     *            offset from the start of the array
636
+     * @return how much bytes use this member
637
+     */
638
+    public int putValue(byte[] blob, Member rc, int offset) {
639
+        for (int index = 0; index < rc.value.length; index++) {
640
+            blob[offset + index] = rc.value[index];
641
+        }
642
+        return rc.value.length;
643
+    }
644
+
645
+    /**
646
+     * take the value from the DynCol.
647
+     * @param blob
648
+     *            DynamicColumns
649
+     * @param rc
650
+     *            member
651
+     * @param offsetValue offset of value
652
+     * @param byteLong
653
+     *            how much bytes use this member
654
+     */
655
+    public void saveValue(byte[] blob, Member rc, int offsetValue, int byteLong) {
656
+        rc.value = new byte[byteLong];
657
+        for (int index = 0; index < byteLong; index++) {
658
+            rc.value[index] = blob[blb.headerOffset + blb.nmpoolSize + offsetValue + index];
659
+        }
660
+    }
661
+}

+ 362
- 0
src/test/java/org/mariadb/dyncol/DynColTest.java View File

@@ -0,0 +1,362 @@
1
+package test.java.org.mariadb.dyncol;
2
+
3
+import org.junit.Assert;
4
+import org.junit.Test;
5
+import org.mariadb.dyncol.DynCol;
6
+
7
+import java.sql.SQLException;
8
+import java.io.UnsupportedEncodingException;
9
+
10
+public class DynColTest {
11
+
12
+    @Test
13
+    public void setNullIntTest() throws SQLException, UnsupportedEncodingException {
14
+        DynCol dynCol = new DynCol();
15
+        dynCol.setInt("1", 0);
16
+        Assert.assertEquals(0, dynCol.getInt("1"));
17
+    }
18
+
19
+    @Test
20
+    public void setMinusOneIntTest() throws SQLException, UnsupportedEncodingException {
21
+        DynCol dynCol = new DynCol();
22
+        dynCol.setInt("1", -1);
23
+        Assert.assertEquals(-1, dynCol.getInt("1"));
24
+    }
25
+
26
+    @Test
27
+    public void setOneIntTest() throws SQLException, UnsupportedEncodingException {
28
+        DynCol dynCol = new DynCol();
29
+        dynCol.setInt("1", 1);
30
+        Assert.assertEquals(1, dynCol.getInt("1"));
31
+    }
32
+
33
+    @Test
34
+    public void setMaxValueIntTest() throws SQLException, UnsupportedEncodingException {
35
+        DynCol dynCol = new DynCol();
36
+        dynCol.setInt("1", Long.MAX_VALUE);
37
+        Assert.assertEquals(Long.MAX_VALUE, dynCol.getInt("1"));
38
+    }
39
+
40
+    @Test
41
+    public void setMinValueIntTest() throws SQLException, UnsupportedEncodingException {
42
+        DynCol dynCol = new DynCol();
43
+        dynCol.setInt("1", Long.MIN_VALUE);
44
+        Assert.assertEquals(Long.MIN_VALUE, dynCol.getInt("1"));
45
+    }
46
+
47
+    @Test
48
+    public void setNullUintTest() throws SQLException, Exception {
49
+        DynCol dynCol = new DynCol();
50
+        dynCol.setUint("1", 0);
51
+        Assert.assertEquals(0, dynCol.getUint("1"));
52
+    }
53
+
54
+    @Test (expected = Exception.class)
55
+    public void setMinusOneUintTest() throws SQLException, Exception {
56
+        DynCol dynCol = new DynCol();
57
+        dynCol.setUint("1", -1);
58
+    }
59
+
60
+    @Test
61
+    public void setOneUintTest() throws SQLException, Exception {
62
+        DynCol dynCol = new DynCol();
63
+        dynCol.setUint("1", 1);
64
+        Assert.assertEquals(1, dynCol.getUint("1"));
65
+    }
66
+
67
+    @Test
68
+    public void setMaxValueUintTest() throws SQLException, Exception {
69
+        DynCol dynCol = new DynCol();
70
+        dynCol.setUint("1", Long.MAX_VALUE);
71
+        Assert.assertEquals(Long.MAX_VALUE, dynCol.getUint("1"));
72
+    }
73
+
74
+    @Test
75
+    public void setNullDoubleTest() throws SQLException, UnsupportedEncodingException {
76
+        DynCol dynCol = new DynCol();
77
+        dynCol.setDouble("1", 0.0);
78
+        Assert.assertEquals(0.0, dynCol.getDouble("1"), 0.001);
79
+    }
80
+
81
+    @Test
82
+    public void setIntegerDoubleTest() throws SQLException, UnsupportedEncodingException {
83
+        DynCol dynCol = new DynCol();
84
+        dynCol.setDouble("1", 1212.0);
85
+        Assert.assertEquals(1212.0, dynCol.getDouble("1"), 0.001);
86
+    }
87
+
88
+    @Test
89
+    public void setDoubleTest() throws SQLException, UnsupportedEncodingException {
90
+        DynCol dynCol = new DynCol();
91
+        dynCol.setDouble("1", 12.12);
92
+        Assert.assertEquals(12.12, dynCol.getDouble("1"), 0.001);
93
+    }
94
+
95
+    @Test
96
+    public void setMaxValueDoubleTest() throws SQLException, UnsupportedEncodingException {
97
+        DynCol dynCol = new DynCol();
98
+        dynCol.setDouble("1", Double.MAX_VALUE);
99
+        Assert.assertEquals(Double.MAX_VALUE, dynCol.getDouble("1"), 0.0001);
100
+    }
101
+
102
+    @Test
103
+    public void setMinValueDoubleTest() throws SQLException, UnsupportedEncodingException {
104
+        DynCol dynCol = new DynCol();
105
+        dynCol.setDouble("1", Double.MIN_VALUE);
106
+        Assert.assertEquals(Double.MIN_VALUE, dynCol.getDouble("1"), 0.0001);
107
+    }
108
+    @Test (expected = Exception.class)
109
+    public void setNullTest() throws SQLException, UnsupportedEncodingException {
110
+        DynCol dynCol = new DynCol();
111
+        dynCol.setString("1", null);
112
+        dynCol.getString("1");
113
+    }
114
+    @Test
115
+    public void setAfafStringTest() throws SQLException, UnsupportedEncodingException {
116
+        DynCol dynCol = new DynCol();
117
+        dynCol.setString("1", "afaf");
118
+        Assert.assertEquals("afaf", dynCol.getString("1"));
119
+    }
120
+
121
+    @Test
122
+    public void setNumStringTest() throws SQLException, UnsupportedEncodingException {
123
+        DynCol dynCol = new DynCol();
124
+        dynCol.setString("1", "1212");
125
+        Assert.assertEquals("1212", dynCol.getString("1"));
126
+    }
127
+
128
+    @Test
129
+    public void setJsonTest() throws SQLException, Exception {
130
+        DynCol dynCol = new DynCol();
131
+        dynCol.setJson("{\"1\":1," +
132
+                       "\"2\":-1," +
133
+                       "\"3\":12.12," +
134
+                       "\"4\":\"afaf\"}");
135
+        Assert.assertEquals(1, dynCol.getUint("1"));
136
+        Assert.assertEquals(-1, dynCol.getInt("2"));
137
+        Assert.assertEquals(12.12, dynCol.getDouble("3"), 0.0001);
138
+        Assert.assertEquals("afaf", dynCol.getString("4"));
139
+    }
140
+    @Test
141
+    public void getJsonTest() throws SQLException, Exception {
142
+        DynCol dynCol = new DynCol();
143
+        dynCol.setJson("{\"1\":1," +
144
+                       "\"2\":-1," +
145
+                       "\"3\":12.12," +
146
+                       "\"4\":\"afaf\"}");
147
+        dynCol.setJson(dynCol.getJson());
148
+        Assert.assertEquals(1, dynCol.getUint("1"));
149
+        Assert.assertEquals(-1, dynCol.getInt("2"));
150
+        Assert.assertEquals(12.12, dynCol.getDouble("3"), 0.0001);
151
+        Assert.assertEquals("afaf", dynCol.getString("4"));
152
+    }
153
+    
154
+    @Test
155
+    public void getBlobTest() throws SQLException, Exception {
156
+        DynCol dynCol = new DynCol();
157
+        dynCol.setJson("{\"1\":1," +
158
+                       "\"2\":-1," +
159
+                       "\"3\":12.12," +
160
+                       "\"4\":\"afaf\"}");
161
+        Assert.assertEquals("00040001000102000803001204005301013D0AD7A3703D28402D61666166", 
162
+        javax.xml.bind.DatatypeConverter.printHexBinary(dynCol.getBlob()));
163
+    }
164
+
165
+    @Test
166
+    public void setBlobTest() throws SQLException, Exception {
167
+        DynCol dynCol = new DynCol();
168
+        dynCol.setJson("{\"1\":1," +
169
+                       "\"2\":-1," +
170
+                       "\"3\":12.12," +
171
+                       "\"4\":\"afaf\"}");
172
+        dynCol.setBlob(dynCol.getBlob());
173
+        Assert.assertEquals(1, dynCol.getUint("1"));
174
+        Assert.assertEquals(-1, dynCol.getInt("2"));
175
+        Assert.assertEquals(12.12, dynCol.getDouble("3"), 0.0001);
176
+        Assert.assertEquals("afaf", dynCol.getString("4"));
177
+    }
178
+
179
+    @Test
180
+    public void setNullIntNamedTest() throws SQLException, UnsupportedEncodingException {
181
+        DynCol dynCol = new DynCol();
182
+        dynCol.setInt("n", 0);
183
+        Assert.assertEquals(0, dynCol.getInt("n"));
184
+    }
185
+
186
+    @Test
187
+    public void setMinusOneIntNamedTest() throws SQLException, UnsupportedEncodingException {
188
+        DynCol dynCol = new DynCol();
189
+        dynCol.setInt("n", -1);
190
+        Assert.assertEquals(-1, dynCol.getInt("n"));
191
+    }
192
+
193
+    @Test
194
+    public void setOneIntNamedTest() throws SQLException, UnsupportedEncodingException {
195
+        DynCol dynCol = new DynCol();
196
+        dynCol.setInt("n", 1);
197
+        Assert.assertEquals(1, dynCol.getInt("n"));
198
+    }
199
+
200
+    @Test
201
+    public void setMaxValueIntNamedTest() throws SQLException, UnsupportedEncodingException {
202
+        DynCol dynCol = new DynCol();
203
+        dynCol.setInt("n", Long.MAX_VALUE);
204
+        Assert.assertEquals(Long.MAX_VALUE, dynCol.getInt("n"));
205
+    }
206
+
207
+    @Test
208
+    public void setMinValueIntNamedTest() throws SQLException, UnsupportedEncodingException {
209
+        DynCol dynCol = new DynCol();
210
+        dynCol.setInt("n", Long.MIN_VALUE);
211
+        Assert.assertEquals(Long.MIN_VALUE, dynCol.getInt("n"));
212
+    }
213
+
214
+    @Test
215
+    public void setNullUintNamedTest() throws SQLException, Exception {
216
+        DynCol dynCol = new DynCol();
217
+        dynCol.setUint("n", 0);
218
+        Assert.assertEquals(0, dynCol.getUint("n"));
219
+    }
220
+
221
+    @Test (expected = Exception.class)
222
+    public void setMinusOneUintNamedTest() throws SQLException, Exception {
223
+        DynCol dynCol = new DynCol();
224
+        dynCol.setUint("n", -1);
225
+    }
226
+
227
+    @Test
228
+    public void setOneUintNamedTest() throws SQLException, Exception {
229
+        DynCol dynCol = new DynCol();
230
+        dynCol.setUint("n", 1);
231
+        Assert.assertEquals(1, dynCol.getUint("n"));
232
+    }
233
+
234
+    @Test
235
+    public void setMaxValueUintNamedTest() throws SQLException, Exception {
236
+        DynCol dynCol = new DynCol();
237
+        dynCol.setUint("n", Long.MAX_VALUE);
238
+        Assert.assertEquals(Long.MAX_VALUE, dynCol.getUint("n"));
239
+    }
240
+
241
+    @Test
242
+    public void setNullDoubleNamedTest() throws SQLException, UnsupportedEncodingException {
243
+        DynCol dynCol = new DynCol();
244
+        dynCol.setDouble("n", 0.0);
245
+        Assert.assertEquals(0.0, dynCol.getDouble("n"), 0.001);
246
+    }
247
+
248
+    @Test
249
+    public void setIntegerDoubleNamedTest() throws SQLException, UnsupportedEncodingException {
250
+        DynCol dynCol = new DynCol();
251
+        dynCol.setDouble("n", 1212.0);
252
+        Assert.assertEquals(1212.0, dynCol.getDouble("n"), 0.001);
253
+    }
254
+
255
+    @Test
256
+    public void setDoubleNamedTest() throws SQLException, UnsupportedEncodingException {
257
+        DynCol dynCol = new DynCol();
258
+        dynCol.setDouble("n", 12.12);
259
+        Assert.assertEquals(12.12, dynCol.getDouble("n"), 0.001);
260
+    }
261
+
262
+    @Test
263
+    public void setMaxValueDoubleNamedTest() throws SQLException, UnsupportedEncodingException {
264
+        DynCol dynCol = new DynCol();
265
+        dynCol.setDouble("n", Double.MAX_VALUE);
266
+        Assert.assertEquals(Double.MAX_VALUE, dynCol.getDouble("n"), 0.0001);
267
+    }
268
+
269
+    @Test
270
+    public void setMinValueDoubleNamedTest() throws SQLException, UnsupportedEncodingException {
271
+        DynCol dynCol = new DynCol();
272
+        dynCol.setDouble("n", Double.MIN_VALUE);
273
+        Assert.assertEquals(Double.MIN_VALUE, dynCol.getDouble("n"), 0.0001);
274
+    }
275
+    @Test (expected = Exception.class)
276
+    public void setNullNamedTest() throws SQLException, UnsupportedEncodingException {
277
+        DynCol dynCol = new DynCol();
278
+        dynCol.setString("n", null);
279
+        dynCol.getString("n");
280
+    }
281
+    @Test
282
+    public void setAfafStringNamedTest() throws SQLException, UnsupportedEncodingException {
283
+        DynCol dynCol = new DynCol();
284
+        dynCol.setString("n", "afaf");
285
+        Assert.assertEquals("afaf", dynCol.getString("n"));
286
+    }
287
+
288
+    @Test
289
+    public void setNumStringNamedTest() throws SQLException, UnsupportedEncodingException {
290
+        DynCol dynCol = new DynCol();
291
+        dynCol.setString("n", "1212");
292
+        Assert.assertEquals("1212", dynCol.getString("n"));
293
+    }
294
+
295
+    @Test
296
+    public void setJsonNamedTest() throws SQLException, Exception {
297
+        DynCol dynCol = new DynCol();
298
+        dynCol.setJson("{\"1\":1," +
299
+                       "\"2\":-1," +
300
+                       "\"3\":12.12," +
301
+                       "\"4\":{\"1\":-1}}");
302
+        Assert.assertEquals(1, dynCol.getUint("1"));
303
+        Assert.assertEquals(-1, dynCol.getInt("2"));
304
+        Assert.assertEquals(12.12, dynCol.getDouble("3"), 0.0001);
305
+        Assert.assertEquals(-1, dynCol.getDynCol("4").getInt("1"));
306
+    }
307
+    @Test
308
+    public void getJsonNamedTest() throws SQLException, Exception {
309
+        DynCol dynCol = new DynCol();
310
+        dynCol.setJson("{\"1\":1," +
311
+                       "\"2\":-1," +
312
+                       "\"3\":12.12," +
313
+                       "\"4\":{\"1\":-1}}");
314
+        dynCol.setJson(dynCol.getJson());
315
+        Assert.assertEquals(1, dynCol.getUint("1"));
316
+        Assert.assertEquals(-1, dynCol.getInt("2"));
317
+        Assert.assertEquals(12.12, dynCol.getDouble("3"), 0.0001);
318
+        Assert.assertEquals(-1, dynCol.getDynCol("4").getInt("1"));
319
+    }
320
+    
321
+    @Test
322
+    public void getBlobNamedTest() throws SQLException, Exception {
323
+        DynCol dynCol = new DynCol();
324
+        dynCol.setJson("{\"1\":1," +
325
+                       "\"2\":-1," +
326
+                       "\"3\":12.12," +
327
+                       "\"4\":{\"1\":-1}}");
328
+        Assert.assertEquals("04040004000000010001001000020022000300A8003132333401013D0AD7A3703D284000010001000001", 
329
+        javax.xml.bind.DatatypeConverter.printHexBinary(dynCol.getBlob()));
330
+    }
331
+
332
+    @Test
333
+    public void setBlobNamedTest() throws SQLException, Exception {
334
+        DynCol dynCol = new DynCol();
335
+        dynCol.setJson("{\"1\":1," +
336
+                       "\"2\":-1," +
337
+                       "\"3\":12.12," +
338
+                       "\"4\":{\"1\":-1}}");
339
+        dynCol.setBlob(dynCol.getBlob());
340
+        Assert.assertEquals(1, dynCol.getUint("1"));
341
+        Assert.assertEquals(-1, dynCol.getInt("2"));
342
+        Assert.assertEquals(12.12, dynCol.getDouble("3"), 0.0001);
343
+        Assert.assertEquals(-1, dynCol.getDynCol("4").getInt("1"));
344
+    }
345
+
346
+    @Test
347
+    public void setDynColNamedTest() throws SQLException, Exception {
348
+        DynCol dynCol = new DynCol();
349
+        dynCol.setInt("1", -1);
350
+        dynCol.setDynCol("1", dynCol);
351
+        Assert.assertEquals("0401000100000008003100010001000001",
352
+        javax.xml.bind.DatatypeConverter.printHexBinary(dynCol.getBlob()));
353
+    }
354
+
355
+    @Test
356
+    public void getDynColNamedTest() throws SQLException, Exception {
357
+        DynCol dynCol = new DynCol();
358
+        dynCol.setInt("1", -1);
359
+        dynCol.setDynCol("1", dynCol);
360
+        Assert.assertEquals(-1, dynCol.getDynCol("1").getInt("1"));
361
+    }
362
+}

+ 183
- 0
src/test/resources/style.xml View File

@@ -0,0 +1,183 @@
1
+<?xml version="1.0"?>
2
+<!DOCTYPE module PUBLIC
3
+        "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
4
+        "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
5
+
6
+<module name="Checker">
7
+    <property name="charset" value="UTF-8"/>
8
+
9
+    <property name="severity" value="error"/>
10
+    <property name="localeCountry" value="EN"/>
11
+    <property name="localeLanguage" value="en"/>
12
+
13
+    <property name="fileExtensions" value="java, properties, xml"/>
14
+    <!-- Checks for whitespace                               -->
15
+    <!-- See http://checkstyle.sf.net/config_whitespace.html -->
16
+    <module name="FileTabCharacter">
17
+        <property name="eachLine" value="true"/>
18
+    </module>
19
+
20
+    <module name="TreeWalker">
21
+        <module name="FileContentsHolder"/>
22
+        <module name="OuterTypeFilename"/>
23
+        <module name="IllegalTokenText">
24
+            <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
25
+            <property name="format"
26
+                      value="\\u00(08|09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
27
+            <property name="message" value="Avoid using corresponding octal or Unicode escape."/>
28
+        </module>
29
+
30
+        <module name="LineLength">
31
+            <property name="max" value="150"/>
32
+            <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
33
+        </module>
34
+        <!--<module name="AvoidStarImport">-->
35
+        <module name="OneTopLevelClass"/>
36
+        <module name="NoLineWrap"/>
37
+        <module name="EmptyBlock">
38
+            <property name="option" value="TEXT"/>
39
+            <property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
40
+        </module>
41
+        <module name="NeedBraces"/>
42
+        <module name="LeftCurly">
43
+            <property name="maxLineLength" value="150"/>
44
+        </module>
45
+        <module name="RightCurly"/>
46
+        <module name="RightCurly">
47
+            <property name="option" value="alone"/>
48
+            <property name="tokens" value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"/>
49
+        </module>
50
+        <module name="WhitespaceAround">
51
+            <property name="allowEmptyConstructors" value="true"/>
52
+            <property name="allowEmptyMethods" value="true"/>
53
+            <property name="allowEmptyTypes" value="true"/>
54
+            <property name="allowEmptyLoops" value="true"/>
55
+            <message key="ws.notFollowed"
56
+                     value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
57
+            <message key="ws.notPreceded"
58
+                     value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
59
+        </module>
60
+        <module name="OneStatementPerLine"/>
61
+        <module name="MultipleVariableDeclarations"/>
62
+        <module name="ArrayTypeStyle"/>
63
+        <module name="MissingSwitchDefault"/>
64
+        <module name="FallThrough"/>
65
+        <module name="UpperEll"/>
66
+        <module name="ModifierOrder"/>
67
+        <module name="EmptyLineSeparator">
68
+            <property name="allowNoEmptyLineBetweenFields" value="true"/>
69
+        </module>
70
+        <module name="SeparatorWrap">
71
+            <property name="tokens" value="DOT"/>
72
+            <property name="option" value="nl"/>
73
+        </module>
74
+        <module name="SeparatorWrap">
75
+            <property name="tokens" value="COMMA"/>
76
+            <property name="option" value="EOL"/>
77
+        </module>
78
+        <module name="PackageName">
79
+            <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
80
+            <message key="name.invalidPattern"
81
+                     value="Package name ''{0}'' must match pattern ''{1}''."/>
82
+        </module>
83
+        <module name="TypeName">
84
+            <message key="name.invalidPattern"
85
+                     value="Type name ''{0}'' must match pattern ''{1}''."/>
86
+        </module>
87
+        <module name="MemberName">
88
+            <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
89
+            <message key="name.invalidPattern"
90
+                     value="Member name ''{0}'' must match pattern ''{1}''."/>
91
+        </module>
92
+        <module name="ParameterName">
93
+            <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
94
+            <message key="name.invalidPattern"
95
+                     value="Parameter name ''{0}'' must match pattern ''{1}''."/>
96
+        </module>
97
+        <module name="LocalVariableName">
98
+            <property name="tokens" value="VARIABLE_DEF"/>
99
+            <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
100
+            <property name="allowOneCharVarInForLoop" value="true"/>
101
+            <message key="name.invalidPattern"
102
+                     value="Local variable name ''{0}'' must match pattern ''{1}''."/>
103
+        </module>
104
+        <module name="ClassTypeParameterName">
105
+            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
106
+            <message key="name.invalidPattern"
107
+                     value="Class type name ''{0}'' must match pattern ''{1}''."/>
108
+        </module>
109
+        <module name="MethodTypeParameterName">
110
+            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
111
+            <message key="name.invalidPattern"
112
+                     value="Method type name ''{0}'' must match pattern ''{1}''."/>
113
+        </module>
114
+        <module name="NoFinalizer"/>
115
+        <module name="GenericWhitespace">
116
+            <message key="ws.followed"
117
+                     value="GenericWhitespace ''{0}'' is followed by whitespace."/>
118
+            <message key="ws.preceded"
119
+                     value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
120
+            <message key="ws.illegalFollow"
121
+                     value="GenericWhitespace ''{0}'' should followed by whitespace."/>
122
+            <message key="ws.notPreceded"
123
+                     value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
124
+        </module>
125
+        <module name="Indentation">
126
+            <property name="basicOffset" value="4"/>
127
+            <property name="braceAdjustment" value="0"/>
128
+            <property name="caseIndent" value="4"/>
129
+            <property name="throwsIndent" value="4"/>
130
+            <property name="lineWrappingIndentation" value="4"/>
131
+            <property name="arrayInitIndent" value="8"/>
132
+        </module>
133
+        <module name="AbbreviationAsWordInName">
134
+            <property name="ignoreFinal" value="false"/>
135
+            <property name="allowedAbbreviationLength" value="1"/>
136
+        </module>
137
+        <module name="OverloadMethodsDeclarationOrder"/>
138
+        <module name="VariableDeclarationUsageDistance"/>
139
+        <module name="MethodParamPad"/>
140
+        <module name="OperatorWrap">
141
+            <property name="option" value="NL"/>
142
+            <property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/>
143
+        </module>
144
+        <module name="AnnotationLocation">
145
+            <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
146
+        </module>
147
+        <module name="AnnotationLocation">
148
+            <property name="tokens" value="VARIABLE_DEF"/>
149
+            <property name="allowSamelineMultipleAnnotations" value="true"/>
150
+        </module>
151
+        <module name="NonEmptyAtclauseDescription"/>
152
+        <!--<module name="JavadocTagContinuationIndentation"/>-->
153
+        <module name="SummaryJavadocCheck">
154
+            <property name="forbiddenSummaryFragments"
155
+                      value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
156
+        </module>
157
+        <!--<module name="JavadocParagraph"/>-->
158
+        <module name="AtclauseOrder">
159
+            <property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
160
+            <property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
161
+        </module>
162
+        <module name="JavadocMethod">
163
+            <property name="scope" value="public"/>
164
+            <property name="allowMissingParamTags" value="true"/>
165
+            <property name="allowMissingThrowsTags" value="true"/>
166
+            <property name="allowMissingReturnTag" value="true"/>
167
+            <property name="minLineCount" value="2"/>
168
+            <property name="allowedAnnotations" value="Override, Test"/>
169
+            <property name="allowThrowsTagsForSubclasses" value="true"/>
170
+        </module>
171
+        <module name="MethodName">
172
+            <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
173
+            <message key="name.invalidPattern"
174
+                     value="Method name ''{0}'' must match pattern ''{1}''."/>
175
+        </module>
176
+        <module name="SingleLineJavadoc"/>
177
+    </module>
178
+    <module name="SuppressWithNearbyCommentFilter">
179
+        <property name="commentFormat" value=".*deprecated.*"/>
180
+        <property name="checkFormat" value=".*"/>
181
+        <property name="influenceFormat" value="4"/>
182
+    </module>
183
+</module>

Loading…
Cancel
Save