Review Board 1.7.22


Fix for SQOOP-1013

Review Request #11537 - Created May 30, 2013 and updated

Venkat Ranganathan
Reviewers
Sqoop
sqoop-sqoop2
This addresses Boolean, date, time, and timestamp splitters.

THis also disallows char type splitters as discussed in SQOOP-976
Introduced new unit tests to test new functionality
All tests pass
connector/connector-generic-jdbc/src/main/java/org/apache/sqoop/connector/jdbc/GenericJdbcImportPartitioner.java
Revision f80f30d New Change
[20] 15 lines
[+20]
16
 * limitations under the License.
16
 * limitations under the License.
17
 */
17
 */
18
package org.apache.sqoop.connector.jdbc;
18
package org.apache.sqoop.connector.jdbc;
19

    
   
19

   
20
import java.math.BigDecimal;
20
import java.math.BigDecimal;

    
   
21
import java.sql.Date;

    
   
22
import java.sql.Time;

    
   
23
import java.sql.Timestamp;
21
import java.sql.Types;
24
import java.sql.Types;
22
import java.util.LinkedList;
25
import java.util.LinkedList;
23
import java.util.List;
26
import java.util.List;
24

    
   
27

   
25
import org.apache.sqoop.common.SqoopException;
28
import org.apache.sqoop.common.SqoopException;
[+20] [20] 5 lines
[+20]
31

    
   
