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 ; 1166 } 1167 1168 public boolean isdatabricksplsql(){ 1169 return (this instanceof TCommonBlock) 1170 ; 1171 } 1172 1173 public boolean isgreeplumplsql(){ 1174 return (this instanceof TCommonBlock) 1175 ||(this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1176 ||(this.sqlstatementtype == ESqlStatementType.sstcreatefunction) 1177 ||(this.sqlstatementtype == ESqlStatementType.sstDoExecuteBlock) 1178 ; 1179 } 1180 1181 public boolean isathenaplsql(){ 1182 return (this instanceof TCommonBlock) 1183 ; 1184 } 1185 1186 public boolean isprestoplsql(){ 1187 return (this instanceof TCommonBlock) 1188 ; 1189 } 1190 1191 public boolean issnowflakeplsql(){ 1192 return ((this instanceof TCommonBlock) 1193 ||(this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1194 ); 1195 } 1196 1197 public boolean isBigQueryplsql(){ 1198 return ((this instanceof TCommonBlock) 1199 ||(this.sqlstatementtype == ESqlStatementType.sstcreateprocedure) 1200 ); 1201 } 1202 1203 public boolean isverticaplsql(){ 1204 return ( 1205 (this.sqlstatementtype == ESqlStatementType.sstcreatefunction) 1206 ); 1207 } 1208 1209 public boolean isoracleplsql(){ 1210 return ( 1211 (this.sqlstatementtype == ESqlStatementType.sst_plsql_block) 1212 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createprocedure) 1213 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createfunction) 1214 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createpackage) 1215 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtype_placeholder) 1216 ||(this.sqlstatementtype == ESqlStatementType.sstoraclecreatepackagebody) 1217 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtrigger) 1218 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createtypebody) 1219 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_tabletypedef) 1220 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_varraytypedef) 1221 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_createprocedure) 1222 ||(this.sqlstatementtype == ESqlStatementType.sstplsql_execimmestmt) 1223 ||(this.sqlstatementtype == ESqlStatementType.sstoraclecreatelibrary) 1224 ); 1225 } 1226 1227 int checksyntax(TCustomSqlStatement psql){ 1228 return dochecksyntax(psql); 1229 } 1230 1231 protected int dochecksyntax(TCustomSqlStatement psql){ 1232 int ret = -1; 1233 clear(); 1234 if (sourcetokenlist.size() == 0) return ret; 1235 1236// TCustomParser lcparser; 1237// lcparser = new TLzParserOracleSql(sourcetokenlist); 1238// lcparser.sql = this; 1239// ret = lcparser.yyparse(); 1240 1241 1242 if ((this.dbvendor == EDbVendor.dbvoracle)&&(this.isoracleplsql()&&(plsqlparser!=null)) 1243// || ((this.dbvendor == EDbVendor.dbvgaussdb) // gaussdb 中用 oracle plsql 写的存储过程,用 oracle plsql parser 来解析 1244// &&( 1245// ((this instanceof TCreateFunctionStmt)&&(((TCreateFunctionStmt)this).isGaussDBSpInOracle())) 1246// ||((this instanceof TCreateProcedureStmt)&&(((TCreateProcedureStmt)this).isGaussDBSpInOracle())) 1247// ||(this instanceof TPlsqlCreatePackage) 1248// ) 1249// ) 1250 ){ 1251 plsqlparser.sql = this; 1252// if (this.dbvendor == EDbVendor.dbvgaussdb){ 1253// // 原来用 gaussDB lexer tokenize 的 token 需要用 Oracle lexer 重新 tokenize 一边 1254// String sqlText=""; 1255// for(int k = 0;k<sourcetokenlist.size();k++){ 1256// sqlText = sqlText + sourcetokenlist.get(k).toString(); 1257// } 1258// // TODO, need to use singleton pattern to get a single instance of Oracle parser. 1259// TGSqlParser sqlParser = new TGSqlParser(EDbVendor.dbvoracle); 1260// // keep coordinate of the origin query 1261// long originalLineNo = sourcetokenlist.get(0).lineNo; 1262// long originalColumnNo = sourcetokenlist.get(0).columnNo; 1263// sqlParser.sqltext = TBaseType.stringBlock((int) originalLineNo - 1,(int) originalColumnNo - 1)+ sqlText;; 1264// 1265// int r = sqlParser.getrawsqlstatements(); 1266// sourcetokenlist.clear(); 1267// for(int k=0;k<sqlParser.sourcetokenlist.size();k++){ 1268// sourcetokenlist.add(sqlParser.sourcetokenlist.get(k)); 1269// } 1270// } 1271 1272 plsqlparser.sourcetokenlist = sourcetokenlist; 1273 1274 if ((this instanceof TCommonStoredProcedureSqlStatement) 1275 &&((TCommonStoredProcedureSqlStatement)this).isWrapped()){ 1276 // don't parse wrapped oracle plsql 1277 ret = 0; 1278 this.rootNode = this; 1279 }else { 1280 ret = plsqlparser.yyparse(); 1281 this.rootNode = plsqlparser.rootNode; 1282 } 1283 } 1284 else{ 1285 if ((this.sqlstatementtype == ESqlStatementType.sstExplain)&&(dbvendor != EDbVendor.dbvhana)){ 1286 // EXPLAIN PLAN ... FOR statement; only parse token after FOR keyword 1287 boolean isFoundStopToken = false; 1288 1289 for(int k=0;k<sourcetokenlist.size();k++){ 1290 TSourceToken st = sourcetokenlist.get(k); 1291 switch (dbvendor){ 1292 case dbvoracle: 1293 if (st.tokencode == TBaseType.rrw_for) { 1294 st.tokencode = TBaseType.sqlpluscmd; 1295 isFoundStopToken = true; 1296 } 1297 break; 1298 case dbvredshift: 1299 if (st.tokencode == TBaseType.rrw_explain){ 1300 st.tokencode = TBaseType.sqlpluscmd; 1301 TSourceToken nextst = st.nextSolidToken(); 1302 if (nextst.tokencode == TBaseType.rrw_redshift_verbose){ 1303 nextst.tokencode = TBaseType.sqlpluscmd; 1304 //System.out.println("Found verbose after explain"); 1305 } 1306 isFoundStopToken = true; 1307 } 1308 break; 1309 case dbvvertica: 1310 if ((st.tokencode == TBaseType.rrw_select) 1311 ||(st.tokencode == TBaseType.rrw_insert) 1312 ||(st.tokencode == TBaseType.rrw_update) 1313 ||(st.tokencode == TBaseType.rrw_merge) 1314 ) 1315 { 1316 isFoundStopToken = true; 1317 } 1318 break; 1319 case dbvclickhouse: 1320 case dbvmysql: 1321 case dbvsparksql: 1322 case dbvdatabricks: 1323 if ((st.tokencode == TBaseType.rrw_select) 1324 ||(st.tokencode == TBaseType.rrw_insert) 1325 ||(st.tokencode == TBaseType.rrw_update) 1326 ||(st.tokencode == TBaseType.rrw_delete) 1327 ||(st.tokencode == TBaseType.rrw_replace) 1328 ||(st.tokencode == TBaseType.rrw_with) 1329 ||(st.tokencode == TBaseType.rrw_create) 1330 ||(st.tokencode == '(') 1331 ) 1332 { 1333 isFoundStopToken = true; 1334 } 1335 break; 1336 case dbvpostgresql: 1337 if ((st.tokencode == TBaseType.rrw_select) 1338 ||(st.tokencode == TBaseType.rrw_insert) 1339 ||(st.tokencode == TBaseType.rrw_update) 1340 ||(st.tokencode == TBaseType.rrw_delete) 1341 ||(st.tokencode == TBaseType.rrw_replace) 1342 ||(st.tokencode == TBaseType.rrw_with) 1343 ||(st.tokencode == TBaseType.rrw_create) 1344 ||(st.tokencode == TBaseType.rrw_execute) 1345 ) 1346 { 1347 isFoundStopToken = true; 1348 }else if (st.tokencode == '('){ 1349 // Check if this '(' starts EXPLAIN options like (COSTS FALSE) 1350 // or a subquery like (SELECT ...) 1351 TSourceToken nextSolid = sourcetokenlist.nextsolidtoken(k, 1, false); 1352 if (nextSolid != null 1353 && nextSolid.tokencode != TBaseType.rrw_select 1354 && nextSolid.tokencode != TBaseType.rrw_insert 1355 && nextSolid.tokencode != TBaseType.rrw_update 1356 && nextSolid.tokencode != TBaseType.rrw_delete 1357 && nextSolid.tokencode != TBaseType.rrw_with){ 1358 // Options list: skip past closing ')' 1359 int depth = 1; 1360 st.tokencode = TBaseType.sqlpluscmd; 1361 for (k = k + 1; k < sourcetokenlist.size() && depth > 0; k++){ 1362 TSourceToken inner = sourcetokenlist.get(k); 1363 if (inner.tokencode == '(') depth++; 1364 else if (inner.tokencode == ')') depth--; 1365 inner.tokencode = TBaseType.sqlpluscmd; 1366 } 1367 k--; // adjust for loop increment 1368 }else{ 1369 isFoundStopToken = true; 1370 } 1371 } 1372 break; 1373 case dbvflink: 1374 // Flink EXPLAIN can have: EXPLAIN (options) stmt or EXPLAIN options stmt 1375 // Don't stop at '(' because it might be part of EXPLAIN (ESTIMATED_COST, ...) 1376 if ((st.tokencode == TBaseType.rrw_select) 1377 ||(st.tokencode == TBaseType.rrw_insert) 1378 ||(st.tokencode == TBaseType.rrw_update) 1379 ||(st.tokencode == TBaseType.rrw_delete) 1380 ||(st.tokencode == TBaseType.rrw_replace) 1381 ||(st.tokencode == TBaseType.rrw_with) 1382 ||(st.tokencode == TBaseType.rrw_create) 1383 ) 1384 { 1385 isFoundStopToken = true; 1386 } 1387 break; 1388 case dbvcouchbase: 1389 if (st.tokencode == TBaseType.rrw_explain){ 1390 st.tokencode = TBaseType.sqlpluscmd; 1391 isFoundStopToken = true; 1392 } 1393 break; 1394 case dbvpresto: 1395 case dbvathena: 1396 case dbvnetezza: 1397 if ((st.tokencode == TBaseType.rrw_select) 1398 ||(st.tokencode == TBaseType.rrw_insert) 1399 ||(st.tokencode == TBaseType.rrw_update) 1400 ||(st.tokencode == TBaseType.rrw_delete) 1401 ) 1402 { 1403 isFoundStopToken = true; 1404 } 1405 break; 1406 case dbvteradata: 1407 if ((st.tokencode == TBaseType.rrw_select) 1408 ||(st.tokencode == TBaseType.rrw_insert) 1409 ||(st.tokencode == TBaseType.rrw_update) 1410 ||(st.tokencode == TBaseType.rrw_delete) 1411 ||(st.tokencode == TBaseType.rrw_teradata_collect) 1412 ) 1413 { 1414 isFoundStopToken = true; 1415 } 1416 break; 1417 }//switch 1418 1419 if (isFoundStopToken) break; 1420 st.tokencode = TBaseType.sqlpluscmd; 1421 } 1422 }else if (this.sqlstatementtype == ESqlStatementType.sstProfile){ 1423 for(int k=0;k<sourcetokenlist.size();k++) { 1424 TSourceToken st = sourcetokenlist.get(k); 1425 if (dbvendor == EDbVendor.dbvvertica){ 1426 if ((st.tokencode == TBaseType.rrw_select) 1427 ||(st.tokencode == TBaseType.rrw_insert) 1428 ||(st.tokencode == TBaseType.rrw_update) 1429 ||(st.tokencode == TBaseType.rrw_merge) 1430 ) 1431 { 1432 break; 1433 } 1434 } 1435 st.tokencode = TBaseType.sqlpluscmd; 1436 } 1437 }else if (this.sqlstatementtype == ESqlStatementType.sstprepare){ 1438 if ((dbvendor == EDbVendor.dbvcouchbase)||(dbvendor == EDbVendor.dbvpresto)||(dbvendor == EDbVendor.dbvathena)){ 1439 int keywordCount = 0; 1440 for(int k=0;k<sourcetokenlist.size();k++) { 1441 TSourceToken st = sourcetokenlist.get(k); 1442 if (st.tokencode == TBaseType.rrw_prepare) 1443 { 1444 keywordCount++; 1445 }else if ((st.tokentype == ETokenType.ttkeyword) 1446 &&(st.tokencode != TBaseType.rrw_from) 1447 &&(st.tokencode != TBaseType.rrw_as)){ 1448 keywordCount++; 1449 if (keywordCount > 1) break; 1450 } 1451 st.tokencode = TBaseType.sqlpluscmd; 1452 } 1453 } 1454 } 1455 1456 if (parser == null){ 1457 // statement such as select/insert and etc inside plsql 1458 if (psql != null){ 1459 parser = psql.getTopStatement().parser; 1460 this.setParentStmt(psql); 1461 } 1462 // parser = new TParserOracleSql(null); 1463 //parser.lexer = new TLexerOracle(); 1464 //parser.lexer.delimiterchar = '/'; 1465 } 1466 parser.sql = this; 1467 parser.sourcetokenlist = sourcetokenlist; 1468 ret = parser.yyparse(); 1469 this.rootNode = parser.rootNode; 1470 } 1471 1472 if (ret == 0){ 1473 ret = syntaxErrors.size(); 1474 } 1475 // if (rootNode == null) { 1476 if (rootNode == null) { 1477 // EXPLAIN FOR CONNECTION has no inner statement to parse - this is valid 1478 if (this.sqlstatementtype == ESqlStatementType.sstExplain && isExplainForConnection()) { 1479 ret = 0; 1480 } else { 1481 ret = TBaseType.MSG_ERROR_NO_ROOT_NODE; 1482 // todo , uncomment next line when all sql statements in .y file was processed 1483 parseerrormessagehandle( new TSyntaxError("no root node",0,0,"no_root_node",EErrorType.sperror,TBaseType.MSG_ERROR_NO_ROOT_NODE,this,-1)); 1484 } 1485 } 1486 return ret; 1487 } 1488 1489 private boolean isExplainForConnection() { 1490 if (sourcetokenlist == null) return false; 1491 for (int i = 0; i < sourcetokenlist.size() - 1; i++) { 1492 TSourceToken st = sourcetokenlist.get(i); 1493 if (st.toString().equalsIgnoreCase("for")) { 1494 TSourceToken next = sourcetokenlist.nextsolidtoken(i, 1, false); 1495 if (next != null && next.toString().equalsIgnoreCase("connection")) { 1496 return true; 1497 } 1498 } 1499 } 1500 return false; 1501 } 1502 1503 public void clearError(){ 1504 syntaxErrors.clear(); 1505 syntaxHints.clear(); 1506 } 1507 1508 void clear(){ 1509 syntaxErrors.clear(); 1510 syntaxHints.clear(); 1511// todo all subclass should add super() 1512 } 1513 1514 public void setStmtScope(TStmtScope stmtScope) { 1515 this.stmtScope = stmtScope; 1516 } 1517 1518 public TStmtScope getStmtScope() { 1519 return stmtScope; 1520 } 1521 1522 /** 1523 * Original SQL fragment of this statement. 1524 * @return Original statement text. 1525 */ 1526 1527 /* 1528 public String toString(){ 1529 StringBuffer sb = new StringBuffer(""); 1530 for(int i=0; i<sourcetokenlist.size();i++){ 1531 sb.append(sourcetokenlist.get(i).toString()); 1532 } 1533 return sb.toString(); 1534 } 1535 */ 1536 protected TStmtScope stmtScope = null; 1537 void buildsql(){} 1538 public int doParseStatement(TCustomSqlStatement psql){ 1539 if (psql != null){ 1540 this.setParentStmt(psql); 1541 this.setFrameStack(psql.getFrameStack()); 1542 psql.stmtScope.incrementCurrentStmtIndex(); 1543 this.queryId = String.format("%s#stmt_%d_%s", psql.getQueryId(),psql.stmtScope.getCurrentStmtIndex(), this.sqlstatementtype); 1544 stmtScope = new TStmtScope(psql.stmtScope,this); 1545 // psql.statements.add(this); 1546 }else{ 1547 stmtScope = new TStmtScope(this); 1548 1549 // global scope 1550 this.getFrameStack().peek().getScope().incrementCurrentStmtIndex(); 1551 this.queryId = String.format("stmt_%d_%s",this.getFrameStack().peek().getScope().getCurrentStmtIndex(), this.sqlstatementtype); 1552 } 1553 1554 if ((this.getStartToken() == null)&&(rootNode != null)){ 1555 this.setStartToken(rootNode.getStartToken()); 1556 } 1557 if ((this.getEndToken() == null)&&(rootNode != null)){ 1558 this.setEndToken(rootNode.getEndToken()); 1559 } 1560 1561 if(this.getGsqlparser() == null){ 1562 if (rootNode != null){ 1563 this.setGsqlparser(rootNode.getGsqlparser()); 1564 } 1565 } 1566 return 0; 1567 } 1568 1569 void addtokentolist(TSourceToken st){ 1570 st.stmt = this; 1571 sourcetokenlist.add(st); 1572 } 1573 1574 public TTable analyzeTablename(TObjectName tableName){ 1575 TTable lcTable = new TTable(); 1576 lcTable.setTableType(ETableSource.objectname); 1577 lcTable.setStartToken(tableName.getStartToken()); 1578 lcTable.setEndToken(tableName.getEndToken()); 1579 lcTable.setGsqlparser(this.getGsqlparser()); 1580 lcTable.setTableName(tableName); 1581 1582 tables.addTable(lcTable); 1583 return lcTable; 1584 } 1585 1586 protected boolean isTableACTE(TTable pTable){ 1587 boolean lcResult = false; 1588 TCTEList cteList1 = getCteList(); 1589 if (cteList1 == null){ 1590 TCustomSqlStatement lcStmt = getParentStmt(); 1591 while (lcStmt != null){ 1592 if (lcStmt.getCteList() != null){ 1593 cteList1 = lcStmt.getCteList(); 1594 break; 1595 }else { 1596 lcStmt = lcStmt.getParentStmt(); 1597 } 1598 } 1599 } 1600 if (cteList1 == null) return false; 1601 // TCTE lcCTE = cteList1.cteNames.get(TBaseType.getTextWithoutQuoted(pTable.toString()).toUpperCase()); 1602 if (pTable.toString() == null) return false; 1603 1604 int searchPos = pTable.getStartToken().posinlist; 1605 if (this.getCteIncludeThisStmt() != null){ 1606 searchPos = this.getCteIncludeThisStmt().getStartToken().posinlist; 1607 } 1608 TCTE lcCTE = cteList1.searchCTEByName(TBaseType.getTextWithoutQuoted(pTable.toString()).toUpperCase(),searchPos); 1609 if ( lcCTE != null ){ 1610 if (pTable.setCTE(lcCTE)){ 1611 pTable.setCTEName(true); 1612 lcResult = true; 1613 } 1614 } 1615// for (int i=0;i<cteList1.size();i++){ 1616// lcCTE = cteList1.getCTE(i); 1617// if (TBaseType.getTextWithoutQuoted(lcCTE.getTableName().toString()).equalsIgnoreCase(TBaseType.getTextWithoutQuoted(pTable.toString()))){ 1618// pTable.setCTEName(true); 1619// pTable.setCTE(lcCTE); 1620// lcResult = true; 1621// break; 1622// } 1623// } 1624 1625 return lcResult; 1626 1627 } 1628 1629 public TTable findTable(ETableEffectType[] tableEffectTypes){ 1630 TTable lcResult = null; 1631 for(int i=0;i<tables.size();i++){ 1632 for(int j=0;j<tableEffectTypes.length;j++){ 1633 if (tables.getTable(i).getEffectType() == tableEffectTypes[j]){ 1634 lcResult = tables.getTable(i); 1635 return lcResult; 1636 } 1637 } 1638 } 1639 return lcResult; 1640 } 1641 public void addToTables(TTable pTable){ 1642 tables.addTable(pTable); 1643 if (isTableACTE(pTable)) return; 1644 1645 if (pTable.getTableName() == null) return; 1646 if (pTable.getTableName().getTableToken() == null) return; 1647 if ((pTable.getTableName().getTableString().toString().equalsIgnoreCase("inserted"))||(pTable.getTableName().getTableString().toString().equalsIgnoreCase("deleted"))){ 1648 if ((getAncestorStmt().sqlstatementtype == ESqlStatementType.sstcreatetrigger) 1649 ||(getAncestorStmt().sqlstatementtype == ESqlStatementType.sstmssqlaltertrigger)){ 1650 //pTable.setLinkTable(true); 1651 ETableEffectType[] effectTypes = new ETableEffectType[]{ 1652 ETableEffectType.tetTriggerOn,ETableEffectType.tetTriggerInsert,ETableEffectType.tetTriggerDelete,ETableEffectType.tetTriggerUpdate,ETableEffectType.tetTriggerInsteadOf 1653 }; 1654 pTable.setLinkTable(getAncestorStmt().findTable(effectTypes)); 1655 } 1656 } 1657 1658 } 1659 1660 public TJoin analyzeTableOrJoin(TFromTable pfromTable){ 1661 TFromTable lcFromTable = pfromTable; 1662 TJoin lcJoin; 1663 TTable lcTable; 1664 1665 if (lcFromTable.getFromtableType() != ETableSource.join){ 1666 lcJoin = new TJoin(); 1667 lcTable = analyzeFromTable(lcFromTable,true); 1668 lcTable.setEffectType(ETableEffectType.tetSelect); 1669 lcJoin.setTable(lcTable); 1670 lcJoin.setStartToken(lcJoin.getTable().getStartToken()); 1671 lcJoin.setEndToken(lcJoin.getTable().getEndToken()); 1672 lcJoin.setGsqlparser(getGsqlparser()); 1673 this.fromSourceTable = lcTable; 1674 this.getRelations().add(lcTable); 1675 }else{ 1676 this.fromSourceJoin = lcFromTable.getJoinExpr(); 1677 1678 this.fromSourceTable = new TTable(); 1679 this.fromSourceTable.setTableType(ETableSource.join); 1680 this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause()); 1681 this.fromSourceTable.setStartToken(lcFromTable.getStartToken()); 1682 this.fromSourceTable.setEndToken(lcFromTable.getEndToken()); 1683 this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser()); 1684 this.fromSourceTable.setJoinExpr(this.fromSourceJoin); 1685 this.getRelations().add(this.fromSourceTable); 1686 1687 lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true); 1688 lcJoin.doParse(this, ESqlClause.join); 1689 1690 if (lcFromTable.getLateralViewList() != null){ 1691 for(TLateralView lateralView:lcFromTable.getLateralViewList()){ 1692 TTable t = lateralView.createATable(this); 1693 addToTables(t); 1694 this.relations.add(t); 1695 } 1696 } 1697 } 1698 1699 return lcJoin; 1700 } 1701 1702 public TTable analyzeFromTable(TFromTable pfromTable, Boolean addToTableList){ 1703 return analyzeFromTable(pfromTable,addToTableList,ESqlClause.unknown); 1704 } 1705 1706 public TTable analyzeFromTable(TFromTable pfromTable, Boolean addToTableList, ESqlClause pLocation){ 1707 TTable lcTable = new TTable(); 1708 lcTable.setTableType(pfromTable.getFromtableType()); 1709 lcTable.setAliasClause(pfromTable.getAliasClause()); 1710 lcTable.setStartToken(pfromTable.getStartToken()); 1711 lcTable.setEndToken(pfromTable.getEndToken()); 1712 lcTable.setGsqlparser(pfromTable.getGsqlparser()); 1713 lcTable.setTableHintList(pfromTable.getTableHintList()); 1714 lcTable.setTableSample(pfromTable.getTableSample()); 1715 lcTable.setLateralViewList(pfromTable.getLateralViewList()); 1716 lcTable.setTableProperties(pfromTable.getTableProperties()); 1717 lcTable.setPivotedTable(pfromTable.getPivotedTable()); 1718 lcTable.setParenthesisCount(pfromTable.getParenthesisCount()); 1719 lcTable.setParenthesisAfterAliasCount(pfromTable.getParenthesisAfterAliasCount()); 1720 lcTable.setTableKeyword(pfromTable.isTableKeyword()); 1721 lcTable.setOnlyKeyword(pfromTable.isOnlyKeyword()); 1722 lcTable.setFlashback(pfromTable.getFlashback()); 1723 lcTable.setPxGranule(pfromTable.getPxGranule()); 1724 lcTable.setTimeTravelClause(pfromTable.getTimeTravelClause()); 1725 //lcTable.setPartitionClause(pfromTable.getPartitionClause()); 1726 1727 if(getFrameStack().firstElement() != null){ 1728 TFrame stackFrame = getFrameStack().firstElement(); 1729 TGlobalScope globalScope = (TGlobalScope)stackFrame.getScope(); 1730 lcTable.setSqlEnv(globalScope.getSqlEnv()); 1731 } 1732 1733 switch(lcTable.getTableType()){ 1734 case objectname:{ 1735 // tables.addTableByTableRefernce(pfromTable.getTableObjectName()); 1736 boolean insertedInTrigger = false; 1737 if (getTopStatement().sqlstatementtype == ESqlStatementType.sstcreatetrigger){ 1738 insertedInTrigger = (pfromTable.getTableObjectName().toString().compareToIgnoreCase("inserted")==0); 1739 } 1740 1741 if (insertedInTrigger){ 1742 // change table name from inserted to onTable name in create trigger 1743 lcTable.setTableName(((TCreateTriggerStmt)getTopStatement()).getOnTable().getTableName()); 1744 //lcTable.setLinkTable(true); 1745 lcTable.setLinkTable(((TCreateTriggerStmt)getTopStatement()).getOnTable()); 1746 1747 }else{ 1748 lcTable.setTableName(pfromTable.getTableObjectName()); 1749 lcTable.getTableName().setSqlEnv(getSqlEnv()); 1750 1751// if (getSqlEnv().getDefaultCatalogName() != null){ 1752// if (lcTable.getTableName().getDatabaseToken() == null){ 1753// lcTable.getTableName().setDatabaseToken(new TSourceToken(getSqlEnv().getDefaultCatalogName()),true); 1754// } 1755// } 1756 1757// if ((lcTable.getTableName().getSchemaToken() == null)&&(TSQLEnv.supportSchema(this.dbvendor))){ 1758// // let find schema name for this table in env 1759// TSQLTable t = getSqlEnv().searchTable(".."+lcTable.getFullName()); 1760// if (t != null){ 1761// TSQLSchema s = t.getSchema(); 1762// if (s != null){ 1763// lcTable.getTableName().setSchemaToken(new TSourceToken(s.getName()),true); 1764// } 1765// } 1766// } 1767 1768 } 1769 // let's check is it cte name or ordinary table name 1770 TCTEList lcCteList = searchCTEList(false); 1771 TCTE lcCte = null; 1772 if (lcCteList != null){ 1773 for(int i=0;i<lcCteList.size();i++){ 1774 lcCte = lcCteList.getCTE(i); 1775 if (lcCte.getTableName().toString().compareToIgnoreCase(TBaseType.getTextWithoutQuoted(lcTable.getTableName().toString()))==0){ 1776 // this is cte name 1777 if (lcTable.setCTE(lcCte)){ 1778 lcTable.setCTEName(true); 1779 lcTable.setCteColomnReferences(lcCte.getColumnList()); 1780 break; 1781 } 1782 } 1783 } 1784 } 1785 1786 break; 1787 } 1788 case tableExpr:{ 1789 ESqlClause location = ESqlClause.tableExpr; //ESqlClause.resultColumn; 1790 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1791 // change location here 1792 } 1793 lcTable.setTableExpr(pfromTable.getTableExpr()); 1794 lcTable.getTableExpr().doParse(this,location); 1795 // 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; 1796 // RETURNS (outkey integer, tokennum integer, token varchar(20)) 1797 lcTable.setColumnDefinitions(pfromTable.getColumnDefinitions()); 1798 // Teradata table function HASH BY and LOCAL ORDER BY clauses 1799 lcTable.setHashByClause(pfromTable.getHashByClause()); 1800 lcTable.setLocalOrderBy(pfromTable.getLocalOrderBy()); 1801 break; 1802 } 1803 case subquery:{ 1804// if (pfromTable.getSubquerynode().isHiveFromQuery()){ 1805// THiveFromQuery fromQuery = new THiveFromQuery(dbvendor); 1806// lcTable.setHiveFromQuery(fromQuery); 1807// fromQuery.rootNode = pfromTable.getSubquerynode(); 1808// fromQuery.setStartToken(pfromTable.getSubquerynode()); 1809// fromQuery.setEndToken(pfromTable.getSubquerynode()); 1810// fromQuery.setLabelName(this.labelName); 1811// fromQuery.doParseStatement(this); 1812// }else{ 1813// lcTable.subquery = new TSelectSqlStatement(dbvendor); 1814// lcTable.subquery.rootNode = pfromTable.getSubquerynode(); 1815// lcTable.subquery.setLocation(ESqlClause.elTable); 1816// //lcTable.subquery.resultColumnList = ((TSelectSqlNode)lcTable.subquery.rootNode).getResultColumnList(); 1817// lcTable.subquery.doParseStatement(this); 1818// } 1819 1820 lcTable.subquery = new TSelectSqlStatement(dbvendor); 1821 lcTable.subquery.rootNode = pfromTable.getSubquerynode(); 1822 if (pLocation == ESqlClause.unknown){ 1823 lcTable.subquery.setLocation(ESqlClause.elTable); 1824 }else{ 1825 lcTable.subquery.setLocation(pLocation); 1826 } 1827 //lcTable.subquery.resultColumnList = ((TSelectSqlNode)lcTable.subquery.rootNode).getResultColumnList(); 1828 lcTable.subquery.doParseStatement(this); 1829 1830 break; 1831 } 1832 case function:{ 1833 ESqlClause location = ESqlClause.tableFunction;// resultColumn; 1834 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1835 // change location here 1836 } 1837 lcTable.setFuncCall(pfromTable.getFuncCall()); 1838 lcTable.getFuncCall().doParse(this,location); 1839 break; 1840 } 1841 case containsTable:{ 1842 ESqlClause location = ESqlClause.containsTable;//resultColumn; 1843 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1844 // change location here 1845 } 1846 lcTable.setContainsTable(pfromTable.getContainsTable()); 1847 lcTable.getContainsTable().doParse(this,location); 1848 break; 1849 } 1850 1851 case openrowset:{ 1852 ESqlClause location = ESqlClause.openrowset;//resultColumn; 1853 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1854 // change location here 1855 } 1856 lcTable.setOpenRowSet(pfromTable.getOpenRowSet()); 1857 lcTable.getOpenRowSet().doParse(this,location); 1858 break; 1859 } 1860 1861 case openxml:{ 1862 ESqlClause location = ESqlClause.openxml;//resultColumn; 1863 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1864 // change location here 1865 } 1866 lcTable.setOpenXML(pfromTable.getOpenXML()); 1867 lcTable.getOpenXML().doParse(this,location); 1868 break; 1869 } 1870 1871 case opendatasource:{ 1872 ESqlClause location = ESqlClause.opendatasource;//resultColumn; 1873 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1874 // change location here 1875 } 1876 lcTable.setOpenDatasource(pfromTable.getOpenDatasource()); 1877 lcTable.getOpenDatasource().doParse(this,location); 1878 break; 1879 } 1880 1881 case openquery:{ 1882 ESqlClause location = ESqlClause.openquery;//resultColumn; 1883 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1884 // change location here 1885 } 1886 lcTable.setOpenquery(pfromTable.getOpenQuery()); 1887 lcTable.getOpenquery().doParse(this,location); 1888 lcTable.setSubquery(lcTable.getOpenquery().getSubquery()); 1889 break; 1890 } 1891 1892 case datachangeTable:{ 1893 ESqlClause location = ESqlClause.datachangeTable;//resultColumn; 1894 if (sqlstatementtype == ESqlStatementType.sstinsert ){ 1895 // change location here 1896 } 1897 lcTable.setDatachangeTable(pfromTable.getDatachangeTable()); 1898 lcTable.getDatachangeTable().doParse(this,location); 1899 break; 1900 } 1901 case rowList:{ 1902 ESqlClause location = ESqlClause.rowList;//resultColumn; 1903 lcTable.setValueClause(pfromTable.getValueClause()); 1904 lcTable.getValueClause().doParse(this,location); 1905 break; 1906 } 1907 case pivoted_table:{ 1908 ESqlClause location = ESqlClause.pivoted_table;//resultColumn; 1909 lcTable.getPivotedTable().doParse(this,location); 1910 addToTableList = false; 1911 targetTable = lcTable; 1912 break; 1913 } 1914 case xmltable:{ 1915 ESqlClause location = ESqlClause.xmltable;//resultColumn; 1916 lcTable.setXmlTable(pfromTable.getXmlTable()); 1917 lcTable.getXmlTable().doParse(this,location); 1918 break; 1919 } 1920 1921 case informixOuter:{ 1922 ESqlClause location = ESqlClause.outerTable;//resultColumn; 1923 lcTable.setOuterClause(pfromTable.getOuterClause()); 1924 lcTable.getOuterClause().doParse(this,location); 1925 break; 1926 } 1927 1928 case table_ref_list:{ 1929 lcTable.setFromTableList(pfromTable.getFromTableList()); 1930 break; 1931 } 1932// case hiveFromQuery:{ 1933// THiveFromQuery fromQuery = new THiveFromQuery(EDbVendor.dbvhive); 1934// fromQuery.rootNode = pfromTable.getFromQuerySqlNode(); 1935// fromQuery.doParseStatement(this); 1936// lcTable.setHiveFromQuery(fromQuery); 1937// break; 1938// } 1939 case output_merge:{ 1940 TMergeSqlStatement outputMerge = new TMergeSqlStatement(EDbVendor.dbvmssql); 1941 outputMerge.rootNode = pfromTable.getMergeSqlNode(); 1942 outputMerge.doParseStatement(this); 1943 lcTable.setOutputMerge(outputMerge); 1944 break; 1945 } 1946 case td_unpivot:{ 1947 // Set the TD_UNPIVOT output table before doParse so that VALUE_COLUMNS and 1948 // UNPIVOT_COLUMN can be linked to it (they are output columns of TD_UNPIVOT) 1949 pfromTable.getTdUnpivot().setTdUnpivotOutputTable(lcTable); 1950 pfromTable.getTdUnpivot().doParse(this,ESqlClause.tdUnPivot); 1951 lcTable.setTdUnpivot(pfromTable.getTdUnpivot()); 1952 break; 1953 } 1954 case unnest:{ 1955 pfromTable.getUnnestClause().doParse(this,ESqlClause.elTable); 1956 lcTable.setUnnestClause(pfromTable.getUnnestClause()); 1957 if (lcTable.getAliasClause() != null){ 1958 if (lcTable.getAliasClause().getColumns() != null){ 1959 for(TObjectName pColumn:lcTable.getAliasClause().getColumns()){ 1960 lcTable.getLinkedColumns().addObjectName(pColumn); 1961 pColumn.setSourceTable(lcTable); 1962 } 1963 }else if (lcTable.getAliasClause().getAliasName() != null){ 1964// SELECT * 1965// FROM UNNEST(['foo', 'bar', 'baz', 'qux', 'corge', 'garply', 'waldo', 'fred']) AS element 1966// WITH OFFSET AS offset 1967 1968 // add element as column of unnest table. 1969 TObjectName newColumn = TObjectName.createObjectName(this.dbvendor,EDbObjectType.column,lcTable.getAliasClause().getAliasName().getStartToken()); 1970 lcTable.getLinkedColumns().addObjectName(newColumn); 1971 newColumn.setSourceTable(lcTable); 1972 } 1973 } 1974 1975 if (lcTable.getUnnestClause().getWithOffset() != null){ 1976 if (lcTable.getUnnestClause().getWithOffsetAlais() != null){ 1977 // with offset as offsetAlias 1978 TAliasClause aliasClause = lcTable.getUnnestClause().getWithOffsetAlais(); 1979 if (aliasClause.getAliasName() != null){ 1980 TObjectName newColumn = TObjectName.createObjectName(this.dbvendor,EDbObjectType.column,aliasClause.getAliasName().getStartToken()); 1981 lcTable.getLinkedColumns().addObjectName(newColumn); 1982 newColumn.setSourceTable(lcTable); 1983 } 1984 }else{ 1985 // with offset 1986 TObjectName newColumn = TObjectName.createObjectName(this.dbvendor,EDbObjectType.column,new TSourceToken("offset")); 1987 lcTable.getLinkedColumns().addObjectName(newColumn); 1988 newColumn.setSourceTable(lcTable); 1989 } 1990 } 1991 1992 // link columns in the select list to unnest() 1993 // select emp_id,name,state,city,zipcode from `absolute-runner-302907.gudu_sqlflow.ADDRESS_NESTED`, UNNEST(address) 1994 if (lcTable.getUnnestClause().getDerivedColumnList() != null){ 1995 TObjectNameList derivedColumns = lcTable.getUnnestClause().getDerivedColumnList(); 1996 for(int i=0;i<derivedColumns.size();i++){ 1997 //System.out.println(derivedColumns.getObjectName(i).toString()); 1998 lcTable.getLinkedColumns().addObjectName(derivedColumns.getObjectName(i)); 1999 } 2000 } 2001 2002 break; 2003 } 2004 case jsonTable:{ 2005 ESqlClause location = ESqlClause.jsonTable;//resultColumn; 2006 lcTable.setJsonTable(pfromTable.getJsonTable()); 2007 lcTable.getJsonTable().doParse(this,location); 2008 break; 2009 } 2010 case externalTable: 2011 lcTable.setTableName(pfromTable.getTableObjectName()); 2012 lcTable.setColumnDefinitions(pfromTable.getColumnDefinitions()); 2013 lcTable.getColumnDefinitions().doParse(this,pLocation); 2014 lcTable.setTableType(ETableSource.externalTable); // tableType is reset in setTableName() method, so we reset it here 2015 break; 2016 case caseJoin: 2017 lcTable.setCaseJoin(pfromTable.getCaseJoin()); 2018 lcTable.getCaseJoin().doParse(this,pLocation); 2019 break; 2020 case stageReference: 2021 lcTable.setStageReference(pfromTable.getStageReference()); 2022 lcTable.getStageReference().doParse(this,pLocation); 2023 2024 lcTable.setTableName(lcTable.getStageReference().getStageName()); 2025 lcTable.setTableType(ETableSource.stageReference); 2026 lcTable.getTableName().setSqlEnv(getSqlEnv()); 2027 2028 break; 2029 2030 }//switch 2031 2032// if (pfromTable.getPivotClause() != null){ 2033// lcTable.setPivotClause(pfromTable.getPivotClause()); 2034// lcTable.getPivotClause().doParse(this,ESqlClause.resultColumn); 2035// } 2036 2037 lcTable.setPartitionExtensionClause(pfromTable.getPartitionExtensionClause()); 2038 2039 //tables.addTable(lcTable); 2040 if (addToTableList) { 2041 addToTables(lcTable); 2042 } 2043 2044 if (lcTable.getTableHintList() != null){ 2045 for(int i=0;i<lcTable.getTableHintList().size();i++){ 2046 TTableHint hint = lcTable.getTableHintList().getElement(i); 2047 hint.setOwnerTable(lcTable); 2048 hint.doParse(this,ESqlClause.tableHint); 2049 } 2050 } 2051 2052 if (lcTable.getLateralViewList() != null){ 2053 for(TLateralView lateralView:lcTable.getLateralViewList()){ 2054 TTable t = lateralView.createATable(this); 2055 addToTables(t); 2056 this.relations.add(t); 2057 } 2058 } 2059 2060 if (lcTable.getAliasClause() != null){ 2061 if (lcTable.getAliasClause().toString().equalsIgnoreCase("and")){ 2062 // end keyword can't be alias name 2063 TSourceToken st1 = lcTable.getAliasClause().getStartToken(); 2064 TSyntaxError err = new TSyntaxError(st1.toString() 2065 ,st1.lineNo,st1.columnNo 2066 ,String.format("AND keyword can't be table alias") 2067 ,EErrorType.sperror 2068 ,TBaseType.MSG_ERROR_AND_KEYWORD_CANT_USED_AS_TABLE_ALIAS 2069 ,this,st1.posinlist); 2070 this.parseerrormessagehandle( err); 2071 2072 } 2073 } 2074 2075 return lcTable; 2076 } 2077 2078 public TJoin analyzeJoin(TJoinExpr pJoinExpr,TJoin pJoin,Boolean isSub){ 2079 TJoin retval = pJoin; 2080 TJoinItem lcJoinItem = null ; 2081 2082 if (pJoinExpr == null) {return retval;} 2083 2084 if (pJoinExpr.getJointype() == EJoinType.nested) 2085 { 2086 if (isSub) 2087 { 2088 if (retval == null) { // top level, left side is a join 2089 retval = new TJoin(); 2090 retval.setStartToken(pJoinExpr.getStartToken()); 2091 retval.setEndToken(pJoinExpr.getEndToken()); 2092 } 2093 2094 pJoinExpr.setJointype(pJoinExpr.original_jontype); 2095 retval.setJoin(analyzeJoin(pJoinExpr,null,true)); 2096 //retval =analyzeJoin(pJoinExpr,null,true); 2097 retval.setKind(TBaseType.join_source_join); 2098 retval.getJoin().setAliasClause(pJoinExpr.getAliasClause()); 2099 retval.getJoin().setWithParen(true); 2100 retval.getJoin().setNestedParen(pJoinExpr.getNestedParen()); 2101 } 2102 else 2103 { 2104 if (retval == null) 2105 { 2106 retval = new TJoin(); 2107 retval.setStartToken(pJoinExpr.getStartToken()); 2108 retval.setEndToken(pJoinExpr.getEndToken()); 2109 retval.setGsqlparser(this.getGsqlparser()); 2110 } 2111 else 2112 { 2113 } 2114 pJoinExpr.setJointype(pJoinExpr.original_jontype); 2115 retval = analyzeJoin(pJoinExpr,retval,false); 2116 //retval.setJoin(analyzeJoin(pJoinExpr,retval,false)); 2117 //retval = analyzeJoin(pJoinExpr,retval,false); 2118 //retval.setKind(TBaseType.join_source_join); 2119 //retval.setKind(TBaseType.join_source_table); 2120 //retval.setAliasClause(pJoinExpr.getAliasClause()); 2121 retval.setAliasClause(pJoinExpr.getAliasClause()); 2122 retval.setWithParen(true); 2123 retval.setNestedParen(pJoinExpr.getNestedParen()); 2124 } 2125 return retval; 2126 } 2127 2128 if (pJoinExpr.getLeftOperand().getFromtableType() != ETableSource.join){ 2129 if (retval == null) { 2130 retval = new TJoin(); 2131 retval.setStartToken(pJoinExpr.getStartToken()); 2132 retval.setEndToken(pJoinExpr.getEndToken()); 2133 retval.setGsqlparser(this.getGsqlparser()); 2134 2135 // retval.setStartToken(pJoinExpr.getLeftOperand().getStartToken()); 2136 // retval.setEndToken(pJoinExpr.getLeftOperand().getEndToken()); 2137 } 2138 TTable lcTable = analyzeFromTable(pJoinExpr.getLeftOperand(),true,ESqlClause.join); 2139 lcTable.setEffectType(ETableEffectType.tetSelect); 2140 retval.setTable(lcTable); 2141 //retval.joinTable.OwnerJoin = result; 2142 retval.setKind(TBaseType.join_source_table); 2143 pJoinExpr.setLeftTable(lcTable); 2144 }else{ 2145 TJoinExpr lcJoinItemJoinExpr = pJoinExpr.getLeftOperand().getJoinExpr(); 2146 //if (lcJoinItemJoinExpr.getJointype() == TBaseType.join_nested){ 2147 // lcJoinItemJoinExpr.setJointype(lcJoinItemJoinExpr.original_jontype); 2148 //} 2149 2150 if (retval != null) { 2151 retval = analyzeJoin(lcJoinItemJoinExpr,retval,true); 2152 } else { 2153 retval = analyzeJoin(lcJoinItemJoinExpr,retval,isSub); 2154 } 2155 retval.setStartToken(lcJoinItemJoinExpr.getStartToken()); 2156 retval.setEndToken(lcJoinItemJoinExpr.getEndToken()); 2157 2158 2159 TTable lcTable = new TTable(); 2160 lcTable.setTableType(pJoinExpr.getLeftOperand().getFromtableType()); 2161 lcTable.setAliasClause(lcJoinItemJoinExpr.getAliasClause()); 2162 lcTable.setStartToken(lcJoinItemJoinExpr.getStartToken()); 2163 lcTable.setEndToken(lcJoinItemJoinExpr.getEndToken()); 2164 pJoinExpr.setLeftTable(lcTable); 2165 lcTable.setJoinExpr(lcJoinItemJoinExpr); 2166 } 2167 2168 if (pJoinExpr.getRightOperand().getFromtableType() != ETableSource.join){ 2169 if (retval != null) 2170 { 2171 lcJoinItem = new TJoinItem(); 2172 TTable lcTable = analyzeFromTable(pJoinExpr.getRightOperand(),true,ESqlClause.join); 2173 lcTable.setEffectType(ETableEffectType.tetSelect); 2174 lcJoinItem.setTable(lcTable); 2175 lcJoinItem.setStartToken(lcJoinItem.getTable().getStartToken()); 2176 lcJoinItem.setEndToken(lcJoinItem.getTable().getEndToken()); 2177 // lcJoinItem.JoinItemTable.OwnerJoinItem := lcJoinItem; 2178 lcJoinItem.setKind(TBaseType.join_source_table); 2179 retval.getJoinItems().addJoinItem(lcJoinItem); 2180 pJoinExpr.setRightTable(lcTable); 2181 } 2182 }else{ 2183 if (retval != null) 2184 { 2185 lcJoinItem = new TJoinItem(); 2186 lcJoinItem.setKind(TBaseType.join_source_join); 2187 TJoinExpr lcJoinItemJoinExpr = pJoinExpr.getRightOperand().getJoinExpr(); 2188 //if (lcJoinItemJoinExpr.getJointype() == TBaseType.join_nested){ 2189 // lcJoinItemJoinExpr.setJointype(lcJoinItemJoinExpr.original_jontype); 2190 //} 2191 lcJoinItem.setJoin(analyzeJoin(pJoinExpr.getRightOperand().getJoinExpr(),null,false)); 2192 lcJoinItem.getJoin().setAliasClause(lcJoinItemJoinExpr.getAliasClause()); 2193 lcJoinItem.setStartToken(lcJoinItem.getJoin().getStartToken()); 2194 lcJoinItem.setEndToken(lcJoinItem.getJoin().getEndToken()); 2195 retval.getJoinItems().addJoinItem(lcJoinItem); 2196 2197 TTable lcTable = new TTable(); 2198 lcTable.setTableType(pJoinExpr.getRightOperand().getFromtableType()); 2199 lcTable.setAliasClause(lcJoinItemJoinExpr.getAliasClause()); 2200 lcTable.setStartToken(lcJoinItemJoinExpr.getStartToken()); 2201 lcTable.setEndToken(lcJoinItemJoinExpr.getEndToken()); 2202 pJoinExpr.setRightTable(lcTable); 2203 lcTable.setJoinExpr(lcJoinItemJoinExpr); 2204 } 2205 } 2206 2207 if (lcJoinItem == null) return retval; 2208 2209 lcJoinItem.setJoinType(pJoinExpr.getJointype()); 2210 lcJoinItem.setUsingColumns(pJoinExpr.usingColumns); 2211 if ((lcJoinItem.getUsingColumns() != null) && (tables.size()>1)){ 2212 TObjectName crf ; 2213 for (int i=0;i<lcJoinItem.getUsingColumns().size();i++){ 2214 crf = lcJoinItem.getUsingColumns().getObjectName(i); 2215 // link this column to last 2 tables 2216 tables.getTable(tables.size()-1).getObjectNameReferences().addObjectName(crf); 2217 tables.getTable(tables.size()-2).getObjectNameReferences().addObjectName(crf); 2218 2219 tables.getTable(tables.size()-1).getLinkedColumns().addObjectName(crf); 2220 crf.setSourceTable(tables.getTable(tables.size()-1)); 2221 tables.getTable(tables.size()-2).getLinkedColumns().addObjectName(crf); 2222 crf.setSourceTable(tables.getTable(tables.size()-2)); 2223 2224 } 2225 lcJoinItem.setEndToken(lcJoinItem.getUsingColumns().getEndToken()); 2226 } 2227 lcJoinItem.setOnCondition(pJoinExpr.onCondition); 2228 if (lcJoinItem.getOnCondition() != null) 2229 { 2230 lcJoinItem.getOnCondition().doParse(this,ESqlClause.joinCondition); 2231 lcJoinItem.setEndToken(lcJoinItem.getOnCondition().getEndToken()); 2232 } 2233 2234 2235 return retval; 2236 } 2237 2238 public boolean locateVariableOrParameter(TObjectName cr){ 2239 return locateVariableOrParameter(cr,false); 2240 } 2241 2242 public boolean locateVariableOrParameter(TObjectName cr, boolean checkVariableDeclaredInProcedure){ 2243 boolean ret = false; 2244 if (cr.getDbObjectType() == EDbObjectType.variable) return true; 2245 if (cr.toString().equalsIgnoreCase("*")) return false; 2246 //search variable in framestack 2247 2248 TVariable symbolVariable = null; 2249 2250 if (cr.getTableToken() != null){ 2251 // record_variable.column 2252 symbolVariable = TSymbolTableManager.searchSymbolVariable(this.getFrameStack(),cr.getTableToken().toString()); 2253 if (symbolVariable != null){ 2254 cr.getTableToken().setDbObjectType(EDbObjectType.variable); 2255 //TTable sourceTable = new TTable(new TObjectName(EDbObjectType.table,symbolVariable.getVariableName().getStartToken())); 2256 TTable sourceTable = new TTable(TObjectName.createObjectName (this.dbvendor, EDbObjectType.variable,symbolVariable.getVariableName().getStartToken())); 2257 sourceTable.getLinkedColumns().addObjectName(cr); 2258 cr.setSourceTable(sourceTable); 2259 // symbolVariable.getVariableName().getReferencedObjects().addObjectName(cr); 2260 // System.out.println("find variable:"+cr.toString()); 2261 cr.setResolveStatus(TBaseType.RESOLVED_AND_FOUND); // set resolve status to resolved,避免在 TAttributeResolver 中关联到其他 table 2262 return true; 2263 } 2264 2265 }else{ 2266 // variable 2267 symbolVariable = TSymbolTableManager.searchSymbolVariable(this.getFrameStack(),cr.toString()); 2268 if (symbolVariable != null){ 2269 cr.setDbObjectType(EDbObjectType.variable); 2270 symbolVariable.getVariableName().getReferencedObjects().addObjectName(cr); 2271 return true; 2272 } 2273 } 2274 2275 // check parameters in plsql only, may add support for sql server later. 2276 if(! ((dbvendor == EDbVendor.dbvoracle)||(dbvendor == EDbVendor.dbvmysql))) return false; 2277 if (cr.getObjectType() == TObjectName.ttobjVariable) return true; 2278 2279 Stack symbolTable = this.getTopStatement().getSymbolTable(); 2280 TSymbolTableItem item = null; 2281 TObjectName objName = null; 2282 TObjectName qualifiedName = null; // function/procedure name or label name of plsql block 2283 for (int i = symbolTable.size()-1;i>=0;i--){ 2284 item = (TSymbolTableItem)symbolTable.get(i); 2285 if (item.getData() instanceof TParameterDeclaration){ 2286 objName = ((TParameterDeclaration)item.getData()).getParameterName(); 2287 }else if (item.getData() instanceof TVarDeclStmt){ 2288 objName = ((TVarDeclStmt)item.getData()).getElementName(); 2289 }else if (item.getData() instanceof TObjectName){ 2290 objName = (TObjectName)item.getData(); 2291 } 2292 2293 if (objName == null) continue; 2294 2295 if (cr.toString().compareToIgnoreCase(objName.toString()) == 0){ 2296 ret = true; 2297 if (checkVariableDeclaredInProcedure) break; // return true if variable declared in procedure 2298 for(int j=0;i<tables.size();i++){ 2299 TTable lcTable = tables.getTable(j); 2300 if (lcTable.isBaseTable()){ 2301 if (fireOnMetaDatabaseTableColumn( 2302 lcTable.getPrefixServer() 2303 ,lcTable.getPrefixDatabase() 2304 ,lcTable.getPrefixSchema() 2305 ,lcTable.getName() 2306 ,cr.getColumnNameOnly())){ 2307 ret = false; 2308 break; 2309 } 2310 } 2311 } 2312 2313 if (ret) break; 2314 }else if (cr.toString().indexOf(".")>0){ 2315 // qualified object reference, compare it with procedure/function/block label prefixed 2316 if (item.getStmt() instanceof TPlsqlCreateFunction){ 2317 qualifiedName = ((TPlsqlCreateFunction)item.getStmt()).getFunctionName(); 2318 }else if (item.getStmt() instanceof TPlsqlCreateProcedure){ 2319 qualifiedName = ((TPlsqlCreateProcedure)item.getStmt()).getProcedureName(); 2320 }else if (item.getStmt() instanceof TCommonBlock){ 2321 qualifiedName = ((TCommonBlock)item.getStmt()).getLabelName(); 2322 } 2323 2324 if (qualifiedName != null){ 2325 if (cr.toString().compareToIgnoreCase(qualifiedName.toString()+'.'+objName.toString()) == 0){ 2326 ret = true; 2327 } 2328 } 2329 2330 if (ret ) break; 2331 } 2332 2333 } 2334 if (ret){ 2335 //add this parameter or variable reference to original parameter/variable 2336 objName.getReferencedObjects().addObjectName(cr); 2337 cr.setObjectType(TObjectName.ttobjVariable); 2338 } 2339 return ret; 2340 } 2341 2342 TCTE findCTEByName(String cteName){ 2343 TCTEList lcCteList = searchCTEList(false); 2344 TCTE lcCte = null; 2345 if (lcCteList != null){ 2346 for(int i=0;i<lcCteList.size();i++){ 2347 if (lcCteList.getCTE(i).getTableName().toString().compareToIgnoreCase(cteName)==0){ 2348 lcCte = lcCteList.getCTE(i); 2349 break; 2350 } 2351 } 2352 } 2353 return lcCte; 2354 } 2355 2356 /** 2357 * @deprecated since 2.3.8.2, use {@link TTable#getExpandedStarColumns()} instead. 2358 * 2359 * @param lcTable 2360 * @return 2361 */ 2362 public ArrayList<String> getColumnsInTable(TTable lcTable){ 2363 if (lcTable.isCTEName()){ 2364 ArrayList<String> columns = new ArrayList<>(); 2365 if (lcTable.getCteColomnReferences()!=null){ 2366 for(TObjectName n:lcTable.getCteColomnReferences()){ 2367 columns.add(n.toString()); 2368 } 2369 }else if (lcTable.getCTE().getSubquery() != null && lcTable.getCTE().getSubquery().getResultColumnList() != null){ 2370 for(TResultColumn resultColumn:lcTable.getCTE().getSubquery().getResultColumnList()){ 2371 columns.add(resultColumn.getDisplayName()); 2372 } 2373 } 2374 return columns; 2375 }else{ 2376 return getColumnsInTable( 2377 lcTable.getPrefixServer() 2378 ,lcTable.getPrefixDatabase() 2379 ,lcTable.getPrefixSchema() 2380 ,lcTable.getName() 2381 ); 2382 } 2383 } 2384 2385 2386 /** 2387 * @deprecated since 2.3.8.2, use {@link TTable#getExpandedStarColumns()} instead. 2388 * 2389 * @param pServer 2390 * @param pDatabase 2391 * @param pSchema 2392 * @param pTable 2393 * @return 2394 */ 2395 public ArrayList<String> getColumnsInTable(String pServer,String pDatabase,String pSchema,String pTable){ 2396 TFrame stackFrame = getFrameStack().firstElement(); 2397 TGlobalScope globalScope = (TGlobalScope)stackFrame.getScope(); 2398 2399 if (globalScope.getSqlEnv() != null){ 2400 return globalScope.getSqlEnv().getColumnsInTable(pDatabase+"."+pSchema+"."+pTable,false); 2401 }else{ 2402 return null; 2403 } 2404 } 2405 2406 2407 public boolean fireOnMetaDatabaseTableColumn(String pServer,String pDatabase,String pSchema,String pTable,String pColumn){ 2408// boolean lcResult = false; 2409// if (this.getGsqlparser().getMetaDatabase() != null){ 2410// lcResult = this.getGsqlparser().getMetaDatabase().checkColumn(pServer,pDatabase,pSchema,pTable,pColumn); 2411// } 2412 2413 TFrame stackFrame = getFrameStack().firstElement(); 2414 TGlobalScope globalScope = (TGlobalScope)stackFrame.getScope(); 2415 2416 if (globalScope.getSqlEnv() != null){ 2417 // System.out.println(globalScope.getSqlEnv().toString()); 2418 2419 return globalScope.getSqlEnv().columnInTable(pDatabase+"."+pSchema+"."+pTable,pColumn); 2420 }else{ 2421 return false; 2422 } 2423 2424// return lcResult; 2425 } 2426 2427 public TTable getFirstPhysicalTable(){ 2428 TTable ret = null; 2429 if (tables.size() == 0) return null; 2430 for(int i=0;i<tables.size();i++){ 2431 if (tables.getTable(i).isBaseTable()) { 2432 ret = tables.getTable(i); 2433 break; 2434 } 2435 } 2436 return ret; 2437 } 2438 private TObjectNameList orphanColumns = null; 2439 2440 public TObjectNameList getOrphanColumns() { 2441 if (orphanColumns == null) orphanColumns = new TObjectNameList(); 2442 return orphanColumns; 2443 } 2444 2445 protected boolean linkToFirstTable(TObjectName pColumn,int pCandidateTableCnt){ 2446 boolean lcResult = false; 2447 if ((dbvendor == EDbVendor.dbvteradata)&&(pColumn.isQualified())&&(pColumn.getTableToken().getDbObjectType() != EDbObjectType.subquery_alias)){ 2448 // update table1 set col = 'value' where table1.id = table2.id2 2449 boolean isFoundLinkedTable = false; 2450 TCustomSqlStatement lcSql = this; 2451 while (lcSql != null){ 2452 int i = 0; 2453 i = lcSql.tables.searchTableByNameOrAlias(pColumn.getTableToken().toString()); 2454 isFoundLinkedTable = ( i != -1); 2455 if (isFoundLinkedTable) { 2456 if (lcSql.tables.getTable(i).getEffectType() == ETableEffectType.tetImplicitLateralDerivedTable ){ 2457 // 如果不查重table,会导致 employee.first_name 中的 employee 被第二次加到 tables 中 2458// DELETE FROM foodmart.trimmed_employee ACT 2459// WHERE ACT.employee_id = employee.employee_id 2460// AND employee.first_name = 'Walter' 2461// AND trimmed_salary.employee_id = -1 2462 2463 TTable newTable = lcSql.tables.getTable(i); 2464 newTable.getLinkedColumns().addObjectName(pColumn); 2465 pColumn.setSourceTable(newTable); 2466 pColumn.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_TABLE_IN_OLD_ALGORITHM); 2467 } 2468 break; 2469 } 2470 lcSql = lcSql.getParentStmt(); 2471 } 2472 if (!isFoundLinkedTable){ 2473 TTable newTable = null; 2474 if (pColumn.getDatabaseToken() == null){ 2475 2476 //newTable = new TTable(new TObjectName(EDbObjectType.table,pColumn.getTableToken())); 2477 newTable = new TTable(TObjectName.createObjectName (this.dbvendor, EDbObjectType.table,pColumn.getTableToken())); 2478 newTable.setStartToken(pColumn.getTableToken()); 2479 newTable.setEndToken(pColumn.getTableToken()); 2480 }else{ 2481 2482 //newTable = new TTable(new TObjectName(EDbObjectType.table,pColumn.getSchemaToken(), pColumn.getTableToken())); 2483 newTable = new TTable(TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,pColumn.getDatabaseToken(), pColumn.getTableToken())); 2484 newTable.setStartToken(pColumn.getSchemaToken()); 2485 newTable.setEndToken(pColumn.getTableToken()); 2486 } 2487 2488 newTable.setTableType(ETableSource.objectname); 2489 newTable.setEffectType(ETableEffectType.tetImplicitLateralDerivedTable); 2490 newTable.getLinkedColumns().addObjectName(pColumn); 2491 pColumn.setSourceTable(newTable); 2492 pColumn.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_TABLE_IN_OLD_ALGORITHM); 2493 this.addToTables(newTable); 2494 2495 // 2024 年 2496 // 不能加入到 relations 中,否则会导致 下面 SQL 中 star column 同时链接到 SPCOMM.L_FIXED_RATE_PLAN_REF, ipshare_ofccplv.cprof_d_period_dates_ref 2497 // 从而导致 本来不该有的歧义产生 2498 2499 // UPDATE b_rate_plan 2500 //FROM 2501 //( 2502 //SELECT * FROM SPCOMM.L_FIXED_RATE_PLAN_REF 2503 //WHERE rate_plan_ref_eff_dt<= ipshare_ofccplv.cprof_d_period_dates_ref.PERIOD 2504 //) AS ref 2505 //SET accs_fee = REF.accs_fee, 2506 //SVC_TYPE = REF.prod_grp_lvl_1, 2507 //rate_plan_lvl3 = REF.rate_plan_lvl_3, 2508 //prod_grp_lvl3 = REF.prod_grp_lvl_2 2509 //WHERE b_rate_plan.svc_type IS NULL 2510 2511 // 2025/2/25, v3.0.4.8 2512 // 需要加入到 relations 中,新的 gudusoft.gsqlparser.resolver package 中的算法会处理这种情况 2513 // teradata 的隐式横向派生表不能加入到关系解析器中 2514 // this.getRelations().add(newTable); 2515 } 2516 return true; 2517 } 2518 if (pColumn.getCandidateTables().size() == 1){ 2519 TTable table = pColumn.getCandidateTables().getTable(0); 2520 table.getLinkedColumns().addObjectName(pColumn); 2521 pColumn.setSourceTable(table); 2522 lcResult = true; 2523 } 2524 else if ((tables.size() == 1) || (pCandidateTableCnt == 1)){ 2525 TTable table = tables.getTable(0); 2526 2527 if(table.getTableType() == ETableSource.function){ 2528 //lcResult = linkToFunctionTable(table, pColumn); 2529 int iRet = table.getFuncCall().isColumnInThisTableFunction(this.getSqlEnv(),this.dbvendor,pColumn); 2530 if ( iRet == TBaseType.COLUMN_IN_TABEL_FUNCTION_YES){ 2531 lcResult = true; 2532 table.getLinkedColumns().addObjectName(pColumn); 2533 pColumn.setSourceTable(table); 2534 lcResult = true; 2535 }else if ( iRet == TBaseType.COLUMN_IN_TABEL_FUNCTION_NO){ 2536 lcResult = false; 2537 }else{ 2538 table.getLinkedColumns().addObjectName(pColumn); 2539 pColumn.setSourceTable(table); 2540 lcResult = true; 2541 } 2542 }else if(table.getTableType() == ETableSource.subquery){ 2543 if (! table.getSubquery().searchColumnInResultSet(pColumn,(tables.size()==1))){ 2544 getOrphanColumns().addObjectName(pColumn); 2545 pColumn.setOrphanColumn(true); 2546 pColumn.setOwnStmt(this); 2547 TSourceToken st = pColumn.getStartToken(); 2548 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 2549 TBaseType.log(String.format("Add orphan column <%s> to statement in old algorithm in subquery %s",pColumn.toString(),table.getAliasName()),TLog.WARNING,table); 2550 } 2551 this.parseerrormessagehandle(new TSyntaxError(st.getAstext(), st.lineNo, st.columnNo 2552 ,"find orphan column", EErrorType.sphint 2553 , TBaseType.MSG_HINT_FIND_ORPHAN_COLUMN,this,st.posinlist,pColumn)); 2554 } 2555 } 2556 else{ 2557 table.getLinkedColumns().addObjectName(pColumn); 2558 pColumn.setSourceTable(table); 2559 lcResult = true; 2560 if ((dbvendor == EDbVendor.dbvbigquery)&&(pCandidateTableCnt == 0) && (pColumn.isQualified())){ 2561 // bigquery struct column used in query 2562// create view test as (SELECT rollNo, 2563// info.name as n1, 2564// info2.name as n2, 2565// info.age from my_first_dataset.student_records); 2566 2567 pColumn.columnToProperty(); 2568 } 2569 } 2570 }else if (tables.size() > 1){ 2571 // if there is only a table without table alias, then, link to this table 2572 boolean foundOnlyOneTable = false; 2573 TTable tableWithoutAlias = null; 2574 for(TTable table:tables){ 2575 if (table.isCTEName()) continue; // CTE 即便没有 指定alias,也不作为考虑对象 2576 if (table.getAliasClause() == null){ 2577 tableWithoutAlias = table; 2578 if (foundOnlyOneTable){ 2579 foundOnlyOneTable = false; 2580 break; 2581 }else{ 2582 foundOnlyOneTable = true; 2583 } 2584 } 2585 } 2586 2587 if (foundOnlyOneTable){ 2588 tableWithoutAlias.getLinkedColumns().addObjectName(pColumn); 2589 pColumn.setSourceTable(tableWithoutAlias); 2590 lcResult = true; 2591 }else{ 2592 getOrphanColumns().addObjectName(pColumn); 2593 pColumn.setOrphanColumn(true); 2594 pColumn.setOwnStmt(this); 2595 TSourceToken st = pColumn.getStartToken(); 2596 if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){ 2597 TBaseType.log(String.format("Add orphan column <%s> to statement in old algorithm ",pColumn.toString()),TLog.WARNING,this); 2598 } 2599 2600 this.parseerrormessagehandle(new TSyntaxError(st.getAstext(), st.lineNo, st.columnNo 2601 ,"find orphan column", EErrorType.sphint 2602 , TBaseType.MSG_HINT_FIND_ORPHAN_COLUMN,this,st.posinlist,pColumn)); 2603 } 2604 2605 } 2606 return lcResult; 2607 } 2608 2609 private boolean linkToFunctionTable(TTable table, TObjectName pColumn) { 2610 if(table.getTableName().toString().toUpperCase().equals("STRING_SPLIT")){ 2611 if(pColumn.getColumnNameOnly().toUpperCase().equals("VALUE")){ 2612 table.getLinkedColumns().addObjectName(pColumn); 2613 pColumn.setSourceTable(table); 2614 return true; 2615 } 2616 else return false; 2617 } 2618 else { 2619 table.getLinkedColumns().addObjectName(pColumn); 2620 pColumn.setSourceTable(table); 2621 return true; 2622 } 2623 } 2624 2625 2626 private TTable findInsertedOrDeleteTable(TTable table) { 2627 if (table == null) return null; 2628 2629 // Check if this table is 'inserted' by examining both name and toString() 2630 // The inserted table might have different representations 2631 String tableName = table.getName(); 2632 String tableString = table.toString(); 2633 2634 if ("inserted".equalsIgnoreCase(tableName) || 2635 "inserted".equalsIgnoreCase(tableString) || 2636 "deleted".equalsIgnoreCase(tableName) || 2637 "deleted".equalsIgnoreCase(tableString)) { 2638 return table; 2639 } 2640 2641 // If this is a join table, recursively check its components 2642 if (table.getTableType() == ETableSource.join && table.getJoinExpr() != null) { 2643 TJoinExpr joinExpr = table.getJoinExpr(); 2644 2645 // Check left side recursively 2646 TTable leftResult = findInsertedOrDeleteTable(joinExpr.getLeftTable()); 2647 if (leftResult != null) { 2648 return leftResult; 2649 } 2650 2651 // Check right side recursively 2652 TTable rightResult = findInsertedOrDeleteTable(joinExpr.getRightTable()); 2653 if (rightResult != null) { 2654 return rightResult; 2655 } 2656 } 2657 2658 return null; 2659 } 2660 2661 2662 boolean isSQLServerInsertedDelete(TObjectName pColumn){ 2663 if (dbvendor != EDbVendor.dbvmssql) return false; 2664 2665 // only process sql server inserted delete column, if not then return false 2666 // if (!((pColumn.toString().toUpperCase().startsWith("INSERTED"))||(pColumn.toString().toUpperCase().startsWith("DELETED")))) return false; 2667 if (!((pColumn.getStartToken().tokencode == TBaseType.rrw_sqlserver_INSERTED ) 2668 ||(pColumn.getStartToken().tokencode == TBaseType.rrw_sqlserver_DELETED ))) return false; 2669 2670 // 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 2671 // to find the target table in the literal as 'inserted' or 'deleted'. 2672 2673 TTable lcTargetTable = null; 2674 for(TTable table : this.getRelations()){ 2675 lcTargetTable = findInsertedOrDeleteTable(table); 2676 if (lcTargetTable != null){ 2677 break; 2678 } 2679 } 2680 2681 if (lcTargetTable == null) return false; 2682 2683 2684 if (lcTargetTable.getLinkTable() != null){ 2685 lcTargetTable.getLinkTable().getLinkedColumns().addObjectName(pColumn); 2686 pColumn.setSourceTable(lcTargetTable.getLinkTable()); 2687 2688 pColumn.setResolveStatus(TBaseType.RESOLVED_AND_FOUND); // 避免在 // TAttributeResolver 中再次进行处理,关联到其他 table 2689 2690 }else{ 2691 lcTargetTable.getLinkedColumns().addObjectName(pColumn); 2692 pColumn.setSourceTable(lcTargetTable); 2693 pColumn.setResolveStatus(TBaseType.RESOLVED_AND_FOUND); // 避免在 // TAttributeResolver 中再次进行处理,关联到其他 table 2694 } 2695 return true; 2696 2697 } 2698 2699 boolean isOracleNewOldTable(TObjectName pColumn){ 2700 boolean ret = false; 2701 if (dbvendor != EDbVendor.dbvoracle) return false; 2702 if (!(pColumn.isQualified())) return false; 2703 if ((pColumn.getTableString().equalsIgnoreCase(":new")) 2704 ||(pColumn.getTableString().equalsIgnoreCase(":old"))){ 2705 if (getAncestorStmt().tables != null){ 2706 if (getAncestorStmt().tables.size() > 0){ 2707 getAncestorStmt().tables.getTable(0).getLinkedColumns().addObjectName(pColumn); 2708 pColumn.setSourceTable(getAncestorStmt().tables.getTable(0)); 2709 ret = true; 2710 } 2711 } 2712 } 2713 2714 return ret; 2715 } 2716 2717 public boolean searchDaxVariableInStack(TObjectName pName){ 2718 boolean ret = false; 2719 if (getVariableStack().size() == 0) return false; 2720 if (pName.getDbObjectType() == EDbObjectType.column) return false; 2721 for(int i=0;i<variableStack.size();i++){ 2722 if (pName.toString().equalsIgnoreCase(((TObjectName) variableStack.get(i)).toString())){ 2723 ret = true; 2724 break; 2725 } 2726 } 2727 return ret; 2728 } 2729 2730 boolean linkColumnToTableDax(TObjectName pColumn, ESqlClause pLocation){ 2731 boolean lcResult = true ; 2732 TDaxFunction daxFunction = null; 2733 if (searchDaxVariableInStack(pColumn)) return false; 2734 if (getDaxFunctionStack().size() > 0){ 2735 daxFunction = daxFunctionStack.peek(); 2736 } 2737 2738 if (pColumn.getTableToken() != null){ 2739 //TTable sourceTable = new TTable(new TObjectName(EDbObjectType.table,pColumn.getTableToken())); 2740 TTable sourceTable = new TTable(TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,pColumn.getTableToken())); 2741 sourceTable.getLinkedColumns().addObjectName(pColumn); 2742 addToTables(sourceTable); 2743 if ((daxFunction != null) && (daxFunction.getDefaultTable() == null)){ 2744 daxFunction.setDefaultTable(sourceTable); 2745 } 2746 }else{ 2747 if ((daxFunction != null) &&(daxFunction.getDefaultTable() != null)){ 2748 daxFunction.getDefaultTable().getLinkedColumns().addObjectName(pColumn); 2749 }else{ 2750 ((TDaxStmt)this).getDefaultTable().getLinkedColumns().addObjectName(pColumn); 2751 } 2752 } 2753 return lcResult; 2754 } 2755 2756 /** 2757 * 将列引用解析并绑定到其来源(表、子查询、CTE、表函数、OPENQUERY/UNNEST 等)。 2758 * 2759 * 功能概述: 2760 * 1) 针对 DAX 语法直接走 DAX 分支。 2761 * 2) 已绑定或标记“延迟到列解析器”的列直接返回。 2762 * 3) 设定列所在语法位置,并校验列名/保留字(含 MySQL true/false/default、内置函数等)。 2763 * 4) 处理厂商伪表/特殊前缀(Oracle :new/:old;SQL Server INSERTED/DELETED)。 2764 * 5) Insert All/VALUES 场景:优先在子查询结果集中/变量或过程参数中匹配。 2765 * 6) 在当前语句的 FROM 表集合中查找并建立绑定: 2766 * - 限定列 table.col:按别名/表名匹配;对子查询/CTE/OPENQUERY 进一步在结果集中定位源列; 2767 * 命中后写入 linkedColumns,必要时将 TableToken 标记为 subquery_alias。 2768 * - 非限定列 col: 2769 * a. 先尝试同层 SELECT 列别名(支持 LATERAL 语义且位置在别名之后); 2770 * b. 处理通配符“*”:收集所有来源表; 2771 * c. 基础表通过元数据回调 fireOnMetaDatabaseTableColumn 校验;未命中则记录候选; 2772 * d. 子查询/CTE/函数/UNNEST/PIVOT 分别按各自规则匹配。 2773 * 7) 命中后将列加入表的 linkedColumns 并设置 sourceTable/sourceColumn,必要时维持 isContinue 以继续匹配“*”。 2774 * 8) 若未命中:尝试变量/参数;再按条件(语句类型/位置/是否限定等)向上一层语句递归查找(维护 searchLevel)。 2775 * 9) 仍未命中:在顶层(searchLevel==0)按“候选唯一/或首表”兜底策略 {@link #linkToFirstTable(TObjectName, int)}。 2776 * 2777 * 参数: 2778 * @param pColumn 需要绑定的列名对象(方法会更新其 location、sourceTable、sourceColumn 等) 2779 * @param pLocation 列出现的语法位置(如 selectList、where、insertValues 等) 2780 * 2781 * 返回值: 2782 * @return 成功绑定到某个来源返回 true;未能绑定或被识别为变量/保留字等返回 false 2783 * 2784 * 厂商兼容: 2785 * - Oracle: 处理 :new/:old,Insert All 的 values 子句源自子查询的匹配 2786 * - SQL Server: 处理 INSERTED/DELETED 伪表 2787 * - MySQL: 对保留字/布尔字面量/内置函数名的特殊判断 2788 * - DAX: 委托 {@link #linkColumnToTableDax(TObjectName, ESqlClause)} 2789 * 2790 * 副作用: 2791 * - 更新 pColumn 的 location/searchLevel/sourceTable/sourceColumn/validate 状态 2792 * - 向命中的表写入 linkedColumns 或向别名列写入 targetColumns 2793 * - 对“*”列填充 sourceTableList;对子查询命中时可能将 TableToken 标为 subquery_alias 2794 * - 记录候选表数量并填充 pColumn.candidateTables,用于后续兜底 2795 * 2796 * 复杂度与顺序: 2797 * - 优先使用同层信息(别名/元数据/子查询结果),再逐层向外查找;避免无谓的上层搜索 2798 * 2799 * 注意: 2800 * - 本方法完成“旧算法”的快速联接,新的解析/消歧逻辑在解析器(如 TStmtScope/TAttributeResolver)中继续处理 2801 */ 2802 public boolean linkColumnToTable(TObjectName pColumn, ESqlClause pLocation){ 2803 boolean lcResult = false,isContinue = false; 2804 int candidateTableCnt = 0; 2805 if (pColumn == null) return false; 2806 if (dbvendor == EDbVendor.dbvdax){ 2807 return linkColumnToTableDax(pColumn,pLocation); 2808 } 2809 2810 // Skip alias definition columns - they define column names in alias clauses, not column references 2811 // Example: In "AS x (numbers, animals)", numbers and animals are column_alias type 2812 if (pColumn.getDbObjectType() == EDbObjectType.column_alias) { 2813 return true; 2814 } 2815 2816 if (pColumn.getSourceTable() != null) { 2817 lcResult = true; 2818 return lcResult; 2819 } 2820 2821 if (pColumn.getResolveStatus() == TBaseType.RESOLVE_DELAY_TO_COLUMN_RESOLVER) return true; 2822 2823 pColumn.setLocation(pLocation); 2824 2825 if (! pColumn.isValidColumnName(dbvendor)) { 2826 if (pColumn.isReservedKeyword()){ 2827 if ( 2828 ((pColumn.getStartToken().tokencode != TBaseType.rrw_mysql_true)&&(!(pColumn.getStartToken().toString().equalsIgnoreCase("true")))) 2829 &&((pColumn.getStartToken().tokencode != TBaseType.rrw_mysql_false)&&(!(pColumn.getStartToken().toString().equalsIgnoreCase("false")))) 2830 &&(pColumn.getStartToken().tokencode != TBaseType.rrw_mysql_default) 2831 ) { 2832 boolean mysqlBuiltFunction = false; 2833 if (dbvendor == EDbVendor.dbvmysql){ 2834 mysqlBuiltFunction = functionChecker.isBuiltInFunction(pColumn.toString(),EDbVendor.dbvmysql,"6.0"); 2835 } 2836 if (!mysqlBuiltFunction){ 2837 TSourceToken st1 = pColumn.getStartToken(); 2838 TSyntaxError err = new TSyntaxError(st1.toString() 2839 , st1.lineNo, st1.columnNo 2840 , String.format("Reserved keyword can't be column name") 2841 , EErrorType.sperror 2842 , TBaseType.MSG_ERROR_RESERVED_KEYWORD_CANT_USED_AS_COLUMN_NAME 2843 ,this,st1.posinlist); 2844 this.parseerrormessagehandle(err); 2845 } 2846 } 2847 } 2848 return false; 2849 } 2850 2851 if (isOracleNewOldTable(pColumn)) return true; 2852 if (isSQLServerInsertedDelete(pColumn)) return true; 2853 2854 // oracle insert all statement, 2855 // WHEN id <= 3 THEN INTO dest_tab1 VALUES(id, description1) 2856 // column in values clause must be in the subquery of insert all statement 2857 if (pColumn.getLocation() == ESqlClause.insertValues){ 2858 if (this instanceof TInsertSqlStatement){ 2859 TInsertSqlStatement insertSqlStatement = (TInsertSqlStatement)this; 2860 if (insertSqlStatement.isInsertAll()){ 2861 // if (pColumn.getStartToken().tokencode == TBaseType.rrw_snowflake_default) return true; 2862 lcResult = insertSqlStatement.getSubQuery().searchColumnInResultSet(pColumn, true); 2863 } 2864 } 2865 2866 if (lcResult) return true; 2867 2868 // value in values clause maybe parameter of the procedure/function parameter 2869 lcResult = locateVariableOrParameter(pColumn,true); 2870 if (lcResult) return true; 2871 } 2872 2873 boolean foundInMetaData = false; 2874 2875 for(int i=0;i<tables.size();i++){ 2876 TTable lcTable = tables.getTable(i); 2877 if (lcTable.getEffectType() == ETableEffectType.tetSelectInto) continue; 2878 if (lcTable.getEffectType() == ETableEffectType.tetImplicitLateralDerivedTable) continue; 2879 2880 if (pColumn.isQualified()){ 2881 lcResult = pColumn.resolveWithThisTable(lcTable); 2882 if ((lcResult) && (lcTable.getTableType() == ETableSource.subquery)){ 2883 pColumn.getTableToken().setDbObjectType(EDbObjectType.subquery_alias); 2884 2885 int lcPos = lcTable.searchColumnInAlias(pColumn); 2886 lcResult = lcPos>=0; 2887 if (lcResult){ 2888 // 在 alias 中找到 source column, 还需要对应到 subquery select 中的 select list 2889 // sql 见 https://e.gitee.com/gudusoft/projects/151613/tasks/list?issue=I8JR0W#note_23051633 2890 if ((lcTable.getSubquery() != null)&&(lcTable.getSubquery().getResultColumnList() != null)){ 2891 pColumn.setSourceColumn(lcTable.getSubquery().getResultColumnList().getResultColumn(lcPos)); 2892 } 2893 }else{ 2894 lcResult = lcTable.getSubquery().searchColumnInResultSet(pColumn,true); 2895 } 2896 // lcTable.getSubquery().searchColumnInResultSet(pColumn,true); 2897 2898 }else if ((lcResult) && (lcTable.isCTEName())){ 2899 lcTable.getCTE().searchColumnInResultSet(this,lcTable,pColumn,true); 2900 }else if ((lcResult) && (lcTable.getTableType() == ETableSource.openquery)&&(lcTable.getSubquery() != null)){ 2901 pColumn.getTableToken().setDbObjectType(EDbObjectType.subquery_alias); 2902 lcTable.getSubquery().searchColumnInResultSet(pColumn,true); 2903// }else if ((lcResult) && (lcTable.getTableType() == ETableSource.unnest)&&(lcTable.getUnnestClause() != null)){ 2904// pColumn.getTableToken().setDbObjectType(EDbObjectType.subquery_alias); 2905// lcTable.getSubquery().searchColumnInResultSet(pColumn,true); 2906 } 2907 if (lcResult&&pColumn.toString().endsWith("*")){ 2908 pColumn.getSourceTableList().add(lcTable); 2909// ArrayList<String> lcColumns = getColumnsInTable(lcTable); 2910// if (lcColumns != null){ 2911// pColumn.getColumnsLinkedToStarColumn().addAll(lcColumns); 2912// } 2913 } 2914 }else { 2915 // column not qualified 2916 2917 // check if this is the column alias in current select list. 2918 if((!lcResult)&& ((!pColumn.isQualified()) && (this instanceof TSelectSqlStatement)&&(getResultColumnList() !=null)) 2919 && (TBaseType.isSupportLateralColumn(dbvendor)) 2920 ){ 2921 for(int j=0;j<getResultColumnList().size();j++){ 2922 TResultColumn lcField = getResultColumnList().getResultColumn(j); 2923 lcResult = lcField.isMatchedUsingAlias(pColumn); 2924 if ( 2925 (!TSQLEnv.isAliasReferenceForbidden.get(this.dbvendor))&& 2926 ((lcResult)&&(pColumn.getStartToken().posinlist > lcField.getAliasClause().getStartToken().posinlist))){ 2927 pColumn.setSourceColumn(lcField); 2928 lcField.getTargetColumns().addObjectName(pColumn); 2929 pColumn.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_COLUMN_ALIAS_IN_OLD_ALGORITHM); 2930 break; 2931 }else{ 2932 lcResult = false; 2933 } 2934 } 2935 2936 if (lcResult) return true; 2937 } 2938 2939 if (pColumn.getColumnNameOnly().equalsIgnoreCase("*")){ 2940 lcResult = true; 2941 isContinue = true; // in order to match next table in the from clause 2942 pColumn.getSourceTableList().add(lcTable); 2943// ArrayList<String> lcColumns = getColumnsInTable(lcTable); 2944// if (lcColumns != null){ 2945// pColumn.getColumnsLinkedToStarColumn().addAll(lcColumns); 2946// } 2947 }else if (lcTable.isBaseTable()){ 2948 lcResult = fireOnMetaDatabaseTableColumn( 2949 lcTable.getPrefixServer() 2950 ,lcTable.getPrefixDatabase() 2951 ,lcTable.getPrefixSchema() 2952 ,lcTable.getName() 2953 ,pColumn.getColumnNameOnly()); 2954 if (! lcResult) { 2955 candidateTableCnt++; 2956 pColumn.getCandidateTables().addTable(lcTable); 2957 }else{ 2958 foundInMetaData = true; 2959 isContinue = false; 2960 } 2961 2962 }else if ((lcTable.getTableType() == ETableSource.subquery) 2963 ||((lcTable.getTableType() == ETableSource.openquery)&&(lcTable.getSubquery() != null))){ 2964 2965 lcResult = lcTable.searchColumnInAlias(pColumn)>=0; 2966 if (!lcResult){ 2967 lcResult = lcTable.getSubquery().searchColumnInResultSet(pColumn,(tables.size() == 1) 2968 &&(pColumn.getCandidateTables().size() == 0)); 2969 if (! lcResult) { 2970 candidateTableCnt++; 2971 pColumn.getCandidateTables().addTable(lcTable); 2972 } 2973 } 2974 2975 2976// if (lcTable.isIncludeColumnAlias()){ 2977// // System.out.println("subquery with alias:"+lcTable.getAliasClause().toString()+", skip search:"+pColumn.toString()); 2978// 2979// }else{ 2980// lcResult = lcTable.getSubquery().searchColumnInResultSet(pColumn,(tables.size() == 1)&&(pColumn.getCandidateTables().size() == 0)); 2981// if (! lcResult) candidateTableCnt++; 2982// } 2983 }else if (lcTable.isCTEName()){ 2984 lcResult = lcTable.getCTE().searchColumnInResultSet(this,lcTable,pColumn,tables.size() == 1); 2985 if (! lcResult) { 2986 candidateTableCnt++; 2987 pColumn.getCandidateTables().addTable(lcTable); 2988 } 2989 }else if (lcTable.getTableType() == ETableSource.function){ 2990 // search in this table function 2991 if(tables.size() == 1){ 2992 lcResult = ( lcTable.getFuncCall().isColumnInThisTableFunction(this.getSqlEnv(),this.dbvendor,pColumn) 2993 != TBaseType.COLUMN_IN_TABEL_FUNCTION_NO); 2994 } 2995 else{ 2996 lcResult = ( lcTable.getFuncCall().isColumnInThisTableFunction(this.getSqlEnv(),this.dbvendor,pColumn) 2997 == TBaseType.COLUMN_IN_TABEL_FUNCTION_YES); 2998 } 2999 }else if (lcTable.getTableType() == ETableSource.tableExpr 3000 && lcTable.getTableExpr().getExpressionType() == EExpressionType.function_t 3001 && lcTable.getTableExpr().getFunctionCall() != null){ 3002 // search in this table function 3003 lcResult = ( lcTable.getTableExpr().getFunctionCall().isColumnInThisTableFunction(this.getSqlEnv(),this.dbvendor,pColumn) 3004 == TBaseType.COLUMN_IN_TABEL_FUNCTION_YES); 3005 }else if (lcTable.getTableType() == ETableSource.pivoted_table){ 3006 lcResult = fireOnMetaDatabaseTableColumn( 3007 lcTable.getPrefixServer() 3008 ,lcTable.getPrefixDatabase() 3009 ,lcTable.getPrefixSchema() 3010 ,lcTable.getName() 3011 ,pColumn.getColumnNameOnly()); 3012 if (lcResult){ 3013 foundInMetaData = true; 3014 isContinue = false; 3015 } 3016 }else if (lcTable.getTableType() == ETableSource.unnest){ 3017 for(TObjectName objectName:lcTable.getLinkedColumns()){ 3018 if (objectName.toString().equalsIgnoreCase(pColumn.toString())){ 3019 lcResult = true; 3020 break; 3021 } 3022 } 3023 3024 if (!lcResult){ 3025 if (lcTable.getAliasClause() == null){ 3026 // this unnest() clause generate column with default name: "value" 3027 if (pColumn.toString().equalsIgnoreCase("value")){ 3028 lcResult = true; 3029 } 3030 }else{ 3031 } 3032 } 3033 }//unnest 3034 } 3035 3036 if (lcResult) { 3037 lcTable.getLinkedColumns().addObjectName(pColumn); 3038 pColumn.setSourceTable(lcTable); 3039 // pColumn.setValidate_column_status(TBaseType.COLUMN_LINKED_TO_TABLE_IN_OLD_ALGORITHM); 3040 if (!isContinue) break; 3041 } 3042 } 3043 3044 if ((lcResult) && (foundInMetaData)) return true; 3045 3046 // check variable after metadata checking 3047 if (locateVariableOrParameter(pColumn)) return false; 3048 3049 // check if this is the column alias in current select list. 3050// if((!lcResult)&& ((!pColumn.isPrefixed()) && (this instanceof TSelectSqlStatement)&&(getResultColumnList() !=null))){ 3051// for(int j=0;j<getResultColumnList().size();j++){ 3052// TResultColumn lcField = getResultColumnList().getResultColumn(j); 3053// lcResult = lcField.isMatchedUsingAlias(pColumn); 3054// if ((lcResult)&&(pColumn.getStartToken().posinlist > lcField.getAliasClause().getStartToken().posinlist)){ 3055// pColumn.setSourceColumn(lcField); 3056// lcField.getTargetColumns().addObjectName(pColumn); 3057// break; 3058// }else{ 3059// lcResult = false; 3060// } 3061// } 3062// } 3063 3064 if (lcResult) return true; 3065 3066 boolean isSearchUpLevel = (this.parentStmt != null); 3067 3068 if ((isSearchUpLevel) && (sqlstatementtype == ESqlStatementType.sstselect)){ 3069 isSearchUpLevel = (pColumn.isQualified() 3070 || ( 3071// (((TSelectSqlStatement)(this)).getLocation() != ESqlClause.elTable) && 3072 (! ((TSelectSqlStatement)(this)).isQueryOfCTE()) 3073 ) 3074 ) 3075 && (parentStmt.sqlstatementtype != ESqlStatementType.sstinsert) 3076 && (!((pColumn.getLocation() == ESqlClause.selectList)&&(((TSelectSqlStatement)(this)).getLocation() == ESqlClause.join))) 3077 && ((((TSelectSqlStatement)(this)).getLocation() != ESqlClause.pivot_in)) 3078 && (!((parentStmt.sqlstatementtype == ESqlStatementType.sstcreatetable))) 3079 && (!((parentStmt.sqlstatementtype == ESqlStatementType.sstcreateview))) 3080// && (!((pColumn.getLocation() == ESqlClause.selectList)&&(parentStmt.sqlstatementtype == ESqlStatementType.sstcreatetable))) 3081// && (!((pColumn.getLocation() == ESqlClause.selectList)&&(parentStmt.sqlstatementtype == ESqlStatementType.sstcreateview))) 3082 && (! ((pColumn.getLocation() == ESqlClause.selectList) 3083 &&(candidateTableCnt == 1) && (this instanceof TSelectSqlStatement) 3084 && (((TSelectSqlStatement)(this)).getLocation() == ESqlClause.elTable) 3085 ) ) // ref:mantis: #2628 3086 // && ( ((TSelectSqlStatement)(this.parentStmt)).getSetOperatorType() == ESetOperatorType.none) 3087 ; 3088 3089 if (isSearchUpLevel){ 3090 isSearchUpLevel = !((!pColumn.isQualified())&&(((TSelectSqlStatement) this).getLocation() == ESqlClause.where)); 3091 } 3092 } 3093 3094 if (isSearchUpLevel&&(pColumn.isContinueToSearch())){ // only search one level up, c:\prg\gsp_sqlfiles\TestCases\java\oracle\dbobject\berger_sqltest_04.sql 3095 boolean increaseLevel = true; 3096 if (parentStmt instanceof TSelectSqlStatement){ 3097 if( ((TSelectSqlStatement)parentStmt).getSetOperatorType() != ESetOperatorType.none){ 3098 increaseLevel = false; 3099 } 3100 } 3101 if (increaseLevel){ 3102 pColumn.searchLevel++; 3103 } 3104 3105 lcResult = parentStmt.linkColumnToTable(pColumn,pLocation); 3106 3107 if (increaseLevel){ 3108 pColumn.searchLevel--; 3109 } 3110 } 3111 3112 if ((! lcResult) && (pColumn.searchLevel == 0)) { 3113 if (this.sqlstatementtype == ESqlStatementType.sstselect){ 3114 if( ((TSelectSqlStatement)this).getSetOperatorType() == ESetOperatorType.none){ 3115 // USING _spVV0 (INTEGER) 3116 // INSERT INTO table3 3117 // SELECT :_spVV0,x. *,m.col3 3118 // from (( select table1.col1, (table1.col1 + table5.col2) c from table1 3119 // union all select col3,col4 from table2) x 3120 // cross join (select id from table2) m ) 3121 3122 // table5 in the above sql only link to the nearest level sql, but not to up-level which is union all 3123 3124 linkToFirstTable(pColumn,candidateTableCnt); 3125 } 3126 }else{ 3127 linkToFirstTable(pColumn,candidateTableCnt); 3128 } 3129 } 3130 3131 return lcResult; 3132 } 3133 3134 3135 /** 3136 * 3137 * @deprecated As of v1.6.0.1, use {@link #linkColumnToTable} instead 3138 */ 3139 public void linkColumnReferenceToTable(TObjectName cr, ESqlClause plocation){ 3140 // this is the column name, link it to table 3141 if (cr == null) return; 3142 cr.setLocation(plocation); 3143 if (cr.getObjectType() == TObjectName.ttobjVariable) return; 3144 if (cr.getObjectType() == TObjectName.ttobjColumnAlias) return; 3145 if (this.dbvendor == EDbVendor.dbvsybase){ 3146 TSourceToken pt = cr.getPartToken(); 3147 if ( pt != null){ 3148 if (pt.tokentype == ETokenType.ttdqstring){ 3149 //"0123", quoted string start with a number can't a column 3150 if ((pt.toString().charAt(1) >= '0') 3151 &&(pt.toString().charAt(1) <= '9')){ 3152 return; 3153 }else if (pt.toString().length() == 2){ 3154 //"", empty 3155 return; 3156 }else if (pt.toString().substring(1,pt.toString().length()-1).trim().length() == 0){ 3157 //" " 3158 return; 3159 } 3160 } 3161 } 3162 } 3163 3164 3165 if (cr.getPartToken() != null){ 3166 if (cr.getPartToken().tokentype == ETokenType.ttkeyword){ 3167 boolean reservedKeyword = false; 3168 switch (dbvendor){ 3169 case dbvmssql: 3170 //reservedKeyword = ! this.getGsqlparser().getFlexer().canBeColumnName(cr.getPartToken().tokencode); 3171 reservedKeyword = ! TLexerMssql.canBeColumnName(cr.getPartToken().tokencode); 3172 break; 3173 case dbvsybase: 3174 reservedKeyword = keywordChecker.isKeyword(cr.getPartToken().toString(), EDbVendor.dbvsybase, "15.7", true); 3175 break; 3176 default: 3177 break; 3178 } 3179 if (reservedKeyword) return; 3180 } 3181 } 3182 3183 // let's check is this columnreference is variable or parameter of plsql function/procedure 3184 // if (locateVariableOrParameter(cr)) return; 3185 3186// if ((cr.getPartToken() != null)&&((dbvendor == EDbVendor.dbvmssql)||(dbvendor == EDbVendor.dbvsybase))){ 3187// if ((cr.getPartToken().tokentype == ETokenType.ttkeyword)&&(!(this.getGsqlparser().getFlexer().canBeColumnName(cr.getPartToken().tokencode)))){ 3188// // keyword can't be column name: 3189// //select * From dbo.table Where DATEDIFF(day, create_date, expiry_date) < 14 3190// return; 3191// } 3192// } 3193 3194 if ((cr.toString().startsWith("@"))) 3195// if ((cr.toString().endsWith("*"))||(cr.toString().startsWith("@"))) 3196 { 3197 cr.setObjectType(TObjectName.ttobjNotAObject); 3198 return; 3199 } 3200 3201 if (dbvendor == EDbVendor.dbvoracle){ 3202 if ( //(cr.toString().compareToIgnoreCase ("rowid") == 0)|| 3203 (cr.toString().compareToIgnoreCase ("sysdate") == 0) 3204 || (cr.toString().compareToIgnoreCase ("nextval") == 0) 3205 || (cr.toString().compareToIgnoreCase ("rownum") == 0) 3206 || (cr.toString().compareToIgnoreCase ("level") == 0) 3207 ){ 3208 cr.setObjectType(TObjectName.ttobjNotAObject); 3209 if (cr.getDbObjectType() == EDbObjectType.unknown){ 3210 cr.setDbObjectType(EDbObjectType.notAColumn); 3211 } 3212 return; 3213 } 3214 } 3215 3216 if (((cr.toString().toUpperCase().startsWith("INSERTED"))||(cr.toString().toUpperCase().startsWith("DELETED")))&&(plocation == ESqlClause.output)&&(targetTable != null)){ 3217 targetTable.getObjectNameReferences().addObjectName(cr); 3218 return; 3219 } 3220 3221 if ( ((cr.toString().toUpperCase().startsWith(":NEW")) 3222 ||(cr.toString().toUpperCase().startsWith(":OLD"))) 3223 &&(this.getTopStatement() instanceof TPlsqlCreateTrigger) 3224 &&(dbvendor == EDbVendor.dbvoracle)){ 3225 this.getTopStatement().tables.getTable(0).getObjectNameReferences().addObjectName(cr); 3226 return; 3227 } 3228 3229 3230 3231 int ret = this.tables.checkColumnReferenceInTables(cr); 3232 if (ret >= 0) { 3233 TTable lcTable = this.tables.getTable(ret); 3234 if (lcTable.isBaseTable()){ 3235 lcTable.getObjectNameReferences().addObjectName(cr); 3236 }else if (lcTable.isCTEName()){ 3237 //WITH temp 3238 // AS (SELECT * 3239 // FROM sysibm.systables), 3240 // temp1 3241 // AS (SELECT * 3242 // FROM sysibm.syscolumns) 3243 //SELECT * 3244 //FROM temp A 3245 // INNER JOIN temp1 B 3246 // ON A.creator = B.tbcreator 3247 // AND A.name = B.tbname 3248 TCTE lccte = findCTEByName(lcTable.toString()); 3249 if (lccte != null){ 3250 TObjectName objectName = new TObjectName(); 3251 objectName.init(cr.getPartToken()); 3252 if (lccte.getSubquery() != null){ 3253 lccte.getSubquery().linkColumnReferenceToTable(objectName,plocation); 3254 } 3255 } 3256 }else if (lcTable.getTableType() == ETableSource.subquery){ 3257 // link s2t1a1 to subselect2table1 via s2 3258 //select 3259 // s2.s2t1a1 3260 //from 3261 // ( 3262 // select s2t1.* 3263 // from subselect2table1 s2t1 3264 // ) s2 3265 TSelectSqlStatement subquery = lcTable.getSubquery(); 3266 3267 if(((subquery.getValueClause() == null))&&(!subquery.isCombinedQuery())&&(subquery.getResultColumnList() != null)&&(subquery.getResultColumnList().size() == 1)){ 3268 TResultColumn lcColumn = subquery.getResultColumnList().getResultColumn(0); 3269 if (lcColumn.toString().endsWith("*")){ 3270 boolean isfound = false; 3271 3272 for(int i=0;i<subquery.tables.size();i++){ 3273 if (subquery.tables.getTable(i).getTableType() == ETableSource.subquery) continue; 3274 String columnStr = null; 3275 if (cr.getPartToken() != null){ 3276 //cr.getObjectType() is not ttObjColumn, so we can't use 3277 // getColumnToken, this is a bug, need to check it later. 3278 columnStr = cr.getPartToken().toString(); 3279 } 3280 if (this.fireOnMetaDatabaseTableColumn( 3281 subquery.tables.getTable(i).getTableName().getServerString(), 3282 subquery.tables.getTable(i).getTableName().getDatabaseString(), 3283 subquery.tables.getTable(i).getTableName().getSchemaString(), 3284 subquery.tables.getTable(i).getName(),columnStr)){ 3285 subquery.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3286 isfound = true; 3287 break; 3288 } 3289 } 3290 3291 3292 3293 if (!isfound) 3294 { 3295 if(subquery.tables.size() > 1){ 3296 cr.setTableDetermined(false); 3297 } 3298 for(int i=0;i<subquery.tables.size();i++){ 3299 subquery.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3300 } 3301 } 3302 3303 } // "*" 3304 } 3305 } 3306 }else if (ret == -2){ 3307 // no qualifier before column, check is this column of a cte, if not,set it to non-cte table 3308 boolean isfound = false; 3309 for (int i=0;i<this.tables.size();i++){ 3310 if ((this.tables.getTable(i).isCTEName()) &&(this.tables.getTable(i).getCteColomnReferences() != null)){ 3311 if (this.tables.getTable(i).getCteColomnReferences().searchColumnReference(cr) >= 0){ 3312 this.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3313 isfound = true; 3314 break; 3315 } 3316 } 3317 } 3318 3319 // no qualifier before column, but we still need to check uplevel table like this: 3320 //SELECT 3321 // col1 , 3322 // 3323 // ( SELECT col2 3324 // FROM tab1 3325 // WHERE col2 = col1 ) 3326 // FROM tab2 3327 // we need to link col1 to tab2 in up level, but not to tab1 3328 if ((!isfound) &&( 3329 (cr.getLocation() != ESqlClause.resultColumn) 3330 &&(cr.getLocation() != ESqlClause.insertColumn) 3331 &&(cr.getLocation() != ESqlClause.mergeInsert) 3332 &&(cr.getLocation() != ESqlClause.selectList) 3333 ) ){ // code #111 3334 TCustomSqlStatement lcParent = null; 3335 lcParent = this.getParentStmt(); 3336 while ( lcParent != null) { 3337 TTable lcTable; 3338 //ret = lcParent.tables.checkColumnReferenceInTables(cr); 3339 if (lcParent.sqlstatementtype != ESqlStatementType.sstselect) { 3340 break; 3341 } 3342 for (int i=0;i<lcParent.tables.size();i++){ 3343 lcTable = lcParent.tables.getTable(i); 3344 if (lcTable.getTableType() == ETableSource.objectname) { 3345 for(int k = 0; k< lcTable.getObjectNameReferences().size();k++){ 3346 if (lcTable.getObjectNameReferences().getObjectName(k).isTableDetermined()){ 3347 if (cr.toString().equalsIgnoreCase(lcTable.getObjectNameReferences().getObjectName(k).toString())){ 3348 isfound = true; 3349 break; 3350 } 3351 } 3352 } 3353 if (isfound) break; 3354 } 3355 } 3356 3357 if (isfound){ 3358 break; 3359 }else{ 3360 lcParent = lcParent.getParentStmt(); 3361 } 3362 } // while 3363 3364 } // end of code #111 3365 3366 if (!isfound){ 3367 isfound = checkNonQualifiedColumnReferenceInSubQueryOfUplevelStmt(cr 3368 , ((plocation == ESqlClause.resultColumn) 3369 ||(plocation == ESqlClause.insertColumn) 3370 ||(plocation == ESqlClause.mergeInsert) 3371 ||(plocation == ESqlClause.selectList) 3372 ) 3373 ); 3374 } 3375 3376 if ((!isfound)&&(this.tables.size() > 0)){ 3377 int candidate = 0, firstCandidate = -1; 3378 // add this column reference to first non-cte( or cte with column list is null) and non-subquery table 3379 for (int i=0;i<this.tables.size();i++){ 3380 // 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 3381 //if (this.tables.getTable(i).aliasClause != null) continue; 3382 if ( 3383 ( 3384 (!this.tables.getTable(i).isCTEName()) 3385 ||((this.tables.getTable(i).isCTEName())&&(this.tables.getTable(i).getCteColomnReferences() == null)) 3386 )&&((this.tables.getTable(i).getTableType() != ETableSource.subquery)) 3387 ) 3388 { 3389 candidate++; 3390 if (firstCandidate == -1) firstCandidate = i; 3391 if (this.fireOnMetaDatabaseTableColumn( 3392 this.tables.getTable(i).getTableName().getServerString(), 3393 this.tables.getTable(i).getTableName().getDatabaseString(), 3394 this.tables.getTable(i).getTableName().getSchemaString(), 3395 this.tables.getTable(i).getName(),cr.toString())){ 3396 this.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3397 isfound = true; 3398 break; 3399 } 3400 else{ 3401 this.tables.getTable(i).getObjectNameReferences().addObjectName(cr); 3402 if (this.tables.size() > 1){ 3403 cr.setTableDetermined(false); 3404 } 3405 isfound = true; 3406 break; 3407 } 3408 } 3409 } 3410 if ((!isfound) && (candidate == 1)){ 3411 this.tables.getTable(firstCandidate).getObjectNameReferences().addObjectName(cr); 3412 } 3413 } 3414 }else if (ret == -1){ 3415 TCustomSqlStatement lcParent = null; 3416 lcParent = this.getParentStmt(); 3417 while ( lcParent != null) { 3418 ret = lcParent.tables.checkColumnReferenceInTables(cr); 3419 if (ret >= 0){ 3420 lcParent.tables.getTable(ret).getObjectNameReferences().addObjectName(cr); 3421 break; 3422 }else{ 3423 lcParent = lcParent.getParentStmt(); 3424 } 3425 } // while 3426 } //-1 3427 3428 } 3429 3430 /** 3431 * Found out is a non qualified column is a column in uplevel subquery table like this: 3432 * take ma_parkey for example: ma_parkey is not a physical column 3433 * 3434 SELECT c_mandant 3435 , CASE WHEN EXISTS (SELECT 1 3436 FROM CDS_H_GRUPPE GRP1 3437 WHERE GRP1.c_mandant = c_mandant 3438 AND GRP1.parkey1 = ma_parkey) 3439 THEN 1 3440 ELSE NULL 3441 END MA_ME 3442 FROM (SELECT c_mandant 3443 , CASE WHEN funktionscode = 'U' 3444 THEN parkey1 3445 ELSE parkey2 3446 END MA_PARKEY 3447 FROM 3448 CDS_H_GRUPPE 3449 ) 3450 */ 3451 public boolean checkNonQualifiedColumnReferenceInSubQueryOfUplevelStmt(TObjectName crf,boolean sameLevelOnly){ 3452 boolean ret = false; 3453 3454 TCustomSqlStatement lcParent = null; 3455 lcParent = this;//getParentStmt(); 3456 while ( lcParent != null) { 3457 TTable lcTable; 3458 for (int i=0;i<lcParent.tables.size();i++){ 3459 lcTable = lcParent.tables.getTable(i); 3460 3461 if ((lcTable.getTableType() != ETableSource.subquery)) {continue;} 3462 3463 ret = isColumnNameInSelectList(crf.toString(),lcTable.subquery); 3464 if (ret) {break;} 3465 3466 } 3467 if (ret) {break;} 3468 else{ 3469 if (sameLevelOnly){ 3470 lcParent = null; 3471 }else{ 3472 lcParent = lcParent.getParentStmt(); 3473 } 3474 } 3475 } // while 3476 3477 return ret; 3478 } 3479 3480 private boolean isColumnNameInSelectList(String pColumn, TSelectSqlStatement pSelect){ 3481 boolean ret = false; 3482 TResultColumn lcColumn; 3483 if (pSelect.isCombinedQuery()){ 3484 ret = isColumnNameInSelectList(pColumn,pSelect.getLeftStmt()); 3485 if (!ret){ 3486 ret = isColumnNameInSelectList(pColumn,pSelect.getRightStmt()); 3487 } 3488 }else{ 3489 if (pSelect.getResultColumnList() != null){ //if it's a db2 value row, then pSelect.getResultColumnList() will be null 3490 for(int j=0;j<pSelect.getResultColumnList().size();j++){ 3491 lcColumn = pSelect.getResultColumnList().getResultColumn(j); 3492 if (lcColumn.getAliasClause() != null){ 3493 ret = pColumn.equalsIgnoreCase(lcColumn.getAliasClause().toString()); 3494 } 3495 if (ret) break; 3496 ret = pColumn.equalsIgnoreCase(lcColumn.getExpr().toString()); 3497 if (ret) break; 3498 } 3499 } 3500 } 3501 return ret; 3502 } 3503 3504 public TCustomSqlStatement getTopStatement(){ 3505 TCustomSqlStatement ret = this; 3506 while (ret.getParentStmt() != null){ 3507 ret = ret.getParentStmt(); 3508 } 3509 return ret; 3510 } 3511 3512 3513// public String toScript(){ 3514// if (!isChanged()){ 3515// return this.toString(); 3516// } 3517// return super.toScript(); 3518// } 3519 3520} 3521 3522class constantVisitor extends TParseTreeVisitor { 3523 private boolean inWhere = false,inExprList = false; 3524 public void preVisit(TWhereClause node){ 3525 inWhere = true; 3526 } 3527 3528 public void postVisit(TWhereClause node){ 3529 inWhere = false; 3530 } 3531 3532 public void preVisit(TExpression node){ 3533 if (inWhere){ 3534 switch (node.getExpressionType()){ 3535 case list_t: 3536 inExprList = true; 3537 boolean isNumber = true; 3538 if (node.getExprList().size() > 0){ 3539 // check the type of the constant in the expr list 3540 TExpression expr = node.getExprList().getExpression(0); 3541 if (expr.getExpressionType() == EExpressionType.simple_constant_t){ 3542 if (expr.getConstantOperand().getLiteralType() == ELiteralType.etString){ 3543 isNumber = false; 3544 } 3545 } 3546 } 3547 3548 TSourceToken lcStartToken = node.getStartToken(); 3549 TSourceToken lcEndToken = node.getEndToken(); 3550 int tokenPos = 0; 3551 if ((lcEndToken != null) && (lcStartToken != null)){ 3552 TSourceToken lcCurrentToken = lcStartToken; 3553 while (lcCurrentToken != null){ 3554 3555 if (lcCurrentToken.equals(lcEndToken)){ 3556 break; 3557 }else{ 3558 3559 if (tokenPos == 1){ 3560 if (isNumber){ 3561 lcCurrentToken.setTextWithBackup("999"); 3562 }else{ 3563 lcCurrentToken.setTextWithBackup("'placeholder_str'"); 3564 } 3565 }else if (tokenPos > 1){ 3566 lcCurrentToken.tokenstatus = ETokenStatus.tsdeleted; 3567 } 3568 3569 lcCurrentToken = lcCurrentToken.getNextTokenInChain(); 3570 tokenPos++; 3571 } 3572 } 3573 } 3574 3575 break; 3576 } 3577 } // where 3578 } 3579 3580 public void postVisit(TExpression node){ 3581 if (inWhere){ 3582 switch (node.getExpressionType()){ 3583 case list_t: 3584 inExprList = false; 3585 break; 3586 } 3587 } 3588 } 3589 3590 public void preVisit(TConstant node){ 3591 if (inWhere&&(!inExprList)){ 3592 switch (node.getLiteralType()){ 3593 case etNumber: 3594 case etFloat: 3595 node.getStartToken().setTextWithBackup("999"); 3596 break; 3597 case etString: 3598 node.getStartToken().setTextWithBackup("'placeholder_str'"); 3599 break; 3600 } 3601 } 3602 } 3603 3604 public void preVisit(TFunctionCall node){ 3605 if (TBaseType.as_canonical_f_decrypt_replace_password){ 3606 int i = TBaseType.searchCryptFunction(node.getFunctionName().toString()); 3607 3608 if (i>0){ // find this function 3609 if (node.getArgs().size() >= i){ 3610 TExpression secondArg = node.getArgs().getExpression(i-1); 3611 if (secondArg.getExpressionType() == EExpressionType.simple_constant_t){ 3612 TConstant constant = secondArg.getConstantOperand(); 3613 constant.getValueToken().setTextWithBackup("'***'"); 3614 //System.out.println(node.toString()+":"+constant.toString()); 3615 }else if (secondArg.getExpressionType() == EExpressionType.simple_object_name_t){ 3616 TObjectName objectName = secondArg.getObjectOperand(); 3617 objectName.getStartToken().setTextWithBackup("'***'"); 3618 //System.out.println(node.toString()+":"+constant.toString()); 3619 } 3620 } 3621 } 3622 3623 } 3624 } 3625 3626 void processConstant(TConstant node){ 3627 switch (node.getLiteralType()){ 3628 case etNumber: 3629 case etFloat: 3630 node.getStartToken().setTextWithBackup("999"); 3631 break; 3632 case etString: 3633 node.getStartToken().setTextWithBackup("'placeholder_str'"); 3634 break; 3635 } 3636 } 3637 3638}