001package gudusoft.gsqlparser; 002 003 004import gudusoft.gsqlparser.compiler.*; 005import gudusoft.gsqlparser.nodes.*; 006import gudusoft.gsqlparser.nodes.dax.TDaxFunction; 007import gudusoft.gsqlparser.nodes.teradata.THashByClause; 008import gudusoft.gsqlparser.sqlenv.TSQLEnv; 009import gudusoft.gsqlparser.sqlenv.TSQLFunction; 010import gudusoft.gsqlparser.stmt.*; 011import gudusoft.gsqlparser.stmt.dax.TDaxStmt; 012import gudusoft.gsqlparser.stmt.oracle.*; 013import gudusoft.gsqlparser.util.functionChecker; 014import gudusoft.gsqlparser.util.keywordChecker; 015 016import java.util.ArrayList; 017import java.util.Stack; 018import java.util.TreeMap; 019import java.security.MessageDigest; 020import java.security.NoSuchAlgorithmException; 021import java.nio.charset.StandardCharsets; 022 023/** 024 * TCustomSqlStatement is the root class for all SQL statements. 025 */ 026public class TCustomSqlStatement extends TParseTreeNode implements IRelation{ 027 028 private String sqlHash; 029 030 public void setSqlHash(String sqlHash) { 031 this.sqlHash = sqlHash; 032 } 033 034 /** 035 * Returns a stable, vendor-aware hash of this statement's SQL text for 036 * lineage grouping and statement identity. 037 * <p> 038 * Purpose: 039 * <ul> 040 * <li>Provide a deterministic identifier for a statement that is 041 * insensitive to formatting (whitespace, comments, keyword case).</li> 042 * <li>Act as the first component of a recommended {@code statementKey} 043 * for lineage grouping: {@code statementKey = sqlHash + "#" + queryId}.</li> 044 * </ul> 045 * How it works: 046 * <ul> 047 * <li>Builds a normalized textual representation of the statement by 048 * iterating the token chain between {@code getStartToken()} and 049 * {@code getEndToken()}.</li> 050 * <li>Normalization rules (Profile A by default): remove comments; 051 * collapse spacing deterministically; uppercase keywords; handle 052 * identifiers by the current vendor's case-sensitivity 053 * ({@link gudusoft.gsqlparser.sqlenv.TSQLEnv#columnCollationCaseSensitive}). 054 * For delimited identifiers (quoted identifiers), the quotes are 055 * removed via {@link gudusoft.gsqlparser.TBaseType#removeQuoteChar(String)} 056 * before case normalization. String literals are kept as-is.</li> 057 * <li>The hash input is prefixed by a normalization version and the 058 * current vendor, so future evolution of the normalizer will not break 059 * previously computed values: {@code normVersion + "\n" + vendor + "\n" + normalizedSql}.</li> 060 * <li>Hash function: SHA-256 (lowercase hex).</li> 061 * </ul> 062 * Usage: 063 * <ul> 064 * <li>Call {@code getSqlHash(false)} for cached result or lazy 065 * calculation with Profile A (identity-safe) normalization.</li> 066 * <li>Call {@code getSqlHash(true)} to force recalculation (e.g., after 067 * mutating the underlying token chain).</li> 068 * <li>If you need a grouping-friendly variant (masking certain literal 069 * classes), use {@link #computeSqlHash(SqlNormalizationProfile, String)} 070 * with {@link SqlNormalizationProfile#GROUPING_FRIENDLY}.</li> 071 * </ul> 072 * 073 * @param forceReCalculate if true, recompute the hash even if a cached 074 * value exists 075 * @return lowercase hex SHA-256 hash of the normalized SQL text 076 */ 077 public String getSqlHash(boolean forceReCalculate) { 078 if (sqlHash != null && !forceReCalculate) { 079 return sqlHash; 080 } 081 // Default: Profile A (identity-safe) 082 this.sqlHash = computeSqlHash(SqlNormalizationProfile.IDENTITY_SAFE, DEFAULT_SQLHASH_NORM_VERSION); 083 return this.sqlHash; 084 } 085 086 /** 087 * Backward compatible overload equivalent to {@code getSqlHash(false)}. 088 */ 089 public String getSqlHash() { 090 return getSqlHash(false); 091 } 092 093 /** 094 * Normalization profiles for SQL hashing. 095 * <ul> 096 * <li>IDENTITY_SAFE: Remove comments and normalize spacing/case only. 097 * Literal values are preserved. Operator synonyms are minimally 098 * unified (e.g., {@code !=} to {@code <>}).</li> 099 * <li>GROUPING_FRIENDLY: In addition to IDENTITY_SAFE, date/time 100 * string literals are normalized to {@code '1970-01-01'} to aid 101 * grouping across different runs where only timestamps vary.</li> 102 * </ul> 103 */ 104 public enum SqlNormalizationProfile { 105 IDENTITY_SAFE, 106 GROUPING_FRIENDLY 107 } 108 109 private static final String DEFAULT_SQLHASH_NORM_VERSION = "sqlHash.norm.v1"; 110 111 /** 112 * Compute a SQL hash using the given normalization profile and version. 113 * See {@link #getSqlHash(boolean)} for details. 114 * 115 * @param profile normalization profile 116 * @param normVersion version tag embedded in the hash input 117 * @return lowercase hex SHA-256 hash 118 */ 119 public String computeSqlHash(SqlNormalizationProfile profile, String normVersion) { 120 String normalized = toNormalizedSql(profile); 121 String input = normVersion + "\n" + String.valueOf(this.dbvendor) + "\n" + normalized; 122 return sha256Hex(input); 123 } 124 125 /** 126 * Produce a normalized textual representation of this statement according 127 * to the supplied profile. The method is non-mutating: it does not alter 128 * token texts or statuses permanently. 129 * 130 * Rules applied: 131 * - Remove comments. 132 * - Remove trailing semicolon. 133 * - Deterministic spacing around punctuation/operators. 134 * - Uppercase keywords, keep string literals as-is. 135 * - Identifiers: if the vendor's column collation is case sensitive, keep 136 * identifier case; otherwise uppercase. For quoted identifiers, remove 137 * quoting via {@link TBaseType#removeQuoteChar(String)} prior to case 138 * handling. 139 * - Minimal operator unification: {@code "!="} becomes {@code "<>"}. 140 * - Profile B adds date/time string masking: {@code '1970-01-01'}. 141 * 142 * @param profile normalization profile 143 * @return normalized SQL string 144 */ 145 public String toNormalizedSql(SqlNormalizationProfile profile) { 146 TSourceToken start = getStartToken(); 147 TSourceToken end = getEndToken(); 148 if (start == null || end == null) { 149 return String.valueOf(this.toString()); 150 } 151 152 boolean idCaseSensitive = Boolean.TRUE.equals(TSQLEnv.columnCollationCaseSensitive.get(this.dbvendor)); 153 154 StringBuilder sb = new StringBuilder(256); 155 TokenClass prevClass = null; 156 char lastAppended = '\0'; 157 158 // We may need to skip a single trailing semicolon that is the end token 159 // Detect once to simplify checks in the loop 160 boolean endIsSemicolon = (end.toString().equals(";")); 161 162 TSourceToken cur = start; 163 while (cur != null) { 164 // Skip tokens that should not contribute 165 if (isComment(cur)) { 166 // skip comments 167 } else if (cur == end && endIsSemicolon) { 168 // drop trailing semicolon 169 } else if (cur.tokenstatus == ETokenStatus.tsdeleted || cur.tokenstatus == ETokenStatus.tsignorebyyacc) { 170 // ignore deleted/ignored tokens 171 } else { 172 String text = normalizeTokenText(cur, idCaseSensitive, profile); 173 if (text != null && !text.isEmpty()) { 174 TokenClass clazz = classify(cur, text); 175 if (shouldAddSpaceBefore(prevClass, clazz, lastAppended)) { 176 sb.append(' '); 177 lastAppended = ' '; 178 } 179 sb.append(text); 180 lastAppended = text.charAt(text.length() - 1); 181 prevClass = clazz; 182 } 183 } 184 185 if (cur == end) { 186 break; 187 } else { 188 cur = cur.getNextTokenInChain(); 189 } 190 } 191 192 // Trim any trailing single space for cleanliness 193 int len = sb.length(); 194 if (len > 0 && sb.charAt(len - 1) == ' ') { 195 sb.setLength(len - 1); 196 } 197 return sb.toString(); 198 } 199 200 private static boolean isComment(TSourceToken t) { 201 return t.tokentype == ETokenType.ttsimplecomment || t.tokentype == ETokenType.ttbracketedcomment; 202 } 203 204 private enum TokenClass { WORD, OP, DOT, COMMA, PAREN_LEFT, PAREN_RIGHT, SEMICOLON, OTHER } 205 206 private static TokenClass classify(TSourceToken t, String normalizedText) { 207 switch (t.tokentype) { 208 case ttidentifier: 209 case ttdqstring: 210 case ttdbstring: 211 case ttbrstring: 212 case ttnumber: 213 case ttsqstring: 214 case ttkeyword: 215 case ttnonreservedkeyword: 216 case ttbindvar: 217 case ttsqlvar: 218 case ttsubstitutionvar: 219 return TokenClass.WORD; 220 case ttperiod: 221 return TokenClass.DOT; 222 case ttcomma: 223 return TokenClass.COMMA; 224 case ttleftparenthesis: 225 return TokenClass.PAREN_LEFT; 226 case ttrightparenthesis: 227 return TokenClass.PAREN_RIGHT; 228 case ttsemicolon: 229 case ttsemicolon2: 230 case ttsemicolon3: 231 return TokenClass.SEMICOLON; 232 case ttequals: 233 case ttplussign: 234 case ttminussign: 235 case ttasterisk: 236 case ttslash: 237 case ttgreaterthan: 238 case ttlessthan: 239 case ttsinglecharoperator: 240 case ttmulticharoperator: 241 case ttconcatenationop: 242 return TokenClass.OP; 243 default: 244 break; 245 } 246 // Heuristic: treat UNKNOWN single-char punctuation as operator 247 if (normalizedText.length() == 1 && !Character.isLetterOrDigit(normalizedText.charAt(0))) { 248 return TokenClass.OP; 249 } 250 return TokenClass.OTHER; 251 } 252 253 private static boolean shouldAddSpaceBefore(TokenClass prev, TokenClass curr, char lastAppended) { 254 if (prev == null) return false; 255 if (lastAppended == '\0') return false; 256 257 // No space rules 258 if (curr == TokenClass.DOT || curr == TokenClass.COMMA || curr == TokenClass.PAREN_RIGHT) return false; 259 if (prev == TokenClass.DOT || prev == TokenClass.PAREN_LEFT) return false; 260 261 // Space around operators and between words 262 if (prev == TokenClass.OP && (curr == TokenClass.WORD || curr == TokenClass.PAREN_LEFT)) return true; 263 if ((prev == TokenClass.WORD || prev == TokenClass.PAREN_RIGHT) && (curr == TokenClass.OP || curr == TokenClass.WORD)) return true; 264 265 // After comma ensure a space before next word 266 if (prev == TokenClass.COMMA && (curr == TokenClass.WORD || curr == TokenClass.PAREN_LEFT)) return true; 267 268 // Default: no space 269 return false; 270 } 271 272 private String normalizeTokenText(TSourceToken t, boolean idCaseSensitive, SqlNormalizationProfile profile) { 273 String s = t.toString(); 274 275 // Minimal operator unification: != => <> 276 if (t.tokentype == ETokenType.ttmulticharoperator || t.tokentype == ETokenType.ttsinglecharoperator || 277 t.tokentype == ETokenType.ttgreaterthan || t.tokentype == ETokenType.ttlessthan) { 278 if ("!=".equals(s)) { 279 return "<>"; 280 } 281 return s; 282 } 283 284 switch (t.tokentype) { 285 case ttsimplecomment: 286 case ttbracketedcomment: 287 return null; // removed 288 case ttkeyword: 289 case ttnonreservedkeyword: 290 return s.toUpperCase(); 291 case ttidentifier: { 292 // regular identifier 293 return idCaseSensitive ? s : s.toUpperCase(); 294 } 295 case ttdqstring: 296 case ttdbstring: 297 case ttbrstring: { 298 // delimited/quoted identifier -> remove quotes, then apply case rule 299 String unquoted = TBaseType.removeQuoteChar(s); 300 return idCaseSensitive ? unquoted : unquoted.toUpperCase(); 301 } 302 case ttsqstring: { 303 if (profile == SqlNormalizationProfile.GROUPING_FRIENDLY && looksLikeDateOrTimestampLiteral(s)) { 304 return "'1970-01-01'"; 305 } 306 return s; // keep string literal as-is 307 } 308 default: 309 return s; 310 } 311 } 312 313 private static boolean looksLikeDateOrTimestampLiteral(String s) { 314 // Very lightweight check for common SQL string date/timestamp formats, e.g. '2025-09-14' or '2025-09-14 12:34:56' 315 // Input includes surrounding quotes per token text. 316 if (s == null || s.length() < 2) return false; 317 if (!(s.charAt(0) == '\'' && s.charAt(s.length() - 1) == '\'')) return false; 318 String inner = s.substring(1, s.length() - 1).trim(); 319 // yyyy-mm-dd or yyyy-mm-dd hh:mm[:ss[.fff]] 320 if (inner.matches("\\d{4}-\\d{2}-\\d{2}")) return true; 321 if (inner.matches("\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,9})?)?")) return true; 322 return false; 323 } 324 325 private static String sha256Hex(String input) { 326 try { 327 MessageDigest md = MessageDigest.getInstance("SHA-256"); 328 byte[] out = md.digest(input.getBytes(StandardCharsets.UTF_8)); 329 char[] hex = new char[out.length * 2]; 330 final char[] digits = "0123456789abcdef".toCharArray(); 331 for (int i = 0, j = 0; i < out.length; i++) { 332 int b = out[i] & 0xFF; 333 hex[j++] = digits[(b >>> 4) & 0x0F]; 334 hex[j++] = digits[b & 0x0F]; 335 } 336 return new String(hex); 337 } catch (NoSuchAlgorithmException e) { 338 // Should never happen on a standard JVM 339 throw new RuntimeException("SHA-256 not available", e); 340 } 341 } 342 343 private String queryId; 344 345 public void setQueryId(String queryId) { 346 this.queryId = queryId; 347 } 348 349 /** 350 * Retrieves the unique and stable identifier for this SQL statement. 351 * <p> 352 * The queryId provides a reliable way to reference any statement, including subqueries, 353 * within a parsed SQL script. It is generated hierarchically based on the statement's 354 * position within the Abstract Syntax Tree (AST), ensuring that the ID is reproducible 355 * across identical SQL inputs. 356 * <p> 357 * <b>ID Format:</b> 358 * <ul> 359 * <li>A top-level statement has an ID like {@code "stmt_0_select"}, where {@code 0} is the index 360 * of the statement in the script and {@code select} is the statement type.</li> 361 * <li>A nested statement will have a path-like ID that includes its parent's ID. For example, 362 * an {@code INSERT} statement containing a {@code SELECT} subquery might have an ID for the 363 * subquery like {@code "stmt_0_insert#stmt_1_select"}.</li> 364 * </ul> 365 * This identifier is particularly useful for tasks like data lineage analysis, where tracking 366 * the origin and transformation of data through various statements is required. 367 * 368 * @return The unique query identifier string for this statement, or {@code null} if it has not been set. 369 */ 370 public String getQueryId() { 371 return queryId; 372 } 373 374 public void setUsingVariableList(TColumnDefinitionList usingVariableList) { 375 this.usingVariableList = usingVariableList; 376 } 377 378 private TColumnDefinitionList usingVariableList; 379 380 /* 381 * Variables defined in teradata using clause. 382 * */ 383 public TColumnDefinitionList getUsingVariableList() { 384 return usingVariableList; 385 } 386 387 protected ArrayList<TAttributeNode> relationAttributes = new ArrayList<>(); 388 389 @Override 390 public ArrayList<TAttributeNode> getAttributes(){ 391 // if (relationAttributes.size() != 0) return relationAttributes; 392 relationAttributes.clear(); 393 for(TTable table:relations){ 394 //relationAttributes.addAll(table.getAttributes()); 395 TAttributeNode.addAllNodesToList(table.getAttributes(),relationAttributes); 396 } 397 398 return relationAttributes; 399 } 400 401 @Override 402 public String getRelationName(){ 403 return null; 404 } 405 406 @Override 407 public int size(){ 408 return relationAttributes.size(); 409 } 410 411 @Override 412 public String toScript(){ 413 String ret = super.toScript(); 414 if ((ret == null)||(ret.isEmpty())){ 415 ret = this.toString(); 416 }else{ 417 if ((this.getEndToken() != null) && (this.getEndToken().tokencode == ';')) { 418 if (!ret.endsWith(";")){ 419 ret = ret + ";"; 420 } 421 } 422 } 423 return ret; 424 } 425 426 protected TFromClause fromClause; 427 428 public void setFromClause(TFromClause fromClause) { 429 this.fromClause = fromClause; 430 } 431 432 public TFromClause getFromClause() { 433 return fromClause; 434 } 435 436 /** 437 * Relations that used in from clause of select statement. 438 * Or tables of other statements such as insert, update, delete and etc 439 * 440 * Please use this property to get the relations instead of {@link #getTables()} and {@link #getJoins()}after version 2.7.4.0 441 * 442 * when a join is used in from clause, then the table in getRelations() is type of ETableSource.join, and you can 443 * use TTable.getJoinExpr() to get this join. 444 * 445 * @return 446 */ 447 public ArrayList<TTable> getRelations() { 448 return relations; 449 } 450 451 private ArrayList<TTable> relations = new ArrayList<>(); 452 453 protected TTable fromSourceTable; 454 455 /** 456 * This is table in from clause if only one table is listed in the from clause, 457 * If more than one table is listed in from clause, please check {@link #getFromSourceJoin()} instead. 458 * 459 * @return table in from clause 460 */ 461 public TTable getFromSourceTable() { 462 return fromSourceTable; 463 } 464 465 /** 466 * This is a join in from clause, including left and right relation. 467 * If only a single table is listed in from clause, please use {@link #getFromSourceTable()} instead 468 * @return 469 */ 470 public TJoinExpr getFromSourceJoin() { 471 return fromSourceJoin; 472 } 473 474 protected TJoinExpr fromSourceJoin; 475 476 private String asCanonicalText = null; 477 478 /** 479 * this method return a canonical form of a SQL statement in plan text. 480 * <br>1. remove all comment inside SQL query. 481 * <br>2. remove redundant parenthesis at the begin/end of a select statement. 482 * <br>3. replace all number in where clause with 999 constant 483 * <br>4. replace all string constant in where clause with 'placeholder_str' 484 * <br>5. all number elements in a list such as (1,2,3,4) will be change to a single element (999) 485 * <br>6. all string elements in a list such as ('a','b','c','d') will be change to a single element ('placeholder_str') 486 * 487 * @return a canonical form of a SQL statement in plan text. 488 */ 489 public String asCanonical(){ 490 if (asCanonicalText != null) return asCanonicalText; 491 492 String ret = null; 493 TSourceToken lcStartToken = getStartToken(); 494 if (lcStartToken == null) return toString(); 495 TSourceToken lcEndToken = getEndToken(); 496 if (lcEndToken == null) return toString(); 497 498 // remove the ; token at the end of statement 499 if (lcEndToken.tokencode == ';') lcEndToken.tokenstatus = ETokenStatus.tsdeleted; 500 501 502 // remove ( ) at the begin and end of the statement 503 TSourceToken lcCurrentToken = lcStartToken; 504 while (lcCurrentToken != null){ 505 if (lcCurrentToken.tokencode != '(') { 506 break; 507 }else{ 508 if (lcCurrentToken.getLinkToken() != null){ 509 lcCurrentToken.tokenstatus = ETokenStatus.tsdeleted; 510 lcCurrentToken.getLinkToken().tokenstatus = ETokenStatus.tsdeleted; 511 } 512 } 513 514 if (lcCurrentToken.equals(lcEndToken)){ 515 break; 516 }else{ 517 lcCurrentToken = lcCurrentToken.getNextTokenInChain(); 518 } 519 } 520 521 // change constant to placeholder, all number change to 999 and string constant change to placeholder_str 522 constantVisitor cv = new constantVisitor(); 523 this.acceptChildren(cv); 524 525 526 boolean chainUnchanged = true, includingComment = false; 527 StringBuffer sb = new StringBuffer(""); 528 TSourceToken lcPrevSt = null; 529 boolean ignoreNextReturnToken = false, isChainModified = false; 530 531 lcCurrentToken = lcStartToken; 532 while (lcCurrentToken != null){ 533 if((lcCurrentToken.tokenstatus == ETokenStatus.tsdeleted) 534 ||(!includingComment && ((lcCurrentToken.tokencode == TBaseType.cmtslashstar) ||(lcCurrentToken.tokencode == TBaseType.cmtdoublehyphen))) 535 ){ 536 // ignore this token, do nothing 537 //System.out.println("out: ignore deleted token:"+lcCurrentToken.astext); 538 }else{ 539 // 540 sb.append(lcCurrentToken.toString()); 541 if (lcCurrentToken.isChangedInAsCanonical()){ 542 lcCurrentToken.restoreText(); 543 } 544 } 545 546 if (lcCurrentToken.equals(lcEndToken)){ 547 break; 548 }else{ 549 lcCurrentToken = lcCurrentToken.getNextTokenInChain(); 550 } 551 552 } 553 asCanonicalText = sb.toString(); 554 return asCanonicalText; 555 } 556 557 private TCTE cteIncludeThisStmt = null; 558 559 public void setCteIncludeThisStmt(TCTE cteIncludeThisStmt) { 560 this.cteIncludeThisStmt = cteIncludeThisStmt; 561 } 562 563 public TCTE getCteIncludeThisStmt() { 564 return cteIncludeThisStmt; 565 } 566 567 private TreeMap<String,TResultColumn> expandedResultColumns = null; 568 569 public TreeMap<String,TResultColumn> getExpandedResultColumns() { 570 if (expandedResultColumns == null){ 571 expandedResultColumns = new TreeMap<>(); 572 } 573 return expandedResultColumns; 574 } 575 576 public TSQLFunction searchFunctionInSQLEnv(String functionName){ 577 if (getSqlEnv() == null) return null; 578 return getSqlEnv().searchFunction(functionName); 579 } 580 581 public TSQLEnv getSqlEnv() { 582 if (getGlobalScope() == null) return null; 583 return getGlobalScope().getSqlEnv(); 584 } 585 586 public TGlobalScope getGlobalScope() { 587 TGlobalScope lcResult = null; 588 if (frameStack != null){ 589 if (frameStack.get(0) != null){ 590 lcResult = (TGlobalScope)frameStack.get(0).getScope(); 591 } 592 } 593 return lcResult; 594 } 595 596 private Stack<TFrame> frameStack; 597 598 public void setFrameStack(Stack<TFrame> frameStack) { 599 this.frameStack = frameStack; 600 } 601 602 public Stack<TFrame> getFrameStack() { 603 return frameStack; 604 } 605 606 private TPTNodeList<TColumnWithSortOrder> indexColumns = null; 607 608 public TPTNodeList<TColumnWithSortOrder> getIndexColumns() { 609 return indexColumns; 610 } 611 612 private Stack<TObjectName> variableStack = null; 613 614 public void setVariableStack(Stack<TObjectName> variableStack) { 615 this.variableStack = variableStack; 616 } 617 618 public Stack<TObjectName> getVariableStack() { 619 if (variableStack == null){ 620 variableStack = new Stack<TObjectName>(); 621 } 622 623 return variableStack; 624 } 625 626 private Stack<TDaxFunction> daxFunctionStack = null; 627 628 public Stack<TDaxFunction> getDaxFunctionStack() { 629 if (daxFunctionStack == null){ 630 daxFunctionStack = new Stack<TDaxFunction>(); 631 } 632 return daxFunctionStack; 633 } 634 635 private TObjectName labelName; 636 637 public void setLabelName(TObjectName lName) { 638 labelName = lName; 639 if (labelName != null){ 640 //labelName.setObjectType(TObjectName.ttobjLabelName); 641 labelName.setDbObjectType(EDbObjectType.label); 642 } 643 } 644 645 /** 646 * 647 * @return label name used in plsql statement. 648 */ 649 public TObjectName getLabelName() { 650 651 return labelName; 652 } 653 654 655 private TObjectName endlabelName; 656 657 public void setEndlabelName(TObjectName endlabelName) { 658 this.endlabelName = endlabelName; 659 } 660 661 public TObjectName getEndlabelName() { 662 663 return endlabelName; 664 } 665 666 /** 667 * Type of this statement. 668 */ 669 public ESqlStatementType sqlstatementtype; 670 /** 671 * Source tokens included in this statement. only source tokens available when this is a top level statement, otherwise, there is no source token in this statement. 672 * Please check {@link gudusoft.gsqlparser.nodes.TParseTreeNode#getStartToken()}, and {@link gudusoft.gsqlparser.nodes.TParseTreeNode#getEndToken()} of this statement. 673 */ 674 public TSourceTokenList sourcetokenlist; 675 676 public TSourceTokenList getTokenList() { 677 return sourcetokenlist; 678 } 679 /** 680 * Parser used to parse this statement. 681 */ 682 public TCustomParser parser; 683 /** 684 * PLSQL parser used to parse this statement. 685 */ 686 public TCustomParser plsqlparser; 687 /** 688 * Tag used by parser internally. 689 */ 690 public int dummytag; 691 692 /** 693 * target table in the delete/insert/update/create table statement. 694 * @see #joins 695 * @see TSelectSqlStatement 696 * @see TDeleteSqlStatement 697 * @see TUpdateSqlStatement 698 * @see TCreateTableSqlStatement 699 * @see gudusoft.gsqlparser.stmt.TMergeSqlStatement 700 */ 701 public TTable getTargetTable() { 702 return targetTable; 703 } 704 705 public void setTargetTable(TTable targetTable) { 706 setNewSubNode(this.targetTable,targetTable,getAnchorNode()); 707 this.targetTable = targetTable; 708 } 709 710 private TTable targetTable ; 711 712 /** 713 * joins represents table sources in the from clause. All structure information was reserved. 714 * <p>SQL 1: 715 * <p><blockquote><pre>select f from t1</pre></blockquote> 716 * <p>size of joins will be 1, t1 can be fetch via joins.getJoin(0).getTable() 717 * <p> 718 * <p>SQL 2: 719 * <p><blockquote><pre>select f from t1,t2</pre></blockquote> 720 * <p>size of joins will be 2, 721 * <p>t1 can be fetch via joins.getJoin(0).getTable() 722 * <p>t2 can be fetch via joins.getJoin(1).getTable() 723 * <p> 724 * <p>SQL 3: 725 * <p><blockquote><pre>select f from t1 join t2 on t1.f1 = t2.f1</pre></blockquote> 726 * <p>size of joins will be 1, 727 * <p>t1 information can be fetch via joins.getJoin(0).getTable() 728 * <p>In order to access t2, we need to introduce a new class {@link TJoinItem} which includes all information about t2 and join condition. 729 * <p>There is a property named joinItems of {@link TJoin} which is type of {@link TJoinItemList} that includes a list of {@link TJoinItem}. 730 * <p>this property can be access via {@link gudusoft.gsqlparser.nodes.TJoin#getJoinItems()}. 731 * <p>Now, t2 can be fetch via joins.getJoin(0).getJoinItems().getJoinItem(0).getTable() 732 * <p> 733 * <p>SQL 4: 734 * <p><blockquote><pre>select f from t1 join t2 on t1.f1 = t2.f1 join t3 on t1.f1 = t3.f1</pre></blockquote> 735 * <p>size of joins will be 1, 736 * <p>t1 can be fetch via joins.getJoin(0).getTable() 737 * <p>t2 can be fetch via joins.getJoin(0).getJoinItems().getJoinItem(0).getTable() 738 * <p>t3 can be fetch via joins.getJoin(0).getJoinItems().getJoinItem(1).getTable() 739 * 740 * @see #tables 741 */ 742 public TJoinList joins; 743 744 /** 745 * Provides a quick way to access all tables involved in this SQL statement. 746 * <p>It stores all tables in a flat way while {@link #joins} stores all tables in a hierarchical structure. 747 * <p>joins only represents tables in from clause of select/delete statement, and tables in update/insert statement. 748 * <p>{@link #tables} includes all tables in all types of SQL statements such as tables involved in a create table or create trigger statements. 749 */ 750 public TTableList tables; 751 752 public TJoinList getJoins() { 753 return joins; 754 } 755 756 public TTableList getTables() { 757 return tables; 758 } 759 760 /** 761 * Saves all first level sub statements. 762 * <p>By iterating statements recursively, you can fetch all included statements in an easy way. 763 * <p><blockquote><pre> 764 * select f1+(select f2 from t2) from t1 765 * where f2 > all (select f3 from t3 where f4 = (select f5 from t4))</pre> 766 * </blockquote> 767 * <p> Statements included in above SQL was save in a hierarchical way like this: 768 * <ul> 769 * <li>(select f2 from t2)</li> 770 * <li>(select f3 from t3 where f4 = (select f5 from t4)) 771 * <ul> 772 * <li>(select f5 from t4)</li> 773 * </ul> 774 * </li> 775 * </ul> 776 * <p>If this statement is a create procedure/function statement, then all declaration statements and statements in 777 * procedure body can also be fetched quickly by iterating this property recursively. 778 * 779 * 780 */ 781 public TStatementList getStatements() { 782 if (statements == null){ 783 statements = new TStatementList(); 784 } 785 return statements; 786 } 787 788 private TStatementList statements; 789 790 public void setCteList(TCTEList cteList) { 791 setNewSubNode(this.cteList,cteList,getAnchorNode()); 792 this.cteList = cteList; 793 } 794 795 /** 796 * Multiple common table expressions {@link TCTE} can be specified following the single WITH keyword. 797 *<p> Each common table expression specified can also be referenced by name in the FROM clause of subsequent common table expressions. 798 * 799 * <p>Used in select, delete, update statement. 800 * @return List of common table expression. 801 */ 802 803 public TCTEList getCteList() { 804 805 return cteList; 806 } 807 808 private TCTEList cteList = null; 809 810 public void setResultColumnList(TResultColumnList resultColumnList) { 811 setNewSubNode(this.resultColumnList,resultColumnList,getAnchorNode()); 812 this.resultColumnList = resultColumnList; 813 } 814 815 /** 816 * In select statement, this method returns Items in select_list. 817 * Can be *, expr, and name.* 818 * <br><br> 819 * In update statement, this method returns assignments in set clause. 820 * 821 * @return select list of select statement or assignments of update statement. 822 */ 823 public TResultColumnList getResultColumnList() { 824 825 return resultColumnList; 826 } 827 828 private TResultColumnList resultColumnList = null; 829 830 private TWhereClause whereClause = null; 831 private TTopClause topClause = null; 832 private TOutputClause outputClause = null; 833 private TReturningClause returningClause = null; 834 835 public void setReturningClause(TReturningClause returningClause) { 836 setNewSubNode(this.returningClause,returningClause,getAnchorNode()); 837 this.returningClause = returningClause; 838 } 839 840 /** 841 * @return {@link TReturningClause returning clause.} 842 */ 843 844 public TReturningClause getReturningClause() { 845 846 return returningClause; 847 } 848 849 public void setOutputClause(TOutputClause outputClause) { 850 setNewSubNode(this.outputClause,outputClause,getAnchorNode()); 851 this.outputClause = outputClause; 852 } 853 854 /** 855 * @return output clause. 856 */ 857 858 public TOutputClause getOutputClause() { 859 860 return outputClause; 861 } 862 863 public void setTopClause(TTopClause topClause) { 864 setNewSubNode(this.topClause,topClause,getAnchorNode()); 865 this.topClause = topClause; 866 } 867 868 /** 869 * @return {@link TTopClause top clause.} 870 */ 871 public TTopClause getTopClause() { 872 return topClause; 873 } 874 875 public void setWhereClause(TWhereClause newWhereClause){ 876 setNewSubNode(this.whereClause ,newWhereClause,getAnchorNode()); 877 this.whereClause = newWhereClause; 878 } 879 880 881 /** 882 * @deprecated As of 2.0.9.0, use {@link #setWhereClause(TWhereClause)} instead 883 * Or, use {@link TWhereClause#setText(String)} 884 * 885 * @param condition 886 * @return 887 */ 888 public TWhereClause addWhereClause(String condition){ 889 return this.whereClause; 890 } 891 892 /** 893 * restrict the rows selected to those that satisfy one or more conditions. 894 * used in select, delete, update statement. 895 * @return {@link TWhereClause where clause.} 896 */ 897 public TWhereClause getWhereClause() { 898 return whereClause; 899 } 900 901 public void setAlreadyAddToParent(boolean alreadyAddToParent) { 902 this.alreadyAddToParent = alreadyAddToParent; 903 } 904 905 private boolean alreadyAddToParent = false; 906 907 private boolean ableToIncludeCTE(ESqlStatementType sst){ 908 return ((sst == ESqlStatementType.sstselect) 909 ||(sst == ESqlStatementType.sstupdate) 910 ||(sst == ESqlStatementType.sstinsert) 911 ||(sst == ESqlStatementType.sstdelete) 912 ); 913 } 914 915 private TCTEList cteListInAllLevels = new TCTEList(); 916 917 protected TCTEList searchCTEList(Boolean stopAtFirstFinding){ 918 cteListInAllLevels.clear(); 919 if (cteList != null ) { 920 cteListInAllLevels.addAll(cteList); 921 if (stopAtFirstFinding) return cteListInAllLevels; 922 } 923 924 TCustomSqlStatement lcParent = this.parentStmt; 925 while (lcParent != null){ 926 if (!ableToIncludeCTE(lcParent.sqlstatementtype)) break; 927 928 if (lcParent.cteList != null) { 929 cteListInAllLevels.addAll(lcParent.cteList); 930 if (stopAtFirstFinding) break; 931 } 932 lcParent = lcParent.parentStmt; 933 } 934 return cteListInAllLevels; 935 } 936 937 938// protected TCTEList searchCTEList(){ 939// TCTEList ret = null; 940// if (cteList != null ) {return cteList;} 941// TCustomSqlStatement lcParent = this.parentStmt; 942// while (lcParent != null){ 943// if (!ableToIncludeCTE(lcParent.sqlstatementtype)) break; 944// ret = lcParent.cteList; 945// if (ret != null) break; 946// lcParent = lcParent.parentStmt; 947// } 948// return ret; 949// } 950 951 public TCustomSqlStatement getParentStmt() { 952 return parentStmt; 953 } 954 955 public TParseTreeNode getParentObjectName(){ 956 TParseTreeNode result = super.getParentObjectName(); 957 if (result != null) return result; 958 return getParentStmt(); 959 } 960 961 public void setParentStmt(TCustomSqlStatement parentStmt) { 962 if (!alreadyAddToParent){ 963 this.parentStmt = parentStmt; 964 if (this.parentStmt != null){ 965 parentStmt.getStatements().add(this); 966 alreadyAddToParent = true; 967 } 968 } 969 } 970 971 public void setParentStmtToNull() { 972 this.parentStmt = null; 973 } 974 975 private TCustomSqlStatement ancestorStmt = null; 976 977 public TCustomSqlStatement getAncestorStmt() { 978 TCustomSqlStatement lcRet = this; 979 while (lcRet.getParentStmt() != null){ 980 lcRet = lcRet.getParentStmt(); 981 } 982 return lcRet; 983 } 984 985 /** 986 * parent statement of this statement if any 987 */ 988 private TCustomSqlStatement parentStmt = null; 989 990 /** 991 * Original Parse tree node from parser 992 */ 993 public TParseTreeNode rootNode; 994 995 private Stack symbolTable = null; 996 997 /** 998 * 999 * @deprecated since ver 2.5.3.5, please use {@link TStmtScope} instead 1000 */ 1001 public Stack getSymbolTable() { 1002 if (symbolTable == null){ 1003 symbolTable = new Stack(); 1004 } 1005 return symbolTable; 1006 } 1007 1008 public TSourceToken semicolonended; 1009 public boolean isctequery; 1010 private ArrayList <TSyntaxError> syntaxErrors; 1011 1012 public ArrayList<TSyntaxError> getSyntaxErrors() { 1013 return syntaxErrors; 1014 } 1015 1016 public String getErrormessage(){ 1017 1018 String s="",hint="Syntax error"; 1019 TSyntaxError t; 1020 for (int i= 0; i< syntaxErrors.size(); i++) 1021 { 1022 t = (TSyntaxError) syntaxErrors.get(i); 1023 if (t.hint.length() > 0) hint = t.hint; 1024 s= s+hint+"("+t.errorno+") near: "+t.tokentext; 1025 s=s+"("+t.lineNo; 1026 s=s+","+t.columnNo +")"; 1027 //s=s+" expected tokentext:"+t.hint; 1028 1029 // break;//get only one message, remove this one and uncomment next line to get all error messages 1030 if (i != syntaxErrors.size() - 1) 1031 s = s +TBaseType.linebreak; 1032 } 1033 1034 return s; 1035 } 1036 1037 public ArrayList<TSyntaxError> getSyntaxHints() { 1038 return syntaxHints; 1039 } 1040 1041 private ArrayList <TSyntaxError> syntaxHints; 1042 1043 protected boolean isparsed; 1044 TSourceToken _semicolon; 1045 1046 /** 1047 * Number of syntax errors for this statement. 1048 * @return 0 means no syntax error. 1049 */ 1050 public int getErrorCount() { 1051 return syntaxErrors.size(); 1052 } 1053 1054 1055 public TCustomSqlStatement(EDbVendor dbvendor){ 1056 super(); 1057 this.dbvendor = dbvendor; 1058 sqlstatementtype = ESqlStatementType.sstunknown; 1059 dummytag = 0; 1060 sourcetokenlist = new TSourceTokenList(); 1061 syntaxErrors = new ArrayList<TSyntaxError>(4); 1062 syntaxHints = new ArrayList<TSyntaxError>(4); 1063 tables = new TTableList(); 1064 joins = new TJoinList(); 1065 indexColumns = new TPTNodeList<TColumnWithSortOrder>(); 1066 } 1067 1068 /** 1069 * Log error messages if syntax errors found while parsing this statement. 1070 * @param se syntax error structure. 1071 * @return type of error 1072 */ 1073 public EActionOnParseError parseerrormessagehandle(TSyntaxError se){ 1074 if (se.errortype == EErrorType.sphint){ 1075 this.getAncestorStmt().syntaxHints.add(se); 1076 }else 1077 this.getAncestorStmt().syntaxErrors.add(se); 1078 return EActionOnParseError.aopcontinue; 1079 } 1080 1081 public int parsestatement(TCustomSqlStatement pparentsql,boolean isparsetreeavailable){ 1082 return parsestatement(pparentsql,isparsetreeavailable,false); 1083 } 1084 1085 /** 1086 * Parse this statement. 1087 * @param pparentsql 1088 * @param isparsetreeavailable 1089 * @return parse result, zero means no syntax error found. 1090 */ 1091 public int parsestatement(TCustomSqlStatement pparentsql,boolean isparsetreeavailable, boolean onlyNeedRawParseTree){ 1092 int ret = 0; 1093 isparsed = false; 1094 if (!isparsetreeavailable){ 1095 ret = checksyntax(pparentsql); 1096 } 1097 if (ret == 0) 1098 { 1099 isparsed = true; 1100 if (!onlyNeedRawParseTree){ 1101 ret = doParseStatement(pparentsql); 1102 } 1103 }else if (dbvendor == EDbVendor.dbvsybase){ 1104 if ((this.rootNode != null)&& 1105 ((sqlstatementtype == ESqlStatementType.sstmssqlcreateprocedure) 1106 ||(sqlstatementtype == ESqlStatementType.sstmssqlcreatefunction) 1107 ||(sqlstatementtype == ESqlStatementType.sstcreatetrigger) 1108 )){ 1109 if (!onlyNeedRawParseTree){ 1110 doParseStatement(pparentsql); 1111 } 1112 1113 } 1114 } 1115 return ret; 1116 } 1117 1118 public boolean OracleStatementCanBeSeparatedByBeginEndPair(){ 1119 return ( 1120 1121 (this.sqlstatementtype == ESqlStatementType.sstplsql_createprocedure) 1122 //|| (this.sqlstatementtype == ESqlStatementType.sst_block_with_label) 1123 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createfunction) 1124 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createpackage) 1125 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtype_placeholder) 1126 ||(this.sqlstatementtype == ESqlStatementType.sstoraclecreatepackagebody) 1127 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtrigger) 1128// ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtypebody) 1129// ||(this.sqlstatementtype == ESqlStatementType.sstplsql_tabletypedef) 1130 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_varraytypedef) 1131 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createprocedure) 1132 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_execimmestmt) 1133 ||(this.sqlstatementtype == ESqlStatementType.sstoraclecreatelibrary) 1134 ); 1135 } 1136 1137 public boolean VerticaStatementCanBeSeparatedByBeginEndPair(){ 1138 return ( 1139 1140 (this.sqlstatementtype == ESqlStatementType.sstcreatefunction) 1141 ); 1142 } 1143 1144 public boolean isnzplsql(){ 1145 return ( 1146 (this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1147 ); 1148 } 1149 1150 public boolean ispgplsql(){ 1151 return (this instanceof TCommonBlock) 1152 ||(this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1153 ||(this.sqlstatementtype == ESqlStatementType.sstcreatefunction) 1154 ||(this.sqlstatementtype == ESqlStatementType.sstDoExecuteBlock) 1155 ; 1156 } 1157 1158 public boolean isGaussDBStoredProcedure(){ 1159 return (this instanceof TCommonBlock) 1160 ||(this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1161 ||(this.sqlstatementtype == ESqlStatementType.sstcreatefunction) 1162 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createpackage) 1163 ||(this.sqlstatementtype == ESqlStatementType.sstoraclecreatepackagebody) 1164 ||(this.sqlstatementtype == ESqlStatementType.sstDoExecuteBlock) 1165 ||(this.sqlstatementtype == ESqlStatementType.sstcreatetrigger) 1166 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtypebody) 1167 ; 1168 } 1169 1170 public boolean isdatabricksplsql(){ 1171 return (this instanceof TCommonBlock) 1172 ; 1173 } 1174 1175 public boolean isgreeplumplsql(){ 1176 return (this instanceof TCommonBlock) 1177 ||(this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1178 ||(this.sqlstatementtype == ESqlStatementType.sstcreatefunction) 1179 ||(this.sqlstatementtype == ESqlStatementType.sstDoExecuteBlock) 1180 ; 1181 } 1182 1183 public boolean isathenaplsql(){ 1184 return (this instanceof TCommonBlock) 1185 ; 1186 } 1187 1188 public boolean isprestoplsql(){ 1189 return (this instanceof TCommonBlock) 1190 ; 1191 } 1192 1193 public boolean issnowflakeplsql(){ 1194 return ((this instanceof TCommonBlock) 1195 ||(this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1196 ); 1197 } 1198 1199 public boolean isBigQueryplsql(){ 1200 return ((this instanceof TCommonBlock) 1201 ||(this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1202 ); 1203 } 1204 1205 public boolean isverticaplsql(){ 1206 return ( 1207 (this.sqlstatementtype == ESqlStatementType.sstcreatefunction) 1208 ); 1209 } 1210 1211 public boolean isoracleplsql(){ 1212 return ( 1213 (this.sqlstatementtype == ESqlStatementType.sst_plsql_block) 1214 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createprocedure) 1215 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createfunction) 1216 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createpackage) 1217 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtype_placeholder) 1218 ||(this.sqlstatementtype == ESqlStatementType.sstoraclecreatepackagebody) 1219 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtrigger) 1220 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtypebody) 1221 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_tabletypedef) 1222 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_varraytypedef) 1223 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createprocedure) 1224 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_execimmestmt) 1225 ||(this.sqlstatementtype == ESqlStatementType.sstoraclecreatelibrary) 1226 ); 1227 } 1228 1229 int checksyntax(TCustomSqlStatement psql){ 1230 return dochecksyntax(psql); 1231 } 1232 1233 protected int dochecksyntax(TCustomSqlStatement psql){ 1234 int ret = -1; 1235 clear(); 1236 if (sourcetokenlist.size() == 0) return ret; 1237 1238// TCustomParser lcparser; 1239// lcparser = new TLzParserOracleSql(sourcetokenlist); 1240// lcparser.sql = this; 1241// ret = lcparser.yyparse(); 1242 1243 1244 if (((this.dbvendor == EDbVendor.dbvoracle)||(this.dbvendor == EDbVendor.dbvoceanbase))&&(this.isoracleplsql()&&(plsqlparser!=null)) 1245// || ((this.dbvendor == EDbVendor.dbvgaussdb) // gaussdb 中用 oracle plsql 写的存储过程,用 oracle plsql parser 来解析 1246// &&( 1247// ((this instanceof TCreateFunctionStmt)&&(((TCreateFunctionStmt)this).isGaussDBSpInOracle())) 1248// ||((this instanceof TCreateProcedureStmt)&&(((TCreateProcedureStmt)this).isGaussDBSpInOracle())) 1249// ||(this instanceof TPlsqlCreatePackage) 1250// ) 1251// ) 1252 ){ 1253 plsqlparser.sql = this; 1254// if (this.dbvendor == EDbVendor.dbvgaussdb){ 1255// // 原来用 gaussDB lexer tokenize 的 token 需要用 Oracle lexer 重新 tokenize 一边 1256// String sqlText=""; 1257// for(int k = 0;k<sourcetokenlist.size();k++){ 1258// sqlText = sqlText + sourcetokenlist.get(k).toString(); 1259// } 1260// // TODO, need to use singleton pattern to get a single instance of Oracle parser. 1261// TGSqlParser sqlParser = new TGSqlParser(EDbVendor.dbvoracle); 1262// // keep coordinate of the origin query 1263// long originalLineNo = sourcetokenlist.get(0).lineNo; 1264// long originalColumnNo = sourcetokenlist.get(0).columnNo; 1265// sqlParser.sqltext = TBaseType.stringBlock((int) originalLineNo - 1,(int) originalColumnNo - 1)+ sqlText;; 1266// 1267// int r = sqlParser.getrawsqlstatements(); 1268// sourcetokenlist.clear(); 1269// for(int k=0;k<sqlParser.sourcetokenlist.size();k++){ 1270// sourcetokenlist.add(sqlParser.sourcetokenlist.get(k)); 1271// } 1272// } 1273 1274 plsqlparser.sourcetokenlist = sourcetokenlist; 1275 1276 if ((this instanceof TCommonStoredProcedureSqlStatement) 1277 &&((TCommonStoredProcedureSqlStatement)this).isWrapped()){ 1278 // don't parse wrapped oracle plsql 1279 ret = 0; 1280 this.rootNode = this; 1281 }else { 1282 ret = plsqlparser.yyparse(); 1283 this.rootNode = plsqlparser.rootNode; 1284 } 1285 } 1286 else{ 1287 if ((this.sqlstatementtype == ESqlStatementType.sstExplain)&&(dbvendor != EDbVendor.dbvhana)){ 1288 // EXPLAIN PLAN ... FOR statement; only parse token after FOR keyword 1289 boolean isFoundStopToken = false; 1290 1291 for(int k=0;k<sourcetokenlist.size();k++){ 1292 TSourceToken st = sourcetokenlist.get(k); 1293 switch (dbvendor){ 1294 case dbvoracle: 1295 if (st.tokencode == TBaseType.rrw_for) { 1296 st.tokencode = TBaseType.sqlpluscmd; 1297 isFoundStopToken = true; 1298 } 1299 break; 1300 case dbvdameng: 1301 if (st.tokencode == TBaseType.rrw_for) { 1302 st.tokencode = TBaseType.sqlpluscmd; 1303 isFoundStopToken = true; 1304 } 1305 break; 1306 case dbvredshift: 1307 if (st.tokencode == TBaseType.rrw_explain){ 1308 st.tokencode = TBaseType.sqlpluscmd; 1309 TSourceToken nextst = st.nextSolidToken(); 1310 if (nextst.tokencode == TBaseType.rrw_redshift_verbose){ 1311 nextst.tokencode = TBaseType.sqlpluscmd; 1312 //System.out.println("Found verbose after explain"); 1313 } 1314 isFoundStopToken = true; 1315 } 1316 break; 1317 case dbvvertica: 1318 if ((st.tokencode == TBaseType.rrw_select) 1319 ||(st.tokencode == TBaseType.rrw_insert) 1320 ||(st.tokencode == TBaseType.rrw_update) 1321 ||(st.tokencode == TBaseType.rrw_merge) 1322 ) 1323 { 1324 isFoundStopToken = true; 1325 } 1326 break; 1327 case dbvclickhouse: 1328 case dbvmysql: 1329 case dbvoceanbase: 1330 case dbvsparksql: 1331 case dbvdatabricks: 1332 if ((st.tokencode == TBaseType.rrw_select) 1333 ||(st.tokencode == TBaseType.rrw_insert) 1334 ||(st.tokencode == TBaseType.rrw_update) 1335 ||(st.tokencode == TBaseType.rrw_delete) 1336 ||(st.tokencode == TBaseType.rrw_replace) 1337 ||(st.tokencode == TBaseType.rrw_with) 1338 ||(st.tokencode == TBaseType.rrw_create) 1339 ||(st.tokencode == '(') 1340 ) 1341 { 1342 isFoundStopToken = true; 1343 } 1344 break; 1345 case dbvpostgresql: 1346 if ((st.tokencode == TBaseType.rrw_select) 1347 ||(st.tokencode == TBaseType.rrw_insert) 1348 ||(st.tokencode == TBaseType.rrw_update) 1349 ||(st.tokencode == TBaseType.rrw_delete) 1350 ||(st.tokencode == TBaseType.rrw_replace) 1351 ||(st.tokencode == TBaseType.rrw_with) 1352 ||(st.tokencode == TBaseType.rrw_create) 1353 ||(st.tokencode == TBaseType.rrw_execute) 1354 ) 1355 { 1356 isFoundStopToken = true; 1357 }else if (st.tokencode == '('){ 1358 // Check if this '(' starts EXPLAIN options like (COSTS FALSE) 1359 // or a subquery like (SELECT ...) 1360 TSourceToken nextSolid = sourcetokenlist.nextsolidtoken(k, 1, false); 1361 if (nextSolid != null 1362 && nextSolid.tokencode != TBaseType.rrw_select 1363 && nextSolid.tokencode != TBaseType.rrw_insert 1364 && nextSolid.tokencode != TBaseType.rrw_update 1365 && nextSolid.tokencode != TBaseType.rrw_delete 1366 && nextSolid.tokencode != TBaseType.rrw_with){ 1367 // Options list: skip past closing ')' 1368 int depth = 1; 1369 st.tokencode = TBaseType.sqlpluscmd; 1370 for (k = k + 1; k < sourcetokenlist.size() && depth > 0; k++){ 1371 TSourceToken inner = sourcetokenlist.get(k); 1372 if (inner.tokencode == '(') depth++; 1373 else if (inner.tokencode == ')') depth--; 1374 inner.tokencode = TBaseType.sqlpluscmd; 1375 } 1376 k--; // adjust for loop increment 1377 }else{ 1378 isFoundStopToken = true; 1379 } 1380 } 1381 break; 1382 case dbvduckdb: 1383 if ((st.tokencode == TBaseType.rrw_select) 1384 ||(st.tokencode == TBaseType.rrw_insert) 1385 ||(st.tokencode == TBaseType.rrw_update) 1386 ||(st.tokencode == TBaseType.rrw_delete) 1387 ||(st.tokencode == TBaseType.rrw_replace) 1388 ||(st.tokencode == TBaseType.rrw_with) 1389 ||(st.tokencode == TBaseType.rrw_create) 1390 ||(st.tokencode == TBaseType.rrw_alter) 1391 ||(st.tokencode == TBaseType.rrw_merge) 1392 ||(st.tokencode == '(') 1393 ) 1394 { 1395 isFoundStopToken = true; 1396 } 1397 break; 1398 case dbvflink: 1399 // Flink EXPLAIN can have: EXPLAIN (options) stmt or EXPLAIN options stmt 1400 // Don't stop at '(' because it might be part of EXPLAIN (ESTIMATED_COST, ...) 1401 if ((st.tokencode == TBaseType.rrw_select) 1402 ||(st.tokencode == TBaseType.rrw_insert) 1403 ||(st.tokencode == TBaseType.rrw_update) 1404 ||(st.tokencode == TBaseType.rrw_delete) 1405 ||(st.tokencode == TBaseType.rrw_replace) 1406 ||(st.tokencode == TBaseType.rrw_with) 1407 ||(st.tokencode == TBaseType.rrw_create) 1408 ) 1409 { 1410 isFoundStopToken = true; 1411 } 1412 break; 1413 case dbvcouchbase: 1414 if (st.tokencode == TBaseType.rrw_explain){ 1415 st.tokencode = TBaseType.sqlpluscmd; 1416 isFoundStopToken = true; 1417 } 1418 break; 1419 case dbvpresto: 1420 case dbvathena: 1421 case dbvnetezza: 1422 if ((st.tokencode == TBaseType.rrw_select) 1423 ||(st.tokencode == TBaseType.rrw_insert) 1424 ||(st.tokencode == TBaseType.rrw_update) 1425 ||(st.tokencode == TBaseType.rrw_delete) 1426 ) 1427 { 1428 isFoundStopToken = true; 1429 } 1430 break; 1431 case dbvteradata: 1432 if ((st.tokencode == TBaseType.rrw_select) 1433 ||(st.tokencode == TBaseType.rrw_insert) 1434 ||(st.tokencode == TBaseType.rrw_update) 1435 ||(st.tokencode == TBaseType.rrw_delete) 1436 ||(st.tokencode == TBaseType.rrw_teradata_collect) 1437 ) 1438 { 1439 isFoundStopToken = true; 1440 } 1441 break; 1442 }//switch 1443 1444 if (isFoundStopToken) break; 1445 st.tokencode = TBaseType.sqlpluscmd; 1446 } 1447 }else if (this.sqlstatementtype == ESqlStatementType.sstProfile){ 1448 for(int k=0;k<sourcetokenlist.size();k++) { 1449 TSourceToken st = sourcetokenlist.get(k); 1450 if (dbvendor == EDbVendor.dbvvertica){ 1451 if ((st.tokencode == TBaseType.rrw_select) 1452 ||(st.tokencode == TBaseType.rrw_insert) 1453 ||(st.tokencode == TBaseType.rrw_update) 1454 ||(st.tokencode == TBaseType.rrw_merge) 1455 ) 1456 { 1457 break; 1458 } 1459 } 1460 st.tokencode = TBaseType.sqlpluscmd; 1461 } 1462 }else if (this.sqlstatementtype == ESqlStatementType.sstprepare){ 1463 if ((dbvendor == EDbVendor.dbvcouchbase)||(dbvendor == EDbVendor.dbvpresto)||(dbvendor == EDbVendor.dbvathena)){ 1464 int keywordCount = 0; 1465 for(int k=0;k<sourcetokenlist.size();k++) { 1466 TSourceToken st = sourcetokenlist.get(k); 1467 if (st.tokencode == TBaseType.rrw_prepare) 1468 { 1469 keywordCount++; 1470 }else if ((st.tokentype == ETokenType.ttkeyword) 1471 &&(st.tokencode != TBaseType.rrw_from) 1472 &&(st.tokencode != TBaseType.rrw_as)){ 1473 keywordCount++; 1474 if (keywordCount > 1) break; 1475 } 1476 st.tokencode = TBaseType.sqlpluscmd; 1477 } 1478 } 1479 } 1480 1481 if (parser == null){ 1482 // statement such as select/insert and etc inside plsql 1483 if (psql != null){ 1484 parser = psql.getTopStatement().parser; 1485 this.setParentStmt(psql); 1486 } 1487 // parser = new TParserOracleSql(null); 1488 //parser.lexer = new TLexerOracle(); 1489 //parser.lexer.delimiterchar = '/'; 1490 } 1491 parser.sql = this; 1492 parser.sourcetokenlist = sourcetokenlist; 1493 ret = parser.yyparse(); 1494 this.rootNode = parser.rootNode; 1495 } 1496 1497 if (ret == 0){ 1498 ret = syntaxErrors.size(); 1499 } 1500 // if (rootNode == null) { 1501 if (rootNode == null) { 1502 // EXPLAIN FOR CONNECTION has no inner statement to parse - this is valid 1503 if (this.sqlstatementtype == ESqlStatementType.sstExplain && isExplainForConnection()) { 1504 ret = 0; 1505 } else { 1506 ret = TBaseType.MSG_ERROR_NO_ROOT_NODE; 1507 // todo , uncomment next line when all sql statements in .y file was processed 1508 parseerrormessagehandle( new TSyntaxError("no root node",0,0,"no_root_node",EErrorType.sperror,TBaseType.MSG_ERROR_NO_ROOT_NODE,this,-1)); 1509 } 1510 } 1511 return ret; 1512 } 1513 1514 private boolean isExplainForConnection() { 1515 if (sourcetokenlist == null) return false; 1516 for (int i = 0; i < sourcetokenlist.size() - 1; i++) { 1517 TSourceToken st = sourcetokenlist.get(i); 1518 if (st.toString().equalsIgnoreCase("for")) { 1519 TSourceToken next = sourcetokenlist.nextsolidtoken(i, 1, false); 1520 if (next != null && next.toString().equalsIgnoreCase("connection")) { 1521 return true; 1522 } 1523 } 1524 } 1525 return false; 1526 } 1527 1528 public void clearError(){ 1529 syntaxErrors.clear(); 1530 syntaxHints.clear(); 1531 } 1532 1533 void clear(){ 1534 syntaxErrors.clear(); 1535 syntaxHints.clear(); 1536// todo all subclass should add super() 1537 } 1538 1539 public void setStmtScope(TStmtScope stmtScope) { 1540 this.stmtScope = stmtScope; 1541 } 1542 1543 public TStmtScope getStmtScope() { 1544 return stmtScope; 1545 } 1546 1547 /** 1548 * Original SQL fragment of this statement. 1549 * @return Original statement text. 1550 */ 1551 1552 /* 1553 public String toString(){ 1554 StringBuffer sb = new StringBuffer(""); 1555 for(int i=0; i<sourcetokenlist.size();i++){ 1556 sb.append(sourcetokenlist.get(i).toString()); 1557 } 1558 return sb.toString(); 1559 } 1560 */ 1561 protected TStmtScope stmtScope = null; 1562 void buildsql(){} 1563 public int doParseStatement(TCustomSqlStatement psql){ 1564 if (psql != null){ 1565 this.setParentStmt(psql); 1566 this.setFrameStack(psql.getFrameStack()); 1567 psql.stmtScope.incrementCurrentStmtIndex(); 1568 this.queryId = String.format("%s#stmt_%d_%s", psql.getQueryId(),psql.stmtScope.getCurrentStmtIndex(), this.sqlstatementtype); 1569 stmtScope = new TStmtScope(psql.stmtScope,this); 1570 // psql.statements.add(this); 1571 }else{ 1572 stmtScope = new TStmtScope(this); 1573 1574 // global scope 1575 this.getFrameStack().peek().getScope().incrementCurrentStmtIndex(); 1576 this.queryId = String.format("stmt_%d_%s",this.getFrameStack().peek().getScope().getCurrentStmtIndex(), this.sqlstatementtype); 1577 } 1578 1579 if ((this.getStartToken() == null)&&(rootNode != null)){ 1580 this.setStartToken(rootNode.getStartToken()); 1581 } 1582 if ((this.getEndToken() == null)&&(rootNode != null)){ 1583 this.setEndToken(rootNode.getEndToken()); 1584 } 1585 1586 if(this.getGsqlparser() == null){ 1587 if (rootNode != null){ 1588 this.setGsqlparser(rootNode.getGsqlparser()); 1589 } 1590 } 1591 return 0; 1592 } 1593 1594 void addtokentolist(TSourceToken st){ 1595 st.stmt = this; 1596 sourcetokenlist.add(st); 1597 } 1598 1599 public TTable analyzeTablename(TObjectName tableName){ 1600 TTable lcTable = new TTable(); 1601 lcTable.setTableType(ETableSource.objectname); 1602 lcTable.setStartToken(tableName.getStartToken()); 1603 lcTable.setEndToken(tableName.getEndToken()); 1604 lcTable.setGsqlparser(this.getGsqlparser()); 1605 lcTable.setTableName(tableName); 1606 1607 tables.addTable(lcTable); 1608 return lcTable; 1609 } 1610 1611 protected boolean isTableACTE(TTable pTable){ 1612 boolean lcResult = false; 1613 TCTEList cteList1 = getCteList(); 1614 if (cteList1 == null){ 1615 TCustomSqlStatement lcStmt = getParentStmt(); 1616 while (lcStmt != null){ 1617 if (lcStmt.getCteList() != null){ 1618 cteList1 = lcStmt.getCteList(); 1619 break; 1620 }else { 1621 lcStmt = lcStmt.getParentStmt(); 1622 } 1623 } 1624 } 1625 if (cteList1 == null) return false; 1626 // TCTE lcCTE = cteList1.cteNames.get(TBaseType.getTextWithoutQuoted(pTable.toString()).toUpperCase()); 1627 if (pTable.toString() == null) return false; 1628 1629 int searchPos = pTable.getStartToken().posinlist; 1630 if (this.getCteIncludeThisStmt() != null){ 1631 searchPos = this.getCteIncludeThisStmt().getStartToken().posinlist; 1632 } 1633 TCTE lcCTE = cteList1.searchCTEByName(TBaseType.getTextWithoutQuoted(pTable.toString()).toUpperCase(),searchPos); 1634 if ( lcCTE != null ){ 1635 if (pTable.setCTE(lcCTE)){ 1636 pTable.setCTEName(true); 1637 lcResult = true; 1638 } 1639 } 1640// for (int i=0;i<cteList1.size();i++){ 1641// lcCTE = cteList1.getCTE(i); 1642// if (TBaseType.getTextWithoutQuoted(lcCTE.getTableName().toString()).equalsIgnoreCase(TBaseType.getTextWithoutQuoted(pTable.toString()))){ 1643// pTable.setCTEName(true); 1644// pTable.setCTE(lcCTE); 1645// lcResult = true; 1646// break; 1647// } 1648// } 1649 1650 return lcResult; 1651 1652 } 1653 1654 public TTable findTable(ETableEffectType[] tableEffectTypes){ 1655 TTable lcResult = null; 1656 for(int i=0;i<tables.size();i++){ 1657 for(int j=0;j<tableEffectTypes.length;j++){ 1658 if (tables.getTable(i).getEffectType() == tableEffectTypes[j]){ 1659 lcResult = tables.getTable(i); 1660 return lcResult; 1661 } 1662 } 1663 } 1664 return lcResult; 1665 } 1666 public void addToTables(TTable pTable){ 1667 tables.addTable(pTable); 1668 if (isTableACTE(pTable)) return; 1669 1670 if (pTable.getTableName() == null) return; 1671 if (pTable.getTableName().getTableToken() == null) return; 1672 if ((pTable.getTableName().getTableString().toString().equalsIgnoreCase("inserted"))||(pTable.getTableName().getTableString().toString().equalsIgnoreCase("deleted"))){ 1673 if ((getAncestorStmt().sqlstatementtype == ESqlStatementType.sstcreatetrigger) 1674 ||(getAncestorStmt().sqlstatementtype == ESqlStatementType.sstmssqlaltertrigger)){ 1675 //pTable.setLinkTable(true); 1676 ETableEffectType[] effectTypes = new ETableEffectType[]{ 1677 ETableEffectType.tetTriggerOn,ETableEffectType.tetTriggerInsert,ETableEffectType.tetTriggerDelete,ETableEffectType.tetTriggerUpdate,ETableEffectType.tetTriggerInsteadOf 1678 }; 1679 pTable.setLinkTable(getAncestorStmt().findTable(effectTypes)); 1680 } 1681 } 1682 1683 } 1684 1685 public TJoin analyzeTableOrJoin(TFromTable pfromTable){ 1686 TFromTable lcFromTable = pfromTable; 1687 TJoin lcJoin; 1688 TTable lcTable; 1689 1690 if (lcFromTable.getFromtableType() != ETableSource.join){ 1691 lcJoin = new TJoin(); 1692 lcTable = analyzeFromTable(lcFromTable,true); 1693 lcTable.setEffectType(ETableEffectType.tetSelect); 1694 lcJoin.setTable(lcTable); 1695 lcJoin.setStartToken(lcJoin.getTable().getStartToken()); 1696 lcJoin.setEndToken(lcJoin.getTable().getEndToken()); 1697 lcJoin.setGsqlparser(getGsqlparser()); 1698 this.fromSourceTable = lcTable; 1699 this.getRelations().add(lcTable); 1700 }else{ 1701 this.fromSourceJoin = lcFromTable.getJoinExpr(); 1702 1703 this.fromSourceTable = new TTable(); 1704 this.fromSourceTable.setTableType(ETableSource.join); 1705 this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause()); 1706 this.fromSourceTable.setStartToken(lcFromTable.getStartToken()); 1707 this.fromSourceTable.setEndToken(lcFromTable.getEndToken()); 1708 this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser()); 1709 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 1710 this.getRelations().add(this.fromSourceTable); 1711 1712 lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true); 1713 lcJoin.doParse(this, ESqlClause.join); 1714 1715 if (lcFromTable.getLateralViewList() != null){ 1716 for(TLateralView lateralView:lcFromTable.getLateralViewList()){ 1717 TTable t = lateralView.createATable(this); 1718 addToTables(t); 1719 this.relations.add(t); 1720 } 1721 } 1722 } 1723 1724 return lcJoin; 1725 } 1726 1727 public TTable analyzeFromTable(TFromTable pfromTable, Boolean addToTableList){ 1728 return analyzeFromTable(pfromTable,addToTableList,ESqlClause.unknown); 1729 } 1730 1731 public TTable analyzeFromTable(TFromTable pfromTable, Boolean addToTableList, ESqlClause pLocation){ 1732 TTable lcTable = new TTable(); 1733 lcTable.setTableType(pfromTable.getFromtableType()); 1734 lcTable.setAliasClause(pfromTable.getAliasClause()); 1735 lcTable.setStartToken(pfromTable.getStartToken()); 1736 lcTable.setEndToken(pfromTable.getEndToken()); 1737 lcTable.setGsqlparser(pfromTable.getGsqlparser()); 1738 lcTable.setTableHintList(pfromTable.getTableHintList()); 1739 lcTable.setTableSample(pfromTable.getTableSample()); 1740 lcTable.setLateralViewList(pfromTable.getLateralViewList()); 1741 lcTable.setTableProperties(pfromTable.getTableProperties()); 1742 lcTable.setPivotedTable(pfromTable.getPivotedTable()); 1743 lcTable.setParenthesisCount(pfromTable.getParenthesisCount()); 1744 lcTable.setParenthesisAfterAliasCount(pfromTable.getParenthesisAfterAliasCount()); 1745 lcTable.setTableKeyword(pfromTable.isTableKeyword()); 1746 lcTable.setOnlyKeyword(pfromTable.isOnlyKeyword()); 1747 lcTable.setFlashback(pfromTable.getFlashback()); 1748 lcTable.setPxGranule(pfromTable.getPxGranule()); 1749 lcTable.setTimeTravelClause(pfromTable.getTimeTravelClause()); 1750 //lcTable.setPartitionClause(pfromTable.getPartitionClause()); 1751 1752 if(getFrameStack().firstElement() != null){ 1753 TFrame stackFrame = getFrameStack().firstElement(); 1754 TGlobalScope globalScope = (TGlobalScope)stackFrame.getScope(); 1755 lcTable.setSqlEnv(globalScope.getSqlEnv()); 1756 } 1757 1758 switch(lcTable.getTableType()){ 1759 case objectname:{ 1760 // tables.addTableByTableRefernce(pfromTable.getTableObjectName()); 1761 boolean insertedInTrigger = false; 1762 if (getTopStatement().sqlstatementtype == ESqlStatementType.sstcreatetrigger){ 1763 insertedInTrigger = (pfromTable.getTableObjectName().toString().compareToIgnoreCase("inserted")==0); 1764 } 1765 1766 if (insertedInTrigger){ 1767 // change table name from inserted to onTable name in create trigger 1768 lcTable.setTableName(((TCreateTriggerStmt)getTopStatement()).getOnTable().getTableName()); 1769 //lcTable.setLinkTable(true); 1770 lcTable.setLinkTable(((TCreateTriggerStmt)getTopStatement()).getOnTable()); 1771 1772 }else{ 1773 lcTable.setTableName(pfromTable.getTableObjectName()); 1774 lcTable.getTableName().setSqlEnv(getSqlEnv()); 1775 1776// if (getSqlEnv().getDefaultCatalogName() != null){ 1777// if (lcTable.getTableName().getDatabaseToken() == null){ 1778// lcTable.getTableName().setDatabaseToken(new TSourceToken(getSqlEnv().getDefaultCatalogName()),true); 1779// } 1780// } 1781 1782// if ((lcTable.getTableName().getSchemaToken() == null)&&(TSQLEnv.supportSchema(this.dbvendor))){ 1783// // let find schema name for this table in env 1784// TSQLTable t = getSqlEnv().searchTable(".."+lcTable.getFullName()); 1785// if (t != null){ 1786// TSQLSchema s = t.getSchema(); 1787// if (s != null){ 1788// lcTable.getTableName().setSchemaToken(new TSourceToken(s.getName()),true); 1789// } 1790// } 1791// } 1792 1793 } 1794 // let's check is it cte name or ordinary table name 1795 TCTEList lcCteList = searchCTEList(false); 1796 TCTE lcCte = null; 1797 if (lcCteList != null){ 1798 for(int i=0;i<lcCteList.size();i++){ 1799 lcCte = lcCteList.getCTE(i); 1800 if (lcCte.getTableName().toString().compareToIgnoreCase(TBaseType.getTextWithoutQuoted(lcTable.getTableName().toString()))==0){ 1801 // this is cte name 1802 if (lcTable.setCTE(lcCte)){ 1803 lcTable.setCTEName(true); 1804 lcTable.setCteColomnReferences(lcCte.getColumnList()); 1805 break; 1806 } 1807 } 1808 } 1809 } 1810 1811 break; 1812 } 1813 case tableExpr:{ 1814 ESqlClause location = ESqlClause.tableExpr; //ESqlClause.resultColumn; 1815 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1816 // change location here 1817 } 1818 lcTable.setTableExpr(pfromTable.getTableExpr()); 1819 lcTable.getTableExpr().doParse(this,location); 1820 // teradata: SELECT table1.* FROM table(strtok_split_to_table(1, 'dm-calcite-raven/td/bq', '-') RETURNS (outkey integer, tokennum integer, token varchar(20)) ) as table1; 1821 // RETURNS (outkey integer, tokennum integer, token varchar(20)) 1822 lcTable.setColumnDefinitions(pfromTable.getColumnDefinitions()); 1823 // Teradata table function HASH BY and LOCAL ORDER BY clauses 1824 lcTable.setHashByClause(pfromTable.getHashByClause()); 1825 lcTable.setLocalOrderBy(pfromTable.getLocalOrderBy()); 1826 break; 1827 } 1828 case subquery:{ 1829// if (pfromTable.getSubquerynode().isHiveFromQuery()){ 1830// THiveFromQuery fromQuery = new THiveFromQuery(dbvendor); 1831// lcTable.setHiveFromQuery(fromQuery); 1832// fromQuery.rootNode = pfromTable.getSubquerynode(); 1833// fromQuery.setStartToken(pfromTable.getSubquerynode()); 1834// fromQuery.setEndToken(pfromTable.getSubquerynode()); 1835// fromQuery.setLabelName(this.labelName); 1836// fromQuery.doParseStatement(this); 1837// }else{ 1838// lcTable.subquery = new TSelectSqlStatement(dbvendor); 1839// lcTable.subquery.rootNode = pfromTable.getSubquerynode(); 1840// lcTable.subquery.setLocation(ESqlClause.elTable); 1841// //lcTable.subquery.resultColumnList = ((TSelectSqlNode)lcTable.subquery.rootNode).getResultColumnList(); 1842// lcTable.subquery.doParseStatement(this); 1843// } 1844 1845 lcTable.subquery = new TSelectSqlStatement(dbvendor); 1846 lcTable.subquery.rootNode = pfromTable.getSubquerynode(); 1847 if (pLocation == ESqlClause.unknown){ 1848 lcTable.subquery.setLocation(ESqlClause.elTable); 1849 }else{ 1850 lcTable.subquery.setLocation(pLocation); 1851 } 1852 //lcTable.subquery.resultColumnList = ((TSelectSqlNode)lcTable.subquery.rootNode).getResultColumnList(); 1853 lcTable.subquery.doParseStatement(this); 1854 1855 break; 1856 } 1857 case function:{ 1858 ESqlClause location = ESqlClause.tableFunction;// resultColumn; 1859 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1860 // change location here 1861 } 1862 lcTable.setFuncCall(pfromTable.getFuncCall()); 1863 lcTable.getFuncCall().doParse(this,location); 1864 break; 1865 } 1866 case containsTable:{ 1867 ESqlClause location = ESqlClause.containsTable;//resultColumn; 1868 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1869 // change location here 1870 } 1871 lcTable.setContainsTable(pfromTable.getContainsTable()); 1872 lcTable.getContainsTable().doParse(this,location); 1873 break; 1874 } 1875 1876 case openrowset:{ 1877 ESqlClause location = ESqlClause.openrowset;//resultColumn; 1878 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1879 // change location here 1880 } 1881 lcTable.setOpenRowSet(pfromTable.getOpenRowSet()); 1882 lcTable.getOpenRowSet().doParse(this,location); 1883 break; 1884 } 1885 1886 case openxml:{ 1887 ESqlClause location = ESqlClause.openxml;//resultColumn; 1888 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1889 // change location here 1890 } 1891 lcTable.setOpenXML(pfromTable.getOpenXML()); 1892 lcTable.getOpenXML().doParse(this,location); 1893 break; 1894 } 1895 1896 case opendatasource:{ 1897 ESqlClause location = ESqlClause.opendatasource;//resultColumn; 1898 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1899 // change location here 1900 } 1901 lcTable.setOpenDatasource(pfromTable.getOpenDatasource()); 1902 lcTable.getOpenDatasource().doParse(this,location); 1903 break; 1904 } 1905 1906 case openquery:{ 1907 ESqlClause location = ESqlClause.openquery;//resultColumn; 1908 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1909 // change location here 1910 } 1911 lcTable.setOpenquery(pfromTable.getOpenQuery()); 1912 lcTable.getOpenquery().doParse(this,location); 1913 lcTable.setSubquery(lcTable.getOpenquery().getSubquery()); 1914 break; 1915 } 1916 1917 case datachangeTable:{ 1918 ESqlClause location = ESqlClause.datachangeTable;//resultColumn; 1919 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1920 // change location here 1921 } 1922 lcTable.setDatachangeTable(pfromTable.getDatachangeTable()); 1923 lcTable.getDatachangeTable().doParse(this,location); 1924 break; 1925 } 1926 case rowList:{ 1927 ESqlClause location = ESqlClause.rowList;//resultColumn; 1928 lcTable.setValueClause(pfromTable.getValueClause()); 1929 lcTable.getValueClause().doParse(this,location); 1930 break; 1931 } 1932 case pivoted_table:{ 1933 ESqlClause location = ESqlClause.pivoted_table;//resultColumn; 1934 lcTable.getPivotedTable().doParse(this,location); 1935 addToTableList = false; 1936 targetTable = lcTable; 1937 break; 1938 } 1939 case xmltable:{ 1940 ESqlClause location = ESqlClause.xmltable;//resultColumn; 1941 lcTable.setXmlTable(pfromTable.getXmlTable()); 1942 lcTable.getXmlTable().doParse(this,location); 1943 break; 1944 } 1945 1946 case informixOuter:{ 1947 ESqlClause location = ESqlClause.outerTable;//resultColumn; 1948 lcTable.setOuterClause(pfromTable.getOuterClause()); 1949 lcTable.getOuterClause().doParse(this,location); 1950 break; 1951 } 1952 1953 case table_ref_list:{ 1954 lcTable.setFromTableList(pfromTable.getFromTableList()); 1955 break; 1956 } 1957// case hiveFromQuery:{ 1958// THiveFromQuery fromQuery = new THiveFromQuery(EDbVendor.dbvhive); 1959// fromQuery.rootNode = pfromTable.getFromQuerySqlNode(); 1960// fromQuery.doParseStatement(this); 1961// lcTable.setHiveFromQuery(fromQuery); 1962// break; 1963// } 1964 case output_merge:{ 1965 TMergeSqlStatement outputMerge = new TMergeSqlStatement(EDbVendor.dbvmssql); 1966 outputMerge.rootNode = pfromTable.getMergeSqlNode(); 1967 outputMerge.doParseStatement(this); 1968 lcTable.setOutputMerge(outputMerge); 1969 break; 1970 } 1971 case td_unpivot:{ 1972 // Set the TD_UNPIVOT output table before doParse so that VALUE_COLUMNS and 1973 // UNPIVOT_COLUMN can be linked to it (they are output columns of TD_UNPIVOT) 1974 pfromTable.getTdUnpivot().setTdUnpivotOutputTable(lcTable); 1975 pfromTable.getTdUnpivot().doParse(this,ESqlClause.tdUnPivot); 1976 lcTable.setTdUnpivot(pfromTable.getTdUnpivot()); 1977 break; 1978 } 1979 case unnest:{ 1980 pfromTable.getUnnestClause().doParse(this,ESqlClause.elTable); 1981 lcTable.setUnnestClause(pfromTable.getUnnestClause()); 1982 if (lcTable.getAliasClause() != null){ 1983 if (lcTable.getAliasClause().getColumns() != null){ 1984 for(TObjectName pColumn:lcTable.getAliasClause().getColumns()){ 1985 lcTable.getLinkedColumns().addObjectName(pColumn); 1986 pColumn.setSourceTable(lcTable); 1987 } 1988 }else if (lcTable.getAliasClause().getAliasName() != null){ 1989// SELECT * 1990// FROM UNNEST(['foo', 'bar', 'baz', 'qux', 'corge', 'garply', 'waldo', 'fred']) AS element 1991// WITH OFFSET AS offset 1992 1993 // add element as column of unnest table. 1994 TObjectName newColumn = TObjectName.createObjectName(this.dbvendor,EDbObjectType.column,lcTable.getAliasClause().getAliasName().getStartToken()); 1995 lcTable.getLinkedColumns().addObjectName(newColumn); 1996 newColumn.setSourceTable(lcTable); 1997 } 1998 } 1999 2000 if (lcTable.getUnnestClause().getWithOffset() != null){ 2001 if (lcTable.getUnnestClause().getWithOffsetAlais() != null){ 2002 // with offset as offsetAlias 2003 TAliasClause aliasClause = lcTable.getUnnestClause().getWithOffsetAlais(); 2004 if (aliasClause.getAliasName() != null){ 2005 TObjectName newColumn = TObjectName.createObjectName(this.dbvendor,EDbObjectType.column,aliasClause.getAliasName().getStartToken()); 2006 lcTable.getLinkedColumns().addObjectName(newColumn); 2007 newColumn.setSourceTable(lcTable); 2008 } 2009 }else{ 2010 // with offset 2011 TObjectName newColumn = TObjectName.createObjectName(this.dbvendor,EDbObjectType.column,new TSourceToken("offset")); 2012 lcTable.getLinkedColumns().addObjectName(newColumn); 2013 newColumn.setSourceTable(lcTable); 2014 } 2015 } 2016 2017 // link columns in the select list to unnest() 2018 // select emp_id,name,state,city,zipcode from `absolute-runner-302907.gudu_sqlflow.ADDRESS_NESTED`, UNNEST(address) 2019 if (lcTable.getUnnestClause().getDerivedColumnList() != null){ 2020 TObjectNameList derivedColumns = lcTable.getUnnestClause().getDerivedColumnList(); 2021 for(int i=0;i<derivedColumns.size();i++){ 2022 //System.out.println(derivedColumns.getObjectName(i).toString()); 2023 lcTable.getLinkedColumns().addObjectName(derivedColumns.getObjectName(i)); 2024 } 2025 } 2026 2027 break; 2028 } 2029 case jsonTable:{ 2030 ESqlClause location = ESqlClause.jsonTable;//resultColumn; 2031 lcTable.setJsonTable(pfromTable.getJsonTable()); 2032 lcTable.getJsonTable().doParse(this,location); 2033 break; 2034 } 2035 case externalTable: 2036 lcTable.setTableName(pfromTable.getTableObjectName()); 2037 lcTable.setColumnDefinitions(pfromTable.getColumnDefinitions()); 2038 lcTable.getColumnDefinitions().doParse(this,pLocation); 2039 lcTable.setTableType(ETableSource.externalTable); // tableType is reset in setTableName() method, so we reset it here 2040 break; 2041 case caseJoin: 2042 lcTable.setCaseJoin(pfromTable.getCaseJoin()); 2043 lcTable.getCaseJoin().doParse(this,pLocation); 2044 break; 2045 case stageReference: 2046 lcTable.setStageReference(pfromTable.getStageReference()); 2047 lcTable.getStageReference().doParse(this,pLocation); 2048 2049 lcTable.setTableName(lcTable.getStageReference().getStageName()); 2050 lcTable.setTableType(ETableSource.stageReference); 2051 lcTable.getTableName().setSqlEnv(getSqlEnv()); 2052 2053 break; 2054 2055 }//switch 2056 2057// if (pfromTable.getPivotClause() != null){ 2058// lcTable.setPivotClause(pfromTable.getPivotClause()); 2059// lcTable.getPivotClause().doParse(this,ESqlClause.resultColumn); 2060// } 2061 2062 lcTable.setPartitionExtensionClause(pfromTable.getPartitionExtensionClause()); 2063 2064 //tables.addTable(lcTable); 2065 if (addToTableList) { 2066 addToTables(lcTable); 2067 } 2068 2069 if (lcTable.getTableHintList() != null){ 2070 for(int i=0;i<lcTable.getTableHintList().size();i++){ 2071 TTableHint hint = lcTable.getTableHintList().getElement(i); 2072 hint.setOwnerTable(lcTable); 2073 hint.doParse(this,ESqlClause.tableHint); 2074 } 2075 } 2076 2077 if (lcTable.getLateralViewList() != null){ 2078 for(TLateralView lateralView:lcTable.getLateralViewList()){ 2079 TTable t = lateralView.createATable(this); 2080 addToTables(t); 2081 this.relations.add(t); 2082 } 2083 } 2084 2085 if (lcTable.getAliasClause() != null){ 2086 if (lcTable.getAliasClause().toString().equalsIgnoreCase("and")){ 2087 // end keyword can't be alias name 2088 TSourceToken st1 = lcTable.getAliasClause().getStartToken(); 2089 TSyntaxError err = new TSyntaxError(st1.toString() 2090 ,st1.lineNo,st1.columnNo 2091 ,String.format("AND keyword can't be table alias") 2092 ,EErrorType.sperror 2093 ,TBaseType.MSG_ERROR_AND_KEYWORD_CANT_USED_AS_TABLE_ALIAS 2094 ,this,st1.posinlist); 2095 this.parseerrormessagehandle( err); 2096 2097 } 2098 } 2099 2100 return lcTable; 2101 } 2102 2103 public TJoin analyzeJoin(TJoinExpr pJoinExpr,TJoin pJoin,Boolean isSub){ 2104 TJoin retval = pJoin; 2105 TJoinItem lcJoinItem = null ; 2106 2107 if (pJoinExpr == null) {return retval;} 2108 2109 if (pJoinExpr.getJointype() == EJoinType.nested) 2110 { 2111 if (isSub) 2112 { 2113 if (retval == null) { // top level, left side is a join 2114 retval = new TJoin(); 2115 retval.setStartToken(pJoinExpr.getStartToken()); 2116 retval.setEndToken(pJoinExpr.getEndToken()); 2117 } 2118 2119 pJoinExpr.setJointype(pJoinExpr.original_jontype); 2120 retval.setJoin(analyzeJoin(pJoinExpr,null,true)); 2121 //retval =analyzeJoin(pJoinExpr,null,true); 2122 retval.setKind(TBaseType.join_source_join); 2123 retval.getJoin().setAliasClause(pJoinExpr.getAliasClause()); 2124 retval.getJoin().setWithParen(true); 2125 retval.getJoin().setNestedParen(pJoinExpr.getNestedParen()); 2126 } 2127 else 2128 { 2129 if (retval == null) 2130 { 2131 retval = new TJoin(); 2132 retval.setStartToken(pJoinExpr.getStartToken()); 2133 retval.setEndToken(pJoinExpr.getEndToken()); 2134 retval.setGsqlparser(this.getGsqlparser()); 2135 } 2136 else 2137 { 2138 } 2139 pJoinExpr.setJointype(pJoinExpr.original_jontype); 2140 retval = analyzeJoin(pJoinExpr,retval,false); 2141 //retval.setJoin(analyzeJoin(pJoinExpr,retval,false)); 2142 //retval = analyzeJoin(pJoinExpr,retval,false); 2143 //retval.setKind(TBaseType.join_source_join); 2144 //retval.setKind(TBaseType.join_source_table); 2145 //retval.setAliasClause(pJoinExpr.getAliasClause()); 2146 retval.setAliasClause(pJoinExpr.getAliasClause()); 2147 retval.setWithParen(true); 2148 retval.setNestedParen(pJoinExpr.getNestedParen()); 2149 } 2150 return retval; 2151 } 2152 2153 if (pJoinExpr.getLeftOperand().getFromtableType() != ETableSource.join){ 2154 if (retval == null) { 2155 retval = new TJoin(); 2156 retval.setStartToken(pJoinExpr.getStartToken()); 2157 retval.setEndToken(pJoinExpr.getEndToken()); 2158 retval.setGsqlparser(this.getGsqlparser()); 2159 2160 // retval.setStartToken(pJoinExpr.getLeftOperand().getStartToken()); 2161 // retval.setEndToken(pJoinExpr.getLeftOperand().getEndToken()); 2162 } 2163 TTable lcTable = analyzeFromTable(pJoinExpr.getLeftOperand(),true,ESqlClause.join); 2164 lcTable.setEffectType(ETableEffectType.tetSelect); 2165 retval.setTable(lcTable); 2166 //retval.joinTable.OwnerJoin = result; 2167 retval.setKind(TBaseType.join_source_table); 2168 pJoinExpr.setLeftTable(lcTable); 2169 }else{ 2170 TJoinExpr lcJoinItemJoinExpr = pJoinExpr.getLeftOperand().getJoinExpr(); 2171 //if (lcJoinItemJoinExpr.getJointype() == TBaseType.join_nested){ 2172 // lcJoinItemJoinExpr.setJointype(lcJoinItemJoinExpr.original_jontype); 2173 //} 2174 2175 if (retval != null) { 2176 retval = analyzeJoin(lcJoinItemJoinExpr,retval,true); 2177 } else { 2178 retval = analyzeJoin(lcJoinItemJoinExpr,retval,isSub); 2179 } 2180 retval.setStartToken(lcJoinItemJoinExpr.getStartToken()); 2181 retval.setEndToken(lcJoinItemJoinExpr.getEndToken()); 2182 2183 2184 TTable lcTable = new TTable(); 2185 lcTable.setTableType(pJoinExpr.getLeftOperand().getFromtableType()); 2186 lcTable.setAliasClause(lcJoinItemJoinExpr.getAliasClause()); 2187 lcTable.setStartToken(lcJoinItemJoinExpr.getStartToken()); 2188 lcTable.setEndToken(lcJoinItemJoinExpr.getEndToken()); 2189 pJoinExpr.setLeftTable(lcTable); 2190 lcTable.setJoinExpr(lcJoinItemJoinExpr); 2191 } 2192 2193 if (pJoinExpr.getRightOperand().getFromtableType() != ETableSource.join){ 2194 if (retval != null) 2195 { 2196 lcJoinItem = new TJoinItem(); 2197 TTable lcTable = analyzeFromTable(pJoinExpr.getRightOperand(),true,ESqlClause.join); 2198 lcTable.setEffectType(ETableEffectType.tetSelect); 2199 lcJoinItem.setTable(lcTable); 2200 lcJoinItem.setStartToken(lcJoinItem.getTable().getStartToken()); 2201 lcJoinItem.setEndToken(lcJoinItem.getTable().getEndToken()); 2202 // lcJoinItem.JoinItemTable.OwnerJoinItem := lcJoinItem; 2203 lcJoinItem.setKind(TBaseType.join_source_table); 2204 retval.getJoinItems().addJoinItem(lcJoinItem); 2205 pJoinExpr.setRightTable(lcTable); 2206 } 2207 }else{ 2208 if (retval != null) 2209 { 2210 lcJoinItem = new TJoinItem(); 2211 lcJoinItem.setKind(TBaseType.join_source_join); 2212 TJoinExpr lcJoinItemJoinExpr = pJoinExpr.getRightOperand().getJoinExpr(); 2213 //if (lcJoinItemJoinExpr.getJointype() == TBaseType.join_nested){ 2214 // lcJoinItemJoinExpr.setJointype(lcJoinItemJoinExpr.original_jontype); 2215 //} 2216 lcJoinItem.setJoin(analyzeJoin(pJoinExpr.getRightOperand().getJoinExpr(),null,false)); 2217 lcJoinItem.getJoin().setAliasClause(lcJoinItemJoinExpr.getAliasClause()); 2218 lcJoinItem.setStartToken(lcJoinItem.getJoin().getStartToken()); 2219 lcJoinItem.setEndToken(lcJoinItem.getJoin().getEndToken()); 2220 retval.getJoinItems().addJoinItem(lcJoinItem); 2221 2222 TTable lcTable = new TTable(); 2223 lcTable.setTableType(pJoinExpr.getRightOperand().getFromtableType()); 2224 lcTable.setAliasClause(lcJoinItemJoinExpr.getAliasClause()); 2225 lcTable.setStartToken(lcJoinItemJoinExpr.getStartToken()); 2226 lcTable.setEndToken(lcJoinItemJoinExpr.getEndToken()); 2227 pJoinExpr.setRightTable(lcTable); 2228 lcTable.setJoinExpr(lcJoinItemJoinExpr); 2229 } 2230 } 2231 2232 if (lcJoinItem == null) return retval; 2233 2234 lcJoinItem.setJoinType(pJoinExpr.getJointype()); 2235 lcJoinItem.setUsingColumns(pJoinExpr.usingColumns); 2236 if ((lcJoinItem.getUsingColumns() != null) && (tables.size()>1)){ 2237 TObjectName crf ; 2238 for (int i=0;i<lcJoinItem.getUsingColumns().size();i++){ 2239 crf = lcJoinItem.getUsingColumns().getObjectName(i); 2240 // link this column to last 2 tables 2241 tables.getTable(tables.size()-1).getObjectNameReferences().addObjectName(crf); 2242 tables.getTable(tables.size()-2).getObjectNameReferences().addObjectName(crf); 2243 2244 tables.getTable(tables.size()-1).getLinkedColumns().addObjectName(crf); 2245 crf.setSourceTable(tables.getTable(tables.size()-1)); 2246 tables.getTable(tables.size()-2).getLinkedColumns().addObjectName(crf); 2247 crf.setSourceTable(tables.getTable(tables.size()-2)); 2248 2249 } 2250 lcJoinItem.setEndToken(lcJoinItem.getUsingColumns().getEndToken()); 2251 } 2252 lcJoinItem.setOnCondition(pJoinExpr.onCondition); 2253 if (lcJoinItem.getOnCondition() != null) 2254 { 2255 lcJoinItem.getOnCondition().doParse(this,ESqlClause.joinCondition); 2256 lcJoinItem.setEndToken(lcJoinItem.getOnCondition().getEndToken()); 2257 } 2258 2259 2260 return retval; 2261 } 2262 2263 public boolean locateVariableOrParameter(TObjectName cr){ 2264 return locateVariableOrParameter(cr,false); 2265 } 2266 2267 public boolean locateVariableOrParameter(TObjectName cr, boolean checkVariableDeclaredInProcedure){ 2268 boolean ret = false; 2269 if (cr.getDbObjectType() == EDbObjectType.variable) return true; 2270 if (cr.toString().equalsIgnoreCase("*")) return false; 2271 //search variable in framestack 2272 2273 TVariable symbolVariable = null; 2274 2275 if (cr.getTableToken() != null){ 2276 // record_variable.column 2277 symbolVariable = TSymbolTableManager.searchSymbolVariable(this.getFrameStack(),cr.getTableToken().toString()); 2278 if (symbolVariable != null){ 2279 cr.getTableToken().setDbObjectType(EDbObjectType.variable); 2280 //TTable sourceTable = new TTable(new TObjectName(EDbObjectType.table,symbolVariable.getVariableName().getStartToken())); 2281 TTable sourceTable = new TTable(TObjectName.createObjectName (this.dbvendor, EDbObjectType.variable,symbolVariable.getVariableName().getStartToken())); 2282 sourceTable.getLinkedColumns().addObjectName(cr); 2283 cr.setSourceTable(sourceTable); 2284 // symbolVariable.getVariableName().getReferencedObjects().addObjectName(cr); 2285 // System.out.println("find variable:"+cr.toString()); 2286 cr.setResolveStatus(TBaseType.RESOLVED_AND_FOUND); // set resolve status to resolved,避免在 TAttributeResolver 中关联到其他 table 2287 return true; 2288 } 2289 2290 }else{ 2291 // variable 2292 symbolVariable = TSymbolTableManager.searchSymbolVariable(this.getFrameStack(),cr.toString()); 2293 if (symbolVariable != null){ 2294 cr.setDbObjectType(EDbObjectType.variable); 2295 symbolVariable.getVariableName().getReferencedObjects().addObjectName(cr); 2296 return true; 2297 } 2298 } 2299 2300 // check parameters in plsql only, may add support for sql server later. 2301 if(! ((dbvendor == EDbVendor.dbvoracle)||(dbvendor == EDbVendor.dbvmysql))) return false; 2302 if (cr.getObjectType() == TObjectName.ttobjVariable) return true; 2303 2304 Stack symbolTable = this.getTopStatement().getSymbolTable(); 2305 TSymbolTableItem item = null; 2306 TObjectName objName = null; 2307 TObjectName qualifiedName = null; // function/procedure name or label name of plsql block 2308 for (int i = symbolTable.size()-1;i>=0;i--){ 2309 item = (TSymbolTableItem)symbolTable.get(i); 2310 if (item.getData() instanceof TParameterDeclaration){ 2311 objName = ((TParameterDeclaration)item.getData()).getParameterName(); 2312 }else if (item.getData() instanceof TVarDeclStmt){ 2313 objName = ((TVarDeclStmt)item.getData()).getElementName(); 2314 }else if (item.getData() instanceof TObjectName){ 2315 objName = (TObjectName)item.getData(); 2316 } 2317 2318 if (objName == null) continue; 2319 2320 if (cr.toString().compareToIgnoreCase(objName.toString()) == 0){ 2321 ret = true; 2322 if (checkVariableDeclaredInProcedure) break; // return true if variable declared in procedure 2323 for(int j=0;i<tables.size();i++){ 2324 TTable lcTable = tables.getTable(j); 2325 if (lcTable.isBaseTable()){ 2326 if (fireOnMetaDatabaseTableColumn( 2327 lcTable.getPrefixServer() 2328 ,lcTable.getPrefixDatabase() 2329 ,lcTable.getPrefixSchema() 2330 ,lcTable.getName() 2331 ,cr.getColumnNameOnly())){ 2332 ret = false; 2333 break; 2334 } 2335 } 2336 } 2337 2338 if (ret) break; 2339 }else if (cr.toString().indexOf(".")>0){ 2340 // qualified object reference, compare it with procedure/function/block label prefixed 2341 if (item.getStmt() instanceof TPlsqlCreateFunction){ 2342 qualifiedName = ((TPlsqlCreateFunction)item.getStmt()).getFunctionName(); 2343 }else if (item.getStmt() instanceof TPlsqlCreateProcedure){ 2344 qualifiedName = ((TPlsqlCreateProcedure)item.getStmt()).getProcedureName(); 2345 }else if (item.getStmt() instanceof TCommonBlock){ 2346 qualifiedName = ((TCommonBlock)item.getStmt()).getLabelName(); 2347 } 2348 2349 if (qualifiedName != null){ 2350 if (cr.toString().compareToIgnoreCase(qualifiedName.toString()+'.'+objName.toString()) == 0){ 2351 ret = true; 2352 } 2353 } 2354 2355 if (ret ) break; 2356 } 2357 2358 } 2359 if (ret){ 2360 //add this parameter or variable reference to original parameter/variable 2361 objName.getReferencedObjects().addObjectName(cr); 2362 cr.setObjectType(TObjectName.ttobjVariable); 2363 } 2364 return ret; 2365 } 2366 2367 TCTE findCTEByName(String cteName){ 2368 TCTEList lcCteList = searchCTEList(false); 2369 TCTE lcCte = null; 2370 if (lcCteList != null){ 2371 for(int i=0;i<lcCteList.size();i++){ 2372 if (lcCteList.getCTE(i).getTableName().toString().compareToIgnoreCase(cteName)==0){ 2373 lcCte = lcCteList.getCTE(i); 2374 break; 2375 } 2376 } 2377 } 2378 return lcCte; 2379 } 2380 2381 /** 2382 * @deprecated since 2.3.8.2, use {@link TTable#getExpandedStarColumns()} instead. 2383 * 2384 * @param lcTable 2385 * @return 2386 */ 2387 public ArrayList<String> getColumnsInTable(TTable lcTable){ 2388 if (lcTable.isCTEName()){ 2389 ArrayList<String> columns = new ArrayList<>(); 2390 if (lcTable.getCteColomnReferences()!=null){ 2391 for(TObjectName n:lcTable.getCteColomnReferences()){ 2392 columns.add(n.toString()); 2393 } 2394 }else if (lcTable.getCTE().getSubquery() != null && lcTable.getCTE().getSubquery().getResultColumnList() != null){ 2395 for(TResultColumn resultColumn:lcTable.getCTE().getSubquery().getResultColumnList()){ 2396 columns.add(resultColumn.getDisplayName()); 2397 } 2398 } 2399 return columns; 2400 }else{ 2401 return getColumnsInTable( 2402 lcTable.getPrefixServer() 2403 ,lcTable.getPrefixDatabase() 2404 ,lcTable.getPrefixSchema() 2405 ,lcTable.getName() 2406 ); 2407 } 2408 } 2409 2410 2411 /** 2412 * @deprecated since 2.3.8.2, use {@link TTable#getExpandedStarColumns()} instead. 2413 * 2414 * @param pServer 2415 * @param pDatabase 2416 * @param pSchema 2417 * @param pTable 2418 * @return 2419 */ 2420 public ArrayList<String> getColumnsInTable(String pServer,String pDatabase,String pSchema,String pTable){ 2421 TFrame stackFrame = getFrameStack().firstElement(); 2422 TGlobalScope globalScope = (TGlobalScope)stackFrame.getScope(); 2423 2424 if (globalScope.getSqlEnv() != null){ 2425 return globalScope.getSqlEnv().getColumnsInTable(pDatabase+"."+pSchema+"."+pTable,false); 2426 }else{ 2427 return null; 2428 } 2429 } 2430 2431 2432 public boolean fireOnMetaDatabaseTableColumn(String pServer,String pDatabase,String pSchema,String pTable,String pColumn){ 2433// boolean lcResult = false; 2434// if (this.getGsqlparser().getMetaDatabase() != null){ 2435// lcResult = this.getGsqlparser().getMetaDatabase().checkColumn(pServer,pDatabase,pSchema,pTable,pColumn); 2436// } 2437 2438 TFrame stackFrame = getFrameStack().firstElement(); 2439 TGlobalScope globalScope = (TGlobalScope)stackFrame.getScope(); 2440 2441 if (globalScope.getSqlEnv() != null){ 2442 // System.out.println(globalScope.getSqlEnv().toString()); 2443 2444 return globalScope.getSqlEnv().columnInTable(pDatabase+"."+pSchema+"."+pTable,pColumn); 2445 }else{ 2446 return false; 2447 } 2448 2449// return lcResult; 2450 } 2451 2452 public TTable getFirstPhysicalTable(){ 2453 TTable ret = null; 2454 if (tables.size() == 0) return null; 2455 for(int i=0;i<tables.size();i++){ 2456 if (tables.getTable(i).isBaseTable()) { 2457 ret = tables.getTable(i); 2458 break; 2459 } 2460 } 2461 return ret; 2462 } 2463 private TObjectNameList orphanColumns = null; 2464 2465 public TObjectNameList getOrphanColumns() { 2466 if (orphanColumns == null) orphanColumns = new TObjectNameList(); 2467 return orphanColumns; 2468 } 2469 2470 protected boolean linkToFirstTable(TObjectName pColumn,int pCandidateTableCnt){ 2471 boolean lcResult = false; 2472 if ((dbvendor == EDbVendor.dbvteradata)&&(pColumn.isQualified())&&(pColumn.getTableToken().getDbObjectType() != EDbObjectType.subquery_alias)){ 2473 // update table1 set col = 'value' where table1.id = table2.id2 2474 boolean isFoundLinkedTable = false; 2475 TCustomSqlStatement lcSql = this; 2476 while (lcSql != null){ 2477 int i = 0; 2478 i = lcSql.tables.searchTableByNameOrAlias(pColumn.getTableToken().toString()); 2479 isFoundLinkedTable = ( i != -1); 2480 if (isFoundLinkedTable) { 2481 if (lcSql.tables.getTable(i).getEffectType() == ETableEffectType.tetImplicitLateralDerivedTable ){ 2482 // 如果不查重table,会导致 employee.first_name 中的 employee 被第二次加到 tables 中 2483// DELETE FROM foodmart.trimmed_employee ACT 2484// WHERE ACT.employee_id = employee.employee_id 2485// AND employee.first_name = 'Walter' 2486// AND trimmed_salary.employee_id = -1 2487 2488 TTable newTable = lcSql.tables.getTable(i); 2489 newTable.getLinkedColumns().addObjectName(pColumn); 2490 pColumn.setSourceTable(newTable); 2491 pColumn.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_TABLE_IN_OLD_ALGORITHM); 2492 } 2493 break; 2494 } 2495 lcSql = lcSql.getParentStmt(); 2496 } 2497 if (!isFoundLinkedTable){ 2498 TTable newTable = null; 2499 if (pColumn.getDatabaseToken() == null){ 2500 2501 //newTable = new TTable(new TObjectName(EDbObjectType.table,pColumn.getTableToken())); 2502 newTable = new TTable(TObjectName.createObjectName (this.dbvendor, EDbObjectType.table,pColumn.getTableToken())); 2503 newTable.setStartToken(pColumn.getTableToken()); 2504 newTable.setEndToken(pColumn.getTableToken()); 2505 }else{ 2506 2507 //newTable = new TTable(new TObjectName(EDbObjectType.table,pColumn.getSchemaToken(), pColumn.getTableToken())); 2508 newTable = new TTable(TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,pColumn.getDatabaseToken(), pColumn.getTableToken())); 2509 newTable.setStartToken(pColumn.getSchemaToken()); 2510 newTable.setEndToken(pColumn.getTableToken()); 2511 } 2512 2513 newTable.setTableType(ETableSource.objectname); 2514 newTable.setEffectType(ETableEffectType.tetImplicitLateralDerivedTable); 2515 newTable.getLinkedColumns().addObjectName(pColumn); 2516 pColumn.setSourceTable(newTable); 2517 pColumn.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_TABLE_IN_OLD_ALGORITHM); 2518 this.addToTables(newTable); 2519 2520 // 2024 年 2521 // 不能加入到 relations 中,否则会导致 下面 SQL 中 star column 同时链接到 SPCOMM.L_FIXED_RATE_PLAN_REF, ipshare_ofccplv.cprof_d_period_dates_ref 2522 // 从而导致 本来不该有的歧义产生 2523 2524 // UPDATE b_rate_plan 2525 //FROM 2526 //( 2527 //SELECT * FROM SPCOMM.L_FIXED_RATE_PLAN_REF 2528 //WHERE rate_plan_ref_eff_dt<= ipshare_ofccplv.cprof_d_period_dates_ref.PERIOD 2529 //) AS ref 2530 //SET accs_fee = REF.accs_fee, 2531 //SVC_TYPE = REF.prod_grp_lvl_1, 2532 //rate_plan_lvl3 = REF.rate_plan_lvl_3, 2533 //prod_grp_lvl3 = REF.prod_grp_lvl_2 2534 //WHERE b_rate_plan.svc_type IS NULL 2535 2536 // 2025/2/25, v3.0.4.8 2537 // 需要加入到 relations 中,新的 gudusoft.gsqlparser.resolver package 中的算法会处理这种情况 2538 // teradata 的隐式横向派生表不能加入到关系解析器中 2539 // this.getRelations().add(newTable); 2540 } 2541 return true; 2542 } 2543 if (pColumn.getCandidateTables().size() == 1){ 2544 TTable table = pColumn.getCandidateTables().getTable(0); 2545 table.getLinkedColumns().addObjectName(pColumn); 2546 pColumn.setSourceTable(table); 2547 lcResult = true; 2548 } 2549 else if ((tables.size() == 1) || (pCandidateTableCnt == 1)){ 2550 TTable table = tables.getTable(0); 2551 2552 if(table.getTableType() == ETableSource.function){ 2553 //lcResult = linkToFunctionTable(table, pColumn); 2554 int iRet = table.getFuncCall().isColumnInThisTableFunction(this.getSqlEnv(),this.dbvendor,pColumn); 2555 if ( iRet == TBaseType.COLUMN_IN_TABEL_FUNCTION_YES){ 2556 lcResult = true; 2557 table.getLinkedColumns().addObjectName(pColumn); 2558 pColumn.setSourceTable(table); 2559 lcResult = true; 2560 }else if ( iRet == TBaseType.COLUMN_IN_TABEL_FUNCTION_NO){ 2561 lcResult = false; 2562 }else{ 2563 table.getLinkedColumns().addObjectName(pColumn); 2564 pColumn.setSourceTable(table); 2565 lcResult = true; 2566 } 2567 }else if(table.getTableType() == ETableSource.subquery){ 2568 if (! table.getSubquery().searchColumnInResultSet(pColumn,(tables.size()==1))){ 2569 getOrphanColumns().addObjectName(pColumn); 2570 pColumn.setOrphanColumn(true); 2571 pColumn.setOwnStmt(this); 2572 TSourceToken st = pColumn.getStartToken(); 2573 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 2574 TBaseType.log(String.format("Add orphan column <%s> to statement in old algorithm in subquery %s",pColumn.toString(),table.getAliasName()),TLog.WARNING,table); 2575 } 2576 this.parseerrormessagehandle(new TSyntaxError(st.getAstext(), st.lineNo, st.columnNo 2577 ,"find orphan column", EErrorType.sphint 2578 , TBaseType.MSG_HINT_FIND_ORPHAN_COLUMN,this,st.posinlist,pColumn)); 2579 } 2580 } 2581 else{ 2582 table.getLinkedColumns().addObjectName(pColumn); 2583 pColumn.setSourceTable(table); 2584 lcResult = true; 2585 if ((dbvendor == EDbVendor.dbvbigquery)&&(pCandidateTableCnt == 0) && (pColumn.isQualified())){ 2586 // bigquery struct column used in query 2587// create view test as (SELECT rollNo, 2588// info.name as n1, 2589// info2.name as n2, 2590// info.age from my_first_dataset.student_records); 2591 2592 pColumn.columnToProperty(); 2593 } 2594 } 2595 }else if (tables.size() > 1){ 2596 // if there is only a table without table alias, then, link to this table 2597 boolean foundOnlyOneTable = false; 2598 TTable tableWithoutAlias = null; 2599 for(TTable table:tables){ 2600 if (table.isCTEName()) continue; // CTE 即便没有 指定alias,也不作为考虑对象 2601 if (table.getAliasClause() == null){ 2602 tableWithoutAlias = table; 2603 if (foundOnlyOneTable){ 2604 foundOnlyOneTable = false; 2605 break; 2606 }else{ 2607 foundOnlyOneTable = true; 2608 } 2609 } 2610 } 2611 2612 if (foundOnlyOneTable){ 2613 tableWithoutAlias.getLinkedColumns().addObjectName(pColumn); 2614 pColumn.setSourceTable(tableWithoutAlias); 2615 lcResult = true; 2616 }else{ 2617 getOrphanColumns().addObjectName(pColumn); 2618 pColumn.setOrphanColumn(true); 2619 pColumn.setOwnStmt(this); 2620 TSourceToken st = pColumn.getStartToken(); 2621 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 2622 TBaseType.log(String.format("Add orphan column <%s> to statement in old algorithm ",pColumn.toString()),TLog.WARNING,this); 2623 } 2624 2625 this.parseerrormessagehandle(new TSyntaxError(st.getAstext(), st.lineNo, st.columnNo 2626 ,"find orphan column", EErrorType.sphint 2627 , TBaseType.MSG_HINT_FIND_ORPHAN_COLUMN,this,st.posinlist,pColumn)); 2628 } 2629 2630 } 2631 return lcResult; 2632 } 2633 2634 private boolean linkToFunctionTable(TTable table, TObjectName pColumn) { 2635 if(table.getTableName().toString().toUpperCase().equals("STRING_SPLIT")){ 2636 if(pColumn.getColumnNameOnly().toUpperCase().equals("VALUE")){ 2637 table.getLinkedColumns().addObjectName(pColumn); 2638 pColumn.setSourceTable(table); 2639 return true; 2640 } 2641 else return false; 2642 } 2643 else { 2644 table.getLinkedColumns().addObjectName(pColumn); 2645 pColumn.setSourceTable(table); 2646 return true; 2647 } 2648 } 2649 2650 2651 private TTable findInsertedOrDeleteTable(TTable table) { 2652 if (table == null) return null; 2653 2654 // Check if this table is 'inserted' by examining both name and toString() 2655 // The inserted table might have different representations 2656 String tableName = table.getName(); 2657 String tableString = table.toString(); 2658 2659 if ("inserted".equalsIgnoreCase(tableName) || 2660 "inserted".equalsIgnoreCase(tableString) || 2661 "deleted".equalsIgnoreCase(tableName) || 2662 "deleted".equalsIgnoreCase(tableString)) { 2663 return table; 2664 } 2665 2666 // If this is a join table, recursively check its components 2667 if (table.getTableType() == ETableSource.join && table.getJoinExpr() != null) { 2668 TJoinExpr joinExpr = table.getJoinExpr(); 2669 2670 // Check left side recursively 2671 TTable leftResult = findInsertedOrDeleteTable(joinExpr.getLeftTable()); 2672 if (leftResult != null) { 2673 return leftResult; 2674 } 2675 2676 // Check right side recursively 2677 TTable rightResult = findInsertedOrDeleteTable(joinExpr.getRightTable()); 2678 if (rightResult != null) { 2679 return rightResult; 2680 } 2681 } 2682 2683 return null; 2684 } 2685 2686 2687 boolean isSQLServerInsertedDelete(TObjectName pColumn){ 2688 if (dbvendor != EDbVendor.dbvmssql) return false; 2689 2690 // only process sql server inserted delete column, if not then return false 2691 // if (!((pColumn.toString().toUpperCase().startsWith("INSERTED"))||(pColumn.toString().toUpperCase().startsWith("DELETED")))) return false; 2692 if (!((pColumn.getStartToken().tokencode == TBaseType.rrw_sqlserver_INSERTED ) 2693 ||(pColumn.getStartToken().tokencode == TBaseType.rrw_sqlserver_DELETED ))) return false; 2694 2695 // we need to get the target table in this statement's from clause which can be complex join, so we need to iterate all tables in this statement's from clause 2696 // to find the target table in the literal as 'inserted' or 'deleted'. 2697 2698 TTable lcTargetTable = null; 2699 for(TTable table : this.getRelations()){ 2700 lcTargetTable = findInsertedOrDeleteTable(table); 2701 if (lcTargetTable != null){ 2702 break; 2703 } 2704 } 2705 2706 if (lcTargetTable == null) return false; 2707 2708 2709 if (lcTargetTable.getLinkTable() != null){ 2710 lcTargetTable.getLinkTable().getLinkedColumns().addObjectName(pColumn); 2711 pColumn.setSourceTable(lcTargetTable.getLinkTable()); 2712 2713 pColumn.setResolveStatus(TBaseType.RESOLVED_AND_FOUND); // 避免在 // TAttributeResolver 中再次进行处理,关联到其他 table 2714 2715 }else{ 2716 lcTargetTable.getLinkedColumns().addObjectName(pColumn); 2717 pColumn.setSourceTable(lcTargetTable); 2718 pColumn.setResolveStatus(TBaseType.RESOLVED_AND_FOUND); // 避免在 // TAttributeResolver 中再次进行处理,关联到其他 table 2719 } 2720 return true; 2721 2722 } 2723 2724 boolean isOracleNewOldTable(TObjectName pColumn){ 2725 boolean ret = false; 2726 if (dbvendor != EDbVendor.dbvoracle) return false; 2727 if (!(pColumn.isQualified())) return false; 2728 if ((pColumn.getTableString().equalsIgnoreCase(":new")) 2729 ||(pColumn.getTableString().equalsIgnoreCase(":old"))){ 2730 if (getAncestorStmt().tables != null){ 2731 if (getAncestorStmt().tables.size() > 0){ 2732 getAncestorStmt().tables.getTable(0).getLinkedColumns().addObjectName(pColumn); 2733 pColumn.setSourceTable(getAncestorStmt().tables.getTable(0)); 2734 ret = true; 2735 } 2736 } 2737 } 2738 2739 return ret; 2740 } 2741 2742 public boolean searchDaxVariableInStack(TObjectName pName){ 2743 boolean ret = false; 2744 if (getVariableStack().size() == 0) return false; 2745 if (pName.getDbObjectType() == EDbObjectType.column) return false; 2746 for(int i=0;i<variableStack.size();i++){ 2747 if (pName.toString().equalsIgnoreCase(((TObjectName) variableStack.get(i)).toString())){ 2748 ret = true; 2749 break; 2750 } 2751 } 2752 return ret; 2753 } 2754 2755 boolean linkColumnToTableDax(TObjectName pColumn, ESqlClause pLocation){ 2756 boolean lcResult = true ; 2757 TDaxFunction daxFunction = null; 2758 if (searchDaxVariableInStack(pColumn)) return false; 2759 if (getDaxFunctionStack().size() > 0){ 2760 daxFunction = daxFunctionStack.peek(); 2761 } 2762 2763 if (pColumn.getTableToken() != null){ 2764 //TTable sourceTable = new TTable(new TObjectName(EDbObjectType.table,pColumn.getTableToken())); 2765 TTable sourceTable = new TTable(TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,pColumn.getTableToken())); 2766 sourceTable.getLinkedColumns().addObjectName(pColumn); 2767 addToTables(sourceTable); 2768 if ((daxFunction != null) && (daxFunction.getDefaultTable() == null)){ 2769 daxFunction.setDefaultTable(sourceTable); 2770 } 2771 }else{ 2772 if ((daxFunction != null) &&(daxFunction.getDefaultTable() != null)){ 2773 daxFunction.getDefaultTable().getLinkedColumns().addObjectName(pColumn); 2774 }else{ 2775 ((TDaxStmt)this).getDefaultTable().getLinkedColumns().addObjectName(pColumn); 2776 } 2777 } 2778 return lcResult; 2779 } 2780 2781 /** 2782 * 将列引用解析并绑定到其来源(表、子查询、CTE、表函数、OPENQUERY/UNNEST 等)。 2783 * 2784 * 功能概述: 2785 * 1) 针对 DAX 语法直接走 DAX 分支。 2786 * 2) 已绑定或标记“延迟到列解析器”的列直接返回。 2787 * 3) 设定列所在语法位置,并校验列名/保留字(含 MySQL true/false/default、内置函数等)。 2788 * 4) 处理厂商伪表/特殊前缀(Oracle :new/:old;SQL Server INSERTED/DELETED)。 2789 * 5) Insert All/VALUES 场景:优先在子查询结果集中/变量或过程参数中匹配。 2790 * 6) 在当前语句的 FROM 表集合中查找并建立绑定: 2791 * - 限定列 table.col:按别名/表名匹配;对子查询/CTE/OPENQUERY 进一步在结果集中定位源列; 2792 * 命中后写入 linkedColumns,必要时将 TableToken 标记为 subquery_alias。 2793 * - 非限定列 col: 2794 * a. 先尝试同层 SELECT 列别名(支持 LATERAL 语义且位置在别名之后); 2795 * b. 处理通配符“*”:收集所有来源表; 2796 * c. 基础表通过元数据回调 fireOnMetaDatabaseTableColumn 校验;未命中则记录候选; 2797 * d. 子查询/CTE/函数/UNNEST/PIVOT 分别按各自规则匹配。 2798 * 7) 命中后将列加入表的 linkedColumns 并设置 sourceTable/sourceColumn,必要时维持 isContinue 以继续匹配“*”。 2799 * 8) 若未命中:尝试变量/参数;再按条件(语句类型/位置/是否限定等)向上一层语句递归查找(维护 searchLevel)。 2800 * 9) 仍未命中:在顶层(searchLevel==0)按“候选唯一/或首表”兜底策略 {@link #linkToFirstTable(TObjectName, int)}。 2801 * 2802 * 参数: 2803 * @param pColumn 需要绑定的列名对象(方法会更新其 location、sourceTable、sourceColumn 等) 2804 * @param pLocation 列出现的语法位置(如 selectList、where、insertValues 等) 2805 * 2806 * 返回值: 2807 * @return 成功绑定到某个来源返回 true;未能绑定或被识别为变量/保留字等返回 false 2808 * 2809 * 厂商兼容: 2810 * - Oracle: 处理 :new/:old,Insert All 的 values 子句源自子查询的匹配 2811 * - SQL Server: 处理 INSERTED/DELETED 伪表 2812 * - MySQL: 对保留字/布尔字面量/内置函数名的特殊判断 2813 * - DAX: 委托 {@link #linkColumnToTableDax(TObjectName, ESqlClause)} 2814 * 2815 * 副作用: 2816 * - 更新 pColumn 的 location/searchLevel/sourceTable/sourceColumn/validate 状态 2817 * - 向命中的表写入 linkedColumns 或向别名列写入 targetColumns 2818 * - 对“*”列填充 sourceTableList;对子查询命中时可能将 TableToken 标为 subquery_alias 2819 * - 记录候选表数量并填充 pColumn.candidateTables,用于后续兜底 2820 * 2821 * 复杂度与顺序: 2822 * - 优先使用同层信息(别名/元数据/子查询结果),再逐层向外查找;避免无谓的上层搜索 2823 * 2824 * 注意: 2825 * - 本方法完成“旧算法”的快速联接,新的解析/消歧逻辑在解析器(如 TStmtScope/TAttributeResolver)中继续处理 2826 */ 2827 public boolean linkColumnToTable(TObjectName pColumn, ESqlClause pLocation){ 2828 boolean lcResult = false,isContinue = false; 2829 int candidateTableCnt = 0; 2830 if (pColumn == null) return false; 2831 if (dbvendor == EDbVendor.dbvdax){ 2832 return linkColumnToTableDax(pColumn,pLocation); 2833 } 2834 2835 // Skip alias definition columns - they define column names in alias clauses, not column references 2836 // Example: In "AS x (numbers, animals)", numbers and animals are column_alias type 2837 if (pColumn.getDbObjectType() == EDbObjectType.column_alias) { 2838 return true; 2839 } 2840 2841 if (pColumn.getSourceTable() != null) { 2842 lcResult = true; 2843 return lcResult; 2844 } 2845 2846 if (pColumn.getResolveStatus() == TBaseType.RESOLVE_DELAY_TO_COLUMN_RESOLVER) return true; 2847 2848 pColumn.setLocation(pLocation); 2849 2850 if (! pColumn.isValidColumnName(dbvendor)) { 2851 if (pColumn.isReservedKeyword()){ 2852 if ( 2853 ((pColumn.getStartToken().tokencode != TBaseType.rrw_mysql_true)&&(!(pColumn.getStartToken().toString().equalsIgnoreCase("true")))) 2854 &&((pColumn.getStartToken().tokencode != TBaseType.rrw_mysql_false)&&(!(pColumn.getStartToken().toString().equalsIgnoreCase("false")))) 2855 &&(pColumn.getStartToken().tokencode != TBaseType.rrw_mysql_default) 2856 &&(pColumn.getStartToken().tokencode != TBaseType.rrw_on)&&(!(pColumn.getStartToken().toString().equalsIgnoreCase("on"))) 2857 ) { 2858 boolean mysqlBuiltFunction = false; 2859 if (dbvendor == EDbVendor.dbvmysql){ 2860 mysqlBuiltFunction = functionChecker.isBuiltInFunction(pColumn.toString(),EDbVendor.dbvmysql,"6.0"); 2861 } 2862 if (!mysqlBuiltFunction){ 2863 TSourceToken st1 = pColumn.getStartToken(); 2864 TSyntaxError err = new TSyntaxError(st1.toString() 2865 , st1.lineNo, st1.columnNo 2866 , String.format("Reserved keyword can't be column name") 2867 , EErrorType.sperror 2868 , TBaseType.MSG_ERROR_RESERVED_KEYWORD_CANT_USED_AS_COLUMN_NAME 2869 ,this,st1.posinlist); 2870 this.parseerrormessagehandle(err); 2871 } 2872 } 2873 } 2874 return false; 2875 } 2876 2877 if (isOracleNewOldTable(pColumn)) return true; 2878 if (isSQLServerInsertedDelete(pColumn)) return true; 2879 2880 // oracle insert all statement, 2881 // WHEN id <= 3 THEN INTO dest_tab1 VALUES(id, description1) 2882 // column in values clause must be in the subquery of insert all statement 2883 if (pColumn.getLocation() == ESqlClause.insertValues){ 2884 if (this instanceof TInsertSqlStatement){ 2885 TInsertSqlStatement insertSqlStatement = (TInsertSqlStatement)this; 2886 if (insertSqlStatement.isInsertAll()){ 2887 // if (pColumn.getStartToken().tokencode == TBaseType.rrw_snowflake_default) return true; 2888 lcResult = insertSqlStatement.getSubQuery().searchColumnInResultSet(pColumn, true); 2889 } 2890 } 2891 2892 if (lcResult) return true; 2893 2894 // value in values clause maybe parameter of the procedure/function parameter 2895 lcResult = locateVariableOrParameter(pColumn,true); 2896 if (lcResult) return true; 2897 } 2898 2899 boolean foundInMetaData = false; 2900 2901 for(int i=0;i<tables.size();i++){ 2902 TTable lcTable = tables.getTable(i); 2903 if (lcTable.getEffectType() == ETableEffectType.tetSelectInto) continue; 2904 if (lcTable.getEffectType() == ETableEffectType.tetImplicitLateralDerivedTable) continue; 2905 2906 if (pColumn.isQualified()){ 2907 lcResult = pColumn.resolveWithThisTable(lcTable); 2908 if ((lcResult) && (lcTable.getTableType() == ETableSource.subquery)){ 2909 pColumn.getTableToken().setDbObjectType(EDbObjectType.subquery_alias); 2910 2911 int lcPos = lcTable.searchColumnInAlias(pColumn); 2912 lcResult = lcPos>=0; 2913 if (lcResult){ 2914 // 在 alias 中找到 source column, 还需要对应到 subquery select 中的 select list 2915 // sql 见 https://e.gitee.com/gudusoft/projects/151613/tasks/list?issue=I8JR0W#note_23051633 2916 if ((lcTable.getSubquery() != null)&&(lcTable.getSubquery().getResultColumnList() != null)){ 2917 pColumn.setSourceColumn(lcTable.getSubquery().getResultColumnList().getResultColumn(lcPos)); 2918 } 2919 }else{ 2920 lcResult = lcTable.getSubquery().searchColumnInResultSet(pColumn,true); 2921 } 2922 // lcTable.getSubquery().searchColumnInResultSet(pColumn,true); 2923 2924 }else if ((lcResult) && (lcTable.isCTEName())){ 2925 lcTable.getCTE().searchColumnInResultSet(this,lcTable,pColumn,true); 2926 }else if ((lcResult) && (lcTable.getTableType() == ETableSource.openquery)&&(lcTable.getSubquery() != null)){ 2927 pColumn.getTableToken().setDbObjectType(EDbObjectType.subquery_alias); 2928 lcTable.getSubquery().searchColumnInResultSet(pColumn,true); 2929// }else if ((lcResult) && (lcTable.getTableType() == ETableSource.unnest)&&(lcTable.getUnnestClause() != null)){ 2930// pColumn.getTableToken().setDbObjectType(EDbObjectType.subquery_alias); 2931// lcTable.getSubquery().searchColumnInResultSet(pColumn,true); 2932 } 2933 if (lcResult&&pColumn.toString().endsWith("*")){ 2934 pColumn.getSourceTableList().add(lcTable); 2935// ArrayList<String> lcColumns = getColumnsInTable(lcTable); 2936// if (lcColumns != null){ 2937// pColumn.getColumnsLinkedToStarColumn().addAll(lcColumns); 2938// } 2939 } 2940 }else { 2941 // column not qualified 2942 2943 // check if this is the column alias in current select list. 2944 if((!lcResult)&& ((!pColumn.isQualified()) && (this instanceof TSelectSqlStatement)&&(getResultColumnList() !=null)) 2945 && (TBaseType.isSupportLateralColumn(dbvendor)) 2946 ){ 2947 for(int j=0;j<getResultColumnList().size();j++){ 2948 TResultColumn lcField = getResultColumnList().getResultColumn(j); 2949 lcResult = lcField.isMatchedUsingAlias(pColumn); 2950 if ( 2951 (!TSQLEnv.isAliasReferenceForbidden.get(this.dbvendor))&& 2952 ((lcResult)&&(pColumn.getStartToken().posinlist > lcField.getAliasClause().getStartToken().posinlist))){ 2953 pColumn.setSourceColumn(lcField); 2954 lcField.getTargetColumns().addObjectName(pColumn); 2955 pColumn.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_COLUMN_ALIAS_IN_OLD_ALGORITHM); 2956 break; 2957 }else{ 2958 lcResult = false; 2959 } 2960 } 2961 2962 if (lcResult) return true; 2963 } 2964 2965 if (pColumn.getColumnNameOnly().equalsIgnoreCase("*")){ 2966 lcResult = true; 2967 isContinue = true; // in order to match next table in the from clause 2968 pColumn.getSourceTableList().add(lcTable); 2969// ArrayList<String> lcColumns = getColumnsInTable(lcTable); 2970// if (lcColumns != null){ 2971// pColumn.getColumnsLinkedToStarColumn().addAll(lcColumns); 2972// } 2973 }else if (lcTable.isBaseTable()){ 2974 lcResult = fireOnMetaDatabaseTableColumn( 2975 lcTable.getPrefixServer() 2976 ,lcTable.getPrefixDatabase() 2977 ,lcTable.getPrefixSchema() 2978 ,lcTable.getName() 2979 ,pColumn.getColumnNameOnly()); 2980 if (! lcResult) { 2981 candidateTableCnt++; 2982 pColumn.getCandidateTables().addTable(lcTable); 2983 }else{ 2984 foundInMetaData = true; 2985 isContinue = false; 2986 } 2987 2988 }else if ((lcTable.getTableType() == ETableSource.subquery) 2989 ||((lcTable.getTableType() == ETableSource.openquery)&&(lcTable.getSubquery() != null))){ 2990 2991 lcResult = lcTable.searchColumnInAlias(pColumn)>=0; 2992 if (!lcResult){ 2993 lcResult = lcTable.getSubquery().searchColumnInResultSet(pColumn,(tables.size() == 1) 2994 &&(pColumn.getCandidateTables().size() == 0)); 2995 if (! lcResult) { 2996 candidateTableCnt++; 2997 pColumn.getCandidateTables().addTable(lcTable); 2998 } 2999 } 3000 3001 3002// if (lcTable.isIncludeColumnAlias()){ 3003// // System.out.println("subquery with alias:"+lcTable.getAliasClause().toString()+", skip search:"+pColumn.toString()); 3004// 3005// }else{ 3006// lcResult = lcTable.getSubquery().searchColumnInResultSet(pColumn,(tables.size() == 1)&&(pColumn.getCandidateTables().size() == 0)); 3007// if (! lcResult) candidateTableCnt++; 3008// } 3009 }else if (lcTable.isCTEName()){ 3010 lcResult = lcTable.getCTE().searchColumnInResultSet(this,lcTable,pColumn,tables.size() == 1); 3011 if (! lcResult) { 3012 candidateTableCnt++; 3013 pColumn.getCandidateTables().addTable(lcTable); 3014 } 3015 }else if (lcTable.getTableType() == ETableSource.function){ 3016 // search in this table function 3017 if(tables.size() == 1){ 3018 lcResult = ( lcTable.getFuncCall().isColumnInThisTableFunction(this.getSqlEnv(),this.dbvendor,pColumn) 3019 != TBaseType.COLUMN_IN_TABEL_FUNCTION_NO); 3020 } 3021 else{ 3022 lcResult = ( lcTable.getFuncCall().isColumnInThisTableFunction(this.getSqlEnv(),this.dbvendor,pColumn) 3023 == TBaseType.COLUMN_IN_TABEL_FUNCTION_YES); 3024 } 3025 }else if (lcTable.getTableType() == ETableSource.tableExpr 3026 && lcTable.getTableExpr().getExpressionType() == EExpressionType.function_t 3027 && lcTable.getTableExpr().getFunctionCall() != null){ 3028 // search in this table function 3029 lcResult = ( lcTable.getTableExpr().getFunctionCall().isColumnInThisTableFunction(this.getSqlEnv(),this.dbvendor,pColumn) 3030 == TBaseType.COLUMN_IN_TABEL_FUNCTION_YES); 3031 }else if (lcTable.getTableType() == ETableSource.pivoted_table){ 3032 lcResult = fireOnMetaDatabaseTableColumn( 3033 lcTable.getPrefixServer() 3034 ,lcTable.getPrefixDatabase() 3035 ,lcTable.getPrefixSchema() 3036 ,lcTable.getName() 3037 ,pColumn.getColumnNameOnly()); 3038 if (lcResult){ 3039 foundInMetaData = true; 3040 isContinue = false; 3041 } 3042 }else if (lcTable.getTableType() == ETableSource.unnest){ 3043 for(TObjectName objectName:lcTable.getLinkedColumns()){ 3044 if (objectName.toString().equalsIgnoreCase(pColumn.toString())){ 3045 lcResult = true; 3046 break; 3047 } 3048 } 3049 3050 if (!lcResult){ 3051 if (lcTable.getAliasClause() == null){ 3052 // this unnest() clause generate column with default name: "value" 3053 if (pColumn.toString().equalsIgnoreCase("value")){ 3054 lcResult = true; 3055 } 3056 }else{ 3057 } 3058 } 3059 }//unnest 3060 } 3061 3062 if (lcResult) { 3063 lcTable.getLinkedColumns().addObjectName(pColumn); 3064 pColumn.setSourceTable(lcTable); 3065 // pColumn.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_TABLE_IN_OLD_ALGORITHM); 3066 if (!isContinue) break; 3067 } 3068 } 3069 3070 if ((lcResult) && (foundInMetaData)) return true; 3071 3072 // check variable after metadata checking 3073 if (locateVariableOrParameter(pColumn)) return false; 3074 3075 // check if this is the column alias in current select list. 3076// if((!lcResult)&& ((!pColumn.isPrefixed()) && (this instanceof TSelectSqlStatement)&&(getResultColumnList() !=null))){ 3077// for(int j=0;j<getResultColumnList().size();j++){ 3078// TResultColumn lcField = getResultColumnList().getResultColumn(j); 3079// lcResult = lcField.isMatchedUsingAlias(pColumn); 3080// if ((lcResult)&&(pColumn.getStartToken().posinlist > lcField.getAliasClause().getStartToken().posinlist)){ 3081// pColumn.setSourceColumn(lcField); 3082// lcField.getTargetColumns().addObjectName(pColumn); 3083// break; 3084// }else{ 3085// lcResult = false; 3086// } 3087// } 3088// } 3089 3090 if (lcResult) return true; 3091 3092 boolean isSearchUpLevel = (this.parentStmt != null); 3093 3094 if ((isSearchUpLevel) && (sqlstatementtype == ESqlStatementType.sstselect)){ 3095 isSearchUpLevel = (pColumn.isQualified() 3096 || ( 3097// (((TSelectSqlStatement)(this)).getLocation() != ESqlClause.elTable) && 3098 (! ((TSelectSqlStatement)(this)).isQueryOfCTE()) 3099 ) 3100 ) 3101 && (parentStmt.sqlstatementtype != ESqlStatementType.sstinsert) 3102 && (!((pColumn.getLocation() == ESqlClause.selectList)&&(((TSelectSqlStatement)(this)).getLocation() == ESqlClause.join))) 3103 && ((((TSelectSqlStatement)(this)).getLocation() != ESqlClause.pivot_in)) 3104 && (!((parentStmt.sqlstatementtype == ESqlStatementType.sstcreatetable))) 3105 && (!((parentStmt.sqlstatementtype == ESqlStatementType.sstcreateview))) 3106// && (!((pColumn.getLocation() == ESqlClause.selectList)&&(parentStmt.sqlstatementtype == ESqlStatementType.sstcreatetable))) 3107// && (!((pColumn.getLocation() == ESqlClause.selectList)&&(parentStmt.sqlstatementtype == ESqlStatementType.sstcreateview))) 3108 && (! ((pColumn.getLocation() == ESqlClause.selectList) 3109 &&(candidateTableCnt == 1) && (this instanceof TSelectSqlStatement) 3110 && (((TSelectSqlStatement)(this)).getLocation() == ESqlClause.elTable) 3111 ) ) // ref:mantis: #2628 3112 // && ( ((TSelectSqlStatement)(this.parentStmt)).getSetOperatorType() == ESetOperatorType.none) 3113 ; 3114 3115 if (isSearchUpLevel){ 3116 isSearchUpLevel = !((!pColumn.isQualified())&&(((TSelectSqlStatement) this).getLocation() == ESqlClause.where)); 3117 } 3118 } 3119 3120 if (isSearchUpLevel&&(pColumn.isContinueToSearch())){ // only search one level up, c:\prg\gsp_sqlfiles\TestCases\java\oracle\dbobject\berger_sqltest_04.sql 3121 boolean increaseLevel = true; 3122 if (parentStmt instanceof TSelectSqlStatement){ 3123 if( ((TSelectSqlStatement)parentStmt).getSetOperatorType() != ESetOperatorType.none){ 3124 increaseLevel = false; 3125 } 3126 } 3127 if (increaseLevel){ 3128 pColumn.searchLevel++; 3129 } 3130 3131 lcResult = parentStmt.linkColumnToTable(pColumn,pLocation); 3132 3133 if (increaseLevel){ 3134 pColumn.searchLevel--; 3135 } 3136 } 3137 3138 if ((! lcResult) && (pColumn.searchLevel == 0)) { 3139 if (this.sqlstatementtype == ESqlStatementType.sstselect){ 3140 if( ((TSelectSqlStatement)this).getSetOperatorType() == ESetOperatorType.none){ 3141 // USING _spVV0 (INTEGER) 3142 // INSERT INTO table3 3143 // SELECT :_spVV0,x. *,m.col3 3144 // from (( select table1.col1, (table1.col1 + table5.col2) c from table1 3145 // union all select col3,col4 from table2) x 3146 // cross join (select id from table2) m ) 3147 3148 // table5 in the above sql only link to the nearest level sql, but not to up-level which is union all 3149 3150 linkToFirstTable(pColumn,candidateTableCnt); 3151 } 3152 }else{ 3153 linkToFirstTable(pColumn,candidateTableCnt); 3154 } 3155 } 3156 3157 return lcResult; 3158 } 3159 3160 3161 /** 3162 * 3163 * @deprecated As of v1.6.0.1, use {@link #linkColumnToTable} instead 3164 */ 3165 public void linkColumnReferenceToTable(TObjectName cr, ESqlClause plocation){ 3166 // this is the column name, link it to table 3167 if (cr == null) return; 3168 cr.setLocation(plocation); 3169 if (cr.getObjectType() == TObjectName.ttobjVariable) return; 3170 if (cr.getObjectType() == TObjectName.ttobjColumnAlias) return; 3171 if (this.dbvendor == EDbVendor.dbvsybase){ 3172 TSourceToken pt = cr.getPartToken(); 3173 if ( pt != null){ 3174 if (pt.tokentype == ETokenType.ttdqstring){ 3175 //"0123", quoted string start with a number can't a column 3176 if ((pt.toString().charAt(1) >= '0') 3177 &&(pt.toString().charAt(1) <= '9')){ 3178 return; 3179 }else if (pt.toString().length() == 2){ 3180 //"", empty 3181 return; 3182 }else if (pt.toString().substring(1,pt.toString().length()-1).trim().length() == 0){ 3183 //" " 3184 return; 3185 } 3186 } 3187 } 3188 } 3189 3190 3191 if (cr.getPartToken() != null){ 3192 if (cr.getPartToken().tokentype == ETokenType.ttkeyword){ 3193 boolean reservedKeyword = false; 3194 switch (dbvendor){ 3195 case dbvmssql: 3196 //reservedKeyword = ! this.getGsqlparser().getFlexer().canBeColumnName(cr.getPartToken().tokencode); 3197 reservedKeyword = ! TLexerMssql.canBeColumnName(cr.getPartToken().tokencode); 3198 break; 3199 case dbvsybase: 3200 reservedKeyword = keywordChecker.isKeyword(cr.getPartToken().toString(), EDbVendor.dbvsybase, "15.7", true); 3201 break; 3202 default: 3203 break; 3204 } 3205 if (reservedKeyword) return; 3206 } 3207 } 3208 3209 // let's check is this columnreference is variable or parameter of plsql function/procedure 3210 // if (locateVariableOrParameter(cr)) return; 3211 3212// if ((cr.getPartToken() != null)&&((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase))){ 3213// if ((cr.getPartToken().tokentype == ETokenType.ttkeyword)&&(!(this.getGsqlparser().getFlexer().canBeColumnName(cr.getPartToken().tokencode)))){ 3214// // keyword can't be column name: 3215// //select * From dbo.table Where DATEDIFF(day, create_date, expiry_date) < 14 3216// return; 3217// } 3218// } 3219 3220 if ((cr.toString().startsWith("@"))) 3221// if ((cr.toString().endsWith("*"))||(cr.toString().startsWith("@"))) 3222 { 3223 cr.setObjectType(TObjectName.ttobjNotAObject); 3224 return; 3225 } 3226 3227 if (dbvendor == EDbVendor.dbvoracle){ 3228 if ( //(cr.toString().compareToIgnoreCase ("rowid") == 0)|| 3229 (cr.toString().compareToIgnoreCase ("sysdate") == 0) 3230 || (cr.toString().compareToIgnoreCase ("nextval") == 0) 3231 || (cr.toString().compareToIgnoreCase ("rownum") == 0) 3232 || (cr.toString().compareToIgnoreCase ("level") == 0) 3233 ){ 3234 cr.setObjectType(TObjectName.ttobjNotAObject); 3235 if (cr.getDbObjectType() == EDbObjectType.unknown){ 3236 cr.setDbObjectType(EDbObjectType.notAColumn); 3237 } 3238 return; 3239 } 3240 } 3241 3242 if (((cr.toString().toUpperCase().startsWith("INSERTED"))||(cr.toString().toUpperCase().startsWith("DELETED")))&&(plocation == ESqlClause.output)&&(targetTable != null)){ 3243 targetTable.getObjectNameReferences().addObjectName(cr); 3244 return; 3245 } 3246 3247 if ( ((cr.toString().toUpperCase().startsWith(":NEW")) 3248 ||(cr.toString().toUpperCase().startsWith(":OLD"))) 3249 &&(this.getTopStatement() instanceof TPlsqlCreateTrigger) 3250 &&(dbvendor == EDbVendor.dbvoracle)){ 3251 this.getTopStatement().tables.getTable(0).getObjectNameReferences().addObjectName(cr); 3252 return; 3253 } 3254 3255 3256 3257 int ret = this.tables.checkColumnReferenceInTables(cr); 3258 if (ret >= 0) { 3259 TTable lcTable = this.tables.getTable(ret); 3260 if (lcTable.isBaseTable()){ 3261 lcTable.getObjectNameReferences().addObjectName(cr); 3262 }else if (lcTable.isCTEName()){ 3263 //WITH temp 3264 // AS (SELECT * 3265 // FROM sysibm.systables), 3266 // temp1 3267 // AS (SELECT * 3268 // FROM sysibm.syscolumns) 3269 //SELECT * 3270 //FROM temp A 3271 // INNER JOIN temp1 B 3272 // ON A.creator = B.tbcreator 3273 // AND A.name = B.tbname 3274 TCTE lccte = findCTEByName(lcTable.toString()); 3275 if (lccte != null){ 3276 TObjectName objectName = new TObjectName(); 3277 objectName.init(cr.getPartToken()); 3278 if (lccte.getSubquery() != null){ 3279 lccte.getSubquery().linkColumnReferenceToTable(objectName,plocation); 3280 } 3281 } 3282 }else if (lcTable.getTableType() == ETableSource.subquery){ 3283 // link s2t1a1 to subselect2table1 via s2 3284 //select 3285 // s2.s2t1a1 3286 //from 3287 // ( 3288 // select s2t1.* 3289 // from subselect2table1 s2t1 3290 // ) s2 3291 TSelectSqlStatement subquery = lcTable.getSubquery(); 3292 3293 if(((subquery.getValueClause() == null))&&(!subquery.isCombinedQuery())&&(subquery.getResultColumnList() != null)&&(subquery.getResultColumnList().size() == 1)){ 3294 TResultColumn lcColumn = subquery.getResultColumnList().getResultColumn(0); 3295 if (lcColumn.toString().endsWith("*")){ 3296 boolean isfound = false; 3297 3298 for(int i=0;i<subquery.tables.size();i++){ 3299 if (subquery.tables.getTable(i).getTableType() == ETableSource.subquery) continue; 3300 String columnStr = null; 3301 if (cr.getPartToken() != null){ 3302 //cr.getObjectType() is not ttObjColumn, so we can't use 3303 // getColumnToken, this is a bug, need to check it later. 3304 columnStr = cr.getPartToken().toString(); 3305 } 3306 if (this.fireOnMetaDatabaseTableColumn( 3307 subquery.tables.getTable(i).getTableName().getServerString(), 3308 subquery.tables.getTable(i).getTableName().getDatabaseString(), 3309 subquery.tables.getTable(i).getTableName().getSchemaString(), 3310 subquery.tables.getTable(i).getName(),columnStr)){ 3311 subquery.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3312 isfound = true; 3313 break; 3314 } 3315 } 3316 3317 3318 3319 if (!isfound) 3320 { 3321 if(subquery.tables.size() > 1){ 3322 cr.setTableDetermined(false); 3323 } 3324 for(int i=0;i<subquery.tables.size();i++){ 3325 subquery.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3326 } 3327 } 3328 3329 } // "*" 3330 } 3331 } 3332 }else if (ret == -2){ 3333 // no qualifier before column, check is this column of a cte, if not,set it to non-cte table 3334 boolean isfound = false; 3335 for (int i=0;i<this.tables.size();i++){ 3336 if ((this.tables.getTable(i).isCTEName()) &&(this.tables.getTable(i).getCteColomnReferences() != null)){ 3337 if (this.tables.getTable(i).getCteColomnReferences().searchColumnReference(cr) >= 0){ 3338 this.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3339 isfound = true; 3340 break; 3341 } 3342 } 3343 } 3344 3345 // no qualifier before column, but we still need to check uplevel table like this: 3346 //SELECT 3347 // col1 , 3348 // 3349 // ( SELECT col2 3350 // FROM tab1 3351 // WHERE col2 = col1 ) 3352 // FROM tab2 3353 // we need to link col1 to tab2 in up level, but not to tab1 3354 if ((!isfound) &&( 3355 (cr.getLocation() != ESqlClause.resultColumn) 3356 &&(cr.getLocation() != ESqlClause.insertColumn) 3357 &&(cr.getLocation() != ESqlClause.mergeInsert) 3358 &&(cr.getLocation() != ESqlClause.selectList) 3359 ) ){ // code #111 3360 TCustomSqlStatement lcParent = null; 3361 lcParent = this.getParentStmt(); 3362 while ( lcParent != null) { 3363 TTable lcTable; 3364 //ret = lcParent.tables.checkColumnReferenceInTables(cr); 3365 if (lcParent.sqlstatementtype != ESqlStatementType.sstselect) { 3366 break; 3367 } 3368 for (int i=0;i<lcParent.tables.size();i++){ 3369 lcTable = lcParent.tables.getTable(i); 3370 if (lcTable.getTableType() == ETableSource.objectname) { 3371 for(int k = 0; k< lcTable.getObjectNameReferences().size();k++){ 3372 if (lcTable.getObjectNameReferences().getObjectName(k).isTableDetermined()){ 3373 if (cr.toString().equalsIgnoreCase(lcTable.getObjectNameReferences().getObjectName(k).toString())){ 3374 isfound = true; 3375 break; 3376 } 3377 } 3378 } 3379 if (isfound) break; 3380 } 3381 } 3382 3383 if (isfound){ 3384 break; 3385 }else{ 3386 lcParent = lcParent.getParentStmt(); 3387 } 3388 } // while 3389 3390 } // end of code #111 3391 3392 if (!isfound){ 3393 isfound = checkNonQualifiedColumnReferenceInSubQueryOfUplevelStmt(cr 3394 , ((plocation == ESqlClause.resultColumn) 3395 ||(plocation == ESqlClause.insertColumn) 3396 ||(plocation == ESqlClause.mergeInsert) 3397 ||(plocation == ESqlClause.selectList) 3398 ) 3399 ); 3400 } 3401 3402 if ((!isfound)&&(this.tables.size() > 0)){ 3403 int candidate = 0, firstCandidate = -1; 3404 // add this column reference to first non-cte( or cte with column list is null) and non-subquery table 3405 for (int i=0;i<this.tables.size();i++){ 3406 // no qualified column can't belong to a table with alias, that column must be qualified if it's belong to a table with alias 3407 //if (this.tables.getTable(i).aliasClause != null) continue; 3408 if ( 3409 ( 3410 (!this.tables.getTable(i).isCTEName()) 3411 ||((this.tables.getTable(i).isCTEName())&&(this.tables.getTable(i).getCteColomnReferences() == null)) 3412 )&&((this.tables.getTable(i).getTableType() != ETableSource.subquery)) 3413 ) 3414 { 3415 candidate++; 3416 if (firstCandidate == -1) firstCandidate = i; 3417 if (this.fireOnMetaDatabaseTableColumn( 3418 this.tables.getTable(i).getTableName().getServerString(), 3419 this.tables.getTable(i).getTableName().getDatabaseString(), 3420 this.tables.getTable(i).getTableName().getSchemaString(), 3421 this.tables.getTable(i).getName(),cr.toString())){ 3422 this.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3423 isfound = true; 3424 break; 3425 } 3426 else{ 3427 this.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3428 if (this.tables.size() > 1){ 3429 cr.setTableDetermined(false); 3430 } 3431 isfound = true; 3432 break; 3433 } 3434 } 3435 } 3436 if ((!isfound) && (candidate == 1)){ 3437 this.tables.getTable(firstCandidate).getObjectNameReferences().addObjectName(cr); 3438 } 3439 } 3440 }else if (ret == -1){ 3441 TCustomSqlStatement lcParent = null; 3442 lcParent = this.getParentStmt(); 3443 while ( lcParent != null) { 3444 ret = lcParent.tables.checkColumnReferenceInTables(cr); 3445 if (ret >= 0){ 3446 lcParent.tables.getTable(ret).getObjectNameReferences().addObjectName(cr); 3447 break; 3448 }else{ 3449 lcParent = lcParent.getParentStmt(); 3450 } 3451 } // while 3452 } //-1 3453 3454 } 3455 3456 /** 3457 * Found out is a non qualified column is a column in uplevel subquery table like this: 3458 * take ma_parkey for example: ma_parkey is not a physical column 3459 * 3460 SELECT c_mandant 3461 , CASE WHEN EXISTS (SELECT 1 3462 FROM CDS_H_GRUPPE GRP1 3463 WHERE GRP1.c_mandant = c_mandant 3464 AND GRP1.parkey1 = ma_parkey) 3465 THEN 1 3466 ELSE NULL 3467 END MA_ME 3468 FROM (SELECT c_mandant 3469 , CASE WHEN funktionscode = 'U' 3470 THEN parkey1 3471 ELSE parkey2 3472 END MA_PARKEY 3473 FROM 3474 CDS_H_GRUPPE 3475 ) 3476 */ 3477 public boolean checkNonQualifiedColumnReferenceInSubQueryOfUplevelStmt(TObjectName crf,boolean sameLevelOnly){ 3478 boolean ret = false; 3479 3480 TCustomSqlStatement lcParent = null; 3481 lcParent = this;//getParentStmt(); 3482 while ( lcParent != null) { 3483 TTable lcTable; 3484 for (int i=0;i<lcParent.tables.size();i++){ 3485 lcTable = lcParent.tables.getTable(i); 3486 3487 if ((lcTable.getTableType() != ETableSource.subquery)) {continue;} 3488 3489 ret = isColumnNameInSelectList(crf.toString(),lcTable.subquery); 3490 if (ret) {break;} 3491 3492 } 3493 if (ret) {break;} 3494 else{ 3495 if (sameLevelOnly){ 3496 lcParent = null; 3497 }else{ 3498 lcParent = lcParent.getParentStmt(); 3499 } 3500 } 3501 } // while 3502 3503 return ret; 3504 } 3505 3506 private boolean isColumnNameInSelectList(String pColumn, TSelectSqlStatement pSelect){ 3507 boolean ret = false; 3508 TResultColumn lcColumn; 3509 if (pSelect.isCombinedQuery()){ 3510 ret = isColumnNameInSelectList(pColumn,pSelect.getLeftStmt()); 3511 if (!ret){ 3512 ret = isColumnNameInSelectList(pColumn,pSelect.getRightStmt()); 3513 } 3514 }else{ 3515 if (pSelect.getResultColumnList() != null){ //if it's a db2 value row, then pSelect.getResultColumnList() will be null 3516 for(int j=0;j<pSelect.getResultColumnList().size();j++){ 3517 lcColumn = pSelect.getResultColumnList().getResultColumn(j); 3518 if (lcColumn.getAliasClause() != null){ 3519 ret = pColumn.equalsIgnoreCase(lcColumn.getAliasClause().toString()); 3520 } 3521 if (ret) break; 3522 ret = pColumn.equalsIgnoreCase(lcColumn.getExpr().toString()); 3523 if (ret) break; 3524 } 3525 } 3526 } 3527 return ret; 3528 } 3529 3530 public TCustomSqlStatement getTopStatement(){ 3531 TCustomSqlStatement ret = this; 3532 while (ret.getParentStmt() != null){ 3533 ret = ret.getParentStmt(); 3534 } 3535 return ret; 3536 } 3537 3538 3539// public String toScript(){ 3540// if (!isChanged()){ 3541// return this.toString(); 3542// } 3543// return super.toScript(); 3544// } 3545 3546} 3547 3548class constantVisitor extends TParseTreeVisitor { 3549 private boolean inWhere = false,inExprList = false; 3550 public void preVisit(TWhereClause node){ 3551 inWhere = true; 3552 } 3553 3554 public void postVisit(TWhereClause node){ 3555 inWhere = false; 3556 } 3557 3558 public void preVisit(TExpression node){ 3559 if (inWhere){ 3560 switch (node.getExpressionType()){ 3561 case list_t: 3562 inExprList = true; 3563 boolean isNumber = true; 3564 if (node.getExprList().size() > 0){ 3565 // check the type of the constant in the expr list 3566 TExpression expr = node.getExprList().getExpression(0); 3567 if (expr.getExpressionType() == EExpressionType.simple_constant_t){ 3568 if (expr.getConstantOperand().getLiteralType() == ELiteralType.etString){ 3569 isNumber = false; 3570 } 3571 } 3572 } 3573 3574 TSourceToken lcStartToken = node.getStartToken(); 3575 TSourceToken lcEndToken = node.getEndToken(); 3576 int tokenPos = 0; 3577 if ((lcEndToken != null) && (lcStartToken != null)){ 3578 TSourceToken lcCurrentToken = lcStartToken; 3579 while (lcCurrentToken != null){ 3580 3581 if (lcCurrentToken.equals(lcEndToken)){ 3582 break; 3583 }else{ 3584 3585 if (tokenPos == 1){ 3586 if (isNumber){ 3587 lcCurrentToken.setTextWithBackup("999"); 3588 }else{ 3589 lcCurrentToken.setTextWithBackup("'placeholder_str'"); 3590 } 3591 }else if (tokenPos > 1){ 3592 lcCurrentToken.tokenstatus = ETokenStatus.tsdeleted; 3593 } 3594 3595 lcCurrentToken = lcCurrentToken.getNextTokenInChain(); 3596 tokenPos++; 3597 } 3598 } 3599 } 3600 3601 break; 3602 } 3603 } // where 3604 } 3605 3606 public void postVisit(TExpression node){ 3607 if (inWhere){ 3608 switch (node.getExpressionType()){ 3609 case list_t: 3610 inExprList = false; 3611 break; 3612 } 3613 } 3614 } 3615 3616 public void preVisit(TConstant node){ 3617 if (inWhere&&(!inExprList)){ 3618 switch (node.getLiteralType()){ 3619 case etNumber: 3620 case etFloat: 3621 node.getStartToken().setTextWithBackup("999"); 3622 break; 3623 case etString: 3624 node.getStartToken().setTextWithBackup("'placeholder_str'"); 3625 break; 3626 } 3627 } 3628 } 3629 3630 public void preVisit(TFunctionCall node){ 3631 if (TBaseType.as_canonical_f_decrypt_replace_password){ 3632 int i = TBaseType.searchCryptFunction(node.getFunctionName().toString()); 3633 3634 if (i>0){ // find this function 3635 if (node.getArgs().size() >= i){ 3636 TExpression secondArg = node.getArgs().getExpression(i-1); 3637 if (secondArg.getExpressionType() == EExpressionType.simple_constant_t){ 3638 TConstant constant = secondArg.getConstantOperand(); 3639 constant.getValueToken().setTextWithBackup("'***'"); 3640 //System.out.println(node.toString()+":"+constant.toString()); 3641 }else if (secondArg.getExpressionType() == EExpressionType.simple_object_name_t){ 3642 TObjectName objectName = secondArg.getObjectOperand(); 3643 objectName.getStartToken().setTextWithBackup("'***'"); 3644 //System.out.println(node.toString()+":"+constant.toString()); 3645 } 3646 } 3647 } 3648 3649 } 3650 } 3651 3652 void processConstant(TConstant node){ 3653 switch (node.getLiteralType()){ 3654 case etNumber: 3655 case etFloat: 3656 node.getStartToken().setTextWithBackup("999"); 3657 break; 3658 case etString: 3659 node.getStartToken().setTextWithBackup("'placeholder_str'"); 3660 break; 3661 } 3662 } 3663 3664}