dblift 2.5.2__tar.gz → 2.6.0__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.
- {dblift-2.5.2 → dblift-2.6.0}/PKG-INFO +4 -1
- {dblift-2.5.2 → dblift-2.6.0}/README.md +1 -0
- dblift-2.6.0/db/plugins/snowflake/__init__.py +12 -0
- dblift-2.6.0/db/plugins/snowflake/config.py +67 -0
- dblift-2.6.0/db/plugins/snowflake/plugin.py +22 -0
- dblift-2.6.0/db/plugins/snowflake/provider.py +449 -0
- dblift-2.6.0/db/plugins/snowflake/quirks.py +70 -0
- dblift-2.6.0/db/plugins/snowflake/sqlalchemy_url.py +83 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/provider_registry.py +4 -1
- {dblift-2.5.2 → dblift-2.6.0}/dblift.egg-info/PKG-INFO +4 -1
- {dblift-2.5.2 → dblift-2.6.0}/dblift.egg-info/SOURCES.txt +6 -0
- {dblift-2.5.2 → dblift-2.6.0}/dblift.egg-info/entry_points.txt +1 -0
- {dblift-2.5.2 → dblift-2.6.0}/dblift.egg-info/requires.txt +3 -0
- {dblift-2.5.2 → dblift-2.6.0}/pyproject.toml +3 -1
- {dblift-2.5.2 → dblift-2.6.0}/LICENSE +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/_cli_support.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/_client_factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/_client_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/_engine_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/async_client.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/client.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/events.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/migrations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/api/py.typed +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/_command_handlers.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/_config_helpers.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/_constants.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/_output.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/_parser_setup.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/commands/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/commands/config_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/db_utils.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/extensions.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/_shared.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/baseline.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/clean.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/import_flyway.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/info.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/migrate.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/repair.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/undo.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/handlers/validate.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/cli/main.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/_credential_masking.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/_subclasses/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/_subclasses/dummy_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/_url_builder_mixin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/config_builder.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/database_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/dblift_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/errors.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/property_registry.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/secrets/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/secrets/_cache.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/secrets/_provider_base.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/secrets/_registry.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/secrets/_resolver.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/config/secrets/_secrets_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/constants.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/dialect_boundary.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/exceptions.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/_column_enricher.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/_partition_enricher.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/_schema_orchestrator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/_utils.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/_vendor_property_applier.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/base_introspector.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/base_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/column_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/constraint_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/index_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/misc_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/procedure_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/sequence_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/table_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/trigger_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/extractors/view_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/introspector_factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/result.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/schema_introspector.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/vendor_queries_base.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/vendor_queries_factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/vendor_queries_protocols.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/introspection/version_detector.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/_base.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/_factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/_formatters.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/_levels.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/_multi.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/_null.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/console.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/formatters/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/formatters/_formatter_impl.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/formatters/factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/formatters/formatter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/formatters/htmlformatter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/formatters/jsonformatter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/log.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/results.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/templates/oldreport.html +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/logger/templates/report.html +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/_type_match.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/clean_summary.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/_script_events.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/base_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/baseline_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/clean_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/import_flyway_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/info_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/migrate_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/repair_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/undo_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/commands/validate_command.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/encoding.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executor/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executor/execution_engine.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executor/migration_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executor/migration_helpers.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executor/placeholder_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executor/transaction_policy.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executors/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executors/base_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executors/executor_factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executors/python_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/executors/sql_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/formats/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/formats/format_detector.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/formats/migration_format.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/history/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/history/migration_history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/journals/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/journals/migration_journal.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/migration.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/placeholders/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/placeholders/placeholder_service.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/rules/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/rules/migration_rules.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/migration_script_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/undo_script_generator/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/undo_script_generator/_ddl_reversers.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/undo_script_generator/_dml_reversers.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/undo_script_generator/_extractors.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/undo_script_generator/_generator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/undo_script_generator/_helpers.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/undo_script_generator/_models.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/scripting/undo_script_generator/_reversers.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/sql/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/sql/execution_statement.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/sql/sql_analyzer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/sql/sql_execution_service.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/sql/statement_splitter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/state/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/state/migration_data_service.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/state/migration_display_state.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/state/migration_formatter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/state/migration_state.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/state/migration_state_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/state/migration_state_service.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/ui/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/ui/data_collector.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/ui/display_formatters.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/ui/migration_analyzer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/ui/migration_ui.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/ui/table_renderer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/migration/version_utils.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/normalization/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/normalization/dependency_resolver.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/normalization/identifier_normalizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/normalization/object_orderer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/normalization/type_constants.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/normalization/type_mapper.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/normalization/type_mappings.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/normalization/type_normalizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/capabilities.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/event_listeners.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/feature_loading.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/introspection.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/license_info.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/runtime_checks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/sql_generators.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/seams/tier_resolver.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/alter/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/alter/alter_generator_factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/alter/base_alter_generator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/alter_generator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/base_generator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/basic_table_ddl_generator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/dependency_analyzer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/diff_converters/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/diff_converters/base_converter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/formatter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/generator_factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/options.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/script_organizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/sql_generator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/sql_statement.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_generator/table_ddl_render.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/_base_parse_result.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/_base_sql_column.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/_base_sql_constraint.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/_base_sql_object.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/_base_sql_statement.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/base.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/constraint_validator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/database_link.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/dialect.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/event.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/extension.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/foreign_data_wrapper.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/foreign_server.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/index.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/linked_server.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/module.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/package.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/partition.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/procedure.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/sequence.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/synonym.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/table.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/table_canonicalizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/table_options.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/trigger.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/user_defined_type.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/view.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_model/view_options.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/_partition_handler.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/_sqlglot_builders.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/base_statement_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/base_tokenizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/common/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/common/base_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/dialects/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/dialects/base_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/enhanced_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/hybrid_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/parser_context.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/parser_factory.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/parser_interface.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/sqlglot_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/tokens.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_parser/unified_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_validator/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_validator/_checksum_validator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_validator/_flyway_compatibility.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_validator/_migration_filter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_validator/_sql_syntax_validator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_validator/_strict_mode_validator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/sql_validator/migration_validator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/state/sql_script_formatter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/state/sql_statement.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/utils/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/utils/database_url_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/utils/metadata_helpers.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/utils/row_access.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/utils/string_utils.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/core/utils/url_masking.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/base_provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/base_quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/constants.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/dml_analysis.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/error.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/error_handler.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/exceptions.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/native_connection_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/object_naming.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/alloydb/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/alloydb/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/alloydb/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/alloydb/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/aurora_postgresql/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/aurora_postgresql/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/aurora_postgresql/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/aurora_postgresql/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/base_history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/base_locking_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/base_query_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/base_schema_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/base_snapshot_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/base_undo_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/citus/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/citus/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/citus/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/citus/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cockroachdb/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cockroachdb/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cockroachdb/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cockroachdb/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/cosmosdb/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/cosmosdb/_sdk.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/cosmosdb/connection_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/cosmosdb/history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/cosmosdb/locking_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/cosmosdb/query_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/cosmosdb/schema_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/introspection/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/parser/cosmosdb_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/sdk_translator/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/sdk_translator/_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/sdk_translator/_executors.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/sdk_translator/_parsing.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/sdk_translator/_script_generation.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/sdk_translator/_translator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/cosmosdb/sdk_translator/_translators.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/db2/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/db2/history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/db2/locking_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/db2/schema_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/introspection/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/parser/db2_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/parser/parser_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/db2/sqlalchemy_url.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/parser/duckdb_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/parser/parser_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/duckdb/sqlalchemy_url.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mariadb/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mariadb/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mariadb/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mariadb/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/introspection/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/mysql/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/mysql/history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/mysql/locking_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/mysql/schema_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/parser/mysql_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/parser/mysql_statement_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/parser/mysql_tokenizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/parser/parser_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/mysql/sqlalchemy_url.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/neon/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/neon/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/neon/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/neon/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/introspection/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/introspection/oracle_utils.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/oracle/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/oracle/dbms_output.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/oracle/history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/oracle/locking_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/oracle/schema_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/_comments.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/_object_extractor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/_plsql_block.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/_sqlplus.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/_statement_splitter.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/oracle_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/oracle_statement_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/oracle_tokenizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/parser_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/parser/sqlplus_context.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/oracle/sqlalchemy_url.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/_provider_query_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/introspection/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/parser/parser_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/parser/postgresql_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/parser/postgresql_statement_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/parser/postgresql_tokenizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/postgresql/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/postgresql/history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/postgresql/locking_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/postgresql/schema_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/postgresql/sqlalchemy_url.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/redshift/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/redshift/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/redshift/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/redshift/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/redshift/sqlalchemy_url.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/introspection/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/parser/parser_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/parser/sqlite_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/sqlalchemy_url.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/sqlite/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/sqlite/connection_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/sqlite/history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/sqlite/locking_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/sqlite/query_executor.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlite/sqlite/schema_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/introspection/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/parser/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/parser/parser_config.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/parser/sqlserver_regex_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/parser/sqlserver_statement_parser.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/parser/sqlserver_tokenizer.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/parser/tsql_batch_separator.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/sqlalchemy_url.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/sqlserver/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/sqlserver/history_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/sqlserver/locking_manager.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/sqlserver/sqlserver/schema_operations.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/supabase/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/supabase/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/supabase/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/supabase/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/timescaledb/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/timescaledb/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/timescaledb/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/timescaledb/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/yugabytedb/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/yugabytedb/plugin.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/yugabytedb/provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/plugins/yugabytedb/quirks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/provider_capabilities.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/provider_interfaces.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/sqlalchemy_provider.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/db/value_utils.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/dblift.egg-info/dependency_links.txt +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/dblift.egg-info/top_level.txt +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/_client.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/_engine.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/apps.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/checks.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/management/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/management/commands/__init__.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/management/commands/dblift_info.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/management/commands/dblift_migrate.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/django/management/commands/dblift_validate.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/fastapi.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/flask.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/integrations/opentelemetry.py +0 -0
- {dblift-2.5.2 → dblift-2.6.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dblift
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
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
|
|
@@ -88,6 +88,8 @@ Requires-Dist: psycopg[binary]>=3.1; extra == "cockroachdb"
|
|
|
88
88
|
Provides-Extra: redshift
|
|
89
89
|
Requires-Dist: sqlalchemy-redshift>=1.0.0; extra == "redshift"
|
|
90
90
|
Requires-Dist: redshift-connector>=2.1.0; extra == "redshift"
|
|
91
|
+
Provides-Extra: snowflake
|
|
92
|
+
Requires-Dist: snowflake-sqlalchemy>=1.11.0; extra == "snowflake"
|
|
91
93
|
Provides-Extra: fastapi
|
|
92
94
|
Requires-Dist: fastapi>=0.100; extra == "fastapi"
|
|
93
95
|
Provides-Extra: flask
|
|
@@ -734,6 +736,7 @@ DBLift works with these databases:
|
|
|
734
736
|
| PostgreSQL | `postgresql+psycopg://localhost:5432/mydb` | `dblift[postgresql]` |
|
|
735
737
|
| CockroachDB | `postgresql+psycopg://localhost:26257/mydb` | `dblift[cockroachdb]` |
|
|
736
738
|
| Redshift | `postgresql+psycopg://cluster.example.com:5439/dev` | `dblift[redshift]` |
|
|
739
|
+
| Snowflake | `snowflake://user:password@account_identifier/database/schema?warehouse=WH&role=ROLE` | `dblift[snowflake]` |
|
|
737
740
|
| SQL Server | `mssql+pymssql://localhost:1433/mydb` | `dblift[sqlserver]` |
|
|
738
741
|
| Oracle | `oracle+oracledb://localhost:1521?sid=SID` | `dblift[oracle]` |
|
|
739
742
|
| MySQL | `mysql+pymysql://localhost:3306/mydb` | `dblift[mysql]` |
|
|
@@ -632,6 +632,7 @@ DBLift works with these databases:
|
|
|
632
632
|
| PostgreSQL | `postgresql+psycopg://localhost:5432/mydb` | `dblift[postgresql]` |
|
|
633
633
|
| CockroachDB | `postgresql+psycopg://localhost:26257/mydb` | `dblift[cockroachdb]` |
|
|
634
634
|
| Redshift | `postgresql+psycopg://cluster.example.com:5439/dev` | `dblift[redshift]` |
|
|
635
|
+
| Snowflake | `snowflake://user:password@account_identifier/database/schema?warehouse=WH&role=ROLE` | `dblift[snowflake]` |
|
|
635
636
|
| SQL Server | `mssql+pymssql://localhost:1433/mydb` | `dblift[sqlserver]` |
|
|
636
637
|
| Oracle | `oracle+oracledb://localhost:1521?sid=SID` | `dblift[oracle]` |
|
|
637
638
|
| MySQL | `mysql+pymysql://localhost:3306/mydb` | `dblift[mysql]` |
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Snowflake database provider plugin."""
|
|
2
|
+
|
|
3
|
+
__plugin_name__ = "snowflake"
|
|
4
|
+
__plugin_version__ = "1.0.0"
|
|
5
|
+
__plugin_description__ = "Snowflake database provider"
|
|
6
|
+
__plugin_dialects__ = ["snowflake"]
|
|
7
|
+
__plugin_transport__ = "native"
|
|
8
|
+
__plugin_class__ = "SnowflakeProvider"
|
|
9
|
+
|
|
10
|
+
from .provider import SnowflakeProvider
|
|
11
|
+
|
|
12
|
+
__all__ = ["SnowflakeProvider"]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Snowflake-specific ``BaseDatabaseConfig`` subclass."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
|
|
6
|
+
from config.database_config import BaseDatabaseConfig, register_database_type
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# lint: allow-dialect-string: config type registration
|
|
10
|
+
@register_database_type("snowflake")
|
|
11
|
+
@dataclass
|
|
12
|
+
class SnowflakeConfig(BaseDatabaseConfig):
|
|
13
|
+
"""Configuration for Snowflake SQLAlchemy connections."""
|
|
14
|
+
|
|
15
|
+
account: Optional[str] = None
|
|
16
|
+
warehouse: Optional[str] = None
|
|
17
|
+
role: Optional[str] = None
|
|
18
|
+
authenticator: Optional[str] = None
|
|
19
|
+
|
|
20
|
+
def __post_init__(self) -> None:
|
|
21
|
+
"""Resolve account/database/schema from Snowflake URL fields."""
|
|
22
|
+
super().__post_init__()
|
|
23
|
+
# lint: allow-dialect-string: config type identity
|
|
24
|
+
self.type = "snowflake"
|
|
25
|
+
|
|
26
|
+
if not self.account and self.host:
|
|
27
|
+
self.account = str(self.host)
|
|
28
|
+
|
|
29
|
+
database_value = getattr(self, "database", None)
|
|
30
|
+
if database_value and "/" in str(database_value):
|
|
31
|
+
database, schema = str(database_value).split("/", 1)
|
|
32
|
+
self.database = database or None
|
|
33
|
+
if schema and not getattr(self, "schema", ""):
|
|
34
|
+
self.schema = schema
|
|
35
|
+
|
|
36
|
+
def build_connection_string(self) -> str:
|
|
37
|
+
"""Build the Snowflake plugin-owned SQLAlchemy URL."""
|
|
38
|
+
return self.build_database_url()
|
|
39
|
+
|
|
40
|
+
def build_database_url(self) -> str:
|
|
41
|
+
"""Build the Snowflake SQLAlchemy URL through the provider registry."""
|
|
42
|
+
from db.provider_registry import ProviderRegistry
|
|
43
|
+
|
|
44
|
+
url: str = ProviderRegistry.build_sqlalchemy_url(self)
|
|
45
|
+
return url
|
|
46
|
+
|
|
47
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
48
|
+
"""Convert to dictionary with Snowflake-specific parameters."""
|
|
49
|
+
result: Dict[str, Any] = super().to_dict()
|
|
50
|
+
result["account"] = self.account
|
|
51
|
+
result["warehouse"] = self.warehouse
|
|
52
|
+
result["role"] = self.role
|
|
53
|
+
result["authenticator"] = self.authenticator
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
def get_connection_props(self) -> Dict[str, str]:
|
|
57
|
+
"""Return Snowflake connection properties."""
|
|
58
|
+
props: Dict[str, str] = super().get_connection_props()
|
|
59
|
+
if self.account:
|
|
60
|
+
props["account"] = self.account
|
|
61
|
+
if self.warehouse:
|
|
62
|
+
props["warehouse"] = self.warehouse
|
|
63
|
+
if self.role:
|
|
64
|
+
props["role"] = self.role
|
|
65
|
+
if self.authenticator:
|
|
66
|
+
props["authenticator"] = self.authenticator
|
|
67
|
+
return props
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Entry-point declaration for the Snowflake plugin."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from db.plugins.snowflake.config import SnowflakeConfig
|
|
6
|
+
from db.plugins.snowflake.provider import SnowflakeProvider
|
|
7
|
+
from db.plugins.snowflake.quirks import SnowflakeQuirks
|
|
8
|
+
from db.plugins.snowflake.sqlalchemy_url import build_sqlalchemy_url
|
|
9
|
+
from db.provider_registry import PluginInfo
|
|
10
|
+
|
|
11
|
+
PLUGIN: PluginInfo = PluginInfo(
|
|
12
|
+
name="snowflake",
|
|
13
|
+
version="1.0.0",
|
|
14
|
+
description="Snowflake database provider",
|
|
15
|
+
dialects=["snowflake"],
|
|
16
|
+
provider_class=SnowflakeProvider,
|
|
17
|
+
transport="native",
|
|
18
|
+
quirks_class=SnowflakeQuirks,
|
|
19
|
+
config_class=SnowflakeConfig,
|
|
20
|
+
sqlalchemy_url_builder=build_sqlalchemy_url,
|
|
21
|
+
native_driver_module="snowflake.connector",
|
|
22
|
+
)
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"""Snowflake native provider backed by SQLAlchemy Core."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from sqlalchemy.engine import Connection, Transaction
|
|
8
|
+
|
|
9
|
+
from config import DbliftConfig
|
|
10
|
+
from core.logger import Log
|
|
11
|
+
from core.migration.clean_summary import CleanExecutionSummary
|
|
12
|
+
from db.provider_interfaces import DroppableObject
|
|
13
|
+
from db.sqlalchemy_provider import SqlAlchemyProvider
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _quote_identifier(identifier: str) -> str:
|
|
17
|
+
return '"' + identifier.upper().replace('"', '""') + '"'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _is_lock_timeout_error(error: Exception) -> bool:
|
|
21
|
+
message = " ".join(
|
|
22
|
+
str(value or "").lower()
|
|
23
|
+
for value in (
|
|
24
|
+
getattr(error, "msg", None),
|
|
25
|
+
getattr(error, "raw_msg", None),
|
|
26
|
+
str(error),
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
markers = (
|
|
30
|
+
"lock timeout",
|
|
31
|
+
"lock wait timeout",
|
|
32
|
+
"waiting for this lock",
|
|
33
|
+
"waited too long for a lock",
|
|
34
|
+
)
|
|
35
|
+
return any(marker in message for marker in markers)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class SnowflakeProvider(SqlAlchemyProvider):
|
|
39
|
+
"""Snowflake provider using the Snowflake SQLAlchemy dialect."""
|
|
40
|
+
|
|
41
|
+
canonical_dialect_key = "snowflake"
|
|
42
|
+
MIGRATION_LOCK_TABLE = "DBLIFT_MIGRATION_LOCK"
|
|
43
|
+
_migration_lock_connection: Connection | None = None
|
|
44
|
+
_migration_lock_transaction: Transaction | None = None
|
|
45
|
+
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
config: DbliftConfig,
|
|
49
|
+
log: Optional[Log] = None,
|
|
50
|
+
) -> None:
|
|
51
|
+
super().__init__(config, log)
|
|
52
|
+
|
|
53
|
+
def execute_statement(
|
|
54
|
+
self,
|
|
55
|
+
sql: str,
|
|
56
|
+
schema: Optional[str] = None,
|
|
57
|
+
params: Optional[List[Any]] = None,
|
|
58
|
+
) -> int:
|
|
59
|
+
"""Execute a SQL statement, optionally preparing the schema first."""
|
|
60
|
+
if schema:
|
|
61
|
+
self.create_schema_if_not_exists(schema)
|
|
62
|
+
self.set_current_schema(schema)
|
|
63
|
+
rowcount: int = super().execute_statement(
|
|
64
|
+
sql,
|
|
65
|
+
schema=schema,
|
|
66
|
+
params=params,
|
|
67
|
+
)
|
|
68
|
+
return rowcount
|
|
69
|
+
|
|
70
|
+
def create_schema_if_not_exists(self, schema: str) -> None:
|
|
71
|
+
"""Create a Snowflake schema if it is missing."""
|
|
72
|
+
schema_name = _quote_identifier(schema)
|
|
73
|
+
self.execute_statement(f"CREATE SCHEMA IF NOT EXISTS {schema_name}")
|
|
74
|
+
|
|
75
|
+
def table_exists(self, schema: str, table_name: str) -> bool:
|
|
76
|
+
"""Return whether a table exists in the given schema."""
|
|
77
|
+
rows = self.execute_query(
|
|
78
|
+
"""
|
|
79
|
+
SELECT 1 AS present
|
|
80
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
81
|
+
WHERE TABLE_SCHEMA = UPPER(?)
|
|
82
|
+
AND TABLE_NAME = UPPER(?)
|
|
83
|
+
""",
|
|
84
|
+
[schema, table_name],
|
|
85
|
+
)
|
|
86
|
+
return bool(rows)
|
|
87
|
+
|
|
88
|
+
def get_database_version(self) -> str:
|
|
89
|
+
"""Return Snowflake version information."""
|
|
90
|
+
rows = self.execute_query("SELECT CURRENT_VERSION() AS version")
|
|
91
|
+
if rows:
|
|
92
|
+
return f"Snowflake {rows[0]['version']}"
|
|
93
|
+
return "Unknown Snowflake Version"
|
|
94
|
+
|
|
95
|
+
def supports_transactional_ddl(self) -> bool:
|
|
96
|
+
"""Snowflake DDL auto-commits."""
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
def set_current_schema(self, schema: str) -> None:
|
|
100
|
+
"""Set the current Snowflake schema for this session."""
|
|
101
|
+
super().execute_statement(f"USE SCHEMA {_quote_identifier(schema)}")
|
|
102
|
+
|
|
103
|
+
def get_schema_qualified_name(self, schema: str, object_name: str) -> str:
|
|
104
|
+
"""Return a quoted schema-qualified object name."""
|
|
105
|
+
return f"{_quote_identifier(schema)}.{_quote_identifier(object_name)}"
|
|
106
|
+
|
|
107
|
+
def clean_schema(self, schema: str) -> CleanExecutionSummary:
|
|
108
|
+
"""Drop Snowflake views, tables, and sequences in a schema."""
|
|
109
|
+
summary = self.get_clean_preview(schema)
|
|
110
|
+
for stmt in summary.statements:
|
|
111
|
+
self.execute_statement(stmt)
|
|
112
|
+
return summary
|
|
113
|
+
|
|
114
|
+
def get_clean_preview(self, schema: str) -> CleanExecutionSummary:
|
|
115
|
+
"""Return Snowflake objects that clean would drop."""
|
|
116
|
+
summary = CleanExecutionSummary()
|
|
117
|
+
|
|
118
|
+
for view_name in self._object_names(_SNOWFLAKE_VIEWS_QUERY, schema):
|
|
119
|
+
qualified = self.get_schema_qualified_name(schema, view_name)
|
|
120
|
+
summary.record_drop(
|
|
121
|
+
f"DROP VIEW IF EXISTS {qualified}",
|
|
122
|
+
object_type="view",
|
|
123
|
+
name=view_name,
|
|
124
|
+
schema=schema,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
for table_name in self._object_names(_SNOWFLAKE_TABLES_QUERY, schema):
|
|
128
|
+
qualified = self.get_schema_qualified_name(schema, table_name)
|
|
129
|
+
summary.record_drop(
|
|
130
|
+
f"DROP TABLE IF EXISTS {qualified} CASCADE",
|
|
131
|
+
object_type="table",
|
|
132
|
+
name=table_name,
|
|
133
|
+
schema=schema,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
sequence_names = self._object_names(_SNOWFLAKE_SEQUENCES_QUERY, schema)
|
|
137
|
+
for sequence_name in sequence_names:
|
|
138
|
+
qualified = self.get_schema_qualified_name(schema, sequence_name)
|
|
139
|
+
summary.record_drop(
|
|
140
|
+
f"DROP SEQUENCE IF EXISTS {qualified}",
|
|
141
|
+
object_type="sequence",
|
|
142
|
+
name=sequence_name,
|
|
143
|
+
schema=schema,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
return summary
|
|
147
|
+
|
|
148
|
+
def list_droppable_objects(self, schema: str) -> List[DroppableObject]:
|
|
149
|
+
"""Return Snowflake clean candidates in preview order."""
|
|
150
|
+
summary = self.get_clean_preview(schema)
|
|
151
|
+
return [
|
|
152
|
+
DroppableObject(
|
|
153
|
+
name=obj.name,
|
|
154
|
+
object_type=obj.object_type,
|
|
155
|
+
drop_sql=drop_sql,
|
|
156
|
+
)
|
|
157
|
+
for obj, drop_sql in zip(summary.objects, summary.statements)
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
def _object_names(self, query: str, schema: str) -> List[str]:
|
|
161
|
+
rows = self.execute_query(query, [schema])
|
|
162
|
+
return [
|
|
163
|
+
str(row.get("object_name") or row.get("OBJECT_NAME"))
|
|
164
|
+
for row in rows
|
|
165
|
+
if row.get("object_name") or row.get("OBJECT_NAME")
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
def create_migration_lock_table_sql(self, schema: str) -> str:
|
|
169
|
+
"""Return the Snowflake migration lock table DDL."""
|
|
170
|
+
qualified = self.get_schema_qualified_name(
|
|
171
|
+
schema,
|
|
172
|
+
self.MIGRATION_LOCK_TABLE,
|
|
173
|
+
)
|
|
174
|
+
return f"""
|
|
175
|
+
CREATE TABLE IF NOT EXISTS {qualified} (
|
|
176
|
+
lock_name VARCHAR(128) NOT NULL,
|
|
177
|
+
locked_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP()
|
|
178
|
+
)
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
def acquire_migration_lock_sql(self, schema: str) -> str:
|
|
182
|
+
"""Return the DML statement holding the migration lock row."""
|
|
183
|
+
qualified = self.get_schema_qualified_name(
|
|
184
|
+
schema,
|
|
185
|
+
self.MIGRATION_LOCK_TABLE,
|
|
186
|
+
)
|
|
187
|
+
return (
|
|
188
|
+
f"UPDATE {qualified} "
|
|
189
|
+
"SET locked_at = CURRENT_TIMESTAMP() WHERE lock_name = 'migration'"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
def create_migration_lock_table_if_not_exists(self, schema: str) -> None:
|
|
193
|
+
"""Create and seed the Snowflake migration lock table."""
|
|
194
|
+
self.create_schema_if_not_exists(schema)
|
|
195
|
+
self.execute_statement(self.create_migration_lock_table_sql(schema))
|
|
196
|
+
lock_table = self.MIGRATION_LOCK_TABLE
|
|
197
|
+
qualified = self.get_schema_qualified_name(schema, lock_table)
|
|
198
|
+
# Snowflake accepts UNIQUE/PRIMARY KEY syntax on standard tables but
|
|
199
|
+
# does not enforce it, so seed the singleton lock row with one MERGE.
|
|
200
|
+
self.execute_statement(f"""
|
|
201
|
+
MERGE INTO {qualified} target
|
|
202
|
+
USING (
|
|
203
|
+
SELECT
|
|
204
|
+
'migration' AS lock_name,
|
|
205
|
+
CURRENT_TIMESTAMP() AS locked_at
|
|
206
|
+
) source
|
|
207
|
+
ON target.lock_name = source.lock_name
|
|
208
|
+
WHEN NOT MATCHED THEN
|
|
209
|
+
INSERT (lock_name, locked_at)
|
|
210
|
+
VALUES (source.lock_name, source.locked_at)
|
|
211
|
+
""")
|
|
212
|
+
|
|
213
|
+
def acquire_migration_lock(
|
|
214
|
+
self,
|
|
215
|
+
schema: str,
|
|
216
|
+
wait_timeout_seconds: int = 60,
|
|
217
|
+
) -> bool:
|
|
218
|
+
"""Acquire the migration lock with a DML transaction."""
|
|
219
|
+
if self._migration_lock_transaction is not None:
|
|
220
|
+
return True
|
|
221
|
+
|
|
222
|
+
self.create_migration_lock_table_if_not_exists(schema)
|
|
223
|
+
connection = self.engine.connect()
|
|
224
|
+
try:
|
|
225
|
+
timeout = max(0, int(wait_timeout_seconds))
|
|
226
|
+
set_timeout = f"ALTER SESSION SET LOCK_TIMEOUT = {timeout}"
|
|
227
|
+
connection.exec_driver_sql(set_timeout)
|
|
228
|
+
connection.commit()
|
|
229
|
+
transaction = connection.begin()
|
|
230
|
+
connection.exec_driver_sql(self.acquire_migration_lock_sql(schema))
|
|
231
|
+
except Exception as exc:
|
|
232
|
+
try:
|
|
233
|
+
connection.rollback()
|
|
234
|
+
finally:
|
|
235
|
+
connection.close()
|
|
236
|
+
if _is_lock_timeout_error(exc):
|
|
237
|
+
return False
|
|
238
|
+
raise
|
|
239
|
+
|
|
240
|
+
self._migration_lock_connection = connection
|
|
241
|
+
self._migration_lock_transaction = transaction
|
|
242
|
+
return True
|
|
243
|
+
|
|
244
|
+
def release_migration_lock(self, schema: str) -> bool:
|
|
245
|
+
"""Release the Snowflake migration lock by ending its transaction."""
|
|
246
|
+
transaction = self._migration_lock_transaction
|
|
247
|
+
connection = self._migration_lock_connection
|
|
248
|
+
if transaction is None or connection is None:
|
|
249
|
+
return True
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
transaction.commit()
|
|
253
|
+
return True
|
|
254
|
+
except Exception:
|
|
255
|
+
try:
|
|
256
|
+
transaction.rollback()
|
|
257
|
+
except Exception:
|
|
258
|
+
pass
|
|
259
|
+
return False
|
|
260
|
+
finally:
|
|
261
|
+
try:
|
|
262
|
+
connection.close()
|
|
263
|
+
finally:
|
|
264
|
+
self._migration_lock_connection = None
|
|
265
|
+
self._migration_lock_transaction = None
|
|
266
|
+
|
|
267
|
+
def close(self) -> None:
|
|
268
|
+
"""Close SQLAlchemy resources and release any held migration lock."""
|
|
269
|
+
try:
|
|
270
|
+
self.release_migration_lock("")
|
|
271
|
+
finally:
|
|
272
|
+
super().close()
|
|
273
|
+
|
|
274
|
+
def get_applied_migrations(
|
|
275
|
+
self, schema: str, table_name: str = "dblift_schema_history"
|
|
276
|
+
) -> List[Dict[str, Any]]:
|
|
277
|
+
"""Return applied migration rows from the history table."""
|
|
278
|
+
normalized_table = table_name.upper()
|
|
279
|
+
if not self.table_exists(schema, normalized_table):
|
|
280
|
+
return []
|
|
281
|
+
rows: List[Dict[str, Any]] = self.execute_query(f"""
|
|
282
|
+
SELECT *
|
|
283
|
+
FROM {self.get_schema_qualified_name(schema, normalized_table)}
|
|
284
|
+
ORDER BY installed_rank
|
|
285
|
+
""")
|
|
286
|
+
return rows
|
|
287
|
+
|
|
288
|
+
def create_migration_history_table_if_not_exists(
|
|
289
|
+
self,
|
|
290
|
+
schema: str,
|
|
291
|
+
create_schema: bool = False,
|
|
292
|
+
table_name: str = "dblift_schema_history",
|
|
293
|
+
) -> None:
|
|
294
|
+
"""Create the Snowflake migration history table if missing."""
|
|
295
|
+
normalized_table = table_name.upper()
|
|
296
|
+
if create_schema:
|
|
297
|
+
self.create_schema_if_not_exists(schema)
|
|
298
|
+
if self.table_exists(schema, normalized_table):
|
|
299
|
+
if create_schema:
|
|
300
|
+
self._check_baseline_safety(schema, normalized_table)
|
|
301
|
+
return
|
|
302
|
+
create_sql = self.create_history_table(schema, normalized_table)
|
|
303
|
+
self.execute_statement(create_sql)
|
|
304
|
+
|
|
305
|
+
def _check_baseline_safety(self, schema: str, table_name: str) -> None:
|
|
306
|
+
"""Refuse baseline when history already contains migrations."""
|
|
307
|
+
qualified_table = self.get_schema_qualified_name(schema, table_name)
|
|
308
|
+
count_sql = f"SELECT COUNT(1) AS count FROM {qualified_table}"
|
|
309
|
+
rows = self.execute_query(count_sql)
|
|
310
|
+
migration_count = 0
|
|
311
|
+
if rows:
|
|
312
|
+
count = rows[0].get("count", rows[0].get("COUNT", 0))
|
|
313
|
+
migration_count = int(count or 0)
|
|
314
|
+
if migration_count > 0:
|
|
315
|
+
baseline_error = "Baseline cannot run with existing migrations."
|
|
316
|
+
raise RuntimeError(
|
|
317
|
+
f"Schema {schema} already contains a migration history table "
|
|
318
|
+
f"{table_name} with {migration_count} migration(s). "
|
|
319
|
+
f"{baseline_error}"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
def record_migration(
|
|
323
|
+
self,
|
|
324
|
+
schema: str,
|
|
325
|
+
migration_info: Dict[str, Any],
|
|
326
|
+
table_name: str = "dblift_schema_history",
|
|
327
|
+
) -> None:
|
|
328
|
+
"""Insert a migration record into the Snowflake history table."""
|
|
329
|
+
normalized_table = table_name.upper()
|
|
330
|
+
self.create_migration_history_table_if_not_exists(
|
|
331
|
+
schema,
|
|
332
|
+
table_name=normalized_table,
|
|
333
|
+
)
|
|
334
|
+
qualified_table = self.get_schema_qualified_name(
|
|
335
|
+
schema,
|
|
336
|
+
normalized_table,
|
|
337
|
+
)
|
|
338
|
+
self.execute_statement(
|
|
339
|
+
f"""
|
|
340
|
+
INSERT INTO {qualified_table}
|
|
341
|
+
(version, description, type, script, checksum,
|
|
342
|
+
installed_by, execution_time, success)
|
|
343
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
344
|
+
""",
|
|
345
|
+
params=[
|
|
346
|
+
migration_info.get("version"),
|
|
347
|
+
migration_info.get("description", ""),
|
|
348
|
+
migration_info.get("type", "SQL"),
|
|
349
|
+
migration_info.get("script", ""),
|
|
350
|
+
migration_info.get("checksum"),
|
|
351
|
+
migration_info.get("installed_by", "dblift"),
|
|
352
|
+
migration_info.get("execution_time", 0),
|
|
353
|
+
migration_info.get("success", True),
|
|
354
|
+
],
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
def record_undo(
|
|
358
|
+
self,
|
|
359
|
+
schema: str,
|
|
360
|
+
version: str,
|
|
361
|
+
table_name: Optional[str] = None,
|
|
362
|
+
script_name: Optional[str] = None,
|
|
363
|
+
) -> bool:
|
|
364
|
+
"""Record a successful undo in Snowflake migration history."""
|
|
365
|
+
undo_script = script_name or f"UNDO_{version}.sql"
|
|
366
|
+
self.record_migration(
|
|
367
|
+
schema,
|
|
368
|
+
{
|
|
369
|
+
"version": version,
|
|
370
|
+
"description": f"Undo migration {version}",
|
|
371
|
+
"type": "UNDO_SQL",
|
|
372
|
+
"script": undo_script,
|
|
373
|
+
"checksum": 0,
|
|
374
|
+
"success": True,
|
|
375
|
+
},
|
|
376
|
+
table_name or "dblift_schema_history",
|
|
377
|
+
)
|
|
378
|
+
return True
|
|
379
|
+
|
|
380
|
+
def repair_migration_history(
|
|
381
|
+
self,
|
|
382
|
+
schema: str,
|
|
383
|
+
script_name: str,
|
|
384
|
+
checksum: Any,
|
|
385
|
+
table_name: str = "dblift_schema_history",
|
|
386
|
+
success_value: Optional[Any] = None,
|
|
387
|
+
) -> bool:
|
|
388
|
+
"""Update checksum and success state for an existing migration row."""
|
|
389
|
+
normalized_table = table_name.upper()
|
|
390
|
+
if not self.table_exists(schema, normalized_table):
|
|
391
|
+
return False
|
|
392
|
+
qualified_table = self.get_schema_qualified_name(
|
|
393
|
+
schema,
|
|
394
|
+
normalized_table,
|
|
395
|
+
)
|
|
396
|
+
result = self.execute_statement(
|
|
397
|
+
f"""
|
|
398
|
+
UPDATE {qualified_table}
|
|
399
|
+
SET checksum = ?, success = COALESCE(?, success)
|
|
400
|
+
WHERE script = ?
|
|
401
|
+
""",
|
|
402
|
+
params=[checksum, success_value, script_name],
|
|
403
|
+
)
|
|
404
|
+
return result > 0
|
|
405
|
+
|
|
406
|
+
def create_history_table(self, schema: str, table_name: str) -> str:
|
|
407
|
+
"""Return SQL for the Snowflake migration history table."""
|
|
408
|
+
qualified_table = self.get_schema_qualified_name(schema, table_name)
|
|
409
|
+
return f"""
|
|
410
|
+
CREATE TABLE IF NOT EXISTS {qualified_table} (
|
|
411
|
+
installed_rank INTEGER AUTOINCREMENT
|
|
412
|
+
START 1 INCREMENT 1 PRIMARY KEY,
|
|
413
|
+
version VARCHAR(50),
|
|
414
|
+
description VARCHAR(200) NOT NULL,
|
|
415
|
+
type VARCHAR(20) NOT NULL,
|
|
416
|
+
script VARCHAR(1000) NOT NULL,
|
|
417
|
+
checksum VARCHAR(64),
|
|
418
|
+
installed_by VARCHAR(100) NOT NULL,
|
|
419
|
+
installed_on TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP(),
|
|
420
|
+
execution_time INTEGER NOT NULL,
|
|
421
|
+
success BOOLEAN NOT NULL
|
|
422
|
+
)
|
|
423
|
+
"""
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
__all__ = ["SnowflakeProvider"]
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
_SNOWFLAKE_VIEWS_QUERY = """
|
|
430
|
+
SELECT table_name AS object_name
|
|
431
|
+
FROM INFORMATION_SCHEMA.VIEWS
|
|
432
|
+
WHERE TABLE_SCHEMA = UPPER(?)
|
|
433
|
+
ORDER BY table_name
|
|
434
|
+
"""
|
|
435
|
+
|
|
436
|
+
_SNOWFLAKE_TABLES_QUERY = """
|
|
437
|
+
SELECT table_name AS object_name
|
|
438
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
439
|
+
WHERE TABLE_SCHEMA = UPPER(?)
|
|
440
|
+
AND TABLE_TYPE = 'BASE TABLE'
|
|
441
|
+
ORDER BY table_name
|
|
442
|
+
"""
|
|
443
|
+
|
|
444
|
+
_SNOWFLAKE_SEQUENCES_QUERY = """
|
|
445
|
+
SELECT sequence_name AS object_name
|
|
446
|
+
FROM INFORMATION_SCHEMA.SEQUENCES
|
|
447
|
+
WHERE SEQUENCE_SCHEMA = UPPER(?)
|
|
448
|
+
ORDER BY sequence_name
|
|
449
|
+
"""
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Snowflake :class:`DialectQuirks`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Optional, Type
|
|
6
|
+
|
|
7
|
+
from db.base_quirks import BaseQuirks
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from core.sql_generator.alter.base_alter_generator import (
|
|
11
|
+
BaseAlterGenerator,
|
|
12
|
+
)
|
|
13
|
+
from core.sql_generator.base_generator import BaseSqlGenerator
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SnowflakeQuirks(BaseQuirks):
|
|
17
|
+
"""Snowflake-specific dialect behaviour."""
|
|
18
|
+
|
|
19
|
+
supports_transactions = True
|
|
20
|
+
supports_transactional_ddl = False
|
|
21
|
+
schema_required = True
|
|
22
|
+
uppercase_identifiers = True
|
|
23
|
+
clean_strategy = "native"
|
|
24
|
+
sqlglot_dialect = "snowflake"
|
|
25
|
+
default_schema_name = "PUBLIC"
|
|
26
|
+
drop_supports_if_exists = True
|
|
27
|
+
table_drop_style = "if_exists_cascade"
|
|
28
|
+
unquoted_identifier_case = "uppercase"
|
|
29
|
+
quote_qualified_folds_to_uppercase = True
|
|
30
|
+
connection_identifier_attrs = ("url", "account")
|
|
31
|
+
missing_connection_identifier_hint = "Snowflake requires url or account"
|
|
32
|
+
native_url_schema_params = ("schema",)
|
|
33
|
+
native_driver_display = "snowflake-connector-python"
|
|
34
|
+
pygments_lexer = "sql"
|
|
35
|
+
|
|
36
|
+
def __init__(self, dialect_name: str = "snowflake") -> None:
|
|
37
|
+
super().__init__(dialect_name=dialect_name)
|
|
38
|
+
|
|
39
|
+
def has_connection_identifier(self, database_config: Any) -> bool:
|
|
40
|
+
"""Snowflake accepts a URL or an account identifier."""
|
|
41
|
+
if isinstance(database_config, dict):
|
|
42
|
+
url = database_config.get("url")
|
|
43
|
+
account = database_config.get("account")
|
|
44
|
+
if not account:
|
|
45
|
+
account = database_config.get("host")
|
|
46
|
+
else:
|
|
47
|
+
url = getattr(database_config, "url", None)
|
|
48
|
+
account = getattr(database_config, "account", None) or getattr(
|
|
49
|
+
database_config, "host", None
|
|
50
|
+
)
|
|
51
|
+
return bool(str(url or "").strip() or str(account or "").strip())
|
|
52
|
+
|
|
53
|
+
def ddl_generator_class(self) -> Optional[Type["BaseSqlGenerator"]]:
|
|
54
|
+
"""Snowflake rich DDL generation is registered by higher tiers."""
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
def alter_generator_class(self) -> Optional[Type["BaseAlterGenerator"]]:
|
|
58
|
+
"""Snowflake ALTER generation is registered by higher tiers."""
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
def introspector_class(self) -> Optional[Type[Any]]:
|
|
62
|
+
"""Snowflake rich introspection is registered by higher tiers."""
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
def vendor_queries_class(self) -> Optional[Type[Any]]:
|
|
66
|
+
"""Snowflake metadata queries are registered by higher tiers."""
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
__all__ = ["SnowflakeQuirks"]
|