sqlalchemy-iris 0.16.1b1__py3-none-any.whl → 0.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlalchemy_iris/__init__.py +3 -2
- sqlalchemy_iris/base.py +5 -1
- sqlalchemy_iris/intersystems/__init__.py +167 -0
- sqlalchemy_iris/intersystems/cursor.py +17 -0
- sqlalchemy_iris/intersystems/dbapi.py +67 -0
- sqlalchemy_iris/requirements.py +1236 -16
- sqlalchemy_iris/types.py +32 -0
- {sqlalchemy_iris-0.16.1b1.dist-info → sqlalchemy_iris-0.17.0.dist-info}/METADATA +23 -1
- {sqlalchemy_iris-0.16.1b1.dist-info → sqlalchemy_iris-0.17.0.dist-info}/RECORD +13 -10
- {sqlalchemy_iris-0.16.1b1.dist-info → sqlalchemy_iris-0.17.0.dist-info}/entry_points.txt +1 -0
- {sqlalchemy_iris-0.16.1b1.dist-info → sqlalchemy_iris-0.17.0.dist-info}/LICENSE +0 -0
- {sqlalchemy_iris-0.16.1b1.dist-info → sqlalchemy_iris-0.17.0.dist-info}/WHEEL +0 -0
- {sqlalchemy_iris-0.16.1b1.dist-info → sqlalchemy_iris-0.17.0.dist-info}/top_level.txt +0 -0
sqlalchemy_iris/requirements.py
CHANGED
@@ -16,10 +16,28 @@ from sqlalchemy.testing import exclusions
|
|
16
16
|
|
17
17
|
class Requirements(SuiteRequirements, AlembicRequirements):
|
18
18
|
|
19
|
+
@property
|
20
|
+
def community_driver(self):
|
21
|
+
return exclusions.only_if(
|
22
|
+
lambda config: not config.db.dialect.driver == "intersystems",
|
23
|
+
"Only on community driver"
|
24
|
+
)
|
25
|
+
|
26
|
+
@property
|
27
|
+
def intersystems_driver(self):
|
28
|
+
return exclusions.only_if(
|
29
|
+
lambda config: config.db.dialect.driver == "intersystems",
|
30
|
+
"InterSystems official driver"
|
31
|
+
)
|
32
|
+
|
19
33
|
@property
|
20
34
|
def array_type(self):
|
21
35
|
return exclusions.closed()
|
22
36
|
|
37
|
+
@property
|
38
|
+
def table_ddl_if_exists(self):
|
39
|
+
return exclusions.open()
|
40
|
+
|
23
41
|
@property
|
24
42
|
def uuid_data_type(self):
|
25
43
|
return exclusions.open()
|
@@ -185,21 +203,6 @@ class Requirements(SuiteRequirements, AlembicRequirements):
|
|
185
203
|
|
186
204
|
return exclusions.closed()
|
187
205
|
|
188
|
-
@property
|
189
|
-
def order_by_label_with_expression(self):
|
190
|
-
"""target backend supports ORDER BY a column label within an
|
191
|
-
expression.
|
192
|
-
|
193
|
-
Basically this::
|
194
|
-
|
195
|
-
select data as foo from test order by foo || 'bar'
|
196
|
-
|
197
|
-
Lots of databases including PostgreSQL don't support this,
|
198
|
-
so this is off by default.
|
199
|
-
|
200
|
-
"""
|
201
|
-
return exclusions.closed()
|
202
|
-
|
203
206
|
@property
|
204
207
|
def memory_process_intensive(self):
|
205
208
|
"""Driver is able to handle the memory tests which run in a subprocess
|
@@ -240,7 +243,7 @@ class Requirements(SuiteRequirements, AlembicRequirements):
|
|
240
243
|
def get_isolation_levels(self, config):
|
241
244
|
levels = set(config.db.dialect._isolation_lookup)
|
242
245
|
|
243
|
-
default = "READ
|
246
|
+
default = "READ UNCOMMITTED"
|
244
247
|
levels.add("AUTOCOMMIT")
|
245
248
|
|
246
249
|
return {"default": default, "supported": levels}
|
@@ -287,3 +290,1220 @@ class Requirements(SuiteRequirements, AlembicRequirements):
|
|
287
290
|
@property
|
288
291
|
def iris_vector(self):
|
289
292
|
return only_on(lambda config: self._iris_vector(config))
|
293
|
+
|
294
|
+
@property
|
295
|
+
def index_ddl_if_exists(self):
|
296
|
+
"""target platform supports IF NOT EXISTS / IF EXISTS for indexes."""
|
297
|
+
|
298
|
+
return exclusions.closed()
|
299
|
+
|
300
|
+
@property
|
301
|
+
def foreign_keys(self):
|
302
|
+
"""Target database must support foreign keys."""
|
303
|
+
|
304
|
+
return exclusions.open()
|
305
|
+
|
306
|
+
@property
|
307
|
+
def foreign_keys_reflect_as_index(self):
|
308
|
+
"""Target database creates an index that's reflected for
|
309
|
+
foreign keys."""
|
310
|
+
|
311
|
+
return exclusions.closed()
|
312
|
+
|
313
|
+
@property
|
314
|
+
def table_value_constructor(self):
|
315
|
+
"""Database / dialect supports a query like::
|
316
|
+
|
317
|
+
SELECT * FROM VALUES ( (c1, c2), (c1, c2), ...)
|
318
|
+
AS some_table(col1, col2)
|
319
|
+
|
320
|
+
SQLAlchemy generates this with the :func:`_sql.values` function.
|
321
|
+
|
322
|
+
"""
|
323
|
+
return exclusions.closed()
|
324
|
+
|
325
|
+
@property
|
326
|
+
def standard_cursor_sql(self):
|
327
|
+
"""Target database passes SQL-92 style statements to cursor.execute()
|
328
|
+
when a statement like select() or insert() is run.
|
329
|
+
|
330
|
+
A very small portion of dialect-level tests will ensure that certain
|
331
|
+
conditions are present in SQL strings, and these tests use very basic
|
332
|
+
SQL that will work on any SQL-like platform in order to assert results.
|
333
|
+
|
334
|
+
It's normally a given for any pep-249 DBAPI that a statement like
|
335
|
+
"SELECT id, name FROM table WHERE some_table.id=5" will work.
|
336
|
+
However, there are dialects that don't actually produce SQL Strings
|
337
|
+
and instead may work with symbolic objects instead, or dialects that
|
338
|
+
aren't working with SQL, so for those this requirement can be marked
|
339
|
+
as excluded.
|
340
|
+
|
341
|
+
"""
|
342
|
+
|
343
|
+
return exclusions.open()
|
344
|
+
|
345
|
+
@property
|
346
|
+
def on_update_cascade(self):
|
347
|
+
"""target database must support ON UPDATE..CASCADE behavior in
|
348
|
+
foreign keys."""
|
349
|
+
|
350
|
+
return exclusions.open()
|
351
|
+
|
352
|
+
@property
|
353
|
+
def non_updating_cascade(self):
|
354
|
+
"""target database must *not* support ON UPDATE..CASCADE behavior in
|
355
|
+
foreign keys."""
|
356
|
+
return exclusions.closed()
|
357
|
+
|
358
|
+
@property
|
359
|
+
def deferrable_fks(self):
|
360
|
+
return exclusions.closed()
|
361
|
+
|
362
|
+
@property
|
363
|
+
def on_update_or_deferrable_fks(self):
|
364
|
+
# TODO: exclusions should be composable,
|
365
|
+
# somehow only_if([x, y]) isn't working here, negation/conjunctions
|
366
|
+
# getting confused.
|
367
|
+
return exclusions.only_if(
|
368
|
+
lambda: self.on_update_cascade.enabled
|
369
|
+
or self.deferrable_fks.enabled
|
370
|
+
)
|
371
|
+
|
372
|
+
@property
|
373
|
+
def self_referential_foreign_keys(self):
|
374
|
+
"""Target database must support self-referential foreign keys."""
|
375
|
+
|
376
|
+
return exclusions.open()
|
377
|
+
|
378
|
+
@property
|
379
|
+
def foreign_key_ddl(self):
|
380
|
+
"""Target database must support the DDL phrases for FOREIGN KEY."""
|
381
|
+
|
382
|
+
return exclusions.open()
|
383
|
+
|
384
|
+
@property
|
385
|
+
def named_constraints(self):
|
386
|
+
"""target database must support names for constraints."""
|
387
|
+
|
388
|
+
return exclusions.open()
|
389
|
+
|
390
|
+
@property
|
391
|
+
def implicitly_named_constraints(self):
|
392
|
+
"""target database must apply names to unnamed constraints."""
|
393
|
+
|
394
|
+
return exclusions.open()
|
395
|
+
|
396
|
+
@property
|
397
|
+
def unusual_column_name_characters(self):
|
398
|
+
"""target database allows column names that have unusual characters
|
399
|
+
in them, such as dots, spaces, slashes, or percent signs.
|
400
|
+
|
401
|
+
The column names are as always in such a case quoted, however the
|
402
|
+
DB still needs to support those characters in the name somehow.
|
403
|
+
|
404
|
+
"""
|
405
|
+
return exclusions.open()
|
406
|
+
|
407
|
+
@property
|
408
|
+
def subqueries(self):
|
409
|
+
"""Target database must support subqueries."""
|
410
|
+
|
411
|
+
return exclusions.open()
|
412
|
+
|
413
|
+
@property
|
414
|
+
def offset(self):
|
415
|
+
"""target database can render OFFSET, or an equivalent, in a
|
416
|
+
SELECT.
|
417
|
+
"""
|
418
|
+
|
419
|
+
return exclusions.open()
|
420
|
+
|
421
|
+
@property
|
422
|
+
def bound_limit_offset(self):
|
423
|
+
"""target database can render LIMIT and/or OFFSET using a bound
|
424
|
+
parameter
|
425
|
+
"""
|
426
|
+
|
427
|
+
return exclusions.open()
|
428
|
+
|
429
|
+
@property
|
430
|
+
def sql_expression_limit_offset(self):
|
431
|
+
"""target database can render LIMIT and/or OFFSET with a complete
|
432
|
+
SQL expression, such as one that uses the addition operator.
|
433
|
+
parameter
|
434
|
+
"""
|
435
|
+
|
436
|
+
return exclusions.open()
|
437
|
+
|
438
|
+
@property
|
439
|
+
def parens_in_union_contained_select_w_limit_offset(self):
|
440
|
+
"""Target database must support parenthesized SELECT in UNION
|
441
|
+
when LIMIT/OFFSET is specifically present.
|
442
|
+
|
443
|
+
E.g. (SELECT ...) UNION (SELECT ..)
|
444
|
+
"""
|
445
|
+
return exclusions.open()
|
446
|
+
|
447
|
+
@property
|
448
|
+
def parens_in_union_contained_select_wo_limit_offset(self):
|
449
|
+
"""Target database must support parenthesized SELECT in UNION
|
450
|
+
when OFFSET/LIMIT is specifically not present.
|
451
|
+
|
452
|
+
E.g. (SELECT ... LIMIT ..) UNION (SELECT .. OFFSET ..)
|
453
|
+
"""
|
454
|
+
return exclusions.open()
|
455
|
+
|
456
|
+
@property
|
457
|
+
def nullable_booleans(self):
|
458
|
+
"""Target database allows boolean columns to store NULL."""
|
459
|
+
|
460
|
+
return exclusions.open()
|
461
|
+
|
462
|
+
@property
|
463
|
+
def nullsordering(self):
|
464
|
+
"""Target backends that support nulls ordering."""
|
465
|
+
|
466
|
+
return exclusions.closed()
|
467
|
+
|
468
|
+
@property
|
469
|
+
def standalone_binds(self):
|
470
|
+
"""target database/driver supports bound parameters as column
|
471
|
+
expressions without being in the context of a typed column.
|
472
|
+
"""
|
473
|
+
return exclusions.open()
|
474
|
+
|
475
|
+
@property
|
476
|
+
def standalone_null_binds_whereclause(self):
|
477
|
+
"""target database/driver supports bound parameters with NULL in the
|
478
|
+
WHERE clause, in situations where it has to be typed.
|
479
|
+
|
480
|
+
"""
|
481
|
+
return exclusions.open()
|
482
|
+
|
483
|
+
@property
|
484
|
+
def window_functions(self):
|
485
|
+
"""Target database must support window functions."""
|
486
|
+
return exclusions.closed()
|
487
|
+
|
488
|
+
@property
|
489
|
+
def autoincrement_insert(self):
|
490
|
+
"""target platform generates new surrogate integer primary key values
|
491
|
+
when insert() is executed, excluding the pk column."""
|
492
|
+
|
493
|
+
return exclusions.open()
|
494
|
+
|
495
|
+
@property
|
496
|
+
def fetch_rows_post_commit(self):
|
497
|
+
"""target platform will allow cursor.fetchone() to proceed after a
|
498
|
+
COMMIT.
|
499
|
+
|
500
|
+
Typically this refers to an INSERT statement with RETURNING which
|
501
|
+
is invoked within "autocommit". If the row can be returned
|
502
|
+
after the autocommit, then this rule can be open.
|
503
|
+
|
504
|
+
"""
|
505
|
+
|
506
|
+
return exclusions.open()
|
507
|
+
|
508
|
+
@property
|
509
|
+
def group_by_complex_expression(self):
|
510
|
+
"""target platform supports SQL expressions in GROUP BY
|
511
|
+
|
512
|
+
e.g.
|
513
|
+
|
514
|
+
SELECT x + y AS somelabel FROM table GROUP BY x + y
|
515
|
+
|
516
|
+
"""
|
517
|
+
|
518
|
+
return exclusions.open()
|
519
|
+
|
520
|
+
@property
|
521
|
+
def sane_rowcount(self):
|
522
|
+
return exclusions.skip_if(
|
523
|
+
lambda config: not config.db.dialect.supports_sane_rowcount,
|
524
|
+
"driver doesn't support 'sane' rowcount",
|
525
|
+
)
|
526
|
+
|
527
|
+
@property
|
528
|
+
def sane_multi_rowcount(self):
|
529
|
+
return exclusions.fails_if(
|
530
|
+
lambda config: not config.db.dialect.supports_sane_multi_rowcount,
|
531
|
+
"driver %(driver)s %(doesnt_support)s 'sane' multi row count",
|
532
|
+
)
|
533
|
+
|
534
|
+
@property
|
535
|
+
def sane_rowcount_w_returning(self):
|
536
|
+
return exclusions.fails_if(
|
537
|
+
lambda config: not (
|
538
|
+
config.db.dialect.supports_sane_rowcount_returning
|
539
|
+
),
|
540
|
+
"driver doesn't support 'sane' rowcount when returning is on",
|
541
|
+
)
|
542
|
+
|
543
|
+
@property
|
544
|
+
def empty_inserts(self):
|
545
|
+
"""target platform supports INSERT with no values, i.e.
|
546
|
+
INSERT DEFAULT VALUES or equivalent."""
|
547
|
+
|
548
|
+
return exclusions.only_if(
|
549
|
+
lambda config: config.db.dialect.supports_empty_insert
|
550
|
+
or config.db.dialect.supports_default_values
|
551
|
+
or config.db.dialect.supports_default_metavalue,
|
552
|
+
"empty inserts not supported",
|
553
|
+
)
|
554
|
+
|
555
|
+
@property
|
556
|
+
def empty_inserts_executemany(self):
|
557
|
+
"""target platform supports INSERT with no values, i.e.
|
558
|
+
INSERT DEFAULT VALUES or equivalent, within executemany()"""
|
559
|
+
|
560
|
+
return self.empty_inserts
|
561
|
+
|
562
|
+
@property
|
563
|
+
def insert_from_select(self):
|
564
|
+
"""target platform supports INSERT from a SELECT."""
|
565
|
+
|
566
|
+
return exclusions.open()
|
567
|
+
|
568
|
+
@property
|
569
|
+
def delete_returning(self):
|
570
|
+
"""target platform supports DELETE ... RETURNING."""
|
571
|
+
|
572
|
+
return exclusions.only_if(
|
573
|
+
lambda config: config.db.dialect.delete_returning,
|
574
|
+
"%(database)s %(does_support)s 'DELETE ... RETURNING'",
|
575
|
+
)
|
576
|
+
|
577
|
+
@property
|
578
|
+
def update_returning(self):
|
579
|
+
"""target platform supports UPDATE ... RETURNING."""
|
580
|
+
|
581
|
+
return exclusions.only_if(
|
582
|
+
lambda config: config.db.dialect.update_returning,
|
583
|
+
"%(database)s %(does_support)s 'UPDATE ... RETURNING'",
|
584
|
+
)
|
585
|
+
|
586
|
+
@property
|
587
|
+
def insert_executemany_returning(self):
|
588
|
+
"""target platform supports RETURNING when INSERT is used with
|
589
|
+
executemany(), e.g. multiple parameter sets, indicating
|
590
|
+
as many rows come back as do parameter sets were passed.
|
591
|
+
|
592
|
+
"""
|
593
|
+
|
594
|
+
return exclusions.only_if(
|
595
|
+
lambda config: config.db.dialect.insert_executemany_returning,
|
596
|
+
"%(database)s %(does_support)s 'RETURNING of "
|
597
|
+
"multiple rows with INSERT executemany'",
|
598
|
+
)
|
599
|
+
|
600
|
+
@property
|
601
|
+
def insertmanyvalues(self):
|
602
|
+
return exclusions.only_if(
|
603
|
+
lambda config: config.db.dialect.supports_multivalues_insert
|
604
|
+
and config.db.dialect.insert_returning
|
605
|
+
and config.db.dialect.use_insertmanyvalues,
|
606
|
+
"%(database)s %(does_support)s 'insertmanyvalues functionality",
|
607
|
+
)
|
608
|
+
|
609
|
+
@property
|
610
|
+
def tuple_in(self):
|
611
|
+
"""Target platform supports the syntax
|
612
|
+
"(x, y) IN ((x1, y1), (x2, y2), ...)"
|
613
|
+
"""
|
614
|
+
|
615
|
+
return exclusions.closed()
|
616
|
+
|
617
|
+
@property
|
618
|
+
def tuple_in_w_empty(self):
|
619
|
+
"""Target platform tuple IN w/ empty set"""
|
620
|
+
return self.tuple_in
|
621
|
+
|
622
|
+
@property
|
623
|
+
def duplicate_names_in_cursor_description(self):
|
624
|
+
"""target platform supports a SELECT statement that has
|
625
|
+
the same name repeated more than once in the columns list."""
|
626
|
+
|
627
|
+
return exclusions.open()
|
628
|
+
|
629
|
+
@property
|
630
|
+
def denormalized_names(self):
|
631
|
+
"""Target database must have 'denormalized', i.e.
|
632
|
+
UPPERCASE as case insensitive names."""
|
633
|
+
|
634
|
+
return exclusions.skip_if(
|
635
|
+
lambda config: not config.db.dialect.requires_name_normalize,
|
636
|
+
"Backend does not require denormalized names.",
|
637
|
+
)
|
638
|
+
|
639
|
+
@property
|
640
|
+
def multivalues_inserts(self):
|
641
|
+
"""target database must support multiple VALUES clauses in an
|
642
|
+
INSERT statement."""
|
643
|
+
|
644
|
+
return exclusions.skip_if(
|
645
|
+
lambda config: not config.db.dialect.supports_multivalues_insert,
|
646
|
+
"Backend does not support multirow inserts.",
|
647
|
+
)
|
648
|
+
|
649
|
+
@property
|
650
|
+
def implements_get_lastrowid(self):
|
651
|
+
"""target dialect implements the executioncontext.get_lastrowid()
|
652
|
+
method without reliance on RETURNING.
|
653
|
+
|
654
|
+
"""
|
655
|
+
return exclusions.open()
|
656
|
+
|
657
|
+
@property
|
658
|
+
def arraysize(self):
|
659
|
+
"""dialect includes the required pep-249 attribute
|
660
|
+
``cursor.arraysize``"""
|
661
|
+
|
662
|
+
return exclusions.open()
|
663
|
+
|
664
|
+
@property
|
665
|
+
def emulated_lastrowid(self):
|
666
|
+
"""target dialect retrieves cursor.lastrowid, or fetches
|
667
|
+
from a database-side function after an insert() construct executes,
|
668
|
+
within the get_lastrowid() method.
|
669
|
+
|
670
|
+
Only dialects that "pre-execute", or need RETURNING to get last
|
671
|
+
inserted id, would return closed/fail/skip for this.
|
672
|
+
|
673
|
+
"""
|
674
|
+
return exclusions.closed()
|
675
|
+
|
676
|
+
@property
|
677
|
+
def emulated_lastrowid_even_with_sequences(self):
|
678
|
+
"""target dialect retrieves cursor.lastrowid or an equivalent
|
679
|
+
after an insert() construct executes, even if the table has a
|
680
|
+
Sequence on it.
|
681
|
+
|
682
|
+
"""
|
683
|
+
return exclusions.closed()
|
684
|
+
|
685
|
+
@property
|
686
|
+
def dbapi_lastrowid(self):
|
687
|
+
"""target platform includes a 'lastrowid' accessor on the DBAPI
|
688
|
+
cursor object.
|
689
|
+
|
690
|
+
"""
|
691
|
+
return exclusions.closed()
|
692
|
+
|
693
|
+
@property
|
694
|
+
def schemas(self):
|
695
|
+
"""Target database must support external schemas, and have one
|
696
|
+
named 'test_schema'."""
|
697
|
+
|
698
|
+
return only_on(lambda config: config.db.dialect.supports_schemas)
|
699
|
+
|
700
|
+
@property
|
701
|
+
def cross_schema_fk_reflection(self):
|
702
|
+
"""target system must support reflection of inter-schema
|
703
|
+
foreign keys"""
|
704
|
+
return exclusions.closed()
|
705
|
+
|
706
|
+
@property
|
707
|
+
def foreign_key_constraint_name_reflection(self):
|
708
|
+
"""Target supports reflection of FOREIGN KEY constraints and
|
709
|
+
will return the name of the constraint that was used in the
|
710
|
+
"CONSTRAINT <name> FOREIGN KEY" DDL.
|
711
|
+
"""
|
712
|
+
return exclusions.closed()
|
713
|
+
|
714
|
+
@property
|
715
|
+
def implicit_default_schema(self):
|
716
|
+
"""target system has a strong concept of 'default' schema that can
|
717
|
+
be referred to implicitly.
|
718
|
+
"""
|
719
|
+
return exclusions.closed()
|
720
|
+
|
721
|
+
@property
|
722
|
+
def default_schema_name_switch(self):
|
723
|
+
"""target dialect implements provisioning module including
|
724
|
+
set_default_schema_on_connection"""
|
725
|
+
|
726
|
+
return exclusions.closed()
|
727
|
+
|
728
|
+
@property
|
729
|
+
def server_side_cursors(self):
|
730
|
+
"""Target dialect must support server side cursors."""
|
731
|
+
|
732
|
+
return exclusions.only_if(
|
733
|
+
[lambda config: config.db.dialect.supports_server_side_cursors],
|
734
|
+
"no server side cursors support",
|
735
|
+
)
|
736
|
+
|
737
|
+
@property
|
738
|
+
def sequences(self):
|
739
|
+
"""Target database must support SEQUENCEs."""
|
740
|
+
|
741
|
+
return exclusions.only_if(
|
742
|
+
[lambda config: config.db.dialect.supports_sequences],
|
743
|
+
"no sequence support",
|
744
|
+
)
|
745
|
+
|
746
|
+
@property
|
747
|
+
def no_sequences(self):
|
748
|
+
"""the opposite of "sequences", DB does not support sequences at
|
749
|
+
all."""
|
750
|
+
|
751
|
+
return exclusions.NotPredicate(self.sequences)
|
752
|
+
|
753
|
+
@property
|
754
|
+
def sequences_optional(self):
|
755
|
+
"""Target database supports sequences, but also optionally
|
756
|
+
as a means of generating new PK values."""
|
757
|
+
|
758
|
+
return exclusions.only_if(
|
759
|
+
[
|
760
|
+
lambda config: config.db.dialect.supports_sequences
|
761
|
+
and config.db.dialect.sequences_optional
|
762
|
+
],
|
763
|
+
"no sequence support, or sequences not optional",
|
764
|
+
)
|
765
|
+
|
766
|
+
@property
|
767
|
+
def supports_lastrowid(self):
|
768
|
+
"""target database / driver supports cursor.lastrowid as a means
|
769
|
+
of retrieving the last inserted primary key value.
|
770
|
+
|
771
|
+
note that if the target DB supports sequences also, this is still
|
772
|
+
assumed to work. This is a new use case brought on by MariaDB 10.3.
|
773
|
+
|
774
|
+
"""
|
775
|
+
return exclusions.only_if(
|
776
|
+
[lambda config: config.db.dialect.postfetch_lastrowid]
|
777
|
+
)
|
778
|
+
|
779
|
+
@property
|
780
|
+
def no_lastrowid_support(self):
|
781
|
+
"""the opposite of supports_lastrowid"""
|
782
|
+
return exclusions.only_if(
|
783
|
+
[lambda config: not config.db.dialect.postfetch_lastrowid]
|
784
|
+
)
|
785
|
+
|
786
|
+
@property
|
787
|
+
def table_reflection(self):
|
788
|
+
"""target database has general support for table reflection"""
|
789
|
+
return exclusions.open()
|
790
|
+
|
791
|
+
@property
|
792
|
+
def reflect_tables_no_columns(self):
|
793
|
+
"""target database supports creation and reflection of tables with no
|
794
|
+
columns, or at least tables that seem to have no columns."""
|
795
|
+
|
796
|
+
return exclusions.closed()
|
797
|
+
|
798
|
+
@property
|
799
|
+
def comment_reflection_full_unicode(self):
|
800
|
+
"""Indicates if the database support table comment reflection in the
|
801
|
+
full unicode range, including emoji etc.
|
802
|
+
"""
|
803
|
+
return exclusions.closed()
|
804
|
+
|
805
|
+
@property
|
806
|
+
def constraint_comment_reflection(self):
|
807
|
+
"""indicates if the database support comments on constraints
|
808
|
+
and their reflection"""
|
809
|
+
return exclusions.closed()
|
810
|
+
|
811
|
+
@property
|
812
|
+
def view_column_reflection(self):
|
813
|
+
"""target database must support retrieval of the columns in a view,
|
814
|
+
similarly to how a table is inspected.
|
815
|
+
|
816
|
+
This does not include the full CREATE VIEW definition.
|
817
|
+
|
818
|
+
"""
|
819
|
+
return self.views
|
820
|
+
|
821
|
+
@property
|
822
|
+
def view_reflection(self):
|
823
|
+
"""target database must support inspection of the full CREATE VIEW
|
824
|
+
definition."""
|
825
|
+
return self.views
|
826
|
+
|
827
|
+
@property
|
828
|
+
def schema_reflection(self):
|
829
|
+
return self.schemas
|
830
|
+
|
831
|
+
@property
|
832
|
+
def schema_create_delete(self):
|
833
|
+
"""target database supports schema create and dropped with
|
834
|
+
'CREATE SCHEMA' and 'DROP SCHEMA'"""
|
835
|
+
return exclusions.closed()
|
836
|
+
|
837
|
+
@property
|
838
|
+
def primary_key_constraint_reflection(self):
|
839
|
+
return exclusions.open()
|
840
|
+
|
841
|
+
@property
|
842
|
+
def foreign_key_constraint_reflection(self):
|
843
|
+
return exclusions.open()
|
844
|
+
|
845
|
+
@property
|
846
|
+
def temp_table_reflection(self):
|
847
|
+
return exclusions.open()
|
848
|
+
|
849
|
+
@property
|
850
|
+
def temp_table_reflect_indexes(self):
|
851
|
+
return self.temp_table_reflection
|
852
|
+
|
853
|
+
@property
|
854
|
+
def has_temp_table(self):
|
855
|
+
"""target dialect supports checking a single temp table name"""
|
856
|
+
return exclusions.closed()
|
857
|
+
|
858
|
+
@property
|
859
|
+
def temporary_tables(self):
|
860
|
+
"""target database supports temporary tables"""
|
861
|
+
return exclusions.open()
|
862
|
+
|
863
|
+
@property
|
864
|
+
def temporary_views(self):
|
865
|
+
"""target database supports temporary views"""
|
866
|
+
return exclusions.closed()
|
867
|
+
|
868
|
+
@property
|
869
|
+
def index_reflection(self):
|
870
|
+
return exclusions.open()
|
871
|
+
|
872
|
+
@property
|
873
|
+
def indexes_with_ascdesc(self):
|
874
|
+
"""target database supports CREATE INDEX with per-column ASC/DESC."""
|
875
|
+
return exclusions.open()
|
876
|
+
|
877
|
+
@property
|
878
|
+
def reflect_indexes_with_ascdesc(self):
|
879
|
+
"""target database supports reflecting INDEX with per-column
|
880
|
+
ASC/DESC."""
|
881
|
+
return exclusions.open()
|
882
|
+
|
883
|
+
@property
|
884
|
+
def reflect_indexes_with_ascdesc_as_expression(self):
|
885
|
+
"""target database supports reflecting INDEX with per-column
|
886
|
+
ASC/DESC but reflects them as expressions."""
|
887
|
+
return exclusions.closed()
|
888
|
+
|
889
|
+
@property
|
890
|
+
def indexes_with_expressions(self):
|
891
|
+
"""target database supports CREATE INDEX against SQL expressions."""
|
892
|
+
return exclusions.closed()
|
893
|
+
|
894
|
+
@property
|
895
|
+
def reflect_indexes_with_expressions(self):
|
896
|
+
"""target database supports reflection of indexes with
|
897
|
+
SQL expressions."""
|
898
|
+
return exclusions.closed()
|
899
|
+
|
900
|
+
@property
|
901
|
+
def inline_check_constraint_reflection(self):
|
902
|
+
"""target dialect supports reflection of inline check constraints"""
|
903
|
+
return exclusions.closed()
|
904
|
+
|
905
|
+
@property
|
906
|
+
def check_constraint_reflection(self):
|
907
|
+
"""target dialect supports reflection of check constraints"""
|
908
|
+
return exclusions.closed()
|
909
|
+
|
910
|
+
@property
|
911
|
+
def duplicate_key_raises_integrity_error(self):
|
912
|
+
"""target dialect raises IntegrityError when reporting an INSERT
|
913
|
+
with a primary key violation. (hint: it should)
|
914
|
+
|
915
|
+
"""
|
916
|
+
return exclusions.open()
|
917
|
+
|
918
|
+
@property
|
919
|
+
def unbounded_varchar(self):
|
920
|
+
"""Target database must support VARCHAR with no length"""
|
921
|
+
|
922
|
+
return exclusions.open()
|
923
|
+
|
924
|
+
@property
|
925
|
+
def unicode_data_no_special_types(self):
|
926
|
+
"""Target database/dialect can receive / deliver / compare data with
|
927
|
+
non-ASCII characters in plain VARCHAR, TEXT columns, without the need
|
928
|
+
for special "national" datatypes like NVARCHAR or similar.
|
929
|
+
|
930
|
+
"""
|
931
|
+
return exclusions.open()
|
932
|
+
|
933
|
+
@property
|
934
|
+
def unicode_data(self):
|
935
|
+
"""Target database/dialect must support Python unicode objects with
|
936
|
+
non-ASCII characters represented, delivered as bound parameters
|
937
|
+
as well as in result rows.
|
938
|
+
|
939
|
+
"""
|
940
|
+
return exclusions.open()
|
941
|
+
|
942
|
+
@property
|
943
|
+
def unicode_ddl(self):
|
944
|
+
"""Target driver must support some degree of non-ascii symbol
|
945
|
+
names.
|
946
|
+
"""
|
947
|
+
return exclusions.open()
|
948
|
+
|
949
|
+
@property
|
950
|
+
def datetime_interval(self):
|
951
|
+
"""target dialect supports rendering of a datetime.timedelta as a
|
952
|
+
literal string, e.g. via the TypeEngine.literal_processor() method.
|
953
|
+
|
954
|
+
"""
|
955
|
+
return exclusions.closed()
|
956
|
+
|
957
|
+
@property
|
958
|
+
def datetime_literals(self):
|
959
|
+
"""target dialect supports rendering of a date, time, or datetime as a
|
960
|
+
literal string, e.g. via the TypeEngine.literal_processor() method.
|
961
|
+
|
962
|
+
"""
|
963
|
+
|
964
|
+
return exclusions.open()
|
965
|
+
|
966
|
+
@property
|
967
|
+
def datetime(self):
|
968
|
+
"""target dialect supports representation of Python
|
969
|
+
datetime.datetime() objects."""
|
970
|
+
|
971
|
+
return exclusions.open()
|
972
|
+
|
973
|
+
@property
|
974
|
+
def datetime_timezone(self):
|
975
|
+
"""target dialect supports representation of Python
|
976
|
+
datetime.datetime() with tzinfo with DateTime(timezone=True)."""
|
977
|
+
|
978
|
+
return exclusions.closed()
|
979
|
+
|
980
|
+
@property
|
981
|
+
def time_timezone(self):
|
982
|
+
"""target dialect supports representation of Python
|
983
|
+
datetime.time() with tzinfo with Time(timezone=True)."""
|
984
|
+
|
985
|
+
return exclusions.closed()
|
986
|
+
|
987
|
+
@property
|
988
|
+
def date_implicit_bound(self):
|
989
|
+
"""target dialect when given a date object will bind it such
|
990
|
+
that the database server knows the object is a date, and not
|
991
|
+
a plain string.
|
992
|
+
|
993
|
+
"""
|
994
|
+
return exclusions.open()
|
995
|
+
|
996
|
+
@property
|
997
|
+
def time_implicit_bound(self):
|
998
|
+
"""target dialect when given a time object will bind it such
|
999
|
+
that the database server knows the object is a time, and not
|
1000
|
+
a plain string.
|
1001
|
+
|
1002
|
+
"""
|
1003
|
+
return exclusions.open()
|
1004
|
+
|
1005
|
+
@property
|
1006
|
+
def datetime_implicit_bound(self):
|
1007
|
+
"""target dialect when given a datetime object will bind it such
|
1008
|
+
that the database server knows the object is a datetime, and not
|
1009
|
+
a plain string.
|
1010
|
+
|
1011
|
+
"""
|
1012
|
+
return exclusions.open()
|
1013
|
+
|
1014
|
+
@property
|
1015
|
+
def datetime_microseconds(self):
|
1016
|
+
"""target dialect supports representation of Python
|
1017
|
+
datetime.datetime() with microsecond objects."""
|
1018
|
+
|
1019
|
+
return exclusions.open()
|
1020
|
+
|
1021
|
+
@property
|
1022
|
+
def timestamp_microseconds(self):
|
1023
|
+
"""target dialect supports representation of Python
|
1024
|
+
datetime.datetime() with microsecond objects but only
|
1025
|
+
if TIMESTAMP is used."""
|
1026
|
+
return exclusions.closed()
|
1027
|
+
|
1028
|
+
@property
|
1029
|
+
def timestamp_microseconds_implicit_bound(self):
|
1030
|
+
"""target dialect when given a datetime object which also includes
|
1031
|
+
a microseconds portion when using the TIMESTAMP data type
|
1032
|
+
will bind it such that the database server knows
|
1033
|
+
the object is a datetime with microseconds, and not a plain string.
|
1034
|
+
|
1035
|
+
"""
|
1036
|
+
return self.timestamp_microseconds
|
1037
|
+
|
1038
|
+
@property
|
1039
|
+
def date(self):
|
1040
|
+
"""target dialect supports representation of Python
|
1041
|
+
datetime.date() objects."""
|
1042
|
+
|
1043
|
+
return exclusions.open()
|
1044
|
+
|
1045
|
+
@property
|
1046
|
+
def date_coerces_from_datetime(self):
|
1047
|
+
"""target dialect accepts a datetime object as the target
|
1048
|
+
of a date column."""
|
1049
|
+
|
1050
|
+
return exclusions.open()
|
1051
|
+
|
1052
|
+
@property
|
1053
|
+
def time(self):
|
1054
|
+
"""target dialect supports representation of Python
|
1055
|
+
datetime.time() objects."""
|
1056
|
+
|
1057
|
+
return exclusions.open()
|
1058
|
+
|
1059
|
+
@property
|
1060
|
+
def time_microseconds(self):
|
1061
|
+
"""target dialect supports representation of Python
|
1062
|
+
datetime.time() with microsecond objects."""
|
1063
|
+
|
1064
|
+
return exclusions.open()
|
1065
|
+
|
1066
|
+
@property
|
1067
|
+
def isolation_level(self):
|
1068
|
+
"""target dialect supports general isolation level settings.
|
1069
|
+
|
1070
|
+
Note that this requirement, when enabled, also requires that
|
1071
|
+
the get_isolation_levels() method be implemented.
|
1072
|
+
|
1073
|
+
"""
|
1074
|
+
return exclusions.open()
|
1075
|
+
|
1076
|
+
@property
|
1077
|
+
def get_isolation_level_values(self):
|
1078
|
+
"""target dialect supports the
|
1079
|
+
:meth:`_engine.Dialect.get_isolation_level_values`
|
1080
|
+
method added in SQLAlchemy 2.0.
|
1081
|
+
|
1082
|
+
"""
|
1083
|
+
|
1084
|
+
def go(config):
|
1085
|
+
with config.db.connect() as conn:
|
1086
|
+
try:
|
1087
|
+
conn.dialect.get_isolation_level_values(
|
1088
|
+
conn.connection.dbapi_connection
|
1089
|
+
)
|
1090
|
+
except NotImplementedError:
|
1091
|
+
return False
|
1092
|
+
else:
|
1093
|
+
return True
|
1094
|
+
|
1095
|
+
return exclusions.only_if(go)
|
1096
|
+
|
1097
|
+
@property
|
1098
|
+
def json_type(self):
|
1099
|
+
"""target platform implements a native JSON type."""
|
1100
|
+
|
1101
|
+
return exclusions.closed()
|
1102
|
+
|
1103
|
+
@property
|
1104
|
+
def json_array_indexes(self):
|
1105
|
+
"""target platform supports numeric array indexes
|
1106
|
+
within a JSON structure"""
|
1107
|
+
|
1108
|
+
return self.json_type
|
1109
|
+
|
1110
|
+
@property
|
1111
|
+
def json_index_supplementary_unicode_element(self):
|
1112
|
+
return exclusions.open()
|
1113
|
+
|
1114
|
+
@property
|
1115
|
+
def legacy_unconditional_json_extract(self):
|
1116
|
+
"""Backend has a JSON_EXTRACT or similar function that returns a
|
1117
|
+
valid JSON string in all cases.
|
1118
|
+
|
1119
|
+
Used to test a legacy feature and is not needed.
|
1120
|
+
|
1121
|
+
"""
|
1122
|
+
return exclusions.closed()
|
1123
|
+
|
1124
|
+
@property
|
1125
|
+
def precision_numerics_general(self):
|
1126
|
+
"""target backend has general support for moderately high-precision
|
1127
|
+
numerics."""
|
1128
|
+
return exclusions.open()
|
1129
|
+
|
1130
|
+
@property
|
1131
|
+
def precision_numerics_enotation_small(self):
|
1132
|
+
"""target backend supports Decimal() objects using E notation
|
1133
|
+
to represent very small values."""
|
1134
|
+
return exclusions.closed()
|
1135
|
+
|
1136
|
+
@property
|
1137
|
+
def precision_numerics_enotation_large(self):
|
1138
|
+
"""target backend supports Decimal() objects using E notation
|
1139
|
+
to represent very large values."""
|
1140
|
+
return exclusions.open()
|
1141
|
+
|
1142
|
+
@property
|
1143
|
+
def cast_precision_numerics_many_significant_digits(self):
|
1144
|
+
"""same as precision_numerics_many_significant_digits but within the
|
1145
|
+
context of a CAST statement
|
1146
|
+
|
1147
|
+
"""
|
1148
|
+
return self.precision_numerics_many_significant_digits
|
1149
|
+
|
1150
|
+
@property
|
1151
|
+
def implicit_decimal_binds(self):
|
1152
|
+
"""target backend will return a selected Decimal as a Decimal, not
|
1153
|
+
a string.
|
1154
|
+
"""
|
1155
|
+
|
1156
|
+
return exclusions.open()
|
1157
|
+
|
1158
|
+
@property
|
1159
|
+
def numeric_received_as_decimal_untyped(self):
|
1160
|
+
"""target backend will return result columns that are explicitly
|
1161
|
+
against NUMERIC or similar precision-numeric datatypes (not including
|
1162
|
+
FLOAT or INT types) as Python Decimal objects, and not as floats
|
1163
|
+
or ints, including when no SQLAlchemy-side typing information is
|
1164
|
+
associated with the statement (e.g. such as a raw SQL string).
|
1165
|
+
|
1166
|
+
This should be enabled if either the DBAPI itself returns Decimal
|
1167
|
+
objects, or if the dialect has set up DBAPI-specific return type
|
1168
|
+
handlers such that Decimal objects come back automatically.
|
1169
|
+
|
1170
|
+
"""
|
1171
|
+
return exclusions.open()
|
1172
|
+
|
1173
|
+
@property
|
1174
|
+
def nested_aggregates(self):
|
1175
|
+
"""target database can select an aggregate from a subquery that's
|
1176
|
+
also using an aggregate
|
1177
|
+
|
1178
|
+
"""
|
1179
|
+
return exclusions.open()
|
1180
|
+
|
1181
|
+
@property
|
1182
|
+
def recursive_fk_cascade(self):
|
1183
|
+
"""target database must support ON DELETE CASCADE on a self-referential
|
1184
|
+
foreign key
|
1185
|
+
|
1186
|
+
"""
|
1187
|
+
return exclusions.open()
|
1188
|
+
|
1189
|
+
@property
|
1190
|
+
def precision_numerics_retains_significant_digits(self):
|
1191
|
+
"""A precision numeric type will return empty significant digits,
|
1192
|
+
i.e. a value such as 10.000 will come back in Decimal form with
|
1193
|
+
the .000 maintained."""
|
1194
|
+
|
1195
|
+
return exclusions.closed()
|
1196
|
+
|
1197
|
+
@property
|
1198
|
+
def infinity_floats(self):
|
1199
|
+
"""The Float type can persist and load float('inf'), float('-inf')."""
|
1200
|
+
|
1201
|
+
return exclusions.closed()
|
1202
|
+
|
1203
|
+
@property
|
1204
|
+
def float_or_double_precision_behaves_generically(self):
|
1205
|
+
return exclusions.closed()
|
1206
|
+
|
1207
|
+
@property
|
1208
|
+
def precision_generic_float_type(self):
|
1209
|
+
"""target backend will return native floating point numbers with at
|
1210
|
+
least seven decimal places when using the generic Float type.
|
1211
|
+
|
1212
|
+
"""
|
1213
|
+
return exclusions.open()
|
1214
|
+
|
1215
|
+
@property
|
1216
|
+
def literal_float_coercion(self):
|
1217
|
+
"""target backend will return the exact float value 15.7563
|
1218
|
+
with only four significant digits from this statement:
|
1219
|
+
|
1220
|
+
SELECT :param
|
1221
|
+
|
1222
|
+
where :param is the Python float 15.7563
|
1223
|
+
|
1224
|
+
i.e. it does not return 15.75629997253418
|
1225
|
+
|
1226
|
+
"""
|
1227
|
+
return exclusions.open()
|
1228
|
+
|
1229
|
+
@property
|
1230
|
+
def floats_to_four_decimals(self):
|
1231
|
+
"""target backend can return a floating-point number with four
|
1232
|
+
significant digits (such as 15.7563) accurately
|
1233
|
+
(i.e. without FP inaccuracies, such as 15.75629997253418).
|
1234
|
+
|
1235
|
+
"""
|
1236
|
+
return exclusions.open()
|
1237
|
+
|
1238
|
+
@property
|
1239
|
+
def fetch_null_from_numeric(self):
|
1240
|
+
"""target backend doesn't crash when you try to select a NUMERIC
|
1241
|
+
value that has a value of NULL.
|
1242
|
+
|
1243
|
+
Added to support Pyodbc bug #351.
|
1244
|
+
"""
|
1245
|
+
|
1246
|
+
return exclusions.open()
|
1247
|
+
|
1248
|
+
@property
|
1249
|
+
def float_is_numeric(self):
|
1250
|
+
"""target backend uses Numeric for Float/Dual"""
|
1251
|
+
|
1252
|
+
return exclusions.open()
|
1253
|
+
|
1254
|
+
@property
|
1255
|
+
def text_type(self):
|
1256
|
+
"""Target database must support an unbounded Text() "
|
1257
|
+
"type such as TEXT or CLOB"""
|
1258
|
+
|
1259
|
+
return exclusions.open()
|
1260
|
+
|
1261
|
+
@property
|
1262
|
+
def empty_strings_varchar(self):
|
1263
|
+
"""target database can persist/return an empty string with a
|
1264
|
+
varchar.
|
1265
|
+
|
1266
|
+
"""
|
1267
|
+
return exclusions.open()
|
1268
|
+
|
1269
|
+
@property
|
1270
|
+
def empty_strings_text(self):
|
1271
|
+
"""target database can persist/return an empty string with an
|
1272
|
+
unbounded text."""
|
1273
|
+
|
1274
|
+
return exclusions.open()
|
1275
|
+
|
1276
|
+
@property
|
1277
|
+
def expressions_against_unbounded_text(self):
|
1278
|
+
"""target database supports use of an unbounded textual field in a
|
1279
|
+
WHERE clause."""
|
1280
|
+
|
1281
|
+
return exclusions.open()
|
1282
|
+
|
1283
|
+
@property
|
1284
|
+
def selectone(self):
|
1285
|
+
"""target driver must support the literal statement 'select 1'"""
|
1286
|
+
return exclusions.open()
|
1287
|
+
|
1288
|
+
@property
|
1289
|
+
def savepoints(self):
|
1290
|
+
"""Target database must support savepoints."""
|
1291
|
+
|
1292
|
+
return exclusions.closed()
|
1293
|
+
|
1294
|
+
@property
|
1295
|
+
def update_from(self):
|
1296
|
+
"""Target must support UPDATE..FROM syntax"""
|
1297
|
+
return exclusions.closed()
|
1298
|
+
|
1299
|
+
@property
|
1300
|
+
def delete_from(self):
|
1301
|
+
"""Target must support DELETE FROM..FROM or DELETE..USING syntax"""
|
1302
|
+
return exclusions.closed()
|
1303
|
+
|
1304
|
+
@property
|
1305
|
+
def update_where_target_in_subquery(self):
|
1306
|
+
"""Target must support UPDATE (or DELETE) where the same table is
|
1307
|
+
present in a subquery in the WHERE clause.
|
1308
|
+
"""
|
1309
|
+
return exclusions.open()
|
1310
|
+
|
1311
|
+
@property
|
1312
|
+
def mod_operator_as_percent_sign(self):
|
1313
|
+
"""target database must use a plain percent '%' as the 'modulus'
|
1314
|
+
operator."""
|
1315
|
+
return exclusions.closed()
|
1316
|
+
|
1317
|
+
@property
|
1318
|
+
def percent_schema_names(self):
|
1319
|
+
"""target backend supports weird identifiers with percent signs
|
1320
|
+
in them, e.g. 'some % column'.
|
1321
|
+
|
1322
|
+
this is a very weird use case but often has problems because of
|
1323
|
+
DBAPIs that use python formatting. It's not a critical use
|
1324
|
+
case either.
|
1325
|
+
|
1326
|
+
"""
|
1327
|
+
return exclusions.closed()
|
1328
|
+
|
1329
|
+
@property
|
1330
|
+
def order_by_col_from_union(self):
|
1331
|
+
"""target database supports ordering by a column from a SELECT
|
1332
|
+
inside of a UNION
|
1333
|
+
|
1334
|
+
E.g. (SELECT id, ...) UNION (SELECT id, ...) ORDER BY id
|
1335
|
+
|
1336
|
+
"""
|
1337
|
+
return exclusions.open()
|
1338
|
+
|
1339
|
+
@property
|
1340
|
+
def order_by_collation(self):
|
1341
|
+
def check(config):
|
1342
|
+
try:
|
1343
|
+
self.get_order_by_collation(config)
|
1344
|
+
return False
|
1345
|
+
except NotImplementedError:
|
1346
|
+
return True
|
1347
|
+
|
1348
|
+
return exclusions.skip_if(check)
|
1349
|
+
|
1350
|
+
def get_order_by_collation(self, config):
|
1351
|
+
raise NotImplementedError()
|
1352
|
+
|
1353
|
+
@property
|
1354
|
+
def unicode_connections(self):
|
1355
|
+
"""Target driver must support non-ASCII characters being passed at
|
1356
|
+
all.
|
1357
|
+
"""
|
1358
|
+
return exclusions.open()
|
1359
|
+
|
1360
|
+
@property
|
1361
|
+
def graceful_disconnects(self):
|
1362
|
+
"""Target driver must raise a DBAPI-level exception, such as
|
1363
|
+
InterfaceError, when the underlying connection has been closed
|
1364
|
+
and the execute() method is called.
|
1365
|
+
"""
|
1366
|
+
return exclusions.open()
|
1367
|
+
|
1368
|
+
@property
|
1369
|
+
def independent_connections(self):
|
1370
|
+
"""
|
1371
|
+
Target must support simultaneous, independent database connections.
|
1372
|
+
"""
|
1373
|
+
return exclusions.open()
|
1374
|
+
|
1375
|
+
@property
|
1376
|
+
def independent_readonly_connections(self):
|
1377
|
+
"""
|
1378
|
+
Target must support simultaneous, independent database connections
|
1379
|
+
that will be used in a readonly fashion.
|
1380
|
+
|
1381
|
+
"""
|
1382
|
+
return exclusions.open()
|
1383
|
+
|
1384
|
+
@property
|
1385
|
+
def async_dialect(self):
|
1386
|
+
"""dialect makes use of await_() to invoke operations on the DBAPI."""
|
1387
|
+
|
1388
|
+
return exclusions.closed()
|
1389
|
+
|
1390
|
+
@property
|
1391
|
+
def supports_is_distinct_from(self):
|
1392
|
+
"""Supports some form of "x IS [NOT] DISTINCT FROM y" construct.
|
1393
|
+
Different dialects will implement their own flavour
|
1394
|
+
|
1395
|
+
.. seealso::
|
1396
|
+
|
1397
|
+
:meth:`.ColumnOperators.is_distinct_from`
|
1398
|
+
|
1399
|
+
"""
|
1400
|
+
return exclusions.skip_if(
|
1401
|
+
lambda config: not config.db.dialect.supports_is_distinct_from,
|
1402
|
+
"driver doesn't support an IS DISTINCT FROM construct",
|
1403
|
+
)
|
1404
|
+
|
1405
|
+
@property
|
1406
|
+
def identity_columns(self):
|
1407
|
+
"""If a backend supports GENERATED { ALWAYS | BY DEFAULT }
|
1408
|
+
AS IDENTITY"""
|
1409
|
+
return exclusions.closed()
|
1410
|
+
|
1411
|
+
@property
|
1412
|
+
def identity_columns_standard(self):
|
1413
|
+
"""If a backend supports GENERATED { ALWAYS | BY DEFAULT }
|
1414
|
+
AS IDENTITY with a standard syntax.
|
1415
|
+
"""
|
1416
|
+
return exclusions.closed()
|
1417
|
+
|
1418
|
+
@property
|
1419
|
+
def regexp_replace(self):
|
1420
|
+
"""backend supports the regexp_replace operator."""
|
1421
|
+
return exclusions.closed()
|
1422
|
+
|
1423
|
+
@property
|
1424
|
+
def fetch_first(self):
|
1425
|
+
"""backend supports the fetch first clause."""
|
1426
|
+
return exclusions.open()
|
1427
|
+
|
1428
|
+
@property
|
1429
|
+
def fetch_percent(self):
|
1430
|
+
"""backend supports the fetch first clause with percent."""
|
1431
|
+
return exclusions.closed()
|
1432
|
+
|
1433
|
+
@property
|
1434
|
+
def fetch_ties(self):
|
1435
|
+
"""backend supports the fetch first clause with ties."""
|
1436
|
+
return exclusions.closed()
|
1437
|
+
|
1438
|
+
@property
|
1439
|
+
def fetch_no_order_by(self):
|
1440
|
+
"""backend supports the fetch first without order by"""
|
1441
|
+
return exclusions.open()
|
1442
|
+
|
1443
|
+
@property
|
1444
|
+
def fetch_offset_with_options(self):
|
1445
|
+
"""backend supports the offset when using fetch first with percent
|
1446
|
+
or ties.
|
1447
|
+
"""
|
1448
|
+
return exclusions.open()
|
1449
|
+
|
1450
|
+
@property
|
1451
|
+
def fetch_expression(self):
|
1452
|
+
"""backend supports fetch / offset with expression in them, like
|
1453
|
+
|
1454
|
+
SELECT * FROM some_table
|
1455
|
+
OFFSET 1 + 1 ROWS FETCH FIRST 1 + 1 ROWS ONLY
|
1456
|
+
"""
|
1457
|
+
return exclusions.open()
|
1458
|
+
|
1459
|
+
@property
|
1460
|
+
def autoincrement_without_sequence(self):
|
1461
|
+
"""If autoincrement=True on a column does not require an explicit
|
1462
|
+
sequence.
|
1463
|
+
"""
|
1464
|
+
return exclusions.open()
|
1465
|
+
|
1466
|
+
@property
|
1467
|
+
def generic_classes(self):
|
1468
|
+
"If X[Y] can be implemented with ``__class_getitem__``. py3.7+"
|
1469
|
+
return exclusions.open()
|
1470
|
+
|
1471
|
+
@property
|
1472
|
+
def json_deserializer_binary(self):
|
1473
|
+
"indicates if the json_deserializer function is called with bytes"
|
1474
|
+
return exclusions.closed()
|
1475
|
+
|
1476
|
+
@property
|
1477
|
+
def materialized_views(self):
|
1478
|
+
"""Target database must support MATERIALIZED VIEWs."""
|
1479
|
+
return exclusions.closed()
|
1480
|
+
|
1481
|
+
@property
|
1482
|
+
def materialized_views_reflect_pk(self):
|
1483
|
+
"""Target database reflect MATERIALIZED VIEWs pks."""
|
1484
|
+
return exclusions.closed()
|
1485
|
+
|
1486
|
+
@property
|
1487
|
+
def supports_bitwise_or(self):
|
1488
|
+
"""Target database supports bitwise or"""
|
1489
|
+
return exclusions.closed()
|
1490
|
+
|
1491
|
+
@property
|
1492
|
+
def supports_bitwise_and(self):
|
1493
|
+
"""Target database supports bitwise and"""
|
1494
|
+
return exclusions.closed()
|
1495
|
+
|
1496
|
+
@property
|
1497
|
+
def supports_bitwise_not(self):
|
1498
|
+
"""Target database supports bitwise not"""
|
1499
|
+
return exclusions.closed()
|
1500
|
+
|
1501
|
+
@property
|
1502
|
+
def supports_bitwise_xor(self):
|
1503
|
+
"""Target database supports bitwise xor"""
|
1504
|
+
return exclusions.closed()
|
1505
|
+
|
1506
|
+
@property
|
1507
|
+
def supports_bitwise_shift(self):
|
1508
|
+
"""Target database supports bitwise left or right shift"""
|
1509
|
+
return exclusions.closed()
|