crate 0.29.0__py2.py3-none-any.whl → 0.30.1__py2.py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- crate/client/__init__.py +1 -1
- crate/client/_pep440.py +501 -0
- crate/client/connection.py +3 -3
- crate/client/sqlalchemy/__init__.py +24 -0
- crate/client/sqlalchemy/compat/__init__.py +0 -0
- crate/client/sqlalchemy/compat/api13.py +156 -0
- crate/client/sqlalchemy/compat/core10.py +264 -0
- crate/client/sqlalchemy/compat/core14.py +359 -0
- crate/client/sqlalchemy/compat/core20.py +447 -0
- crate/client/sqlalchemy/compiler.py +1 -481
- crate/client/sqlalchemy/dialect.py +32 -17
- crate/client/sqlalchemy/sa_version.py +4 -3
- crate/client/sqlalchemy/tests/__init__.py +17 -6
- crate/client/sqlalchemy/tests/array_test.py +6 -3
- crate/client/sqlalchemy/tests/bulk_test.py +7 -4
- crate/client/sqlalchemy/tests/compiler_test.py +10 -9
- crate/client/sqlalchemy/tests/connection_test.py +25 -11
- crate/client/sqlalchemy/tests/create_table_test.py +19 -16
- crate/client/sqlalchemy/tests/datetime_test.py +6 -3
- crate/client/sqlalchemy/tests/dialect_test.py +42 -13
- crate/client/sqlalchemy/tests/dict_test.py +17 -13
- crate/client/sqlalchemy/tests/function_test.py +6 -3
- crate/client/sqlalchemy/tests/insert_from_select_test.py +9 -6
- crate/client/sqlalchemy/tests/match_test.py +6 -3
- crate/client/sqlalchemy/tests/update_test.py +6 -3
- crate/client/sqlalchemy/tests/warnings_test.py +33 -0
- crate/client/test_connection.py +25 -0
- crate/client/tests.py +98 -119
- crate/testing/layer.py +1 -1
- crate/testing/settings.py +51 -0
- crate/testing/test_layer.py +188 -2
- crate/testing/tests.py +2 -38
- crate/testing/util.py +20 -0
- {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/METADATA +10 -8
- crate-0.30.1.dist-info/RECORD +53 -0
- crate-0.29.0.dist-info/RECORD +0 -44
- /crate-0.29.0-py3.9-nspkg.pth → /crate-0.30.1-py3.9-nspkg.pth +0 -0
- {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/LICENSE +0 -0
- {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/NOTICE +0 -0
- {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/WHEEL +0 -0
- {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/entry_points.txt +0 -0
- {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/namespace_packages.txt +0 -0
- {crate-0.29.0.dist-info → crate-0.30.1.dist-info}/top_level.txt +0 -0
@@ -24,7 +24,7 @@ from collections import defaultdict
|
|
24
24
|
|
25
25
|
import sqlalchemy as sa
|
26
26
|
from sqlalchemy.dialects.postgresql.base import PGCompiler
|
27
|
-
from sqlalchemy.sql import compiler
|
27
|
+
from sqlalchemy.sql import compiler
|
28
28
|
from .types import MutableDict, _Craty, Geopoint, Geoshape
|
29
29
|
from .sa_version import SA_VERSION, SA_1_4
|
30
30
|
|
@@ -208,8 +208,6 @@ class CrateTypeCompiler(compiler.GenericTypeCompiler):
|
|
208
208
|
|
209
209
|
class CrateCompiler(compiler.SQLCompiler):
|
210
210
|
|
211
|
-
prefetch = []
|
212
|
-
|
213
211
|
def visit_getitem_binary(self, binary, operator, **kw):
|
214
212
|
return "{0}['{1}']".format(
|
215
213
|
self.process(binary.left, **kw),
|
@@ -223,486 +221,8 @@ class CrateCompiler(compiler.SQLCompiler):
|
|
223
221
|
self.process(element.right, **kw)
|
224
222
|
)
|
225
223
|
|
226
|
-
def returning_clause(self, stmt, returning_cols):
|
227
|
-
columns = [
|
228
|
-
self._label_select_column(None, c, True, False, {})
|
229
|
-
for c in sa.sql.expression._select_iterables(returning_cols)
|
230
|
-
]
|
231
|
-
return "RETURNING " + ", ".join(columns)
|
232
|
-
|
233
|
-
def visit_update(self, update_stmt, **kw):
|
234
|
-
"""
|
235
|
-
used to compile <sql.expression.Update> expressions
|
236
|
-
Parts are taken from the SQLCompiler base class.
|
237
|
-
"""
|
238
|
-
|
239
|
-
if SA_VERSION >= SA_1_4:
|
240
|
-
return self.visit_update_14(update_stmt, **kw)
|
241
|
-
|
242
|
-
if not update_stmt.parameters and \
|
243
|
-
not hasattr(update_stmt, '_crate_specific'):
|
244
|
-
return super(CrateCompiler, self).visit_update(update_stmt, **kw)
|
245
|
-
|
246
|
-
self.isupdate = True
|
247
|
-
|
248
|
-
extra_froms = update_stmt._extra_froms
|
249
|
-
|
250
|
-
text = 'UPDATE '
|
251
|
-
|
252
|
-
if update_stmt._prefixes:
|
253
|
-
text += self._generate_prefixes(update_stmt,
|
254
|
-
update_stmt._prefixes, **kw)
|
255
|
-
|
256
|
-
table_text = self.update_tables_clause(update_stmt, update_stmt.table,
|
257
|
-
extra_froms, **kw)
|
258
|
-
|
259
|
-
dialect_hints = None
|
260
|
-
if update_stmt._hints:
|
261
|
-
dialect_hints, table_text = self._setup_crud_hints(
|
262
|
-
update_stmt, table_text
|
263
|
-
)
|
264
|
-
|
265
|
-
# CrateDB patch.
|
266
|
-
crud_params = self._get_crud_params(update_stmt, **kw)
|
267
|
-
|
268
|
-
text += table_text
|
269
|
-
|
270
|
-
text += ' SET '
|
271
|
-
|
272
|
-
# CrateDB patch begin.
|
273
|
-
include_table = extra_froms and \
|
274
|
-
self.render_table_with_column_in_update_from
|
275
|
-
|
276
|
-
set_clauses = []
|
277
|
-
|
278
|
-
for k, v in crud_params:
|
279
|
-
clause = k._compiler_dispatch(self,
|
280
|
-
include_table=include_table) + \
|
281
|
-
' = ' + v
|
282
|
-
set_clauses.append(clause)
|
283
|
-
|
284
|
-
for k, v in update_stmt.parameters.items():
|
285
|
-
if isinstance(k, str) and '[' in k:
|
286
|
-
bindparam = sa.sql.bindparam(k, v)
|
287
|
-
set_clauses.append(k + ' = ' + self.process(bindparam))
|
288
|
-
|
289
|
-
text += ', '.join(set_clauses)
|
290
|
-
# CrateDB patch end.
|
291
|
-
|
292
|
-
if self.returning or update_stmt._returning:
|
293
|
-
if not self.returning:
|
294
|
-
self.returning = update_stmt._returning
|
295
|
-
if self.returning_precedes_values:
|
296
|
-
text += " " + self.returning_clause(
|
297
|
-
update_stmt, self.returning)
|
298
|
-
|
299
|
-
if extra_froms:
|
300
|
-
extra_from_text = self.update_from_clause(
|
301
|
-
update_stmt,
|
302
|
-
update_stmt.table,
|
303
|
-
extra_froms,
|
304
|
-
dialect_hints,
|
305
|
-
**kw)
|
306
|
-
if extra_from_text:
|
307
|
-
text += " " + extra_from_text
|
308
|
-
|
309
|
-
if update_stmt._whereclause is not None:
|
310
|
-
t = self.process(update_stmt._whereclause)
|
311
|
-
if t:
|
312
|
-
text += " WHERE " + t
|
313
|
-
|
314
|
-
limit_clause = self.update_limit_clause(update_stmt)
|
315
|
-
if limit_clause:
|
316
|
-
text += " " + limit_clause
|
317
|
-
|
318
|
-
if self.returning and not self.returning_precedes_values:
|
319
|
-
text += " " + self.returning_clause(
|
320
|
-
update_stmt, self.returning)
|
321
|
-
|
322
|
-
return text
|
323
|
-
|
324
224
|
def limit_clause(self, select, **kw):
|
325
225
|
"""
|
326
226
|
Generate OFFSET / LIMIT clause, PostgreSQL-compatible.
|
327
227
|
"""
|
328
228
|
return PGCompiler.limit_clause(self, select, **kw)
|
329
|
-
|
330
|
-
def _get_crud_params(compiler, stmt, **kw):
|
331
|
-
""" extract values from crud parameters
|
332
|
-
taken from SQLAlchemy's crud module (since 1.0.x) and
|
333
|
-
adapted for Crate dialect"""
|
334
|
-
|
335
|
-
compiler.postfetch = []
|
336
|
-
compiler.insert_prefetch = []
|
337
|
-
compiler.update_prefetch = []
|
338
|
-
compiler.returning = []
|
339
|
-
|
340
|
-
# no parameters in the statement, no parameters in the
|
341
|
-
# compiled params - return binds for all columns
|
342
|
-
if compiler.column_keys is None and stmt.parameters is None:
|
343
|
-
return [(c, crud._create_bind_param(compiler, c, None,
|
344
|
-
required=True))
|
345
|
-
for c in stmt.table.columns]
|
346
|
-
|
347
|
-
if stmt._has_multi_parameters:
|
348
|
-
stmt_parameters = stmt.parameters[0]
|
349
|
-
else:
|
350
|
-
stmt_parameters = stmt.parameters
|
351
|
-
|
352
|
-
# getters - these are normally just column.key,
|
353
|
-
# but in the case of mysql multi-table update, the rules for
|
354
|
-
# .key must conditionally take tablename into account
|
355
|
-
_column_as_key, _getattr_col_key, _col_bind_name = \
|
356
|
-
crud._key_getters_for_crud_column(compiler, stmt)
|
357
|
-
|
358
|
-
# if we have statement parameters - set defaults in the
|
359
|
-
# compiled params
|
360
|
-
if compiler.column_keys is None:
|
361
|
-
parameters = {}
|
362
|
-
else:
|
363
|
-
parameters = dict((_column_as_key(key), crud.REQUIRED)
|
364
|
-
for key in compiler.column_keys
|
365
|
-
if not stmt_parameters or
|
366
|
-
key not in stmt_parameters)
|
367
|
-
|
368
|
-
# create a list of column assignment clauses as tuples
|
369
|
-
values = []
|
370
|
-
|
371
|
-
if stmt_parameters is not None:
|
372
|
-
crud._get_stmt_parameters_params(
|
373
|
-
compiler,
|
374
|
-
parameters, stmt_parameters, _column_as_key, values, kw)
|
375
|
-
|
376
|
-
check_columns = {}
|
377
|
-
|
378
|
-
crud._scan_cols(compiler, stmt, parameters,
|
379
|
-
_getattr_col_key, _column_as_key,
|
380
|
-
_col_bind_name, check_columns, values, kw)
|
381
|
-
|
382
|
-
if stmt._has_multi_parameters:
|
383
|
-
values = crud._extend_values_for_multiparams(compiler, stmt,
|
384
|
-
values, kw)
|
385
|
-
|
386
|
-
return values
|
387
|
-
|
388
|
-
def visit_update_14(self, update_stmt, **kw):
|
389
|
-
|
390
|
-
compile_state = update_stmt._compile_state_factory(
|
391
|
-
update_stmt, self, **kw
|
392
|
-
)
|
393
|
-
update_stmt = compile_state.statement
|
394
|
-
|
395
|
-
toplevel = not self.stack
|
396
|
-
if toplevel:
|
397
|
-
self.isupdate = True
|
398
|
-
if not self.compile_state:
|
399
|
-
self.compile_state = compile_state
|
400
|
-
|
401
|
-
extra_froms = compile_state._extra_froms
|
402
|
-
is_multitable = bool(extra_froms)
|
403
|
-
|
404
|
-
if is_multitable:
|
405
|
-
# main table might be a JOIN
|
406
|
-
main_froms = set(selectable._from_objects(update_stmt.table))
|
407
|
-
render_extra_froms = [
|
408
|
-
f for f in extra_froms if f not in main_froms
|
409
|
-
]
|
410
|
-
correlate_froms = main_froms.union(extra_froms)
|
411
|
-
else:
|
412
|
-
render_extra_froms = []
|
413
|
-
correlate_froms = {update_stmt.table}
|
414
|
-
|
415
|
-
self.stack.append(
|
416
|
-
{
|
417
|
-
"correlate_froms": correlate_froms,
|
418
|
-
"asfrom_froms": correlate_froms,
|
419
|
-
"selectable": update_stmt,
|
420
|
-
}
|
421
|
-
)
|
422
|
-
|
423
|
-
text = "UPDATE "
|
424
|
-
|
425
|
-
if update_stmt._prefixes:
|
426
|
-
text += self._generate_prefixes(
|
427
|
-
update_stmt, update_stmt._prefixes, **kw
|
428
|
-
)
|
429
|
-
|
430
|
-
table_text = self.update_tables_clause(
|
431
|
-
update_stmt, update_stmt.table, render_extra_froms, **kw
|
432
|
-
)
|
433
|
-
|
434
|
-
# CrateDB patch.
|
435
|
-
crud_params = _get_crud_params_14(
|
436
|
-
self, update_stmt, compile_state, **kw
|
437
|
-
)
|
438
|
-
|
439
|
-
if update_stmt._hints:
|
440
|
-
dialect_hints, table_text = self._setup_crud_hints(
|
441
|
-
update_stmt, table_text
|
442
|
-
)
|
443
|
-
else:
|
444
|
-
dialect_hints = None
|
445
|
-
|
446
|
-
if update_stmt._independent_ctes:
|
447
|
-
for cte in update_stmt._independent_ctes:
|
448
|
-
cte._compiler_dispatch(self, **kw)
|
449
|
-
|
450
|
-
text += table_text
|
451
|
-
|
452
|
-
text += " SET "
|
453
|
-
|
454
|
-
# CrateDB patch begin.
|
455
|
-
include_table = extra_froms and \
|
456
|
-
self.render_table_with_column_in_update_from
|
457
|
-
|
458
|
-
set_clauses = []
|
459
|
-
|
460
|
-
for c, expr, value in crud_params:
|
461
|
-
key = c._compiler_dispatch(self, include_table=include_table)
|
462
|
-
clause = key + ' = ' + value
|
463
|
-
set_clauses.append(clause)
|
464
|
-
|
465
|
-
for k, v in compile_state._dict_parameters.items():
|
466
|
-
if isinstance(k, str) and '[' in k:
|
467
|
-
bindparam = sa.sql.bindparam(k, v)
|
468
|
-
clause = k + ' = ' + self.process(bindparam)
|
469
|
-
set_clauses.append(clause)
|
470
|
-
|
471
|
-
text += ', '.join(set_clauses)
|
472
|
-
# CrateDB patch end.
|
473
|
-
|
474
|
-
if self.returning or update_stmt._returning:
|
475
|
-
if self.returning_precedes_values:
|
476
|
-
text += " " + self.returning_clause(
|
477
|
-
update_stmt, self.returning or update_stmt._returning
|
478
|
-
)
|
479
|
-
|
480
|
-
if extra_froms:
|
481
|
-
extra_from_text = self.update_from_clause(
|
482
|
-
update_stmt,
|
483
|
-
update_stmt.table,
|
484
|
-
render_extra_froms,
|
485
|
-
dialect_hints,
|
486
|
-
**kw
|
487
|
-
)
|
488
|
-
if extra_from_text:
|
489
|
-
text += " " + extra_from_text
|
490
|
-
|
491
|
-
if update_stmt._where_criteria:
|
492
|
-
t = self._generate_delimited_and_list(
|
493
|
-
update_stmt._where_criteria, **kw
|
494
|
-
)
|
495
|
-
if t:
|
496
|
-
text += " WHERE " + t
|
497
|
-
|
498
|
-
limit_clause = self.update_limit_clause(update_stmt)
|
499
|
-
if limit_clause:
|
500
|
-
text += " " + limit_clause
|
501
|
-
|
502
|
-
if (
|
503
|
-
self.returning or update_stmt._returning
|
504
|
-
) and not self.returning_precedes_values:
|
505
|
-
text += " " + self.returning_clause(
|
506
|
-
update_stmt, self.returning or update_stmt._returning
|
507
|
-
)
|
508
|
-
|
509
|
-
if self.ctes:
|
510
|
-
nesting_level = len(self.stack) if not toplevel else None
|
511
|
-
text = self._render_cte_clause(nesting_level=nesting_level) + text
|
512
|
-
|
513
|
-
self.stack.pop(-1)
|
514
|
-
|
515
|
-
return text
|
516
|
-
|
517
|
-
|
518
|
-
def _get_crud_params_14(compiler, stmt, compile_state, **kw):
|
519
|
-
"""create a set of tuples representing column/string pairs for use
|
520
|
-
in an INSERT or UPDATE statement.
|
521
|
-
|
522
|
-
Also generates the Compiled object's postfetch, prefetch, and
|
523
|
-
returning column collections, used for default handling and ultimately
|
524
|
-
populating the CursorResult's prefetch_cols() and postfetch_cols()
|
525
|
-
collections.
|
526
|
-
|
527
|
-
"""
|
528
|
-
from sqlalchemy.sql.crud import _key_getters_for_crud_column
|
529
|
-
from sqlalchemy.sql.crud import _create_bind_param
|
530
|
-
from sqlalchemy.sql.crud import REQUIRED
|
531
|
-
from sqlalchemy.sql.crud import _get_stmt_parameter_tuples_params
|
532
|
-
from sqlalchemy.sql.crud import _get_update_multitable_params
|
533
|
-
from sqlalchemy.sql.crud import _scan_insert_from_select_cols
|
534
|
-
from sqlalchemy.sql.crud import _scan_cols
|
535
|
-
from sqlalchemy import exc # noqa: F401
|
536
|
-
from sqlalchemy.sql.crud import _extend_values_for_multiparams
|
537
|
-
|
538
|
-
compiler.postfetch = []
|
539
|
-
compiler.insert_prefetch = []
|
540
|
-
compiler.update_prefetch = []
|
541
|
-
compiler.returning = []
|
542
|
-
|
543
|
-
# getters - these are normally just column.key,
|
544
|
-
# but in the case of mysql multi-table update, the rules for
|
545
|
-
# .key must conditionally take tablename into account
|
546
|
-
(
|
547
|
-
_column_as_key,
|
548
|
-
_getattr_col_key,
|
549
|
-
_col_bind_name,
|
550
|
-
) = getters = _key_getters_for_crud_column(compiler, stmt, compile_state)
|
551
|
-
|
552
|
-
compiler._key_getters_for_crud_column = getters
|
553
|
-
|
554
|
-
# no parameters in the statement, no parameters in the
|
555
|
-
# compiled params - return binds for all columns
|
556
|
-
if compiler.column_keys is None and compile_state._no_parameters:
|
557
|
-
return [
|
558
|
-
(
|
559
|
-
c,
|
560
|
-
compiler.preparer.format_column(c),
|
561
|
-
_create_bind_param(compiler, c, None, required=True),
|
562
|
-
)
|
563
|
-
for c in stmt.table.columns
|
564
|
-
]
|
565
|
-
|
566
|
-
if compile_state._has_multi_parameters:
|
567
|
-
spd = compile_state._multi_parameters[0]
|
568
|
-
stmt_parameter_tuples = list(spd.items())
|
569
|
-
elif compile_state._ordered_values:
|
570
|
-
spd = compile_state._dict_parameters
|
571
|
-
stmt_parameter_tuples = compile_state._ordered_values
|
572
|
-
elif compile_state._dict_parameters:
|
573
|
-
spd = compile_state._dict_parameters
|
574
|
-
stmt_parameter_tuples = list(spd.items())
|
575
|
-
else:
|
576
|
-
stmt_parameter_tuples = spd = None
|
577
|
-
|
578
|
-
# if we have statement parameters - set defaults in the
|
579
|
-
# compiled params
|
580
|
-
if compiler.column_keys is None:
|
581
|
-
parameters = {}
|
582
|
-
elif stmt_parameter_tuples:
|
583
|
-
parameters = dict(
|
584
|
-
(_column_as_key(key), REQUIRED)
|
585
|
-
for key in compiler.column_keys
|
586
|
-
if key not in spd
|
587
|
-
)
|
588
|
-
else:
|
589
|
-
parameters = dict(
|
590
|
-
(_column_as_key(key), REQUIRED) for key in compiler.column_keys
|
591
|
-
)
|
592
|
-
|
593
|
-
# create a list of column assignment clauses as tuples
|
594
|
-
values = []
|
595
|
-
|
596
|
-
if stmt_parameter_tuples is not None:
|
597
|
-
_get_stmt_parameter_tuples_params(
|
598
|
-
compiler,
|
599
|
-
compile_state,
|
600
|
-
parameters,
|
601
|
-
stmt_parameter_tuples,
|
602
|
-
_column_as_key,
|
603
|
-
values,
|
604
|
-
kw,
|
605
|
-
)
|
606
|
-
|
607
|
-
check_columns = {}
|
608
|
-
|
609
|
-
# special logic that only occurs for multi-table UPDATE
|
610
|
-
# statements
|
611
|
-
if compile_state.isupdate and compile_state.is_multitable:
|
612
|
-
_get_update_multitable_params(
|
613
|
-
compiler,
|
614
|
-
stmt,
|
615
|
-
compile_state,
|
616
|
-
stmt_parameter_tuples,
|
617
|
-
check_columns,
|
618
|
-
_col_bind_name,
|
619
|
-
_getattr_col_key,
|
620
|
-
values,
|
621
|
-
kw,
|
622
|
-
)
|
623
|
-
|
624
|
-
if compile_state.isinsert and stmt._select_names:
|
625
|
-
_scan_insert_from_select_cols(
|
626
|
-
compiler,
|
627
|
-
stmt,
|
628
|
-
compile_state,
|
629
|
-
parameters,
|
630
|
-
_getattr_col_key,
|
631
|
-
_column_as_key,
|
632
|
-
_col_bind_name,
|
633
|
-
check_columns,
|
634
|
-
values,
|
635
|
-
kw,
|
636
|
-
)
|
637
|
-
else:
|
638
|
-
_scan_cols(
|
639
|
-
compiler,
|
640
|
-
stmt,
|
641
|
-
compile_state,
|
642
|
-
parameters,
|
643
|
-
_getattr_col_key,
|
644
|
-
_column_as_key,
|
645
|
-
_col_bind_name,
|
646
|
-
check_columns,
|
647
|
-
values,
|
648
|
-
kw,
|
649
|
-
)
|
650
|
-
|
651
|
-
# CrateDB patch.
|
652
|
-
#
|
653
|
-
# This sanity check performed by SQLAlchemy currently needs to be
|
654
|
-
# deactivated in order to satisfy the rewriting logic of the CrateDB
|
655
|
-
# dialect in `rewrite_update` and `visit_update`.
|
656
|
-
#
|
657
|
-
# It can be quickly reproduced by activating this section and running the
|
658
|
-
# test cases::
|
659
|
-
#
|
660
|
-
# ./bin/test -vvvv -t dict_test
|
661
|
-
#
|
662
|
-
# That croaks like::
|
663
|
-
#
|
664
|
-
# sqlalchemy.exc.CompileError: Unconsumed column names: characters_name, data['nested']
|
665
|
-
#
|
666
|
-
# TODO: Investigate why this is actually happening and eventually mitigate
|
667
|
-
# the root cause.
|
668
|
-
"""
|
669
|
-
if parameters and stmt_parameter_tuples:
|
670
|
-
check = (
|
671
|
-
set(parameters)
|
672
|
-
.intersection(_column_as_key(k) for k, v in stmt_parameter_tuples)
|
673
|
-
.difference(check_columns)
|
674
|
-
)
|
675
|
-
if check:
|
676
|
-
raise exc.CompileError(
|
677
|
-
"Unconsumed column names: %s"
|
678
|
-
% (", ".join("%s" % (c,) for c in check))
|
679
|
-
)
|
680
|
-
"""
|
681
|
-
|
682
|
-
if compile_state._has_multi_parameters:
|
683
|
-
values = _extend_values_for_multiparams(
|
684
|
-
compiler,
|
685
|
-
stmt,
|
686
|
-
compile_state,
|
687
|
-
values,
|
688
|
-
_column_as_key,
|
689
|
-
kw,
|
690
|
-
)
|
691
|
-
elif (
|
692
|
-
not values
|
693
|
-
and compiler.for_executemany # noqa: W503
|
694
|
-
and compiler.dialect.supports_default_metavalue # noqa: W503
|
695
|
-
):
|
696
|
-
# convert an "INSERT DEFAULT VALUES"
|
697
|
-
# into INSERT (firstcol) VALUES (DEFAULT) which can be turned
|
698
|
-
# into an in-place multi values. This supports
|
699
|
-
# insert_executemany_returning mode :)
|
700
|
-
values = [
|
701
|
-
(
|
702
|
-
stmt.table.columns[0],
|
703
|
-
compiler.preparer.format_column(stmt.table.columns[0]),
|
704
|
-
"DEFAULT",
|
705
|
-
)
|
706
|
-
]
|
707
|
-
|
708
|
-
return values
|
@@ -28,11 +28,11 @@ from sqlalchemy.sql import functions
|
|
28
28
|
from sqlalchemy.util import asbool, to_list
|
29
29
|
|
30
30
|
from .compiler import (
|
31
|
-
CrateCompiler,
|
32
31
|
CrateTypeCompiler,
|
33
32
|
CrateDDLCompiler
|
34
33
|
)
|
35
34
|
from crate.client.exceptions import TimezoneUnawareException
|
35
|
+
from .sa_version import SA_VERSION, SA_1_4, SA_2_0
|
36
36
|
from .types import Object, ObjectArray
|
37
37
|
|
38
38
|
TYPES_MAP = {
|
@@ -155,10 +155,21 @@ colspecs = {
|
|
155
155
|
}
|
156
156
|
|
157
157
|
|
158
|
+
if SA_VERSION >= SA_2_0:
|
159
|
+
from .compat.core20 import CrateCompilerSA20
|
160
|
+
statement_compiler = CrateCompilerSA20
|
161
|
+
elif SA_VERSION >= SA_1_4:
|
162
|
+
from .compat.core14 import CrateCompilerSA14
|
163
|
+
statement_compiler = CrateCompilerSA14
|
164
|
+
else:
|
165
|
+
from .compat.core10 import CrateCompilerSA10
|
166
|
+
statement_compiler = CrateCompilerSA10
|
167
|
+
|
168
|
+
|
158
169
|
class CrateDialect(default.DefaultDialect):
|
159
170
|
name = 'crate'
|
160
171
|
driver = 'crate-python'
|
161
|
-
statement_compiler =
|
172
|
+
statement_compiler = statement_compiler
|
162
173
|
ddl_compiler = CrateDDLCompiler
|
163
174
|
type_compiler = CrateTypeCompiler
|
164
175
|
supports_native_boolean = True
|
@@ -208,19 +219,23 @@ class CrateDialect(default.DefaultDialect):
|
|
208
219
|
return tuple(connection.connection.lowest_server_version.version)
|
209
220
|
|
210
221
|
@classmethod
|
211
|
-
def
|
222
|
+
def import_dbapi(cls):
|
212
223
|
from crate import client
|
213
224
|
return client
|
214
225
|
|
215
|
-
|
216
|
-
|
226
|
+
@classmethod
|
227
|
+
def dbapi(cls):
|
228
|
+
return cls.import_dbapi()
|
229
|
+
|
230
|
+
def has_schema(self, connection, schema, **kw):
|
231
|
+
return schema in self.get_schema_names(connection, **kw)
|
217
232
|
|
218
|
-
def has_table(self, connection, table_name, schema=None):
|
219
|
-
return table_name in self.get_table_names(connection, schema=schema)
|
233
|
+
def has_table(self, connection, table_name, schema=None, **kw):
|
234
|
+
return table_name in self.get_table_names(connection, schema=schema, **kw)
|
220
235
|
|
221
236
|
@reflection.cache
|
222
237
|
def get_schema_names(self, connection, **kw):
|
223
|
-
cursor = connection.
|
238
|
+
cursor = connection.exec_driver_sql(
|
224
239
|
"select schema_name "
|
225
240
|
"from information_schema.schemata "
|
226
241
|
"order by schema_name asc"
|
@@ -229,21 +244,21 @@ class CrateDialect(default.DefaultDialect):
|
|
229
244
|
|
230
245
|
@reflection.cache
|
231
246
|
def get_table_names(self, connection, schema=None, **kw):
|
232
|
-
cursor = connection.
|
247
|
+
cursor = connection.exec_driver_sql(
|
233
248
|
"SELECT table_name FROM information_schema.tables "
|
234
249
|
"WHERE {0} = ? "
|
235
250
|
"AND table_type = 'BASE TABLE' "
|
236
251
|
"ORDER BY table_name ASC, {0} ASC".format(self.schema_column),
|
237
|
-
|
252
|
+
(schema or self.default_schema_name, )
|
238
253
|
)
|
239
254
|
return [row[0] for row in cursor.fetchall()]
|
240
255
|
|
241
256
|
@reflection.cache
|
242
257
|
def get_view_names(self, connection, schema=None, **kw):
|
243
|
-
cursor = connection.
|
258
|
+
cursor = connection.exec_driver_sql(
|
244
259
|
"SELECT table_name FROM information_schema.views "
|
245
260
|
"ORDER BY table_name ASC, {0} ASC".format(self.schema_column),
|
246
|
-
|
261
|
+
(schema or self.default_schema_name, )
|
247
262
|
)
|
248
263
|
return [row[0] for row in cursor.fetchall()]
|
249
264
|
|
@@ -254,11 +269,11 @@ class CrateDialect(default.DefaultDialect):
|
|
254
269
|
"WHERE table_name = ? AND {0} = ? " \
|
255
270
|
"AND column_name !~ ?" \
|
256
271
|
.format(self.schema_column)
|
257
|
-
cursor = connection.
|
272
|
+
cursor = connection.exec_driver_sql(
|
258
273
|
query,
|
259
|
-
|
274
|
+
(table_name,
|
260
275
|
schema or self.default_schema_name,
|
261
|
-
r"(.*)\[\'(.*)\'\]"
|
276
|
+
r"(.*)\[\'(.*)\'\]") # regex to filter subscript
|
262
277
|
)
|
263
278
|
return [self._create_column_info(row) for row in cursor.fetchall()]
|
264
279
|
|
@@ -293,9 +308,9 @@ class CrateDialect(default.DefaultDialect):
|
|
293
308
|
rows = result.fetchone()
|
294
309
|
return set(rows[0] if rows else [])
|
295
310
|
|
296
|
-
pk_result = engine.
|
311
|
+
pk_result = engine.exec_driver_sql(
|
297
312
|
query,
|
298
|
-
|
313
|
+
(table_name, schema or self.default_schema_name)
|
299
314
|
)
|
300
315
|
pks = result_fun(pk_result)
|
301
316
|
return {'constrained_columns': pks,
|
@@ -20,8 +20,9 @@
|
|
20
20
|
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
21
|
|
22
22
|
import sqlalchemy as sa
|
23
|
-
from
|
23
|
+
from crate.client._pep440 import Version
|
24
24
|
|
25
|
-
SA_VERSION =
|
25
|
+
SA_VERSION = Version(sa.__version__)
|
26
26
|
|
27
|
-
SA_1_4 =
|
27
|
+
SA_1_4 = Version('1.4.0b1')
|
28
|
+
SA_2_0 = Version('2.0.0')
|
@@ -1,5 +1,14 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
+
from ..compat.api13 import monkeypatch_amend_select_sa14, monkeypatch_add_connectionfairy_driver_connection
|
4
|
+
from ..sa_version import SA_1_4, SA_VERSION
|
5
|
+
|
6
|
+
# `sql.select()` of SQLAlchemy 1.3 uses old calling semantics,
|
7
|
+
# but the test cases already need the modern ones.
|
8
|
+
if SA_VERSION < SA_1_4:
|
9
|
+
monkeypatch_amend_select_sa14()
|
10
|
+
monkeypatch_add_connectionfairy_driver_connection()
|
11
|
+
|
3
12
|
from unittest import TestSuite, makeSuite
|
4
13
|
from .connection_test import SqlAlchemyConnectionTest
|
5
14
|
from .dict_test import SqlAlchemyDictTypeTest
|
@@ -9,10 +18,11 @@ from .update_test import SqlAlchemyUpdateTest
|
|
9
18
|
from .match_test import SqlAlchemyMatchTest
|
10
19
|
from .bulk_test import SqlAlchemyBulkTest
|
11
20
|
from .insert_from_select_test import SqlAlchemyInsertFromSelectTest
|
12
|
-
from .create_table_test import
|
21
|
+
from .create_table_test import SqlAlchemyCreateTableTest
|
13
22
|
from .array_test import SqlAlchemyArrayTypeTest
|
14
|
-
from .dialect_test import
|
15
|
-
from .function_test import
|
23
|
+
from .dialect_test import SqlAlchemyDialectTest
|
24
|
+
from .function_test import SqlAlchemyFunctionTest
|
25
|
+
from .warnings_test import SqlAlchemyWarningsTest
|
16
26
|
|
17
27
|
|
18
28
|
def test_suite():
|
@@ -23,11 +33,12 @@ def test_suite():
|
|
23
33
|
tests.addTest(makeSuite(SqlAlchemyCompilerTest))
|
24
34
|
tests.addTest(makeSuite(SqlAlchemyUpdateTest))
|
25
35
|
tests.addTest(makeSuite(SqlAlchemyMatchTest))
|
26
|
-
tests.addTest(makeSuite(
|
36
|
+
tests.addTest(makeSuite(SqlAlchemyCreateTableTest))
|
27
37
|
tests.addTest(makeSuite(SqlAlchemyBulkTest))
|
28
38
|
tests.addTest(makeSuite(SqlAlchemyInsertFromSelectTest))
|
29
39
|
tests.addTest(makeSuite(SqlAlchemyInsertFromSelectTest))
|
30
|
-
tests.addTest(makeSuite(
|
31
|
-
tests.addTest(makeSuite(
|
40
|
+
tests.addTest(makeSuite(SqlAlchemyDialectTest))
|
41
|
+
tests.addTest(makeSuite(SqlAlchemyFunctionTest))
|
32
42
|
tests.addTest(makeSuite(SqlAlchemyArrayTypeTest))
|
43
|
+
tests.addTest(makeSuite(SqlAlchemyWarningsTest))
|
33
44
|
return tests
|