34

   
32
public class GenericJdbcImportPartitioner extends Partitioner<ConnectionConfiguration, ImportJobConfiguration> {
35
public class GenericJdbcImportPartitioner extends Partitioner<ConnectionConfiguration, ImportJobConfiguration> {
33

    
   
36

   
34
  private static final BigDecimal NUMERIC_MIN_INCREMENT = new BigDecimal(10000 * Double.MIN_VALUE);
37
  private static final BigDecimal NUMERIC_MIN_INCREMENT = new BigDecimal(10000 * Double.MIN_VALUE);
35

    
   
38

   

    
   
39

   
36
  private long numberPartitions;
40
  private long numberPartitions;
37
  private String partitionColumnName;
41
  private String partitionColumnName;
38
  private int partitionColumnType;
42
  private int partitionColumnType;
39
  private String partitionMinValue;
43
  private String partitionMinValue;
40
  private String partitionMaxValue;
44
  private String partitionMaxValue;
[+20] [20] 4 lines
[+20] public class GenericJdbcImportPartitioner extends Partitioner<ConnectionConfiguration, ImportJobConfiguration> {
45
    partitionColumnName = context.getString(GenericJdbcConnectorConstants.CONNECTOR_JDBC_PARTITION_COLUMNNAME);
49
    partitionColumnName = context.getString(GenericJdbcConnectorConstants.CONNECTOR_JDBC_PARTITION_COLUMNNAME);
46
    partitionColumnType = context.getInt(GenericJdbcConnectorConstants.CONNECTOR_JDBC_PARTITION_COLUMNTYPE, -1);
50
    partitionColumnType = context.getInt(GenericJdbcConnectorConstants.CONNECTOR_JDBC_PARTITION_COLUMNTYPE, -1);
47
    partitionMinValue = context.getString(GenericJdbcConnectorConstants.CONNECTOR_JDBC_PARTITION_MINVALUE);
51
    partitionMinValue = context.getString(GenericJdbcConnectorConstants.CONNECTOR_JDBC_PARTITION_MINVALUE);
48
    partitionMaxValue = context.getString(GenericJdbcConnectorConstants.CONNECTOR_JDBC_PARTITION_MAXVALUE);
52
    partitionMaxValue = context.getString(GenericJdbcConnectorConstants.CONNECTOR_JDBC_PARTITION_MAXVALUE);
49

    
   
53

   

    
   
54
    if (partitionMinValue == null && partitionMaxValue == null) {

    
   
55
      List<Partition> partitions = new LinkedList<Partition>();
Moved from 138

    
   
56
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();
Moved from 139

    
   
57
      partition.setConditions(partitionColumnName + "IS NULL");
Moved from 140

    
   
58
      partitions.add(partition);
Moved from 141

    
   
59
      return partitions;
Moved from 142

    
   
60
    }

    
   
61

   
50
    switch (partitionColumnType) {
62
    switch (partitionColumnType) {
51
    case Types.TINYINT:
63
    case Types.TINYINT:
52
    case Types.SMALLINT:
64
    case Types.SMALLINT:
53
    case Types.INTEGER:
65
    case Types.INTEGER:
54
    case Types.BIGINT:
66
    case Types.BIGINT:
[+20] [20] 12 lines
[+20] public class GenericJdbcImportPartitioner extends Partitioner<ConnectionConfiguration, ImportJobConfiguration> {
67
      return partitionNumericColumn();
79
      return partitionNumericColumn();
68

    
   
80

   
69
    case Types.BIT:
81
    case Types.BIT:
70
    case Types.BOOLEAN:
82
    case Types.BOOLEAN:
71
      // Boolean column
83
      // Boolean column
72
      // TODO: Add partition function
84
      return partitionBooleanColumn();
73

    
   
85

   
74
    case Types.DATE:
86
    case Types.DATE:
75
    case Types.TIME:
87
    case Types.TIME:
76
    case Types.TIMESTAMP:
88
    case Types.TIMESTAMP:
77
      // Date time column
89
      // Date time column
78
      // TODO: Add partition function
90
      return partitionDateTimeColumn();
79

    
   
91

   
80
    case Types.CHAR:
92
    case Types.CHAR:
81
    case Types.VARCHAR:
93
    case Types.VARCHAR:
82
    case Types.LONGVARCHAR:
94
    case Types.LONGVARCHAR:
83
      // Text column
95
      // Text column
84
      // TODO: Add partition function
96
      return partitionTextColumn();
85

    
   
97

   
86
    default:
98
    default:
87
      throw new SqoopException(
99
      throw new SqoopException(
88
          GenericJdbcConnectorError.GENERIC_JDBC_CONNECTOR_0011,
100
          GenericJdbcConnectorError.GENERIC_JDBC_CONNECTOR_0011,
89
          String.valueOf(partitionColumnType));
101
          String.valueOf(partitionColumnType));
90
    }
102
    }
91
  }
103
  }

    
   
104
  protected List<Partition> partitionDateTimeColumn() {

    
   
105
    List<Partition> partitions = new LinkedList<Partition>();
92

    
   
106

   
93
  protected List<Partition> partitionIntegerColumn() {
107
    long minDateValue = 0;

    
   
108
    long maxDateValue = 0;

    
   
109

   

    
   
110
    switch(partitionColumnType) {

    
   
111
      case Types.DATE:

    
   
112
        minDateValue = Date.valueOf(partitionMinValue).getTime();

    
   
113
        maxDateValue = Date.valueOf(partitionMaxValue).getTime();

    
   
114
        break;

    
   
115
      case Types.TIME:

    
   
116
        minDateValue = Time.valueOf(partitionMinValue).getTime();

    
   
117
        maxDateValue = Time.valueOf(partitionMaxValue).getTime();

    
   
118
        break;

    
   
119
      case Types.TIMESTAMP:

    
   
120
        minDateValue = Timestamp.valueOf(partitionMinValue).getTime();

    
   
121
        maxDateValue = Timestamp.valueOf(partitionMaxValue).getTime();

    
   
122
        break;

    
   
123
    }

    
   
124
    long interval =  (maxDateValue - minDateValue) / numberPartitions;

    
   
125
    long remainder = (maxDateValue - minDateValue) % numberPartitions;

    
   
126

   

    
   
127
    if (interval == 0) {

    
   
128
      numberPartitions = (int)remainder;

    
   
129
    }

    
   
130
    long lowerBound;

    
   
131
    long upperBound = minDateValue;

    
   
132

   

    
   
133
    Object objLB = null;

    
   
134
    Object objUB = null;

    
   
135

   

    
   
136
    for (int i = 1; i < numberPartitions; i++) {

    
   
137
      lowerBound = upperBound;

    
   
138
      upperBound = lowerBound + interval;

    
   
139
      upperBound += (i <= remainder) ? 1 : 0;

    
   
140

   

    
   
141
      switch(partitionColumnType) {

    
   
142
        case Types.DATE:

    
   
143
          objLB = new Date(lowerBound);

    
   
144
          objUB = new Date(upperBound);

    
   
145
          break;

    
   
146
        case Types.TIME:

    
   
147
          objLB = new Time(lowerBound);

    
   
148
          objUB = new Time(upperBound);

    
   
149
          break;

    
   
150
        case Types.TIMESTAMP:

    
   
151
          objLB = new Timestamp(lowerBound);

    
   
152
          objUB = new Timestamp(upperBound);

    
   
153
          break;

    
   
154
      }

    
   
155

   

    
   
156
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();

    
   
157
      partition.setConditions(

    
   
158
          constructDateConditions(objLB, objUB, false));

    
   
159
      partitions.add(partition);

    
   
160
    }

    
   
161
    switch(partitionColumnType) {

    
   
162
      case Types.DATE:

    
   
163
        objLB = new Date(upperBound);

    
   
164
        objUB = new Date(maxDateValue);

    
   
165
        break;

    
   
166
      case Types.TIME:

    
   
167
        objLB = new Time(upperBound);

    
   
168
        objUB = new Time(maxDateValue);

    
   
169
        break;

    
   
170
      case Types.TIMESTAMP:

    
   
171
        objLB = new Timestamp(upperBound);

    
   
172
        objUB = new Timestamp(maxDateValue);

    
   
173
        break;

    
   
174
    }

    
   
175
    GenericJdbcImportPartition partition = new GenericJdbcImportPartition();

    
   
176
    partition.setConditions(

    
   
177
        constructDateConditions(objLB, objUB, true));
Moved from 140

    
   
178
    partitions.add(partition);
Moved from 141

    
   
179
    return partitions;
Moved from 142

    
   
180
  }

    
   
181

   

    
   
182
  protected List<Partition> partitionTextColumn() {
94
    List<Partition> partitions = new LinkedList<Partition>();
183
    List<Partition> partitions = new LinkedList<Partition>();
95

    
   
184

   
96
    if (partitionMinValue == null && partitionMaxValue == null) {
185
    String minStringValue = null;

    
   
186
    String maxStringValue = null;

    
   
187

   

    
   
188
    // Remove common prefix if any as it does not affect outcome.

    
   
189
    int maxPrefixLen = Math.min(partitionMinValue.length(),

    
   
190
        partitionMaxValue.length());

    
   
191
    // Calculate common prefix length

    
   
192
    int cpLen = 0;

    
   
193

   

    
   
194
    for (cpLen = 0; cpLen < maxPrefixLen; cpLen++) {

    
   
195
      char c1 = partitionMinValue.charAt(cpLen);

    
   
196
      char c2 = partitionMaxValue.charAt(cpLen);

    
   
197
      if (c1 != c2) {

    
   
198
        break;

    
   
199
      }

    
   
200
    }

    
   
201

   

    
   
202
    // The common prefix has length 'sharedLen'. Extract it from both.

    
   
203
    String prefix = partitionMinValue.substring(0, cpLen);

    
   
204
    minStringValue = partitionMinValue.substring(cpLen);

    
   
205
    maxStringValue = partitionMaxValue.substring(cpLen);

    
   
206

   

    
   
207
    BigDecimal minStringBD = textToBigDecimal(minStringValue);

    
   
208
    BigDecimal maxStringBD = textToBigDecimal(maxStringValue);

    
   
209

   

    
   
210
    // Having one single value means that we can create only one single split

    
   
211
    if(minStringBD.equals(maxStringBD)) {
97
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();
212
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();
98
      partition.setConditions(partitionColumnName + "IS NULL");
213
      partition.setConditions(constructTextConditions(prefix, maxStringBD));
99
      partitions.add(partition);
214
      partitions.add(partition);
100
      return partitions;
215
      return partitions;
101
    }
216
    }
102

    
   
217

   
103
    long minValue = Long.parseLong(partitionMinValue);
218
    // Get all the split points together.

    
   
219
    List<BigDecimal> splitPoints = new LinkedList<BigDecimal>();

    
   
220

   

    
   
221
    BigDecimal splitSize = divide(maxStringBD.subtract(minStringBD),

    
   
222
        new BigDecimal(numberPartitions));

    
   
223
    if (splitSize.compareTo(NUMERIC_MIN_INCREMENT) < 0) {

    
   
224
      splitSize = NUMERIC_MIN_INCREMENT;

    
   
225
    }

    
   
226

   

    
   
227
    BigDecimal curVal = minStringBD;

    
   
228

   

    
   
229
    while (curVal.compareTo(maxStringBD) <= 0) {

    
   
230
      splitPoints.add(curVal);

    
   
231
      curVal = curVal.add(splitSize);

    
   
232
    }

    
   
233

   

    
   
234
    if (splitPoints.size() == 0

    
   
235
        || splitPoints.get(0).compareTo(minStringBD) != 0) {

    
   
236
      splitPoints.add(0, minStringBD);

    
   
237
    }

    
   
238

   

    
   
239
    if (splitPoints.get(splitPoints.size() - 1).compareTo(maxStringBD) != 0

    
   
240
        || splitPoints.size() == 1) {

    
   
241
      splitPoints.add(maxStringBD);

    
   
242
    }

    
   
243

   

    
   
244
    // Turn the split points into a set of string intervals.

    
   
245
    BigDecimal start = splitPoints.get(0);

    
   
246
    for (int i = 1; i < splitPoints.size(); i++) {

    
   
247
      BigDecimal end = splitPoints.get(i);

    
   
248

   

    
   
249
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();

    
   
250
      partition.setConditions(constructTextConditions(prefix, start,

    
   
251
          end, i == splitPoints.size() - 1));

    
   
252
      partitions.add(partition);

    
   
253

   

    
   
254
      start = end;

    
   
255
    }

    
   
256

   
Moved from 141

    
   
257
    return partitions;
Moved from 142

    
   
258
  }

    
   
259

   

    
   
260

   

    
   
261
  protected List<Partition> partitionIntegerColumn() {

    
   
262
    List<Partition> partitions = new LinkedList<Partition>();

    
   
263

   

    
   
264
    long minValue = partitionMinValue == null ? Long.MIN_VALUE

    
   
265
      : Long.parseLong(partitionMinValue);
104
    long maxValue = Long.parseLong(partitionMaxValue);
266
    long maxValue = Long.parseLong(partitionMaxValue);
105

    
   
267

   
106
    long interval =  (maxValue - minValue) / numberPartitions;
268
    long interval =  (maxValue - minValue) / numberPartitions;
107
    long remainder = (maxValue - minValue) % numberPartitions;
269
    long remainder = (maxValue - minValue) % numberPartitions;
108

    
   
270

   
[+20] [20] 23 lines
[+20] public class GenericJdbcImportPartitioner extends Partitioner<ConnectionConfiguration, ImportJobConfiguration> {
132
  }
294
  }
133

    
   
295

   
134
  protected List<Partition> partitionFloatingPointColumn() {
296
  protected List<Partition> partitionFloatingPointColumn() {
135
    List<Partition> partitions = new LinkedList<Partition>();
297
    List<Partition> partitions = new LinkedList<Partition>();
136

    
   
298

   
137
    if (partitionMinValue == null && partitionMaxValue == null) {

   
138
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();

   
139
      partition.setConditions(partitionColumnName + "IS NULL");

   
140
      partitions.add(partition);

   
141
      return partitions;

   
142
    }

   
143

    
   
299

   
144
    double minValue = Double.parseDouble(partitionMinValue);
300
    double minValue = partitionMinValue == null ? Double.MIN_VALUE

    
   
301
      : Double.parseDouble(partitionMinValue);
145
    double maxValue = Double.parseDouble(partitionMaxValue);
302
    double maxValue = Double.parseDouble(partitionMaxValue);
146

    
   
303

   
147
    double interval =  (maxValue - minValue) / numberPartitions;
304
    double interval =  (maxValue - minValue) / numberPartitions;
148

    
   
305

   
149
    double lowerBound;
306
    double lowerBound;
[+20] [20] 16 lines
[+20] public class GenericJdbcImportPartitioner extends Partitioner<ConnectionConfiguration, ImportJobConfiguration> {
166
    return partitions;
323
    return partitions;
167
  }
324
  }
168

    
   
325

   
169
  protected List<Partition> partitionNumericColumn() {
326
  protected List<Partition> partitionNumericColumn() {
170
    List<Partition> partitions = new LinkedList<Partition>();
327
    List<Partition> partitions = new LinkedList<Partition>();
171

    
   

   
172
    // All null values will result in single partition

   
173
    if (partitionMinValue == null && partitionMaxValue == null) {

   
174
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();

   
175
      partition.setConditions(partitionColumnName + "IS NULL");

   
176
      partitions.add(partition);

   
177
      return partitions;

   
178
    }

   
179

    
   

   
180
    // Having one end in null is not supported
328
    // Having one end in null is not supported
181
    if (partitionMinValue == null || partitionMaxValue == null) {
329
    if (partitionMinValue == null || partitionMaxValue == null) {
182
      throw new SqoopException(GenericJdbcConnectorError.GENERIC_JDBC_CONNECTOR_0015);
330
      throw new SqoopException(GenericJdbcConnectorError.GENERIC_JDBC_CONNECTOR_0015);
183
    }
331
    }
184

    
   
332

   
185
    BigDecimal minValue = new BigDecimal(partitionMinValue);
333
    BigDecimal minValue = new BigDecimal(partitionMinValue);
186
    BigDecimal maxValue = new BigDecimal(partitionMaxValue);
334
    BigDecimal maxValue = new BigDecimal(partitionMaxValue);
187

    
   
335

   
188
    // Having one single value means that we can create only one single split
336
    // Having one single value means that we can create only one single split
189
    if(minValue.equals(maxValue)) {
337
    if(minValue.equals(maxValue)) {
190
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();
338
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();
191
      partition.setConditions(constructConditions(minValue));
339
      partition.setConditions(constructConditions(minValue));
192
      partitions.add(partition);
340
      partitions.add(partition);

    
   
341
      return partitions;
193
    }
342
    }
194

    
   
343

   
195
    // Get all the split points together.
344
    // Get all the split points together.
196
    List<BigDecimal> splitPoints = new LinkedList<BigDecimal>();
345
    List<BigDecimal> splitPoints = new LinkedList<BigDecimal>();
197

    
   
346

   
198
    BigDecimal splitSize = divide(maxValue.subtract(minValue), new BigDecimal(numberPartitions));
347
    BigDecimal splitSize = divide(maxValue.subtract(minValue), new BigDecimal(numberPartitions));

    
   
348

   
199
    if (splitSize.compareTo(NUMERIC_MIN_INCREMENT) < 0) {
349
    if (splitSize.compareTo(NUMERIC_MIN_INCREMENT) < 0) {
200
      splitSize = NUMERIC_MIN_INCREMENT;
350
      splitSize = NUMERIC_MIN_INCREMENT;
201
    }
351
    }
202

    
   
352

   
203
    BigDecimal curVal = minValue;
353
    BigDecimal curVal = minValue;
[+20] [20] 21 lines
[+20] public class GenericJdbcImportPartitioner extends Partitioner<ConnectionConfiguration, ImportJobConfiguration> {
225
    }
375
    }
226

    
   
376

   
227
    return partitions;
377
    return partitions;
228
  }
378
  }
229

    
   
379

   

    
   
380
  protected  List<Partition> partitionBooleanColumn() {

    
   
381
    List<Partition> partitions = new LinkedList<Partition>();

    
   
382

   

    
   
383

   

    
   
384
    Boolean minValue = parseBooleanValue(partitionMinValue);

    
   
385
    Boolean maxValue = parseBooleanValue(partitionMaxValue);

    
   
386

   

    
   
387
    StringBuilder conditions = new StringBuilder();

    
   
388

   

    
   
389
    // Having one single value means that we can create only one single split

    
   
390
    if(minValue.equals(maxValue)) {

    
   
391
      GenericJdbcImportPartition partition = new GenericJdbcImportPartition();

    
   
392

   

    
   
393
      conditions.append(partitionColumnName).append(" = ")

    
   
394
          .append(maxValue);

    
   
395
      partition.setConditions(conditions.toString());
Moved from 140

    
   
396
      partitions.add(partition);
Moved from 141

    
   
397
      return partitions;
Moved from 142

    
   
398
    }

    
   
399

   

    
   
400
    GenericJdbcImportPartition partition = new GenericJdbcImportPartition();

    
   
401

   

    
   
402
    if (partitionMinValue == null) {

    
   
403
      conditions = new StringBuilder();

    
   
404
      conditions.append(partitionColumnName).append(" IS NULL");

    
   
405
      partition.setConditions(conditions.toString());

    
   
406
      partitions.add(partition);

    
   
407
    }

    
   
408
    partition = new GenericJdbcImportPartition();

    
   
409
    conditions = new StringBuilder();

    
   
410
    conditions.append(partitionColumnName).append(" = TRUE");

    
   
411
    partition.setConditions(conditions.toString());

    
   
412
    partitions.add(partition);

    
   
413
    partition = new GenericJdbcImportPartition();

    
   
414
    conditions = new StringBuilder();

    
   
415
    conditions.append(partitionColumnName).append(" = FALSE");

    
   
416
    partition.setConditions(conditions.toString());
Moved from 140

    
   
417
    partitions.add(partition);
Moved from 141

    
   
418
    return partitions;
Moved from 142

    
   
419
  }

    
   
420

   

    
   
421
  private Boolean parseBooleanValue(String value) {

    
   
422
    if (value == null) {

    
   
423
      return null;

    
   
424
    }

    
   
425
    if (value.equals("1")) {

    
   
426
      return Boolean.TRUE;

    
   
427
    } else if (value.equals("0")) {

    
   
428
      return Boolean.FALSE;

    
   
429
    } else {

    
   
430
      return Boolean.parseBoolean(value);

    
   
431
    }

    
   
432
  }

    
   
433

   
230
  protected BigDecimal divide(BigDecimal numerator, BigDecimal denominator) {
434
  protected BigDecimal divide(BigDecimal numerator, BigDecimal denominator) {
231
    try {
435
    try {
232
      return numerator.divide(denominator);
436
      return numerator.divide(denominator);
233
    } catch (ArithmeticException ae) {
437
    } catch (ArithmeticException ae) {
234
      return numerator.divide(denominator, BigDecimal.ROUND_HALF_UP);
438
      return numerator.divide(denominator, BigDecimal.ROUND_HALF_UP);
[+20] [20] 19 lines
[+20] [+] protected String constructConditions(Object value) {
254
      .append(" = ")
458
      .append(" = ")
255
      .append(value)
459
      .append(value)
256
      .toString()
460
      .toString()
257
     ;
461
     ;
258
  }
462
  }

    
   
463

   

    
   
464
  protected String constructDateConditions(

    
   
465
      Object lowerBound, Object upperBound, boolean lastOne) {

    
   
466
    StringBuilder conditions = new StringBuilder();

    
   
467
    conditions.append('\'').append(lowerBound.toString()).append('\'');

    
   
468
    conditions.append(" <= ");

    
   
469
    conditions.append(partitionColumnName);

    
   
470
    conditions.append(" AND ");

    
   
471
    conditions.append(partitionColumnName);

    
   
472
    conditions.append(lastOne ? " <= " : " < ");

    
   
473
    conditions.append('\'').append(upperBound.toString()).append('\'');

    
   
474
    return conditions.toString();

    
   
475
  }

    
   
476

   

    
   
477
  protected String constructTextConditions(String prefix,

    
   
478
      Object lowerBound, Object upperBound, boolean lastOne) {

    
   
479
    StringBuilder conditions = new StringBuilder();

    
   
480
    String lbString = prefix + bigDecimalToText((BigDecimal)lowerBound);

    
   
481
    String ubString = prefix + bigDecimalToText((BigDecimal)upperBound);

    
   
482
    conditions.append('\'').append(lbString).append('\'');

    
   
483
    conditions.append(" <= ");

    
   
484
    conditions.append(partitionColumnName);

    
   
485
    conditions.append(" AND ");

    
   
486
    conditions.append(partitionColumnName);

    
   
487
    conditions.append(lastOne ? " <= " : " < ");

    
   
488
    conditions.append('\'').append(ubString).append('\'');

    
   
489
    return conditions.toString();

    
   
490
  }

    
   
491

   

    
   
492
  protected String constructTextConditions(String prefix, Object value) {

    
   
493
    return new StringBuilder()

    
   
494
      .append(partitionColumnName)

    
   
495
      .append(" = ").append('\'')

    
   
496
      .append(prefix + bigDecimalToText((BigDecimal)value))

    
   
497
      .append('\'').toString()

    
   
498
     ;

    
   
499
  }

    
   
500

   

    
   
501

   

    
   
502
  /**

    
   
503
   *  Converts a string to a BigDecimal representation in Base 2^21 format.

    
   
504
   *  The maximum Unicode code point value defined is 10FFFF.  Although

    
   
505
   *  not all database system support UTF16 and mostly we expect UCS2

    
   
506
   *  characters only, for completeness, we assume that all the unicode

    
   
507
   *  characters are supported.

    
   
508
   *  Given a string 's' containing characters s_0, s_1,..s_n,

    
   
509
   *  the string is interpreted as the number: 0.s_0 s_1 s_2 s_3 s_48)

    
   
510
   *  This can be split and each split point can be converted back to

    
   
511
   *  a string value for comparison purposes.   The number of characters

    
   
512
   *  is restricted to prevent repeating fractions and rounding errors

    
   
513
   *  towards the higher fraction positions.

    
   
514
   */

    
   
515
  private static final BigDecimal UNITS_BASE = new BigDecimal(2097152);

    
   
516
  private static final int MAX_CHARS_TO_CONVERT = 4;

    
   
517

   

    
   
518
  private BigDecimal textToBigDecimal(String str) {

    
   
519
    BigDecimal result = BigDecimal.ZERO;

    
   
520
    BigDecimal divisor = UNITS_BASE;

    
   
521

   

    
   
522
    int len = Math.min(str.length(), MAX_CHARS_TO_CONVERT);

    
   
523

   

    
   
524
    for (int n = 0; n < len; ) {

    
   
525
      int codePoint = str.codePointAt(n);

    
   
526
      n += Character.charCount(codePoint);

    
   
527
      BigDecimal val = divide(new BigDecimal(codePoint), divisor);

    
   
528
      result = result.add(val);

    
   
529
      divisor = divisor.multiply(UNITS_BASE);

    
   
530
    }

    
   
531

   

    
   
532
    return result;

    
   
533
  }

    
   
534

   

    
   
535
  private String bigDecimalToText(BigDecimal bd) {

    
   
536
    BigDecimal curVal = bd.stripTrailingZeros();

    
   
537
    StringBuilder sb = new StringBuilder();

    
   
538

   

    
   
539
    for (int n = 0; n < MAX_CHARS_TO_CONVERT; ++n) {

    
   
540
      curVal = curVal.multiply(UNITS_BASE);

    
   
541
      int cp = curVal.intValue();

    
   
542
      if (0 == cp) {

    
   
543
        break;

    
   
544
      }

    
   
545
      curVal = curVal.subtract(new BigDecimal(cp));

    
   
546
      sb.append(Character.toChars(cp));

    
   
547
    }

    
   
548
    return sb.toString();

    
   
549
  }

    
   
550

   
259
}
551
}
connector/connector-generic-jdbc/src/test/java/org/apache/sqoop/connector/jdbc/TestImportPartitioner.java
Revision ee314d0 New Change
 
  1. connector/connector-generic-jdbc/src/main/java/org/apache/sqoop/connector/jdbc/GenericJdbcImportPartitioner.java: Loading...
  2. connector/connector-generic-jdbc/src/test/java/org/apache/sqoop/connector/jdbc/TestImportPartitioner.java: Loading...