sqlmeta.comparison
SQL object comparison and schema drift detection.
This module provides functionality to compare SQL objects from different sources and detect schema drift.
Example
>>> from sqlmeta.comparison import ObjectComparator, DataTypeNormalizer
>>> normalizer = DataTypeNormalizer("postgresql")
>>> comparator = ObjectComparator(normalizer)
>>> diff = comparator.compare_tables(table1, table2)
- class sqlmeta.comparison.ObjectComparator(type_normalizer: DataTypeNormalizer)[source]
Compares SQL Model objects and generates diff results.
This class provides methods to compare SQL objects from different sources (e.g., parsed SQL scripts vs. database metadata) and identify differences.
Example
>>> normalizer = DataTypeNormalizer() >>> comparator = ObjectComparator(normalizer) >>> diff = comparator.compare_tables(script_table, db_table, "postgresql") >>> if diff.has_diffs: ... print(f"Found differences: {diff}")
- __init__(type_normalizer: DataTypeNormalizer)[source]
Initialize the object comparator.
- Parameters:
type_normalizer – DataTypeNormalizer for type comparison
- compare_database_links(expected: DatabaseLink, actual: DatabaseLink, dialect: str = 'oracle') DatabaseLinkDiff | None[source]
Compare two database link objects (Oracle).
- Parameters:
expected – Expected database link from migrations
actual – Actual database link from database
dialect – SQL dialect (typically oracle)
- Returns:
DatabaseLinkDiff if differences found, None otherwise
- compare_events(expected: Event, actual: Event, dialect: str = 'mysql') EventDiff | None[source]
Compare two event objects (MySQL).
- Parameters:
expected – Expected event from migrations
actual – Actual event from database
dialect – SQL dialect (typically mysql)
- Returns:
EventDiff if differences found, None otherwise
- compare_extensions(expected: Extension, actual: Extension, dialect: str = 'postgresql') ExtensionDiff | None[source]
Compare two extension objects (PostgreSQL).
- Parameters:
expected – Expected extension from migrations
actual – Actual extension from database
dialect – SQL dialect (typically postgresql)
- Returns:
ExtensionDiff if differences found, None otherwise
- compare_foreign_data_wrappers(expected: ForeignDataWrapper, actual: ForeignDataWrapper, dialect: str = 'postgresql') ForeignDataWrapperDiff | None[source]
Compare two foreign data wrapper objects (PostgreSQL).
- Parameters:
expected – Expected FDW from migrations
actual – Actual FDW from database
dialect – SQL dialect (typically postgresql)
- Returns:
ForeignDataWrapperDiff if differences found, None otherwise
- compare_foreign_servers(expected: ForeignServer, actual: ForeignServer, dialect: str = 'postgresql') ForeignServerDiff | None[source]
Compare two foreign server objects (PostgreSQL).
- Parameters:
expected – Expected foreign server from migrations
actual – Actual foreign server from database
dialect – SQL dialect (typically postgresql)
- Returns:
ForeignServerDiff if differences found, None otherwise
- compare_functions(expected: Procedure, actual: Procedure, dialect: str = 'postgresql') FunctionDiff | None[source]
Compare two function objects (Procedure with is_function=True).
- Parameters:
expected – Expected function from migrations (Procedure with is_function=True)
actual – Actual function from database (Procedure with is_function=True)
dialect – SQL dialect
- Returns:
FunctionDiff if differences found, None otherwise
- compare_indexes(expected: Index, actual: Index, dialect: str = 'postgresql') IndexDiff | None[source]
Compare two index objects.
- Parameters:
expected – Expected index from migrations
actual – Actual index from database
dialect – SQL dialect
- Returns:
IndexDiff if differences found, None otherwise
- compare_linked_servers(expected: LinkedServer, actual: LinkedServer, dialect: str = 'sqlserver') LinkedServerDiff | None[source]
Compare two linked server objects (SQL Server).
- Parameters:
expected – Expected linked server from migrations
actual – Actual linked server from database
dialect – SQL dialect (typically sqlserver)
- Returns:
LinkedServerDiff if differences found, None otherwise
- compare_modules(expected: Module, actual: Module, dialect: str = 'db2') ModuleDiff | None[source]
Compare two DB2 module objects.
- Parameters:
expected – Expected module from migrations
actual – Actual module from database
dialect – SQL dialect (typically db2)
- Returns:
ModuleDiff if differences found, None otherwise
- compare_packages(expected: Package, actual: Package, dialect: str = 'oracle') PackageDiff | None[source]
Compare two package objects (Oracle).
- Parameters:
expected – Expected package from migrations
actual – Actual package from database
dialect – SQL dialect (typically oracle)
- Returns:
PackageDiff if differences found, None otherwise
- compare_procedures(expected: Procedure, actual: Procedure, dialect: str = 'postgresql') ProcedureDiff | None[source]
Compare two procedure objects.
- Parameters:
expected – Expected procedure from migrations
actual – Actual procedure from database
dialect – SQL dialect
- Returns:
ProcedureDiff if differences found, None otherwise
- compare_schemas(expected_tables: List[Table], actual_tables: List[Table], dialect: str = 'postgresql', schema_name: str = 'public') SchemaDiff[source]
Compare lists of tables from two schemas.
- Parameters:
expected_tables – Expected tables (from scripts)
actual_tables – Actual tables (from database)
dialect – SQL dialect for type normalization
schema_name – Name of the schema being compared
- Returns:
SchemaDiff object with comparison results
- compare_sequences(expected: Sequence, actual: Sequence, dialect: str = 'postgresql') SequenceDiff | None[source]
Compare two sequence objects.
- Parameters:
expected – Expected sequence from migrations
actual – Actual sequence from database
dialect – SQL dialect
- Returns:
SequenceDiff if differences found, None otherwise
- compare_synonyms(expected: Synonym, actual: Synonym, dialect: str = 'postgresql') SynonymDiff | None[source]
Compare two synonym objects.
- Parameters:
expected – Expected synonym from migrations
actual – Actual synonym from database
dialect – SQL dialect
- Returns:
SynonymDiff if differences found, None otherwise
- compare_tables(expected: Table, actual: Table, dialect: str = 'postgresql') TableDiff[source]
Compare two table objects.
- Parameters:
expected – Expected table (from scripts)
actual – Actual table (from database)
dialect – SQL dialect for type normalization
- Returns:
TableDiff object with comparison results
Example
>>> diff = comparator.compare_tables(script_table, db_table, "postgresql") >>> print(f"Missing columns: {diff.missing_columns}")
- compare_triggers(expected: Trigger, actual: Trigger, dialect: str = 'postgresql') TriggerDiff | None[source]
Compare two trigger objects.
- Parameters:
expected – Expected trigger from migrations
actual – Actual trigger from database
dialect – SQL dialect
- Returns:
TriggerDiff if differences found, None otherwise
- compare_user_defined_types(expected: UserDefinedType, actual: UserDefinedType, dialect: str = 'postgresql') UserDefinedTypeDiff | None[source]
Compare two user-defined type objects.
- Parameters:
expected – Expected UDT from migrations
actual – Actual UDT from database
dialect – SQL dialect
- Returns:
UserDefinedTypeDiff if differences found, None otherwise
- class sqlmeta.comparison.DataTypeNormalizer[source]
Normalizes data types across SQL dialects for comparison.
This class handles dialect-specific type equivalences, precision/scale normalization, and cross-dialect type mapping to enable accurate comparison of SQL Model objects from different sources.
Example
>>> normalizer = DataTypeNormalizer() >>> normalizer.normalize("INT", "postgresql") 'INTEGER' >>> normalizer.normalize("VARCHAR2(100)", "oracle") 'VARCHAR(100)' >>> normalizer.normalize("TINYINT(1)", "mysql") 'BOOLEAN'
- are_equivalent(type1: str, type2: str, dialect1: str, dialect2: str) bool[source]
Check if two data types are equivalent across dialects.
- Parameters:
type1 – First data type
type2 – Second data type
dialect1 – Dialect of first type
dialect2 – Dialect of second type
- Returns:
True if types are equivalent, False otherwise
Example
>>> normalizer.are_equivalent("TEXT", "CLOB", "postgresql", "oracle") True >>> normalizer.are_equivalent("INT", "VARCHAR", "mysql", "mysql") False
- extract_precision_scale(data_type: str) Tuple[int | None, int | None][source]
Extract precision and scale from a data type string.
- Parameters:
data_type – Data type with optional precision/scale (e.g., “NUMBER(10,2)”)
- Returns:
Tuple of (precision, scale), both may be None
Example
>>> normalizer.extract_precision_scale("VARCHAR(100)") (100, None) >>> normalizer.extract_precision_scale("NUMBER(10,2)") (10, 2)
- normalize(data_type: str, dialect: str, precision: int | None = None, scale: int | None = None) str[source]
Normalize a data type for the given dialect.
- Parameters:
data_type – The data type to normalize (e.g., “INT”, “VARCHAR2”)
dialect – The SQL dialect (postgresql, oracle, mysql, sqlserver, db2)
precision – Optional precision value
scale – Optional scale value
- Returns:
Normalized data type string
Example
>>> normalizer.normalize("INT", "postgresql") 'INTEGER' >>> normalizer.normalize("NUMBER", "oracle", 10, 2) 'NUMBER(10,2)'
- class sqlmeta.comparison.DiffResult(object_name: str, object_type: str = '', severity: DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False)[source]
Base class for comparison results.
- severity
Highest severity of differences found
- __init__(object_name: str, object_type: str = '', severity: DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False) None
- __str__() str[source]
Human-readable string representation.
- Returns:
Formatted string describing the diff
- severity: DiffSeverity = 'info'
- class sqlmeta.comparison.TableDiff(object_name: str, object_type: str = '', severity: ~sqlmeta.comparison.diff_models.DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False, table_name: str = '', missing_columns: ~typing.List[str] = <factory>, extra_columns: ~typing.List[str] = <factory>, modified_columns: ~typing.List[~sqlmeta.comparison.diff_models.ColumnDiff] = <factory>, missing_constraints: ~typing.List[str] = <factory>, extra_constraints: ~typing.List[str] = <factory>, modified_constraints: ~typing.List[~sqlmeta.comparison.diff_models.ConstraintDiff] = <factory>, missing_indexes: ~typing.List[str] = <factory>, extra_indexes: ~typing.List[str] = <factory>, temporary_changed: bool = False, filegroup_changed: bool = False, memory_optimized_changed: bool = False, system_versioned_changed: bool = False, history_table_changed: bool = False, partition_method_changed: bool = False, partition_columns_changed: bool = False, compress_changed: bool = False, compress_type_changed: bool = False, logged_changed: bool = False, organize_by_changed: bool = False)[source]
Represents differences in a table definition.
- modified_columns
Columns with differences
- Type:
- modified_constraints
Constraints with differences
- Type:
- memory_optimized_changed
Whether memory-optimized property changed (T-SQL grammar-based)
- Type:
- system_versioned_changed
Whether system-versioned property changed (T-SQL grammar-based)
- Type:
- __init__(object_name: str, object_type: str = '', severity: ~sqlmeta.comparison.diff_models.DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False, table_name: str = '', missing_columns: ~typing.List[str] = <factory>, extra_columns: ~typing.List[str] = <factory>, modified_columns: ~typing.List[~sqlmeta.comparison.diff_models.ColumnDiff] = <factory>, missing_constraints: ~typing.List[str] = <factory>, extra_constraints: ~typing.List[str] = <factory>, modified_constraints: ~typing.List[~sqlmeta.comparison.diff_models.ConstraintDiff] = <factory>, missing_indexes: ~typing.List[str] = <factory>, extra_indexes: ~typing.List[str] = <factory>, temporary_changed: bool = False, filegroup_changed: bool = False, memory_optimized_changed: bool = False, system_versioned_changed: bool = False, history_table_changed: bool = False, partition_method_changed: bool = False, partition_columns_changed: bool = False, compress_changed: bool = False, compress_type_changed: bool = False, logged_changed: bool = False, organize_by_changed: bool = False) None
- get_diff_count() Dict[str, int][source]
Get count of each type of difference.
- Returns:
Dictionary with counts of different types
- modified_columns: List[ColumnDiff]
- modified_constraints: List[ConstraintDiff]
- class sqlmeta.comparison.ColumnDiff(object_name: str, object_type: str = '', severity: DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False, column_name: str = '', data_type_diff: tuple | None = None, nullable_diff: tuple | None = None, default_diff: tuple | None = None, identity_diff: tuple | None = None, computed_diff: tuple | None = None)[source]
Represents differences in a column definition.
- __init__(object_name: str, object_type: str = '', severity: DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False, column_name: str = '', data_type_diff: tuple | None = None, nullable_diff: tuple | None = None, default_diff: tuple | None = None, identity_diff: tuple | None = None, computed_diff: tuple | None = None) None
- class sqlmeta.comparison.ConstraintDiff(object_name: str, object_type: str = '', severity: DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False, constraint_name: str = '', constraint_type: str = '', columns_diff: tuple | None = None, references_diff: tuple | None = None, check_clause_diff: tuple | None = None)[source]
Represents differences in a constraint definition.
- class sqlmeta.comparison.SchemaDiff(object_name: str, object_type: str = '', severity: ~sqlmeta.comparison.diff_models.DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False, schema_name: str = '', missing_tables: ~typing.List[str] = <factory>, extra_tables: ~typing.List[str] = <factory>, modified_tables: ~typing.List[~sqlmeta.comparison.diff_models.TableDiff] = <factory>, missing_views: ~typing.List[str] = <factory>, extra_views: ~typing.List[str] = <factory>, modified_views: ~typing.List[~sqlmeta.comparison.diff_models.ViewDiff] = <factory>, missing_indexes: ~typing.List[str] = <factory>, extra_indexes: ~typing.List[str] = <factory>, modified_indexes: ~typing.List[~sqlmeta.comparison.diff_models.IndexDiff] = <factory>, missing_sequences: ~typing.List[str] = <factory>, extra_sequences: ~typing.List[str] = <factory>, modified_sequences: ~typing.List[~sqlmeta.comparison.diff_models.SequenceDiff] = <factory>, missing_triggers: ~typing.List[str] = <factory>, extra_triggers: ~typing.List[str] = <factory>, modified_triggers: ~typing.List[~sqlmeta.comparison.diff_models.TriggerDiff] = <factory>, missing_procedures: ~typing.List[str] = <factory>, extra_procedures: ~typing.List[str] = <factory>, modified_procedures: ~typing.List[~sqlmeta.comparison.diff_models.ProcedureDiff] = <factory>, missing_functions: ~typing.List[str] = <factory>, extra_functions: ~typing.List[str] = <factory>, modified_functions: ~typing.List[~sqlmeta.comparison.diff_models.FunctionDiff] = <factory>, missing_synonyms: ~typing.List[str] = <factory>, extra_synonyms: ~typing.List[str] = <factory>, modified_synonyms: ~typing.List[~sqlmeta.comparison.diff_models.SynonymDiff] = <factory>, missing_packages: ~typing.List[str] = <factory>, extra_packages: ~typing.List[str] = <factory>, modified_packages: ~typing.List[~sqlmeta.comparison.diff_models.PackageDiff] = <factory>, missing_modules: ~typing.List[str] = <factory>, extra_modules: ~typing.List[str] = <factory>, modified_modules: ~typing.List[~sqlmeta.comparison.diff_models.ModuleDiff] = <factory>, missing_database_links: ~typing.List[str] = <factory>, extra_database_links: ~typing.List[str] = <factory>, modified_database_links: ~typing.List[~sqlmeta.comparison.diff_models.DatabaseLinkDiff] = <factory>, missing_linked_servers: ~typing.List[str] = <factory>, extra_linked_servers: ~typing.List[str] = <factory>, modified_linked_servers: ~typing.List[~sqlmeta.comparison.diff_models.LinkedServerDiff] = <factory>, missing_foreign_data_wrappers: ~typing.List[str] = <factory>, extra_foreign_data_wrappers: ~typing.List[str] = <factory>, modified_foreign_data_wrappers: ~typing.List[~sqlmeta.comparison.diff_models.ForeignDataWrapperDiff] = <factory>, missing_foreign_servers: ~typing.List[str] = <factory>, extra_foreign_servers: ~typing.List[str] = <factory>, modified_foreign_servers: ~typing.List[~sqlmeta.comparison.diff_models.ForeignServerDiff] = <factory>, missing_extensions: ~typing.List[str] = <factory>, extra_extensions: ~typing.List[str] = <factory>, modified_extensions: ~typing.List[~sqlmeta.comparison.diff_models.ExtensionDiff] = <factory>, missing_events: ~typing.List[str] = <factory>, extra_events: ~typing.List[str] = <factory>, modified_events: ~typing.List[~sqlmeta.comparison.diff_models.EventDiff] = <factory>, missing_user_defined_types: ~typing.List[str] = <factory>, extra_user_defined_types: ~typing.List[str] = <factory>, modified_user_defined_types: ~typing.List[~sqlmeta.comparison.diff_models.UserDefinedTypeDiff] = <factory>)[source]
Represents schema-level comparison results.
- modified_tables
Tables with differences
- Type:
- modified_views
Views with differences
- Type:
- modified_indexes
Indexes with differences
- Type:
- modified_sequences
Sequences with differences
- Type:
- modified_triggers
Triggers with differences
- Type:
- modified_procedures
Procedures with differences
- Type:
- modified_functions
Functions with differences
- Type:
- modified_synonyms
Synonyms with differences
- Type:
- modified_packages
Packages with differences
- Type:
- modified_extensions
Extensions with differences
- Type:
- modified_events
Events with differences
- Type:
- modified_user_defined_types
User-defined types with differences
- __init__(object_name: str, object_type: str = '', severity: ~sqlmeta.comparison.diff_models.DiffSeverity = DiffSeverity.INFO, has_diffs: bool = False, schema_name: str = '', missing_tables: ~typing.List[str] = <factory>, extra_tables: ~typing.List[str] = <factory>, modified_tables: ~typing.List[~sqlmeta.comparison.diff_models.TableDiff] = <factory>, missing_views: ~typing.List[str] = <factory>, extra_views: ~typing.List[str] = <factory>, modified_views: ~typing.List[~sqlmeta.comparison.diff_models.ViewDiff] = <factory>, missing_indexes: ~typing.List[str] = <factory>, extra_indexes: ~typing.List[str] = <factory>, modified_indexes: ~typing.List[~sqlmeta.comparison.diff_models.IndexDiff] = <factory>, missing_sequences: ~typing.List[str] = <factory>, extra_sequences: ~typing.List[str] = <factory>, modified_sequences: ~typing.List[~sqlmeta.comparison.diff_models.SequenceDiff] = <factory>, missing_triggers: ~typing.List[str] = <factory>, extra_triggers: ~typing.List[str] = <factory>, modified_triggers: ~typing.List[~sqlmeta.comparison.diff_models.TriggerDiff] = <factory>, missing_procedures: ~typing.List[str] = <factory>, extra_procedures: ~typing.List[str] = <factory>, modified_procedures: ~typing.List[~sqlmeta.comparison.diff_models.ProcedureDiff] = <factory>, missing_functions: ~typing.List[str] = <factory>, extra_functions: ~typing.List[str] = <factory>, modified_functions: ~typing.List[~sqlmeta.comparison.diff_models.FunctionDiff] = <factory>, missing_synonyms: ~typing.List[str] = <factory>, extra_synonyms: ~typing.List[str] = <factory>, modified_synonyms: ~typing.List[~sqlmeta.comparison.diff_models.SynonymDiff] = <factory>, missing_packages: ~typing.List[str] = <factory>, extra_packages: ~typing.List[str] = <factory>, modified_packages: ~typing.List[~sqlmeta.comparison.diff_models.PackageDiff] = <factory>, missing_modules: ~typing.List[str] = <factory>, extra_modules: ~typing.List[str] = <factory>, modified_modules: ~typing.List[~sqlmeta.comparison.diff_models.ModuleDiff] = <factory>, missing_database_links: ~typing.List[str] = <factory>, extra_database_links: ~typing.List[str] = <factory>, modified_database_links: ~typing.List[~sqlmeta.comparison.diff_models.DatabaseLinkDiff] = <factory>, missing_linked_servers: ~typing.List[str] = <factory>, extra_linked_servers: ~typing.List[str] = <factory>, modified_linked_servers: ~typing.List[~sqlmeta.comparison.diff_models.LinkedServerDiff] = <factory>, missing_foreign_data_wrappers: ~typing.List[str] = <factory>, extra_foreign_data_wrappers: ~typing.List[str] = <factory>, modified_foreign_data_wrappers: ~typing.List[~sqlmeta.comparison.diff_models.ForeignDataWrapperDiff] = <factory>, missing_foreign_servers: ~typing.List[str] = <factory>, extra_foreign_servers: ~typing.List[str] = <factory>, modified_foreign_servers: ~typing.List[~sqlmeta.comparison.diff_models.ForeignServerDiff] = <factory>, missing_extensions: ~typing.List[str] = <factory>, extra_extensions: ~typing.List[str] = <factory>, modified_extensions: ~typing.List[~sqlmeta.comparison.diff_models.ExtensionDiff] = <factory>, missing_events: ~typing.List[str] = <factory>, extra_events: ~typing.List[str] = <factory>, modified_events: ~typing.List[~sqlmeta.comparison.diff_models.EventDiff] = <factory>, missing_user_defined_types: ~typing.List[str] = <factory>, extra_user_defined_types: ~typing.List[str] = <factory>, modified_user_defined_types: ~typing.List[~sqlmeta.comparison.diff_models.UserDefinedTypeDiff] = <factory>) None
- get_diff_count() Dict[str, int][source]
Get count of each type of difference.
- Returns:
Dictionary with counts of different types
- get_total_diff_count() int[source]
Get total count of all differences.
- Returns:
Total number of differences
- modified_sequences: List[SequenceDiff]
- modified_triggers: List[TriggerDiff]
- modified_procedures: List[ProcedureDiff]
- modified_functions: List[FunctionDiff]
- modified_synonyms: List[SynonymDiff]
- modified_packages: List[PackageDiff]
- modified_modules: List[ModuleDiff]
- modified_database_links: List[DatabaseLinkDiff]
- modified_linked_servers: List[LinkedServerDiff]
- modified_foreign_data_wrappers: List[ForeignDataWrapperDiff]
- modified_foreign_servers: List[ForeignServerDiff]
- modified_extensions: List[ExtensionDiff]
- modified_user_defined_types: List[UserDefinedTypeDiff]
Modules
SQL Object Comparator for Drift Detection. |
|
Diff Models for SQL Object Comparison Results. |
|
Data Type Normalization for Cross-Dialect Comparison. |