google-pso-data-validator 8.1.0__tar.gz → 8.2.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.
- {google_pso_data_validator-8.1.0/google_pso_data_validator.egg-info → google_pso_data_validator-8.2.0}/PKG-INFO +3 -1
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/README.md +2 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/__init__.py +2 -2
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/__main__.py +1 -4
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/cli_tools.py +5 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/clients.py +4 -5
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/config_manager.py +28 -1
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0/google_pso_data_validator.egg-info}/PKG-INFO +3 -1
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/google_pso_data_validator.egg-info/SOURCES.txt +1 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/setup.py +1 -1
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_addon/operations.py +8 -51
- google_pso_data_validator-8.2.0/third_party/ibis/ibis_bigquery/registry.py +57 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_db2/__init__.py +2 -2
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_mssql/registry.py +23 -1
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_oracle/datatypes.py +4 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_oracle/registry.py +2 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_teradata/registry.py +2 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/LICENSE +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/app.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/client_info.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/combiner.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/consts.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/data_validation.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/exceptions.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/find_tables.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/gcs_helper.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/jellyfish_distance.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/metadata.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/partition_builder.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/query_builder/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/query_builder/partition_row_builder.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/query_builder/query_builder.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/query_builder/random_row_builder.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/raw_query.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/result_handlers/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/result_handlers/base_backend.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/result_handlers/bigquery.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/result_handlers/factory.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/result_handlers/postgres.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/result_handlers/text.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/schema_validation.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/secret_manager.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/state_manager.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/util.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/validation_builder.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/google_pso_data_validator.egg-info/dependency_links.txt +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/google_pso_data_validator.egg-info/entry_points.txt +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/google_pso_data_validator.egg-info/requires.txt +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/google_pso_data_validator.egg-info/top_level.txt +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/setup.cfg +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_addon/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_addon/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_bigquery/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_bigquery/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/client.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/compiler.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/datatypes.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/registry.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/tests/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/tests/conftest.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_cloud_spanner/to_pandas.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_db2/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_db2/compiler.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_db2/datatypes.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_db2/registry.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_impala/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_impala/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_mssql/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_mssql/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_mssql/datatypes.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_mysql/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_mysql/base_sql_compiler/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_mysql/base_sql_compiler/select_builder.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_mysql/compiler.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_oracle/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_oracle/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_oracle/compiler.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_postgres/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_postgres/client.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_postgres/datatypes.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_postgres/registry.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_redshift/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_redshift/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_redshift/compiler.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_snowflake/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_snowflake/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_snowflake/datatypes.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_teradata/__init__.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_teradata/api.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_teradata/compiler.py +0 -0
- {google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_teradata/datatypes.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-pso-data-validator
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.2.0
|
|
4
4
|
Summary: A package to enable easy data validation
|
|
5
5
|
Author: PSO DVT Engineering team
|
|
6
6
|
Author-email: data-validator-eng@google.com
|
|
@@ -449,6 +449,8 @@ data-validation
|
|
|
449
449
|
Either --target-query or --target-query-file must be provided
|
|
450
450
|
--target-query-file TARGET_QUERY_FILE, -tqf TARGET_QUERY_FILE
|
|
451
451
|
File containing the target sql command. Supports GCS and local paths.
|
|
452
|
+
[--grouped-columns or -gc GROUPED_COLUMNS]
|
|
453
|
+
Comma separated list of columns for Group By i.e col_a,col_b
|
|
452
454
|
[--count COLUMNS] Comma separated list of columns for count or * for all columns
|
|
453
455
|
[--sum COLUMNS] Comma separated list of columns for sum or * for all numeric
|
|
454
456
|
[--min COLUMNS] Comma separated list of columns for min or * for all numeric
|
|
@@ -390,6 +390,8 @@ data-validation
|
|
|
390
390
|
Either --target-query or --target-query-file must be provided
|
|
391
391
|
--target-query-file TARGET_QUERY_FILE, -tqf TARGET_QUERY_FILE
|
|
392
392
|
File containing the target sql command. Supports GCS and local paths.
|
|
393
|
+
[--grouped-columns or -gc GROUPED_COLUMNS]
|
|
394
|
+
Comma separated list of columns for Group By i.e col_a,col_b
|
|
393
395
|
[--count COLUMNS] Comma separated list of columns for count or * for all columns
|
|
394
396
|
[--sum COLUMNS] Comma separated list of columns for sum or * for all numeric
|
|
395
397
|
[--min COLUMNS] Comma separated list of columns for min or * for all numeric
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/__init__.py
RENAMED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from
|
|
15
|
+
from importlib.metadata import version
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
__version__ =
|
|
18
|
+
__version__ = version("google-pso-data-validator")
|
|
19
19
|
__all__ = ["__version__"]
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/__main__.py
RENAMED
|
@@ -294,10 +294,7 @@ def build_config_from_args(args: "Namespace", config_manager: ConfigManager):
|
|
|
294
294
|
and args.custom_query_type == consts.COLUMN_VALIDATION.lower()
|
|
295
295
|
):
|
|
296
296
|
config_manager.append_aggregates(get_aggregate_config(args, config_manager))
|
|
297
|
-
if
|
|
298
|
-
config_manager.validation_type == consts.COLUMN_VALIDATION
|
|
299
|
-
and args.grouped_columns # grouped_columns not supported in custom queries - at least now.
|
|
300
|
-
):
|
|
297
|
+
if args.grouped_columns:
|
|
301
298
|
grouped_columns = cli_tools.get_arg_list(args.grouped_columns)
|
|
302
299
|
config_manager.append_query_groups(
|
|
303
300
|
config_manager.build_column_configs(grouped_columns)
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/cli_tools.py
RENAMED
|
@@ -948,6 +948,11 @@ def _configure_custom_query_column_parser(custom_query_column_parser):
|
|
|
948
948
|
equivalent) that are comparable across all other supported SQL engines. This option may produce
|
|
949
949
|
unreliable results.""",
|
|
950
950
|
)
|
|
951
|
+
optional_arguments.add_argument(
|
|
952
|
+
"--grouped-columns",
|
|
953
|
+
"-gc",
|
|
954
|
+
help="Comma separated list of columns to group results by, e.g. 'col_a,col_b'. Applies to column validations, including custom-query column.",
|
|
955
|
+
)
|
|
951
956
|
optional_arguments.add_argument(
|
|
952
957
|
"--exclude-columns",
|
|
953
958
|
"-ec",
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/clients.py
RENAMED
|
@@ -69,20 +69,20 @@ def _raise_missing_client_error(msg):
|
|
|
69
69
|
# Teradata requires teradatasql and licensing
|
|
70
70
|
try:
|
|
71
71
|
from third_party.ibis.ibis_teradata.api import teradata_connect
|
|
72
|
-
except
|
|
72
|
+
except ImportError:
|
|
73
73
|
msg = "pip install teradatasql (requires Teradata licensing)"
|
|
74
74
|
teradata_connect = _raise_missing_client_error(msg)
|
|
75
75
|
|
|
76
76
|
# Oracle requires python-oracldb driver
|
|
77
77
|
try:
|
|
78
78
|
from third_party.ibis.ibis_oracle.api import oracle_connect
|
|
79
|
-
except
|
|
79
|
+
except ImportError:
|
|
80
80
|
oracle_connect = _raise_missing_client_error("pip install oracledb")
|
|
81
81
|
|
|
82
82
|
# Snowflake requires snowflake-connector-python and snowflake-sqlalchemy
|
|
83
83
|
try:
|
|
84
84
|
from third_party.ibis.ibis_snowflake.api import snowflake_connect
|
|
85
|
-
except
|
|
85
|
+
except ImportError:
|
|
86
86
|
snowflake_connect = _raise_missing_client_error(
|
|
87
87
|
"pip install snowflake-connector-python && pip install snowflake-sqlalchemy"
|
|
88
88
|
)
|
|
@@ -90,8 +90,7 @@ except Exception:
|
|
|
90
90
|
# DB2 requires ibm_db_sa
|
|
91
91
|
try:
|
|
92
92
|
from third_party.ibis.ibis_db2.api import db2_connect
|
|
93
|
-
except
|
|
94
|
-
logging.error(f"Exception {str(e)} while importing db2_connect")
|
|
93
|
+
except ImportError:
|
|
95
94
|
db2_connect = _raise_missing_client_error("pip install ibm_db_sa")
|
|
96
95
|
|
|
97
96
|
|
|
@@ -664,6 +664,30 @@ class ConfigManager(object):
|
|
|
664
664
|
isinstance(source_type, dt.UUID) or isinstance(target_type, dt.UUID)
|
|
665
665
|
)
|
|
666
666
|
|
|
667
|
+
def _is_sql_server_text(
|
|
668
|
+
self, source_column_name: str, target_column_name: str
|
|
669
|
+
) -> bool:
|
|
670
|
+
"""Returns True when either source or target column is of SQL Server text data type.
|
|
671
|
+
|
|
672
|
+
This is because SQL Server text does not support the len() function to get the length in characters.
|
|
673
|
+
Instead we must fall back to using ByteLength."""
|
|
674
|
+
|
|
675
|
+
raw_source_types = self.get_source_raw_data_types()
|
|
676
|
+
raw_target_types = self.get_target_raw_data_types()
|
|
677
|
+
text_types = ("text", "ntext")
|
|
678
|
+
return bool(
|
|
679
|
+
(
|
|
680
|
+
self.source_client.name == "mssql"
|
|
681
|
+
and raw_source_types
|
|
682
|
+
and raw_source_types.get(source_column_name, [None])[0] in text_types
|
|
683
|
+
)
|
|
684
|
+
or (
|
|
685
|
+
self.target_client.name == "mssql"
|
|
686
|
+
and raw_target_types
|
|
687
|
+
and raw_target_types.get(target_column_name, [None])[0] in text_types
|
|
688
|
+
)
|
|
689
|
+
)
|
|
690
|
+
|
|
667
691
|
def build_config_comparison_fields(self, fields, depth=None):
|
|
668
692
|
"""Return list of field config objects."""
|
|
669
693
|
field_configs = []
|
|
@@ -809,7 +833,10 @@ class ConfigManager(object):
|
|
|
809
833
|
depth = 1
|
|
810
834
|
calc_func = consts.CALC_FIELD_LENGTH
|
|
811
835
|
elif column_type in ["string", "!string"]:
|
|
812
|
-
|
|
836
|
+
if self._is_sql_server_text(source_column, target_column):
|
|
837
|
+
calc_func = consts.CALC_FIELD_BYTE_LENGTH
|
|
838
|
+
else:
|
|
839
|
+
calc_func = consts.CALC_FIELD_LENGTH
|
|
813
840
|
|
|
814
841
|
elif self._is_uuid(column_type, target_column_type):
|
|
815
842
|
calc_func = consts.CONFIG_CAST
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-pso-data-validator
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.2.0
|
|
4
4
|
Summary: A package to enable easy data validation
|
|
5
5
|
Author: PSO DVT Engineering team
|
|
6
6
|
Author-email: data-validator-eng@google.com
|
|
@@ -449,6 +449,8 @@ data-validation
|
|
|
449
449
|
Either --target-query or --target-query-file must be provided
|
|
450
450
|
--target-query-file TARGET_QUERY_FILE, -tqf TARGET_QUERY_FILE
|
|
451
451
|
File containing the target sql command. Supports GCS and local paths.
|
|
452
|
+
[--grouped-columns or -gc GROUPED_COLUMNS]
|
|
453
|
+
Comma separated list of columns for Group By i.e col_a,col_b
|
|
452
454
|
[--count COLUMNS] Comma separated list of columns for count or * for all columns
|
|
453
455
|
[--sum COLUMNS] Comma separated list of columns for sum or * for all numeric
|
|
454
456
|
[--min COLUMNS] Comma separated list of columns for min or * for all numeric
|
|
@@ -45,6 +45,7 @@ third_party/ibis/ibis_addon/api.py
|
|
|
45
45
|
third_party/ibis/ibis_addon/operations.py
|
|
46
46
|
third_party/ibis/ibis_bigquery/__init__.py
|
|
47
47
|
third_party/ibis/ibis_bigquery/api.py
|
|
48
|
+
third_party/ibis/ibis_bigquery/registry.py
|
|
48
49
|
third_party/ibis/ibis_cloud_spanner/__init__.py
|
|
49
50
|
third_party/ibis/ibis_cloud_spanner/api.py
|
|
50
51
|
third_party/ibis/ibis_cloud_spanner/client.py
|
|
@@ -48,10 +48,7 @@ from ibis.backends.bigquery.client import (
|
|
|
48
48
|
_LEGACY_TO_STANDARD as _BQ_LEGACY_TO_STANDARD,
|
|
49
49
|
)
|
|
50
50
|
from ibis.backends.bigquery.compiler import BigQueryExprTranslator
|
|
51
|
-
from ibis.backends.bigquery.registry import
|
|
52
|
-
STRFTIME_FORMAT_FUNCTIONS as BQ_STRFTIME_FORMAT_FUNCTIONS,
|
|
53
|
-
bigquery_cast,
|
|
54
|
-
)
|
|
51
|
+
from ibis.backends.bigquery.registry import bigquery_cast
|
|
55
52
|
from ibis.backends.impala.compiler import ImpalaExprTranslator
|
|
56
53
|
from ibis.backends.mssql.compiler import MsSqlExprTranslator
|
|
57
54
|
from ibis.backends.mysql.compiler import MySQLExprTranslator
|
|
@@ -62,6 +59,7 @@ from ibis.expr.types import BinaryValue, NumericValue, StringValue, TemporalValu
|
|
|
62
59
|
|
|
63
60
|
# Do not remove these lines, they trigger patching of Ibis code.
|
|
64
61
|
import third_party.ibis.ibis_bigquery.api # noqa
|
|
62
|
+
from third_party.ibis.ibis_bigquery import registry as bigquery_registry
|
|
65
63
|
import third_party.ibis.ibis_mysql.compiler # noqa
|
|
66
64
|
from third_party.ibis.ibis_mssql import registry as mssql_registry
|
|
67
65
|
from third_party.ibis.ibis_postgres import registry as postgres_registry
|
|
@@ -101,7 +99,7 @@ NAT_INT64_MIN_IN_SECONDS = np.iinfo(np.int64).min // 1_000_000_000
|
|
|
101
99
|
|
|
102
100
|
|
|
103
101
|
class BinaryLength(ops.Value):
|
|
104
|
-
arg = rlz.one_of([rlz.value(dt.Binary)])
|
|
102
|
+
arg = rlz.one_of([rlz.value(dt.Binary), rlz.value(dt.String)])
|
|
105
103
|
output_dtype = dt.int32
|
|
106
104
|
output_shape = rlz.shape_like("arg")
|
|
107
105
|
|
|
@@ -154,24 +152,6 @@ def bigquery_cast_to_binary_generate(compiled_arg, from_, to):
|
|
|
154
152
|
return f"FROM_HEX({compiled_arg})"
|
|
155
153
|
|
|
156
154
|
|
|
157
|
-
def format_hash_bigquery(translator, op):
|
|
158
|
-
arg = translator.translate(op.arg)
|
|
159
|
-
if op.how == "farm_fingerprint":
|
|
160
|
-
return f"FARM_FINGERPRINT({arg})"
|
|
161
|
-
else:
|
|
162
|
-
raise ValueError(f"unexpected value for 'how': {op.how}")
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def format_hashbytes_bigquery(translator, op):
|
|
166
|
-
arg = translator.translate(op.arg)
|
|
167
|
-
if op.how == "sha256":
|
|
168
|
-
return f"TO_HEX(SHA256({arg}))"
|
|
169
|
-
elif op.how == "farm_fingerprint":
|
|
170
|
-
return f"FARM_FINGERPRINT({arg})"
|
|
171
|
-
else:
|
|
172
|
-
raise ValueError(f"unexpected value for 'how': {op.how}")
|
|
173
|
-
|
|
174
|
-
|
|
175
155
|
def format_hashbytes_teradata(translator, op):
|
|
176
156
|
arg = translator.translate(op.arg)
|
|
177
157
|
if op.how == "sha256":
|
|
@@ -184,30 +164,6 @@ def format_hashbytes_teradata(translator, op):
|
|
|
184
164
|
raise ValueError(f"unexpected value for 'how': {op.how}")
|
|
185
165
|
|
|
186
166
|
|
|
187
|
-
def strftime_bigquery(translator, op):
|
|
188
|
-
"""Timestamp formatting."""
|
|
189
|
-
arg = op.arg
|
|
190
|
-
format_str = op.format_str
|
|
191
|
-
arg_type = arg.output_dtype
|
|
192
|
-
strftime_format_func_name = BQ_STRFTIME_FORMAT_FUNCTIONS[type(arg_type)]
|
|
193
|
-
fmt_string = translator.translate(format_str)
|
|
194
|
-
# Deal with issue 1181 due a GoogleSQL bug with dates before 1000 CE affects both date and timestamp types
|
|
195
|
-
if format_str.value.startswith("%Y"):
|
|
196
|
-
fmt_string = fmt_string.replace("%Y", "%E4Y", 1)
|
|
197
|
-
arg_formatted = translator.translate(arg)
|
|
198
|
-
if isinstance(arg_type, dt.Timestamp):
|
|
199
|
-
return "FORMAT_{}({}, {}({}), {!r})".format(
|
|
200
|
-
strftime_format_func_name,
|
|
201
|
-
fmt_string,
|
|
202
|
-
strftime_format_func_name,
|
|
203
|
-
arg_formatted,
|
|
204
|
-
arg_type.timezone if arg_type.timezone is not None else "UTC",
|
|
205
|
-
)
|
|
206
|
-
return "FORMAT_{}({}, {})".format(
|
|
207
|
-
strftime_format_func_name, fmt_string, arg_formatted
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
|
|
211
167
|
def strftime_mysql(translator, op):
|
|
212
168
|
arg = op.arg
|
|
213
169
|
format_string = op.format_str
|
|
@@ -528,10 +484,10 @@ TemporalValue.to_char = compile_to_char
|
|
|
528
484
|
# so we can piggy back Ibis code rather than writing metadata queries for all engines.
|
|
529
485
|
BaseAlchemyBackend.dvt_list_tables = _dvt_list_tables
|
|
530
486
|
|
|
531
|
-
BigQueryExprTranslator._registry[ops.HashBytes] =
|
|
487
|
+
BigQueryExprTranslator._registry[ops.HashBytes] = bigquery_registry.format_hashbytes
|
|
532
488
|
BigQueryExprTranslator._registry[RawSQL] = format_raw_sql
|
|
533
|
-
BigQueryExprTranslator._registry[ops.Strftime] =
|
|
534
|
-
BigQueryExprTranslator._registry[BinaryLength] =
|
|
489
|
+
BigQueryExprTranslator._registry[ops.Strftime] = bigquery_registry.strftime
|
|
490
|
+
BigQueryExprTranslator._registry[BinaryLength] = bigquery_registry.format_binary_length
|
|
535
491
|
|
|
536
492
|
AlchemyExprTranslator._registry[RawSQL] = format_raw_sql
|
|
537
493
|
AlchemyExprTranslator._registry[ops.HashBytes] = format_hashbytes_alchemy
|
|
@@ -580,6 +536,7 @@ MsSqlExprTranslator._registry[RawSQL] = sa_format_raw_sql
|
|
|
580
536
|
MsSqlExprTranslator._registry[ops.IfNull] = sa_fixed_arity(sa.func.isnull, 2)
|
|
581
537
|
MsSqlExprTranslator._registry[ops.StringJoin] = mssql_registry.sa_string_join
|
|
582
538
|
MsSqlExprTranslator._registry[ops.RandomScalar] = mssql_registry.sa_format_new_id
|
|
539
|
+
MsSqlExprTranslator._registry[ops.StringLength] = mssql_registry.sa_format_string_length
|
|
583
540
|
MsSqlExprTranslator._registry[ops.Strftime] = mssql_registry.strftime
|
|
584
541
|
MsSqlExprTranslator._registry[ops.Cast] = mssql_registry.sa_cast_mssql
|
|
585
542
|
MsSqlExprTranslator._registry[BinaryLength] = mssql_registry.sa_format_binary_length
|
|
@@ -614,7 +571,7 @@ if Db2ExprTranslator:
|
|
|
614
571
|
]
|
|
615
572
|
|
|
616
573
|
SpannerExprTranslator._registry[RawSQL] = format_raw_sql
|
|
617
|
-
SpannerExprTranslator._registry[ops.HashBytes] =
|
|
574
|
+
SpannerExprTranslator._registry[ops.HashBytes] = bigquery_registry.format_hashbytes
|
|
618
575
|
SpannerExprTranslator._registry[BinaryLength] = sa_format_binary_length
|
|
619
576
|
|
|
620
577
|
if TeradataExprTranslator:
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Copyright 2025 Google Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from ibis.backends.bigquery.registry import (
|
|
16
|
+
STRFTIME_FORMAT_FUNCTIONS as BQ_STRFTIME_FORMAT_FUNCTIONS,
|
|
17
|
+
)
|
|
18
|
+
import ibis.expr.datatypes as dt
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def format_hashbytes(translator, op):
|
|
22
|
+
arg = translator.translate(op.arg)
|
|
23
|
+
if op.how == "sha256":
|
|
24
|
+
return f"TO_HEX(SHA256({arg}))"
|
|
25
|
+
elif op.how == "farm_fingerprint":
|
|
26
|
+
return f"FARM_FINGERPRINT({arg})"
|
|
27
|
+
else:
|
|
28
|
+
raise ValueError(f"unexpected value for 'how': {op.how}")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def strftime(translator, op):
|
|
32
|
+
"""Timestamp formatting."""
|
|
33
|
+
arg = op.arg
|
|
34
|
+
format_str = op.format_str
|
|
35
|
+
arg_type = arg.output_dtype
|
|
36
|
+
strftime_format_func_name = BQ_STRFTIME_FORMAT_FUNCTIONS[type(arg_type)]
|
|
37
|
+
fmt_string = translator.translate(format_str)
|
|
38
|
+
# Deal with issue 1181 due a GoogleSQL bug with dates before 1000 CE affects both date and timestamp types
|
|
39
|
+
if format_str.value.startswith("%Y"):
|
|
40
|
+
fmt_string = fmt_string.replace("%Y", "%E4Y", 1)
|
|
41
|
+
arg_formatted = translator.translate(arg)
|
|
42
|
+
if isinstance(arg_type, dt.Timestamp):
|
|
43
|
+
return "FORMAT_{}({}, {}({}), {!r})".format(
|
|
44
|
+
strftime_format_func_name,
|
|
45
|
+
fmt_string,
|
|
46
|
+
strftime_format_func_name,
|
|
47
|
+
arg_formatted,
|
|
48
|
+
arg_type.timezone if arg_type.timezone is not None else "UTC",
|
|
49
|
+
)
|
|
50
|
+
return "FORMAT_{}({}, {})".format(
|
|
51
|
+
strftime_format_func_name, fmt_string, arg_formatted
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def format_binary_length(translator, op):
|
|
56
|
+
arg = translator.translate(op.arg)
|
|
57
|
+
return f"LENGTH({arg})"
|
|
@@ -104,7 +104,7 @@ class Backend(BaseAlchemyBackend):
|
|
|
104
104
|
|
|
105
105
|
def raw_column_metadata_not_implemented(
|
|
106
106
|
self, database: str = None, table: str = None, query: str = None
|
|
107
|
-
) -> list
|
|
107
|
+
) -> list:
|
|
108
108
|
"""Define this method to allow DVT to test if backend specific transformations may be needed for comparison.
|
|
109
109
|
Partner method to _metadata that retains raw data type information instead of converting
|
|
110
110
|
to Ibis types. This works in the same way as _metadata by running a query over the DVT
|
|
@@ -117,7 +117,7 @@ class Backend(BaseAlchemyBackend):
|
|
|
117
117
|
list: A list of tuples containing the standard 7 DB API fields:
|
|
118
118
|
https://peps.python.org/pep-0249/#description
|
|
119
119
|
"""
|
|
120
|
-
return
|
|
120
|
+
return []
|
|
121
121
|
|
|
122
122
|
def is_char_type_padded(self, char_type: Tuple) -> bool:
|
|
123
123
|
"""Define this method if the backend supports character/string types that are padded and returns
|
|
@@ -84,9 +84,25 @@ def sa_epoch_seconds(translator, op):
|
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
|
|
87
|
+
def sa_format_string_length(translator, op):
|
|
88
|
+
"""Calculate SQL Server string length in characters, not bytes.
|
|
89
|
+
|
|
90
|
+
This uses len() rather than datalength() to give an output compatible with BigQuery.
|
|
91
|
+
We need to protect trailing spaces due to an odd quirk in SQL Server len()
|
|
92
|
+
behaviour that ignores them, so this is done by first replacing spaces with
|
|
93
|
+
underscores before passing the string to len().
|
|
94
|
+
|
|
95
|
+
The len expression is cast to BIGINT to prevent int overflow for large tables."""
|
|
96
|
+
arg = translator.translate(op.arg)
|
|
97
|
+
return sa.func.cast(sa.func.len(sa.func.replace(arg, " ", "_")), sa.BIGINT)
|
|
98
|
+
|
|
99
|
+
|
|
87
100
|
def sa_format_binary_length(translator, op):
|
|
101
|
+
"""Calculate SQL Server bytes/string length in bytes, not characters.
|
|
102
|
+
|
|
103
|
+
The len expression is cast to BIGINT to prevent int overflow for large tables."""
|
|
88
104
|
arg = translator.translate(op.arg)
|
|
89
|
-
return sa.func.datalength(arg)
|
|
105
|
+
return sa.func.cast(sa.func.datalength(arg), sa.BIGINT)
|
|
90
106
|
|
|
91
107
|
|
|
92
108
|
def sa_format_hashbytes(translator, op):
|
|
@@ -130,6 +146,12 @@ def sa_cast_mssql(t, op):
|
|
|
130
146
|
formatted_value = sa.func.format(sa_arg, format_string)
|
|
131
147
|
# Replace trailing '.0' with ''
|
|
132
148
|
return sa.func.replace(formatted_value, ".0", "")
|
|
149
|
+
elif arg_dtype.is_boolean() and typ.is_string():
|
|
150
|
+
return sa.case(
|
|
151
|
+
(sa_arg == 0, sa.literal_column("'false'")),
|
|
152
|
+
(sa_arg == 1, sa.literal_column("'true'")),
|
|
153
|
+
else_=sa.null(),
|
|
154
|
+
)
|
|
133
155
|
|
|
134
156
|
# Follow the original Ibis code path.
|
|
135
157
|
return sa_fixed_cast(t, op)
|
|
@@ -84,6 +84,7 @@ _type_mapping = {
|
|
|
84
84
|
oracledb.DB_TYPE_BINARY_DOUBLE: dt.Float64,
|
|
85
85
|
oracledb.DB_TYPE_INTERVAL_DS: dt.Interval,
|
|
86
86
|
oracledb.DB_TYPE_INTERVAL_YM: dt.Interval,
|
|
87
|
+
oracledb.DB_TYPE_BOOLEAN: dt.Boolean,
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
# SQL Alchemy doesn't support LONG RAW which drops us into Ibis 5.1.0 method:
|
|
@@ -100,6 +101,9 @@ if "TIMESTAMP WITH LOCAL TIME ZONE" not in OracleDialect_oracledb.ischema_names:
|
|
|
100
101
|
"TIMESTAMP WITH LOCAL TIME ZONE"
|
|
101
102
|
] = oracle.TIMESTAMP(timezone=True)
|
|
102
103
|
|
|
104
|
+
if "BOOLEAN" not in OracleDialect_oracledb.ischema_names:
|
|
105
|
+
OracleDialect_oracledb.ischema_names["BOOLEAN"] = sat.BOOLEAN
|
|
106
|
+
|
|
103
107
|
|
|
104
108
|
@dt.dtype.register(OracleDialect_oracledb, sa.dialects.oracle.CLOB)
|
|
105
109
|
def sa_oracle_CLOB(_, satype, nullable=True):
|
|
@@ -160,6 +160,8 @@ def _cast(t, op):
|
|
|
160
160
|
(sa_arg.in_(["1", "Y"]), sa.literal(1)),
|
|
161
161
|
else_=sa.literal_column("TO_NUMBER(NULL)"),
|
|
162
162
|
)
|
|
163
|
+
elif arg_dtype.is_boolean() and typ.is_string():
|
|
164
|
+
return sa.func.lower(sa.func.to_char(sa_arg))
|
|
163
165
|
elif (arg_dtype.is_timestamp() or arg_dtype.is_date()) and typ.is_date():
|
|
164
166
|
# If we are casting to Date then simulate what all other engines
|
|
165
167
|
# understand to be a Date, which is without the time element.
|
|
@@ -352,6 +352,8 @@ def _literal(t, op):
|
|
|
352
352
|
dtype = op.output_dtype
|
|
353
353
|
if dtype.is_string():
|
|
354
354
|
return _string_literal_format(t, op)
|
|
355
|
+
elif dtype.is_time(): # The base backend does not have a renderer for TIME Literals
|
|
356
|
+
return f"TIME '{op.value.isoformat()}'"
|
|
355
357
|
else:
|
|
356
358
|
return ibis_literal(t, op)
|
|
357
359
|
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/client_info.py
RENAMED
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/combiner.py
RENAMED
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/consts.py
RENAMED
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/exceptions.py
RENAMED
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/find_tables.py
RENAMED
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/gcs_helper.py
RENAMED
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/raw_query.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/data_validation/state_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{google_pso_data_validator-8.1.0 → google_pso_data_validator-8.2.0}/third_party/ibis/ibis_db2/api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|