dblift 3.3.2__tar.gz → 3.3.4__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 (474) hide show
  1. {dblift-3.3.2 → dblift-3.3.4}/PKG-INFO +3 -3
  2. {dblift-3.3.2 → dblift-3.3.4}/README.md +2 -2
  3. {dblift-3.3.2 → dblift-3.3.4}/core/logger/_formatters.py +47 -38
  4. {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/jsonformatter.py +2 -34
  5. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cockroachdb/__init__.py +8 -0
  6. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cockroachdb/plugin.py +5 -1
  7. dblift-3.3.4/db/plugins/cockroachdb/sqlalchemy_dialect.py +124 -0
  8. dblift-3.3.4/db/plugins/cockroachdb/sqlalchemy_url.py +93 -0
  9. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/provider.py +169 -1
  10. {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/PKG-INFO +3 -3
  11. {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/SOURCES.txt +2 -0
  12. {dblift-3.3.2 → dblift-3.3.4}/pyproject.toml +1 -1
  13. {dblift-3.3.2 → dblift-3.3.4}/LICENSE +0 -0
  14. {dblift-3.3.2 → dblift-3.3.4}/api/__init__.py +0 -0
  15. {dblift-3.3.2 → dblift-3.3.4}/api/_cli_support.py +0 -0
  16. {dblift-3.3.2 → dblift-3.3.4}/api/_client_factory.py +0 -0
  17. {dblift-3.3.2 → dblift-3.3.4}/api/_client_operations.py +0 -0
  18. {dblift-3.3.2 → dblift-3.3.4}/api/_engine_config.py +0 -0
  19. {dblift-3.3.2 → dblift-3.3.4}/api/async_client.py +0 -0
  20. {dblift-3.3.2 → dblift-3.3.4}/api/client.py +0 -0
  21. {dblift-3.3.2 → dblift-3.3.4}/api/events.py +0 -0
  22. {dblift-3.3.2 → dblift-3.3.4}/api/migrations.py +0 -0
  23. {dblift-3.3.2 → dblift-3.3.4}/api/py.typed +0 -0
  24. {dblift-3.3.2 → dblift-3.3.4}/cli/__init__.py +0 -0
  25. {dblift-3.3.2 → dblift-3.3.4}/cli/_command_handlers.py +0 -0
  26. {dblift-3.3.2 → dblift-3.3.4}/cli/_config_helpers.py +0 -0
  27. {dblift-3.3.2 → dblift-3.3.4}/cli/_constants.py +0 -0
  28. {dblift-3.3.2 → dblift-3.3.4}/cli/_output.py +0 -0
  29. {dblift-3.3.2 → dblift-3.3.4}/cli/_parser_setup.py +0 -0
  30. {dblift-3.3.2 → dblift-3.3.4}/cli/commands/__init__.py +0 -0
  31. {dblift-3.3.2 → dblift-3.3.4}/cli/commands/config_command.py +0 -0
  32. {dblift-3.3.2 → dblift-3.3.4}/cli/db_utils.py +0 -0
  33. {dblift-3.3.2 → dblift-3.3.4}/cli/extensions.py +0 -0
  34. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/__init__.py +0 -0
  35. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/_shared.py +0 -0
  36. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/baseline.py +0 -0
  37. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/clean.py +0 -0
  38. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/import_flyway.py +0 -0
  39. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/info.py +0 -0
  40. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/migrate.py +0 -0
  41. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/repair.py +0 -0
  42. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/undo.py +0 -0
  43. {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/validate.py +0 -0
  44. {dblift-3.3.2 → dblift-3.3.4}/cli/main.py +0 -0
  45. {dblift-3.3.2 → dblift-3.3.4}/cli/premium_manifest.py +0 -0
  46. {dblift-3.3.2 → dblift-3.3.4}/config/__init__.py +0 -0
  47. {dblift-3.3.2 → dblift-3.3.4}/config/_credential_masking.py +0 -0
  48. {dblift-3.3.2 → dblift-3.3.4}/config/_subclasses/__init__.py +0 -0
  49. {dblift-3.3.2 → dblift-3.3.4}/config/_subclasses/dummy_config.py +0 -0
  50. {dblift-3.3.2 → dblift-3.3.4}/config/_url_builder_mixin.py +0 -0
  51. {dblift-3.3.2 → dblift-3.3.4}/config/config_builder.py +0 -0
  52. {dblift-3.3.2 → dblift-3.3.4}/config/database_config.py +0 -0
  53. {dblift-3.3.2 → dblift-3.3.4}/config/dblift_config.py +0 -0
  54. {dblift-3.3.2 → dblift-3.3.4}/config/errors.py +0 -0
  55. {dblift-3.3.2 → dblift-3.3.4}/config/property_registry.py +0 -0
  56. {dblift-3.3.2 → dblift-3.3.4}/config/secrets/__init__.py +0 -0
  57. {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_cache.py +0 -0
  58. {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_provider_base.py +0 -0
  59. {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_registry.py +0 -0
  60. {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_resolver.py +0 -0
  61. {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_secrets_config.py +0 -0
  62. {dblift-3.3.2 → dblift-3.3.4}/core/__init__.py +0 -0
  63. {dblift-3.3.2 → dblift-3.3.4}/core/constants.py +0 -0
  64. {dblift-3.3.2 → dblift-3.3.4}/core/dialect_boundary.py +0 -0
  65. {dblift-3.3.2 → dblift-3.3.4}/core/exceptions.py +0 -0
  66. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/__init__.py +0 -0
  67. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_column_enricher.py +0 -0
  68. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_partition_enricher.py +0 -0
  69. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_schema_orchestrator.py +0 -0
  70. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_utils.py +0 -0
  71. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_vendor_property_applier.py +0 -0
  72. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/base_introspector.py +0 -0
  73. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/__init__.py +0 -0
  74. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/base_extractor.py +0 -0
  75. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/column_extractor.py +0 -0
  76. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/constraint_extractor.py +0 -0
  77. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/index_extractor.py +0 -0
  78. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/misc_extractor.py +0 -0
  79. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/procedure_extractor.py +0 -0
  80. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/sequence_extractor.py +0 -0
  81. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/table_extractor.py +0 -0
  82. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/trigger_extractor.py +0 -0
  83. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/view_extractor.py +0 -0
  84. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/introspector_factory.py +0 -0
  85. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/result.py +0 -0
  86. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/schema_introspector.py +0 -0
  87. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/vendor_queries_base.py +0 -0
  88. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/vendor_queries_factory.py +0 -0
  89. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/vendor_queries_protocols.py +0 -0
  90. {dblift-3.3.2 → dblift-3.3.4}/core/introspection/version_detector.py +0 -0
  91. {dblift-3.3.2 → dblift-3.3.4}/core/logger/__init__.py +0 -0
  92. {dblift-3.3.2 → dblift-3.3.4}/core/logger/_base.py +0 -0
  93. {dblift-3.3.2 → dblift-3.3.4}/core/logger/_factory.py +0 -0
  94. {dblift-3.3.2 → dblift-3.3.4}/core/logger/_levels.py +0 -0
  95. {dblift-3.3.2 → dblift-3.3.4}/core/logger/_multi.py +0 -0
  96. {dblift-3.3.2 → dblift-3.3.4}/core/logger/_null.py +0 -0
  97. {dblift-3.3.2 → dblift-3.3.4}/core/logger/console.py +0 -0
  98. {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/__init__.py +0 -0
  99. {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/_formatter_impl.py +0 -0
  100. {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/factory.py +0 -0
  101. {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/formatter.py +0 -0
  102. {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/htmlformatter.py +0 -0
  103. {dblift-3.3.2 → dblift-3.3.4}/core/logger/log.py +0 -0
  104. {dblift-3.3.2 → dblift-3.3.4}/core/logger/results.py +0 -0
  105. {dblift-3.3.2 → dblift-3.3.4}/core/logger/templates/oldreport.html +0 -0
  106. {dblift-3.3.2 → dblift-3.3.4}/core/logger/templates/report.html +0 -0
  107. {dblift-3.3.2 → dblift-3.3.4}/core/migration/__init__.py +0 -0
  108. {dblift-3.3.2 → dblift-3.3.4}/core/migration/_type_match.py +0 -0
  109. {dblift-3.3.2 → dblift-3.3.4}/core/migration/clean_summary.py +0 -0
  110. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/__init__.py +0 -0
  111. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/_script_events.py +0 -0
  112. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/base_command.py +0 -0
  113. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/baseline_command.py +0 -0
  114. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/clean_command.py +0 -0
  115. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/import_flyway_command.py +0 -0
  116. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/info_command.py +0 -0
  117. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/migrate_command.py +0 -0
  118. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/repair_command.py +0 -0
  119. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/undo_command.py +0 -0
  120. {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/validate_command.py +0 -0
  121. {dblift-3.3.2 → dblift-3.3.4}/core/migration/encoding.py +0 -0
  122. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/__init__.py +0 -0
  123. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/execution_engine.py +0 -0
  124. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/migration_executor.py +0 -0
  125. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/migration_helpers.py +0 -0
  126. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/placeholder_manager.py +0 -0
  127. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/transaction_policy.py +0 -0
  128. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/__init__.py +0 -0
  129. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/base_executor.py +0 -0
  130. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/executor_factory.py +0 -0
  131. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/python_executor.py +0 -0
  132. {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/sql_executor.py +0 -0
  133. {dblift-3.3.2 → dblift-3.3.4}/core/migration/formats/__init__.py +0 -0
  134. {dblift-3.3.2 → dblift-3.3.4}/core/migration/formats/format_detector.py +0 -0
  135. {dblift-3.3.2 → dblift-3.3.4}/core/migration/formats/migration_format.py +0 -0
  136. {dblift-3.3.2 → dblift-3.3.4}/core/migration/history/__init__.py +0 -0
  137. {dblift-3.3.2 → dblift-3.3.4}/core/migration/history/migration_history_manager.py +0 -0
  138. {dblift-3.3.2 → dblift-3.3.4}/core/migration/journals/__init__.py +0 -0
  139. {dblift-3.3.2 → dblift-3.3.4}/core/migration/journals/migration_journal.py +0 -0
  140. {dblift-3.3.2 → dblift-3.3.4}/core/migration/migration.py +0 -0
  141. {dblift-3.3.2 → dblift-3.3.4}/core/migration/placeholders/__init__.py +0 -0
  142. {dblift-3.3.2 → dblift-3.3.4}/core/migration/placeholders/placeholder_service.py +0 -0
  143. {dblift-3.3.2 → dblift-3.3.4}/core/migration/rules/__init__.py +0 -0
  144. {dblift-3.3.2 → dblift-3.3.4}/core/migration/rules/migration_rules.py +0 -0
  145. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/__init__.py +0 -0
  146. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/migration_script_manager.py +0 -0
  147. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/__init__.py +0 -0
  148. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_ddl_reversers.py +0 -0
  149. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_dml_reversers.py +0 -0
  150. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_extractors.py +0 -0
  151. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_generator.py +0 -0
  152. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_helpers.py +0 -0
  153. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_models.py +0 -0
  154. {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_reversers.py +0 -0
  155. {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/__init__.py +0 -0
  156. {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/execution_statement.py +0 -0
  157. {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/sql_analyzer.py +0 -0
  158. {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/sql_execution_service.py +0 -0
  159. {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/statement_splitter.py +0 -0
  160. {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/__init__.py +0 -0
  161. {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_data_service.py +0 -0
  162. {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_display_state.py +0 -0
  163. {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_formatter.py +0 -0
  164. {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_state.py +0 -0
  165. {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_state_manager.py +0 -0
  166. {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_state_service.py +0 -0
  167. {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/__init__.py +0 -0
  168. {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/data_collector.py +0 -0
  169. {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/display_formatters.py +0 -0
  170. {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/migration_analyzer.py +0 -0
  171. {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/migration_ui.py +0 -0
  172. {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/table_renderer.py +0 -0
  173. {dblift-3.3.2 → dblift-3.3.4}/core/migration/version_utils.py +0 -0
  174. {dblift-3.3.2 → dblift-3.3.4}/core/normalization/__init__.py +0 -0
  175. {dblift-3.3.2 → dblift-3.3.4}/core/normalization/dependency_resolver.py +0 -0
  176. {dblift-3.3.2 → dblift-3.3.4}/core/normalization/identifier_normalizer.py +0 -0
  177. {dblift-3.3.2 → dblift-3.3.4}/core/normalization/object_orderer.py +0 -0
  178. {dblift-3.3.2 → dblift-3.3.4}/core/normalization/type_constants.py +0 -0
  179. {dblift-3.3.2 → dblift-3.3.4}/core/normalization/type_mapper.py +0 -0
  180. {dblift-3.3.2 → dblift-3.3.4}/core/normalization/type_mappings.py +0 -0
  181. {dblift-3.3.2 → dblift-3.3.4}/core/normalization/type_normalizer.py +0 -0
  182. {dblift-3.3.2 → dblift-3.3.4}/core/seams/__init__.py +0 -0
  183. {dblift-3.3.2 → dblift-3.3.4}/core/seams/capabilities.py +0 -0
  184. {dblift-3.3.2 → dblift-3.3.4}/core/seams/client_factory.py +0 -0
  185. {dblift-3.3.2 → dblift-3.3.4}/core/seams/event_listeners.py +0 -0
  186. {dblift-3.3.2 → dblift-3.3.4}/core/seams/feature_loading.py +0 -0
  187. {dblift-3.3.2 → dblift-3.3.4}/core/seams/introspection.py +0 -0
  188. {dblift-3.3.2 → dblift-3.3.4}/core/seams/license_info.py +0 -0
  189. {dblift-3.3.2 → dblift-3.3.4}/core/seams/runtime_checks.py +0 -0
  190. {dblift-3.3.2 → dblift-3.3.4}/core/seams/sql_generators.py +0 -0
  191. {dblift-3.3.2 → dblift-3.3.4}/core/seams/tier_resolver.py +0 -0
  192. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/__init__.py +0 -0
  193. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/alter/__init__.py +0 -0
  194. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/alter/alter_generator_factory.py +0 -0
  195. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/alter/base_alter_generator.py +0 -0
  196. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/alter_generator.py +0 -0
  197. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/base_generator.py +0 -0
  198. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/basic_table_ddl_generator.py +0 -0
  199. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/dependency_analyzer.py +0 -0
  200. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/diff_converters/__init__.py +0 -0
  201. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/diff_converters/base_converter.py +0 -0
  202. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/formatter.py +0 -0
  203. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/generator_factory.py +0 -0
  204. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/options.py +0 -0
  205. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/script_organizer.py +0 -0
  206. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/sql_generator.py +0 -0
  207. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/sql_statement.py +0 -0
  208. {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/table_ddl_render.py +0 -0
  209. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/__init__.py +0 -0
  210. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_parse_result.py +0 -0
  211. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_sql_column.py +0 -0
  212. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_sql_constraint.py +0 -0
  213. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_sql_object.py +0 -0
  214. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_sql_statement.py +0 -0
  215. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/base.py +0 -0
  216. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/constraint_validator.py +0 -0
  217. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/database_link.py +0 -0
  218. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/dialect.py +0 -0
  219. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/event.py +0 -0
  220. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/extension.py +0 -0
  221. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/feature_gates.py +0 -0
  222. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/foreign_data_wrapper.py +0 -0
  223. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/foreign_server.py +0 -0
  224. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/index.py +0 -0
  225. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/linked_server.py +0 -0
  226. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/module.py +0 -0
  227. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/package.py +0 -0
  228. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/partition.py +0 -0
  229. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/procedure.py +0 -0
  230. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/sequence.py +0 -0
  231. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/server_info.py +0 -0
  232. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/synonym.py +0 -0
  233. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/table.py +0 -0
  234. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/table_canonicalizer.py +0 -0
  235. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/table_options.py +0 -0
  236. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/trigger.py +0 -0
  237. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/user_defined_type.py +0 -0
  238. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/view.py +0 -0
  239. {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/view_options.py +0 -0
  240. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/__init__.py +0 -0
  241. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/_partition_handler.py +0 -0
  242. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/_sqlglot_builders.py +0 -0
  243. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/base_statement_parser.py +0 -0
  244. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/base_tokenizer.py +0 -0
  245. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/common/__init__.py +0 -0
  246. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/common/base_parser.py +0 -0
  247. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/dialects/__init__.py +0 -0
  248. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/dialects/base_config.py +0 -0
  249. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/enhanced_regex_parser.py +0 -0
  250. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/hybrid_parser.py +0 -0
  251. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/parser_context.py +0 -0
  252. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/parser_factory.py +0 -0
  253. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/parser_interface.py +0 -0
  254. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/sqlglot_parser.py +0 -0
  255. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/tokens.py +0 -0
  256. {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/unified_regex_parser.py +0 -0
  257. {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/__init__.py +0 -0
  258. {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_checksum_validator.py +0 -0
  259. {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_flyway_compatibility.py +0 -0
  260. {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_migration_filter.py +0 -0
  261. {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_sql_syntax_validator.py +0 -0
  262. {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_strict_mode_validator.py +0 -0
  263. {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/migration_validator.py +0 -0
  264. {dblift-3.3.2 → dblift-3.3.4}/core/state/sql_script_formatter.py +0 -0
  265. {dblift-3.3.2 → dblift-3.3.4}/core/state/sql_statement.py +0 -0
  266. {dblift-3.3.2 → dblift-3.3.4}/core/utils/__init__.py +0 -0
  267. {dblift-3.3.2 → dblift-3.3.4}/core/utils/database_url_parser.py +0 -0
  268. {dblift-3.3.2 → dblift-3.3.4}/core/utils/metadata_helpers.py +0 -0
  269. {dblift-3.3.2 → dblift-3.3.4}/core/utils/row_access.py +0 -0
  270. {dblift-3.3.2 → dblift-3.3.4}/core/utils/string_utils.py +0 -0
  271. {dblift-3.3.2 → dblift-3.3.4}/core/utils/url_masking.py +0 -0
  272. {dblift-3.3.2 → dblift-3.3.4}/db/__init__.py +0 -0
  273. {dblift-3.3.2 → dblift-3.3.4}/db/base_provider.py +0 -0
  274. {dblift-3.3.2 → dblift-3.3.4}/db/base_quirks.py +0 -0
  275. {dblift-3.3.2 → dblift-3.3.4}/db/constants.py +0 -0
  276. {dblift-3.3.2 → dblift-3.3.4}/db/dml_analysis.py +0 -0
  277. {dblift-3.3.2 → dblift-3.3.4}/db/error.py +0 -0
  278. {dblift-3.3.2 → dblift-3.3.4}/db/error_handler.py +0 -0
  279. {dblift-3.3.2 → dblift-3.3.4}/db/exceptions.py +0 -0
  280. {dblift-3.3.2 → dblift-3.3.4}/db/feature_gate.py +0 -0
  281. {dblift-3.3.2 → dblift-3.3.4}/db/native_connection_manager.py +0 -0
  282. {dblift-3.3.2 → dblift-3.3.4}/db/object_naming.py +0 -0
  283. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/__init__.py +0 -0
  284. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/_pg_compatible.py +0 -0
  285. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/alloydb/__init__.py +0 -0
  286. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/alloydb/plugin.py +0 -0
  287. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/aurora_postgresql/__init__.py +0 -0
  288. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/aurora_postgresql/plugin.py +0 -0
  289. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_history_manager.py +0 -0
  290. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_locking_manager.py +0 -0
  291. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_query_executor.py +0 -0
  292. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_schema_operations.py +0 -0
  293. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_snapshot_manager.py +0 -0
  294. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_undo_manager.py +0 -0
  295. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/citus/__init__.py +0 -0
  296. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/citus/plugin.py +0 -0
  297. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cockroachdb/provider.py +0 -0
  298. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cockroachdb/quirks.py +0 -0
  299. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/__init__.py +0 -0
  300. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/config.py +0 -0
  301. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/__init__.py +0 -0
  302. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/_sdk.py +0 -0
  303. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/connection_manager.py +0 -0
  304. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/history_manager.py +0 -0
  305. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/locking_manager.py +0 -0
  306. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/query_executor.py +0 -0
  307. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/schema_operations.py +0 -0
  308. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/introspection/__init__.py +0 -0
  309. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/plugin.py +0 -0
  310. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/provider.py +0 -0
  311. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/quirks.py +0 -0
  312. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/__init__.py +0 -0
  313. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/config.py +0 -0
  314. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/db2/__init__.py +0 -0
  315. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/db2/history_manager.py +0 -0
  316. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/db2/locking_manager.py +0 -0
  317. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/db2/schema_operations.py +0 -0
  318. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/introspection/__init__.py +0 -0
  319. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/parser/__init__.py +0 -0
  320. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/parser/db2_regex_parser.py +0 -0
  321. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/parser/parser_config.py +0 -0
  322. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/plugin.py +0 -0
  323. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/provider.py +0 -0
  324. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/quirks.py +0 -0
  325. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/sqlalchemy_url.py +0 -0
  326. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/__init__.py +0 -0
  327. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/config.py +0 -0
  328. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/parser/__init__.py +0 -0
  329. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/parser/duckdb_regex_parser.py +0 -0
  330. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/parser/parser_config.py +0 -0
  331. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/plugin.py +0 -0
  332. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/quirks.py +0 -0
  333. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/sqlalchemy_url.py +0 -0
  334. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mariadb/__init__.py +0 -0
  335. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mariadb/plugin.py +0 -0
  336. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mariadb/provider.py +0 -0
  337. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mariadb/quirks.py +0 -0
  338. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/__init__.py +0 -0
  339. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/config.py +0 -0
  340. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/introspection/__init__.py +0 -0
  341. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/mysql/__init__.py +0 -0
  342. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/mysql/history_manager.py +0 -0
  343. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/mysql/locking_manager.py +0 -0
  344. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/mysql/schema_operations.py +0 -0
  345. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/__init__.py +0 -0
  346. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/mysql_regex_parser.py +0 -0
  347. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/mysql_statement_parser.py +0 -0
  348. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/mysql_tokenizer.py +0 -0
  349. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/parser_config.py +0 -0
  350. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/plugin.py +0 -0
  351. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/provider.py +0 -0
  352. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/quirks.py +0 -0
  353. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/sqlalchemy_url.py +0 -0
  354. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/neon/__init__.py +0 -0
  355. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/neon/plugin.py +0 -0
  356. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/nosql_base/__init__.py +0 -0
  357. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/nosql_base/history.py +0 -0
  358. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/nosql_base/introspection.py +0 -0
  359. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/nosql_base/locking.py +0 -0
  360. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/__init__.py +0 -0
  361. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/config.py +0 -0
  362. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/introspection/__init__.py +0 -0
  363. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/introspection/oracle_utils.py +0 -0
  364. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/__init__.py +0 -0
  365. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/dbms_output.py +0 -0
  366. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/history_manager.py +0 -0
  367. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/locking_manager.py +0 -0
  368. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/schema_operations.py +0 -0
  369. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/__init__.py +0 -0
  370. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_comments.py +0 -0
  371. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_object_extractor.py +0 -0
  372. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_plsql_block.py +0 -0
  373. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_sqlplus.py +0 -0
  374. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_statement_splitter.py +0 -0
  375. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/oracle_parser.py +0 -0
  376. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/oracle_statement_parser.py +0 -0
  377. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/oracle_tokenizer.py +0 -0
  378. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/parser_config.py +0 -0
  379. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/sqlplus_context.py +0 -0
  380. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/plugin.py +0 -0
  381. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/provider.py +0 -0
  382. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/quirks.py +0 -0
  383. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/sqlalchemy_url.py +0 -0
  384. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/__init__.py +0 -0
  385. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/_provider_query_executor.py +0 -0
  386. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/config.py +0 -0
  387. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/introspection/__init__.py +0 -0
  388. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/__init__.py +0 -0
  389. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/parser_config.py +0 -0
  390. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/postgresql_regex_parser.py +0 -0
  391. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/postgresql_statement_parser.py +0 -0
  392. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/postgresql_tokenizer.py +0 -0
  393. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/plugin.py +0 -0
  394. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/postgresql/__init__.py +0 -0
  395. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/postgresql/history_manager.py +0 -0
  396. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/postgresql/locking_manager.py +0 -0
  397. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/postgresql/schema_operations.py +0 -0
  398. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/provider.py +0 -0
  399. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/quirks.py +0 -0
  400. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/sqlalchemy_url.py +0 -0
  401. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/__init__.py +0 -0
  402. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/plugin.py +0 -0
  403. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/provider.py +0 -0
  404. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/quirks.py +0 -0
  405. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/sqlalchemy_url.py +0 -0
  406. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/__init__.py +0 -0
  407. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/config.py +0 -0
  408. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/plugin.py +0 -0
  409. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/provider.py +0 -0
  410. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/quirks.py +0 -0
  411. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/sqlalchemy_url.py +0 -0
  412. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/__init__.py +0 -0
  413. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/config.py +0 -0
  414. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/introspection/__init__.py +0 -0
  415. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/parser/__init__.py +0 -0
  416. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/parser/parser_config.py +0 -0
  417. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/parser/sqlite_regex_parser.py +0 -0
  418. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/plugin.py +0 -0
  419. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/provider.py +0 -0
  420. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/quirks.py +0 -0
  421. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlalchemy_url.py +0 -0
  422. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/__init__.py +0 -0
  423. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/connection_manager.py +0 -0
  424. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/history_manager.py +0 -0
  425. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/locking_manager.py +0 -0
  426. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/query_executor.py +0 -0
  427. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/schema_operations.py +0 -0
  428. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/__init__.py +0 -0
  429. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/config.py +0 -0
  430. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/introspection/__init__.py +0 -0
  431. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/__init__.py +0 -0
  432. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/parser_config.py +0 -0
  433. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/sqlserver_regex_parser.py +0 -0
  434. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/sqlserver_statement_parser.py +0 -0
  435. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/sqlserver_tokenizer.py +0 -0
  436. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/tsql_batch_separator.py +0 -0
  437. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/plugin.py +0 -0
  438. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/provider.py +0 -0
  439. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/quirks.py +0 -0
  440. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlalchemy_url.py +0 -0
  441. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlserver/__init__.py +0 -0
  442. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlserver/history_manager.py +0 -0
  443. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlserver/locking_manager.py +0 -0
  444. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlserver/schema_operations.py +0 -0
  445. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/supabase/__init__.py +0 -0
  446. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/supabase/plugin.py +0 -0
  447. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/timescaledb/__init__.py +0 -0
  448. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/timescaledb/plugin.py +0 -0
  449. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/yugabytedb/__init__.py +0 -0
  450. {dblift-3.3.2 → dblift-3.3.4}/db/plugins/yugabytedb/plugin.py +0 -0
  451. {dblift-3.3.2 → dblift-3.3.4}/db/provider_capabilities.py +0 -0
  452. {dblift-3.3.2 → dblift-3.3.4}/db/provider_interfaces.py +0 -0
  453. {dblift-3.3.2 → dblift-3.3.4}/db/provider_registry.py +0 -0
  454. {dblift-3.3.2 → dblift-3.3.4}/db/sqlalchemy_provider.py +0 -0
  455. {dblift-3.3.2 → dblift-3.3.4}/db/value_utils.py +0 -0
  456. {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/dependency_links.txt +0 -0
  457. {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/entry_points.txt +0 -0
  458. {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/requires.txt +0 -0
  459. {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/top_level.txt +0 -0
  460. {dblift-3.3.2 → dblift-3.3.4}/integrations/__init__.py +0 -0
  461. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/__init__.py +0 -0
  462. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/_client.py +0 -0
  463. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/_engine.py +0 -0
  464. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/apps.py +0 -0
  465. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/checks.py +0 -0
  466. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/__init__.py +0 -0
  467. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/commands/__init__.py +0 -0
  468. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/commands/dblift_info.py +0 -0
  469. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/commands/dblift_migrate.py +0 -0
  470. {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/commands/dblift_validate.py +0 -0
  471. {dblift-3.3.2 → dblift-3.3.4}/integrations/fastapi.py +0 -0
  472. {dblift-3.3.2 → dblift-3.3.4}/integrations/flask.py +0 -0
  473. {dblift-3.3.2 → dblift-3.3.4}/integrations/opentelemetry.py +0 -0
  474. {dblift-3.3.2 → dblift-3.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dblift
3
- Version: 3.3.2
3
+ Version: 3.3.4
4
4
  Summary: A database migration tool that supports multiple databases with native Python drivers
5
5
  Classifier: Development Status :: 5 - Production/Stable
6
6
  Classifier: Intended Audience :: Developers
@@ -115,8 +115,8 @@ Dynamic: license-file
115
115
 
116
116
  ![Python](https://img.shields.io/badge/Python-3.11%2B-blue)
117
117
  ![License](https://img.shields.io/badge/License-Apache--2.0-blue)
118
- [![Unit Tests](https://github.com/cmodiano/dblift-oss/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/cmodiano/dblift-oss/actions/workflows/unit-tests.yml)
119
- [![codecov](https://codecov.io/gh/cmodiano/dblift-oss/graph/badge.svg)](https://codecov.io/gh/cmodiano/dblift-oss)
118
+ [![Unit Tests](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml)
119
+ [![codecov](https://codecov.io/gh/dblift/dblift/graph/badge.svg)](https://codecov.io/gh/dblift/dblift)
120
120
  [![Security Policy](https://img.shields.io/badge/Security-Policy-green)](SECURITY.md)
121
121
 
122
122
  Application code usually has tests, CI pipelines, and pull request review. Database changes often skip one or more of those stages. DBLift is a Python-native migration toolkit that shows you exactly what SQL will run before it runs — and keeps the full migration lifecycle inside your Python workflow. No JVM required.
@@ -6,8 +6,8 @@
6
6
 
7
7
  ![Python](https://img.shields.io/badge/Python-3.11%2B-blue)
8
8
  ![License](https://img.shields.io/badge/License-Apache--2.0-blue)
9
- [![Unit Tests](https://github.com/cmodiano/dblift-oss/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/cmodiano/dblift-oss/actions/workflows/unit-tests.yml)
10
- [![codecov](https://codecov.io/gh/cmodiano/dblift-oss/graph/badge.svg)](https://codecov.io/gh/cmodiano/dblift-oss)
9
+ [![Unit Tests](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml)
10
+ [![codecov](https://codecov.io/gh/dblift/dblift/graph/badge.svg)](https://codecov.io/gh/dblift/dblift)
11
11
  [![Security Policy](https://img.shields.io/badge/Security-Policy-green)](SECURITY.md)
12
12
 
13
13
  Application code usually has tests, CI pipelines, and pull request review. Database changes often skip one or more of those stages. DBLift is a Python-native migration toolkit that shows you exactly what SQL will run before it runs — and keeps the full migration lifecycle inside your Python workflow. No JVM required.
@@ -6,6 +6,7 @@ from ``core.logger.log`` for back-compat. JSON / HTML formatters live in
6
6
  """
7
7
 
8
8
  import logging
9
+ import sys
9
10
  from datetime import datetime
10
11
  from pathlib import Path
11
12
  from typing import Any, Dict, Optional
@@ -15,6 +16,51 @@ from core.logger._levels import LogEvent, LogLevel
15
16
  _logger = logging.getLogger(__name__)
16
17
 
17
18
 
19
+ def resolve_dblift_package_version() -> Optional[str]:
20
+ """Return the installed ``dblift`` distribution version for log banners.
21
+
22
+ Prefer ``importlib.metadata`` (correct for wheels and frozen binaries).
23
+ Avoid walking the filesystem first: under PyInstaller ``Path(__file__)``
24
+ can resolve to a unrelated ``__init__.py`` and print a stale version.
25
+ """
26
+ try:
27
+ from importlib.metadata import PackageNotFoundError, version
28
+ except ImportError: # pragma: no cover - Python <3.8
29
+ from importlib_metadata import PackageNotFoundError, version # type: ignore
30
+
31
+ try:
32
+ return version("dblift")
33
+ except PackageNotFoundError:
34
+ pass
35
+ except Exception as e:
36
+ _logger.debug(f"Could not get dblift version from importlib.metadata: {e}")
37
+
38
+ try:
39
+ import dblift # type: ignore[import-untyped]
40
+
41
+ ver = getattr(dblift, "__version__", None)
42
+ if ver:
43
+ return str(ver)
44
+ except (ImportError, AttributeError):
45
+ pass
46
+
47
+ # Dev checkouts only (skip when frozen — MEIPASS layout is not a git tree)
48
+ if not getattr(sys, "frozen", False):
49
+ try:
50
+ init_file = Path(__file__).parent.parent.parent / "__init__.py"
51
+ if init_file.exists():
52
+ with open(init_file, "r", encoding="utf-8") as f:
53
+ for line in f:
54
+ if line.startswith("__version__"):
55
+ parts = line.split("=", 1)
56
+ if len(parts) == 2:
57
+ return parts[1].strip().strip('"').strip("'")
58
+ except Exception as e:
59
+ _logger.debug(f"Could not read version from __init__.py: {e}")
60
+
61
+ return None
62
+
63
+
18
64
  class LogFormatter:
19
65
  """Base class for all log formatters."""
20
66
 
@@ -74,44 +120,7 @@ class TextFormatter(LogFormatter):
74
120
  current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
75
121
  lines.append(f"Timestamp: {current_time}")
76
122
 
77
- # Add Dblift version if available
78
- # Try multiple methods to get the version, prioritizing source code
79
- version = None
80
-
81
- # Method 1: Try to read from source __init__.py file (most reliable for development)
82
- try:
83
- # Path from core/logger/_formatters.py to root __init__.py: up 3 levels
84
- init_file = Path(__file__).parent.parent.parent / "__init__.py"
85
- if init_file.exists():
86
- with open(init_file, "r", encoding="utf-8") as f:
87
- for line in f:
88
- if line.startswith("__version__"):
89
- # Extract version from: __version__ = "x.y.z"
90
- parts = line.split("=", 1)
91
- if len(parts) == 2:
92
- version = parts[1].strip().strip('"').strip("'")
93
- break
94
- except Exception as e:
95
- _logger.debug(f"Could not read version from __init__.py: {e}")
96
-
97
- # Method 2: Try to import directly from package (if source is in path)
98
- if not version:
99
- try:
100
- import dblift # type: ignore[import-untyped]
101
-
102
- version = getattr(dblift, "__version__", None)
103
- except (ImportError, AttributeError):
104
- pass
105
-
106
- # Method 3: Fallback to pkg_resources (for installed packages)
107
- if not version:
108
- try:
109
- import pkg_resources # type: ignore[import-untyped]
110
-
111
- version = pkg_resources.get_distribution("dblift").version
112
- except Exception as e:
113
- _logger.debug(f"Could not get version from pkg_resources: {e}")
114
-
123
+ version = resolve_dblift_package_version()
115
124
  if version:
116
125
  lines.append(f"Dblift version: {version}")
117
126
 
@@ -128,43 +128,11 @@ class JsonFormatter:
128
128
 
129
129
  def _get_version_info(self) -> Dict[str, Any]:
130
130
  """Return a dict with log_format_version and dblift_version."""
131
- dblift_version = None
132
-
133
- # Method 1: Try to read from source __init__.py file (most reliable for development)
134
- try:
135
- init_file = Path(__file__).parent.parent.parent.parent / "__init__.py"
136
- if init_file.exists():
137
- with open(init_file, "r", encoding="utf-8") as f:
138
- for line in f:
139
- if line.startswith("__version__"):
140
- parts = line.split("=", 1)
141
- if len(parts) == 2:
142
- dblift_version = parts[1].strip().strip('"').strip("'")
143
- break
144
- except Exception as e:
145
- _logger.debug(f"Could not read version from __init__.py: {e}")
146
-
147
- # Method 2: Try to import directly from package (if source is in path)
148
- if not dblift_version:
149
- try:
150
- import dblift # type: ignore[import-untyped]
151
-
152
- dblift_version = getattr(dblift, "__version__", None)
153
- except (ImportError, AttributeError):
154
- pass
155
-
156
- # Method 3: Fallback to pkg_resources (for installed packages)
157
- if not dblift_version:
158
- try:
159
- import pkg_resources # type: ignore[import-untyped]
160
-
161
- dblift_version = pkg_resources.get_distribution("dblift").version
162
- except Exception as e:
163
- _logger.debug(f"Could not get version from pkg_resources: {e}")
131
+ from core.logger._formatters import resolve_dblift_package_version
164
132
 
165
133
  return {
166
134
  "log_format_version": "1.0",
167
- "dblift_version": dblift_version,
135
+ "dblift_version": resolve_dblift_package_version(),
168
136
  }
169
137
 
170
138
  def _build_time_metadata(self, result: OperationResult) -> Dict[str, Any]:
@@ -1,5 +1,13 @@
1
1
  """CockroachDB database provider plugin (PostgreSQL-compatible)."""
2
2
 
3
+ # Side-effect import: register the SQLAlchemy dialect so create_engine can
4
+ # resolve cockroachdb+psycopg even if plugin.py was not loaded yet.
5
+ from db.plugins.cockroachdb.sqlalchemy_dialect import ( # noqa: F401
6
+ register_cockroach_dialect,
7
+ )
8
+
9
+ register_cockroach_dialect()
10
+
3
11
  __plugin_name__ = "cockroachdb"
4
12
  __plugin_version__ = "1.0.0"
5
13
  __plugin_description__ = "CockroachDB database provider"
@@ -11,9 +11,13 @@ from __future__ import annotations
11
11
 
12
12
  from db.plugins.cockroachdb.provider import CockroachdbProvider
13
13
  from db.plugins.cockroachdb.quirks import CockroachdbQuirks
14
- from db.plugins.postgresql.sqlalchemy_url import build_sqlalchemy_url
14
+ from db.plugins.cockroachdb.sqlalchemy_dialect import register_cockroach_dialect
15
+ from db.plugins.cockroachdb.sqlalchemy_url import build_sqlalchemy_url
15
16
  from db.provider_registry import PluginInfo
16
17
 
18
+ # Register before any create_engine call can race plugin discovery.
19
+ register_cockroach_dialect()
20
+
17
21
  PLUGIN: PluginInfo = PluginInfo(
18
22
  name="cockroachdb",
19
23
  version="1.0.0",
@@ -0,0 +1,124 @@
1
+ """SQLAlchemy dialect for CockroachDB (PostgreSQL wire, CRDB version banner).
2
+
3
+ SQLAlchemy's stock PostgreSQL dialect requires a ``PostgreSQL X.Y`` (or
4
+ ``EnterpriseDB``) prefix from ``select version()``. CockroachDB returns banners
5
+ like::
6
+
7
+ CockroachDB CCL v24.3.18 (x86_64-pc-linux-gnu, built 2025/08/07 22:44:01, go1.22.8 ...)
8
+
9
+ which raise ``AssertionError: Could not determine version from string`` on every
10
+ ``create_engine`` connect. This dialect reuses the psycopg PostgreSQL dialect
11
+ and only overrides server-version parsing so the product version ``vX.Y.Z`` is
12
+ used — never the trailing ``go1.x.y`` fragment.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import re
18
+ from typing import Any, Optional, Tuple
19
+
20
+ from sqlalchemy.dialects.postgresql.psycopg import PGDialect_psycopg
21
+
22
+ # Prefer an explicit product "vMAJOR.MINOR[.PATCH]" token (CRDB's usual form).
23
+ _CRDB_V_TOKEN = re.compile(r"\bv(\d+)\.(\d+)(?:\.(\d+))?\b", re.IGNORECASE)
24
+ # Fallback when the banner omits the leading ``v`` (older strings).
25
+ _CRDB_DOTTED = re.compile(
26
+ r"CockroachDB(?:\s+CCL)?\s+(\d+)\.(\d+)(?:\.(\d+))?",
27
+ re.IGNORECASE,
28
+ )
29
+
30
+ _registered = False
31
+
32
+
33
+ def parse_cockroach_server_version(banner: str) -> Tuple[int, ...]:
34
+ """Return ``(major, minor[, patch])`` from a CockroachDB ``version()`` banner.
35
+
36
+ Raises:
37
+ AssertionError: when no product version can be extracted (same shape as
38
+ SQLAlchemy's PostgreSQL dialect failure).
39
+ """
40
+ text = banner or ""
41
+ match = _CRDB_V_TOKEN.search(text)
42
+ if match is None:
43
+ match = _CRDB_DOTTED.search(text)
44
+ if match is None:
45
+ raise AssertionError(f"Could not determine version from string '{banner}'")
46
+ major = int(match.group(1))
47
+ minor = int(match.group(2))
48
+ patch = match.group(3)
49
+ if patch is not None:
50
+ return (major, minor, int(patch))
51
+ return (major, minor)
52
+
53
+
54
+ class CockroachDBDialect_psycopg(PGDialect_psycopg):
55
+ """PostgreSQL+psycopg dialect that accepts CockroachDB version banners."""
56
+
57
+ name = "cockroachdb"
58
+ driver = "psycopg"
59
+ # Inherit PG caching semantics; SQLAlchemy warns if a subclass omits this.
60
+ supports_statement_cache = True
61
+
62
+ def _get_server_version_info(self, connection: Any) -> Tuple[int, ...]:
63
+ raw = connection.exec_driver_sql("select version()").scalar()
64
+ return parse_cockroach_server_version(str(raw) if raw is not None else "")
65
+
66
+
67
+ def register_cockroach_dialect() -> None:
68
+ """Register ``cockroachdb`` / ``cockroachdb.psycopg`` with SQLAlchemy once."""
69
+ global _registered
70
+ if _registered:
71
+ return
72
+ from sqlalchemy.dialects import registry
73
+
74
+ registry.register(
75
+ "cockroachdb",
76
+ "db.plugins.cockroachdb.sqlalchemy_dialect",
77
+ "CockroachDBDialect_psycopg",
78
+ )
79
+ registry.register(
80
+ "cockroachdb.psycopg",
81
+ "db.plugins.cockroachdb.sqlalchemy_dialect",
82
+ "CockroachDBDialect_psycopg",
83
+ )
84
+ _registered = True
85
+
86
+
87
+ def ensure_cockroach_drivername(drivername: str) -> str:
88
+ """Map a PostgreSQL-family drivername onto ``cockroachdb+psycopg``.
89
+
90
+ Only the ``psycopg`` DBAPI is registered for CockroachDB. Bare
91
+ ``postgresql`` / ``postgres`` / ``cockroachdb`` names and ``+psycopg``
92
+ variants rewrite cleanly; any other driver suffix (e.g. ``asyncpg``)
93
+ raises so ``create_engine`` does not fail later with an unloadable dialect.
94
+ """
95
+ if drivername in (
96
+ "cockroachdb",
97
+ "cockroachdb+psycopg",
98
+ "postgresql",
99
+ "postgres",
100
+ "postgresql+psycopg",
101
+ "postgres+psycopg",
102
+ ):
103
+ return "cockroachdb+psycopg"
104
+ if drivername.startswith(("postgresql+", "postgres+", "cockroachdb+")):
105
+ suffix = drivername.split("+", 1)[1]
106
+ if suffix != "psycopg":
107
+ raise ValueError(
108
+ "CockroachDB native connections require the psycopg driver "
109
+ f"(got {drivername!r}); use cockroachdb+psycopg or "
110
+ "postgresql+psycopg"
111
+ )
112
+ return "cockroachdb+psycopg"
113
+ raise ValueError(
114
+ "CockroachDB native connections require a PostgreSQL/CockroachDB "
115
+ f"SQLAlchemy URL (got drivername {drivername!r})"
116
+ )
117
+
118
+
119
+ __all__ = [
120
+ "CockroachDBDialect_psycopg",
121
+ "ensure_cockroach_drivername",
122
+ "parse_cockroach_server_version",
123
+ "register_cockroach_dialect",
124
+ ]
@@ -0,0 +1,93 @@
1
+ """SQLAlchemy URL construction for CockroachDB.
2
+
3
+ Reuses the PostgreSQL URL shape (host/user/sslmode/search_path) but forces the
4
+ ``cockroachdb+psycopg`` drivername so SQLAlchemy loads
5
+ :class:`CockroachDBDialect_psycopg` instead of the stock PostgreSQL dialect
6
+ that cannot parse CockroachDB ``version()`` banners.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any, Dict
12
+
13
+ from sqlalchemy.engine import URL, make_url
14
+
15
+ from db.plugins.cockroachdb.sqlalchemy_dialect import (
16
+ ensure_cockroach_drivername,
17
+ register_cockroach_dialect,
18
+ )
19
+
20
+
21
+ def _string_mapping(values: Any) -> Dict[str, str]:
22
+ if not isinstance(values, dict):
23
+ return {}
24
+ return {str(key): str(value) for key, value in values.items()}
25
+
26
+
27
+ def _query_mapping(database_config: Any, base_query: Any = None) -> Dict[str, str]:
28
+ query = _string_mapping(base_query)
29
+ query.update(_string_mapping(getattr(database_config, "extra_params", None)))
30
+ query.update(_string_mapping(getattr(database_config, "options", None)))
31
+
32
+ connection_timeout = getattr(database_config, "connection_timeout", None)
33
+ if connection_timeout:
34
+ query["connect_timeout"] = str(connection_timeout)
35
+
36
+ ssl_mode = getattr(database_config, "ssl_mode", None)
37
+ if ssl_mode:
38
+ query["sslmode"] = str(ssl_mode)
39
+
40
+ schema = getattr(database_config, "schema", None)
41
+ if schema:
42
+ schema_option = f"-csearch_path={schema}"
43
+ query["options"] = (
44
+ f"{query['options']} {schema_option}" if query.get("options") else schema_option
45
+ )
46
+
47
+ return query
48
+
49
+
50
+ def build_sqlalchemy_url(database_config: Any) -> str:
51
+ """Build a CockroachDB SQLAlchemy URL (psycopg driver, CRDB dialect)."""
52
+ register_cockroach_dialect()
53
+
54
+ raw_url = getattr(database_config, "url", None)
55
+ if isinstance(raw_url, str) and raw_url:
56
+ # Same scheme gate as the PostgreSQL builder, plus cockroachdb:// so a
57
+ # pre-rewritten URL still validates. Other schemes raise immediately.
58
+ if not raw_url.startswith(
59
+ (
60
+ "postgresql://",
61
+ "postgresql+",
62
+ "postgres://",
63
+ "postgres+",
64
+ "cockroachdb://",
65
+ "cockroachdb+",
66
+ )
67
+ ):
68
+ raise ValueError(
69
+ "CockroachDB native connections require a PostgreSQL/CockroachDB SQLAlchemy URL"
70
+ )
71
+ url = make_url(raw_url)
72
+ url = url.set(drivername=ensure_cockroach_drivername(url.drivername))
73
+ username = getattr(database_config, "username", None) or url.username or None
74
+ password = getattr(database_config, "password", None) or url.password or None
75
+ if username != url.username or password != url.password:
76
+ url = url.set(username=username, password=password)
77
+ query = _query_mapping(database_config, url.query)
78
+ if query != dict(url.query):
79
+ url = url.set(query=query)
80
+ return url.render_as_string(hide_password=False)
81
+
82
+ return URL.create(
83
+ "cockroachdb+psycopg",
84
+ username=getattr(database_config, "username", None) or None,
85
+ password=getattr(database_config, "password", None) or None,
86
+ host=getattr(database_config, "host", None) or "localhost",
87
+ port=getattr(database_config, "port", None),
88
+ database=getattr(database_config, "database", None),
89
+ query=_query_mapping(database_config),
90
+ ).render_as_string(hide_password=False)
91
+
92
+
93
+ __all__ = ["build_sqlalchemy_url"]
@@ -27,12 +27,180 @@ class DuckDBProvider(SqlAlchemyProvider):
27
27
  def execute_statement(
28
28
  self, sql: str, schema: Optional[str] = None, params: Optional[List[Any]] = None
29
29
  ) -> int:
30
- """Execute a SQL statement, optionally preparing the schema first."""
30
+ """Execute a SQL statement, optionally preparing the schema first.
31
+
32
+ DuckDB/SQLAlchemy often reports ``rowcount == -1`` for DML. For single
33
+ INSERT/UPDATE/DELETE statements without parameters, append
34
+ ``RETURNING 1`` so callers (e.g. data corrections ``expect=N``) get a
35
+ real affected-row count.
36
+ """
31
37
  if schema:
32
38
  self.create_schema_if_not_exists(schema)
33
39
  self.set_current_schema(schema)
40
+
41
+ if params is None:
42
+ counted = self._try_dml_rowcount_via_returning(sql)
43
+ if counted is not None:
44
+ return counted
34
45
  return super().execute_statement(sql, schema=schema, params=params)
35
46
 
47
+ def _try_dml_rowcount_via_returning(self, sql: str) -> Optional[int]:
48
+ """Return affected-row count using RETURNING, or None if not applicable.
49
+
50
+ Returns None only when the statement is not rewritten (caller falls back
51
+ to the default path). Once execution is attempted, errors propagate —
52
+ do not re-run a failed statement via super() (that masks the root cause
53
+ as a follow-on \"transaction is aborted\" error).
54
+ """
55
+ stripped = self._strip_sql_comments(sql.strip()).rstrip(";").strip()
56
+ if not stripped:
57
+ return None
58
+ # Already has a top-level RETURNING clause — do not double-append
59
+ if self._has_top_level_keyword(stripped, "RETURNING"):
60
+ return None
61
+ # Normalize whitespace for statement-type checks only
62
+ upper = " ".join(stripped.upper().split())
63
+ if not (
64
+ upper.startswith("INSERT ")
65
+ or upper.startswith("UPDATE ")
66
+ or upper.startswith("DELETE ")
67
+ ):
68
+ return None
69
+
70
+ # Multi-statement scripts: leave to super (no silent rewrite)
71
+ if self._has_top_level_semicolon(stripped):
72
+ return None
73
+
74
+ rewritten = f"{stripped} RETURNING 1"
75
+ conn = self._ensure_connection()
76
+ driver_sql = self._escape_driver_percent_literals(rewritten, conn.dialect.paramstyle)
77
+ result = conn.exec_driver_sql(driver_sql)
78
+ rows = result.fetchall()
79
+ if self._tx is None and not getattr(self, "_external_connection", False):
80
+ conn.commit()
81
+ return len(rows)
82
+
83
+ @staticmethod
84
+ def _strip_sql_comments(sql: str) -> str:
85
+ """Remove ``--`` / ``/* */`` comments (and blank lines).
86
+
87
+ Strips leading directives, full-line mid-statement comments, and
88
+ trailing *inline* ``--`` on DML lines so an appended ``RETURNING 1``
89
+ is not commented out and keyword detection is not confused by the
90
+ word ``returning`` inside comments.
91
+ """
92
+ s = sql.lstrip()
93
+ # Leading block comments only (line comments handled per-line below)
94
+ while s.startswith("/*"):
95
+ end = s.find("*/")
96
+ if end < 0:
97
+ return ""
98
+ s = s[end + 2 :].lstrip()
99
+
100
+ kept: List[str] = []
101
+ for raw in s.splitlines():
102
+ line = DuckDBProvider._strip_inline_trailing_comment(raw)
103
+ if not line or line.lstrip().startswith("--"):
104
+ continue
105
+ # Drop leftover full-line block comments
106
+ if line.lstrip().startswith("/*") and line.rstrip().endswith("*/"):
107
+ continue
108
+ kept.append(line)
109
+ return "\n".join(kept).strip()
110
+
111
+ @staticmethod
112
+ def _strip_inline_trailing_comment(line: str) -> str:
113
+ """Strip trailing ``--`` or ``/* … */`` outside string/identifier quotes."""
114
+ in_single = in_double = False
115
+ i = 0
116
+ n = len(line)
117
+ cut: Optional[int] = None
118
+ while i < n:
119
+ ch = line[i]
120
+ if ch == "'" and not in_double:
121
+ if in_single and i + 1 < n and line[i + 1] == "'":
122
+ i += 2
123
+ continue
124
+ in_single = not in_single
125
+ elif ch == '"' and not in_single:
126
+ if in_double and i + 1 < n and line[i + 1] == '"':
127
+ i += 2
128
+ continue
129
+ in_double = not in_double
130
+ elif not in_single and not in_double:
131
+ if ch == "-" and i + 1 < n and line[i + 1] == "-":
132
+ cut = i
133
+ break
134
+ if ch == "/" and i + 1 < n and line[i + 1] == "*":
135
+ # Only treat as trailing comment if it runs to end of line
136
+ close = line.find("*/", i + 2)
137
+ if close >= 0 and line[close + 2 :].strip() == "":
138
+ cut = i
139
+ break
140
+ i += 1
141
+ if cut is not None:
142
+ return line[:cut].rstrip()
143
+ return line.rstrip()
144
+
145
+ @staticmethod
146
+ def _has_top_level_semicolon(sql: str) -> bool:
147
+ """True if ``sql`` contains a semicolon outside string/identifier quotes."""
148
+ in_single = in_double = False
149
+ i = 0
150
+ n = len(sql)
151
+ while i < n:
152
+ ch = sql[i]
153
+ if ch == "'" and not in_double:
154
+ # SQL escaped single quote ''
155
+ if in_single and i + 1 < n and sql[i + 1] == "'":
156
+ i += 2
157
+ continue
158
+ in_single = not in_single
159
+ elif ch == '"' and not in_single:
160
+ if in_double and i + 1 < n and sql[i + 1] == '"':
161
+ i += 2
162
+ continue
163
+ in_double = not in_double
164
+ elif ch == ";" and not in_single and not in_double:
165
+ return True
166
+ i += 1
167
+ return False
168
+
169
+ @staticmethod
170
+ def _has_top_level_keyword(sql: str, keyword: str) -> bool:
171
+ """True if ``keyword`` appears as a top-level token outside quotes.
172
+
173
+ Used instead of a raw substring search so values like
174
+ ``SET note = ' returning '`` or mid-line comments mentioning
175
+ ``returning`` do not skip the RETURNING rewrite.
176
+ """
177
+ kw = keyword.upper()
178
+ kw_len = len(kw)
179
+ in_single = in_double = False
180
+ i = 0
181
+ n = len(sql)
182
+ while i < n:
183
+ ch = sql[i]
184
+ if ch == "'" and not in_double:
185
+ if in_single and i + 1 < n and sql[i + 1] == "'":
186
+ i += 2
187
+ continue
188
+ in_single = not in_single
189
+ elif ch == '"' and not in_single:
190
+ if in_double and i + 1 < n and sql[i + 1] == '"':
191
+ i += 2
192
+ continue
193
+ in_double = not in_double
194
+ elif not in_single and not in_double:
195
+ if sql[i : i + kw_len].upper() == kw:
196
+ before_ok = i == 0 or not (sql[i - 1].isalnum() or sql[i - 1] == "_")
197
+ after = i + kw_len
198
+ after_ok = after >= n or not (sql[after].isalnum() or sql[after] == "_")
199
+ if before_ok and after_ok:
200
+ return True
201
+ i += 1
202
+ return False
203
+
36
204
  def create_schema_if_not_exists(self, schema: str) -> None:
37
205
  """Create a DuckDB schema if it is missing."""
38
206
  rows = self.execute_query(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dblift
3
- Version: 3.3.2
3
+ Version: 3.3.4
4
4
  Summary: A database migration tool that supports multiple databases with native Python drivers
5
5
  Classifier: Development Status :: 5 - Production/Stable
6
6
  Classifier: Intended Audience :: Developers
@@ -115,8 +115,8 @@ Dynamic: license-file
115
115
 
116
116
  ![Python](https://img.shields.io/badge/Python-3.11%2B-blue)
117
117
  ![License](https://img.shields.io/badge/License-Apache--2.0-blue)
118
- [![Unit Tests](https://github.com/cmodiano/dblift-oss/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/cmodiano/dblift-oss/actions/workflows/unit-tests.yml)
119
- [![codecov](https://codecov.io/gh/cmodiano/dblift-oss/graph/badge.svg)](https://codecov.io/gh/cmodiano/dblift-oss)
118
+ [![Unit Tests](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml)
119
+ [![codecov](https://codecov.io/gh/dblift/dblift/graph/badge.svg)](https://codecov.io/gh/dblift/dblift)
120
120
  [![Security Policy](https://img.shields.io/badge/Security-Policy-green)](SECURITY.md)
121
121
 
122
122
  Application code usually has tests, CI pipelines, and pull request review. Database changes often skip one or more of those stages. DBLift is a Python-native migration toolkit that shows you exactly what SQL will run before it runs — and keeps the full migration lifecycle inside your Python workflow. No JVM required.
@@ -295,6 +295,8 @@ db/plugins/cockroachdb/__init__.py
295
295
  db/plugins/cockroachdb/plugin.py
296
296
  db/plugins/cockroachdb/provider.py
297
297
  db/plugins/cockroachdb/quirks.py
298
+ db/plugins/cockroachdb/sqlalchemy_dialect.py
299
+ db/plugins/cockroachdb/sqlalchemy_url.py
298
300
  db/plugins/cosmosdb/__init__.py
299
301
  db/plugins/cosmosdb/config.py
300
302
  db/plugins/cosmosdb/plugin.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dblift"
7
- version = "3.3.2"
7
+ version = "3.3.4"
8
8
  description = "A database migration tool that supports multiple databases with native Python drivers"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes