1+ import logging
2+ import typing
3+ import re
4+
5+
6+ from redshift_connector .utils .oids import RedshiftOID
7+ from redshift_connector .utils .sql_types import SQLType
8+
9+ from redshift_connector .error import (
10+ MISSING_MODULE_ERROR_MSG ,
11+ InterfaceError ,
12+ ProgrammingError ,
13+ )
14+
15+ _logger : logging .Logger = logging .getLogger (__name__ )
16+
17+
18+ class MetadataAPIHelper :
19+ def __init__ (self : "MetadataAPIHelper" ) -> None :
20+ self ._CatalogsColNum : int = 1
21+ self ._get_catalogs_col : typing .Dict = {"TABLE_CAT" : int (RedshiftOID .VARCHAR )}
22+
23+ self ._SchemasColNum : int = 2
24+ self ._get_schemas_col : typing .Dict = {"TABLE_SCHEM" : int (RedshiftOID .VARCHAR ),
25+ "TABLE_CATALOG" : int (RedshiftOID .VARCHAR )}
26+
27+ self ._TablesColNum : int = 10
28+ self ._get_tables_col : typing .Dict = {"TABLE_CAT" : int (RedshiftOID .VARCHAR ),
29+ "TABLE_SCHEM" : int (RedshiftOID .VARCHAR ),
30+ "TABLE_NAME" : int (RedshiftOID .VARCHAR ),
31+ "TABLE_TYPE" : int (RedshiftOID .VARCHAR ),
32+ "REMARKS" : int (RedshiftOID .VARCHAR ),
33+ "TYPE_CAT" : int (RedshiftOID .VARCHAR ),
34+ "TYPE_SCHEM" : int (RedshiftOID .VARCHAR ),
35+ "TYPE_NAME" : int (RedshiftOID .VARCHAR ),
36+ "SELF_REFERENCING_COL_NAME" : int (RedshiftOID .VARCHAR ),
37+ "REF_GENERATION" : int (RedshiftOID .VARCHAR )}
38+
39+ self ._ColumnsColNum : int = 24
40+ self ._get_columns_col : typing .Dict = {"TABLE_CAT" : int (RedshiftOID .VARCHAR ),
41+ "TABLE_SCHEM" : int (RedshiftOID .VARCHAR ),
42+ "TABLE_NAME" : int (RedshiftOID .VARCHAR ),
43+ "COLUMN_NAME" : int (RedshiftOID .VARCHAR ),
44+ "DATA_TYPE" : int (RedshiftOID .INTEGER ),
45+ "TYPE_NAME" : int (RedshiftOID .VARCHAR ),
46+ "COLUMN_SIZE" : int (RedshiftOID .INTEGER ),
47+ "BUFFER_LENGTH" : int (RedshiftOID .INTEGER ),
48+ "DECIMAL_DIGITS" : int (RedshiftOID .INTEGER ),
49+ "NUM_PREC_RADIX" : int (RedshiftOID .INTEGER ),
50+ "NULLABLE" : int (RedshiftOID .INTEGER ),
51+ "REMARKS" : int (RedshiftOID .VARCHAR ),
52+ "COLUMN_DEF" : int (RedshiftOID .VARCHAR ),
53+ "SQL_DATA_TYPE" : int (RedshiftOID .INTEGER ),
54+ "SQL_DATETIME_SUB" : int (RedshiftOID .INTEGER ),
55+ "CHAR_OCTET_LENGTH" : int (RedshiftOID .INTEGER ),
56+ "ORDINAL_POSITION" : int (RedshiftOID .INTEGER ),
57+ "IS_NULLABLE" : int (RedshiftOID .VARCHAR ),
58+ "SCOPE_CATALOG" : int (RedshiftOID .VARCHAR ),
59+ "SCOPE_SCHEMA" : int (RedshiftOID .VARCHAR ),
60+ "SCOPE_TABLE" : int (RedshiftOID .VARCHAR ),
61+ "SOURCE_DATA_TYPE" : int (RedshiftOID .SMALLINT ),
62+ "IS_AUTOINCREMENT" : int (RedshiftOID .VARCHAR ),
63+ "IS_GENERATEDCOLUMN" : int (RedshiftOID .VARCHAR )}
64+
65+ self ._SHOW_DATABASES_database_name : str = 'database_name'
66+
67+ self ._SHOW_SCHEMA_database_name : str = 'database_name'
68+ self ._SHOW_SCHEMA_schema_name : str = 'schema_name'
69+
70+ self ._SHOW_TABLES_database_name : str = 'database_name'
71+ self ._SHOW_TABLES_schema_name : str = 'schema_name'
72+ self ._SHOW_TABLES_table_name : str = 'table_name'
73+ self ._SHOW_TABLES_table_type : str = 'table_type'
74+ self ._SHOW_TABLES_remarks : str = 'remarks'
75+
76+ self ._SHOW_COLUMNS_database_name : str = "database_name"
77+ self ._SHOW_COLUMNS_schema_name : str = "schema_name"
78+ self ._SHOW_COLUMNS_table_name : str = "table_name"
79+ self ._SHOW_COLUMNS_column_name : str = "column_name"
80+ self ._SHOW_COLUMNS_ordinal_position : str = "ordinal_position"
81+ self ._SHOW_COLUMNS_column_default : str = "column_default"
82+ self ._SHOW_COLUMNS_is_nullable : str = "is_nullable"
83+ self ._SHOW_COLUMNS_data_type : str = "data_type"
84+ self ._SHOW_COLUMNS_character_maximum_length : str = "character_maximum_length"
85+ self ._SHOW_COLUMNS_numeric_precision : str = "numeric_precision"
86+ self ._SHOW_COLUMNS_numeric_scale : str = "numeric_scale"
87+ self ._SHOW_COLUMNS_remarks : str = "remarks"
88+
89+
90+ self ._sql_show_databases : str = "SHOW DATABASES;"
91+ self ._sql_show_databases_like : str = "SHOW DATABASES LIKE '{0}';"
92+ self ._sql_show_schemas : str = "SHOW SCHEMAS FROM DATABASE {0};"
93+ self ._sql_show_schemas_like : str = "SHOW SCHEMAS FROM DATABASE {0} LIKE '{1}';"
94+ self ._sql_show_tables : str = "SHOW TABLES FROM SCHEMA {0}.{1};"
95+ self ._sql_show_tables_like : str = "SHOW TABLES FROM SCHEMA {0}.{1} LIKE '{2}';"
96+ self ._sql_show_columns : str = "SHOW COLUMNS FROM TABLE {0}.{1}.{2};"
97+ self ._sql_show_columns_like : str = "SHOW COLUMNS FROM TABLE {0}.{1}.{2} LIKE '{3}';"
98+
99+ self .__rs_type_map = {
100+ "character varying" : "varchar" ,
101+ "\" char\" " : "char" ,
102+ "character" : "char" ,
103+ "smallint" : "int2" ,
104+ "integer" : "int4" ,
105+ "bigint" : "int8" ,
106+ "real" : "float4" ,
107+ "double precision" : "float8" ,
108+ "boolean" : "bool" ,
109+ "time without time zone" : "time" ,
110+ "time with time zone" : "timetz" ,
111+ "timestamp without time zone" : "timestamp" ,
112+ "timestamp with time zone" : "timestamptz" ,
113+ "interval year to month" : "intervaly2m" ,
114+ "interval year" : "intervaly2m" ,
115+ "interval month" : "intervaly2m" ,
116+ "interval day to second" : "intervald2s" ,
117+ "interval day" : "intervald2s" ,
118+ "interval second" : "intervald2s" ,
119+ "binary varying" : "varbyte"
120+ }
121+
122+ self .__sql_type_mapping = {
123+ "varchar" : int (SQLType .SQL_VARCHAR ),
124+ "char" : int (SQLType .SQL_CHAR ),
125+ "int2" : int (SQLType .SQL_SMALLINT ),
126+ "int4" : int (SQLType .SQL_INTEGER ),
127+ "int8" : int (SQLType .SQL_BIGINT ),
128+ "float4" : int (SQLType .SQL_REAL ),
129+ "float8" : int (SQLType .SQL_DOUBLE ),
130+ "numeric" : int (SQLType .SQL_NUMERIC ),
131+ "bool" : int (SQLType .SQL_BIT ),
132+ "date" : int (SQLType .SQL_DATE ),
133+ "time" : int (SQLType .SQL_TIME ),
134+ "timetz" : int (SQLType .SQL_TIME_WITH_TIMEZONE ),
135+ "timestamp" : int (SQLType .SQL_TIMESTAMP ),
136+ "timestamptz" : int (SQLType .SQL_TIMESTAMP_WITH_TIMEZONE ),
137+ "intervaly2m" : int (SQLType .SQL_OTHER ),
138+ "intervald2s" : int (SQLType .SQL_OTHER ),
139+ "super" : int (SQLType .SQL_LONGVARCHAR ),
140+ "geometry" : int (SQLType .SQL_LONGVARBINARY ),
141+ "geography" : int (SQLType .SQL_LONGVARBINARY ),
142+ "varbyte" : int (SQLType .SQL_LONGVARBINARY )
143+ }
144+
145+ self .__data_type_length = {
146+ "bool" : 1 ,
147+ "bit" : 1 ,
148+ "boolean" : 1 ,
149+ "int2" : 5 ,
150+ "smallint" : 5 ,
151+ "int4" : 10 ,
152+ "integer" : 10 ,
153+ "int" : 10 ,
154+ "int8" : 19 ,
155+ "bigint" : 19 ,
156+ "float4" : 8 ,
157+ "real" : 8 ,
158+ "float8" : 17 ,
159+ "double precision" : 17 ,
160+ "date" : 13 ,
161+ "time" : 15 ,
162+ "timetz" : 21 ,
163+ "timestamp" : 29 ,
164+ "timestamptz" : 35 ,
165+ "intervaly2m" : 32 ,
166+ "intervald2s" : 64
167+ }
168+
169+ def get_second_fraction (self , data_type : str = None ) -> (str , bool ):
170+ date_time_customize_precision : bool = False
171+ precisions : int = 6
172+ if re .match (r"(time|timetz|timestamp|timestamptz).*\(\d+\)" , data_type ) or re .match (r"interval.*\(\d+\)" , data_type ):
173+ rs_type = self .get_rs_type (str (re .sub (r"\(\d+\)" , "" , data_type ).rstrip ()))
174+ precisions = int (re .search (r"\(\d+\)" , data_type ).group (0 )[1 :- 1 ])
175+ date_time_customize_precision = True
176+ else :
177+ rs_type = self .get_rs_type (data_type )
178+
179+ return rs_type , date_time_customize_precision , precisions
180+
181+ def get_rs_type (self , rs_type : str ) -> str :
182+ return self .__rs_type_map .get (rs_type , rs_type )
183+
184+ def get_sql_type (self ,rs_type : str ) -> int :
185+ return self .__sql_type_mapping .get (rs_type , int (SQLType .SQL_OTHER ))
186+
187+
188+ def get_column_size (self , rs_type : str , numeric_precision : int , character_maximum_length : int ) -> int :
189+ if rs_type == "numeric" or rs_type == "decimal" :
190+ return int (numeric_precision )
191+ elif rs_type == "varchar" or rs_type == "character varying" or rs_type == "char" or rs_type == "character" or rs_type == "bpchar" :
192+ return int (character_maximum_length )
193+ elif rs_type == "super" or rs_type == "geometry" or rs_type == "geography" or rs_type == "varbyte" :
194+ return None
195+ else :
196+ return self .__data_type_length .get (rs_type , 2147483647 )
197+
198+ @staticmethod
199+ def get_decimal_digits (rs_type : str , numeric_scale : int , precision : int , customizePrecision : bool ) -> int :
200+ if rs_type == "float4" or rs_type == "real" :
201+ return 8
202+ elif rs_type == "float8" or rs_type == "double precision" :
203+ return 17
204+ elif rs_type == "numeric" or rs_type == "decimal" :
205+ return int (numeric_scale )
206+ elif rs_type == "time" or rs_type == "timetz" or rs_type == "timestamp" or rs_type == "timestamptz" or rs_type == "intervald2s" :
207+ return precision if customizePrecision else 6
208+ elif rs_type == "super" or rs_type == "geometry" or rs_type == "geography" or rs_type == "varbyte" :
209+ return None
210+ else :
211+ return 0
212+
213+ @staticmethod
214+ def get_num_prefix_radix (rs_type : str ) -> int :
215+ if rs_type == "geography" or rs_type == "varbyte" :
216+ return 2
217+ else :
218+ return 10
219+
220+ @staticmethod
221+ def get_nullable (nullable : str ) -> int :
222+ if nullable == "YES" :
223+ return 1
224+ elif nullable == "NO" :
225+ return 0
226+ else :
227+ return 2
228+
229+ @staticmethod
230+ def get_auto_increment (col_def : str ) -> str :
231+ if col_def is not None and ("\" identity\" " in col_def or "default_identity" in col_def ):
232+ return "YES"
233+ else :
234+ return "NO"
235+
236+ @staticmethod
237+ def check_name_is_not_pattern (name : str ) -> bool :
238+ return name is None or not name or name == "%"
239+
240+ @staticmethod
241+ def check_name_is_exact_name (name : str ) -> bool :
242+ if name is not None and len (name ) != 0 and ("%" not in name ):
243+ return True
244+ return False
0 commit comments