Skip to content

Commit fa94e1d

Browse files
committed
Basic Support for Sequences
1 parent 752e170 commit fa94e1d

File tree

2 files changed

+104
-11
lines changed

2 files changed

+104
-11
lines changed

databend_sqlalchemy/databend_dialect.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
import sqlalchemy.engine.reflection
3333
import sqlalchemy.types as sqltypes
34-
from typing import Any, Dict, Optional, Union
34+
from typing import Any, Dict, Optional, Union, List
3535
from sqlalchemy import util as sa_util
3636
from sqlalchemy.engine import reflection
3737
from sqlalchemy.sql import (
@@ -703,7 +703,6 @@ def __init__(self, key_type, value_type):
703703
super(MAP, self).__init__()
704704

705705

706-
707706
class DatabendDate(sqltypes.DATE):
708707
__visit_name__ = "DATE"
709708

@@ -857,7 +856,6 @@ class DatabendGeography(GEOGRAPHY):
857856
}
858857

859858

860-
861859
# Column spec
862860
colspecs = {
863861
sqltypes.Interval: DatabendInterval,
@@ -872,6 +870,12 @@ class DatabendGeography(GEOGRAPHY):
872870
class DatabendIdentifierPreparer(PGIdentifierPreparer):
873871
reserved_words = {r.lower() for r in RESERVED_WORDS}
874872

873+
# overridden to exclude schema from sequence
874+
def format_sequence(
875+
self, sequence, use_schema: bool = True
876+
) -> str:
877+
return super().format_sequence(sequence, use_schema=False)
878+
875879

876880
class DatabendCompiler(PGCompiler):
877881
iscopyintotable: bool = False
@@ -1230,6 +1234,15 @@ def copy_into_table_results(self) -> list[dict]:
12301234
def copy_into_location_results(self) -> dict:
12311235
return self._copy_into_location_results
12321236

1237+
def fire_sequence(self, seq, type_):
1238+
return self._execute_scalar(
1239+
(
1240+
"select nextval(%s)"
1241+
% self.identifier_preparer.format_sequence(seq)
1242+
),
1243+
type_,
1244+
)
1245+
12331246

12341247
class DatabendTypeCompiler(compiler.GenericTypeCompiler):
12351248
def visit_ARRAY(self, type_, **kw):
@@ -1280,7 +1293,6 @@ def visit_GEOGRAPHY(self, type_, **kw):
12801293
return "GEOGRAPHY"
12811294

12821295

1283-
12841296
class DatabendDDLCompiler(compiler.DDLCompiler):
12851297
def visit_primary_key_constraint(self, constraint, **kw):
12861298
return ""
@@ -1394,6 +1406,7 @@ class DatabendDialect(default.DefaultDialect):
13941406
supports_empty_insert = False
13951407
supports_is_distinct_from = True
13961408
supports_multivalues_insert = True
1409+
supports_sequences = True
13971410

13981411
supports_statement_cache = False
13991412
supports_server_side_cursors = True
@@ -1621,7 +1634,6 @@ def get_temp_table_names(self, connection, schema=None, **kw):
16211634
result = connection.execute(query, dict(schema_name=schema))
16221635
return [row[0] for row in result]
16231636

1624-
16251637
@reflection.cache
16261638
def get_view_names(self, connection, schema=None, **kw):
16271639
view_name_query = """
@@ -1762,7 +1774,6 @@ def get_multi_table_comment(
17621774
schema='system',
17631775
).alias("a_tab_comments")
17641776

1765-
17661777
has_filter_names, params = self._prepare_filter_names(filter_names)
17671778
owner = schema or self.default_schema_name
17681779

@@ -1804,6 +1815,20 @@ def _check_unicode_description(self, connection):
18041815
# We decode everything as UTF-8
18051816
return True
18061817

1818+
@reflection.cache
1819+
def get_sequence_names(self, connection, schema: Optional[str] = None, **kw: Any) -> List[str]:
1820+
# N.B. sequences are not defined per schema/database
1821+
sequence_query = """
1822+
show sequences
1823+
"""
1824+
query = text(sequence_query)
1825+
result = connection.execute(query)
1826+
return [row[0] for row in result]
1827+
1828+
def has_sequence(self, connection, sequence_name: str, schema: Optional[str] = None, **kw: Any) -> bool:
1829+
# N.B. sequences are not defined per schema/database
1830+
return sequence_name in self.get_sequence_names(connection, schema, **kw)
1831+
18071832

18081833
dialect = DatabendDialect
18091834

tests/test_sqlalchemy.py

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from sqlalchemy.testing.suite import LongNameBlowoutTest as _LongNameBlowoutTest
1414
from sqlalchemy.testing.suite import QuotedNameArgumentTest as _QuotedNameArgumentTest
1515
from sqlalchemy.testing.suite import JoinTest as _JoinTest
16+
from sqlalchemy.testing.suite import HasSequenceTest as _HasSequenceTest
1617

1718
from sqlalchemy.testing.suite import ServerSideCursorsTest as _ServerSideCursorsTest
1819

@@ -21,7 +22,7 @@
2122
from sqlalchemy.testing.suite import IntegerTest as _IntegerTest
2223

2324
from sqlalchemy import types as sql_types
24-
from sqlalchemy.testing import config
25+
from sqlalchemy.testing import config, skip_test
2526
from sqlalchemy import testing, Table, Column, Integer
2627
from sqlalchemy.testing import eq_, fixtures, assertions
2728

@@ -586,9 +587,6 @@ def test_geometry_write_and_read(self, connection):
586587
eq_(result, ('{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [10,20]},{"type": "LineString", "coordinates": [[10,20],[30,40]]},{"type": "Polygon", "coordinates": [[[10,20],[30,40],[50,60],[10,20]]]}]}'))
587588

588589

589-
590-
591-
592590
class GeographyTest(fixtures.TablesTest):
593591

594592
@classmethod
@@ -664,4 +662,74 @@ def test_geography_write_and_read(self, connection):
664662
result = connection.execute(
665663
select(geography_table.c.geography_data).where(geography_table.c.id == 7)
666664
).scalar()
667-
eq_(result, ('{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [10,20]},{"type": "LineString", "coordinates": [[10,20],[30,40]]},{"type": "Polygon", "coordinates": [[[10,20],[30,40],[50,60],[10,20]]]}]}'))
665+
eq_(result, ('{"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [10,20]},{"type": "LineString", "coordinates": [[10,20],[30,40]]},{"type": "Polygon", "coordinates": [[[10,20],[30,40],[50,60],[10,20]]]}]}'))
666+
667+
668+
class HasSequenceTest(_HasSequenceTest):
669+
670+
# ToDo - overridden other_seq definition due to lack of sequence ddl support for nominvalue nomaxvalue
671+
@classmethod
672+
def define_tables(cls, metadata):
673+
normalize_sequence(config, Sequence("user_id_seq", metadata=metadata))
674+
normalize_sequence(
675+
config,
676+
Sequence(
677+
"other_seq",
678+
metadata=metadata,
679+
# nomaxvalue=True,
680+
# nominvalue=True,
681+
),
682+
)
683+
if testing.requires.schemas.enabled:
684+
#ToDo - omitted because Databend does not allow schema on sequence
685+
# normalize_sequence(
686+
# config,
687+
# Sequence(
688+
# "user_id_seq", schema=config.test_schema, metadata=metadata
689+
# ),
690+
# )
691+
normalize_sequence(
692+
config,
693+
Sequence(
694+
"schema_seq", schema=config.test_schema, metadata=metadata
695+
),
696+
)
697+
Table(
698+
"user_id_table",
699+
metadata,
700+
Column("id", Integer, primary_key=True),
701+
)
702+
703+
@testing.skip("databend") # ToDo - requires definition of sequences with schema
704+
def test_has_sequence_remote_not_in_default(self, connection):
705+
eq_(inspect(connection).has_sequence("schema_seq"), False)
706+
707+
@testing.skip("databend") # ToDo - requires definition of sequences with schema
708+
def test_get_sequence_names(self, connection):
709+
exp = {"other_seq", "user_id_seq"}
710+
711+
res = set(inspect(connection).get_sequence_names())
712+
is_true(res.intersection(exp) == exp)
713+
is_true("schema_seq" not in res)
714+
715+
@testing.skip("databend") # ToDo - requires definition of sequences with schema
716+
@testing.requires.schemas
717+
def test_get_sequence_names_no_sequence_schema(self, connection):
718+
eq_(
719+
inspect(connection).get_sequence_names(
720+
schema=config.test_schema_2
721+
),
722+
[],
723+
)
724+
725+
@testing.skip("databend") # ToDo - requires definition of sequences with schema
726+
@testing.requires.schemas
727+
def test_get_sequence_names_sequences_schema(self, connection):
728+
eq_(
729+
sorted(
730+
inspect(connection).get_sequence_names(
731+
schema=config.test_schema
732+
)
733+
),
734+
["schema_seq", "user_id_seq"],
735+
)

0 commit comments

Comments
 (0)