confluent-sql 0.5.1__tar.gz → 0.5.2__tar.gz

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.
Files changed (67) hide show
  1. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/CHANGELOG.md +6 -1
  2. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/PKG-INFO +1 -1
  3. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/pyproject.toml +1 -1
  4. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/statement.py +35 -4
  5. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/integration/test_fetch.py +128 -1
  6. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_statement_unit.py +38 -3
  7. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/uv.lock +1 -1
  8. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/.github/CODEOWNERS +0 -0
  9. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/.gitignore +0 -0
  10. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/.semaphore/publish_to_pypi.yml +0 -0
  11. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/.semaphore/semaphore.yml +0 -0
  12. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/ARCHITECTURE.md +0 -0
  13. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/CLAUDE.md +0 -0
  14. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/DBAPI_EXTENSIONS.md +0 -0
  15. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/LICENSE.txt +0 -0
  16. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/Makefile +0 -0
  17. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/README.md +0 -0
  18. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/STREAMING.md +0 -0
  19. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/TYPES.md +0 -0
  20. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/examples/byoidc_bearer_token_example.py +0 -0
  21. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/examples/errors.py +0 -0
  22. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/examples/simple_append_only_streaming_query_example.py +0 -0
  23. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/examples/snapshot_mode_tuple_cursor_simple_example.py +0 -0
  24. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/examples/statement_properties_example.py +0 -0
  25. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/examples/tableflow_lifecycle_example.py +0 -0
  26. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/service.yml +0 -0
  27. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/__init__.py +0 -0
  28. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/__version__.py +0 -0
  29. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/auth.py +0 -0
  30. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/changelog_compressor.py +0 -0
  31. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/connection.py +0 -0
  32. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/connectors.py +0 -0
  33. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/cursor.py +0 -0
  34. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/exceptions.py +0 -0
  35. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/execution_mode.py +0 -0
  36. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/polling.py +0 -0
  37. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/result_readers.py +0 -0
  38. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/retry.py +0 -0
  39. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/statement_properties.py +0 -0
  40. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/tableflow.py +0 -0
  41. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/src/confluent_sql/types.py +0 -0
  42. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/__init__.py +0 -0
  43. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/conftest.py +0 -0
  44. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/integration/conftest.py +0 -0
  45. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/integration/test_connection.py +0 -0
  46. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/integration/test_connector.py +0 -0
  47. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/integration/test_cursor.py +0 -0
  48. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/integration/test_tableflow.py +0 -0
  49. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/conftest.py +0 -0
  50. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_auth_unit.py +0 -0
  51. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_changelog_compressor_unit.py +0 -0
  52. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_changelog_unit.py +0 -0
  53. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_connection_byoidc_unit.py +0 -0
  54. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_connection_connector_unit.py +0 -0
  55. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_connection_unit.py +0 -0
  56. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_connection_unit_properties.py +0 -0
  57. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_connectors_connection_unit.py +0 -0
  58. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_connectors_unit.py +0 -0
  59. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_cursor_unit.py +0 -0
  60. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_execution_mode_unit.py +0 -0
  61. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_polling_unit.py +0 -0
  62. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_result_readers_unit.py +0 -0
  63. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_retry_unit.py +0 -0
  64. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_statement_properties_unit.py +0 -0
  65. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_tableflow_connection_unit.py +0 -0
  66. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_tableflow_unit.py +0 -0
  67. {confluent_sql-0.5.1 → confluent_sql-0.5.2}/tests/unit/test_types_unit.py +0 -0
@@ -2,7 +2,12 @@
2
2
 
3
3
  All notable changes to this dbapi driver will be documented in this file.
4
4
 
5
- ## Unreleased
5
+ ## 0.5.2, 2026-08-26
6
+
7
+ ### Fixed
8
+
9
+ - `Statement.is_pure_ddl` / `_PURE_DDL_KINDS` now include `CREATE_MATERIALIZED_TABLE`, `CREATE_OR_ALTER_MATERIALIZED_TABLE`, `ALTER_MATERIALIZED_TABLE` (the bare, query-evolving form), and `DROP_MATERIALIZED_TABLE`.
10
+ - Previously these kinds weren't classified as pure or impure DDL, so in **streaming** execution mode, `Statement.can_fetch_results` fell through to the "ready when RUNNING" branch used for CTAS -- meaning a streaming-mode `Cursor.execute()` (and therefore `Connection.execute_streaming_ddl()`) on one of these statements could in principle return control as soon as the statement was RUNNING rather than waiting for it to reach a terminal phase, the same way `execute_streaming_ddl()` correctly waits out a genuinely perpetual CTAS job's RUNNING phase. Snapshot execution mode (the default, and what `execute_snapshot_ddl()` always uses) was unaffected -- it already waits for a terminal phase regardless of `is_pure_ddl`.
6
11
 
