001package gudusoft.gsqlparser.sqlenv; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.nodes.TObjectName; 005import gudusoft.gsqlparser.nodes.TTypeName; 006import gudusoft.gsqlparser.sqlenv.calcite.CatalogStore; 007import gudusoft.gsqlparser.sqlenv.calcite.NameService; 008import gudusoft.gsqlparser.sqlenv.catalog.ICatalogProvider; 009import gudusoft.gsqlparser.sqlenv.catalog.CatalogStoreProvider; 010import gudusoft.gsqlparser.util.SQLUtil; 011 012import java.util.ArrayList; 013import java.util.EnumMap; 014import java.util.HashMap; 015import java.util.List; 016import java.util.Map; 017import java.util.concurrent.ConcurrentHashMap; 018import java.util.concurrent.CopyOnWriteArrayList; 019 020import static gudusoft.gsqlparser.sqlenv.ESQLDataObjectType.*; 021 022/** 023 * SQL environment includes the metadata of a list of databases. The typical scenario is there is one database includes 024 * some schemas, and each schema includes some tables, views, procedures and etc. 025 * <br> 026 * <br>Database known as catalog in ANSI SQL. 027 * <br>Each catalog including a list of schemas. 028 * <br>Each schema including a list of schema objects such as table, procedure, function, trigger and more. 029 * <br> 030 * Implement your own concrete class derived from this class to get the metadata from a real database. 031 * Usually, this is done by querying the INFORMATION_SCHEMA in the {@link #initSQLEnv()} method which should be override 032 * in your own class. 033 * <br><br> 034 * 035 */ 036public abstract class TSQLEnv { 037 038 public static final Map<EDbVendor, Boolean> columnCollationCaseSensitive; 039 040 static { 041 columnCollationCaseSensitive = new EnumMap<>(EDbVendor.class); 042 columnCollationCaseSensitive.put(EDbVendor.dbvaccess, false); 043 columnCollationCaseSensitive.put(EDbVendor.dbvansi, false); 044 columnCollationCaseSensitive.put(EDbVendor.dbvathena, false); 045 columnCollationCaseSensitive.put(EDbVendor.dbvazuresql, false); 046 columnCollationCaseSensitive.put(EDbVendor.dbvbigquery, false); 047 columnCollationCaseSensitive.put(EDbVendor.dbvclickhouse, false); 048 columnCollationCaseSensitive.put(EDbVendor.dbvcouchbase, false); 049 columnCollationCaseSensitive.put(EDbVendor.dbvdax, false); 050 columnCollationCaseSensitive.put(EDbVendor.dbvdb2, false); 051 columnCollationCaseSensitive.put(EDbVendor.dbvexasol, false); 052 columnCollationCaseSensitive.put(EDbVendor.dbvfirebird, false); 053 columnCollationCaseSensitive.put(EDbVendor.dbvgeneric, false); 054 columnCollationCaseSensitive.put(EDbVendor.dbvgreenplum, false); 055 columnCollationCaseSensitive.put(EDbVendor.dbvhana, false); 056 columnCollationCaseSensitive.put(EDbVendor.dbvhive, false); 057 columnCollationCaseSensitive.put(EDbVendor.dbvimpala, false); 058 columnCollationCaseSensitive.put(EDbVendor.dbvinformix, false); 059 columnCollationCaseSensitive.put(EDbVendor.dbvmdx, false); 060 columnCollationCaseSensitive.put(EDbVendor.dbvmysql, false); 061 columnCollationCaseSensitive.put(EDbVendor.dbvmssql, false); 062 columnCollationCaseSensitive.put(EDbVendor.dbvnetezza, false); 063 columnCollationCaseSensitive.put(EDbVendor.dbvodbc, false); 064 columnCollationCaseSensitive.put(EDbVendor.dbvopenedge, false); 065 columnCollationCaseSensitive.put(EDbVendor.dbvoracle, true); 066 columnCollationCaseSensitive.put(EDbVendor.dbvpostgresql, false); 067 columnCollationCaseSensitive.put(EDbVendor.dbvpresto, false); 068 columnCollationCaseSensitive.put(EDbVendor.dbvredshift, false); 069 columnCollationCaseSensitive.put(EDbVendor.dbvsnowflake, false); 070 columnCollationCaseSensitive.put(EDbVendor.dbvsoql, false); 071 columnCollationCaseSensitive.put(EDbVendor.dbvsparksql, false); 072 columnCollationCaseSensitive.put(EDbVendor.dbvsybase, false); 073 columnCollationCaseSensitive.put(EDbVendor.dbvteradata, false); 074 columnCollationCaseSensitive.put(EDbVendor.dbvtrino, false); 075 columnCollationCaseSensitive.put(EDbVendor.dbvvertica, false); 076 columnCollationCaseSensitive.put(EDbVendor.dbvdatabricks, false); 077 columnCollationCaseSensitive.put(EDbVendor.dbvgaussdb, false); 078 079 // Compile-time check to ensure all enum values are covered 080 if (columnCollationCaseSensitive.size() != EDbVendor.values().length) { 081 throw new IllegalStateException("columnCollationCaseSensitive map must contain all EDbVendor values"); 082 } 083 } 084 085 public static final Map<EDbVendor, Boolean> functionCollationCaseSensitive; 086 087 static { 088 functionCollationCaseSensitive = new EnumMap<>(EDbVendor.class); 089 functionCollationCaseSensitive.put(EDbVendor.dbvaccess, false); 090 functionCollationCaseSensitive.put(EDbVendor.dbvansi, false); 091 functionCollationCaseSensitive.put(EDbVendor.dbvathena, false); 092 functionCollationCaseSensitive.put(EDbVendor.dbvazuresql, false); 093 functionCollationCaseSensitive.put(EDbVendor.dbvbigquery, false); 094 functionCollationCaseSensitive.put(EDbVendor.dbvclickhouse, false); 095 functionCollationCaseSensitive.put(EDbVendor.dbvcouchbase, false); 096 functionCollationCaseSensitive.put(EDbVendor.dbvdax, false); 097 functionCollationCaseSensitive.put(EDbVendor.dbvdb2, false); 098 functionCollationCaseSensitive.put(EDbVendor.dbvexasol, false); 099 functionCollationCaseSensitive.put(EDbVendor.dbvfirebird, false); 100 functionCollationCaseSensitive.put(EDbVendor.dbvgeneric, false); 101 functionCollationCaseSensitive.put(EDbVendor.dbvgreenplum, false); 102 functionCollationCaseSensitive.put(EDbVendor.dbvhana, false); 103 functionCollationCaseSensitive.put(EDbVendor.dbvhive, false); 104 functionCollationCaseSensitive.put(EDbVendor.dbvimpala, false); 105 functionCollationCaseSensitive.put(EDbVendor.dbvinformix, false); 106 functionCollationCaseSensitive.put(EDbVendor.dbvmdx, false); 107 functionCollationCaseSensitive.put(EDbVendor.dbvmysql, false); 108 functionCollationCaseSensitive.put(EDbVendor.dbvmssql, false); 109 functionCollationCaseSensitive.put(EDbVendor.dbvnetezza, false); 110 functionCollationCaseSensitive.put(EDbVendor.dbvodbc, false); 111 functionCollationCaseSensitive.put(EDbVendor.dbvopenedge, false); 112 functionCollationCaseSensitive.put(EDbVendor.dbvoracle, true); 113 functionCollationCaseSensitive.put(EDbVendor.dbvpostgresql, true); 114 functionCollationCaseSensitive.put(EDbVendor.dbvpresto, false); 115 functionCollationCaseSensitive.put(EDbVendor.dbvredshift, false); 116 functionCollationCaseSensitive.put(EDbVendor.dbvsnowflake, false); 117 functionCollationCaseSensitive.put(EDbVendor.dbvsoql, false); 118 functionCollationCaseSensitive.put(EDbVendor.dbvsparksql, false); 119 functionCollationCaseSensitive.put(EDbVendor.dbvsybase, false); 120 functionCollationCaseSensitive.put(EDbVendor.dbvteradata, false); 121 functionCollationCaseSensitive.put(EDbVendor.dbvtrino, false); 122 functionCollationCaseSensitive.put(EDbVendor.dbvvertica, false); 123 functionCollationCaseSensitive.put(EDbVendor.dbvdatabricks, false); 124 functionCollationCaseSensitive.put(EDbVendor.dbvgaussdb, false); 125 126 // Compile-time check to ensure all enum values are covered 127 if (functionCollationCaseSensitive.size() != EDbVendor.values().length) { 128 throw new IllegalStateException("functionCollationCaseSensitive map must contain all EDbVendor values"); 129 } 130 } 131 public static final Map<EDbVendor, Boolean> tableCollationCaseSensitive; 132 133 static { 134 tableCollationCaseSensitive = new EnumMap<>(EDbVendor.class); 135 tableCollationCaseSensitive.put(EDbVendor.dbvaccess, false); 136 tableCollationCaseSensitive.put(EDbVendor.dbvansi, false); 137 tableCollationCaseSensitive.put(EDbVendor.dbvathena, false); 138 tableCollationCaseSensitive.put(EDbVendor.dbvazuresql, false); 139 tableCollationCaseSensitive.put(EDbVendor.dbvbigquery, false); 140 tableCollationCaseSensitive.put(EDbVendor.dbvclickhouse, false); 141 tableCollationCaseSensitive.put(EDbVendor.dbvcouchbase, false); 142 tableCollationCaseSensitive.put(EDbVendor.dbvdax, false); 143 tableCollationCaseSensitive.put(EDbVendor.dbvdb2, true); 144 tableCollationCaseSensitive.put(EDbVendor.dbvexasol, false); 145 tableCollationCaseSensitive.put(EDbVendor.dbvfirebird, false); 146 tableCollationCaseSensitive.put(EDbVendor.dbvgeneric, false); 147 tableCollationCaseSensitive.put(EDbVendor.dbvgreenplum, false); 148 tableCollationCaseSensitive.put(EDbVendor.dbvhana, false); 149 tableCollationCaseSensitive.put(EDbVendor.dbvhive, false); 150 tableCollationCaseSensitive.put(EDbVendor.dbvimpala, false); 151 tableCollationCaseSensitive.put(EDbVendor.dbvinformix, false); 152 tableCollationCaseSensitive.put(EDbVendor.dbvmdx, false); 153 tableCollationCaseSensitive.put(EDbVendor.dbvmysql, false); 154 tableCollationCaseSensitive.put(EDbVendor.dbvmssql, false); 155 tableCollationCaseSensitive.put(EDbVendor.dbvnetezza, false); 156 tableCollationCaseSensitive.put(EDbVendor.dbvodbc, false); 157 tableCollationCaseSensitive.put(EDbVendor.dbvopenedge, false); 158 tableCollationCaseSensitive.put(EDbVendor.dbvoracle, true); 159 tableCollationCaseSensitive.put(EDbVendor.dbvpostgresql, true); 160 tableCollationCaseSensitive.put(EDbVendor.dbvpresto, false); 161 tableCollationCaseSensitive.put(EDbVendor.dbvredshift, false); 162 tableCollationCaseSensitive.put(EDbVendor.dbvsnowflake, false); 163 tableCollationCaseSensitive.put(EDbVendor.dbvsoql, false); 164 tableCollationCaseSensitive.put(EDbVendor.dbvsparksql, false); 165 tableCollationCaseSensitive.put(EDbVendor.dbvsybase, false); 166 tableCollationCaseSensitive.put(EDbVendor.dbvteradata, false); 167 tableCollationCaseSensitive.put(EDbVendor.dbvtrino, false); 168 tableCollationCaseSensitive.put(EDbVendor.dbvvertica, false); 169 tableCollationCaseSensitive.put(EDbVendor.dbvdatabricks, false); 170 tableCollationCaseSensitive.put(EDbVendor.dbvgaussdb, false); 171 172 // Compile-time check to ensure all enum values are covered 173 if (tableCollationCaseSensitive.size() != EDbVendor.values().length) { 174 throw new IllegalStateException("tableCollationCaseSensitive map must contain all EDbVendor values"); 175 } 176 } 177 178 public static final Map<EDbVendor, Boolean> catalogCollationCaseSensitive; 179 180 static { 181 catalogCollationCaseSensitive = new EnumMap<>(EDbVendor.class); 182 catalogCollationCaseSensitive.put(EDbVendor.dbvaccess, false); 183 catalogCollationCaseSensitive.put(EDbVendor.dbvansi, false); 184 catalogCollationCaseSensitive.put(EDbVendor.dbvathena, false); 185 catalogCollationCaseSensitive.put(EDbVendor.dbvazuresql, false); 186 catalogCollationCaseSensitive.put(EDbVendor.dbvbigquery, false); 187 catalogCollationCaseSensitive.put(EDbVendor.dbvclickhouse, false); 188 catalogCollationCaseSensitive.put(EDbVendor.dbvcouchbase, false); 189 catalogCollationCaseSensitive.put(EDbVendor.dbvdax, false); 190 catalogCollationCaseSensitive.put(EDbVendor.dbvdb2, true); 191 catalogCollationCaseSensitive.put(EDbVendor.dbvexasol, false); 192 catalogCollationCaseSensitive.put(EDbVendor.dbvfirebird, false); 193 catalogCollationCaseSensitive.put(EDbVendor.dbvgeneric, false); 194 catalogCollationCaseSensitive.put(EDbVendor.dbvgreenplum, false); 195 catalogCollationCaseSensitive.put(EDbVendor.dbvhana, false); 196 catalogCollationCaseSensitive.put(EDbVendor.dbvhive, false); 197 catalogCollationCaseSensitive.put(EDbVendor.dbvimpala, false); 198 catalogCollationCaseSensitive.put(EDbVendor.dbvinformix, false); 199 catalogCollationCaseSensitive.put(EDbVendor.dbvmdx, false); 200 catalogCollationCaseSensitive.put(EDbVendor.dbvmysql, true); 201 catalogCollationCaseSensitive.put(EDbVendor.dbvmssql, false); 202 catalogCollationCaseSensitive.put(EDbVendor.dbvnetezza, false); 203 catalogCollationCaseSensitive.put(EDbVendor.dbvodbc, false); 204 catalogCollationCaseSensitive.put(EDbVendor.dbvopenedge, false); 205 catalogCollationCaseSensitive.put(EDbVendor.dbvoracle, false); 206 catalogCollationCaseSensitive.put(EDbVendor.dbvpostgresql, true); 207 catalogCollationCaseSensitive.put(EDbVendor.dbvpresto, false); 208 catalogCollationCaseSensitive.put(EDbVendor.dbvredshift, false); 209 catalogCollationCaseSensitive.put(EDbVendor.dbvsnowflake, false); 210 catalogCollationCaseSensitive.put(EDbVendor.dbvsoql, false); 211 catalogCollationCaseSensitive.put(EDbVendor.dbvsparksql, false); 212 catalogCollationCaseSensitive.put(EDbVendor.dbvsybase, false); 213 catalogCollationCaseSensitive.put(EDbVendor.dbvteradata, false); 214 catalogCollationCaseSensitive.put(EDbVendor.dbvtrino, false); 215 catalogCollationCaseSensitive.put(EDbVendor.dbvvertica, false); 216 catalogCollationCaseSensitive.put(EDbVendor.dbvdatabricks, false); 217 catalogCollationCaseSensitive.put(EDbVendor.dbvgaussdb, false); 218 219 // Compile-time check to ensure all enum values are covered 220 if (catalogCollationCaseSensitive.size() != EDbVendor.values().length) { 221 throw new IllegalStateException("catalogCollationCaseSensitive map must contain all EDbVendor values"); 222 } 223 } 224 225 public static final Map<EDbVendor, Boolean> defaultCollationCaseSensitive; 226 227 static { 228 defaultCollationCaseSensitive = new EnumMap<>(EDbVendor.class); 229 defaultCollationCaseSensitive.put(EDbVendor.dbvaccess, false); 230 defaultCollationCaseSensitive.put(EDbVendor.dbvansi, false); 231 defaultCollationCaseSensitive.put(EDbVendor.dbvathena, false); 232 defaultCollationCaseSensitive.put(EDbVendor.dbvazuresql, false); 233 defaultCollationCaseSensitive.put(EDbVendor.dbvbigquery, false); 234 defaultCollationCaseSensitive.put(EDbVendor.dbvclickhouse, false); 235 defaultCollationCaseSensitive.put(EDbVendor.dbvcouchbase, false); 236 defaultCollationCaseSensitive.put(EDbVendor.dbvdax, false); 237 defaultCollationCaseSensitive.put(EDbVendor.dbvdb2, false); 238 defaultCollationCaseSensitive.put(EDbVendor.dbvexasol, false); 239 defaultCollationCaseSensitive.put(EDbVendor.dbvfirebird, false); 240 defaultCollationCaseSensitive.put(EDbVendor.dbvgeneric, false); 241 defaultCollationCaseSensitive.put(EDbVendor.dbvgreenplum, false); 242 defaultCollationCaseSensitive.put(EDbVendor.dbvhana, false); 243 defaultCollationCaseSensitive.put(EDbVendor.dbvhive, false); 244 defaultCollationCaseSensitive.put(EDbVendor.dbvimpala, false); 245 defaultCollationCaseSensitive.put(EDbVendor.dbvinformix, false); 246 defaultCollationCaseSensitive.put(EDbVendor.dbvmdx, false); 247 defaultCollationCaseSensitive.put(EDbVendor.dbvmysql, false); 248 defaultCollationCaseSensitive.put(EDbVendor.dbvmssql, false); 249 defaultCollationCaseSensitive.put(EDbVendor.dbvnetezza, false); 250 defaultCollationCaseSensitive.put(EDbVendor.dbvodbc, false); 251 defaultCollationCaseSensitive.put(EDbVendor.dbvopenedge, false); 252 defaultCollationCaseSensitive.put(EDbVendor.dbvoracle, false); 253 defaultCollationCaseSensitive.put(EDbVendor.dbvpostgresql, false); 254 defaultCollationCaseSensitive.put(EDbVendor.dbvpresto, false); 255 defaultCollationCaseSensitive.put(EDbVendor.dbvredshift, false); 256 defaultCollationCaseSensitive.put(EDbVendor.dbvsnowflake, false); 257 defaultCollationCaseSensitive.put(EDbVendor.dbvsoql, false); 258 defaultCollationCaseSensitive.put(EDbVendor.dbvsparksql, false); 259 defaultCollationCaseSensitive.put(EDbVendor.dbvsybase, false); 260 defaultCollationCaseSensitive.put(EDbVendor.dbvteradata, false); 261 defaultCollationCaseSensitive.put(EDbVendor.dbvtrino, false); 262 defaultCollationCaseSensitive.put(EDbVendor.dbvvertica, false); 263 defaultCollationCaseSensitive.put(EDbVendor.dbvdatabricks, false); 264 defaultCollationCaseSensitive.put(EDbVendor.dbvgaussdb, false); 265 266 // Compile-time check to ensure all enum values are covered 267 if (defaultCollationCaseSensitive.size() != EDbVendor.values().length) { 268 throw new IllegalStateException("defaultCollationCaseSensitive map must contain all EDbVendor values"); 269 } 270 } 271 272 273 274 public static final Map<EDbVendor, Boolean> isAliasReferenceForbidden; 275 276 static { 277 isAliasReferenceForbidden = new EnumMap<>(EDbVendor.class); 278 isAliasReferenceForbidden.put(EDbVendor.dbvaccess, false); 279 isAliasReferenceForbidden.put(EDbVendor.dbvansi, false); 280 isAliasReferenceForbidden.put(EDbVendor.dbvathena, false); 281 isAliasReferenceForbidden.put(EDbVendor.dbvazuresql, true); 282 isAliasReferenceForbidden.put(EDbVendor.dbvbigquery, true); 283 isAliasReferenceForbidden.put(EDbVendor.dbvclickhouse, false); 284 isAliasReferenceForbidden.put(EDbVendor.dbvcouchbase, false); 285 isAliasReferenceForbidden.put(EDbVendor.dbvdax, false); 286 isAliasReferenceForbidden.put(EDbVendor.dbvdb2, true); 287 isAliasReferenceForbidden.put(EDbVendor.dbvexasol, false); // Exasol disallows forward references 288 isAliasReferenceForbidden.put(EDbVendor.dbvfirebird, false); // Firebird follows standard SQL behavior 289 isAliasReferenceForbidden.put(EDbVendor.dbvgeneric, false); 290 isAliasReferenceForbidden.put(EDbVendor.dbvgreenplum, true); 291 isAliasReferenceForbidden.put(EDbVendor.dbvhana, false); // SAP HANA follows standard SQL behavior 292 isAliasReferenceForbidden.put(EDbVendor.dbvhive, true); 293 isAliasReferenceForbidden.put(EDbVendor.dbvimpala, false); // Impala follows Hive's behavior 294 isAliasReferenceForbidden.put(EDbVendor.dbvinformix, true); 295 isAliasReferenceForbidden.put(EDbVendor.dbvmdx, false); 296 isAliasReferenceForbidden.put(EDbVendor.dbvmysql, true); 297 isAliasReferenceForbidden.put(EDbVendor.dbvmssql, true); 298 isAliasReferenceForbidden.put(EDbVendor.dbvnetezza, true); 299 isAliasReferenceForbidden.put(EDbVendor.dbvodbc, false); 300 isAliasReferenceForbidden.put(EDbVendor.dbvopenedge, false); 301 isAliasReferenceForbidden.put(EDbVendor.dbvoracle, true); 302 isAliasReferenceForbidden.put(EDbVendor.dbvpostgresql, true); 303 isAliasReferenceForbidden.put(EDbVendor.dbvpresto, true); 304 isAliasReferenceForbidden.put(EDbVendor.dbvredshift, true); 305 isAliasReferenceForbidden.put(EDbVendor.dbvsnowflake, false); // Snowflake disallows column alias references 306 isAliasReferenceForbidden.put(EDbVendor.dbvsoql, false); 307 isAliasReferenceForbidden.put(EDbVendor.dbvsparksql, true); 308 isAliasReferenceForbidden.put(EDbVendor.dbvsybase, true); 309 isAliasReferenceForbidden.put(EDbVendor.dbvteradata, false); // Teradata follows standard SQL behavior 310 isAliasReferenceForbidden.put(EDbVendor.dbvtrino, true); 311 isAliasReferenceForbidden.put(EDbVendor.dbvvertica, false); // Vertica disallows forward references 312 isAliasReferenceForbidden.put(EDbVendor.dbvdatabricks, true); 313 isAliasReferenceForbidden.put(EDbVendor.dbvgaussdb, true); 314 315 // Compile-time check to ensure all enum values are covered 316 if (isAliasReferenceForbidden.size() != EDbVendor.values().length) { 317 throw new IllegalStateException("isAliasReferenceForbidden map must contain all EDbVendor values"); 318 } 319 } 320 321 public static String getStmtSeparatorChar(EDbVendor dbVendor){ 322 String ret = ";"; 323 switch (dbVendor){ 324 case dbvoracle: 325 case dbvteradata: 326 case dbvpostgresql: 327 case dbvredshift: 328 case dbvgreenplum: 329 ret = "/"; 330 break; 331 case dbvdb2: 332 ret = "@"; 333 break; 334 case dbvmysql: 335 ret = "$"; 336 break; 337 default: 338 break; 339 } 340 return ret; 341 } 342 343 344 /** 345 * Whether this database support schema or not? 346 * 347 * @param dbVendor 348 * @return 349 */ 350 public static boolean supportSchema(EDbVendor dbVendor){ 351 return (!((dbVendor == EDbVendor.dbvmysql) 352 ||(dbVendor == EDbVendor.dbvteradata)||(dbVendor == EDbVendor.dbvhive)||(dbVendor == EDbVendor.dbvimpala) 353 )); 354 } 355 356 /** 357 * Whether this database support catalog or not? 358 * 359 * @param dbVendor 360 * @return 361 */ 362 public static boolean supportCatalog(EDbVendor dbVendor) { 363// return (!((dbVendor == EDbVendor.dbvoracle) 364// )); 365 return true; 366 } 367 368 /** 369 * used to delimit a database identifier, such as [ used in SQL Server, ` used in MySQL 370 * 371 * @param dbVendor 372 * @return 373 */ 374 public static String delimitedChar(EDbVendor dbVendor){ 375 String ret = "\""; 376 switch (dbVendor){ 377 case dbvmssql: 378 case dbvazuresql: 379 ret = "["; 380 break; 381 case dbvathena: 382 case dbvmysql: 383 case dbvbigquery: 384 case dbvcouchbase: 385 case dbvhive: 386 case dbvimpala: 387 case dbvdatabricks: 388 ret = "`"; 389 break; 390 case dbvdax: 391 ret = "'"; 392 break; 393 default: 394 break; 395 } 396 return ret; 397 } 398 399 public static boolean isDelimitedIdentifier(EDbVendor dbVendor, String identifier){ 400 boolean ret = false; 401 switch (dbVendor){ 402 case dbvmssql: 403 case dbvazuresql: 404 ret = identifier.startsWith("[")||identifier.startsWith("\"")||identifier.startsWith("'"); 405 break; 406 case dbvmysql: 407 case dbvbigquery: 408 case dbvcouchbase: 409 case dbvhive: 410 case dbvimpala: 411 ret = identifier.startsWith("`"); 412 break; 413 case dbvdax: 414 ret = identifier.startsWith("'"); 415 break; 416 default: 417 ret = identifier.startsWith("\""); 418 break; 419 } 420 return ret; 421 } 422 423 public static boolean endsWithDelimitedIdentifier(EDbVendor dbVendor, String identifier){ 424 boolean ret = false; 425 switch (dbVendor){ 426 case dbvmssql: 427 case dbvazuresql: 428 ret = identifier.endsWith("]")||identifier.endsWith("\""); 429 break; 430 case dbvmysql: 431 case dbvbigquery: 432 case dbvcouchbase: 433 case dbvhive: 434 case dbvimpala: 435 ret = identifier.endsWith("`"); 436 break; 437 case dbvdax: 438 ret = identifier.endsWith("'"); 439 break; 440 default: 441 ret = identifier.endsWith("\""); 442 break; 443 } 444 return ret; 445 } 446 447 public boolean isDelimitedIdentifier(String identifier){ 448 return TSQLEnv.isDelimitedIdentifier(this.getDBVendor(),identifier); 449 } 450 451 452 public boolean compareColumn(String ident1, String ident2){ 453 // Phase 2: Route through Calcite NameService when flag is enabled 454 if (TBaseType.USE_CALCITE_MATCHER) { 455 return nameService.equals(ESQLDataObjectType.dotColumn, ident1, ident2); 456 } 457 return compareIdentifier(this.getDBVendor(),ESQLDataObjectType.dotColumn,ident1,ident2); 458 } 459 460 public boolean compareTable(String ident1, String ident2){ 461 // Phase 2: Route through Calcite NameService when flag is enabled 462 if (TBaseType.USE_CALCITE_MATCHER) { 463 return nameService.equals(ESQLDataObjectType.dotTable, ident1, ident2); 464 } 465 return compareIdentifier(this.getDBVendor(),ESQLDataObjectType.dotTable,ident1,ident2); 466 } 467 468 public boolean compareIdentifier(ESQLDataObjectType objectType, String ident1, String ident2){ 469 // Phase 2: Route through Calcite NameService when flag is enabled 470 if (TBaseType.USE_CALCITE_MATCHER) { 471 return nameService.equals(objectType, ident1, ident2); 472 } 473 474 // Legacy path: use existing logic 475 switch (objectType){ 476 case dotTable: 477 return compareTable(ident1,ident2); 478 case dotColumn: 479 return compareColumn(ident1,ident2); 480 default: 481 return compareIdentifier(this.getDBVendor(),objectType,ident1,ident2); 482 } 483 } 484 485 public static boolean compareColumn( EDbVendor dbVendor, TObjectName sourceColumn, TObjectName targetColumn){ 486 return compareQualifiedColumn(dbVendor,sourceColumn.getColumnNameOnly(),targetColumn.getColumnNameOnly(), 487 sourceColumn.getTableString(),targetColumn.getTableString(), 488 sourceColumn.getSchemaString(),targetColumn.getSchemaString(), 489 sourceColumn.getDatabaseString(),targetColumn.getDatabaseString()); 490 } 491 492 public static boolean compareTable( EDbVendor dbVendor, TObjectName sourceTable, TObjectName targetTable){ 493 return compareQualifiedTable(dbVendor, 494 sourceTable.getTableString(),targetTable.getTableString(), 495 sourceTable.getSchemaString(),targetTable.getSchemaString(), 496 sourceTable.getDatabaseString(),targetTable.getDatabaseString() 497 ); 498 } 499 500 public static boolean compareQualifiedTable( EDbVendor dbVendor, String sourceTable, String targetTable, String sourceSchema, String targetSchema, String sourceDatabase, String targetDatabase){ 501 boolean ret = compareIdentifier(dbVendor,dotTable,sourceTable,targetTable); 502 if (!ret) return ret; 503 504 // compare schema 505 ret = compareIdentifier(dbVendor,dotSchema,sourceSchema,targetSchema); 506 if (!ret) return ret; 507 508 // compare database 509 return compareIdentifier(dbVendor,dotCatalog,sourceDatabase,targetDatabase); 510 } 511 512 public static boolean compareQualifiedColumn( EDbVendor dbVendor, String sourceColumn, String targetColumn, String sourceTable, String targetTable, String sourceSchema, String targetSchema, String sourceDatabase, String targetDatabase){ 513 514 boolean ret = compareIdentifier(dbVendor,dotColumn,sourceColumn,targetColumn); 515 if (!ret) return ret; 516 517 return compareQualifiedTable(dbVendor,sourceTable,targetTable,sourceSchema,targetSchema,sourceDatabase,targetDatabase); 518 } 519 520 public static boolean compareIdentifier( EDbVendor dbVendor, ESQLDataObjectType objectType, TObjectName source, TObjectName target){ 521 return compareIdentifier(dbVendor,objectType,source.toString(),target.toString()); 522 } 523 524 public static boolean compareIdentifier( EDbVendor dbVendor, ESQLDataObjectType objectType, String ident1, String ident2){ 525 526// ident1 = IdentifierService.normalizeStatic(dbVendor,objectType,ident1); 527// ident2 = IdentifierService.normalizeStatic(dbVendor,objectType,ident1); 528// 529// return IdentifierService.areEqualStatic(dbVendor,objectType,ident1,ident2); 530 531 ident1 = normalizeIdentifier(dbVendor,objectType,ident1); // IdentifierService.normalizeStatic(dbVendor,objectType,ident1); 532 ident2 = normalizeIdentifier(dbVendor,objectType,ident2); // IdentifierService.normalizeStatic(dbVendor,objectType,ident1); 533 534 boolean collationSensitive = false; 535 switch (objectType){ 536 case dotCatalog: 537 case dotSchema: 538 collationSensitive = catalogCollationCaseSensitive.get(dbVendor); 539 break; 540 case dotOraclePackage: 541 case dotProcedure: 542 case dotTrigger: 543 case dotTable: 544 collationSensitive = tableCollationCaseSensitive.get(dbVendor); 545 break; 546 case dotFunction: 547 collationSensitive = functionCollationCaseSensitive.get(dbVendor); 548 break; 549 case dotColumn: 550 collationSensitive = columnCollationCaseSensitive.get(dbVendor); 551 break; 552 case dotDblink: // oracle dblink 553 collationSensitive = false; 554 break; 555 default: 556 collationSensitive = defaultCollationCaseSensitive.get(dbVendor); 557 break; 558 } 559 560 if (collationSensitive) { 561 return ident1.equals(ident2); 562 } else { 563 return ident1.equalsIgnoreCase(ident2); 564 } 565 566 } 567 568 public String normalizeIdentifier(ESQLDataObjectType sqlDataObjectType, String identifier) { 569 return this.getIdentifierService().normalize(identifier,sqlDataObjectType); 570 } 571 572 /** 573 * 1. remove delimited char if it's delimited/quoted identifier 574 * 2. change the case of the name in the same way as it saved to the information_schema 575 * 576 * @param dbVendor 577 * @param sqlDataObjectType 578 * @param identifier 579 * @return 580 */ 581 public static String normalizeIdentifier(EDbVendor dbVendor, ESQLDataObjectType sqlDataObjectType, String identifier){ 582 String ret; 583 584 if (identifier == null) return identifier; 585 if (identifier.length() == 0) return identifier; 586 587 if (TSQLEnv.isDelimitedIdentifier(dbVendor,identifier)){ 588 ret = TBaseType.getTextWithoutQuoted(identifier); 589 }else { 590 switch (dbVendor){ 591 case dbvdb2: 592 case dbvoracle: 593 ret = identifier.toUpperCase(); 594 break; 595 case dbvpostgresql: 596 case dbvgreenplum: 597 case dbvredshift: 598 ret = identifier.toLowerCase(); 599 break; 600 default: 601 ret = identifier; 602 break; 603 } 604 } 605 return ret; 606 } 607 608 /** 609 * 比较 一个数据库对象名是否等于或者属于另一个对象 610 * 等于 就是完全相等(根据不同数据库的比较规则) 611 * 属于 表示如下情况: 612 * 1. column1 -> 属于 -> table1.column1 613 * 2. table1 -> 属于 -> db1.schema1.table1 614 * 3. `schema1.table1` -> 属于 -> `db1`.`schema1`.`table1` 615 * 4. `schema1.table1` -> 不属于 -> `db1`.`schema2`.`table1` 616 * 617 * @param sub 618 * @param whole 619 * @return 620 */ 621 public static boolean matchSubObjectNameToWhole(EDbVendor dbVendor, ESQLDataObjectType sqlDataObjectType,String sub, String whole){ 622 List<String> subParts = SQLUtil.parseNames(sub); 623 // `data.RETAIL_PROD_EXCEPTIONS_SOURCE` 没有被分开,需要去掉 `` 后再次拆分 624 if ((subParts.size() == 1)&&(sub.indexOf(".") != -1)){ 625 subParts = SQLUtil.parseNames(IdentifierService.normalizeStatic(dbVendor,sqlDataObjectType,sub)); 626 } 627 628 List<String> wholeParts = SQLUtil.parseNames(whole); 629 if ((wholeParts.size() == 1)&&(whole.indexOf(".") != -1)){ 630 wholeParts = SQLUtil.parseNames(IdentifierService.normalizeStatic(dbVendor,sqlDataObjectType,whole)); 631 } 632 633 634 if(subParts.size() >wholeParts.size()) return false; 635 int k=0; 636 for(String s:subParts){ 637 subParts.set(k,TBaseType.removePrefixOrSuffixQuoteChar(normalizeIdentifier(dbVendor,sqlDataObjectType,s))); 638 k++; 639 } 640 k=0; 641 for(String s:wholeParts){ 642 wholeParts.set(k, TBaseType.removePrefixOrSuffixQuoteChar(normalizeIdentifier(dbVendor,sqlDataObjectType,s))); 643 k++; 644 } 645 646 boolean ret = false; 647 int i= subParts.size() -1; 648 int j = wholeParts.size() -1; 649 while (i >= 0){ 650 if ( !subParts.get(i).toUpperCase().equals(wholeParts.get(j).toUpperCase())) break; 651 if (i == 0) ret = true; 652 i--; 653 j--; 654 } 655 656 return ret; 657 } 658 659 private boolean enableGetMetadataFromDDL = true; 660 661 public void setEnableGetMetadataFromDDL(boolean enableGetMetadataFromDDL) { 662 this.enableGetMetadataFromDDL = enableGetMetadataFromDDL; 663 } 664 665 /** 666 * If this option is enabled, SQLEnv will collect table/view/function/procedure metadata 667 * from the create table/create view/create function/create procedure statement during the parse of the SQL script. 668 * <br>A TSQLEnv object instance must be passed to {@link TGSqlParser} before parsing the SQL script. And this TSQLEnv 669 * instance can be passed to another {@link TGSqlParser} object with the collected database metadata. 670 * <br>Default value is true. 671 * 672 * @return 673 */ 674 public boolean isEnableGetMetadataFromDDL() { 675 return enableGetMetadataFromDDL; 676 } 677 678 /** 679 * create a SQL environment. 680 * 681 * @param dbVendor the database vendor 682 */ 683 public TSQLEnv(EDbVendor dbVendor){ 684 this.dbVendor = dbVendor; 685 this.nameService = new NameService(dbVendor); 686 687 // ===== Phase 0: Initialize IdentifierService first (required by CatalogStore) ===== 688 // Create IdentifierProfile and IdentifierService 689 this.identifierProfile = IdentifierProfile.forVendor( 690 dbVendor, 691 IdentifierProfile.VendorFlags.defaults() // Default configuration 692 ); 693 this.collatorProvider = createCollatorProvider(dbVendor); // SQL Server needs this 694 this.identifierService = new IdentifierService(identifierProfile, collatorProvider); 695 696 // Phase 3.5: Create CatalogStoreProvider (which internally creates CatalogStore) 697 this.catalogProvider = new CatalogStoreProvider(dbVendor, IdentifierProfile.VendorFlags.defaults()); 698 } 699 700 private EDbVendor dbVendor; 701 702 // Calcite-backed name matching service (Phase 2 integration) 703 private final NameService nameService; 704 705 // ===== Phase 3.5: Final catalog implementation ===== 706 private IdentifierProfile identifierProfile; 707 private IdentifierService identifierService; 708 private CollatorProvider collatorProvider; // SQL Server specific 709 private ICatalogProvider catalogProvider; // Uses CatalogStoreProvider 710 711 /** 712 * the database vendor where this SQL environment is generated from. 713 * 714 * @return the database vendor 715 */ 716 public EDbVendor getDBVendor() { 717 return dbVendor; 718 } 719 720 /** 721 * Returns the Calcite-backed catalog store (Phase 3.5 integration). 722 * 723 * <p>Note: This method delegates to the underlying CatalogStoreProvider. 724 * Direct access to CatalogStore is provided for backward compatibility 725 * with existing test code.</p> 726 * 727 * @return the catalog store 728 */ 729 public CatalogStore getCatalogStore() { 730 if (catalogProvider instanceof CatalogStoreProvider) { 731 return ((CatalogStoreProvider) catalogProvider).getCatalogStore(); 732 } 733 return null; 734 } 735 736 // ===== Phase 0: Helper methods and getters ===== 737 738 /** 739 * Create CollatorProvider for SQL Server 740 * 741 * @param vendor database vendor 742 * @return CollatorProvider instance, null for non-SQL Server databases 743 */ 744 private CollatorProvider createCollatorProvider(EDbVendor vendor) { 745 if (vendor == EDbVendor.dbvmssql || vendor == EDbVendor.dbvazuresql) { 746 return new CollatorProvider(); // SQL Server collation 747 } 748 return null; 749 } 750 751 /** 752 * Get IdentifierService (Phase 0) 753 * 754 * @return IdentifierService instance 755 */ 756 public IdentifierService getIdentifierService() { 757 return identifierService; 758 } 759 760 /** 761 * Get IdentifierProfile (Phase 0) 762 * 763 * @return IdentifierProfile instance 764 */ 765 public IdentifierProfile getIdentifierProfile() { 766 return identifierProfile; 767 } 768 769 /** 770 * Get ICatalogProvider (Phase 3) 771 * 772 * @return ICatalogProvider instance 773 */ 774 public ICatalogProvider getCatalogProvider() { 775 return catalogProvider; 776 } 777 778 /** 779 * This method must be override in the subclass to build a SQL environment with real metadata. 780 * <br>this usually done by querying the INFORMATION_SCHEMA 781 */ 782 public abstract void initSQLEnv(); 783 784 /** 785 * a list of catalog/database in this SQL environment. 786 * 787 * @return a list of catalog/database 788 */ 789 public List<TSQLCatalog> getCatalogList() { 790 return catalogList; 791 } 792 793 private String serverName = null; // SQL Server 794 795 private List<TSQLCatalog> catalogList = new CopyOnWriteArrayList<>(); 796 797 /** 798 * add a catalog to the SQL environment, called internally. 799 * 800 * @param sqlCatalog catalog 801 * @return return false if a catalog with the same name already exists. 802 */ 803 protected boolean doAddCatalog(TSQLCatalog sqlCatalog){ 804 boolean isFound = false; 805 for(TSQLCatalog c : catalogList){ 806 if ( sqlCatalog.getName().compareTo(c.getName()) == 0){ 807 isFound = true; 808 break; 809 } 810 } 811 if (!isFound){ 812 catalogList.add(sqlCatalog); 813 } 814 return !isFound; 815 } 816 817 private Map<String, TSQLSchemaObject> schemaObjectList = new ConcurrentHashMap<>(); 818 819 // Fast canonical index for fully-qualified lookups (additive, keeps existing map intact) 820 private final Map<NameKey, TSQLSchemaObject> objectIndex = new ConcurrentHashMap<NameKey, TSQLSchemaObject>(); 821 // Reverse index for tables by object name only (speeds up ..table lookups) 822 private final Map<String, List<TSQLTable>> tablesByName = new ConcurrentHashMap<String, List<TSQLTable>>(); 823 824 /** 825 * put a schema object into the hashmap which can be used to find a schema object in a more efficient way. 826 * 827 * @param schemaObjectName name of schema object 828 * @param schemaObject instance of a schema object 829 * @return always return true. 830 */ 831 protected boolean putSchemaObject(String schemaObjectName, TSQLSchemaObject schemaObject){ 832 String newSchemaName = schemaObjectName; 833 if (schemaObject.getDataObjectType() == dotTable){ 834 if (!tableCollationCaseSensitive.get(this.getDBVendor())){ 835 newSchemaName = newSchemaName.toUpperCase(); 836 } 837 }else { 838 if (!defaultCollationCaseSensitive.get(this.getDBVendor())){ 839 newSchemaName = newSchemaName.toUpperCase(); 840 } 841 } 842 843 if (schemaObject.getDataObjectType() == dotFunction){ 844 newSchemaName = newSchemaName+"$function"; 845 }else if (schemaObject.getDataObjectType() == dotProcedure){ 846 newSchemaName = newSchemaName+"$procedure"; 847 } 848 849 schemaObjectList.put(newSchemaName,schemaObject); 850 851 // ===== Phase 3.5: Write to catalog provider (no redundancy) ===== 852 try { 853 catalogProvider.addObject(schemaObject); 854 } catch (Throwable e) { 855 // Log error but maintain backward compatibility 856 System.err.println("[CatalogProvider] Error adding object: " + schemaObject + ", error=" + e.getMessage()); 857 } 858 859 // Maintain fast index 860 try { 861 List<String> parts = SQLUtil.parseNames(schemaObjectName); 862 if (parts.size() >= 3) { 863 String catalog = this.normalizeIdentifier(ESQLDataObjectType.dotCatalog, parts.get(0)); 864 String schema = this.normalizeIdentifier(ESQLDataObjectType.dotSchema, parts.get(1)); 865 String object = this.normalizeIdentifier( 866 (schemaObject.getDataObjectType() == ESQLDataObjectType.dotColumn) ? ESQLDataObjectType.dotTable : schemaObject.getDataObjectType(), 867 SQLUtil.mergeSegments(parts, 2)); 868 String server = (getDefaultServerName() == null) ? DEFAULT_SERVER_NAME : getDefaultServerName(); 869 NameKey key = new NameKey(schemaObject.getDataObjectType(), server, catalog, schema, object); 870 objectIndex.put(key, schemaObject); 871 872 if (schemaObject instanceof TSQLTable) { 873 String objOnly = this.normalizeIdentifier(ESQLDataObjectType.dotTable, getObjectName(schemaObjectName)); 874 List<TSQLTable> list = tablesByName.get(objOnly); 875 if (list == null) { 876 list = new ArrayList<TSQLTable>(); 877 tablesByName.put(objOnly, list); 878 } 879 list.add((TSQLTable) schemaObject); 880 } 881 } 882 } catch (Throwable ignore) { 883 // keep backward compatibility even if fast index building fails 884 } 885 return true; 886 } 887 888 /** 889 * add a table 890 * 891 * @param qualifiedTableName, must be in syntax like: catalog.schema.table 892 * @param sqlTable, table instance 893 */ 894// public void addSQLTable(String qualifiedTableName, TSQLTable sqlTable){ 895// schemaObjectList.put(qualifiedTableName,sqlTable); 896// } 897// 898// public void addRoutine(String qualifiedRoutineName, TSQLRoutine sqlRoutine){ 899// schemaObjectList.put(qualifiedRoutineName,sqlRoutine); 900// } 901 902 public static final String DEFAULT_SERVER_NAME = "DEFAULT_SERVER"; 903 public static final String DEFAULT_DB_NAME = "DEFAULT"; 904 public static final String DEFAULT_SCHEMA_NAME = "DEFAULT"; 905 906 private String defaultCatalogName = null; 907 private String defaultSchemaName = null; 908 private String defaultServerName = null; 909 910 protected TSQLSchemaObject doSearchSchemaObject(String catalog, String schema, String table, ESQLDataObjectType objectType){ 911 TSQLSchemaObject result = null; 912 913 String normalizedCurrentCatalogName = this.normalizeIdentifier(ESQLDataObjectType.dotCatalog, defaultCatalogName); 914 String normalizedCurrentSchemaName = this.normalizeIdentifier(ESQLDataObjectType.dotSchema, defaultSchemaName); 915 916 if ((catalog.length()>0)&&(schema.length()>0)){ // catalog.schema.table 917 result = doSearchSchemaObject(catalog+"."+schema+"."+table,objectType); 918 }else if (schema.length()>0){ //.schema.table 919 if (defaultCatalogName != null){ 920 result = doSearchSchemaObject(normalizedCurrentCatalogName+"."+schema+"."+table,objectType); 921 }else{ 922 for(TSQLCatalog c : catalogList){ 923 result = doSearchSchemaObject(c.name+"."+schema+"."+table,objectType); 924 if (result != null) break; 925 } 926 } 927 }else if (catalog.length()>0){ // catalog..table 928 if (defaultSchemaName != null){ 929 result = doSearchSchemaObject(catalog+"."+normalizedCurrentSchemaName+"."+table,objectType); 930 }else{ 931 for(TSQLCatalog c : catalogList){ 932 if ( c.compareTo(catalog) != 0) continue; 933 for(TSQLSchema s: c.getSchemaList()){ 934 result = doSearchSchemaObject(s.getQualifiedName()+"."+table,objectType); 935 if (result != null) break; 936 } 937 if (result != null) break; 938 } 939 } 940 }else{ // ..table, search under the current default database and schema. 941 // The current default database and schema can be set by the user. 942 // if current default database and schema is not set, then search in all databases and schemas 943 if ((objectType == dotTable) && (defaultCatalogName == null) && (defaultSchemaName == null)){ 944 String canonicalTable = this.normalizeIdentifier(ESQLDataObjectType.dotTable, table); 945 List<TSQLTable> candidates = tablesByName.get(canonicalTable); 946 if (candidates != null && !candidates.isEmpty()){ 947 return candidates.get(0); 948 } 949 } 950 for(TSQLCatalog c : catalogList){ 951 if ((defaultCatalogName != null) && ( c.compareTo(defaultCatalogName) != 0)) continue; 952 for(TSQLSchema s: c.getSchemaList()){ 953 if ((defaultSchemaName != null)&&(s.compareTo(defaultSchemaName) != 0)) continue; 954 result = doSearchSchemaObject(s.getQualifiedName()+"."+table,objectType); 955 if (result != null) break; 956 } 957 if (result != null) break; 958 } 959 } 960 961 return result; 962 } 963 964 protected TSQLSchemaObject searchSchemaObject(TObjectName qualifiedName, ESQLDataObjectType objectType){ 965 966 String catalog = this.normalizeIdentifier(ESQLDataObjectType.dotCatalog, qualifiedName.getDatabaseString()); 967 String schema = this.normalizeIdentifier(ESQLDataObjectType.dotSchema, qualifiedName.getSchemaString()); 968 String table = this.normalizeIdentifier(ESQLDataObjectType.dotTable, qualifiedName.getTableString()); 969 970 schema = (schema == null)?getDefaultSchemaName():schema; 971 schema = (schema == null)?"":schema; 972 973 catalog = (catalog == null)?getDefaultCatalogName():catalog; 974 catalog = (catalog == null)?"":catalog; 975 976 return doSearchSchemaObject(catalog,schema,table,objectType); 977 } 978 979 /** 980 * Phase 1: 使用 IdentifierService 的新方法处理多段名 981 */ 982 public TSQLSchemaObject searchSchemaObject(String qualifiedName, ESQLDataObjectType objectType){ 983 // Phase 1: 使用 IdentifierService 的新方法 984 IdentifierService svc = getIdentifierService(); 985 986 // 1. 解析多段名 987 List<String> parts = svc.parseQualifiedName(qualifiedName); 988 989 // 2. 展开厂商特定语法(MSSQL "..") 990 // Pass the default schema name to avoid relying on global state 991 parts = svc.expandVendorSpecific(parts, dbVendor, getDefaultSchemaName()); 992 993 if (parts.size() < 3) { 994 return null; 995 } 996 997 boolean supportCatalog = TSQLEnv.supportCatalog(dbVendor); 998 boolean supportSchema = TSQLEnv.supportSchema(dbVendor); 999 1000 // 3. 使用 normalizeSegment 规范化各段(Phase 1: 单段处理) 1001 String catalog = svc.normalizeSegment(parts.get(0), ESQLDataObjectType.dotCatalog); 1002 String schema = svc.normalizeSegment(parts.get(1), ESQLDataObjectType.dotSchema); 1003 String table = svc.normalizeSegment(SQLUtil.mergeSegments(parts, 2), ESQLDataObjectType.dotTable); 1004 1005 TSQLSchemaObject object = doSearchSchemaObject(catalog,schema,table,objectType); 1006 1007 //如果不是同时支持database和schema,且没有找到object,交换database和schema顺序查找 1008 if (!(supportCatalog && supportSchema) && object == null) { 1009 catalog = svc.normalizeSegment(parts.get(1), ESQLDataObjectType.dotCatalog); 1010 schema = svc.normalizeSegment(parts.get(0), ESQLDataObjectType.dotSchema); 1011 object = doSearchSchemaObject(catalog, schema, table, objectType); 1012 } 1013 1014 return object; 1015 1016// String normalizedCurrentCatalogName = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotCatalog, defaultCatalogName); 1017// String normalizedCurrentSchemaName = TSQLObject.normalizeIdentifier(this,ESQLDataObjectType.dotSchema, defaultSchemaName); 1018// 1019// if ((catalog.length()>0)&&(schema.length()>0)){ // catalog.schema.table 1020// result = doSearchSchemaObject(catalog+"."+schema+"."+table,objectType); 1021// }else if (schema.length()>0){ //.schema.table 1022// if (defaultCatalogName != null){ 1023// result = doSearchSchemaObject(normalizedCurrentCatalogName+"."+schema+"."+table,objectType); 1024// }else{ 1025// for(TSQLCatalog c : catalogList){ 1026// result = doSearchSchemaObject(c.name+"."+schema+"."+table,objectType); 1027// if (result != null) break; 1028// } 1029// } 1030// }else if (catalog.length()>0){ // catalog..table 1031// if (defaultSchemaName != null){ 1032// result = doSearchSchemaObject(catalog+"."+normalizedCurrentSchemaName+"."+table,objectType); 1033// }else{ 1034// for(TSQLCatalog c : catalogList){ 1035// if ( c.compareTo(catalog) != 0) continue; 1036// for(TSQLSchema s: c.getSchemaList()){ 1037// result = doSearchSchemaObject(s.getQualifiedName()+"."+table,objectType); 1038// if (result != null) break; 1039// } 1040// if (result != null) break; 1041// } 1042// } 1043// }else{ // ..table 1044// for(TSQLCatalog c : catalogList){ 1045// if ((defaultCatalogName != null) && ( c.compareTo(defaultCatalogName) != 0)) continue; 1046// for(TSQLSchema s: c.getSchemaList()){ 1047// if ((defaultSchemaName != null)&&(s.compareTo(defaultSchemaName) != 0)) continue; 1048// result = doSearchSchemaObject(s.getQualifiedName()+"."+table,objectType); 1049// if (result != null) break; 1050// } 1051// if (result != null) break; 1052// } 1053// } 1054// 1055// return result; 1056 1057 } 1058 /** 1059 * find a table in the SQL environment by using a qualified table name: catalogName.schemaName.tableName 1060 * 1061 * @param qualifiedTablename, can be catalog.schema.table, 1062 * or .schema.table, use currentCatalogName or iterate all catalogs 1063 * or catalog..table, use current schema name or iterate all schema under catalog 1064 * or ..table, use currentCatalogName or iterate all catalogs, use current schema 1065 * or iterate all schema 1066 * @return a table 1067 */ 1068 public TSQLTable searchTable(String qualifiedTablename){ 1069 TSQLSchemaObject result = searchSchemaObject(qualifiedTablename,dotTable); 1070 1071 if (result instanceof TSQLTable){ 1072 return (TSQLTable)result; 1073 }else return null; 1074 1075 } 1076 1077 public TSQLTable searchTable(TObjectName tableName){ 1078 if ((tableName.getSchemaToken() == null) && (tableName.getDatabaseToken() == null)) return searchTable(".."+tableName.getTableString()); 1079 if (tableName.getDatabaseToken() == null) return searchTable("."+tableName.getSchemaString()+"."+tableName.getTableString()); 1080 if (tableName.getSchemaToken() == null) return searchTable(tableName.getDatabaseString()+".."+tableName.getTableString()); 1081 return searchTable(tableName.toString()); 1082 } 1083 /** 1084 * called by {@link #searchTable(String)} method internally. 1085 * 1086 * @param qualifiedName table name 1087 * @return return a table instance if found, otherwise, return null 1088 */ 1089// TSQLTable doSearchTable(String qualifiedTablename){ 1090// TSQLTable result = null; 1091// TSQLSchemaObject schemaObject = schemaObjectList.get(qualifiedTablename); 1092// 1093// if (schemaObject instanceof TSQLTable){ 1094// result = (TSQLTable)schemaObject; 1095// } 1096// return result; 1097// } 1098 1099 /** 1100 * Phase 1: 使用 IdentifierService 新方法 + 双写日志 1101 */ 1102 private TSQLSchemaObject doSearchSchemaObject( String qualifiedName, ESQLDataObjectType objectType){ 1103 // Phase 1: 使用 IdentifierService 1104 IdentifierService svc = getIdentifierService(); 1105 1106 // ===== Phase 3: Try catalog provider first ===== 1107 try { 1108 List<String> parts = svc.parseQualifiedName(qualifiedName); 1109 parts = svc.expandVendorSpecific(parts, dbVendor); 1110 1111 if (parts.size() >= 3) { 1112 // Phase 1: 使用 normalizeSegment 规范化单段名 1113 String catalog = svc.normalizeSegment(parts.get(0), ESQLDataObjectType.dotCatalog); 1114 String schema = svc.normalizeSegment(parts.get(1), ESQLDataObjectType.dotSchema); 1115 String object = svc.normalizeSegment(SQLUtil.mergeSegments(parts, 2), objectType); 1116 1117 TSQLSchemaObject result = catalogProvider.findObject(catalog, schema, object, objectType); 1118 if (result != null) { 1119 return result; 1120 } 1121 } 1122 } catch (Throwable e) { 1123 // Log error but continue to fallback paths 1124 // System.err.println("[CatalogProvider] Search error: " + e.getMessage()); 1125 } 1126 1127 // Fast-path using canonical index when fully qualified 1128 try { 1129 List<String> parts = svc.parseQualifiedName(qualifiedName); 1130 parts = svc.expandVendorSpecific(parts, dbVendor); 1131 1132 if (parts.size() >= 3) { 1133 String server = (getDefaultServerName() == null) ? DEFAULT_SERVER_NAME : getDefaultServerName(); 1134 1135 // Phase 1: 使用新方法规范化 1136 String catalogNew = svc.normalizeSegment(parts.get(0), ESQLDataObjectType.dotCatalog); 1137 String schemaNew = svc.normalizeSegment(parts.get(1), ESQLDataObjectType.dotSchema); 1138 String objectNew = svc.normalizeSegment(SQLUtil.mergeSegments(parts, 2), 1139 (objectType == ESQLDataObjectType.dotColumn) ? ESQLDataObjectType.dotTable : objectType); 1140 1141 // Phase 1: 双写日志 - 比较新旧键 1142 if (TBaseType.LOG_KEY_COMPARISON) { 1143 String catalogOld = this.normalizeIdentifier(ESQLDataObjectType.dotCatalog, parts.get(0)); 1144 String schemaOld = this.normalizeIdentifier(ESQLDataObjectType.dotSchema, parts.get(1)); 1145 String objectOld = this.normalizeIdentifier( 1146 (objectType == ESQLDataObjectType.dotColumn) ? ESQLDataObjectType.dotTable : objectType, 1147 SQLUtil.mergeSegments(parts, 2)); 1148 1149 if (!catalogNew.equals(catalogOld) || !schemaNew.equals(schemaOld) || !objectNew.equals(objectOld)) { 1150 System.err.println("[Phase1] Key mismatch in " + qualifiedName + " (" + objectType + ")"); 1151 System.err.println(" catalog: OLD=" + catalogOld + " NEW=" + catalogNew); 1152 System.err.println(" schema: OLD=" + schemaOld + " NEW=" + schemaNew); 1153 System.err.println(" object: OLD=" + objectOld + " NEW=" + objectNew); 1154 } 1155 } 1156 1157 NameKey key = new NameKey(objectType, server, catalogNew, schemaNew, objectNew); 1158 TSQLSchemaObject hit = objectIndex.get(key); 1159 if (hit != null) { 1160 return hit; 1161 } 1162 } 1163 } catch (Throwable ignore) { 1164 // fallback to legacy map below 1165 } 1166 String newSchemaName = qualifiedName; 1167 if (objectType == dotTable){ 1168 if (!tableCollationCaseSensitive.get(this.getDBVendor())){ 1169 newSchemaName = newSchemaName.toUpperCase(); 1170 } 1171 }else { 1172 if (!defaultCollationCaseSensitive.get(this.getDBVendor())){ 1173 newSchemaName = newSchemaName.toUpperCase(); 1174 } 1175 } 1176 1177 if (objectType == dotFunction){ 1178 newSchemaName = newSchemaName+"$function"; 1179 }else if (objectType == dotProcedure){ 1180 newSchemaName = newSchemaName+"$procedure"; 1181 } 1182 return schemaObjectList.get(newSchemaName); 1183 } 1184 1185 /** 1186 * the current active catalog/database in the SQL environment. 1187 * If search a table in syntax like this: .schemaName.tableName and this current catalog name is not null, 1188 * then, search the table in this syntax: currentCatalogName.schemaName.tableName. 1189 * If the current catalog name is null, search all catalogs in the catalog list. 1190 * 1191 * @return the name of the current active catalog/database 1192 */ 1193 public String getDefaultCatalogName() { 1194 return defaultCatalogName; 1195 } 1196 1197 /** 1198 * the current schema name in the SQL environment. 1199 * <br> 1200 * If search a table in syntax like this: catalogname..tableName and this current schema name is not null, 1201 * then, search the table in this syntax: catalogName.currentSchemaName.tableName. 1202 * If the current schema name is null, search all schemas under catalogName 1203 * 1204 * @return the default schema name 1205 */ 1206 public String getDefaultSchemaName() { 1207// if ((dbVendor == EDbVendor.dbvmssql)&&(defaultSchemaName == null)){ 1208// return "dbo"; 1209// } 1210 return defaultSchemaName; 1211 } 1212 1213 public void setDefaultCatalogName(String defaultCatalogName) { 1214 this.defaultCatalogName = defaultCatalogName; 1215 } 1216 1217 public void setDefaultSchemaName(String defaultSchemaName) { 1218 this.defaultSchemaName = defaultSchemaName; 1219 } 1220 1221 public String getDefaultServerName() { 1222 return defaultServerName; 1223 } 1224 1225 public void setDefaultServerName(String defaultServerName) { 1226 this.defaultServerName = defaultServerName; 1227 } 1228 1229 1230 1231 /** 1232 * create a new catalog/database in the SQL environment. 1233 * 1234 * @param catalogName catalog name 1235 * @return instance of the created catalog 1236 */ 1237 public TSQLCatalog createSQLCatalog(String catalogName){ 1238 return getSQLCatalog(catalogName,true); 1239 } 1240 1241 /** 1242 * get a catalog from the SQL environment if already exists, otherwise, create a new catalog. 1243 * 1244 * @param catalogName catalog name 1245 * @param createIfNotExist if this value is true, then create a new catalog if it's not exists 1246 * @return a catalog instance 1247 */ 1248 public TSQLCatalog getSQLCatalog(String catalogName, boolean createIfNotExist){ 1249 TSQLCatalog result = searchCatalog(catalogName); 1250 1251 if ((createIfNotExist)&&(result == null)){ 1252 result = new TSQLCatalog(this,catalogName); 1253 } 1254 return result; 1255 } 1256 1257 /** 1258 * search catalog in the catalog list, return null if not found. 1259 * 1260 * @param catalogName catalog name 1261 * @return null if not found. 1262 */ 1263 public TSQLCatalog searchCatalog(String catalogName){ 1264 TSQLCatalog result = null; 1265 for(TSQLCatalog c : catalogList){ 1266 if (c.compareTo(catalogName)==0){ 1267 result = c; 1268 break; 1269 } 1270 } 1271 return result; 1272 } 1273 1274 /** 1275 * create a new schema and add to the catalog 1276 * 1277 * @param qualifiedSchemaName must be a qualified name like: catalog.schema. Otherwise, a null exception will be raised. 1278 * @return a new schema instance 1279 */ 1280 public TSQLSchema createSQLSchema(String qualifiedSchemaName){ 1281 return getSQLSchema(qualifiedSchemaName,true); 1282 } 1283 1284 /** 1285 * get a schema from the specified catalog, if not exists, create a new schema in the catalog. 1286 * 1287 * @param qualifiedSchemaName must be a qualified name like: catalog.schema. Otherwise, a null exception will be raised. 1288 * @param createIfNotExist if this value is true, then create a new schema if it's not exists 1289 * @return a schema instance 1290 */ 1291 public TSQLSchema getSQLSchema(String qualifiedSchemaName, boolean createIfNotExist){ 1292 TSQLSchema result = null; 1293 String[] parts = SQLUtil.parseNames(qualifiedSchemaName).toArray(new String[0]); 1294 String catalogName = parts[0]; 1295 String schemaName = parts[1]; 1296 TSQLCatalog catalog = getSQLCatalog(catalogName,createIfNotExist); 1297 return catalog.getSchema(schemaName,createIfNotExist); 1298 } 1299 1300 1301 /** 1302 * 1303 * @param qualifiedTablename 需要完整的tablename,例如 catalog.schema.table, 如果仅传入 table name, 1304 * 需要利用 default catalog, default schema 拼接完整的名称: catalog.schema.table 1305 * @param columnNameOnly 1306 * @return 1307 */ 1308 public ArrayList<String> getColumnsInTable(String qualifiedTablename,boolean columnNameOnly){ 1309 1310 //TSQLTable tsqlTable = searchTable(getAFullQualifiedSchemaObjectName(qualifiedTablename)); 1311 TSQLTable tsqlTable = searchTable(qualifiedTablename); 1312 if (tsqlTable == null) return null; 1313 //return tsqlTable.searchColumn(columnName); 1314 return tsqlTable.getColumns(columnNameOnly); 1315 } 1316 1317 public boolean columnInTable(String qualifiedTablename, String columnName){ 1318 TSQLTable tsqlTable = searchTable(qualifiedTablename); 1319 if (tsqlTable == null) return false; 1320 return tsqlTable.searchColumn(columnName); 1321 } 1322 1323 public TSQLColumn getColumnInTable(String qualifiedTablename, String columnName){ 1324 StringBuilder builder = new StringBuilder(); 1325 String db = (getDatabaseName(qualifiedTablename) == null)?getDefaultCatalogName():getDatabaseName(qualifiedTablename); 1326 if((db == null) || (db.length() == 0)) { 1327 builder.append(DEFAULT_DB_NAME).append("."); 1328 } 1329 1330 String schema = (getSchemaName(qualifiedTablename) == null)?getDefaultSchemaName():getSchemaName(qualifiedTablename); 1331 if ((schema == null)||(schema.length() == 0)) { 1332 builder.append(DEFAULT_SCHEMA_NAME).append("."); 1333 } 1334 1335 builder.append(qualifiedTablename); 1336 1337 TSQLTable tsqlTable = searchTable(builder.toString()); 1338 if (tsqlTable == null) return null; 1339 return tsqlTable.getColumn(columnName); 1340 } 1341 1342// String[] getCatalogSchemaNameWithDefault(String qualifiedObjectName){ 1343// String[] catalogSchemaName = new String[2]; 1344// 1345// if (qualifiedObjectName.startsWith("`") && qualifiedObjectName.endsWith("`")){ 1346// qualifiedObjectName = qualifiedObjectName.substring(1,qualifiedObjectName.length()-1); 1347// } 1348// 1349// String db = (getDatabaseName(qualifiedObjectName) == null)?getDefaultCatalogName():getDatabaseName(qualifiedObjectName); 1350// if((db == null) || (db.length() == 0)) db = DEFAULT_DB_NAME; 1351// String schema = (getSchemaName(qualifiedObjectName) == null)?getDefaultSchemaName():getSchemaName(qualifiedObjectName); 1352// if ((schema == null)||(schema.length() == 0)) schema = DEFAULT_SCHEMA_NAME; 1353// 1354// catalogSchemaName[0] = db; 1355// catalogSchemaName[1] = schema; 1356// 1357// return catalogSchemaName; 1358// } 1359 public TSQLSchemaObject doAddSchemaObject(String qualifiedObjectName,ESQLDataObjectType objectType){ 1360 1361 if (qualifiedObjectName.startsWith("`") && qualifiedObjectName.endsWith("`")){ 1362 qualifiedObjectName = SQLUtil.trimColumnStringQuote(qualifiedObjectName); 1363 } 1364 1365 String db = (getDatabaseName(qualifiedObjectName) == null)?getDefaultCatalogName():getDatabaseName(qualifiedObjectName); 1366 if((db == null) || (db.length() == 0)) db = DEFAULT_DB_NAME; 1367 String schema = (getSchemaName(qualifiedObjectName) == null)?getDefaultSchemaName():getSchemaName(qualifiedObjectName); 1368 if ((schema == null)||(schema.length() == 0)) schema = DEFAULT_SCHEMA_NAME; 1369 1370 // getCatalogSchemaNameWithDefault 这个函数有问题,为导致测试用例失败 1371 // String[] catalogSchemaName = getCatalogSchemaNameWithDefault(qualifiedObjectName); 1372// String db = catalogSchemaName[0]; 1373// String schema = catalogSchemaName[1]; 1374 1375 TSQLCatalog sqlCatalog = createSQLCatalog(db); 1376 TSQLSchema sqlSchema = sqlCatalog.createSchema(schema); 1377 TSQLSchemaObject created = sqlSchema.createSchemaObject(getObjectName(qualifiedObjectName),objectType); 1378 // Ensure fast index contains the new object as well (already handled via putSchemaObject called by schema) 1379 return created; 1380 } 1381 1382 public TSQLSchemaObject doAddSchemaObject(TObjectName qualifiedObjectName,ESQLDataObjectType objectType){ 1383 String db = (getDatabaseName(qualifiedObjectName) == null)?getDefaultCatalogName():getDatabaseName(qualifiedObjectName); 1384 if((db == null) || (db.length() == 0)) db = DEFAULT_DB_NAME; 1385 String schema = (getSchemaName(qualifiedObjectName) == null)?getDefaultSchemaName():getSchemaName(qualifiedObjectName); 1386 if ((schema == null)||(schema.length() == 0)) schema = DEFAULT_SCHEMA_NAME; 1387 TSQLCatalog sqlCatalog = createSQLCatalog(db); 1388 TSQLSchema sqlSchema = sqlCatalog.createSchema(schema); 1389 return sqlSchema.createSchemaObject(getObjectName(qualifiedObjectName),objectType); 1390 } 1391 1392 /** 1393 * Add a function to SQLEnv, if a function with the same already exists, just return the existing one. 1394 * 1395 * @param qualifiedFunctionName 1396 * @return function 1397 */ 1398 public TSQLFunction addFunction(String qualifiedFunctionName, boolean fromDDL){ 1399 if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return null; 1400 return (TSQLFunction)doAddSchemaObject(qualifiedFunctionName,ESQLDataObjectType.dotFunction); 1401 } 1402 1403 public TSQLFunction addFunction(TObjectName qualifiedFunctionName, boolean fromDDL){ 1404 if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return null; 1405 return (TSQLFunction)doAddSchemaObject(qualifiedFunctionName,ESQLDataObjectType.dotFunction); 1406 } 1407 1408 public TSQLProcedure addOraclePackage(String qualifiedProcedureName, boolean fromDDL){ 1409 if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return null; 1410 return (TSQLProcedure)doAddSchemaObject(qualifiedProcedureName, ESQLDataObjectType.dotOraclePackage); 1411 } 1412 1413 public TSQLProcedure addProcedure(String qualifiedProcedureName, boolean fromDDL){ 1414 if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return null; 1415 return (TSQLProcedure)doAddSchemaObject(qualifiedProcedureName,ESQLDataObjectType.dotProcedure); 1416 } 1417 1418 public TSQLRoutine addSQLRoutine(String qualifiedProcedureName, boolean fromDDL, ESQLDataObjectType type){ 1419 if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return null; 1420 return (TSQLRoutine)doAddSchemaObject(qualifiedProcedureName,type); 1421 } 1422 1423 public TSQLTrigger addTrigger(String qualifiedTriggerName, boolean fromDDL){ 1424 if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return null; 1425 return (TSQLTrigger)doAddSchemaObject(qualifiedTriggerName,ESQLDataObjectType.dotTrigger); 1426 } 1427 1428 /** 1429 * Add a new table to the SQLEnv. If the table with the same name already exists in the SQLEnv, 1430 * the existing table will be returned. 1431 * <br>dbName.schemaName.tablename. If dbName is not specified, {@link #getDefaultCatalogName()} will be used to put this table in. 1432 * If schemaName is not specified, {@link #getDefaultSchemaName()} will be used to put this table in. 1433 * <br>If the specified database and schema are not already exists, a new database/schema will be generated automatically. 1434 * 1435 * @param qualifiedTableName qualified table name 1436 * @param fromDDL is this table generated from a create table statement 1437 * 1438 * @return SQL Table 1439 */ 1440 public TSQLTable addTable(String qualifiedTableName, boolean fromDDL){ 1441 if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return null; 1442 return (TSQLTable)doAddSchemaObject(qualifiedTableName,ESQLDataObjectType.dotTable); 1443 } 1444 1445 public TSQLTable addView(String qualifiedViewName, boolean fromDDL){ 1446 if ((fromDDL)&&(!isEnableGetMetadataFromDDL())) return null; 1447 TSQLTable tsqlTable = (TSQLTable)doAddSchemaObject(qualifiedViewName,ESQLDataObjectType.dotTable); 1448 tsqlTable.setView(true); 1449 return tsqlTable; 1450 } 1451 1452 public static String getObjectName(TObjectName schemaObjectName){ 1453 if (schemaObjectName.getObjectString().length() == 0) return null; 1454 else 1455 return schemaObjectName.getObjectString(); 1456 } 1457 1458 public static String getObjectName(String schemaObjectName){ 1459 String[] names = SQLUtil.parseNames(schemaObjectName).toArray(new String[0]); 1460 return names[names.length-1]; 1461 } 1462 1463 public static String getDatabaseName(TObjectName schemaObjectName){ 1464 if (schemaObjectName.getDatabaseString().length() == 0) 1465 return null; 1466 else 1467 return schemaObjectName.getDatabaseString(); 1468 } 1469 1470 public static String getDatabaseName(String schemaObjectName){ 1471 String[] names = SQLUtil.parseNames(schemaObjectName).toArray(new String[0]); 1472 if (names.length == 3){ 1473 return names[0]; 1474 }else if (names.length == 4){ 1475 return names[1]; 1476 }else{ 1477 return null; 1478 } 1479 } 1480 1481 public static String getSchemaName(TObjectName schemaObjectName){ 1482 if (schemaObjectName.getSchemaString().length() == 0) return null; 1483 else 1484 return schemaObjectName.getSchemaString(); 1485 } 1486 1487 public static String getSchemaName(String schemaObjectName){ 1488 String[] names = SQLUtil.parseNames(schemaObjectName).toArray(new String[0]); 1489 if (names.length == 2){ 1490 return names[0]; 1491 }else if (names.length == 3){ 1492 return names[1]; 1493 }else if (names.length == 4){ 1494 return names[2]; 1495 }else{ 1496 return null; 1497 } 1498 } 1499 1500 public TSQLFunction searchFunction(TObjectName qualifiedTablename) { 1501 TSQLSchemaObject result = searchSchemaObject(qualifiedTablename,dotFunction); 1502 1503 if (result instanceof TSQLFunction) { 1504 return (TSQLFunction) result; 1505 } else return null; 1506 } 1507 1508 public TSQLFunction searchFunction(String qualifiedTablename) { 1509 TSQLSchemaObject result = searchSchemaObject( getAFullQualifiedSchemaObjectName(qualifiedTablename),dotFunction); 1510 1511 if (result instanceof TSQLFunction) { 1512 return (TSQLFunction) result; 1513 } else return null; 1514 } 1515 1516 /** 1517 * If the input name is fully qualified with db and schema, just return it without any modification. 1518 * If the schema name is missed, use {@link #getDefaultSchemaName()} instead 1519 * If the database name is missed, use {@link #getDefaultCatalogName()} instead 1520 * 1521 * some sample result: 1522 * <br> 1523 * db.schema.table 1524 * .schema.table, {@link #getDefaultCatalogName()} is null 1525 * ..table, both {@link #getDefaultCatalogName()} and {@link #getDefaultSchemaName()} are null. 1526 * 1527 * @param schemaObjectName 1528 * @return 1529 */ 1530 public String getAFullQualifiedSchemaObjectName(String schemaObjectName){ 1531 if (SQLUtil.parseNames(schemaObjectName).size() == 3) return schemaObjectName; 1532 String schema = (getDefaultSchemaName() == null)?"":getDefaultSchemaName(); 1533 String db = (getDefaultCatalogName() == null)?"":getDefaultCatalogName(); 1534 1535 String[] names = SQLUtil.parseNames(schemaObjectName).toArray(new String[0]); 1536 if (names.length == 1){ // no prefixed schema, db 1537 return db+"."+schema+"."+schemaObjectName; 1538 }else if (names.length == 2){ // prefix with schema, no database 1539 return db+"."+names[0]+"."+names[1]; 1540 }else { 1541 return schemaObjectName; 1542 } 1543 } 1544 1545 1546 1547 public int getNumberOfTables(){ 1548 int numOfTables = 0; 1549 for(int i=0;i<getCatalogList().size();i++){ 1550 TSQLCatalog tsqlCatalog = getCatalogList().get(i); 1551 for(TSQLSchema tsqlSchema: tsqlCatalog.getSchemaList()){ 1552 for(TSQLSchemaObject schemaObject: tsqlSchema.getSchemaObjectList()){ 1553 switch (schemaObject.getDataObjectType()){ 1554 case dotTable: 1555 numOfTables++; 1556 break; 1557 case dotProcedure: 1558 break; 1559 case dotFunction: 1560 break; 1561 case dotOraclePackage: 1562 break; 1563 } 1564 } //schema object list 1565 } // schema list 1566 } //catalog list 1567 return numOfTables; 1568 } 1569 1570 public String toString(){ 1571 String lcResult = ""; 1572 StringBuilder tables = new StringBuilder(); 1573 StringBuilder views = new StringBuilder(); 1574 StringBuilder functions = new StringBuilder(); 1575 StringBuilder oraclePackages = new StringBuilder(); 1576 StringBuilder procedures = new StringBuilder(); 1577 for(int i=0;i<getCatalogList().size();i++){ 1578 TSQLCatalog tsqlCatalog = getCatalogList().get(i); 1579 lcResult = lcResult+"\ndatabase:"+tsqlCatalog.getName(); 1580 for(TSQLSchema tsqlSchema: tsqlCatalog.getSchemaList()){ 1581 lcResult = lcResult+"\n\t"+"schema:"+tsqlSchema.getName(); 1582 for(TSQLSchemaObject schemaObject: tsqlSchema.getSchemaObjectList()){ 1583 switch (schemaObject.getDataObjectType()){ 1584 case dotTable: 1585 TSQLTable tsqlTable = (TSQLTable)schemaObject; 1586 if (tsqlTable.isView()){ 1587 views.append("\n\t\t\t"+schemaObject.getName()); 1588 for(TSQLColumn column: tsqlTable.getColumnList()){ 1589 views.append("\n\t\t\t\t"+column.getName()); 1590 1591 } 1592 }else{ 1593 tables.append("\n\t\t\t"+schemaObject.getName()); 1594 for(TSQLColumn column: tsqlTable.getColumnList()){ 1595 tables.append("\n\t\t\t\t"+column.getName()); 1596 if (column.getColumnDataType() != null){ 1597 tables.append(",\t"+column.getColumnDataType().toString()); 1598 TTypeName subType; 1599 switch (column.getColumnDataType().getDataType()){ 1600 case array_t: 1601 subType = column.getColumnDataType().getTypeOfList(); 1602 1603 if (subType.getDataType() == EDataType.struct_t){ 1604 1605 for(int k=0;k<subType.getColumnDefList().size();k++){ 1606 //System.out.println(subType.getColumnDefList().getColumn(k).getColumnName()); 1607 //System.out.println(subType.getColumnDefList().getColumn(k).getDatatype()); 1608 tables.append("\n\t\t\t\t\t\t"+ subType.getColumnDefList().getColumn(k).getColumnName().toString() 1609 +",\t"+ subType.getColumnDefList().getColumn(k).getDatatype().toString()); 1610 } 1611 } 1612 break; 1613 case struct_t: 1614 subType = column.getColumnDataType(); 1615 for(int k=0;k<subType.getColumnDefList().size();k++){ 1616 tables.append("\n\t\t\t\t\t\t"+ subType.getColumnDefList().getColumn(k).getColumnName().toString() 1617 +",\t"+ subType.getColumnDefList().getColumn(k).getDatatype().toString()); 1618 } 1619 break; 1620 } 1621 } 1622 } 1623 } 1624 1625 break; 1626 case dotProcedure: 1627 procedures.append("\n\t\t\t"+schemaObject.getName()); 1628 break; 1629 case dotFunction: 1630 functions.append("\n\t\t\t"+schemaObject.toString()); 1631 //TSQLFunction f = (TSQLFunction) schemaObject; 1632 1633 break; 1634 case dotOraclePackage: 1635 oraclePackages.append("\n\t\t\t"+schemaObject.getName()); 1636 break; 1637 } 1638 } //schema object list 1639 lcResult = lcResult+"\n\t\t"+"tables:"+tables.toString(); 1640 lcResult = lcResult+"\n\t\t"+"views:"+views.toString(); 1641 if(oraclePackages.length()>0) { 1642 lcResult = lcResult + "\n\t\t" + "oracle package:" + oraclePackages.toString(); 1643 } 1644 lcResult = lcResult+"\n\t\t"+"procedure:"+procedures.toString(); 1645 lcResult = lcResult+"\n\t\t"+"function:"+functions.toString(); 1646 tables.setLength(0); 1647 views.setLength(0); 1648 procedures.setLength(0); 1649 functions.setLength(0); 1650 } // schema list 1651 } //catalog list 1652 return lcResult; 1653 } 1654 1655 public String getProcedureParameterValue(String procedureName, int paramPos){ 1656 return ""; 1657 } 1658 public void getVariableValue(String variableName, String variableValue){} 1659 1660 private static boolean usedBySqlflow = false; 1661 1662 public static boolean isUsedBySqlflow() { 1663 return usedBySqlflow; 1664 } 1665}