4
4
import java .sql .SQLDataException ;
5
5
import java .sql .SQLException ;
6
6
import java .util .ArrayList ;
7
- import java .util .Arrays ;
8
7
import java .util .Collections ;
9
8
import java .util .HashMap ;
10
9
import java .util .HashSet ;
36
35
* @author Aleksandr Gorshenin
37
36
*/
38
37
public class BatchedQuery implements YdbPreparedQuery {
39
- private final String yql ;
38
+ private final String singleQuery ;
39
+ private final String batchQuery ;
40
40
private final String batchParamName ;
41
41
private final Map <String , ParamDescription > paramsByName ;
42
42
private final ParamDescription [] params ;
43
43
44
44
private final List <StructValue > batchList = new ArrayList <>();
45
45
private final Map <String , Value <?>> currentValues = new HashMap <>();
46
46
47
- protected BatchedQuery (YdbTypes types , String yql , String listName , List < String > pnames , Map < String , Type > ptypes )
48
- throws SQLException {
49
- this .yql = yql ;
50
- this .batchParamName = listName ;
47
+ protected BatchedQuery (String single , String batched , String prm , ParamDescription [] params ) throws SQLException {
48
+ this . singleQuery = single ;
49
+ this .batchQuery = batched ;
50
+ this .batchParamName = prm ;
51
51
this .paramsByName = new HashMap <>();
52
- this .params = new ParamDescription [ pnames . size ()] ;
52
+ this .params = params ;
53
53
54
- for (int idx = 0 ; idx < pnames .size (); idx += 1 ) {
55
- String name = pnames .get (idx );
56
- if (!ptypes .containsKey (name )) {
57
- throw new SQLException (YdbConst .INVALID_BATCH_COLUMN + name );
58
- }
59
- TypeDescription type = types .find (ptypes .get (name ));
60
- ParamDescription desc = new ParamDescription (name , YdbConst .VARIABLE_PARAMETER_PREFIX + name , type );
61
- params [idx ] = desc ;
62
- paramsByName .put (name , desc );
54
+ for (ParamDescription pd : params ) {
55
+ paramsByName .put (pd .name (), pd );
63
56
}
64
57
}
65
58
66
59
@ Override
67
60
public String getQueryText (Params prms ) {
68
- return yql ;
61
+ return singleQuery != null ? singleQuery : batchQuery ;
62
+ }
63
+
64
+ @ Override
65
+ public String getBatchText (Params prms ) {
66
+ return batchQuery ;
69
67
}
70
68
71
69
@ Override
@@ -85,7 +83,7 @@ public void clearParameters() {
85
83
86
84
@ Override
87
85
public void addBatch () throws SQLException {
88
- batchList .add (getCurrentValues ( ));
86
+ batchList .add (StructValue . of ( validateValues () ));
89
87
currentValues .clear ();
90
88
}
91
89
@@ -94,13 +92,13 @@ public void clearBatch() {
94
92
batchList .clear ();
95
93
}
96
94
97
- protected StructValue getCurrentValues () throws SQLException {
95
+ protected Map < String , Value <?>> validateValues () throws SQLException {
98
96
for (ParamDescription prm : params ) {
99
97
if (!currentValues .containsKey (prm .name ())) {
100
98
throw new SQLDataException (YdbConst .MISSING_VALUE_FOR_PARAMETER + prm .displayName ());
101
99
}
102
100
}
103
- return StructValue . of ( currentValues ) ;
101
+ return currentValues ;
104
102
}
105
103
106
104
protected List <StructValue > getBatchedValues () {
@@ -109,8 +107,13 @@ protected List<StructValue> getBatchedValues() {
109
107
110
108
@ Override
111
109
public Params getCurrentParams () throws SQLException {
112
- ListValue list = ListValue .of (getCurrentValues ());
113
- return Params .of (batchParamName , list );
110
+ Map <String , Value <?>> vv = validateValues ();
111
+ if (singleQuery == null ) {
112
+ return Params .of (batchParamName , ListValue .of (StructValue .of (vv )));
113
+ }
114
+ Params prms = Params .create (vv .size ());
115
+ vv .forEach ((name , value ) -> prms .put (YdbConst .VARIABLE_PARAMETER_PREFIX + name , value ));
116
+ return prms ;
114
117
}
115
118
116
119
@ Override
@@ -216,7 +219,15 @@ public static BatchedQuery tryCreateBatched(YdbTypes types, YdbQuery query, Map<
216
219
columns [idx ] = param ;
217
220
}
218
221
219
- return new BatchedQuery (types , query .getPreparedYql (), listName , Arrays .asList (columns ), paramTypes );
222
+ ParamDescription [] descriptions = new ParamDescription [columns .length ];
223
+ for (int idx = 0 ; idx < columns .length ; idx += 1 ) {
224
+ String name = columns [idx ];
225
+ if (!paramTypes .containsKey (name )) {
226
+ throw new SQLException (YdbConst .INVALID_BATCH_COLUMN + name );
227
+ }
228
+ descriptions [idx ] = new ParamDescription (name , types .find (paramTypes .get (name )));
229
+ }
230
+ return new BatchedQuery (null , query .getPreparedYql (), listName , descriptions );
220
231
}
221
232
222
233
public static BatchedQuery createAutoBatched (YdbTypes types , YqlBatcher batcher , TableDescription description )
@@ -235,33 +246,38 @@ public static BatchedQuery createAutoBatched(YdbTypes types, YqlBatcher batcher,
235
246
}
236
247
}
237
248
238
- StringBuilder sb = new StringBuilder ();
239
249
Map <String , Type > columnTypes = new HashMap <>();
240
- Map <String , Type > structTypes = new HashMap <>();
241
- List <String > columns = new ArrayList <>();
242
-
243
250
for (TableColumn column : description .getColumns ()) {
244
251
columnTypes .put (column .getName (), column .getType ());
245
252
}
246
253
247
- List <String > params = new ArrayList <>();
248
- params .addAll (batcher .getColumns ());
249
- params .addAll (batcher .getKeyColumns ());
254
+ List <String > columns = new ArrayList <>();
255
+ columns .addAll (batcher .getColumns ());
256
+ columns .addAll (batcher .getKeyColumns ());
257
+
258
+ ParamDescription [] params = new ParamDescription [columns .size ()];
250
259
251
- sb .append ("DECLARE $batch AS List<Struct<" );
252
260
int idx = 1 ;
253
- for (String column : params ) {
261
+ for (String column : columns ) {
254
262
Type type = columnTypes .get (column );
255
263
if (type == null ) {
256
264
return null ;
257
265
}
258
- if (idx > 1 ) {
266
+ params [idx - 1 ] = new ParamDescription ("p" + idx , column , types .find (type ));
267
+ idx ++;
268
+ }
269
+
270
+ return new BatchedQuery (simpleQuery (batcher , params ), batchQuery (batcher , params ), "$batch" , params );
271
+ }
272
+
273
+ private static String batchQuery (YqlBatcher batcher , ParamDescription [] params ) {
274
+ StringBuilder sb = new StringBuilder ();
275
+ sb .append ("DECLARE $batch AS List<Struct<" );
276
+ for (int idx = 0 ; idx < params .length ; idx ++) {
277
+ if (idx > 0 ) {
259
278
sb .append (", " );
260
279
}
261
- sb .append ("p" ).append (idx ).append (":" ).append (type .toString ());
262
- structTypes .put ("p" + idx , type );
263
- columns .add ("p" + idx );
264
- idx ++;
280
+ sb .append (params [idx ].name ()).append (":" ).append (params [idx ].type ().toYqlLiteral ());
265
281
}
266
282
sb .append (">>;\n " );
267
283
@@ -282,20 +298,97 @@ public static BatchedQuery createAutoBatched(YdbTypes types, YqlBatcher batcher,
282
298
sb .append ("DELETE FROM `" ).append (batcher .getTableName ()).append ("` ON SELECT " );
283
299
break ;
284
300
default :
285
- return null ;
301
+ return "UNSUPPORTED CMD " + batcher . getCommand () ;
286
302
}
287
303
288
- idx = 1 ;
289
- for (String column : params ) {
290
- if (idx > 1 ) {
304
+ for (int idx = 0 ; idx < params .length ; idx ++) {
305
+ if (idx > 0 ) {
291
306
sb .append (", " );
292
307
}
293
- sb .append ("p" ).append (idx ).append (" AS `" ).append (column ).append ("`" );
294
- idx ++;
308
+ sb .append (params [idx ].name ()).append (" AS `" ).append (params [idx ].displayName ()).append ("`" );
295
309
}
296
310
297
311
sb .append (" FROM AS_TABLE($batch);" );
312
+ return sb .toString ();
313
+ }
314
+
315
+ private static String simpleQuery (YqlBatcher batcher , ParamDescription [] params ) {
316
+ StringBuilder sb = new StringBuilder ();
317
+ for (ParamDescription p : params ) {
318
+ sb .append ("DECLARE " ).append (YdbConst .VARIABLE_PARAMETER_PREFIX ).append (p .name ())
319
+ .append (" AS " ).append (p .type ().toYqlLiteral ()).append (";\n " );
320
+ }
298
321
299
- return new BatchedQuery (types , sb .toString (), "$batch" , columns , structTypes );
322
+ switch (batcher .getCommand ()) {
323
+ case UPSERT :
324
+ sb .append ("UPSERT INTO `" ).append (batcher .getTableName ()).append ("` (" );
325
+ appendColumns (sb , params );
326
+ sb .append (") VALUES (" );
327
+ appendValues (sb , params );
328
+ sb .append (");" );
329
+ break ;
330
+ case INSERT :
331
+ sb .append ("INSERT INTO `" ).append (batcher .getTableName ()).append ("` (" );
332
+ appendColumns (sb , params );
333
+ sb .append (") VALUES (" );
334
+ appendValues (sb , params );
335
+ sb .append (");" );
336
+ break ;
337
+ case REPLACE :
338
+ sb .append ("REPLACE INTO `" ).append (batcher .getTableName ()).append ("` (" );
339
+ appendColumns (sb , params );
340
+ sb .append (") VALUES (" );
341
+ appendValues (sb , params );
342
+ sb .append (");" );
343
+ break ;
344
+ case UPDATE :
345
+ sb .append ("UPDATE `" ).append (batcher .getTableName ()).append ("` SET " );
346
+ for (int idx = 0 ; idx < batcher .getColumns ().size (); idx ++) {
347
+ if (idx > 0 ) {
348
+ sb .append (", " );
349
+ }
350
+ sb .append ('`' ).append (params [idx ].displayName ()).append ("` = " )
351
+ .append (YdbConst .VARIABLE_PARAMETER_PREFIX ).append (params [idx ].name ());
352
+ }
353
+ sb .append (" WHERE " );
354
+ appendKeys (sb , params , batcher .getColumns ().size ());
355
+ break ;
356
+ case DELETE :
357
+ sb .append ("DELETE FROM `" ).append (batcher .getTableName ()).append ("` WHERE " );
358
+ appendKeys (sb , params , batcher .getColumns ().size ());
359
+ break ;
360
+ default :
361
+ break ;
362
+ }
363
+
364
+ return sb .toString ();
365
+ }
366
+
367
+ private static void appendColumns (StringBuilder sb , ParamDescription [] params ) {
368
+ for (int idx = 0 ; idx < params .length ; idx ++) {
369
+ if (idx > 0 ) {
370
+ sb .append (", " );
371
+ }
372
+ sb .append ('`' ).append (params [idx ].displayName ()).append ('`' );
373
+ }
374
+ }
375
+
376
+ private static void appendValues (StringBuilder sb , ParamDescription [] params ) {
377
+ for (int idx = 0 ; idx < params .length ; idx ++) {
378
+ if (idx > 0 ) {
379
+ sb .append (", " );
380
+ }
381
+ sb .append (YdbConst .VARIABLE_PARAMETER_PREFIX ).append (params [idx ].name ());
382
+ }
383
+ }
384
+
385
+ private static void appendKeys (StringBuilder sb , ParamDescription [] params , int firstKeyIdx ) {
386
+ for (int idx = firstKeyIdx ; idx < params .length ; idx ++) {
387
+ if (idx > firstKeyIdx ) {
388
+ sb .append (" AND " );
389
+ }
390
+ sb .append ('`' ).append (params [idx ].displayName ()).append ("` = " )
391
+ .append (YdbConst .VARIABLE_PARAMETER_PREFIX ).append (params [idx ].name ());
392
+ }
300
393
}
301
394
}
0 commit comments