7
12
  ## 0.5.1, 2026-08-25
8
13
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: confluent-sql
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: DB-API v2 compliant driver for Confluent Cloud Flink SQL
5
5
  Project-URL: Repository, https://github.com/confluentinc/confluent-sql
6
6
  Project-URL: Documentation, https://github.com/confluentinc/confluent-sql?tab=readme-ov-file#confluent-sql
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "confluent-sql"
7
- version = "0.5.1"
7
+ version = "0.5.2"
8
8
  description = "DB-API v2 compliant driver for Confluent Cloud Flink SQL"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -170,12 +170,30 @@ class Statement:
170
170
  """Represents a Confluent SQL statement, including its metadata, spec, status,
171
171
  and parsed traits such as schema, sql kind, etc."""
172
172
 
173
- # SQL kinds that represent pure DDL statements (create/modify schema objects)
173
+ # SQL kinds that represent pure DDL statements (create/modify schema objects) which should
174
+ # be waiting for a terminal state before the created/modified objects are usable.
174
175
  _PURE_DDL_KINDS = frozenset(
175
- {"CREATE_TABLE", "DROP_TABLE", "CREATE_VIEW", "DROP_VIEW", "ALTER_TABLE"}
176
+ {
177
+ "CREATE_TABLE",
178
+ "DROP_TABLE",
179
+ "CREATE_VIEW",
180
+ "DROP_VIEW",
181
+ "ALTER_TABLE",
182
+ # The four MATERIALIZED_TABLE kinds stretch "pure" a little: unlike the other
183
+ # members, CREATE_MATERIALIZED_TABLE, CREATE_OR_ALTER_MATERIALIZED_TABLE, and
184
+ # ALTER_MATERIALIZED_TABLE (a query-evolving ALTER, not just a metadata-only one)
185
+ # also kick off (or redeploy) a persistent background refresh job that keeps running
186
+ # long after this statement settles. But they still will reliably reach terminal
187
+ # COMPLETED (or FAILED) phase independent of the background job, which is the one
188
+ # thing this property actually gates.
189
+ "CREATE_MATERIALIZED_TABLE",
190
+ "CREATE_OR_ALTER_MATERIALIZED_TABLE",
191
+ "ALTER_MATERIALIZED_TABLE",
192
+ "DROP_MATERIALIZED_TABLE",
193
+ }
176
194
  )
177
195
 
178
- # SQL kinds that represent impure DDL (produce no result set but may stream)
196
+ # SQL kinds that represent impure DDL (produce no result set but will remain in RUNNING phase)
179
197
  _IMPURE_DDL_KINDS = frozenset({"CREATE_TABLE_AS"})
180
198
 
181
199
  # From the cursor that created this statement ...
@@ -336,9 +354,22 @@ class Statement:
336
354
  Pure DDL statements need to complete fully before the created/modified objects
337
355
  are ready for use, unlike streaming queries or CTAS which are ready when RUNNING.
338
356
 
357
+ "Pure" is stretched a little to also cover CREATE_MATERIALIZED_TABLE,
358
+ CREATE_OR_ALTER_MATERIALIZED_TABLE, and ALTER_MATERIALIZED_TABLE (the query-evolving
359
+ form -- see CREATE_OR_ALTER_MATERIALIZED_TABLE): their completion additionally kicks off
360
+ (or redeploys) a persistent background refresh job that keeps running long after the
361
+ statement settles, which isn't true of the other members. They earn the label anyway
362
+ because they satisfy the one thing this property actually gates: the statement's own
363
+ phase reliably reaches a terminal phase before the created/altered object is usable,
364
+ rather than lingering in RUNNING the way CTAS does (see _PURE_DDL_KINDS for the
365
+ confirming detail). DROP_MATERIALIZED_TABLE needs no such stretch -- like the other
366
+ DROP_* kinds, it's a one-shot action with no background job of its own.
367
+
339
368
  Returns:
