001package gudusoft.gsqlparser.nodes; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.compiler.TVariable; 005import gudusoft.gsqlparser.resolver.TColumnTableMatch; 006import gudusoft.gsqlparser.sqlenv.*; 007import gudusoft.gsqlparser.util.keywordChecker; 008 009import java.util.ArrayList; 010 011/** 012 * The qualified or unqualified name that identifies a database object. 013 * The qualified name may includes those parts: server,database,schema,object,part and dblink. 014 * This class represents database object in different database vendors such as Oracle, SQL Server in a uniform way. 015 * <p> 016 * The general syntax of database object in Oracle: [schema.]object[.part][@dblink] 017 * <p> 018 * The general syntax of database object in SQL Server: [server.][database.][schema.]object 019 * <p> 020 * The meaning of {@link #getObjectToken()} and {@link #getPartToken()} depends on the {@link #getDbObjectType()}. 021 * If this database object is a schema object such as table, index, then the objectToken represents this 022 * database object and partToken is null. 023 * <p><p> 024 * If this TObjectName represents a column, the partToken represents the column name, the objectToken is table/view 025 * name of this column if this column is qualified like <code>table.column</code>, otherwise, the objectToken is 026 * null. 027 * <p> 028 * schemaToken, databaseToken, serverToken is the qualified part of a database object name. 029 * If this objectName represents a database name in the create database statement like this 030 * <code>CREATE DATABASE menagerie</code>, then, the objectToken is menagerie and databaseToken is null. 031 * 032 * @see gudusoft.gsqlparser.EDbObjectType 033 **/ 034 035public class TObjectName extends TParseTreeNode implements Cloneable{ 036 037 public void setOwnStmt(TCustomSqlStatement ownStmt) { 038 this.ownStmt = ownStmt; 039 } 040 041 public TCustomSqlStatement getOwnStmt() { 042 return ownStmt; 043 } 044 045 private TCustomSqlStatement ownStmt; 046 047 048 private TExceptReplaceClause exceptReplaceClause; 049 050 public TExceptReplaceClause getExceptReplaceClause() { 051 return exceptReplaceClause; 052 } 053 054 public void setExceptReplaceClause(TExceptReplaceClause exceptReplaceClause) { 055 this.exceptReplaceClause = exceptReplaceClause; 056 } 057 058 private ETableKind tableKind = ETableKind.etkBase; 059 060 public void setTableKind(ETableKind tableKind) { 061 this.tableKind = tableKind; 062 } 063 064 public ETableKind getTableKind() { 065 return tableKind; 066 } 067 068 TVariable linkedVariable = null; 069 070 public void setLinkedVariable(TVariable linkedVariable) { 071 this.linkedVariable = linkedVariable; 072 this.dbObjectType = EDbObjectType.variable; 073 } 074 075 public TVariable getLinkedVariable() { 076 return linkedVariable; 077 } 078 079 // 如果该对象表示一个字段,那么本属性表示该字段的数据来自那个源字段 080 private TAttributeNode sourceAttributeNode; 081 082 /** 083 * Sets the source attribute node for this object name. 084 * <p> 085 * This method is used only by the legacy TSQLResolver (RESOLVER). 086 * It is not used when using TSQLResolver2 (RESOLVER2) for name resolution. 087 * For RESOLVER2, use {@link #setResolution(gudusoft.gsqlparser.resolver2.model.ResolutionResult)} instead. 088 * 089 * @param sourceAttributeNode the attribute node representing the resolved source 090 * @deprecated Since 3.4.0.5. Use TSQLResolver2 with {@link #setResolution} instead. 091 */ 092 @Deprecated 093 public void setSourceAttributeNode(TAttributeNode sourceAttributeNode) { 094 this.sourceAttributeNode = sourceAttributeNode; 095 } 096 097 /** 098 * Returns the source attribute node for this object name. 099 * <p> 100 * This method is used only by the legacy TSQLResolver (RESOLVER). 101 * It is not used when using TSQLResolver2 (RESOLVER2) for name resolution. 102 * For RESOLVER2, use {@link #getResolution()} instead. 103 * 104 * @return the attribute node representing the resolved source, or null if not resolved 105 * @deprecated Since 3.4.0.5. Use TSQLResolver2 with {@link #getResolution()} instead. 106 */ 107 @Deprecated 108 public TAttributeNode getSourceAttributeNode() { 109 return sourceAttributeNode; 110 } 111 112 // ===== New Resolver2 fields ===== 113 /** 114 * Resolution result from the new resolver (resolver2). 115 * Contains complete resolution status, column source, and candidate information. 116 * This is set by gudusoft.gsqlparser.resolver2.NameResolver 117 */ 118 private gudusoft.gsqlparser.resolver2.model.ResolutionResult resolution; 119 120 /** 121 * Set resolution result (called by resolver2.NameResolver) 122 */ 123 public void setResolution(gudusoft.gsqlparser.resolver2.model.ResolutionResult resolution) { 124 this.resolution = resolution; 125 126 // Synchronize sourceTable with resolution result 127 // sourceTable represents the IMMEDIATE source table (subquery, CTE, or physical table) 128 // NOT the final physical table after tracing through subqueries/CTEs 129 if (resolution != null && resolution.getStatus() == gudusoft.gsqlparser.resolver2.ResolutionStatus.EXACT_MATCH) { 130 gudusoft.gsqlparser.resolver2.model.ColumnSource source = resolution.getColumnSource(); 131 if (source != null) { 132 // Get the immediate source table from the namespace that resolved this column 133 gudusoft.gsqlparser.resolver2.namespace.INamespace sourceNs = source.getSourceNamespace(); 134 TTable immediateSource = (sourceNs != null) ? sourceNs.getSourceTable() : null; 135 136 // For star columns, preserve the existing sourceTable set by linkColumnToTable 137 // Star columns represent ALL columns from all tables in FROM clause 138 String colName = this.getColumnNameOnly(); 139 if (colName != null && colName.equals("*")) { 140 // Don't update sourceTable for star columns 141 } else if (immediateSource != null) { 142 // Special case: if Phase 1 (linkColumnToTable) already resolved to a physical table, 143 // and Phase 2 resolves to a CTE/subquery, check if they're referring to the same 144 // underlying table. If so, preserve Phase 1's physical table reference. 145 // This handles cases like non-recursive CTEs where a table reference inside the CTE 146 // definition should resolve to the physical table, not the CTE itself. 147 boolean preservePhase1 = false; 148 if (this.sourceTable != null && immediateSource != this.sourceTable) { 149 // Phase 1 already set sourceTable 150 ETableSource phase1Type = this.sourceTable.getTableType(); 151 boolean phase1IsPhysical = (phase1Type == ETableSource.objectname); 152 153 // Check if Phase 2 resolved to CTE/subquery 154 boolean phase2IsCTEOrSubquery = immediateSource.isCTEName() 155 || immediateSource.getTableType() == ETableSource.subquery; 156 157 if (phase1IsPhysical && phase2IsCTEOrSubquery) { 158 // Get finalTable from Phase 2 resolution 159 TTable finalTable = source.getFinalTable(); 160 // If finalTable matches Phase 1's sourceTable (same physical table), 161 // preserve Phase 1's result 162 if (finalTable == this.sourceTable) { 163 preservePhase1 = true; 164 } 165 } 166 } 167 168 if (!preservePhase1) { 169 // Set sourceTable to the immediate source (subquery, CTE, or physical table) 170 this.sourceTable = immediateSource; 171 } 172 } 173 174 // Populate candidateTables from ColumnSource for UNION columns 175 // When getFinalTable() is null but we have candidate tables (from UNION branches), 176 // these should be tracked so the formatter can output all candidates 177 java.util.List<TTable> sourceCandidates = source.getCandidateTables(); 178 if (sourceCandidates != null && !sourceCandidates.isEmpty()) { 179 if (candidateTables == null) { 180 candidateTables = new TTableList(); 181 } 182 for (TTable candidate : sourceCandidates) { 183 if (candidate != null && !containsTable(candidateTables, candidate)) { 184 candidateTables.addTable(candidate); 185 } 186 } 187 // Check if candidates came from UNION/CTE propagation (not ambiguity) 188 // Evidence containing "union" or "propagate" indicates UNION branch tracing 189 String evidence = source.getEvidence(); 190 if (evidence != null && (evidence.contains("union") || evidence.contains("propagate"))) { 191 candidatesFromUnion = true; 192 } 193 } 194 195 // Sync propertyToken for struct field access (backward compatibility) 196 // When resolver2 detects struct field access (e.g., info.name where info is a RECORD column), 197 // call columnToProperty() to shift tokens so propertyToken contains the field name. 198 // 199 // To avoid false positives (e.g., treating table.column as column.field when table not found), 200 // we verify the base column is STRUCT type through: 201 // 1. Semantic analysis: Check if ColumnSource's definition node has STRUCT datatype 202 // 2. SQLEnv fallback: Check external metadata if semantic analysis inconclusive 203 // 3. TableNamespace verification: If base column comes from a physical table, it's STRUCT 204 // 205 // Method 3 is key: if "info" resolves to a column in a real table (TableNamespace), 206 // then "info.name" MUST be STRUCT field access (otherwise the SQL would be invalid). 207 // This enables pure SQL-based STRUCT detection without DDL or metadata. 208 if (source.isStructFieldAccess() && source.hasFieldPath()) { 209 String baseColumnName = source.getExposedName(); 210 boolean isVerifiedStructColumn = false; 211 212 // Method 1: Semantic analysis - check ColumnSource's definition node for STRUCT type 213 // This works when DDL (CREATE TABLE with STRUCT columns) is parsed in the same batch 214 TParseTreeNode definitionNode = source.getDefinitionNode(); 215 if (definitionNode instanceof TColumnDefinition) { 216 TColumnDefinition colDef = (TColumnDefinition) definitionNode; 217 TTypeName datatype = colDef.getDatatype(); 218 if (datatype != null && datatype.getDataType() == EDataType.struct_t) { 219 isVerifiedStructColumn = true; 220 } 221 } 222 223 // Method 2: SQLEnv fallback - check external metadata if semantic analysis didn't verify 224 if (!isVerifiedStructColumn && this.sqlEnv != null && baseColumnName != null && immediateSource != null) { 225 String tableName = immediateSource.getFullName(); 226 if (tableName != null) { 227 gudusoft.gsqlparser.sqlenv.TSQLTable sqlTable = this.sqlEnv.searchTable(tableName); 228 if (sqlTable != null) { 229 gudusoft.gsqlparser.sqlenv.TSQLColumn sqlColumn = sqlTable.getColumn(baseColumnName); 230 if (sqlColumn != null && sqlColumn.getColumnDataType() != null) { 231 EDataType dataType = sqlColumn.getColumnDataType().getDataType(); 232 isVerifiedStructColumn = (dataType == EDataType.struct_t); 233 } 234 } 235 } 236 } 237 238 // Method 3: TableNamespace verification - if base column comes from a physical table 239 // When struct field fallback finds the base column (e.g., "info") in a TableNamespace, 240 // the SQL semantic guarantees it's a STRUCT column. If "info" is a regular column in 241 // table "student_records", then "info.name" can ONLY mean STRUCT field access. 242 // This enables STRUCT detection purely from SELECT statement semantics. 243 // 244 // DISABLED: This optimization causes regressions in complex queries where column names 245 // overlap with table aliases (e.g., UNION subqueries with NULL AS column_name). 246 // Users can access field names via source.getFieldPath().getFirst() instead. 247 // TODO: Implement smarter heuristic to detect truly "clear" semantics. 248 // 249 // if (!isVerifiedStructColumn && sourceNs instanceof gudusoft.gsqlparser.resolver2.namespace.TableNamespace) { 250 // // Base column comes from a physical table - definitely STRUCT access 251 // isVerifiedStructColumn = true; 252 // } 253 254 // Only call columnToProperty() for verified STRUCT columns and non-star columns 255 if (isVerifiedStructColumn) { 256 String currentColName = getColumnNameOnly(); 257 if (currentColName == null || !currentColName.equals("*")) { 258 columnToProperty(); 259 } 260 } 261 } 262 } 263 } 264 265 // Sync resolveStatus for backward compatibility with legacy code (e.g., TGetTableColumn) 266 if (resolution != null) { 267 switch (resolution.getStatus()) { 268 case EXACT_MATCH: 269 this.resolveStatus = TBaseType.RESOLVED_AND_FOUND; 270 break; 271 case AMBIGUOUS: 272 this.resolveStatus = TBaseType.RESOLVED_BUT_AMBIGUOUS; 273 break; 274 case NOT_FOUND: 275 // Leave as NOT_RESOLVED_YET or whatever it was before 276 break; 277 } 278 } 279 } 280 281 /** 282 * Helper to check if a table is already in the TTableList 283 */ 284 private static boolean containsTable(TTableList list, TTable table) { 285 if (list == null || table == null) return false; 286 for (int i = 0; i < list.size(); i++) { 287 TTable existing = list.getTable(i); 288 if (existing == table) return true; 289 } 290 return false; 291 } 292 293 /** 294 * Get resolution result from new resolver 295 */ 296 public gudusoft.gsqlparser.resolver2.model.ResolutionResult getResolution() { 297 return resolution; 298 } 299 300 /** 301 * Convenience method: get column source (most common access pattern) 302 */ 303 public gudusoft.gsqlparser.resolver2.model.ColumnSource getColumnSource() { 304 if (resolution == null) return null; 305 306 if (resolution.getStatus() == gudusoft.gsqlparser.resolver2.ResolutionStatus.EXACT_MATCH) { 307 return resolution.getColumnSource(); 308 } else if (resolution.getStatus() == gudusoft.gsqlparser.resolver2.ResolutionStatus.AMBIGUOUS) { 309 // For ambiguous: return first candidate (configurable behavior) 310 gudusoft.gsqlparser.resolver2.model.AmbiguousColumnSource ambiguous = resolution.getAmbiguousSource(); 311 if (ambiguous != null && ambiguous.getCandidateCount() > 0) { 312 return ambiguous.getCandidates().get(0); 313 } 314 } 315 316 return null; 317 } 318 319 /** 320 * Check if this column reference is ambiguous 321 */ 322 public boolean isAmbiguous() { 323 return resolution != null && 324 resolution.getStatus() == gudusoft.gsqlparser.resolver2.ResolutionStatus.AMBIGUOUS; 325 } 326 327 /** 328 * Check if this column reference has been resolved (by new resolver) 329 */ 330 public boolean isResolved() { 331 return resolution != null && 332 resolution.getStatus() != gudusoft.gsqlparser.resolver2.ResolutionStatus.NOT_FOUND; 333 } 334 335 /** 336 * Get all candidate tables (for ambiguous columns) 337 */ 338 public java.util.List<TTable> getCandidateTables2() { 339 if (!isAmbiguous()) return java.util.Collections.emptyList(); 340 341 gudusoft.gsqlparser.resolver2.model.AmbiguousColumnSource ambiguous = resolution.getAmbiguousSource(); 342 return ambiguous.getCandidates().stream() 343 .map(gudusoft.gsqlparser.resolver2.model.ColumnSource::getFinalTable) 344 .filter(java.util.Objects::nonNull) 345 .collect(java.util.stream.Collectors.toList()); 346 } 347 // ===== End of New Resolver2 fields ===== 348// private boolean isResolved = false; 349// 350// public void setResolved(boolean resolved) { 351// isResolved = resolved; 352// } 353// 354// public void setResolvedRelation(TTable resolvedRelation) { 355// this.resolvedRelation = resolvedRelation; 356// this.isResolved = true; 357// } 358// 359// public boolean isResolved() { 360// return isResolved; 361// } 362// 363// public TTable getResolvedRelation() { 364// return resolvedRelation; 365// } 366// 367// private TTable resolvedRelation = null; 368 369 public TObjectName clone(){ 370 TObjectName cloneObject = new TObjectName(); 371 cloneObject.dbObjectType = this.dbObjectType; 372 cloneObject.dbvendor = this.dbvendor; 373 374 if (this.partToken != null){ 375 cloneObject.partToken = this.partToken.clone(); 376 } 377 if (this.objectToken != null){ 378 cloneObject.objectToken = this.objectToken.clone(); 379 } 380 if (this.schemaToken != null){ 381 cloneObject.schemaToken = this.schemaToken.clone(); 382 } 383 384 if (this.databaseToken != null){ 385 cloneObject.databaseToken = this.databaseToken.clone(); 386 } 387 388 if (this.serverToken != null){ 389 cloneObject.serverToken = this.serverToken.clone(); 390 } 391 392 if (this.propertyToken != null){ 393 cloneObject.propertyToken = this.propertyToken.clone(); 394 } 395 396 if (this.methodToken != null){ 397 cloneObject.methodToken = this.methodToken.clone(); 398 } 399 400 if (this.packageToken != null){ 401 cloneObject.packageToken = this.packageToken.clone(); 402 } 403 404 cloneObject.numberOfPart = this.numberOfPart; 405 406 // Copy startToken and endToken from parent TParseTreeNode 407 if (this.getStartToken() != null) { 408 cloneObject.setStartTokenDirectly(this.getStartToken()); 409 } 410 if (this.getEndToken() != null) { 411 cloneObject.setEndTokenDirectly(this.getEndToken()); 412 } 413 414 return cloneObject; 415 } 416 417 private TObjectName parentObjectName; 418 419 public void setParentObjectName(TObjectName parentObjectName) { 420 this.parentObjectName = parentObjectName; 421 } 422 423 @Override 424 public TObjectName getParentObjectName() { 425 return parentObjectName; 426 } 427 428 public void setPath(TPathSqlNode path) { 429 this.path = path; 430 this.setEndToken(path.getEndToken()); 431 } 432 433 /** 434 * stage path 435 * 436 * @return 437 */ 438 public TPathSqlNode getPath() { 439 return path; 440 } 441 442 private TPathSqlNode path; 443 444// private TObjectName cursorName; 445// 446// public void setCursorName(TObjectName cursorName) { 447// this.cursorName = cursorName; 448// } 449// 450// /** 451// * related cursor name if oracle for statement 452// * like: FOR emp_rec IN emp_cur 453// * @return 454// */ 455// public TObjectName getCursorName() { 456// return cursorName; 457// } 458 459 private ArrayList<TTable> sourceTableList; 460 461 /** 462 * source table list for star column, 463 * <br>select * from emp,dept 464 * <br> * column will be list to both emp and dept table. 465 * <br> 466 * @return 467 */ 468 public ArrayList<TTable> getSourceTableList() { 469 if (sourceTableList == null) { 470 sourceTableList = new ArrayList<>(); 471 } 472 return sourceTableList; 473 } 474 475 private boolean isImplicitSchema = false; 476 private boolean isImplicitDatabase = false; 477 478 public boolean isImplicitSchema() { 479 return isImplicitSchema; 480 } 481 482 public boolean isImplicitDatabase() { 483 return isImplicitDatabase; 484 } 485 486// public void setOriginalQuery(TSelectSqlStatement originalQuery) { 487// this.originalQuery = originalQuery; 488// } 489// 490// public TSelectSqlStatement getOriginalQuery() { 491// return originalQuery; 492// } 493// 494// private TSelectSqlStatement originalQuery = null; 495 496 private ArrayList<TAttributeNode> attributeNodesDerivedFromFromClause; 497 498 /** 499 * 这个属性只有当 column 为 * 时有效 500 * 当 column 为 * 时, 本属性包含该 * 展开后对应的 attributeNode 列表,来源是 FROM CLAUSE中的 tables, 在 resolve star column 501 * 时给本属性赋值, TStmtScope.resolve(TObjectName objectName) 502 * 503 * 当 table 有metadata或DDL给出了明确的字段时,每table个展开的 attributeNode 包含明确的字段名,such as t.c 504 * 当 table 没有 metadata 和 DDL 时,每table个只展开的 一个 attributeNode,内容为 t.* 505 * 506 * 507 * @return 508 */ 509 public ArrayList<TAttributeNode> getAttributeNodesDerivedFromFromClause() { 510 if (attributeNodesDerivedFromFromClause == null){ 511 attributeNodesDerivedFromFromClause = new ArrayList<TAttributeNode>(); 512 } 513 return attributeNodesDerivedFromFromClause; 514 } 515 516 private ArrayList<TColumnTableMatch> candidateAttributeNodes; 517 518 /** 519 * 非 star column 使用该属性存放可能包含该 column 的 attributeNode 520 * star column 使用 {@link #getAttributeNodesDerivedFromFromClause()} 521 * 522 * @return 523 */ 524 public ArrayList<TColumnTableMatch> getCandidateAttributeNodes() { 525 if (candidateAttributeNodes == null){ 526 candidateAttributeNodes = new ArrayList<TColumnTableMatch>(); 527 } 528 return candidateAttributeNodes; 529 } 530 531 private TTableList candidateTables = null; 532 533 public TTableList getCandidateTables() { 534 if (candidateTables == null){ 535 candidateTables = new TTableList(); 536 } 537 return candidateTables; 538 } 539 540 /** True if candidateTables came from UNION/CTE branch propagation, not from ambiguity */ 541 private boolean candidatesFromUnion = false; 542 543 /** 544 * Returns true if candidate tables came from UNION/CTE branch propagation, 545 * false if they came from ambiguity (e.g., unqualified column in multi-table query). 546 * When true, the formatter should output all candidates instead of marking as "missed". 547 */ 548 public boolean isCandidatesFromUnion() { 549 return candidatesFromUnion; 550 } 551 552 /** 553 * Check DDL verification status for a candidate table. 554 * 555 * <p>Returns a tri-state result:</p> 556 * <ul> 557 * <li>1 = Column exists in table's DDL</li> 558 * <li>0 = Column NOT found in table's DDL (DDL available but column missing)</li> 559 * <li>-1 = Cannot verify (no DDL available for this table)</li> 560 * </ul> 561 * 562 * @param table The candidate table to check 563 * @return DDL verification status: 1 (exists), 0 (not found), -1 (no DDL) 564 */ 565 public int getDdlVerificationStatus(TTable table) { 566 String columnName = this.getColumnNameOnly(); 567 return gudusoft.gsqlparser.resolver2.model.ColumnSource.getDdlVerificationStatus(table, columnName); 568 } 569 570 /** 571 * Get DDL verification status for all candidate tables. 572 * 573 * <p>Returns a map from each candidate table to its DDL verification status:</p> 574 * <ul> 575 * <li>1 = Column exists in table's DDL</li> 576 * <li>0 = Column NOT found in table's DDL</li> 577 * <li>-1 = Cannot verify (no DDL available)</li> 578 * </ul> 579 * 580 * @return Map of candidate tables to their DDL verification status, or empty map if no candidates 581 */ 582 public java.util.Map<TTable, Integer> getCandidateTableDdlStatus() { 583 java.util.Map<TTable, Integer> result = new java.util.LinkedHashMap<>(); 584 if (candidateTables == null || candidateTables.size() == 0) { 585 return result; 586 } 587 588 String columnName = this.getColumnNameOnly(); 589 for (int i = 0; i < candidateTables.size(); i++) { 590 TTable candidate = candidateTables.getTable(i); 591 if (candidate != null) { 592 int status = gudusoft.gsqlparser.resolver2.model.ColumnSource.getDdlVerificationStatus(candidate, columnName); 593 result.put(candidate, status); 594 } 595 } 596 return result; 597 } 598 599 private boolean isOrphanColumn = false; 600 601 public void setOrphanColumn(boolean orphanColumn) { 602 isOrphanColumn = orphanColumn; 603 } 604 605 public boolean isOrphanColumn() { 606 return isOrphanColumn; 607 } 608 609 private boolean isReservedKeyword = false; 610 611 public boolean isReservedKeyword() { 612 return isReservedKeyword; 613 } 614 615 private TColumnDefinition linkedColumnDef = null; 616 617 public void setLinkedColumnDef(TColumnDefinition linkedColumnDef) { 618 this.linkedColumnDef = linkedColumnDef; 619 } 620 621 /** 622 * The column definition in create/alter table statement that include this column name object. 623 * <pre> 624 * CREATE TABLE table_name ( 625 * column1 datatype, 626 * column2 datatype 627 * ); 628 * </pre> 629 * In above SQL, <code>column1 datatype</code> is the column definition while <code>column1</code> is this 630 * object name. 631 * @return column definition in create/alter table statement 632 */ 633 public TColumnDefinition getLinkedColumnDef() { 634 635 return linkedColumnDef; 636 } 637 638 private TObjectName namespace; 639 640 public void setNamespace(TObjectName namespace) { 641 this.namespace = namespace; 642 } 643 644 /** 645 * The Couchbase namespace before keyspace 646 * @return the namespace 647 */ 648 public TObjectName getNamespace() { 649 650 return namespace; 651 } 652 653 /** 654 * 返回该对象名的字符串表示(中文说明): 655 * <p> 656 * 1) 优先调用父类 {@link TBaseType#toString()} 获取已构造好的整体标识文本; 657 * 若父类返回非空,则: 658 * - 对于 Snowflake,当文本以 <code>IDENTIFIER(...)</code> 形式出现时,仅提取并返回其中的 659 * 字面量部分(去除引号),以符合 Snowflake 标识符解析规则; 660 * - 其他情况直接返回父类结果。 661 * <p> 662 * 2) 若父类返回为空(尚未生成整体文本),则回退到更细粒度的 token: 663 * - 若存在 <code>part</code> 级 token,返回其字符串; 664 * - 否则若存在 <code>object</code> 级 token,返回其字符串; 665 * - 若仍不存在,返回 null。 666 * <p> 667 * 目的:统一并优先复用已构造的字符串表示,同时兼容特定数据库(如 Snowflake)的 668 * 标识符语义,从而在不同厂商 SQL 中提供稳定、符合预期的对象名输出。 669 */ 670 public String toString() { 671 String ret = super.toString(); 672 673 if (ret != null) { 674 if ((dbvendor == EDbVendor.dbvsnowflake) && (ret.toString().toLowerCase().startsWith("identifier("))){ 675 // snowflake identifier name: IDENTIFIER( { string_literal | session_variable | bind_variable | snowflake_scripting_variable } ) 676 // only return the string_literal part 677 // https://www.sqlparser.com/bugs/mantisbt/view.php?id=3566 678 return TBaseType.removeQuoteChar(getObjectString()); 679 } 680 return ret; 681 } 682 683 if (getPartToken() != null) return getPartString(); 684 if (getObjectToken() != null ) return getObjectString(); 685 686 return null; 687 } 688 689 public void setQuoteType(EQuoteType quoteType) { 690 this.quoteType = quoteType; 691 } 692 693 /** 694 * Tell whether this is a quoted objectName. 695 * @return EQuoteType.squareBracket or EQuoteType.doubleQuote if this objectName is quoted. 696 */ 697 public EQuoteType getQuoteType() { 698 if (toString().startsWith("[")){ 699 return EQuoteType.squareBracket; 700 }else if (toString().startsWith("\"")){ 701 return EQuoteType.doubleQuote; 702 }else if (toString().startsWith("`")){ 703 return EQuoteType.backtick; 704 }else 705 return quoteType; 706 } 707 708 private EQuoteType quoteType = EQuoteType.notQuoted; 709// private String stringValue; 710 711 712 713 /** 714 * Internal use only 715 */ 716 public int searchLevel = 0; 717 718 public boolean isContinueToSearch(){ 719 // if column is in where clause, we can search 10 levels up 720 721 // if column is in select list, only select one level up. 722 // only search one level up, c:\prg\gsp_sqlfiles\TestCases\java\oracle\dbobject\berger_sqltest_04.sql 723 724 if (this.getLocation() == ESqlClause.where) return (searchLevel < 10); 725 else return (searchLevel < 1); 726 } 727 private TResultColumn sourceColumn; 728 729 /** 730 * Set the result column which include this column name. Used by parser internally. 731 * 732 * @param sourceColumn the result column includes this column name 733 */ 734 public void setSourceColumn(TResultColumn sourceColumn) { 735 this.sourceColumn = sourceColumn; 736 this.setDbObjectTypeDirectly(EDbObjectType.column); 737 } 738 739 /** 740 * Set the source column without changing dbObjectType. 741 * Used by resolver2 for legacy API compatibility when the column 742 * is already properly typed (e.g., star-inferred columns). 743 * 744 * @param sourceColumn the result column includes this column name 745 */ 746 public void setSourceColumnOnly(TResultColumn sourceColumn) { 747 this.sourceColumn = sourceColumn; 748 } 749 750 /** 751 * The result column which include this column 752 * <pre> 753 * select salary + 1000 from emp 754 * </pre> 755 * In the above SQL, <code>salary + 1000</code> is the result column while <code>salary</code> is this column name. 756 * 757 * @return the result column includes this column name 758 */ 759 public TResultColumn getSourceColumn() { 760 761 return sourceColumn; 762 } 763 764 /** 765 * The <b>immediate</b> source table where this column is visible in the current scope. 766 * 767 * <p>This represents the table/subquery/CTE that directly exposes this column in the FROM clause, 768 * NOT the final physical table after tracing through subqueries or CTEs.</p> 769 * 770 * <h3>Semantic Difference: sourceTable vs finalTable</h3> 771 * <ul> 772 * <li><b>sourceTable</b> (this field): The immediate/direct source in the current scope. 773 * For a column from a subquery, this points to the subquery's TTable.</li> 774 * <li><b>finalTable</b> (via {@code getResolution().getColumnSource().getFinalTable()}): 775 * The final physical table after tracing through all subqueries and CTEs.</li> 776 * </ul> 777 * 778 * <h3>Example</h3> 779 * <pre>{@code 780 * SELECT title FROM (SELECT * FROM books) sub 781 * 782 * For the 'title' column in outer SELECT: 783 * - sourceTable = TTable for subquery 'sub' (tableType=subquery) 784 * - finalTable = TTable for 'books' (the physical table) 785 * }</pre> 786 * 787 * @see #getSourceTable() 788 * @see gudusoft.gsqlparser.resolver2.model.ColumnSource#getFinalTable() 789 */ 790 private TTable sourceTable; 791 792 /** 793 * This column must be in this syntax: table.column, otherwise, this method always return false. 794 * Match tableToken with the input pTable, compare the alias of pTable to tableToken at first, 795 * If not the same, then compare the table name directly. This method can handle quoted name correctly. 796 * 797 * This method is used by parser internally. 798 * 799 * @param pTable table used to match {@link #getTableToken()} of this column object 800 * @return true if input table is matched with tableToken of this column object 801 */ 802 public boolean resolveWithThisTable(TTable pTable){ 803 boolean lcResult = false; 804 if (getTableString().length() == 0) return false; 805 if (pTable.getAliasName().length() > 0) { 806 lcResult = pTable.checkTableByName(getTableString().toString()); //pTable.getAliasName().toString().equalsIgnoreCase(getTableString().toString()); 807 if ((!lcResult)&&(getSchemaString().length()>0)){ 808 lcResult = pTable.getAliasName().toString().equalsIgnoreCase(getSchemaString().toString()); 809 if (lcResult){ 810 // table.column.field, table was recognized as schema in the parser, change the part token to property token 811 this.columnToProperty(); 812 } 813 } 814 } 815 if (lcResult) return true; 816 817 if (((pTable.isBaseTable()||(pTable.isCTEName()))&&(getTableToken() != null)&&(pTable.getTableName().getTableToken() != null))) { 818 // lcResult = getTableToken().toUnQuotedString().equalsIgnoreCase(pTable.getTableName().getTableToken().toUnQuotedString()); 819 String s1 = TBaseType.getTextWithoutQuoted(getTableToken().toString()); 820 String s2 = TBaseType.getTextWithoutQuoted(pTable.getTableName().getTableToken().toString()); 821// System.out.println("table1: "+s1); 822// System.out.println("table1: "+s2); 823 lcResult = s1.equalsIgnoreCase(s2); 824 825 if (lcResult && (!pTable.getPrefixDatabase().isEmpty()) && (!this.getDatabaseString().isEmpty()) && (!pTable.getPrefixDatabase().equalsIgnoreCase(this.getDatabaseString().toString()))) { 826 // teradata: UPDATE foodmart.STRTOK_TIME A SET SYSTEM_DESK = testdatabase.STRTOK_TIME.SYSTEM_DESK 827 // table STRTOK_TIME in testdatabase should be treat as the same one in foodmart 828 lcResult = false; 829 } 830 831 832 if ((!lcResult)&&(getSchemaString().length()>0)){ 833 // lcResult = pTable.getTableName().getTableToken().toUnQuotedString().equalsIgnoreCase(getSchemaString().toString()); 834 lcResult = TBaseType.getTextWithoutQuoted(pTable.getTableName().getTableToken().toString()).equalsIgnoreCase(getSchemaString().toString()); 835 if (lcResult){ 836 // table.column.field, table was recognized as schema in the parser, change the part token to property token 837 this.columnToProperty(); 838 } 839 } 840 } 841 return lcResult; 842 } 843 844 /** 845 * Check whether a column is prefixed by a table like this: <code>table.column</code> 846 * 847 * @return true if this column is in syntax like this: <code>table.column</code> 848 */ 849 public boolean isQualified(){ 850 return (getTableString().length() > 0); 851 } 852 853 public int getValidate_column_status() { 854 return validate_column_status; 855 } 856 857 public void setValidate_column_status(int validate_column_status) { 858 this.validate_column_status = validate_column_status; 859 } 860 861 private int validate_column_status = TBaseType.CAN_BE_COLUMN_NOT_VALIDATE_YET; 862 /** 863 * Check whether a column name is syntax valid in a specific database vendor. 864 * For example, in Oracle, <code>rowid</code> is not a valid column name. 865 * 866 * @param pDBVendor in which the database vendor the syntax of this column is checked 867 * @return true if this objectName can be used as a column name in the specified database 868 */ 869 public boolean isValidColumnName(EDbVendor pDBVendor){ 870 boolean lcResult = true; 871 if (validate_column_status == TBaseType.VALIDATED_CAN_BE_A_COLUMN_NAME) return true; 872 if (validate_column_status == TBaseType.VALIDATED_CAN_NOT_BE_A_COLUMN_NAME) return false; 873 if (validate_column_status == TBaseType.MARKED_NOT_A_COLUMN_IN_COLUMN_RESOLVER) return false; 874 if (validate_column_status == TBaseType.COLUMN_LINKED_TO_COLUMN_ALIAS_IN_OLD_ALGORITHM) return false; 875 876 877 878 if ((getObjectType() == TObjectName.ttobjVariable) 879 ||(getDbObjectType() == EDbObjectType.variable) 880 ||(getObjectType() == TObjectName.ttobjColumnAlias) 881 || (getDbObjectType() == EDbObjectType.xmlElement) 882 || (getDbObjectType() == EDbObjectType.date_time_part) 883 || (getDbObjectType() == EDbObjectType.constant) 884 || (getDbObjectType() == EDbObjectType.function) 885 ) { 886 validate_column_status = TBaseType.VALIDATED_CAN_NOT_BE_A_COLUMN_NAME; 887 return false; 888 } 889 890 if (pDBVendor == EDbVendor.dbvsybase){ 891 TSourceToken pt = getPartToken(); 892 if ( pt != null){ 893 if (pt.tokentype == ETokenType.ttdqstring){ 894 //"0123", quoted string start with a number can't a column 895 if ((pt.toString().charAt(1) >= '0') 896 &&(pt.toString().charAt(1) <= '9')){ 897 lcResult = false; 898 }else if (pt.toString().length() == 2){ 899 //"", empty 900 lcResult = false; 901 }else if (pt.toString().substring(1,pt.toString().length()-1).trim().length() == 0){ 902 //" " 903 lcResult = false; 904 } 905 } 906 } 907 } 908 909 if (getPartToken() != null){ 910 if (getPartToken().tokentype == ETokenType.ttkeyword){ 911 912 switch (pDBVendor){ 913 case dbvmssql: 914 //lcResult = this.getGsqlparser().getFlexer().canBeColumnName(getPartToken().tokencode); 915 lcResult = TLexerMssql.canBeColumnName(getPartToken().tokencode); 916 break; 917 case dbvsybase: 918 lcResult = !keywordChecker.isKeyword(getPartToken().toString(), EDbVendor.dbvsybase, "15.7", true); 919 break; 920 default: 921 break; 922 } 923 } 924 } 925 926 if ((toString().startsWith("@"))||((toString().startsWith(":"))&&(toString().indexOf(".")==-1))) 927 { 928 setObjectType(TObjectName.ttobjNotAObject); 929 lcResult = false; 930 } 931 932 switch (pDBVendor){ 933 case dbvoracle: 934 if ( //(getColumnNameOnly().compareToIgnoreCase ("rowid") == 0)|| 935 (getColumnNameOnly().compareToIgnoreCase ("sysdate") == 0) 936 || (getColumnNameOnly().compareToIgnoreCase ("nextval") == 0) 937 || (getColumnNameOnly().compareToIgnoreCase ("rownum") == 0) 938 || (getColumnNameOnly().compareToIgnoreCase ("level") == 0) 939 || (getColumnNameOnly().compareToIgnoreCase ("user") == 0) 940 ){ 941 setObjectType(TObjectName.ttobjNotAObject); 942 lcResult = false; 943 } 944 if ((toString().startsWith(":"))&&(toString().indexOf(".") == -1)) 945 { // :bindv, but :new.column should not be enter here 946 setObjectType(TObjectName.ttobjNotAObject); 947 lcResult = false; 948 } 949 break; 950 case dbvmssql: 951 if ((getColumnNameOnly().compareToIgnoreCase ("system_user") == 0) 952 ){ 953 //setObjectType(TObjectName.ttobjNotAObject); 954 lcResult = false; 955 } 956 break; 957 case dbvmysql: 958 if (toString().startsWith("\"")){ 959 // "X" is a string literal 960 lcResult = false; 961 } 962 if (keywordChecker.isKeyword(toString(),EDbVendor.dbvmysql,"6.0",true)){ 963 isReservedKeyword = true; 964 lcResult = false; 965 } 966 break; 967 case dbvteradata: 968 if ((getObjectString().length() == 0)&&((getColumnNameOnly().compareToIgnoreCase ("account") == 0) 969 ||(getColumnNameOnly().compareToIgnoreCase ("current_date") == 0) 970 ||(getColumnNameOnly().compareToIgnoreCase ("current_role") == 0) 971 ||(getColumnNameOnly().compareToIgnoreCase ("current_time") == 0) 972 ||(getColumnNameOnly().compareToIgnoreCase ("current_timestamp") == 0) 973 ||(getColumnNameOnly().compareToIgnoreCase ("current_user") == 0) 974 ||(getColumnNameOnly().compareToIgnoreCase ("database") == 0) 975 ||((getColumnNameOnly().compareToIgnoreCase ("date") == 0)&&( this.getDbObjectType() != EDbObjectType.column )) 976 ||(getColumnNameOnly().compareToIgnoreCase ("profile") == 0) 977 ||(getColumnNameOnly().compareToIgnoreCase ("role") == 0) 978 ||(getColumnNameOnly().compareToIgnoreCase ("session") == 0) 979 ||(getColumnNameOnly().compareToIgnoreCase ("time") == 0) 980 ||(getColumnNameOnly().compareToIgnoreCase ("user") == 0) 981 ||(getColumnNameOnly().compareToIgnoreCase ("sysdate") == 0) 982 )){ 983 lcResult = false; 984 } 985 break; 986 case dbvpostgresql: 987 if (toString().startsWith("$")){ 988 if ((toString().charAt(1) >= '0') 989 &&(toString().charAt(1) <= '9')){ 990 this.setDbObjectType(EDbObjectType.variable); 991 lcResult = false; 992 } 993 } 994 break; 995 case dbvbigquery: 996 if ((getColumnNameOnly().compareToIgnoreCase ("CURRENT_DATE") == 0) 997 ||(getColumnNameOnly().compareToIgnoreCase ("CURRENT_TIME") == 0) 998 ||(getColumnNameOnly().compareToIgnoreCase ("CURRENT_TIMESTAMP") == 0) 999 ){ 1000 //setObjectType(TObjectName.ttobjNotAObject); 1001 lcResult = false; 1002 } 1003 break; 1004 } 1005 1006 if(lcResult){ 1007 validate_column_status = TBaseType.VALIDATED_CAN_BE_A_COLUMN_NAME; 1008 }else{ 1009 validate_column_status = TBaseType.VALIDATED_CAN_NOT_BE_A_COLUMN_NAME; 1010 } 1011 1012 return lcResult; 1013 1014 } 1015 1016 private boolean expandStarColumns = false; 1017 ArrayList<String> expandedStarColumns = new ArrayList<>(); 1018 1019 public ArrayList<String> getColumnsLinkedToStarColumn() { 1020 if (expandStarColumns) return expandedStarColumns; 1021 1022 //TTable sourceTable = this.getSourceTable(); 1023 if (getSourceTableList().size() > 0){ 1024 for( int i = 0;i < getSourceTableList().size();i++){ 1025 for(String c:getSourceTableList().get(i).getExpandedStarColumns()){ 1026 expandedStarColumns.add(c); 1027 } 1028 } 1029 } 1030 1031 expandStarColumns = true; 1032 return expandedStarColumns; 1033 1034 } 1035 1036 private ArrayList<String> columnsLinkedToStarColumn = new ArrayList<String>(); 1037 1038 private TResultColumnList columnsLinkedToStar; 1039 1040 public void setColumnsLinkedToStar(TResultColumnList columnsLinkedToStar) { 1041 this.columnsLinkedToStar = columnsLinkedToStar; 1042 for(TResultColumn rc:columnsLinkedToStar){ 1043 if (rc.getColumnAlias()!= ""){ 1044 columnsLinkedToStarColumn.add(rc.getColumnAlias()); 1045 }else{ 1046 columnsLinkedToStarColumn.add(rc.getColumnNameOnly()); 1047 } 1048 } 1049 1050 this.setDbObjectTypeDirectly(EDbObjectType.column); 1051 } 1052 1053 /** 1054 * if this is a star column(column name is *), and the value of this star column 1055 * is derived from a subquery, then, this field points to the select list in the subquery 1056 * 1057 * @return the select list in the subquery 1058 */ 1059 public TResultColumnList getColumnsLinkedToStar() { 1060 return columnsLinkedToStar; 1061 } 1062 1063 /** 1064 * Set the table this column belongs to. Used by parser internally. 1065 * 1066 * @param sourceTable table contains this column 1067 */ 1068 public void setSourceTable(TTable sourceTable) { 1069 1070 // INSERT INTO "omni"."omni_upload_t1a8067802b804755b1d29ee935b3b0bc" VALUES ($1, $2, $3, $4, $5) 1071 // if this objectname is $1, then just return 1072 if (this.getDbObjectType() == EDbObjectType.parameter) { 1073 // to avoid this parameter been checked in TAttributeResolver preVisit(TObjectName attribute) 1074 this.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_TABLE_IN_OLD_ALGORITHM); 1075 return; 1076 } 1077 1078 this.sourceTable = sourceTable; 1079 1080 // 如果 column token 的 tokentype 为 ETokenType.ttkeyword, 那么调整为 ETokenType.ttidentifier 1081 if ((this.getPartToken() != null)&&(this.getPartToken().tokentype == ETokenType.ttkeyword)){ 1082 if ((this.getPartToken().getDbObjectType() == EDbObjectType.column)||(this.getPartToken().getDbObjectType() == EDbObjectType.unknown)){ 1083 this.getPartToken().tokentype = ETokenType.ttidentifier; 1084 } 1085 } 1086 this.setDbObjectTypeDirectly(EDbObjectType.column); 1087 1088 // If this column was previously an orphan and is now linked to a table, 1089 // remove it from the orphanColumns list of its owning statement 1090 if (sourceTable != null && this.isOrphanColumn() && this.getOwnStmt() != null) { 1091 TObjectNameList orphanColumns = this.getOwnStmt().getOrphanColumns(); 1092 if (orphanColumns != null) { 1093 orphanColumns.removeElement(this); 1094 } 1095 this.setOrphanColumn(false); 1096 } 1097 } 1098 1099 public void setSourceTableBySQLResolver(TCustomSqlStatement sqlStatement, TAttributeNode attributeNode, TTable newSourceTable) { 1100 // 如果 column token 的 tokentype 为 ETokenType.ttkeyword, 那么调整为 ETokenType.ttidentifier 1101 if ((this.getPartToken() != null)&&(this.getPartToken().tokentype == ETokenType.ttkeyword)){ 1102 if ((this.getPartToken().getDbObjectType() == EDbObjectType.column)||(this.getPartToken().getDbObjectType() == EDbObjectType.unknown)){ 1103 this.getPartToken().tokentype = ETokenType.ttidentifier; 1104 } 1105 } 1106 1107 if ((this.sourceTable != null) && (this.sourceTable.equals(newSourceTable))) return; 1108 1109 if ((this.getResolveStatus() == TBaseType.RESOLVED_AND_FOUND ) 1110 || (newSourceTable.getTableType() != ETableSource.subquery)){// 关联到 subquery 的 column 本能算真正找到 table,因此还不能去掉 orphan column 1111 if (sqlStatement.getOrphanColumns().removeElement(this)){ 1112 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 1113 TBaseType.log(String.format("Remove orphan column <%s> find in old algorithm",this.toString()),TLog.WARNING,this); 1114 } 1115 // remove the waring in sql statement's error syntax list 1116 TCustomSqlStatement currentStatement = sqlStatement; 1117 while (currentStatement != null) { 1118 if (currentStatement.getSyntaxHints() != null) { 1119 for(int i=0; i<currentStatement.getSyntaxHints().size(); i++) { 1120 TSyntaxError syntaxError = currentStatement.getSyntaxHints().get(i); 1121 if (syntaxError.errortype == EErrorType.sphint) { 1122 if ((syntaxError.lineNo == this.getStartToken().lineNo)||(syntaxError.columnNo == this.getStartToken().columnNo)) { 1123 currentStatement.getSyntaxHints().remove(i); 1124 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 1125 TBaseType.log(String.format("Remove orphan column <%s> warning message in old algorithm", this.toString()), TLog.WARNING, this); 1126 } 1127 break; 1128 } 1129 } 1130 } 1131 } 1132 currentStatement = currentStatement.getParentStmt(); 1133 } 1134 } 1135 }else{ 1136 TBaseType.log(String.format("Found orphan column <%s> find in old algorithm in subquery %s, but NOT remove it from orphan list",this.toString(),newSourceTable.getAliasName()),TLog.WARNING,this); 1137 } 1138 1139 if (this.sourceTable != null){ 1140 if (this.sourceTable.getLinkedColumns().removeElement(this)){ 1141 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 1142 TBaseType.log(String.format("Remove <%s> at addr: %s from table <%s> that found in old algorithm, new linked table is: %s" 1143 ,this.toString(),Integer.toHexString(this.hashCode()),this.sourceTable.toString(),newSourceTable.toString()) 1144 ,TLog.WARNING,this); 1145 } 1146 } 1147 } 1148 this.sourceTable = newSourceTable; 1149 this.sourceTable.getLinkedColumns().addObjectName(this); 1150 1151 if (this.getSourceColumn() == null){ 1152 // if (attributeNode.isAttributeCreatedFromAliasColumn()){ 1153 this.setSourceColumn(attributeNode.getSubLevelResultColumn()); 1154 // } 1155 } 1156 1157 this.setDbObjectTypeDirectly(EDbObjectType.column); 1158 } 1159 1160 /** 1161 * Get the <b>immediate</b> source table where this column is visible in the current scope. 1162 * 1163 * <p>This returns the table/subquery/CTE that directly exposes this column in the FROM clause, 1164 * NOT the final physical table after tracing through subqueries or CTEs.</p> 1165 * 1166 * <p>To get the final physical table (after tracing through all layers), use: 1167 * {@code getResolution().getColumnSource().getFinalTable()}</p> 1168 * 1169 * <h3>Example</h3> 1170 * <pre>{@code 1171 * SELECT title FROM (SELECT * FROM books) sub 1172 * 1173 * For the 'title' column in outer SELECT: 1174 * - getSourceTable() → TTable for subquery 'sub' (tableType=subquery) 1175 * - resolution.getFinalTable() → TTable for 'books' (the physical table) 1176 * }</pre> 1177 * 1178 * @return The immediate source table, or null if not resolved 1179 * @see #sourceTable 1180 * @see gudusoft.gsqlparser.resolver2.model.ColumnSource#getFinalTable() 1181 */ 1182 public TTable getSourceTable() { 1183 // If new resolver determined this column is ambiguous, don't return old Phase 1 value 1184 // This ensures ambiguous columns are treated as orphan by the formatter 1185 // EXCEPTION: Star columns (*) should preserve their sourceTable for proper output 1186 if (resolution != null && resolution.isAmbiguous()) { 1187 String colName = getColumnNameOnly(); 1188 if (colName != null && colName.equals("*")) { 1189 // Star columns keep their Phase 1 sourceTable 1190 return sourceTable; 1191 } 1192 if (gudusoft.gsqlparser.TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE) { 1193 System.out.println("[TObjectName.getSourceTable] Column '" + colName + 1194 "' is AMBIGUOUS - returning null instead of " + 1195 (sourceTable != null ? sourceTable.getName() : "null")); 1196 } 1197 return null; 1198 } 1199 if (resolution == null && sourceTable != null) { 1200 if (gudusoft.gsqlparser.TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE) { 1201 System.out.println("[TObjectName.getSourceTable] Column '" + getColumnNameOnly() + 1202 "' has NO resolution - using Phase 1 sourceTable: " + sourceTable.getName()); 1203 } 1204 } 1205 return sourceTable; 1206 } 1207 1208 public void setResolveStatus(int resolveStatus) { 1209 this.resolveStatus = resolveStatus; 1210 1211 if (this.resolveStatus == TBaseType.RESOLVED_AND_FOUND){ 1212 this.setDbObjectTypeDirectly(EDbObjectType.column); 1213 } 1214 1215 } 1216 1217 private int resolveStatus = TBaseType.NOT_RESOLVED_YET; 1218 1219 public int getResolveStatus() { 1220 return resolveStatus; 1221 } 1222 1223 public void TObjectName(){ 1224 1225 } 1226 1227 private TObjectNameList columnAttributes = null; 1228 1229 private boolean subscripts; 1230 private TIndirection indirection; 1231 1232 /** 1233 * PostgreSQL column with array types 1234 * <pre> 1235 * CREATE TABLE sal_emp ( 1236 * name text, 1237 * pay_by_quarter integer[], 1238 * schedule text[][] 1239 * ); 1240 * </pre> 1241 * In the above SQL, this method returns true for <code>pay_by_quarter</code> column. 1242 * 1243 * @return true if this objectName is array type 1244 */ 1245 public boolean isSubscripts() { 1246 return subscripts; 1247 } 1248 1249 public void setIndirection(TIndirection indirection) { 1250 if(indirection == null) return; 1251 1252 this.indirection = indirection; 1253 // setup the exceptReplaceClause of the last indirection to the parent object which is set in the .y bnf file 1254 if (indirection.getIndices() != null){ 1255 if (indirection.getIndices().getElement(indirection.getIndices().size()-1).getAttributeName() != null){ 1256 setExceptReplaceClause(indirection.getIndices().getElement(indirection.getIndices().size()-1).getAttributeName().getExceptReplaceClause()); 1257 1258 } 1259 } 1260 1261 // possible syntax, support in postgresql only in current version: 1262 // [ indirection ], list in [] was indirection 1263 // 1264 // tablename[.column] 1265 // tablename[.*] 1266 // $1[.somecolumn] 1267 // 1268 // mytable[.arraycolumn[4]] 1269 // mytable[.two_d_column[17][34]] 1270 // $1[[10:42]] 1271 // 1272 1273 if (this.getObjectType() == TObjectName.ttobjPositionalParameters){ 1274 if(indirection.isRealIndices()){ 1275 //$1[10:42] 1276 this.subscripts = true; 1277 }else{ 1278 //$1.somecolumn 1279 this.setColumnTokenOfPositionalParameters(indirection.getIndices().getElement(0).getAttributeName().getPartToken()); 1280 } 1281 }else{ 1282 if(indirection.isRealIndices()){ 1283 if (indirection.getIndices().size() == 1){ 1284 // arraycolumn[4] 1285 this.subscripts = true; 1286 }else if (indirection.getIndices().size() >= 2){ 1287 if (!indirection.getIndices().getElement(0).isRealIndices()){ 1288 // mytable[.arraycolumn[4]] 1289 // mytable[.two_d_column[17][34]] 1290 // this.setPartTokenOfIndirection(indirection.getIndices().getElement(0).getAttributeName().getPartToken()); 1291 this.subscripts = true; 1292 // this.indirection.getIndices().remove(0); 1293 } 1294 } 1295 } 1296 1297 //else{ 1298 // 首先查找 : 和 [ 分隔符,如果找到,在该分隔符前的是 column,如果没有找到按照一般 qualified name 规则处理 1299 // https://docs.snowflake.com/en/user-guide/querying-semistructured.html 1300 int elementIndex = -1; 1301 for(int i=0;i<indirection.getIndices().size();i++){ 1302 TIndices tmp = indirection.getIndices().getElement(i); 1303 if ((tmp.getStartToken().tokencode == ':')||(tmp.getStartToken().tokencode == '[')||(tmp.getStartToken().tokencode == TBaseType.bind_v)){ 1304 elementIndex = i; 1305 break; 1306 } 1307 } 1308 if (elementIndex >= 0){ 1309 // 找到了 : 和 [ 分隔符 1310 if (elementIndex == 0){ 1311 // snowflake, <column>:<level1_element> 1312 // everything already perfect, nothing need to be changed 1313 partToken.setDbObjectType(EDbObjectType.column); 1314 }else if (elementIndex == 1){ 1315 // snowflake, table.column:<level1_element> 1316 objectToken = partToken; 1317 objectToken.setDbObjectType(EDbObjectType.table); 1318 partToken = indirection.getIndices().getElement(elementIndex-1).getAttributeName().getPartToken(); 1319 partToken.setDbObjectType(EDbObjectType.column); 1320 }else if (elementIndex == 2){ 1321 // snowflake, schema.table.column:<level1_element> 1322 schemaToken = partToken; 1323 schemaToken.setDbObjectType(EDbObjectType.schema); 1324 objectToken = indirection.getIndices().getElement(elementIndex-2).getAttributeName().getPartToken(); 1325 objectToken.setDbObjectType(EDbObjectType.table); 1326 partToken = indirection.getIndices().getElement(elementIndex-1).getAttributeName().getPartToken(); 1327 partToken.setDbObjectType(EDbObjectType.column); 1328 } 1329 }else{ 1330 // 一般 qualified name 规则处理 1331 if (indirection.getIndices().size() == 1){ 1332 this.setPartTokenOfIndirection(indirection.getIndices().getElement(0).getAttributeName().getPartToken()); 1333 }else if (indirection.getIndices().size() == 2){ 1334 schemaToken = partToken; 1335 schemaToken.setDbObjType(TObjectName.ttobjSchemaName); 1336 objectToken = indirection.getIndices().getElement(0).getAttributeName().getPartToken(); 1337 objectToken.setDbObjType(ttobjTable); 1338 partToken = indirection.getIndices().getElement(1).getAttributeName().getPartToken(); 1339 partToken.setDbObjType(ttobjColumn); 1340 }else if (indirection.getIndices().size() == 3){ 1341 // db.schema.tablename.column 1342 databaseToken = partToken; 1343 databaseToken.setDbObjectType(EDbObjectType.database); 1344 partToken = indirection.getIndices().getElement(2).getAttributeName().getPartToken(); 1345 partToken.setDbObjectType(EDbObjectType.column); 1346 objectToken = indirection.getIndices().getElement(1).getAttributeName().getPartToken(); 1347 objectToken.setDbObjectType(EDbObjectType.table); 1348 schemaToken = indirection.getIndices().getElement(0).getAttributeName().getPartToken(); 1349 schemaToken.setDbObjectType(EDbObjectType.schema); 1350 } 1351 } 1352 1353// if (indirection.getIndices().size() == 1){ 1354// if ((indirection.getIndices().getElement(0).getStartToken().tokencode == ':') 1355// ||(indirection.getIndices().getElement(0).getStartToken().tokencode == TBaseType.bind_v)) 1356// { 1357// // snowflake, <column>:<level1_element> 1358// 1359// }else{ 1360// // tablename[.column] 1361// // tablename[.*] 1362// this.setPartTokenOfIndirection(indirection.getIndices().getElement(0).getAttributeName().getPartToken()); 1363// } 1364// }else if (indirection.getIndices().size() == 2){ 1365// if ((indirection.getIndices().getElement(0).getStartToken().tokencode == ':') 1366// ||(indirection.getIndices().getElement(0).getStartToken().tokencode == TBaseType.bind_v)) 1367// { 1368// // snowflake, <column>:<level1_element> 1369// 1370// }else { 1371// // schema.tablename.column 1372// schemaToken = partToken; 1373// schemaToken.setDbObjType(TObjectName.ttobjSchemaName); 1374// objectToken = indirection.getIndices().getElement(0).getAttributeName().getPartToken(); 1375// objectToken.setDbObjType(ttobjTable); 1376// partToken = indirection.getIndices().getElement(1).getAttributeName().getPartToken(); 1377// partToken.setDbObjType(ttobjColumn); 1378// } 1379// }else if (indirection.getIndices().size() == 3){ 1380// // db.schema.tablename.column 1381// databaseToken = partToken; 1382// databaseToken.setDbObjectType(EDbObjectType.database); 1383// partToken = indirection.getIndices().getElement(2).getAttributeName().getPartToken(); 1384// partToken.setDbObjectType(EDbObjectType.column); 1385// objectToken = indirection.getIndices().getElement(1).getAttributeName().getPartToken(); 1386// objectToken.setDbObjectType(EDbObjectType.table); 1387// schemaToken = indirection.getIndices().getElement(0).getAttributeName().getPartToken(); 1388// schemaToken.setDbObjectType(EDbObjectType.schema); 1389// } 1390 1391 // } 1392 1393 } 1394 1395 } 1396 1397 /** 1398 * Array element of this objectName 1399 * <pre> 1400 * select arraycolumn[4] from t; 1401 * </pre> 1402 * In the above SQL, this method returns <code>[4]</code> of this objectName. 1403 * 1404 * @return array element of this objectName 1405 * @see gudusoft.gsqlparser.nodes.TIndirection 1406 */ 1407 public TIndirection getIndirection() { 1408 return indirection; 1409 } 1410 1411 private void setPartTokenOfIndirection(TSourceToken column){ 1412 parseTablename(); 1413 this.partToken = column; 1414 this.partToken.setDbObjType(ttobjColumn); 1415 } 1416 1417 public void setPropertyToken(TSourceToken propertyToken) { 1418 this.propertyToken = propertyToken; 1419 } 1420 1421 public TSourceToken getAtsign() { 1422 return atsign; 1423 } 1424 1425 public TSourceToken getMethodToken() { 1426 1427 return methodToken; 1428 } 1429 1430 public TSourceToken getPropertyToken() { 1431 return propertyToken; 1432 } 1433 1434 /** 1435 * The server part of this objectName: [server.][database.][schema.]object 1436 * 1437 * @return server part of the objectName 1438 */ 1439 public TSourceToken getServerToken() { 1440 return serverToken; 1441 } 1442 1443 public TSourceToken getExclamationmark() { 1444 1445 return exclamationmark; 1446 } 1447 1448 /** 1449 * 1450 * The database link part <code>remoreserver</code> in this objectName: scott.emp@remoreserver 1451 * 1452 * @return database link 1453 */ 1454 public TObjectName getDblink() { 1455 1456 return dblink; 1457 } 1458 1459 /** 1460 * The database part of this objectName: [server.][database.][schema.]object 1461 * 1462 * @return database part of the objectName 1463 */ 1464 public TSourceToken getDatabaseToken() { 1465 return databaseToken; 1466 } 1467 1468 1469 private boolean tableDetermined = true; 1470 1471 public void setTableDetermined(boolean tableDetermined) { 1472 this.tableDetermined = tableDetermined; 1473 } 1474 1475 1476 /** 1477 * Sometime, a non-qualified column can't be linked to a table without additional metadata from database. 1478 * <pre> 1479 * select name from emp, dept 1480 * </pre> 1481 * In the above SQL, the <code>name</code> column can't be determined which table it belongs to. 1482 * 1483 * Below is a more complicated SQL that shows the relationship between column and table. 1484 * <pre> 1485 * select 1486 * s2.s2t1a1, 1487 * s3.s3t1a1 1488 * from 1489 * ( 1490 * select * 1491 * from subselect2table1 s2t1 1492 * ) s2, 1493 * ( 1494 * select * 1495 * from subselect3table1, subselect3table2 1496 * ) s3 1497 * </pre> 1498 * 1499 * column s2t1a1 was linked to subselect2table1, {@link #isTableDetermined()} returns true for this column. 1500 * <br> column s3t1a1 was linked to both subselect3table1 and subselect3table2 1501 * due to lack of meta information from database, {@link #isTableDetermined()} returns false for this column. 1502 * <p> 1503 * Provide database metadata will help GSP links the column to the table correctly. 1504 * 1505 * @return true if this column can be linked to a table without doubt. 1506 * @see gudusoft.gsqlparser.TGSqlParser#setMetaDatabase 1507 */ 1508 public boolean isTableDetermined() { 1509 return tableDetermined; 1510 } 1511 1512 /** 1513 * used in Oracle and teradata SQL syntax 1514 * <p>teradata: 1515 * <p>column.attribute() 1516 * <p>column.attribute().attribute() 1517 * @param attributes 1518 */ 1519 public void attributesToPropertyToken(TObjectNameList attributes){ 1520 if (attributes.size() == 1){ 1521 this.propertyToken = attributes.getObjectName(0).getPartToken(); 1522 } 1523 } 1524 1525 public void setColumnAttributes(TObjectNameList columnAttributes) { 1526 this.columnAttributes = columnAttributes; 1527 } 1528 1529 /** 1530 * The data type of this column is structured UDT, this method returns the column's attributes. 1531 * Below is the sample SQL from <a href="https://info.teradata.com/HTMLPubs/DB_TTU_16_00/index.html#page/SQL_Reference/B035-1146-160K/fyj1472240813334.html">teradata</a>. 1532 * <pre> 1533 * 1534 * CREATE TYPE school_record AS ( 1535 * school_name VARCHAR(20), 1536 * GPA FLOAT); 1537 * 1538 * CREATE TYPE college_record AS ( 1539 * school school_record, 1540 * major VARCHAR(20), 1541 * minor VARCHAR(20)); 1542 * 1543 * CREATE TABLE student_record ( 1544 * student_id INTEGER, 1545 * Last_name VARCHAR(20), 1546 * First_name VARCHAR(20), 1547 * high_school school_record, 1548 * college college_record); 1549 * 1550 * SELECT student_id, last_name, first_name, 1551 * high_school.school_name(), high_school.GPA(), 1552 * college.school().school_name(), college.school().GPA(), 1553 * college.major(), college.minor() 1554 * FROM student_record; 1555 * 1556 * SELECT *.ALL FROM student_record; 1557 * SELECT student_record.*.ALL; 1558 * </pre> 1559 * Take this column <code>college.school().school_name()</code> for example, the partToken of this objectName 1560 * should be <code>college</code>, and the value returned by this method should be 1561 * <code>school().school_name()</code> 1562 * <p> 1563 * PLEASE NOTE THAT CURRENT VERSION CAN'T HANDLE THE ABOVE SQL CORRECTLY. 1564 * 1565 * @return attributes of this structured UDT column 1566 */ 1567 public TObjectNameList getColumnAttributes() { 1568 return columnAttributes; 1569 } 1570 1571 /** 1572 * Used internally. 1573 * @deprecated use {@link #setDbObjectType} instead 1574 * 1575 * @param objectType object type of this objectName 1576 */ 1577 public void setObjectType(int objectType) { 1578 if (this.objectType == objectType) return; 1579 this.objectType = objectType; 1580 // set this object type to source token 1581 switch(this.getObjectType()){ 1582 case TObjectName.ttobjTable: 1583 // case TObjectName.ttobjTableTemp: 1584 // case TObjectName.ttobjTableVar: 1585 this.parseTablename(); 1586 this.objectToken.setDbObjType(this.objectType); 1587 if (dbObjectType != EDbObjectType.stage){ // not already set to stage 1588 dbObjectType = EDbObjectType.table; 1589 } 1590 1591 if ((!TSQLEnv.supportSchema(this.dbvendor))&&(this.schemaToken != null)){ 1592 this.databaseToken = this.schemaToken; 1593 this.schemaToken = null; 1594 } 1595 break; 1596// case TObjectName.ttobjTableCTE: 1597// this.parseTablename(); 1598// this.objectToken.setDbObjType(this.objectType); 1599// dbObjectType = EDbObjectType.cte; 1600// break; 1601// case ttObjLibrary: 1602// this.parseTablename(); 1603// this.objectToken.setDbObjType(this.objectType); 1604// dbObjectType = EDbObjectType.library; 1605// break; 1606 case TObjectName.ttobjColumn: 1607 this.partToken.setDbObjType(this.objectType); 1608 dbObjectType = EDbObjectType.column; 1609 break; 1610 case TObjectName.ttobjColumnAlias: 1611 if ((this.objectToken == null) && (this.partToken != null)){ 1612 this.parseObjectName(); 1613 } 1614 this.objectToken.setDbObjType(this.objectType); 1615 dbObjectType = EDbObjectType.column_alias; 1616 break; 1617// case TObjectName.ttObjTableAlias: 1618// this.parseObjectName(); 1619// this.objectToken.setDbObjType(this.objectType); 1620// dbObjectType = EDbObjectType.table_alias; 1621// break; 1622 case TObjectName.ttobjParameter: 1623 this.parseObjectName(); 1624 this.objectToken.setDbObjType(this.objectType); 1625 dbObjectType = EDbObjectType.parameter; 1626 break; 1627 case TObjectName.ttobjVariable: 1628 this.parseVariableName(); 1629 this.objectToken.setDbObjType(this.objectType); 1630 dbObjectType = EDbObjectType.variable; 1631 break; 1632 case TObjectName.ttobjColumnMethod: 1633 if (dbObjectType != EDbObjectType.method){ 1634 this.parseColumnMethodName(); 1635 this.partToken.setDbObjType(this.ttobjColumn); 1636 this.methodToken.setDbObjType(this.ttobjColumnMethod); 1637 dbObjectType = EDbObjectType.method; 1638 } 1639 break; 1640// case TObjectName.ttobjProcedureName: 1641// this.parseFunctionName(); 1642// this.objectToken.setDbObjType(this.objectType); 1643// dbObjectType = EDbObjectType.procedure; 1644// break; 1645 case TObjectName.ttobjFunctionName: 1646 this.parseFunctionName(); 1647 this.objectToken.setDbObjType(this.objectType); 1648 dbObjectType = EDbObjectType.function; 1649 break; 1650// case TObjectName.ttobjLabelName: 1651// this.parseObjectName(); 1652// this.objectToken.setDbObjType(this.objectType); 1653// dbObjectType = EDbObjectType.label; 1654// break; 1655// case TObjectName.ttobjIndexName: 1656// this.parseObjectName(); 1657// this.objectToken.setDbObjType(this.objectType); 1658// dbObjectType = EDbObjectType.index; 1659// break; 1660// case TObjectName.ttobjMaterializedViewName: 1661// this.parseObjectName(); 1662// this.objectToken.setDbObjType(this.objectType); 1663// dbObjectType = EDbObjectType.materializedView; 1664// break; 1665// case TObjectName.ttobjViewName: 1666// this.parseObjectName(); 1667// this.objectToken.setDbObjType(this.objectType); 1668// dbObjectType = EDbObjectType.view; 1669// break; 1670// case TObjectName.ttobjCursorName: 1671// this.parseObjectName(); 1672// this.objectToken.setDbObjType(this.objectType); 1673// dbObjectType = EDbObjectType.cursor; 1674// break; 1675 case TObjectName.ttobjConstraintName: 1676 this.parseObjectName(); 1677 this.objectToken.setDbObjType(this.objectType); 1678 dbObjectType = EDbObjectType.constraint; 1679 break; 1680// case TObjectName.ttobjPropertyName: 1681// this.propertyToken.setDbObjType(this.objectType); 1682// dbObjectType = EDbObjectType.property; 1683// break; 1684// case TObjectName.ttobjTransactionName: 1685// this.parseObjectName(); 1686// this.objectToken.setDbObjType(this.objectType); 1687// dbObjectType = EDbObjectType.transaction; 1688// break; 1689// case TObjectName.ttobjDatabaseName: 1690// this.parseObjectName(); 1691// this.objectToken.setDbObjType(this.objectType); 1692// dbObjectType = EDbObjectType.database; 1693// break; 1694 case TObjectName.ttobjStringConstant: 1695 this.parseObjectName(); 1696 this.objectToken.setDbObjType(this.objectType); 1697 break; 1698// case TObjectName.ttobjAliasName: 1699// this.parseObjectName(); 1700// this.objectToken.setDbObjType(this.objectType); 1701// dbObjectType = EDbObjectType.alias; 1702// break; 1703 case TObjectName.ttobjAttribute: 1704 this.partToken.setDbObjType(this.objectType); 1705 dbObjectType = EDbObjectType.attribute; 1706 break; 1707 1708 case TObjectName.ttobjPositionalParameters: 1709 dbObjectType = EDbObjectType.parameter; 1710 break; 1711// case TObjectName.ttobjTypeName: 1712// this.parseObjectName(); 1713// this.objectToken.setDbObjType(this.objectType); 1714// dbObjectType = EDbObjectType.user_defined_type; 1715// break; 1716// case TObjectName.ttobjPackage: 1717// this.parseObjectName(); 1718// this.objectToken.setDbObjType(this.objectType); 1719// dbObjectType = EDbObjectType.plsql_package; 1720// break; 1721// case TObjectName.ttobjSequence: 1722// this.parseObjectName(); 1723// this.objectToken.setDbObjType(this.objectType); 1724// dbObjectType = EDbObjectType.sequence; 1725// break; 1726// case TObjectName.ttobjTrigger: 1727// this.parseObjectName(); 1728// this.objectToken.setDbObjType(this.objectType); 1729// dbObjectType = EDbObjectType.trigger; 1730// break; 1731 default: 1732 break; 1733 } 1734 } 1735 1736 public void setDbObjectType(EDbVendor dbVendor, EDbObjectType dbObjectType) { 1737 this.dbvendor = dbVendor; 1738 this.setDbObjectType(dbObjectType); 1739 } 1740 1741 public void setDbObjectTypeDirectly(EDbObjectType dbObjectType) { 1742 this.dbObjectType = dbObjectType; 1743 } 1744 /** 1745 * Set object type of this objectName 1746 * 1747 * @param dbObjectType database object type 1748 */ 1749 public void setDbObjectType(EDbObjectType dbObjectType) { 1750 if (this.dbObjectType == dbObjectType) return; 1751 if (this.dbObjectType == EDbObjectType.stage) return; 1752 // TODO, 如果已经被设定为某个对象类型,不应该再次设置,但如果下面的语句执行,会导致部分测试用例失败,需要查具体原因 1753 // if (this.dbObjectType != EDbObjectType.unknown) return; 1754 1755 EDbObjectType prev = this.dbObjectType; 1756 this.dbObjectType = dbObjectType; 1757 if (prev == EDbObjectType.unknown){ 1758 switch (dbObjectType){ 1759 case column: 1760 parseColumnName(); 1761 break; 1762 case table: 1763 case index: 1764 case synonym: 1765 case macro: 1766 case view: 1767 case stage: 1768 case task: 1769 case stream: 1770 case TEMP_TABLE: 1771 case pipe: 1772 case security_policy: 1773 1774 case plsql_package: 1775 case trigger: 1776 case transaction: 1777 case user_defined_type: 1778 case property: 1779 case cursor: 1780 case label: 1781 case table_alias: 1782 case partitionScheme: 1783 parseTablename(); 1784 break; 1785 case library: 1786 parseTablename(); 1787 break; 1788 case function: 1789 parseFunctionName(); 1790 break; 1791 case procedure: 1792 case materializedView: 1793 parseFunctionName(); 1794 break; 1795 case alias: 1796 case module: 1797 case sequence: 1798 parseTablename(); 1799 break; 1800 case database: 1801 this.objectToken = this.partToken; 1802 this.databaseToken = null; 1803 this.partToken = null; 1804 break; 1805 case variable: 1806 parseVariableName(); 1807 break; 1808 case schema: 1809 this.databaseToken = this.objectToken; 1810 this.objectToken = this.partToken; 1811 this.schemaToken = this.partToken; 1812 break; 1813 case method: 1814 this.parseColumnMethodName(); 1815 this.partToken.setDbObjType(this.ttobjColumn); 1816 //this.methodToken.setDbObjType(this.ttobjColumnMethod); 1817 this.methodToken.setDbObjectType(EDbObjectType.method); 1818 break; 1819 case cte: 1820 parseObjectName(); 1821 break; 1822 case hint: //sql server hint like nolock 1823 parseObjectName(); 1824 break; 1825 default: 1826 break; 1827 } 1828 } 1829 } 1830 1831 private EDbObjectType dbObjectType = EDbObjectType.unknown; 1832 1833 /** 1834 * The database object type of this objectName such as table, view, column for example. 1835 * If object type is {@link gudusoft.gsqlparser.EDbObjectType#column}, {@link #getPartToken} represents 1836 * the column name, for all other object type, the name of this database object is stored in {@link #getObjectToken} 1837 * 1838 * @return database object type 1839 */ 1840 public EDbObjectType getDbObjectType() { 1841 return dbObjectType; 1842 } 1843 1844 /** 1845 * @deprecated use {@link #getDbObjectType()} instead. 1846 * 1847 * @return the type of database object or variable this objectName represents for. 1848 */ 1849 public int getObjectType() { 1850 1851 return objectType; 1852 } 1853 1854 1855 public void setAtsign(TSourceToken atsign) { 1856 this.atsign = atsign; 1857 } 1858 1859 public void setDblink(TObjectName dblink) { 1860 dblink.setDbObjectType(EDbObjectType.dblink); 1861 this.dblink = dblink; 1862 } 1863 1864 public void setDblink(TObjectName dblink, boolean linkToDB) { 1865 setDblink(dblink); 1866 1867 if (linkToDB){ 1868 if (dblink.numberOfPart == 1){ 1869 this.databaseToken = dblink.getPartToken(); 1870 } 1871 } 1872 } 1873 1874 private TSourceToken serverToken = null; //sql server 1875 private TSourceToken databaseToken = null; //sql server 1876 // schemaToken.objectToken.partToken@dblink, schemaToken, partToken, and dblink is optional 1877 private TSourceToken schemaToken; 1878 private TSourceToken objectToken; 1879 1880 /* 1881 * part is a part of the object. This identifier lets you refer to a part of a schema object, 1882 * such as a column or a partition of a table. Not all types of objects have parts. 1883 */ 1884 private TSourceToken partToken; 1885 private TSourceToken propertyToken = null; 1886 private TSourceToken methodToken = null; 1887 private TSourceToken atsign; //@ 1888 private TObjectName dblink; 1889 1890 // ===== Phase 5: Normalized identifier cache (transient, not serialized) ===== 1891 // These caches reduce repeated normalize() calls for the same TObjectName 1892 private transient String normalizedServer; 1893 private transient String normalizedDatabase; 1894 private transient String normalizedSchema; 1895 private transient String normalizedTable; 1896 private transient String normalizedColumn; 1897 private transient long cacheFingerprint = 0; // Profile fingerprint for cache invalidation 1898 1899 public void setServerToken(TSourceToken serverToken) { 1900 this.serverToken = serverToken; 1901 } 1902 1903 public void setDatabaseToken(TSourceToken databaseToken, boolean implicit) { 1904 this.isImplicitDatabase = implicit; 1905 setDatabaseToken(databaseToken); 1906 } 1907 1908 public void setDatabaseToken(TSourceToken databaseToken) { 1909 this.databaseToken = databaseToken; 1910 } 1911 1912 public void setObjectToken(TSourceToken objectToken) { 1913 this.objectToken = objectToken; 1914 } 1915 1916 public void setPartToken(TSourceToken partToken) { 1917 this.partToken = partToken; 1918 } 1919 1920 public void setMethodToken(TSourceToken methodToken) { 1921 this.methodToken = methodToken; 1922 } 1923 1924 public void setSchemaToken(TSourceToken schemaToken, boolean implicit) { 1925 this.isImplicitSchema = implicit; 1926 setSchemaToken(schemaToken); 1927 } 1928 1929 public void setSchemaToken(TSourceToken schemaToken) { 1930 1931 this.schemaToken = schemaToken; 1932 } 1933 1934 public void setPackageToken(TSourceToken packageToken) { 1935 this.packageToken = packageToken; 1936 } 1937 1938 /** 1939 * Oracle package name 1940 * 1941 * @return the source token of Oracle package name. 1942 */ 1943 public TSourceToken getPackageToken() { 1944 return packageToken; 1945 } 1946 1947 private TSourceToken packageToken = null; 1948 1949 1950 /** 1951 * The object part of this objectName such as table name, view name. 1952 * 1953 * @return object part of this objectName 1954 */ 1955 public TSourceToken getObjectToken() { 1956 return objectToken; 1957 } 1958 1959 /** 1960 * The column name of this objectName if {@link #getDbObjectType} is {@link EDbObjectType#column}. 1961 * {@link #getColumnToken} returns the same value. 1962 * 1963 * @return the column name 1964 */ 1965 public TSourceToken getPartToken() { 1966 return partToken; 1967 } 1968 1969 /** 1970 * The schema name of this objectName. 1971 * 1972 * @return schema name 1973 */ 1974 public TSourceToken getSchemaToken() { 1975 return schemaToken; 1976 } 1977 1978 1979 private String schemaString; 1980 private String objectString; 1981 private String partString; 1982 1983 /** 1984 * String text of the package name. 1985 * 1986 * @return string of the package name,return null if empty. 1987 */ 1988 public String getPackageString(){ 1989 if (getPackageToken() != null) return getPackageToken().toString(); 1990 else return ""; 1991 } 1992 1993 /** 1994 * String text of the server name 1995 * 1996 * @return string of the server name,return null if empty. 1997 */ 1998 public String getServerString(){ 1999 if (getServerToken() != null) return getServerToken().toString(); 2000 else return ""; 2001 } 2002 2003 /** 2004 * String text of the database name 2005 * 2006 * @return string of the database name,return null if empty. 2007 */ 2008 public String getDatabaseString(){ 2009 if (isImplicitDatabase ) return ""; 2010 else if (getDatabaseToken() != null) return getDatabaseToken().toString(); 2011 else if ((this.dbObjectType == EDbObjectType.database) && (getObjectToken() != null)){ 2012 return getObjectToken().toString(); 2013 } 2014 else return ""; 2015 } 2016 2017 /** 2018 * String text of schema name in a qualified name of a schema object. 2019 * 2020 * 2021 * @return string of schema name, return null if empty. 2022 */ 2023 public String getSchemaString() { 2024 if (isImplicitSchema) return ""; 2025 else if (schemaToken != null) 2026 return schemaToken.getAstext(); 2027 else 2028 return "" ; 2029 } 2030 2031 private TSQLEnv sqlEnv = null; 2032 2033 public void setSqlEnv(TSQLEnv sqlEnv) { 2034 this.sqlEnv = sqlEnv; 2035 } 2036 2037 2038 2039 /** 2040 * This is the schema fetched from the SQLEnv. Not the direct qualified schema name of this object 2041 * search this table in the current default database and schema. 2042 * 2043 * If this is a qualified schema object, then return {@link #getSchemaString()} 2044 * 2045 * This method is only valid when the {@link #dbObjectType} is a schema object. 2046 * 2047 * @return schema name fetched from the SQLEnv 2048 */ 2049 public String getImplictSchemaString() { 2050 String implictSchema = null; 2051 if (this.implictSchemaName != null) return this.implictSchemaName; 2052 2053 if (schemaToken != null) return schemaToken.toString(); 2054 if (getSchemaString().length() > 0) return getSchemaString(); 2055 2056 if (sqlEnv == null) return null; 2057 2058 TSQLSchema s = searchImplicitSchema(); 2059 if (s != null){ 2060 implictSchema = s.getName(); 2061 } 2062 2063 return implictSchema; 2064 } 2065 2066 private String implictDatabaseName; 2067 private String implictSchemaName; 2068 2069 public void setImplictDatabaseName(String implictDatabaseName) { 2070 this.isImplicitDatabase = true; 2071 this.implictDatabaseName = implictDatabaseName; 2072 } 2073 2074 public void setImplictSchemaName(String implictSchemaName) { 2075 this.isImplicitSchema = true; 2076 this.implictSchemaName = implictSchemaName; 2077 } 2078 2079 public String getImplictDatabaseString() { 2080 String implictDatabase = null; 2081 if (implictDatabaseName != null) return implictDatabaseName; 2082 2083 if (getDatabaseString().length() > 0) return getDatabaseString(); 2084 2085 if (sqlEnv == null) return null; 2086 TSQLSchema s = searchImplicitSchema(); 2087 if (s != null){ 2088 TSQLCatalog c = s.getCatalog(); 2089 if (c != null){ 2090 implictDatabase = c.getName(); 2091 } 2092 } 2093 2094 return implictDatabase; 2095 } 2096 2097 protected TSQLSchema searchImplicitSchema(){ 2098 TSQLSchema s = null; 2099 if (sqlEnv == null) return null; 2100 switch (dbObjectType){ 2101 case table: 2102 case view: 2103 TSQLTable t = sqlEnv.searchTable(".."+this.getObjectString()); 2104 if (t != null){ 2105 s = t.getSchema(); 2106 } 2107 2108 break; 2109 case function: 2110 case procedure: 2111 TSQLFunction f = sqlEnv.searchFunction(".."+this.getObjectString()); 2112 if (f != null){ 2113 s = f.getSchema(); 2114 } 2115 break; 2116 default: 2117 break; 2118 } 2119 2120 return s; 2121 } 2122 2123 /** 2124 * The table name of this objectName, it's the same value as {@link #getObjectToken} if {@link #getDbObjectType} 2125 * is {@link gudusoft.gsqlparser.EDbObjectType#table} 2126 * 2127 * @return table name 2128 */ 2129 public TSourceToken getTableToken(){ 2130 if (objectToken == null) return null; 2131 else return objectToken; 2132 } 2133 2134 /** 2135 * String text of the table name 2136 * 2137 * @return string of the table name, return null if empty. 2138 */ 2139 public String getTableString(){ 2140 if (objectToken == null) return ""; 2141// else if (!((dbObjectType == EDbObjectType.table)||(dbObjectType == EDbObjectType.view))){ 2142// return ""; 2143// } 2144 else return objectToken.toString(); 2145 } 2146 2147 /** 2148 * String text of the object name 2149 * 2150 * @return string of the object name, return null if empty. 2151 */ 2152 public String getObjectString() { 2153 if (objectToken != null) 2154 return objectToken.getAstext(); 2155 else 2156 return "" ; 2157 } 2158 2159 /** 2160 * String text of the part name 2161 * 2162 * @return string of the part name, return null if empty. 2163 */ 2164 public String getPartString() { 2165 if (partToken != null) 2166 return partToken.getAstext(); 2167 else 2168 return "" ; 2169 } 2170 2171 // ===== Phase 5: Cached normalized getters (reduce repeated normalize() calls) ===== 2172 2173 private transient gudusoft.gsqlparser.sqlenv.IdentifierService identifierService; 2174 2175 /** 2176 * Lazy initialization of IdentifierService for normalized identifier caching 2177 */ 2178 private gudusoft.gsqlparser.sqlenv.IdentifierService getIdentifierService() { 2179 if (identifierService == null && sqlEnv != null) { 2180 gudusoft.gsqlparser.sqlenv.IdentifierProfile profile = gudusoft.gsqlparser.sqlenv.IdentifierProfile.forVendor( 2181 sqlEnv.getDBVendor(), 2182 gudusoft.gsqlparser.sqlenv.IdentifierProfile.VendorFlags.defaults() 2183 ); 2184 identifierService = new gudusoft.gsqlparser.sqlenv.IdentifierService(profile, null); 2185 } 2186 return identifierService; 2187 } 2188 2189 /** 2190 * Get normalized database string with caching (Phase 5 optimization). 2191 * 2192 * <p>This method caches the normalized database name to avoid repeated normalize() calls. 2193 * The cache is invalidated automatically when the IdentifierProfile changes (e.g., vendor switch). 2194 * 2195 * @return normalized database name, or empty string if not available 2196 */ 2197 public String getNormalizedDatabaseString() { 2198 if (sqlEnv == null) return getDatabaseString(); 2199 2200 try { 2201 gudusoft.gsqlparser.sqlenv.IdentifierService service = getIdentifierService(); 2202 if (service == null) return getDatabaseString(); 2203 2204 long currentFingerprint = service.getProfile().getFingerprint(); 2205 2206 // Check if cache is valid (not null and fingerprint matches) 2207 if (normalizedDatabase == null || cacheFingerprint != currentFingerprint) { 2208 String raw = getDatabaseString(); 2209 if (raw != null && !raw.isEmpty()) { 2210 normalizedDatabase = service.normalize(raw, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType.dotCatalog); 2211 } else { 2212 normalizedDatabase = ""; 2213 } 2214 cacheFingerprint = currentFingerprint; 2215 } 2216 2217 return normalizedDatabase; 2218 } catch (Throwable t) { 2219 // Fallback to non-cached on any error 2220 return getDatabaseString(); 2221 } 2222 } 2223 2224 /** 2225 * Get normalized schema string with caching (Phase 5 optimization). 2226 * 2227 * <p>This method caches the normalized schema name to avoid repeated normalize() calls. 2228 * The cache is invalidated automatically when the IdentifierProfile changes. 2229 * 2230 * @return normalized schema name, or empty string if not available 2231 */ 2232 public String getNormalizedSchemaString() { 2233 if (sqlEnv == null) return getSchemaString(); 2234 2235 try { 2236 gudusoft.gsqlparser.sqlenv.IdentifierService service = getIdentifierService(); 2237 if (service == null) return getSchemaString(); 2238 2239 long currentFingerprint = service.getProfile().getFingerprint(); 2240 2241 // Check if cache is valid 2242 if (normalizedSchema == null || cacheFingerprint != currentFingerprint) { 2243 String raw = getSchemaString(); 2244 if (raw != null && !raw.isEmpty()) { 2245 normalizedSchema = service.normalize(raw, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType.dotSchema); 2246 } else { 2247 normalizedSchema = ""; 2248 } 2249 cacheFingerprint = currentFingerprint; 2250 } 2251 2252 return normalizedSchema; 2253 } catch (Throwable t) { 2254 // Fallback to non-cached 2255 return getSchemaString(); 2256 } 2257 } 2258 2259 /** 2260 * Get normalized table string with caching (Phase 5 optimization). 2261 * 2262 * <p>This method caches the normalized table name to avoid repeated normalize() calls. 2263 * The cache is invalidated automatically when the IdentifierProfile changes. 2264 * 2265 * @return normalized table name, or empty string if not available 2266 */ 2267 public String getNormalizedTableString() { 2268 if (sqlEnv == null) return getTableString(); 2269 2270 try { 2271 gudusoft.gsqlparser.sqlenv.IdentifierService service = getIdentifierService(); 2272 if (service == null) return getTableString(); 2273 2274 long currentFingerprint = service.getProfile().getFingerprint(); 2275 2276 // Check if cache is valid 2277 if (normalizedTable == null || cacheFingerprint != currentFingerprint) { 2278 String raw = getTableString(); 2279 if (raw != null && !raw.isEmpty()) { 2280 normalizedTable = service.normalize(raw, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType.dotTable); 2281 } else { 2282 normalizedTable = ""; 2283 } 2284 cacheFingerprint = currentFingerprint; 2285 } 2286 2287 return normalizedTable; 2288 } catch (Throwable t) { 2289 // Fallback to non-cached 2290 return getTableString(); 2291 } 2292 } 2293 2294 /** 2295 * Get normalized column string with caching (Phase 5 optimization). 2296 * 2297 * <p>This method caches the normalized column name (from partToken) to avoid repeated normalize() calls. 2298 * The cache is invalidated automatically when the IdentifierProfile changes. 2299 * 2300 * @return normalized column name, or empty string if not available 2301 */ 2302 public String getNormalizedColumnString() { 2303 if (sqlEnv == null) return getPartString(); 2304 2305 try { 2306 gudusoft.gsqlparser.sqlenv.IdentifierService service = getIdentifierService(); 2307 if (service == null) return getPartString(); 2308 2309 long currentFingerprint = service.getProfile().getFingerprint(); 2310 2311 // Check if cache is valid 2312 if (normalizedColumn == null || cacheFingerprint != currentFingerprint) { 2313 String raw = getPartString(); 2314 if (raw != null && !raw.isEmpty()) { 2315 normalizedColumn = service.normalize(raw, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType.dotColumn); 2316 } else { 2317 normalizedColumn = ""; 2318 } 2319 cacheFingerprint = currentFingerprint; 2320 } 2321 2322 return normalizedColumn; 2323 } catch (Throwable t) { 2324 // Fallback to non-cached 2325 return getPartString(); 2326 } 2327 } 2328 2329 /** 2330 * Get normalized server string with caching (Phase 5 optimization). 2331 * 2332 * <p>This method caches the normalized server name to avoid repeated normalize() calls. 2333 * The cache is invalidated automatically when the IdentifierProfile changes. 2334 * 2335 * @return normalized server name, or empty string if not available 2336 */ 2337 public String getNormalizedServerString() { 2338 if (sqlEnv == null) return getServerString(); 2339 2340 try { 2341 gudusoft.gsqlparser.sqlenv.IdentifierService service = getIdentifierService(); 2342 if (service == null) return getServerString(); 2343 2344 long currentFingerprint = service.getProfile().getFingerprint(); 2345 2346 // Check if cache is valid 2347 if (normalizedServer == null || cacheFingerprint != currentFingerprint) { 2348 String raw = getServerString(); 2349 if (raw != null && !raw.isEmpty()) { 2350 // Use dotUnknown for server since there's no dotServer type 2351 normalizedServer = service.normalize(raw, gudusoft.gsqlparser.sqlenv.ESQLDataObjectType.dotUnknown); 2352 } else { 2353 normalizedServer = ""; 2354 } 2355 cacheFingerprint = currentFingerprint; 2356 } 2357 2358 return normalizedServer; 2359 } catch (Throwable t) { 2360 // Fallback to non-cached 2361 return getServerString(); 2362 } 2363 } 2364 2365 2366 public void setExclamationmark(TSourceToken exclamationmark) { 2367 this.exclamationmark = exclamationmark; 2368 } 2369 2370 private TSourceToken exclamationmark; // objectToken@!, ! is dblink 2371 2372 private Boolean isParsed = false; 2373 2374 private void parseObjectName(){ 2375 parseTablename(); 2376 } 2377 2378 private void parseTablename(){ 2379 if ((this.dbObjectType == EDbObjectType.variable) ||(this.dbObjectType == EDbObjectType.stage))return; 2380 2381 switch (this.dbvendor){ 2382 case dbvteradata: 2383 case dbvhive: 2384 if (objectToken != null){ 2385 databaseToken = objectToken; 2386 //databaseToken.setDbObjType(TObjectName.ttobjDatabaseName); 2387 databaseToken.setDbObjectType(EDbObjectType.database); 2388 } 2389 objectToken = partToken; 2390 partToken = null; 2391 2392 break; 2393 default: 2394 if (databaseToken != null){ 2395 serverToken = databaseToken; 2396 //serverToken.setDbObjType(TObjectName.ttobjServerName); 2397 serverToken.setDbObjectType(EDbObjectType.server); 2398 } 2399 2400 if (schemaToken != null){ 2401 databaseToken = schemaToken; 2402 //databaseToken.setDbObjType(TObjectName.ttobjDatabaseName); 2403 databaseToken.setDbObjectType(EDbObjectType.database); 2404 } 2405 2406 if (objectToken != null){ 2407 schemaToken = objectToken; 2408 schemaToken.setDbObjType(TObjectName.ttobjSchemaName); 2409 } 2410 2411 objectToken = partToken; 2412 partToken = null; 2413 break; 2414 } 2415 2416 if (objectToken != null){ 2417 objectToken.setDbObjectType(this.dbObjectType); 2418 } 2419 } 2420 2421 private void parseVariableName(){ 2422 if (databaseToken != null){ 2423 serverToken = databaseToken; 2424 //serverToken.setDbObjType(TObjectName.ttobjServerName); 2425 serverToken.setDbObjectType(EDbObjectType.server); 2426 } 2427 2428 if (schemaToken != null){ 2429 databaseToken = schemaToken; 2430 // databaseToken.setDbObjType(TObjectName.ttobjDatabaseName); 2431 databaseToken.setDbObjectType(EDbObjectType.database); 2432 } 2433 2434 if (objectToken != null){ 2435 if (partToken != null){ 2436 schemaToken = objectToken; 2437 schemaToken.setDbObjType(TObjectName.ttobjSchemaName); 2438 objectToken = partToken; 2439 partToken = null; 2440 }else{ 2441 2442 } 2443 }else{ 2444 objectToken = partToken; 2445 partToken = null; 2446 } 2447 } 2448 2449 private String ansiSchemaName; 2450 private String ansiCatalogName; 2451 2452 2453 /** 2454 * In this SQL: select * from part1.part2, 2455 * In Hive, MySQL and Teradata, part1 will be treated as a database name, returned in getDatabaseString(), 2456 * while getSchemaString() return empty string. 2457 * 2458 * However, TObjectName.getAnsiSchemaName() will return part1, which means it's a schema name. 2459 * 2460 * If a table name is not qualified with a schema name, but GSP detect the schema for this table in the metadata 2461 * then, this method will return this detected schema name. 2462 * 2463 * @return schema name 2464 */ 2465 public String getAnsiSchemaName(){ 2466 String ret = this.getSchemaString(); 2467 if ((ret.length() == 0) && ((this.getImplictSchemaString() != null) && (!this.getImplictSchemaString().equalsIgnoreCase("default")))){ 2468 ret = this.getImplictSchemaString(); 2469 } 2470 2471 switch (dbvendor){ 2472 case dbvmysql: 2473 case dbvhive: 2474 case dbvteradata: 2475 case dbvimpala: 2476 ret = this.getDatabaseString(); 2477 break; 2478 } 2479 return ret; 2480 } 2481 2482 /** 2483 * If a table name is not qualified with a database name, but GSP detect the database for this table in the metadata 2484 * then, this method will return this detected database name. 2485 * 2486 * @return 2487 */ 2488 public String getAnsiCatalogName(){ 2489 String ret = this.getDatabaseString(); 2490 if (( ret.length() == 0) && (this.getImplictDatabaseString() != null) && (!this.getImplictDatabaseString().equalsIgnoreCase("default"))){ 2491 ret = this.getImplictDatabaseString(); 2492 } 2493 2494 switch (dbvendor){ 2495 case dbvmysql: 2496 case dbvhive: 2497 case dbvteradata: 2498 case dbvimpala: 2499 ret = ""; 2500 break; 2501 } 2502 2503 return ret; 2504 } 2505 2506 private void parseFunctionName(){ 2507 this.parseTablename(); 2508 } 2509 2510 private void parseColumnMethodName(){ 2511 // objectType = ttobjColumnMethod; 2512 2513 methodToken = objectToken; 2514 partToken = schemaToken; 2515 2516 objectToken = null;//; 2517 schemaToken = null; 2518 } 2519 2520 private void parseColumnName(){ 2521 assert(partToken != null); 2522 } 2523 2524 public TObjectName(){ 2525 } 2526 2527 /** 2528 * List the number of parts made up this objectName 2529 * 2530 * @return the number of parts that made up this objectName 2531 */ 2532 public int getNumberOfPart() { 2533 return numberOfPart; 2534 } 2535 2536 private int numberOfPart = 1; 2537 2538 public static TObjectName createObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType){ 2539 return new TObjectName(dbVendor,dbObjectType); 2540 } 2541 2542 2543 public static TObjectName createObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType,TSourceToken token1){ 2544 return new TObjectName(dbVendor,dbObjectType,token1); 2545 } 2546 2547 public static TObjectName createObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType, String str) { 2548 String[] parts = str.split("\\."); 2549 if (parts.length == 1) { 2550 return new TObjectName(dbVendor, dbObjectType, new TSourceToken(parts[0])); 2551 } else if (parts.length == 2) { 2552 return new TObjectName(dbVendor, dbObjectType, new TSourceToken(parts[0]), new TSourceToken(parts[1])); 2553 } else if (parts.length == 3) { 2554 return new TObjectName(dbVendor, dbObjectType, new TSourceToken(parts[0]), new TSourceToken(parts[1]), new TSourceToken(parts[2])); 2555 } else if (parts.length == 4) { 2556 return new TObjectName(dbVendor, dbObjectType, new TSourceToken(parts[0]), new TSourceToken(parts[1]), new TSourceToken(parts[2]), new TSourceToken(parts[3])); 2557 } 2558 return new TObjectName(dbVendor, dbObjectType, new TSourceToken(str)); 2559 } 2560 2561 2562 public static TObjectName createObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType,TSourceToken token1,TSourceToken token2){ 2563 return new TObjectName(dbVendor,dbObjectType,token1,token2); 2564 } 2565 2566 public static TObjectName createObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType,TSourceToken token1,TSourceToken token2,TSourceToken token3){ 2567 return new TObjectName(dbVendor,dbObjectType,token1,token2,token3); 2568 } 2569 2570 public static TObjectName createObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType,TSourceToken token1,TSourceToken token2,TSourceToken token3,TSourceToken token4){ 2571 return new TObjectName(dbVendor,dbObjectType,token1,token2,token3,token4); 2572 } 2573 2574 /** 2575 * @deprecated As of v2.0.7.1, please use {@link #TObjectName(EDbObjectType, TSourceToken)} instead. 2576 * 2577 * Class constructor specifying object name and object type. 2578 * <p> 2579 * Use {@link gudusoft.gsqlparser.TGSqlParser#parseObjectName} to create an objectName more than 2 parts. 2580 * 2581 * @param token name of this object 2582 * @param dbObjectType type of this object 2583 */ 2584 private TObjectName(TSourceToken token,EDbObjectType dbObjectType){ 2585 this(dbObjectType,token); 2586 } 2587 2588 public void splitNameInQuotedIdentifier(){ 2589 if (this.dbvendor != EDbVendor.dbvbigquery) return; 2590 if (getQuoteType() == EQuoteType.notQuoted) return; 2591// if ((this.dbvendor != EDbVendor.dbvbigquery) 2592// &&(getQuoteType() == EQuoteType.doubleQuote)) return; 2593 if (this.objectToken == null) return; 2594 TSourceToken token = this.objectToken; 2595 2596 String s = TBaseType.getTextWithoutQuoted(token.toString()); 2597 String[] a = s.split("[.]"); 2598 if (a.length == 1){ 2599 // this.objectToken = token; 2600 }else if (a.length == 2){ 2601 this.objectToken = new TSourceToken(token.toString().charAt(0)+a[1]+token.toString().charAt(0)); 2602 this.schemaToken = new TSourceToken(token.toString().charAt(0)+a[0]+token.toString().charAt(0)); 2603 }else if (a.length == 3){ 2604 this.objectToken = new TSourceToken(token.toString().charAt(0)+a[2]+token.toString().charAt(0)); 2605 this.schemaToken = new TSourceToken(token.toString().charAt(0)+a[1]+token.toString().charAt(0)); 2606 this.databaseToken = new TSourceToken(token.toString().charAt(0)+a[0]+token.toString().charAt(0)); 2607 } 2608 2609 } 2610 2611 private TObjectName(EDbVendor dbVendor){ 2612 this.dbvendor = dbVendor; 2613 } 2614 2615 private TObjectName(EDbVendor dbVendor,EDbObjectType dbObjectType){ 2616 this.dbvendor = dbVendor; 2617 this.dbObjectType = dbObjectType; 2618 } 2619 2620 private TObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType,TSourceToken token){ 2621 this.dbvendor = dbVendor; 2622 numberOfPart = 1; 2623 this.setStartToken(token); 2624 this.setEndToken(token); 2625 2626 this.dbObjectType = dbObjectType; 2627 switch (dbObjectType){ 2628 case column: 2629 this.partToken = token; 2630 break; 2631 case method: 2632 this.methodToken = token; 2633 break; 2634 case table: 2635 case function: 2636 case procedure: 2637 case materializedView: 2638 case alias: 2639 case module: 2640 case sequence: 2641 case collation: 2642 this.objectToken = token; 2643 splitNameInQuotedIdentifier(); 2644 break; 2645 default: 2646 this.objectToken = token; 2647 break; 2648 } 2649 } 2650 2651 private void initWithOneToken(EDbObjectType dbObjectType,TSourceToken token){ 2652 numberOfPart = 1; 2653 this.setStartToken(token); 2654 this.setEndToken(token); 2655 2656 this.dbObjectType = dbObjectType; 2657 switch (dbObjectType){ 2658 case column: 2659 this.partToken = token; 2660 break; 2661 case method: 2662 this.methodToken = token; 2663 break; 2664 case table: 2665 case function: 2666 case procedure: 2667 case materializedView: 2668 case alias: 2669 case module: 2670 case sequence: 2671 case collation: 2672 case stage: 2673 this.objectToken = token; 2674 splitNameInQuotedIdentifier(); 2675 break; 2676 case namespace: 2677 this.schemaToken = token; 2678 break; 2679 default: 2680 this.objectToken = token; 2681 break; 2682 } 2683 } 2684 2685 private void initWithTwoTokens(EDbObjectType dbObjectType,TSourceToken token2,TSourceToken token1){ 2686 initWithOneToken(dbObjectType,token1); 2687 numberOfPart = 2; 2688 this.setStartToken(token2); 2689 this.setEndToken(token1); 2690 2691 switch (dbObjectType){ 2692 case column: 2693 this.objectToken = token2; 2694 break; 2695 case method: 2696 this.partToken = token2; 2697 break; 2698 case table: 2699 case function: 2700 case procedure: 2701 case materializedView: 2702 case alias: 2703 case module: 2704 case sequence: 2705 case collation: 2706 case stage: 2707 this.schemaToken = token2; 2708 break; 2709 case namespace: 2710 this.databaseToken = token2; 2711 break; 2712 default: 2713 this.schemaToken = token2; 2714 break; 2715 } 2716 2717 } 2718 2719 private void initWithThreeTokens(EDbObjectType dbObjectType,TSourceToken token3,TSourceToken token2,TSourceToken token1){ 2720 initWithTwoTokens(dbObjectType,token2,token1); 2721 numberOfPart = 3; 2722 this.setStartToken(token3); 2723 this.setEndToken(token1); 2724 2725 switch (dbObjectType){ 2726 case column: 2727 this.schemaToken = token3; 2728 break; 2729 case method: 2730 this.objectToken = token3; 2731 break; 2732 case table: 2733 case function: 2734 case procedure: 2735 case materializedView: 2736 case alias: 2737 case module: 2738 case sequence: 2739 case collation: 2740 case stage: 2741 this.databaseToken = token3; 2742 break; 2743 default: 2744 this.databaseToken = token3; 2745 break; 2746 } 2747 2748 } 2749 2750 private void initWithFourTokens(EDbObjectType dbObjectType,TSourceToken token4,TSourceToken token3,TSourceToken token2,TSourceToken token1){ 2751 initWithThreeTokens(dbObjectType,token3,token2,token1); 2752 numberOfPart = 4; 2753 this.setStartToken(token4); 2754 this.setEndToken(token1); 2755 2756 switch (dbObjectType){ 2757 case column: 2758 this.databaseToken = token4; 2759 break; 2760 case method: 2761 this.schemaToken = token4; 2762 break; 2763 case table: 2764 case function: 2765 case procedure: 2766 case materializedView: 2767 case alias: 2768 case module: 2769 case sequence: 2770 case collation: 2771 this.serverToken = token4; 2772 break; 2773 default: 2774 this.serverToken = token4; 2775 break; 2776 } 2777 2778 } 2779 2780 /** 2781 * @deprecated As of v2.0.7.1, please use {@link TObjectName#createObjectName(EDbVendor, EDbObjectType, TSourceToken)} instead. 2782 * 2783 * @param dbObjectType 2784 * @param token 2785 */ 2786 private TObjectName(EDbObjectType dbObjectType,TSourceToken token){ 2787 initWithOneToken(dbObjectType,token); 2788 } 2789 2790 private TObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType,TSourceToken token2,TSourceToken token1){ 2791 this(dbVendor,dbObjectType,token1); 2792 numberOfPart = 2; 2793 this.setStartToken(token2); 2794 this.setEndToken(token1); 2795 2796 switch (dbObjectType){ 2797 case column: 2798 this.objectToken = token2; 2799 break; 2800 case method: 2801 this.partToken = token2; 2802 break; 2803 case table: 2804 case function: 2805 case procedure: 2806 case materializedView: 2807 case alias: 2808 case module: 2809 case sequence: 2810 case collation: 2811 if (dbVendor == EDbVendor.dbvteradata){ 2812 this.databaseToken = token2; 2813 }else{ 2814 this.schemaToken = token2; 2815 } 2816 2817 break; 2818 default: 2819 this.schemaToken = token2; 2820 break; 2821 } 2822 2823 } 2824 2825 2826 /** 2827 * @deprecated since ver 2.5.9.8 2828 * 2829 * @param dbObjectType 2830 * @param token2 2831 * @param token1 2832 */ 2833 private TObjectName(EDbObjectType dbObjectType,TSourceToken token2,TSourceToken token1){ 2834 this(dbObjectType,token1); 2835 numberOfPart = 2; 2836 this.setStartToken(token2); 2837 this.setEndToken(token1); 2838 2839 switch (dbObjectType){ 2840 case column: 2841 this.objectToken = token2; 2842 break; 2843 case method: 2844 this.partToken = token2; 2845 break; 2846 case table: 2847 case function: 2848 case procedure: 2849 case materializedView: 2850 case alias: 2851 case module: 2852 case sequence: 2853 case collation: 2854 this.schemaToken = token2; 2855 break; 2856 default: 2857 this.schemaToken = token2; 2858 break; 2859 } 2860 } 2861 private TObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType,TSourceToken token3,TSourceToken token2,TSourceToken token1){ 2862 this(dbVendor,dbObjectType,token2,token1); 2863 numberOfPart = 3; 2864 this.setStartToken(token3); 2865 this.setEndToken(token1); 2866 2867 switch (dbObjectType){ 2868 case column: 2869 this.schemaToken = token3; 2870 break; 2871 case method: 2872 this.objectToken = token3; 2873 break; 2874 case table: 2875 case function: 2876 case procedure: 2877 case materializedView: 2878 case alias: 2879 case module: 2880 case sequence: 2881 case collation: 2882 this.databaseToken = token3; 2883 break; 2884 default: 2885 this.databaseToken = token3; 2886 break; 2887 } 2888 2889 } 2890 2891 2892 /** 2893 * @deprecated since ver 2.5.9.8 2894 * 2895 * @param dbObjectType 2896 * @param token3 2897 * @param token2 2898 * @param token1 2899 */ 2900 private TObjectName(EDbObjectType dbObjectType,TSourceToken token3,TSourceToken token2,TSourceToken token1){ 2901 this(dbObjectType,token2,token1); 2902 numberOfPart = 3; 2903 this.setStartToken(token3); 2904 this.setEndToken(token1); 2905 2906 switch (dbObjectType){ 2907 case column: 2908 this.schemaToken = token3; 2909 break; 2910 case method: 2911 this.objectToken = token3; 2912 break; 2913 case table: 2914 case function: 2915 case procedure: 2916 case materializedView: 2917 case alias: 2918 case module: 2919 case sequence: 2920 case collation: 2921 this.databaseToken = token3; 2922 break; 2923 default: 2924 this.databaseToken = token3; 2925 break; 2926 } 2927 } 2928 2929 private TObjectName(EDbVendor dbVendor, EDbObjectType dbObjectType,TSourceToken token4,TSourceToken token3,TSourceToken token2,TSourceToken token1){ 2930 this(dbVendor,dbObjectType,token3,token2,token1); 2931 numberOfPart = 4; 2932 this.setStartToken(token4); 2933 this.setEndToken(token1); 2934 2935 switch (dbObjectType){ 2936 case column: 2937 this.databaseToken = token4; 2938 break; 2939 case method: 2940 this.schemaToken = token4; 2941 break; 2942 case table: 2943 case function: 2944 case procedure: 2945 case materializedView: 2946 case alias: 2947 case module: 2948 case sequence: 2949 case collation: 2950 this.serverToken = token4; 2951 break; 2952 default: 2953 this.serverToken = token4; 2954 break; 2955 } 2956 2957 } 2958 2959 /** 2960 * @deprecated since ver 2.5.9.8 2961 * 2962 * @param dbObjectType 2963 * @param token4 2964 * @param token3 2965 * @param token2 2966 * @param token1 2967 */ 2968 private TObjectName(EDbObjectType dbObjectType,TSourceToken token4,TSourceToken token3,TSourceToken token2,TSourceToken token1){ 2969 this(dbObjectType,token3,token2,token1); 2970 numberOfPart = 4; 2971 this.setStartToken(token4); 2972 this.setEndToken(token1); 2973 2974 switch (dbObjectType){ 2975 case column: 2976 this.databaseToken = token4; 2977 break; 2978 case method: 2979 this.schemaToken = token4; 2980 break; 2981 case table: 2982 case function: 2983 case procedure: 2984 case materializedView: 2985 case alias: 2986 case module: 2987 case sequence: 2988 case collation: 2989 this.serverToken = token4; 2990 break; 2991 default: 2992 this.serverToken = token4; 2993 break; 2994 } 2995 } 2996 2997 /** 2998 * @deprecated As of v2.0.7.1, please use {@link #TObjectName(EDbObjectType, TSourceToken, TSourceToken)} instead. 2999 * 3000 * Class constructor specifying object, part name and object type. 3001 * Use this constructor to create a <code>table.column</code> objectName. 3002 * Use {@link gudusoft.gsqlparser.TGSqlParser#parseObjectName} to create an objectName more than 2 parts. 3003 * 3004 * @param pObjectToken name of this object, usually it's the table name 3005 * @param pPartToken name of the column 3006 * @param dbObjectType type of this object, usually it's {@link gudusoft.gsqlparser.EDbObjectType#column} 3007 */ 3008 private TObjectName(TSourceToken pObjectToken,TSourceToken pPartToken,EDbObjectType dbObjectType){ 3009 this(dbObjectType,pObjectToken,pPartToken); 3010 } 3011 3012 public void init(Object arg1) 3013 { 3014 partToken = (TSourceToken)arg1; 3015 numberOfPart = 1; 3016 this.setStartToken(partToken); 3017 this.setEndToken(partToken); 3018 } 3019 3020 public void init(Object arg1, Object arg2) 3021 { 3022 if (arg1 instanceof EDbObjectType){ 3023 initWithOneToken((EDbObjectType)arg1,(TSourceToken) arg2); 3024 3025 }else{ 3026 numberOfPart = 0; 3027 objectToken = (TSourceToken)arg1; 3028 partToken = (TSourceToken)arg2; 3029 if (partToken != null) numberOfPart++; 3030 if (objectToken != null) numberOfPart++; 3031 3032 3033 if(objectToken != null){ 3034 this.setStartToken(objectToken); 3035 }else{ 3036 this.setStartToken(partToken); 3037 } 3038 3039 if (partToken != null){ 3040 this.setEndToken(partToken); 3041 }else{ 3042 this.setEndToken(objectToken); 3043 } 3044 } 3045 } 3046 3047 public void init(EDbObjectType dbObjectType, Object arg1, Object arg2, Object arg3){ 3048 numberOfPart = 0; 3049 if (arg1 != null) numberOfPart++; 3050 if (arg2 != null) numberOfPart++; 3051 if (arg3 != null) numberOfPart++; 3052 3053 this.dbObjectType = dbObjectType; 3054 this.setStartToken((TSourceToken)arg1); 3055 this.setEndToken((TSourceToken)arg3); 3056 switch (this.dbObjectType){ 3057 case column: 3058 schemaToken = (TSourceToken)arg1; 3059 objectToken = (TSourceToken)arg2; 3060 partToken = (TSourceToken)arg3; 3061 break; 3062 case table: 3063 case function: 3064 case procedure: 3065 case materializedView: 3066 case module: 3067 case sequence: 3068 databaseToken = (TSourceToken) arg1; 3069 schemaToken = (TSourceToken)arg2; 3070 objectToken = (TSourceToken)arg3; 3071 break; 3072 case alias: 3073 break; 3074 default: 3075 break; 3076 } 3077 3078 } 3079 3080 public void init(Object arg1, Object arg2, Object arg3) 3081 { 3082 if (arg1 instanceof EDbObjectType){ 3083 initWithTwoTokens((EDbObjectType)arg1,(TSourceToken) arg2,(TSourceToken) arg3); 3084 }else{ 3085 numberOfPart = 0; 3086 if (arg1 != null) numberOfPart++; 3087 if (arg2 != null) numberOfPart++; 3088 if (arg3 != null) numberOfPart++; 3089 3090 if (dbvendor == EDbVendor.dbvteradata){ 3091 databaseToken = (TSourceToken) arg1; 3092 this.setStartToken(databaseToken); 3093 }else{ 3094 schemaToken = (TSourceToken)arg1; 3095 this.setStartToken(schemaToken); 3096 if (schemaToken != null) 3097 {schemaToken.setDbObjType(TObjectName.ttobjSchemaName);} 3098 } 3099 3100 objectToken = (TSourceToken)arg2; 3101 partToken = (TSourceToken)arg3; 3102 this.setEndToken(partToken); 3103 } 3104 } 3105 3106 public void init(Object arg1, Object arg2, Object arg3, Object arg4) 3107 { 3108 if (arg1 instanceof EDbObjectType){ 3109 //this.dbObjectType = (EDbObjectType)arg1; 3110 //init(arg2,arg3,arg4); 3111 initWithThreeTokens((EDbObjectType)arg1,(TSourceToken)arg2,(TSourceToken)arg3,(TSourceToken)arg4); 3112 }else{ 3113 numberOfPart = 0; 3114 if (arg1 != null) numberOfPart++; 3115 if (arg2 != null) numberOfPart++; 3116 if (arg3 != null) numberOfPart++; 3117 if (arg4 != null) numberOfPart++; 3118 3119 //serverToken = (TSourceToken)arg1; 3120 databaseToken = (TSourceToken)arg1; 3121 schemaToken = (TSourceToken)arg2; 3122 objectToken = (TSourceToken)arg3; 3123 partToken = (TSourceToken)arg4; 3124 this.setStartToken(databaseToken); 3125 this.setEndToken(partToken); 3126 if (databaseToken != null){ 3127 //databaseToken.setDbObjType(TObjectName.ttobjDatabaseName); 3128 databaseToken.setDbObjectType(EDbObjectType.database); 3129 }else { 3130 } 3131 if (schemaToken != null){ 3132 schemaToken.setDbObjType(TObjectName.ttobjSchemaName); 3133 }else { 3134 } 3135 } 3136 } 3137 3138 public void init(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) 3139 { 3140 numberOfPart = 0; 3141 if (arg1 != null) numberOfPart++; 3142 if (arg2 != null) numberOfPart++; 3143 if (arg3 != null) numberOfPart++; 3144 if (arg4 != null) numberOfPart++; 3145 if (arg5 != null) numberOfPart++; 3146 3147 serverToken = (TSourceToken)arg1; 3148 databaseToken = (TSourceToken)arg2; 3149 schemaToken = (TSourceToken)arg3; 3150 objectToken = (TSourceToken)arg4; 3151 partToken = (TSourceToken)arg5; 3152 3153 this.setStartToken(serverToken); 3154 this.setEndToken(partToken); 3155 3156 if (serverToken != null){ 3157 //serverToken.setDbObjType(TObjectName.ttobjServerName); 3158 serverToken.setDbObjectType(EDbObjectType.server); 3159 }else{ 3160 } 3161 if (databaseToken != null){ 3162 //databaseToken.setDbObjType(TObjectName.ttobjDatabaseName); 3163 databaseToken.setDbObjectType(EDbObjectType.database); 3164 }else{ 3165 } 3166 if (schemaToken != null){ 3167 schemaToken.setDbObjType(TObjectName.ttobjSchemaName); 3168 }else{ 3169 } 3170 } 3171 3172 public void init(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) 3173 { 3174 numberOfPart = 0; 3175 if (arg1 != null) numberOfPart++; 3176 if (arg2 != null) numberOfPart++; 3177 if (arg3 != null) numberOfPart++; 3178 if (arg4 != null) numberOfPart++; 3179 if (arg5 != null) numberOfPart++; 3180 if (arg6 != null) numberOfPart++; 3181 3182 serverToken = (TSourceToken)arg1; 3183 databaseToken = (TSourceToken)arg2; 3184 schemaToken = (TSourceToken)arg3; 3185 objectToken = (TSourceToken)arg4; 3186 partToken = (TSourceToken)arg5; 3187 propertyToken = (TSourceToken)arg6; 3188 3189 this.setStartToken(serverToken); 3190 this.setEndToken(propertyToken); 3191 3192 if (serverToken != null){ 3193 //serverToken.setDbObjType(TObjectName.ttobjServerName); 3194 serverToken.setDbObjectType(EDbObjectType.server); 3195 }else{ 3196 } 3197 if (databaseToken != null){ 3198 // databaseToken.setDbObjType(TObjectName.ttobjDatabaseName); 3199 databaseToken.setDbObjectType(EDbObjectType.database); 3200 }else{ 3201 } 3202 if (schemaToken != null){ 3203 schemaToken.setDbObjType(TObjectName.ttobjSchemaName); 3204 }else{ 3205 } 3206 } 3207 3208 /** 3209 * The column position of this objectName in the SQL 3210 * 3211 * @return column position 3212 */ 3213 @Override 3214 public long getColumnNo() { 3215 long retval = -1; 3216 if (partToken != null) { retval = partToken.columnNo;} 3217 if (objectToken != null) { 3218 retval = objectToken.columnNo; 3219 } 3220 if (schemaToken != null) { 3221 retval = schemaToken.columnNo; 3222 } 3223 if (databaseToken != null) { 3224 retval = databaseToken.columnNo; 3225 } 3226 if (serverToken != null) { 3227 retval = serverToken.columnNo; 3228 } 3229 return retval; 3230 } 3231 3232 /** 3233 * The line number of this objectName in SQL 3234 * 3235 * @return the line number 3236 */ 3237 @Override 3238 public long getLineNo() { 3239 long retval = -1; 3240 if (partToken != null) { retval = partToken.lineNo;} 3241 if (objectToken != null) { 3242 retval = objectToken.lineNo; 3243 } 3244 if (schemaToken != null) { 3245 retval = schemaToken.lineNo; 3246 } 3247 if (databaseToken != null) { 3248 retval = databaseToken.lineNo; 3249 } 3250 if (serverToken != null) { 3251 retval = serverToken.lineNo; 3252 } 3253 return retval; 3254 } 3255 3256 private TObjectNameList referencedObjects = null; 3257 3258 public TObjectNameList getReferencedObjects() { 3259 if (referencedObjects == null){ 3260 referencedObjects = new TObjectNameList(); 3261 } 3262 return referencedObjects; 3263 } 3264 3265 /** 3266 * Returns only the column name if it's prefixed with a table name 3267 * 3268 * @return only the column name if it's prefixed with a table name 3269 */ 3270 public String getColumnNameOnly(){ 3271 3272 if (getPartToken() == null) return ""; 3273 else return getPartToken().toString(); 3274 } 3275 3276 public void accept(TParseTreeVisitor v){ 3277 v.preVisit(this); 3278 v.postVisit(this); 3279 } 3280 3281 public void acceptChildren(TParseTreeVisitor v){ 3282 v.preVisit(this); 3283 v.postVisit(this); 3284 } 3285 3286// private TSourceToken sortType = null; 3287// 3288// public void setSortType(TSourceToken sortType) { 3289// this.sortType = sortType; 3290// } 3291// 3292// /** 3293// * When this object is column in primary key(column,...), unique key(column,...) in sql server 3294// * there maybe sort information like column asc, column desc 3295// * this token represents for ASC, DESC if specified. 3296// * 3297// * @return ASC, DESC or null 3298// */ 3299// 3300// public TSourceToken getSortType() { 3301// return sortType; 3302// } 3303 3304 /** 3305 * It's the same as {@link #getPartToken} if {@link #getDbObjectType} is {@link gudusoft.gsqlparser.EDbObjectType#column} 3306 * 3307 * @return source token that represents column, return null if this objectName is not type of column 3308 * 3309 */ 3310 public TSourceToken getColumnToken(){ 3311 TSourceToken ret = null; 3312 if (this.getObjectType() == ttobjColumn){ 3313 ret = this.getPartToken(); 3314 } 3315 return ret; 3316 } 3317 3318 /* 3319 * re-arranage objectname to make it a valid name includes attribute name 3320 * used by teradata yacc file only. 3321 * valid syntax: 3322 * column.attr1().attr2(). 3323 * column.attr1().attr2().attr3() 3324 * table.column.attr1().attr2(). 3325 * table.column.attr1().attr2().attr3() 3326 * 3327 * @return 3328 */ 3329 public boolean isAttributeNameInObjectName(TSourceToken leftparen,TSourceToken rightparen){ 3330 boolean ret = false; 3331 if ((this.partToken == null) || (this.objectToken == null)){ 3332 return ret; 3333 } 3334 this.objectType = TObjectName.ttobjColumn; 3335 this.columnAttributes = new TObjectNameList(); 3336 TObjectName attr1 = new TObjectName(); 3337 attr1.objectType = TObjectName.ttobjAttribute; 3338 attr1.init(this.partToken); 3339 attr1.setEndToken(rightparen); 3340 this.columnAttributes.addObjectName(attr1); 3341 3342 this.partToken = this.objectToken; 3343 3344 if (this.schemaToken != null){ 3345 this.objectToken = this.schemaToken; 3346 } 3347 3348 return true; 3349 } 3350 3351 /** 3352 * Used internally in hive .y file to merge two objectNames 3353 */ 3354 public void mergeObjectName(TObjectName objectName){ 3355 this.objectToken = this.partToken; 3356 this.partToken = objectName.getPartToken(); 3357 this.setStartToken(objectToken); 3358 this.setEndToken(partToken); 3359 } 3360 3361 public void mergeObjectName(TObjectName objectName,TObjectName objectName2){ 3362 this.schemaToken = this.partToken; 3363 this.objectToken = objectName.getPartToken(); 3364 this.partToken = objectName2.getPartToken(); 3365 this.setStartToken(schemaToken); 3366 this.setEndToken(partToken); 3367 } 3368 3369 3370 public void columnToProperty(){ 3371 // if (numberOfPart == 1) return; 3372 if (this.propertyToken != null) return; // columnToProperty() already called 3373 if (! ((this.partToken != null) && (this.objectToken != null))) return; // 既然是 column.property , 那么 partToken and objectToken 不能为空 3374 3375 this.propertyToken = this.partToken; 3376 this.partToken = this.objectToken; 3377 this.objectToken = this.schemaToken; 3378 3379 this.setDbObjectTypeDirectly(EDbObjectType.column); 3380 } 3381 3382 public void appendObjectName(TObjectName objectName){ 3383 if (this.databaseToken != null){ 3384 this.serverToken = this.databaseToken; 3385 } 3386 if (this.schemaToken != null){ 3387 this.databaseToken = this.schemaToken; 3388 } 3389 if (this.objectToken != null){ 3390 this.schemaToken = this.objectToken; 3391 } 3392 this.objectToken = this.partToken; 3393 this.partToken = objectName.getPartToken(); 3394 this.setEndTokenDirectly(this.partToken); 3395 } 3396 3397 private TSourceToken commentString; 3398 3399 public void setCommentString(TSourceToken commentString) { 3400 this.commentString = commentString; 3401 } 3402 3403 public TSourceToken getCommentString() { 3404 3405 return commentString; 3406 } 3407 3408 3409 /** 3410 * The X and Y position of this objectName in the SQL 3411 * 3412 * @return coordinate in string text 3413 */ 3414 public String coordinate(){ 3415 return this.getStartToken().lineNo+","+this.getEndToken().columnNo; 3416 } 3417 3418 3419 /** 3420 * @deprecated replaced by {@link EDbObjectType}. 3421 * 3422 * this is not an object, like sysdate function in oracle database 3423 */ 3424 public final static int ttobjNotAObject = -1; 3425 3426 /** 3427 * @deprecated replaced by {@link EDbObjectType}. 3428 * object type can't be determined. 3429 */ 3430 public final static int ttobjUnknown = 0; 3431 3432 /** 3433 * @deprecated replaced by {@link EDbObjectType}. 3434 * column in table, objectToken is table if specified, and partToken is column name. 3435 */ 3436 public final static int ttobjColumn = 1; 3437 3438 /** 3439 * @deprecated replaced by {@link EDbObjectType}. 3440 * column alias in objectToken. 3441 */ 3442 public final static int ttobjColumnAlias = 2; 3443 3444 /** 3445 * @deprecated replaced by {@link EDbObjectType}. 3446 * table name in objectToken. 3447 */ 3448 public final static int ttobjTable = 3; 3449 3450 3451 /** 3452 * @deprecated replaced by {@link EDbObjectType}. 3453 * parameter name in objectToken. 3454 */ 3455 public final static int ttobjParameter = 9; 3456 3457 /** 3458 * @deprecated replaced by {@link EDbObjectType}. 3459 * variable name in objectToken. 3460 */ 3461 public final static int ttobjVariable = 10; 3462 3463 3464 /** 3465 * @deprecated replaced by {@link EDbObjectType#method}. 3466 * column method like SetXY below, column method in {@link #methodToken}, and colomn name in {@link #partToken}. 3467 *<p> UPDATE Cities 3468 *<p> SET Location.SetXY(23.5, 23.5) 3469 * 3470 * 3471 */ 3472 public final static int ttobjColumnMethod = 11; 3473 3474 3475 3476 /** 3477 * @deprecated replaced by {@link EDbObjectType}. 3478 * function name in {@link #objectToken} 3479 */ 3480 public final static int ttobjFunctionName = 13; 3481 3482 3483 /** 3484 * @deprecated replaced by {@link EDbObjectType#constraint}. 3485 * constraint name in {@link #objectToken} 3486 */ 3487 public final static int ttobjConstraintName = 19; 3488 3489 /** 3490 * @deprecated replaced by {@link EDbObjectType}. 3491 * string constant in {@link #objectToken} 3492 */ 3493 public final static int ttobjStringConstant = 23; 3494 3495 3496 /** 3497 * @deprecated replaced by {@link EDbObjectType}. 3498 * attribute name is in {@link #partToken} 3499 */ 3500 public final static int ttobjAttribute = 26; 3501 3502 3503 /** 3504 * @deprecated replaced by {@link EDbObjectType}. 3505 * datatype was not represented by a TObjectName object, this constant was used in source tokens that consist of TTypeName. 3506 */ 3507 public final static int ttobjDatatype = 30; 3508 3509 /** 3510 * @deprecated replaced by {@link EDbObjectType}. 3511 * schema name in {@link #schemaToken} 3512 */ 3513 public final static int ttobjSchemaName = 31; 3514 3515 3516 /** 3517 * @deprecated replaced by {@link EDbObjectType}. 3518 * postgresql 3519 * Positional Parameters, $1, $1[1], $1[1,10] 3520 * parameter name is in {@link #partToken} of $1, 3521 * and parameter name is in {@link #objectToken} of $1.columnName, 3522 * and column name is in {@link #partToken} 3523 */ 3524 3525 public final static int ttobjPositionalParameters = 61; 3526 3527 3528 3529 private void setColumnTokenOfPositionalParameters(TSourceToken column){ 3530 this.objectToken = this.partToken; 3531 this.partToken = column; 3532 } 3533 3534 private int objectType = ttobjUnknown; 3535 3536 3537 /** 3538 * @deprecated replaced by {@link EDbObjectType}. 3539 * this type is used in TObjectNameList, when objects in TObjectNameList includes more than 3540 * one type, objtype of that TObjectNameList was set to ttobjMixed. 3541 * 3542 * removed since v2.9.2.5 3543 */ 3544 // public final static int ttobjMixed = 100; 3545 3546 /** 3547 * @deprecated replaced by {@link EDbObjectType#library}. 3548 * removed since v2.9.2.5 3549 */ 3550 // public final static int ttObjLibrary = 72; 3551 3552 /** 3553 * @deprecated replaced by {@link EDbObjectType#oracleHint}. 3554 * removed since v2.9.2.5 3555 */ 3556 // public final static int ttObjOracleHint = 70; 3557 3558 /** 3559 * @deprecated replaced by {@link EDbObjectType#fieldName}. 3560 * check {@link gudusoft.gsqlparser.nodes.TExpression#getFieldName()} for more 3561 * removed since v2.9.2.5 3562 */ 3563 // public final static int ttobjFieldName = 51; 3564 3565 /** 3566 * @deprecated replaced by {@link EDbObjectType#miningModel}. 3567 * removed since v2.9.2.5 3568 */ 3569 // public final static int ttobjMiningModel = 46; 3570 3571 /** 3572 * @deprecated replaced by {@link EDbObjectType#materializedView}. 3573 * removed since v2.9.2.5 3574 */ 3575 // public final static int ttobjMaterializedView = 44; 3576 3577 /** 3578 * @deprecated replaced by {@link EDbObjectType#indextype}. 3579 * removed since v2.9.2.5 3580 */ 3581 // public final static int ttobjIndexType = 42; 3582 3583 /** 3584 * @deprecated replaced by {@link EDbObjectType#operator}. 3585 * removed since v2.9.2.5 3586 */ 3587 // public final static int ttobjOperator = 40; 3588 3589 /** 3590 * @deprecated replaced by {@link EDbObjectType#server}. 3591 * server name in {@link #serverToken} 3592 * 3593 * removed since v2.9.2.5 3594 */ 3595 // public final static int ttobjServerName = 32; 3596 3597 /** 3598 * @deprecated replaced by {@link EDbObjectType#sequence}. 3599 * Sequence name in {@link #objectToken} 3600 * 3601 * removed since v2.9.2.5 3602 */ 3603 // public final static int ttobjSequence = 29; 3604 3605 /** 3606 * @deprecated replaced by {@link EDbObjectType#plsql_package}. 3607 * package name in {@link #objectToken} 3608 * 3609 * removed since v2.9.2.5 3610 */ 3611 // public final static int ttobjPackage = 28; 3612 3613 /** 3614 * @deprecated replaced by {@link EDbObjectType#alias}. 3615 * alias name in {@link #objectToken} 3616 * 3617 * removed since v2.9.2.5 3618 */ 3619 // public final static int ttobjAliasName = 25; 3620 3621 3622 /** 3623 * @deprecated replaced by {@link EDbObjectType#trigger}. 3624 * Trigger name in {@link #objectToken} 3625 * 3626 * removed since v2.9.2.5 3627 */ 3628 // public final static int ttobjTrigger = 24; 3629 3630 /** 3631 * @deprecated replaced by {@link EDbObjectType#database}. 3632 * Database name in {@link #objectToken} 3633 * 3634 * removed since v2.9.2.5 3635 */ 3636 // public final static int ttobjDatabaseName = 22; 3637 3638 /** 3639 * @deprecated replaced by {@link EDbObjectType#transaction}. 3640 * Transaction name in {@link #objectToken} 3641 * 3642 * removed since v2.9.2.5 3643 */ 3644 // public final static int ttobjTransactionName = 21; 3645 3646 3647 /** 3648 * @deprecated replaced by {@link EDbObjectType#user_defined_type}. 3649 * type name in {@link #objectToken} 3650 * 3651 * removed since v2.9.2.5 3652 */ 3653 // public final static int ttobjTypeName = 27; 3654 3655 /** 3656 * @deprecated replaced by {@link EDbObjectType#property}. 3657 * property name in {@link #propertyToken} 3658 * 3659 * removed since v2.9.2.5 3660 */ 3661 // public final static int ttobjPropertyName = 20; 3662 3663 /** 3664 * @deprecated replaced by {@link EDbObjectType#view}. 3665 * view name in {@link #objectToken} 3666 * 3667 * removed since v2.9.2.5 3668 */ 3669 // public final static int ttobjViewName = 18; 3670 3671 /** 3672 * @deprecated replaced by {@link EDbObjectType#cursor}. 3673 * cursor name in {@link #objectToken} 3674 * 3675 * removed since v2.9.2.5 3676 */ 3677 // public final static int ttobjCursorName = 17; 3678 3679 /** 3680 * @deprecated replaced by {@link EDbObjectType#materializedView}. 3681 * materialized view name in {@link #objectToken} 3682 * 3683 * removed since v2.9.2.5 3684 */ 3685 // public final static int ttobjMaterializedViewName = 16; 3686 3687 /** 3688 * @deprecated replaced by {@link EDbObjectType#index}. 3689 * index name in {@link #objectToken} 3690 * 3691 * removed since v2.9.2.5 3692 */ 3693 // public final static int ttobjIndexName = 15; 3694 3695 /** 3696 * @deprecated replaced by {@link EDbObjectType#label}. 3697 * label name in {@link #objectToken} 3698 * 3699 * removed since v2.9.2.5 3700 */ 3701 // public final static int ttobjLabelName = 14; 3702 3703 /** 3704 * @deprecated replaced by {@link EDbObjectType#procedure}. 3705 * procedure name in {@link #objectToken} 3706 * 3707 * removed since v2.9.2.5 3708 */ 3709 // public final static int ttobjProcedureName = 12; 3710 3711 /** 3712 * @deprecated replaced by {@link EDbObjectType#variable}. 3713 * table variable in objectToken. 3714 * 3715 * removed since v2.9.2.5 3716 */ 3717 // public final static int ttobjTableVar = 8; 3718 3719 /** 3720 * @deprecated replaced by {@link EDbObjectType#cte}. 3721 * table name in objectToken. 3722 * 3723 * removed since v2.9.2.5 3724 */ 3725 // public final static int ttobjTableCTE = 5; 3726 3727 /** 3728 * @deprecated replaced by {@link EDbObjectType}. 3729 * table name in objectToken. 3730 */ 3731 // public final static int ttobjTableTemp = 6; 3732 3733 /** 3734 * @deprecated replaced by {@link EDbObjectType}. 3735 */ 3736 // public final static int ttobjTablePivot = 7; 3737 3738 /** 3739 * @deprecated replaced by {@link EDbObjectType#table_alias}. 3740 * table alias in objectToken 3741 * 3742 * removed since v2.9.2.5 3743 */ 3744 // public final static int ttObjTableAlias = 4; 3745}