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