340
369
  True if the statement is one of: CREATE_TABLE, DROP_TABLE, CREATE_VIEW,
341
- DROP_VIEW, ALTER_TABLE. False otherwise.
370
+ DROP_VIEW, ALTER_TABLE, CREATE_MATERIALIZED_TABLE,
371
+ CREATE_OR_ALTER_MATERIALIZED_TABLE, ALTER_MATERIALIZED_TABLE,
372
+ DROP_MATERIALIZED_TABLE. False otherwise.
342
373
  """
343
374
  return self.sql_kind in self._PURE_DDL_KINDS
344
375
 
@@ -9,7 +9,7 @@ from typing import NamedTuple
9
9
 
10
10
  import pytest
11
11
 
12
- from confluent_sql import Connection, SqlNone, YearMonthInterval
12
+ from confluent_sql import Connection, OperationalError, SqlNone, YearMonthInterval
13
13
  from confluent_sql.execution_mode import ExecutionMode
14
14
 
15
15
 
@@ -678,6 +678,133 @@ class TestExecuteDDL:
678
678
  assert statement.schema is None, "CTAS schema should be None"
679
679
  assert statement.is_deleted, "Snapshot DDL statement should be auto-deleted"
680
680
 
681
+ def test_execute_streaming_ddl_create_materialized_table_completes(
682
+ self, connection: Connection, auto_dropped_table_name: str
683
+ ):
684
+ """Prove that CREATE MATERIALIZED TABLE, submitted via execute_streaming_ddl(), waits
685
+ for the statement to reach COMPLETED rather than returning as soon as it's RUNNING --
686
+ unlike CTAS, whose backing job runs forever, a materialized table's own CREATE statement
687
+ settles once its background refresh job is started (see statement.py's is_pure_ddl)."""
688
+ try:
689
+ statement_text = f"""
690
+ CREATE MATERIALIZED TABLE `{auto_dropped_table_name}`
691
+ AS SELECT * FROM `sample_data_stock_trades` WHERE quantity > 100
692
+ """
693
+
694
+ statement = connection.execute_streaming_ddl(statement_text)
695
+
696
+ # execute_streaming_ddl's closing_cursor auto-deletes a terminal statement on exit,
697
+ # which flips Statement.phase to DELETED (it overrides the underlying phase once
698
+ # deleted -- see Statement.phase) -- so we can't read back "COMPLETED" directly here.
699
+ # is_deleted only follows from a *deletable* terminal phase (COMPLETED/FAILED/
700
+ # STOPPED); FAILED would have raised OperationalError out of execute_streaming_ddl
701
+ # instead of returning, and nothing here ever requested a STOPPED, so reaching this
702
+ # line with is_deleted true and no exception raised is exactly the proof that the
703
+ # statement settled to COMPLETED.
704
+ assert not statement.is_running
705
+ assert statement.is_deleted
706
+
707
+ # The table should be immediately queryable.
708
+ with connection.closing_cursor(as_dict=True) as cursor:
709
+ cursor.execute(f"SELECT COUNT(*) AS row_count FROM `{auto_dropped_table_name}`")
710
+ results = cursor.fetchone()
711
+ assert results is not None
712
+ finally:
713
+ with suppress(Exception):
714
+ connection.execute_snapshot_ddl(
715
+ f"DROP MATERIALIZED TABLE IF EXISTS `{auto_dropped_table_name}`"
716
+ )
717
+
718
+ def test_execute_streaming_ddl_create_or_alter_materialized_table_completes(
719
+ self, connection: Connection, auto_dropped_table_name: str
720
+ ):
721
+ """Prove that CREATE OR ALTER MATERIALIZED TABLE, and a bare (query-evolving) ALTER
722
+ MATERIALIZED TABLE, both also wait for COMPLETED, same as a first-time CREATE
723
+ MATERIALIZED TABLE. Each step respells the filter predicate (>100, then >=100, then >50)
724
+ to exercise a genuine redefinition of an already-existing materialized table."""
725
+
726
+ def show_create_ddl_text(table_name: str) -> str:
727
+ # SHOW CREATE MATERIALIZED TABLE is a plain bounded single-row query, so a default
728
+ # (snapshot mode) cursor is all it needs.
729
+ with connection.closing_cursor(as_dict=True) as cursor:
730
+ cursor.execute(f"SHOW CREATE MATERIALIZED TABLE `{table_name}`")
731
+ row = cursor.fetchone()
732
+ assert row is not None
733
+ return row["SHOW CREATE MATERIALIZED TABLE"] # type: ignore[index]
734
+
735
+ try:
736
+ create_statement_text = f"""
737
+ CREATE MATERIALIZED TABLE `{auto_dropped_table_name}`
738
+ AS SELECT * FROM `sample_data_stock_trades` WHERE quantity > 100
739
+ """
740
+ created = connection.execute_streaming_ddl(create_statement_text)
741
+ assert not created.is_running
742
+ assert created.is_deleted # see the sibling CREATE test for why this implies COMPLETED
743
+
744
+ create_or_alter_statement_text = f"""
745
+ CREATE OR ALTER MATERIALIZED TABLE `{auto_dropped_table_name}`
746
+ AS SELECT * FROM `sample_data_stock_trades` WHERE quantity >= 100
747
+ """
748
+ create_or_altered = connection.execute_streaming_ddl(create_or_alter_statement_text)
749
+
750
+ assert not create_or_altered.is_running
751
+ assert create_or_altered.is_deleted
752
+
753
+ # Prove the redefinition actually took effect.
754
+ assert ">= 100" in show_create_ddl_text(auto_dropped_table_name)
755
+
756
+ # A bare ALTER (no CREATE OR prefix) with a new AS SELECT is query evolution too --
757
+ # same completion semantics, since ALTER_MATERIALIZED_TABLE is also pure DDL.
758
+ bare_alter_statement_text = f"""
759
+ ALTER MATERIALIZED TABLE `{auto_dropped_table_name}`
760
+ AS SELECT * FROM `sample_data_stock_trades` WHERE quantity > 50
761
+ """
762
+ bare_altered = connection.execute_streaming_ddl(bare_alter_statement_text)
763
+
764
+ assert not bare_altered.is_running
765
+ assert bare_altered.is_deleted
766
+
767
+ assert "> 50" in show_create_ddl_text(auto_dropped_table_name)
768
+ finally:
769
+ with suppress(Exception):
770
+ connection.execute_snapshot_ddl(
771
+ f"DROP MATERIALIZED TABLE IF EXISTS `{auto_dropped_table_name}`"
772
+ )
773
+
774
+ def test_execute_snapshot_ddl_drop_materialized_table_completes(
775
+ self, connection: Connection, auto_dropped_table_name: str
776
+ ):
777
+ """Prove that DROP MATERIALIZED TABLE, submitted via execute_snapshot_ddl(), completes
778
+ (it's pure DDL, like the other DROP_* kinds -- see statement.py's _PURE_DDL_KINDS)."""
779
+ try:
780
+ create_statement_text = f"""
781
+ CREATE MATERIALIZED TABLE `{auto_dropped_table_name}`
782
+ AS SELECT * FROM `sample_data_stock_trades` WHERE quantity > 100
783
+ """
784
+ connection.execute_streaming_ddl(create_statement_text)
785
+
786
+ drop_statement = connection.execute_snapshot_ddl(
787
+ f"DROP MATERIALIZED TABLE `{auto_dropped_table_name}`"
788
+ )
789
+
790
+ # is_deleted implies COMPLETED here, not just some other deletable terminal phase --
791
+ # see the CREATE test above for why.
792
+ assert not drop_statement.is_running
793
+ assert drop_statement.is_deleted
794
+
795
+ # The table should be gone: selecting from it should now fail with the backend's
796
+ # missing-object diagnostic, not just some unrelated failure.
797
+ with (
798
+ pytest.raises(OperationalError, match="does not exist"),
799
+ connection.closing_cursor() as cursor,
800
+ ):
801
+ cursor.execute(f"SELECT * FROM `{auto_dropped_table_name}`")
802
+ finally:
803
+ with suppress(Exception):
804
+ connection.execute_snapshot_ddl(
805
+ f"DROP MATERIALIZED TABLE IF EXISTS `{auto_dropped_table_name}`"
806
+ )
807
+
681
808
 
682
809
  @pytest.mark.integration
683
810
  class TestArrayStatements:
@@ -440,6 +440,10 @@ class TestStatementProperties:
440
440
  ("CREATE_VIEW", True),
441
441
  ("DROP_VIEW", True),
442
442
  ("ALTER_TABLE", True),
443
+ ("CREATE_MATERIALIZED_TABLE", True),
444
+ ("CREATE_OR_ALTER_MATERIALIZED_TABLE", True),
445
+ ("ALTER_MATERIALIZED_TABLE", True),
446
+ ("DROP_MATERIALIZED_TABLE", True),
443
447
  ("SELECT", False),
444
448
  ("INSERT", False),
445
449
  ("UPDATE", False),
@@ -980,32 +984,63 @@ class TestStatementCanFetchResults:
980
984
  statement = Statement.from_response(mock_connection, statement_json)
981
985
  assert statement.can_fetch_results(ExecutionMode.STREAMING_QUERY)
982
986
 
987
+ @pytest.mark.parametrize(
988
+ "sql_kind",
989
+ [
990
+ "CREATE_TABLE",
991
+ "CREATE_MATERIALIZED_TABLE",
992
+ "CREATE_OR_ALTER_MATERIALIZED_TABLE",
993
+ "ALTER_MATERIALIZED_TABLE",
994
+ "DROP_MATERIALIZED_TABLE",
995
+ ],
996
+ )
983
997
  @pytest.mark.parametrize("phase", ["PENDING", "RUNNING"])
984
998
  def test_streaming_ddl_pure_ddl_not_ready(
985
999
  self,
986
1000
  mock_connection: Connection,
987
1001
  statement_response_factory: StatementResponseFactory,
988
1002
  phase: str,
1003
+ sql_kind: str,
989
1004
  ):
990
- """In streaming DDL mode, pure DDL must wait for terminal state."""
1005
+ """In streaming DDL mode, pure DDL must wait for terminal state.
1006
+
1007
+ The three MATERIALIZED_TABLE kinds are included alongside CREATE_TABLE here: even though
1008
+ CREATE_MATERIALIZED_TABLE, CREATE_OR_ALTER_MATERIALIZED_TABLE, and
1009
+ ALTER_MATERIALIZED_TABLE all kick off (or redeploy) a persistent background refresh job
1010
+ on completion, each statement's own phase reliably reaches a terminal phase once that job
1011
+ is started (confirmed against a real environment -- unlike CTAS, which the Flink API
1012
+ traits currently mis-report as perpetually RUNNING, see is_bounded's Jan 2026 bug note),
1013
+ so they belong in the same "must wait for terminal" bucket as the other pure DDL kinds.
1014
+ """
991
1015
  statement_json = statement_response_factory(
992
1016
  phase=phase,
993
- sql_kind="CREATE_TABLE",
1017
+ sql_kind=sql_kind,
994
1018
  )
995
1019
  statement = Statement.from_response(mock_connection, statement_json)
996
1020
  assert not statement.can_fetch_results(ExecutionMode.STREAMING_DDL)
997
1021
 
1022
+ @pytest.mark.parametrize(
1023
+ "sql_kind",
1024
+ [
1025
+ "CREATE_TABLE",
1026
+ "CREATE_MATERIALIZED_TABLE",
1027
+ "CREATE_OR_ALTER_MATERIALIZED_TABLE",
1028
+ "ALTER_MATERIALIZED_TABLE",
1029
+ "DROP_MATERIALIZED_TABLE",
1030
+ ],
1031
+ )
998
1032
  @pytest.mark.parametrize("phase", ["COMPLETED", "STOPPED", "FAILED"])
999
1033
  def test_streaming_ddl_pure_ddl_ready(
1000
1034
  self,
1001
1035
  mock_connection: Connection,
1002
1036
  statement_response_factory: StatementResponseFactory,
1003
1037
  phase: str,
1038
+ sql_kind: str,
1004
1039
  ):
1005
1040
  """In streaming DDL mode, pure DDL is ready in terminal states."""
1006
1041
  statement_json = statement_response_factory(
1007
1042
  phase=phase,
1008
- sql_kind="CREATE_TABLE",
1043
+ sql_kind=sql_kind,
1009
1044
  )
1010
1045
  statement = Statement.from_response(mock_connection, statement_json)
1011
1046
  assert statement.can_fetch_results(ExecutionMode.STREAMING_DDL)
@@ -36,7 +36,7 @@ wheels = [
36
36
 
37
37
  [[package]]
38
38
  name = "confluent-sql"
39
- version = "0.5.1"
39
+ version = "0.5.2"
40
40
  source = { editable = "." }
41
41
  dependencies = [
42
42
  { name = "httpx" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes