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