001package gudusoft.gsqlparser.stmt; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.compiler.TStmtScope; 005import gudusoft.gsqlparser.nodes.*; 006import gudusoft.gsqlparser.nodes.hana.TTimeTravel; 007import gudusoft.gsqlparser.nodes.hive.*; 008import gudusoft.gsqlparser.nodes.mssql.TOptionClause; 009import gudusoft.gsqlparser.nodes.THierarchical; 010import gudusoft.gsqlparser.nodes.teradata.TExpandOnClause; 011import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType; 012import gudusoft.gsqlparser.sqlenv.IdentifierService; 013import gudusoft.gsqlparser.sqlenv.TSQLEnv; 014import gudusoft.gsqlparser.sqlenv.TSQLTable; 015 016import java.util.ArrayList; 017import java.util.Collections; 018import java.util.TreeMap; 019 020 021/** 022 * Class {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement } represents query specification, query expression and select statement. 023 * <br><br><b>query specification</b> including following clause: 024 * <ul> 025 * <li>select list {@link #getResultColumnList}</li> 026 * <li>from clause {@link #joins}</li> 027 * <li>where clause {@link #getWhereClause}</li> 028 * <li>group clause {@link #getGroupByClause}</li> 029 * <li>having clause {@link #getGroupByClause}</li> 030 * </ul> 031 * In some databases, query specification also known as sub-select. 032 * 033 * <br><br><b>query expression</b> including all elements in query specification and following clause: 034 * <ul> 035 * <li>order by clause {@link #getOrderbyClause}</li> 036 * <li>offset clause {@link #getOffsetClause}</li> 037 * <li>for clause</li> 038 * </ul> 039 * In some databases, query expression also known as full-select. 040 * <br>It is a component of the select-statement, the INSERT statement, and the CREATE VIEW statement. 041 * And a full-select that is enclosed in parentheses is sometimes called a sub-query. 042 * 043 * <br><br>select statement including all elements in query expression and following clause: 044 * <ul> 045 * <li>compute clause {@link #getComputeClause}</li> 046 * <li>for update clause {@link #getForUpdateClause}</li> 047 * <li>optimizer hint</li> 048 * <li>ctes {@link #getCteList}</li> 049 * </ul> 050 * Lots of clauses on this level are db vendors specific. 051 * 052 053 * <br><br> 054 * Use {@link #isCombinedQuery} to check whether UNION, EXCEPT and INTERSECT operators is used. 055 * If returns true, use {@link #getLeftStmt} and {@link #getRightStmt} to get query expression. 056 * You need to check {@link #isCombinedQuery} recursively, all clauses of {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement} 057 * only available when this function returns false. 058 * 059 */ 060 061public class TSelectSqlStatement extends TCustomSqlStatement { 062 063 // 如果是 combined query, 并且当前select 没有预先设定的 endToken, 则取最右边 query 的 endToken 064 public TSourceToken getEndToken() { 065 if (super.getEndToken() != null) return super.getEndToken(); 066 if (this.isCombinedQuery()){ 067 return this.getRightStmt().getEndToken(); 068 }else{ 069 return super.getEndToken(); 070 } 071 } 072 073 public void setSubQueryInFromClauseCanUseParentSelectAsEnclosingScope(boolean subQueryInFromClauseCanUseParentSelectAsEnclosingScope) { 074 this.subQueryInFromClauseCanUseParentSelectAsEnclosingScope = subQueryInFromClauseCanUseParentSelectAsEnclosingScope; 075 } 076 077 public boolean isSubQueryInFromClauseCanUseParentSelectAsEnclosingScope() { 078 return subQueryInFromClauseCanUseParentSelectAsEnclosingScope; 079 } 080 081 private boolean subQueryInFromClauseCanUseParentSelectAsEnclosingScope = false; 082 083 boolean starColumnPushedDown = false; 084 085 public boolean isStarColumnPushedDown() { 086 return starColumnPushedDown; 087 } 088 089 public void setStarColumnPushedDown(boolean starColumnPushedDown) { 090 this.starColumnPushedDown = starColumnPushedDown; 091 } 092 093 // StarRocks pipe operator support 094 private TPTNodeList<TParseTreeNode> pipeOperators; 095 private boolean isPipeQuery = false; 096 097 // Oracle 12c WITH FUNCTION/PROCEDURE support - inline PL/SQL definitions 098 private TStatementListSqlNode withPlsqlItems; 099 100 /** 101 * Get the inline PL/SQL function/procedure definitions from WITH clause. 102 * Oracle 12c+ allows defining PL/SQL functions inline in the WITH clause: 103 * WITH FUNCTION f(x NUMBER) RETURN NUMBER IS BEGIN RETURN x*2; END; 104 * SELECT f(1) FROM dual 105 * 106 * @return list of inline function/procedure definitions, or null if none 107 */ 108 public TStatementListSqlNode getWithPlsqlItems() { 109 return withPlsqlItems; 110 } 111 112 /** 113 * Set the inline PL/SQL function/procedure definitions. 114 * @param withPlsqlItems list of inline function/procedure definitions 115 */ 116 public void setWithPlsqlItems(TStatementListSqlNode withPlsqlItems) { 117 this.withPlsqlItems = withPlsqlItems; 118 } 119 120 /** 121 * Get the list of pipe operators for StarRocks pipe query syntax. 122 * Pipe queries use the |> operator to chain operations: 123 * FROM table |> SELECT * |> WHERE cond |> ORDER BY col 124 * 125 * @return list of TPipeOperator nodes, or null if not a pipe query 126 */ 127 public TPTNodeList<TParseTreeNode> getPipeOperators() { 128 return pipeOperators; 129 } 130 131 /** 132 * Set the pipe operators list. 133 * @param pipeOperators list of pipe operator nodes 134 */ 135 public void setPipeOperators(TPTNodeList<TParseTreeNode> pipeOperators) { 136 this.pipeOperators = pipeOperators; 137 } 138 139 /** 140 * Check if this is a StarRocks pipe query. 141 * Pipe queries use the syntax: FROM table |> SELECT * |> WHERE ... 142 * 143 * @return true if this is a pipe query 144 */ 145 public boolean isPipeQuery() { 146 return isPipeQuery; 147 } 148 149 /** 150 * Set whether this is a pipe query. 151 * @param isPipeQuery true if this is a pipe query 152 */ 153 public void setIsPipeQuery(boolean isPipeQuery) { 154 this.isPipeQuery = isPipeQuery; 155 } 156 157 /** 158 * 在 sql script 中,和该 relation 关联的 attribute。 159 * select a from t; 160 * attribute a 就是 relation t 的 referenceAttribute, 如果没有 metadata and ddl, 161 * relation t 的 getAttributes() 应该可以推断出包含 a, 但 t 是否还包含其他的 attribute 就无从得知。 162 */ 163 164 @Override 165 public ArrayList<TAttributeNode> getAttributes(){ 166 if (this.getFromClause() == null) return null; 167 168 return this.getFromClause().getAttributes(); 169 170// relationAttributes.clear(); 171// for(TTable table:getRelations()){ 172// relationAttributes.addAll(table.getAttributes()); 173// } 174// 175// if (relationAttributes.size() > 0){ 176// TBaseType.log ("relationAttributes.size() in select is :"+relationAttributes.size() 177// +", relation size: "+getRelations().size() 178// +", relation 0 type:"+getRelations().get(0).getTableType() 179// ,1); 180// // System.out.println(this.toString()); 181// } 182// 183// return relationAttributes; 184 } 185 186 ArrayList<TAttributeNode> relationAttributes = new ArrayList<>(); 187 188// private TExpression skipOffset; 189// private TExpression firstMax; 190// private TExpression limitMax; 191// 192// public void setSkipOffset(TExpression skipOffset) { 193// this.skipOffset = skipOffset; 194// } 195// 196// public void setFirstMax(TExpression firstMax) { 197// this.firstMax = firstMax; 198// } 199// 200// public void setLimitMax(TExpression limitMax) { 201// this.limitMax = limitMax; 202// } 203// 204// /** 205// * Informix skip offset 206// * @return skip offset 207// */ 208// public TExpression getSkipOffset() { 209// 210// return skipOffset; 211// } 212// 213// /** 214// * Informix first Max 215// * @return first Max 216// */ 217// public TExpression getFirstMax() { 218// return firstMax; 219// } 220// 221// /** 222// * Informix limit max 223// * @return limit max 224// */ 225// public TExpression getLimitMax() { 226// return limitMax; 227// } 228 229 private ArrayList<TSelectSqlStatement> multiSelectStatements; 230 231 /** 232 * Hive, from ... select, select,... 233 * <br> Multiple select statement in Hive from query syntax 234 * 235 * @return Multiple select statement in Hive from query syntax 236 */ 237 public ArrayList<TSelectSqlStatement> getMultiSelectStatements() { 238 if(multiSelectStatements == null){ 239 multiSelectStatements = new ArrayList<>(); 240 } 241 return multiSelectStatements; 242 } 243 244 private TClusterBy clusterBy; 245 246 public void setClusterBy(TClusterBy clusterBy) { 247 this.clusterBy = clusterBy; 248 } 249 250 public TClusterBy getClusterBy() { 251 return clusterBy; 252 } 253 254 private boolean isConsume; 255 256 public void setConsume(boolean consume) { 257 isConsume = consume; 258 } 259 260 public boolean isConsume() { 261 return isConsume; 262 } 263 264 private TStatementList hiveBodyList = null; 265 266 /** 267 * @deprecated since 2.6.3.5, please use {@link #getMultiSelectStatements()} to retrieve 268 * multimple select statement in Hive from query ... select, select, ... 269 * 270 * @return 271 */ 272 public TStatementList getHiveBodyList() { 273 if (hiveBodyList == null) 274 hiveBodyList = new TStatementList(); 275 return hiveBodyList; 276 } 277 278 public void setSelectModifiers(ArrayList<TSelectModifier> selectModifiers) { 279 this.selectModifiers = selectModifiers; 280 } 281 282 public ArrayList<TSelectModifier> getSelectModifiers() { 283 return selectModifiers; 284 } 285 286 private ArrayList<TSelectModifier> selectModifiers; 287 288 289 private TTimeTravel timeTravel; // hana 290 private THintClause hintClause; //hana 291 292 public void setTimeTravel(TTimeTravel timeTravel) { 293 setNewSubNode(this.timeTravel,timeTravel,getAnchorNode()); 294 this.timeTravel = timeTravel; 295 } 296 297 public void setHintClause(THintClause hintClause) { 298 setNewSubNode(this.hintClause,hintClause,getAnchorNode()); 299 this.hintClause = hintClause; 300 } 301 302 303 public TTimeTravel getTimeTravel() { 304 305 return timeTravel; 306 } 307 308 public THintClause getHintClause() { 309 return hintClause; 310 } 311 312 private int parenthesisCount = 0; 313 private int parenthesisCountBeforeOrder = 0; 314 315 public void setFetchFirstClause(TFetchFirstClause fetchFirstClause) { 316 setNewSubNode(this.fetchFirstClause,fetchFirstClause,getAnchorNode()); 317 this.fetchFirstClause = fetchFirstClause; 318 } 319 320 321 public void setParenthesisCount(int parenthesisCount) { 322 this.parenthesisCount = parenthesisCount; 323 } 324 325 public void setParenthesisCountBeforeOrder(int parenthesisCountBeforeOrder) { 326 this.parenthesisCountBeforeOrder = parenthesisCountBeforeOrder; 327 } 328 329 public void setAll(boolean all) { 330 this.all = all; 331 } 332 333 public void setSetOperatorType(ESetOperatorType setOperatorType) { 334 this.setOperatorType = setOperatorType; 335 } 336 337 public void setWindowClause(TWindowClause windowClause) { 338 setNewSubNode(this.windowClause,windowClause,getAnchorNode()); 339 this.windowClause = windowClause; 340 } 341 342 public void setLockingClauses(TPTNodeList<TLockingClause> lockingClauses) { 343 this.lockingClauses = lockingClauses; 344 } 345 346 public void setSelectDistinct(TSelectDistinct selectDistinct) { 347 setNewSubNode(this.selectDistinct,selectDistinct,getAnchorNode()); 348 this.selectDistinct = selectDistinct; 349 } 350 351 public void setExpandOnClause(TExpandOnClause expandOnClause) { 352 setNewSubNode(this.expandOnClause,expandOnClause,getAnchorNode()); 353 this.expandOnClause = expandOnClause; 354 } 355 356 357 public void setSetOperator(int setOperator) { 358 this.setOperator = setOperator; 359 } 360 361 public void setLeftStmt(TSelectSqlStatement leftStmt) { 362 this.leftStmt = leftStmt; 363 } 364 365 public void setRightStmt(TSelectSqlStatement rightStmt) { 366 this.rightStmt = rightStmt; 367 } 368 369 public void setValueClause(TValueClause valueClause) { 370 setNewSubNode(this.valueClause,valueClause,getAnchorNode()); 371 this.valueClause = valueClause; 372 } 373 374 public void setOracleHint(String oracleHint) { 375 this.oracleHint = oracleHint; 376 } 377 378 public void setHiveHintClause(THiveHintClause hiveHintClause) { 379 setNewSubNode(this.hiveHintClause,hiveHintClause,getAnchorNode()); 380 this.hiveHintClause = hiveHintClause; 381 } 382 383 384 public void setTransformClause(THiveTransformClause transformClause) { 385 setNewSubNode(this.transformClause,transformClause,getAnchorNode()); 386 this.transformClause = transformClause; 387 } 388 389 public void setDistributeBy(TDistributeBy distributeBy) { 390 setNewSubNode(this.distributeBy,distributeBy,getAnchorNode()); 391 this.distributeBy = distributeBy; 392 } 393 394 395 public void setIntoClause(TIntoClause intoClause) { 396 setNewSubNode(this.intoClause,intoClause,getAnchorNode()); 397 this.intoClause = intoClause; 398 } 399 400 public void setOrderbyClause(TOrderBy newOrderbyClause) { 401 setNewSubNode(this.orderbyClause,newOrderbyClause,getAnchorNode()); 402 this.orderbyClause = newOrderbyClause; 403 } 404 405// public void setOrderbyClause(TOrderBy newOrderbyClause, TParseTreeNode anchorNode) { 406// if (newOrderbyClause == null){ 407// //remove 408// this.orderbyClause.removeTokens(); 409// this.orderbyClause = null; 410// }else{ 411// if (this.orderbyClause != null){ 412// this.orderbyClause.replaceWithNewNode(newOrderbyClause); 413// }else{ 414// doAppendNewNode(newOrderbyClause,anchorNode,false); 415// } 416// this.orderbyClause = newOrderbyClause; 417// } 418// } 419 420 public void setQualifyClause(TQualifyClause qualifyClause) { 421 setNewSubNode(this.qualifyClause,qualifyClause,getAnchorNode()); 422 this.qualifyClause = qualifyClause; 423 } 424 425 public void setSampleClause(TSampleClause sampleClause) { 426 setNewSubNode(this.sampleClause,sampleClause,getAnchorNode()); 427 this.sampleClause = sampleClause; 428 } 429 430 public void setTeradataWithClause(TTeradataWithClause teradataWithClause) { 431 setNewSubNode(this.teradataWithClause,teradataWithClause,getAnchorNode()); 432 this.teradataWithClause = teradataWithClause; 433 } 434 435 public void setForUpdateClause(TForUpdate forUpdateClause) { 436 setNewSubNode(this.forUpdateClause,forUpdateClause,getAnchorNode()); 437 this.forUpdateClause = forUpdateClause; 438 } 439 440 441 public void setComputeClause(TComputeClause computeClause) { 442 this.computeClause = computeClause; 443 } 444 445 public void setGroupByClause(TGroupBy groupByClause) { 446 setNewSubNode(this.groupByClause,groupByClause,getAnchorNode()); 447 this.groupByClause = groupByClause; 448 } 449 450 451 public void setHierarchicalClause(THierarchical hierarchicalClause) { 452 setNewSubNode(this.hierarchicalClause,hierarchicalClause,getAnchorNode()); 453 this.hierarchicalClause = hierarchicalClause; 454 } 455 456 457 public void setLimitClause(TLimitClause limitClause) { 458 setNewSubNode(this.limitClause,limitClause,getAnchorNode()); 459 this.limitClause = limitClause; 460 } 461 462 public void setOffsetClause(TOffsetClause offsetClause) { 463 setNewSubNode(this.offsetClause,offsetClause,getAnchorNode()); 464 this.offsetClause = offsetClause; 465 } 466 467 public void setOptionClause(TOptionClause optionClause) { 468 setNewSubNode(this.optionClause,optionClause,getAnchorNode()); 469 this.optionClause = optionClause; 470 } 471 472 public void setIsolationClause(TIsolationClause isolationClause) { 473 setNewSubNode(this.isolationClause,isolationClause,getAnchorNode()); 474 this.isolationClause = isolationClause; 475 } 476 477// public void setHiveClusterBy(THiveClusterBy hiveClusterBy) { 478// setNewSubNode(this.hiveClusterBy,hiveClusterBy,getAnchorNode()); 479// this.hiveClusterBy = hiveClusterBy; 480// } 481 482 483 public void setSortBy(TSortBy sortBy) { 484 setNewSubNode(this.sortBy,sortBy,getAnchorNode()); 485 this.sortBy = sortBy; 486 } 487 488 public void setIntoTableClause(TIntoTableClause intoTableClause) { 489 setNewSubNode(this.intoTableClause,intoTableClause,getAnchorNode()); 490 this.intoTableClause = intoTableClause; 491 } 492 493 public int getParenthesisCountBeforeOrder() { 494 return parenthesisCountBeforeOrder; 495 } 496 497 public int getParenthesisCount() { 498 return parenthesisCount; 499 } 500 501 private boolean queryOfCTE; 502 503 public void setQueryOfCTE(boolean queryOfCTE) { 504 this.queryOfCTE = queryOfCTE; 505 } 506 507 public boolean isQueryOfCTE() { 508 return queryOfCTE; 509 } 510 511 /** 512 * The SELECT-list alias of an ENCLOSING SELECT block that {@code reference}, an unqualified name of this block, 513 * stands for in SAP IQ and SQL Anywhere (Mantis 4752). 514 * 515 * <p>SQL Anywhere: "Aliases can be used anywhere in the SELECT block in which they are defined", and an alias 516 * "occludes" a column or variable of the same name (<i>Renamed columns in query results</i>). A subquery in the 517 * select list, WHERE, GROUP BY, HAVING or ORDER BY of a block is part of that block, so a name the subquery does 518 * not resolve itself is the alias of the block around it:</p> 519 * <pre>SELECT a AS x, (SELECT x) AS y FROM outer_t -- the inner x is the alias x, that is a</pre> 520 * 521 * <p>Only what the SQL and the catalog prove is taken. Walking outward from this block, a block is passed only 522 * when it provably has no column of that name: it reads no table, or the catalog knows every table it reads, with 523 * all its columns, and none of them has that name. A table with no metadata, a table whose columns are not all 524 * known (no column list, or a {@code *} lineage could not expand), a derived table, a CTE or a table function may 525 * have it, so the walk stops there and the name stays a column. The walk leaves a block only from a subquery in one of 526 * those clauses or from a branch of a set operation, never from a derived table, a join condition or a CTE. In 527 * the enclosing block the alias must be defined before the reference (a forward reference is SQLCODE -831), which 528 * also keeps a name inside the alias's own definition a column; there the alias wins over a column of the same 529 * name.</p> 530 * 531 * <p>The single definition of this rule for the older resolver ({@code TCustomSqlStatement.linkColumnToTable}) 532 * and resolver2 ({@code TSQLResolver2.handleSelectListAliasResolution}). An alias of the reference's own block is 533 * {@link TResultColumnList#findLateralAliasDefinition}.</p> 534 * 535 * @param reference an unqualified column reference of this block 536 * @param sqlEnv the catalog to look a table up in when it has no {@link TTable#getResolvedTable() resolved 537 * table}, or null; it must be in the statement's own context (current database and schema), so 538 * resolver2, which reads the catalog after the whole script, passes null 539 * @return the defining result column of the enclosing block, or null 540 */ 541 public TResultColumn findEnclosingAliasDefinition(TObjectName reference, TSQLEnv sqlEnv) { 542 if ((reference == null) || reference.isQualified()) return null; 543 if (!TSQLEnv.isAliasOccludingColumn(dbvendor)) return null; 544 // A set operation is no block of its own, and while it is parsed its select list is not there yet. 545 if (isCombinedQuery()) return null; 546 String columnName = reference.getColumnNameOnly(); 547 if ((columnName == null) || columnName.isEmpty()) return null; 548 // An alias or a possible column of this block is this block's own business. 549 if (hasAliasMatching(this, reference) || mayExposeColumn(this, columnName, sqlEnv)) return null; 550 551 java.util.Set<TCustomSqlStatement> visited = 552 java.util.Collections.newSetFromMap(new java.util.IdentityHashMap<TCustomSqlStatement, Boolean>()); 553 TSelectSqlStatement block = this; 554 while (visited.add(block)) { 555 TCustomSqlStatement parent = block.getParentStmt(); 556 if (!(parent instanceof TSelectSqlStatement)) return null; 557 TSelectSqlStatement enclosing = (TSelectSqlStatement) parent; 558 if (enclosing.isCombinedQuery()) { 559 // A branch of UNION, INTERSECT or EXCEPT: the set operation is not a block of its own. 560 if ((enclosing.getLeftStmt() != block) && (enclosing.getRightStmt() != block)) return null; 561 block = enclosing; 562 continue; 563 } 564 if (block.isQueryOfCTE() || !isInAliasVisibleClause(block, enclosing)) return null; 565 if (hasAliasMatching(enclosing, reference)) { 566 // null when the alias is defined after the reference, or around it 567 return enclosing.getResultColumnList().findLateralAliasDefinition(dbvendor, reference); 568 } 569 if (mayExposeColumn(enclosing, columnName, sqlEnv)) return null; 570 block = enclosing; 571 } 572 return null; 573 } 574 575 /** 576 * Whether the subquery {@code block} is written in the select list, WHERE, GROUP BY, HAVING or ORDER BY of 577 * {@code enclosing}, where its aliases are visible; a derived table or a join condition is in the FROM clause. 578 * Decided by position: an EXISTS or IN subquery reports no clause of its own. 579 */ 580 private static boolean isInAliasVisibleClause(TSelectSqlStatement block, TSelectSqlStatement enclosing) { 581 TSourceToken start = block.getStartToken(); 582 if (start == null) return false; 583 TGroupBy groupBy = enclosing.getGroupByClause(); 584 return spans(enclosing.getResultColumnList(), start) 585 || spans(enclosing.getWhereClause(), start) 586 || spans(groupBy, start) 587 || ((groupBy != null) && spans(groupBy.getHavingClause(), start)) 588 || spans(enclosing.getOrderbyClause(), start); 589 } 590 591 private static boolean spans(TParseTreeNode clause, TSourceToken token) { 592 if ((clause == null) || (clause.getStartToken() == null) || (clause.getEndToken() == null)) return false; 593 return (token.posinlist >= clause.getStartToken().posinlist) && (token.posinlist <= clause.getEndToken().posinlist); 594 } 595 596 private static boolean hasAliasMatching(TSelectSqlStatement block, TObjectName reference) { 597 if (block.isCombinedQuery()) return false; 598 TResultColumnList resultColumns = block.getResultColumnList(); 599 if (resultColumns == null) return false; 600 for (int i = 0; i < resultColumns.size(); i++) { 601 TResultColumn resultColumn = resultColumns.getResultColumn(i); 602 if ((resultColumn != null) && (resultColumn.getAliasClause() != null) 603 && resultColumn.isMatchedUsingAlias(reference)) { 604 return true; 605 } 606 } 607 return false; 608 } 609 610 /** 611 * Whether this block may have a column {@code columnName} of its own: some table it reads may have it (a derived 612 * table, a CTE, a table function, a table whose columns the catalog does not all know, or knows to include it). 613 * False only when the block provably has none. {@code sqlEnv} as in {@link #findEnclosingAliasDefinition}. 614 */ 615 public boolean mayExposeColumn(String columnName, TSQLEnv sqlEnv) { 616 return mayExposeColumn(this, columnName, sqlEnv); 617 } 618 619 /** False only when the block provably has no column of that name. */ 620 private static boolean mayExposeColumn(TSelectSqlStatement block, String columnName, TSQLEnv sqlEnv) { 621 if (block.tables == null) return false; 622 for (int i = 0; i < block.tables.size(); i++) { 623 TTable table = block.tables.getTable(i); 624 if ((table == null) || (table.getEffectType() == ETableEffectType.tetSelectInto)) continue; 625 if (table.getTableType() == ETableSource.unnest) { 626 if (unnestMayExposeColumn(table, columnName)) return true; 627 continue; 628 } 629 TObjectNameList renamed = ((table.getAliasClause() != null) && (table.getAliasClause().getColumns() != null) 630 && (table.getAliasClause().getColumns().size() > 0)) ? table.getAliasClause().getColumns() : null; 631 if ((table.getTableType() == ETableSource.subquery) && (table.getSubquery() != null)) { 632 if (derivedMayExposeColumn(table.dbvendor, table.getSubquery(), columnName, renamed, null)) return true; 633 continue; 634 } 635 if (table.isCTEName() && (table.getCTE() != null) && (table.getCTE().getSubquery() != null)) { 636 if (derivedMayExposeColumn(table.dbvendor, table.getCTE().getSubquery(), columnName, renamed, 637 table.getCTE().getColumnList())) return true; 638 continue; 639 } 640 if (!table.isBaseTable()) return true; 641 // The table as bound in its own statement's context (database, schema, a routine's temporary tables), or 642 // a table the script declared before this block, while it is parsed (Mantis 4797). 643 TSQLTable metadata = tableMetadata(block, table, sqlEnv); 644 if (!hasAllColumnsKnown(metadata) || metadata.searchColumn(columnName)) return true; 645 } 646 return false; 647 } 648 649 /** 650 * The table of an enclosing query that the unqualified {@code name} in {@code subquery} reads, or null when the name 651 * is the subquery's own (Mantis 4797). A SELECT in an expression of a query reads a name from its own tables while 652 * they may have it: in {@code (select Jahr from m_version_table2 where Jahr234 = year(now()))} both names are 653 * m_version_table2's, though a derived table around the subquery names them too. The name is an enclosing query's 654 * when it is compared with a column of the subquery's own tables, the subquery's own tables do not prove it and the 655 * enclosing query does: in {@code (SELECT max(v) FROM customfieldvalues WHERE resourceid = resumeid)} under 656 * {@code FROM (SELECT id AS resumeid FROM resumes) r}, resumeid is r's. Parse-time linking 657 * ({@code TCustomSqlStatement.linkColumnToTable}) and resolver2 ({@code NameResolver}) both decide by this rule. 658 * 659 * @param sqlEnv the catalog the parse reads, or null when each table's {@link TTable#getResolvedTable()} is what 660 * proves its columns, as after resolver2 bound the tables 661 */ 662 public static TTable outerCorrelationTable(TObjectName name, TSelectSqlStatement subquery, TSQLEnv sqlEnv) { 663 if ((name == null) || (subquery == null) || name.isQualified()) return null; 664 TSelectSqlStatement root = setOperationRoot(subquery); 665 if (!isSubqueryInExpression(root)) return null; 666 String column = name.getColumnNameOnly(); 667 TObjectName partner = comparedColumn(subquery, name); 668 if ((partner == null) || (provingTable(subquery, column, sqlEnv) != null)) return null; 669 TTable outer = enclosingProvingTable(root, column, sqlEnv); 670 if (outer == null) return null; 671 if (partner.isQualified()) return namesOwnTable(subquery, partner.getTableString()) ? outer : null; 672 String other = partner.getColumnNameOnly(); 673 if (sameColumn(subquery.dbvendor, other, column) || (enclosingProvingTable(root, other, sqlEnv) != null)) return null; 674 return outer; 675 } 676 677 /** The statement a branch of a set operation belongs to: the outermost set operation holding it. */ 678 private static TSelectSqlStatement setOperationRoot(TSelectSqlStatement select) { 679 TSelectSqlStatement root = select; 680 while (root.getParentStmt() instanceof TSelectSqlStatement) { 681 TSelectSqlStatement parent = (TSelectSqlStatement) root.getParentStmt(); 682 if ((parent.getLeftStmt() != root) && (parent.getRightStmt() != root)) break; 683 root = parent; 684 } 685 return root; 686 } 687 688 /** A SELECT written in an expression of a query, which reads that query's FROM clause: not a derived table or CTE. */ 689 private static boolean isSubqueryInExpression(TSelectSqlStatement root) { 690 return !root.isQueryOfCTE() && (root.getLocation() != ESqlClause.join) && (root.getLocation() != ESqlClause.elTable) 691 && (root.getParentStmt() instanceof TSelectSqlStatement); 692 } 693 694 /** 695 * The column {@code name} is compared with in a WHERE, HAVING or ON condition of {@code block}, or null. Read from 696 * the parse tree while the statement is parsed: its clauses are attached after their names are linked. 697 */ 698 private static TObjectName comparedColumn(TSelectSqlStatement block, TObjectName name) { 699 java.util.Deque<TExpression> pending = new java.util.ArrayDeque<>(); 700 TSelectSqlNode node = (block.rootNode instanceof TSelectSqlNode) ? (TSelectSqlNode) block.rootNode : null; 701 TWhereClause where = (block.getWhereClause() != null) ? block.getWhereClause() 702 : ((node != null) ? node.getWhereCondition() : null); 703 if ((where != null) && (where.getCondition() != null)) pending.push(where.getCondition()); 704 TGroupBy groupBy = (block.getGroupByClause() != null) ? block.getGroupByClause() 705 : ((node != null) ? node.getGroupByClause() : null); 706 if ((groupBy != null) && (groupBy.getHavingClause() != null)) pending.push(groupBy.getHavingClause()); 707 if (block.getJoins() != null) { 708 for (int i = 0; i < block.getJoins().size(); i++) { 709 TJoin join = block.getJoins().getJoin(i); 710 for (int k = 0; (join != null) && (join.getJoinItems() != null) && (k < join.getJoinItems().size()); k++) { 711 TJoinItem item = join.getJoinItems().getJoinItem(k); 712 if ((item != null) && (item.getOnCondition() != null)) pending.push(item.getOnCondition()); 713 } 714 } 715 } 716 while (!pending.isEmpty()) { 717 TExpression expr = pending.pop(); 718 if (expr.getExpressionType() == EExpressionType.subquery_t) continue; 719 if (expr.getExpressionType() == EExpressionType.simple_comparison_t) { 720 TObjectName left = columnOperand(expr.getLeftOperand()); 721 TObjectName right = columnOperand(expr.getRightOperand()); 722 if ((left == name) && (right != null)) return right; 723 if ((right == name) && (left != null)) return left; 724 } 725 if (expr.getLeftOperand() != null) pending.push(expr.getLeftOperand()); 726 if (expr.getRightOperand() != null) pending.push(expr.getRightOperand()); 727 } 728 return null; 729 } 730 731 private static TObjectName columnOperand(TExpression operand) { 732 return ((operand != null) && (operand.getExpressionType() == EExpressionType.simple_object_name_t)) 733 ? operand.getObjectOperand() : null; 734 } 735 736 /** Whether {@code qualifier} names, by alias or by name, a table of {@code block}'s FROM clause. */ 737 private static boolean namesOwnTable(TSelectSqlStatement block, String qualifier) { 738 if ((block.tables == null) || (qualifier == null) || qualifier.isEmpty()) return false; 739 for (int i = 0; i < block.tables.size(); i++) { 740 TTable table = block.tables.getTable(i); 741 if (table == null) continue; 742 String exposed = table.getAliasName().isEmpty() ? table.getName() : table.getAliasName(); 743 if (gudusoft.gsqlparser.util.SQLUtil.compareIdentifier(block.dbvendor, ESQLDataObjectType.dotTable, exposed, qualifier)) { 744 return true; 745 } 746 } 747 return false; 748 } 749 750 /** 751 * The table of the nearest enclosing query that proves {@code column}, climbing while the queries passed only may 752 * have it through tables whose columns are not known; null when there is none, when an enclosing query proves it 753 * twice, or when a derived table, CTE or other source there may have it. A derived table or a CTE body sees no 754 * query around it. 755 */ 756 private static TTable enclosingProvingTable(TSelectSqlStatement root, String column, TSQLEnv sqlEnv) { 757 TSelectSqlStatement block = root; 758 while (isSubqueryInExpression(block)) { 759 TSelectSqlStatement enclosing = (TSelectSqlStatement) block.getParentStmt(); 760 TTable proving = provingTable(enclosing, column, sqlEnv); 761 if (proving == AMBIGUOUS) return null; 762 if (proving != null) return proving; 763 if (sourceMayExposeColumn(enclosing, column)) return null; 764 block = setOperationRoot(enclosing); 765 } 766 return null; 767 } 768 769 /** Marks a column that two tables of one query prove. */ 770 private static final TTable AMBIGUOUS = new TTable(); 771 772 /** 773 * The table of {@code block} that proves {@code column}: a table whose known columns include it, a derived table or 774 * CTE naming it in its select or column list, an UNNEST whose value, offset or STRUCT fields are named so. Null 775 * when none does; {@link #AMBIGUOUS} when two do. 776 */ 777 private static TTable provingTable(TSelectSqlStatement block, String column, TSQLEnv sqlEnv) { 778 if (block.tables == null) return null; 779 TTable found = null; 780 for (int i = 0; i < block.tables.size(); i++) { 781 TTable table = block.tables.getTable(i); 782 if ((table == null) || (table.getEffectType() == ETableEffectType.tetSelectInto) 783 || (table.getEffectType() == ETableEffectType.tetImplicitLateralDerivedTable)) { 784 continue; 785 } 786 if (tableNamesColumn(block, table, column, sqlEnv)) { 787 if (found != null) return AMBIGUOUS; 788 found = table; 789 } 790 } 791 return found; 792 } 793 794 private static boolean tableNamesColumn(TSelectSqlStatement block, TTable table, String column, TSQLEnv sqlEnv) { 795 EDbVendor vendor = table.dbvendor; 796 TObjectNameList renamed = ((table.getAliasClause() != null) && (table.getAliasClause().getColumns() != null) 797 && (table.getAliasClause().getColumns().size() > 0)) ? table.getAliasClause().getColumns() : null; 798 if (table.getTableType() == ETableSource.unnest) return unnestNamesColumn(table, column); 799 if ((table.getTableType() == ETableSource.subquery) && (table.getSubquery() != null)) { 800 return derivedNamesColumn(vendor, table.getSubquery(), column, renamed, null); 801 } 802 if (table.isCTEName() && (table.getCTE() != null) && (table.getCTE().getSubquery() != null)) { 803 return derivedNamesColumn(vendor, table.getCTE().getSubquery(), column, renamed, table.getCTE().getColumnList()); 804 } 805 if (!table.isBaseTable()) return false; 806 TSQLTable metadata = tableMetadata(block, table, sqlEnv); 807 return (metadata != null) && metadata.searchColumn(column); 808 } 809 810 /** Whether a derived table, CTE or another source of {@code block} that is not a table may have {@code column}. */ 811 private static boolean sourceMayExposeColumn(TSelectSqlStatement block, String column) { 812 if (block.tables == null) return false; 813 for (int i = 0; i < block.tables.size(); i++) { 814 TTable table = block.tables.getTable(i); 815 if ((table == null) || table.isBaseTable() || (table.getEffectType() == ETableEffectType.tetSelectInto) 816 || (table.getEffectType() == ETableEffectType.tetImplicitLateralDerivedTable)) { 817 continue; 818 } 819 if (table.getTableType() == ETableSource.unnest) { 820 if (unnestMayExposeColumn(table, column)) return true; 821 continue; 822 } 823 TObjectNameList renamed = ((table.getAliasClause() != null) && (table.getAliasClause().getColumns() != null) 824 && (table.getAliasClause().getColumns().size() > 0)) ? table.getAliasClause().getColumns() : null; 825 if ((table.getTableType() == ETableSource.subquery) && (table.getSubquery() != null)) { 826 if (derivedMayExposeColumn(table.dbvendor, table.getSubquery(), column, renamed, null)) return true; 827 continue; 828 } 829 if (table.isCTEName() && (table.getCTE() != null) && (table.getCTE().getSubquery() != null)) { 830 if (derivedMayExposeColumn(table.dbvendor, table.getCTE().getSubquery(), column, renamed, 831 table.getCTE().getColumnList())) return true; 832 continue; 833 } 834 return true; 835 } 836 return false; 837 } 838 839 /** Whether a derived table or CTE names {@code column} among its columns (a star names none). */ 840 private static boolean derivedNamesColumn(EDbVendor vendor, TSelectSqlStatement query, String column, 841 TObjectNameList renamed, TObjectNameList declared) { 842 if ((renamed != null) && namesColumn(vendor, renamed, column)) return true; 843 if ((declared != null) && namesColumn(vendor, declared, column)) return true; 844 TSelectSqlStatement first = query; 845 while ((first != null) && first.isCombinedQuery()) first = first.getLeftStmt(); 846 if ((first == null) || (first.getValueClause() != null) || (first.getResultColumnList() == null)) return false; 847 int skip = Math.max((renamed == null) ? 0 : renamed.size(), (declared == null) ? 0 : declared.size()); 848 for (int i = skip; i < first.getResultColumnList().size(); i++) { 849 TResultColumn resultColumn = first.getResultColumnList().getResultColumn(i); 850 String output = (resultColumn == null) ? null : outputName(resultColumn); 851 if ((output != null) && sameColumn(vendor, output, column)) return true; 852 } 853 return false; 854 } 855 856 /** Whether an UNNEST names {@code column}: its alias column list, alias or value, offset, or STRUCT fields. */ 857 private static boolean unnestNamesColumn(TTable unnest, String column) { 858 EDbVendor vendor = unnest.dbvendor; 859 TAliasClause alias = unnest.getAliasClause(); 860 if ((alias != null) && (alias.getColumns() != null) && (alias.getColumns().size() > 0)) { 861 return namesColumn(vendor, alias.getColumns(), column); 862 } 863 if ((alias != null) && (alias.getAliasName() != null)) { 864 if (sameColumn(vendor, alias.getAliasName().toString(), column)) return true; 865 } else if (sameColumn(vendor, "value", column)) { 866 return true; 867 } 868 TUnnestClause clause = unnest.getUnnestClause(); 869 if (clause == null) return false; 870 if ((clause.getWithOffsetAlais() != null) && (clause.getWithOffsetAlais().getAliasName() != null) 871 && sameColumn(vendor, clause.getWithOffsetAlais().getAliasName().toString(), column)) { 872 return true; 873 } 874 if (clause.getDerivedColumnList() != null) return namesColumn(vendor, clause.getDerivedColumnList(), column); 875 return unnestHasStructField(unnest, column); 876 } 877 878 /** The catalog table of {@code table} as bound, else as the parse reads it ({@code ParseTimeCatalog}, the catalog). */ 879 private static TSQLTable tableMetadata(TSelectSqlStatement block, TTable table, TSQLEnv sqlEnv) { 880 TSQLTable metadata = table.getResolvedTable(); 881 if ((metadata == null) && (sqlEnv != null)) { 882 metadata = gudusoft.gsqlparser.resolver2.metadata.ParseTimeCatalog.searchTable(block, 883 table.getPrefixDatabase(), table.getPrefixSchema(), table.getName()); 884 if (metadata == null) { 885 metadata = sqlEnv.searchTable(nullToEmpty(table.getPrefixDatabase()) + "." 886 + nullToEmpty(table.getPrefixSchema()) + "." + table.getName()); 887 } 888 } 889 return metadata; 890 } 891 892 /** 893 * Whether a derived table or a CTE may have a column {@code columnName}. Its columns are those of the first SELECT 894 * of {@code query}, named in order by {@code renamed} (the reference's alias column list), else by {@code declared} 895 * (the CTE's column list), else by the SELECT: an alias, or the name of a column it reads. False only when every 896 * column's name is known and none is that name; a star, or an expression the vendor names itself, may be anything. 897 */ 898 private static boolean derivedMayExposeColumn(EDbVendor vendor, TSelectSqlStatement query, String columnName, 899 TObjectNameList renamed, TObjectNameList declared) { 900 TSelectSqlStatement first = query; 901 while ((first != null) && first.isCombinedQuery()) first = first.getLeftStmt(); 902 TResultColumnList projection = ((first == null) || (first.getValueClause() != null)) ? null 903 : first.getResultColumnList(); 904 // The number of columns, or -1 when the SELECT does not show it. 905 int width = (projection == null) ? -1 : projection.size(); 906 for (int i = 0; (width >= 0) && (i < projection.size()); i++) { 907 TResultColumn column = projection.getResultColumn(i); 908 TObjectName field = (column == null) ? null : column.getFieldAttr(); 909 boolean star = (field != null) && (field.getPartToken() != null) 910 && (field.getPartToken().tokentype == ETokenType.ttasterisk); 911 boolean several = (column != null) && (column.getAliasClause() != null) 912 && (column.getAliasClause().getColumns() != null) && (column.getAliasClause().getColumns().size() > 0); 913 if ((column == null) || star || several) width = -1; 914 } 915 int listed = Math.max((renamed == null) ? 0 : renamed.size(), (declared == null) ? 0 : declared.size()); 916 int count = Math.max(width, listed); 917 for (int i = 0; i < count; i++) { 918 String name; 919 if ((renamed != null) && (i < renamed.size())) { 920 name = renamed.getObjectName(i).toString(); 921 } else if ((declared != null) && (i < declared.size())) { 922 name = declared.getObjectName(i).toString(); 923 } else { 924 name = (i < width) ? outputName(projection.getResultColumn(i)) : null; 925 if (name == null) return true; 926 } 927 if (sameColumn(vendor, name, columnName)) return true; 928 } 929 return width < 0; 930 } 931 932 /** The name a SELECT gives a column of its result: its alias, or the column it reads; null when the vendor names it. */ 933 private static String outputName(TResultColumn column) { 934 if (column.getAliasClause() != null) { 935 return (column.getAliasClause().getAliasName() == null) ? null 936 : column.getAliasClause().getAliasName().toString(); 937 } 938 TExpression expr = column.getExpr(); 939 if ((expr != null) && (expr.getExpressionType() == EExpressionType.simple_object_name_t) 940 && (expr.getObjectOperand() != null)) { 941 return expr.getObjectOperand().getColumnNameOnly(); 942 } 943 return null; 944 } 945 946 /** 947 * Whether an UNNEST relation may have a column {@code columnName}: the value column its alias names (GSP names it 948 * {@code value} when there is no alias), its offset column, the columns an alias list such as {@code t(x, n)} or the 949 * catalog's STRUCT type gives it, and, while its elements may be STRUCTs, any of their fields. In 950 * {@code ARRAY(SELECT x FROM UNNEST(some_numbers) AS x WHERE 2 IN UNNEST(some_numbers))} over an array of numbers, 951 * the second {@code some_numbers} can only be the enclosing query's column. 952 */ 953 private static boolean unnestMayExposeColumn(TTable unnest, String columnName) { 954 EDbVendor vendor = unnest.dbvendor; 955 TAliasClause alias = unnest.getAliasClause(); 956 if ((alias != null) && (alias.getColumns() != null) && (alias.getColumns().size() > 0)) { 957 return namesColumn(vendor, alias.getColumns(), columnName); 958 } 959 if ((alias != null) && (alias.getAliasName() != null)) { 960 if (sameColumn(vendor, alias.getAliasName().toString(), columnName)) return true; 961 } else if (sameColumn(vendor, "value", columnName)) { 962 return true; 963 } 964 TUnnestClause clause = unnest.getUnnestClause(); 965 if (clause == null) return true; 966 if ((clause.getWithOffsetAlais() != null) && (clause.getWithOffsetAlais().getAliasName() != null) 967 && sameColumn(vendor, clause.getWithOffsetAlais().getAliasName().toString(), columnName)) { 968 return true; 969 } 970 if (clause.getDerivedColumnList() != null) return namesColumn(vendor, clause.getDerivedColumnList(), columnName); 971 java.util.List<String> fields = structFields(clause); 972 if (fields != null) return containsColumn(vendor, fields, columnName); 973 return !hasScalarElements(clause); 974 } 975 976 /** Whether the arrays an UNNEST reads provably hold no STRUCTs, so it has no column but its value and offset. */ 977 private static boolean hasScalarElements(TUnnestClause clause) { 978 if (clause.getArrayExpr() != null) return hasScalarElements(clause.getArrayExpr(), 0); 979 if (clause.getExprList() != null) { 980 if (clause.getExprList().size() == 0) return false; 981 for (int i = 0; i < clause.getExprList().size(); i++) { 982 if (!hasScalarElements(clause.getExprList().getExpression(i), 0)) return false; 983 } 984 return true; 985 } 986 return (clause.getColumns() != null) && (clause.getColumns().size() == 1) 987 && hasScalarElements(clause.getColumns().getObjectName(0), 0); 988 } 989 990 /** 991 * Whether an array expression provably holds no STRUCTs: an array literal of literals, a BigQuery GENERATE_ARRAY, 992 * GENERATE_DATE_ARRAY, GENERATE_TIMESTAMP_ARRAY or SPLIT, or a column a CTE or derived table defines as one. 993 */ 994 private static boolean hasScalarElements(TExpression array, int depth) { 995 if ((array == null) || (depth > 8)) return false; 996 switch (array.getExpressionType()) { 997 case array_t: 998 if ((array.getExprList() == null) || (array.getExprList().size() == 0)) return false; 999 for (int i = 0; i < array.getExprList().size(); i++) { 1000 TExpression element = array.getExprList().getExpression(i); 1001 if ((element.getExpressionType() == EExpressionType.unary_minus_t) 1002 || (element.getExpressionType() == EExpressionType.unary_plus_t)) { 1003 element = element.getRightOperand(); 1004 } 1005 if ((element == null) || (element.getExpressionType() != EExpressionType.simple_constant_t)) return false; 1006 } 1007 return true; 1008 case function_t: 1009 TFunctionCall call = array.getFunctionCall(); 1010 if ((call == null) || (array.dbvendor != EDbVendor.dbvbigquery) || (call.getFunctionName() == null) 1011 || (call.getFunctionName().getSchemaToken() != null)) { 1012 return false; 1013 } 1014 String function = call.getFunctionName().toString(); 1015 return function.equalsIgnoreCase("GENERATE_ARRAY") // non-identifier-compare: built-in function names 1016 || function.equalsIgnoreCase("GENERATE_DATE_ARRAY") // non-identifier-compare: built-in function name 1017 || function.equalsIgnoreCase("GENERATE_TIMESTAMP_ARRAY") // non-identifier-compare: built-in function name 1018 || function.equalsIgnoreCase("SPLIT"); // non-identifier-compare: built-in function name 1019 case simple_object_name_t: 1020 return hasScalarElements(array.getObjectOperand(), depth + 1); 1021 default: 1022 return false; 1023 } 1024 } 1025 1026 /** Whether the column of a CTE or derived table that {@code column} reads is defined as an array of no STRUCTs. */ 1027 private static boolean hasScalarElements(TObjectName column, int depth) { 1028 TExpression definition = definingExpression(column, depth); 1029 return (definition != null) && hasScalarElements(definition, depth + 1); 1030 } 1031 1032 /** The expression that defines the column of a CTE or derived table {@code column} reads, or null. */ 1033 private static TExpression definingExpression(TObjectName column, int depth) { 1034 if ((column == null) || (column.getSourceTable() == null) || (depth > 8)) return null; 1035 TTable source = column.getSourceTable(); 1036 TSelectSqlStatement query = null; 1037 if (source.isCTEName() && (source.getCTE() != null)) { 1038 // a column list renames by position; not followed 1039 if ((source.getCTE().getColumnList() != null) && (source.getCTE().getColumnList().size() > 0)) return null; 1040 query = source.getCTE().getSubquery(); 1041 } else if (source.getTableType() == ETableSource.subquery) { 1042 query = source.getSubquery(); 1043 } 1044 while ((query != null) && query.isCombinedQuery()) query = query.getLeftStmt(); 1045 if ((query == null) || (query.getResultColumnList() == null)) return null; 1046 for (int i = 0; i < query.getResultColumnList().size(); i++) { 1047 TResultColumn resultColumn = query.getResultColumnList().getResultColumn(i); 1048 TExpression expr = resultColumn.getExpr(); 1049 String name = null; 1050 if ((resultColumn.getAliasClause() != null) && (resultColumn.getAliasClause().getAliasName() != null)) { 1051 name = resultColumn.getAliasClause().getAliasName().toString(); 1052 } else if ((expr != null) && (expr.getObjectOperand() != null) 1053 && (expr.getExpressionType() == EExpressionType.simple_object_name_t)) { 1054 name = expr.getObjectOperand().getColumnNameOnly(); 1055 } 1056 if ((name != null) && sameColumn(column.dbvendor, name, column.getColumnNameOnly())) return expr; 1057 } 1058 return null; 1059 } 1060 1061 /** 1062 * Whether an UNNEST relation provably has a column {@code columnName} as a field of the STRUCTs its array holds: 1063 * {@code UNNEST([STRUCT(0 AS a, 1 AS b)])}, or a CTE or derived column defined so, has the columns a and b. 1064 */ 1065 public static boolean unnestHasStructField(TTable unnest, String columnName) { 1066 java.util.List<String> fields = unnestStructFieldNames(unnest); 1067 return (fields != null) && (columnName != null) && containsColumn(unnest.dbvendor, fields, columnName); 1068 } 1069 1070 /** 1071 * The field names of the STRUCTs an UNNEST reads, which are its columns, or null when they are not known or an 1072 * alias column list names its columns instead. Parse-time linking and resolver2's {@code UnnestNamespace} both 1073 * read them here. 1074 */ 1075 public static java.util.List<String> unnestStructFieldNames(TTable unnest) { 1076 if ((unnest == null) || (unnest.getUnnestClause() == null)) return null; 1077 TAliasClause alias = unnest.getAliasClause(); 1078 if ((alias != null) && (alias.getColumns() != null) && (alias.getColumns().size() > 0)) return null; 1079 return structFields(unnest.getUnnestClause()); 1080 } 1081 1082 /** The field names of the STRUCTs an UNNEST reads, or null when they are not known. */ 1083 private static java.util.List<String> structFields(TUnnestClause clause) { 1084 if (clause.getArrayExpr() != null) return structFields(clause.getArrayExpr(), 0); 1085 if (clause.getExprList() != null) { 1086 return (clause.getExprList().size() == 1) ? structFields(clause.getExprList().getExpression(0), 0) : null; 1087 } 1088 if ((clause.getColumns() != null) && (clause.getColumns().size() == 1)) { 1089 TExpression definition = definingExpression(clause.getColumns().getObjectName(0), 0); 1090 return (definition == null) ? null : structFields(definition, 1); 1091 } 1092 return null; 1093 } 1094 1095 /** The field names of an array of STRUCT literals, or of a CTE or derived column defined as one; else null. */ 1096 private static java.util.List<String> structFields(TExpression array, int depth) { 1097 if ((array == null) || (depth > 8)) return null; 1098 switch (array.getExpressionType()) { 1099 case array_t: { 1100 // a typed array literal, ARRAY<STRUCT<x INT64, y STRING>>[(1, 'a')]: its element type names the fields 1101 // (plan 09 slice 11) 1102 java.util.List<String> typed = typedStructFields(array.getTypeName()); 1103 if (typed != null) return typed; 1104 if ((array.getExprList() == null) || (array.getExprList().size() == 0)) return null; 1105 java.util.List<String> fields = null; 1106 for (int i = 0; i < array.getExprList().size(); i++) { 1107 java.util.List<String> elementFields = structLiteralFields(array.getExprList().getExpression(i)); 1108 if (elementFields == null) return null; 1109 if (fields == null) fields = elementFields; 1110 } 1111 return fields; 1112 } 1113 case simple_object_name_t: { 1114 TExpression definition = definingExpression(array.getObjectOperand(), depth); 1115 return (definition == null) ? null : structFields(definition, depth + 1); 1116 } 1117 default: 1118 return null; 1119 } 1120 } 1121 1122 /** The field names a STRUCT element type declares ({@code STRUCT<x INT64, y STRING>}); else null. */ 1123 private static java.util.List<String> typedStructFields(TTypeName type) { 1124 if ((type == null) || (type.getDataType() != EDataType.struct_t) || (type.getColumnDefList() == null) 1125 || (type.getColumnDefList().size() == 0)) { 1126 return null; 1127 } 1128 java.util.List<String> fields = new java.util.ArrayList<>(); 1129 for (int i = 0; i < type.getColumnDefList().size(); i++) { 1130 TColumnDefinition definition = type.getColumnDefList().getColumn(i); 1131 if ((definition == null) || (definition.getColumnName() == null)) return null; 1132 fields.add(definition.getColumnName().toString()); 1133 } 1134 return fields; 1135 } 1136 1137 /** The field names of a STRUCT literal, {@code STRUCT(0 AS a, 1 AS b)} or {@code STRUCT<a INT64>(0)}; else null. */ 1138 private static java.util.List<String> structLiteralFields(TExpression element) { 1139 if ((element == null) || (element.getExpressionType() != EExpressionType.function_t) 1140 || (element.getFunctionCall() == null) 1141 || (element.getFunctionCall().getFunctionType() != EFunctionType.struct_t)) { 1142 return null; 1143 } 1144 TFunctionCall struct = element.getFunctionCall(); 1145 java.util.List<String> fields = new java.util.ArrayList<>(); 1146 if ((struct.getFieldDefs() != null) && (struct.getFieldDefs().size() > 0)) { 1147 for (int i = 0; i < struct.getFieldDefs().size(); i++) { 1148 TColumnDefinition definition = struct.getFieldDefs().getColumn(i); 1149 if ((definition == null) || (definition.getColumnName() == null)) return null; 1150 fields.add(definition.getColumnName().toString()); 1151 } 1152 return fields; 1153 } 1154 if ((struct.getFieldValues() == null) || (struct.getFieldValues().size() == 0)) return null; 1155 for (int i = 0; i < struct.getFieldValues().size(); i++) { 1156 TResultColumn value = struct.getFieldValues().getResultColumn(i); 1157 String name = (value == null) ? null : outputName(value); 1158 if (name == null) return null; 1159 fields.add(name); 1160 } 1161 return fields; 1162 } 1163 1164 private static boolean containsColumn(EDbVendor vendor, java.util.List<String> names, String columnName) { 1165 for (String name : names) { 1166 if (sameColumn(vendor, name, columnName)) return true; 1167 } 1168 return false; 1169 } 1170 1171 private static boolean namesColumn(EDbVendor vendor, TObjectNameList names, String columnName) { 1172 for (int i = 0; i < names.size(); i++) { 1173 TObjectName name = names.getObjectName(i); 1174 if ((name != null) && sameColumn(vendor, name.toString(), columnName)) return true; 1175 } 1176 return false; 1177 } 1178 1179 private static boolean sameColumn(EDbVendor vendor, String a, String b) { 1180 return gudusoft.gsqlparser.util.SQLUtil.compareIdentifier(vendor, ESQLDataObjectType.dotColumn, a, b); 1181 } 1182 1183 /** A catalog table whose columns are all known: an empty list or a star lineage wrote back proves nothing. */ 1184 private static boolean hasAllColumnsKnown(TSQLTable metadata) { 1185 return (metadata != null) && metadata.hasAllColumnsKnown(); 1186 } 1187 1188 private static String nullToEmpty(String s) { 1189 return (s == null) ? "" : s; 1190 } 1191 1192 /** 1193 * Offset clause. 1194 * <br> 1195 * <pre>OFFSET 2 ROWS FETCH NEXT 4 ROWS ONLY;</pre> 1196 * @return {@link TOffsetClause offset clause} 1197 */ 1198 public TOffsetClause getOffsetClause() { 1199 return offsetClause; 1200 } 1201 1202 /** 1203 * Fetch first/next clause 1204 * <br> 1205 * <pre>OFFSET 2 ROWS FETCH NEXT 4 ROWS ONLY;</pre> 1206 * @return {@link TFetchFirstClause fetch first/next clause} 1207 */ 1208 public TFetchFirstClause getFetchFirstClause() { 1209 1210 return fetchFirstClause; 1211 } 1212 1213 private TFetchFirstClause fetchFirstClause; 1214 private TOffsetClause offsetClause; 1215 1216 private TOptionClause optionClause; 1217 1218 /** 1219 * 1220 * @return {@link TOptionClause sql server option clause} 1221 * 1222 * @see gudusoft.gsqlparser.nodes.mssql.TOptionClause 1223 */ 1224 public TOptionClause getOptionClause() { 1225 return optionClause; 1226 } 1227 1228 1229 /** 1230 * 1231 * @return {@link TIsolationClause isolation clause} 1232 */ 1233 public TIsolationClause getIsolationClause() { 1234 return isolationClause; 1235 } 1236 1237 private TIsolationClause isolationClause; 1238 1239// private THiveClusterBy hiveClusterBy; 1240// 1241// /** 1242// * 1243// * @return {@link THiveClusterBy Hive cluster by clause} 1244// */ 1245// public THiveClusterBy getHiveClusterBy() { 1246// return hiveClusterBy; 1247// } 1248 1249 private TSortBy sortBy; 1250 1251 /** 1252 * 1253 * @return {@link TSortBy Hive sort by clause} 1254 */ 1255 public TSortBy getSortBy() { 1256 return sortBy; 1257 } 1258 1259 private TIntoTableClause intoTableClause; 1260 1261 /** 1262 * 1263 * @return {@link TIntoTableClause informix into table clause} 1264 */ 1265 public TIntoTableClause getIntoTableClause() { 1266 return intoTableClause; 1267 } 1268 1269 public void setSelectToken(TSourceToken selectToken) { 1270 this.selectToken = selectToken; 1271 } 1272 1273 /** 1274 * 1275 * @return SELECT token of this query. 1276 */ 1277 public TSourceToken getSelectToken() { 1278 return selectToken; 1279 } 1280 1281 private TSourceToken selectToken = null; 1282 1283 private boolean tableQuery = false; 1284 1285 /** 1286 * Whether this query was written as {@code TABLE t}, the SQL-standard 1287 * shorthand for {@code SELECT * FROM t}. 1288 * <p> 1289 * Such a query is analyzed as {@code SELECT * FROM t}: t is in 1290 * {@link #getTables()} and {@link #getJoins()}, and {@link #getResultColumnList()} 1291 * holds one wildcard result column. That wildcard is synthesized: its tokens 1292 * are not in the source token list, and the text has no SELECT or FROM 1293 * keyword, so code that rewrites the token stream (a formatter) must leave 1294 * the select list and the FROM list of such a query alone. 1295 * 1296 * @return true if this query was written as {@code TABLE t} 1297 */ 1298 public boolean isTableQuery() { 1299 return tableQuery; 1300 } 1301 1302 public static final int SET_OPERATOR_NONE = 0; 1303 1304 public static final int setOperator_union = 1; 1305 public static final int setOperator_unionall = 2; 1306 public static final int SET_OPERATOR_UNIONDISTINCT = 9; 1307 1308 public static final int setOperator_intersect = 3; 1309 public static final int setOperator_intersectall = 4; 1310 public static final int SET_OPERATOR_INTERSECTDISTINCT = 10; 1311 1312 public static final int setOperator_minus = 5; 1313 public static final int setOperator_minusall = 6; 1314 public static final int SET_OPERATOR_MINUSDISTINCT = 11; 1315 1316 public static final int setOperator_except = 7; 1317 public static final int setOperator_exceptall = 8; 1318 public static final int SET_OPERATOR_EXCEPTDISTINCT = 11; 1319 1320 public boolean isAll() { 1321 return all; 1322 } 1323 1324 private boolean all = false; 1325 1326 public boolean isSetOpDistinct() { 1327 return setOpDistinct; 1328 } 1329 1330 private boolean setOpDistinct = false; 1331 private ESetOperatorType setOperatorType = ESetOperatorType.none; 1332 1333 public ESetOperatorType getSetOperatorType() { 1334 return setOperatorType; 1335 } 1336 1337 private TWindowClause windowClause; 1338 1339 /** 1340 * 1341 * @return {@link TWindowClause window clause.} 1342 */ 1343 public TWindowClause getWindowClause() { 1344 return windowClause; 1345 } 1346 1347 private TPTNodeList <TLockingClause> lockingClauses; 1348 1349 /** 1350 * PostgreSQL, for update of, for read only. 1351 * <br> 1352 * @return list of {@link TLockingClause} 1353 */ 1354 public TPTNodeList<TLockingClause> getLockingClauses() { 1355 return lockingClauses; 1356 } 1357 1358 /** 1359 * 1360 * @return {@link TSelectDistinct distinct clause} 1361 */ 1362 public TSelectDistinct getSelectDistinct() { 1363 return selectDistinct; 1364 } 1365 1366 private TSelectDistinct selectDistinct = null; 1367 1368 /** 1369 * 1370 * @return {@link gudusoft.gsqlparser.nodes.TIntoClause into clause} 1371 */ 1372 public TIntoClause getIntoClause() { 1373 return intoClause; 1374 } 1375 1376 private TIntoClause intoClause = null; 1377 1378 1379 private TOrderBy orderbyClause; 1380 1381 /** 1382 * @return {@link TOrderBy order by clause} 1383 */ 1384 public TOrderBy getOrderbyClause() { 1385 return orderbyClause; 1386 } 1387 1388 public TSelectSqlStatement(EDbVendor dbvendor) { 1389 super(dbvendor); 1390 sqlstatementtype = ESqlStatementType.sstselect; 1391 } 1392 1393 void buildsql() { 1394 } 1395 1396 void clear() { 1397 } 1398 1399 String getasprettytext() { 1400 return ""; 1401 } 1402 1403 void iterate(TVisitorAbs pvisitor) { 1404 } 1405 1406 /** 1407 * 1408 * @return {@link TQualifyClause teradata qualify clause} 1409 */ 1410 public TQualifyClause getQualifyClause() { 1411 return qualifyClause; 1412 } 1413 1414 private TQualifyClause qualifyClause = null; 1415 private TSampleClause sampleClause = null; 1416 private TTeradataWithClause teradataWithClause = null; 1417 1418 /** 1419 * @return {@link TTeradataWithClause Teradata with clause } 1420 */ 1421 public TTeradataWithClause getTeradataWithClause() { 1422 return teradataWithClause; 1423 } 1424 1425 /** 1426 * 1427 * @return {@link gudusoft.gsqlparser.nodes.TSampleClause SQL Server sample clause} 1428 */ 1429 public TSampleClause getSampleClause() { 1430 return sampleClause; 1431 } 1432 1433 /** 1434 * @return {@link gudusoft.gsqlparser.nodes.TForUpdate for update clause} 1435 */ 1436 public TForUpdate getForUpdateClause() { 1437 return forUpdateClause; 1438 } 1439 1440 private TForUpdate forUpdateClause; 1441 1442 /** 1443 * 1444 * @return {@link TComputeClause SQL Server compute clause} 1445 */ 1446 public TComputeClause getComputeClause() { 1447 return computeClause; 1448 } 1449 1450 private TComputeClause computeClause = null; 1451 1452 /** 1453 * @return {@link TGroupBy group by clause and having clause} 1454 */ 1455 public TGroupBy getGroupByClause() { 1456 return groupByClause; 1457 } 1458 1459 private TGroupBy groupByClause = null; 1460 1461 1462 /** 1463 * Oracle hierarchical_query_clause 1464 * @return {@link gudusoft.gsqlparser.nodes.THierarchical Oracle hierarchical_query_clause} 1465 */ 1466 public THierarchical getHierarchicalClause() { 1467 return hierarchicalClause; 1468 } 1469 1470 private THierarchical hierarchicalClause = null; 1471 1472 /** 1473 * MySQL,PostgreSQL limit clause 1474 * @return {@link TLimitClause MySQL,PostgreSQL limit clause} 1475 */ 1476 public TLimitClause getLimitClause() { 1477 return limitClause; 1478 } 1479 1480 private TLimitClause limitClause = null; 1481 1482 1483 private TExpandOnClause expandOnClause; 1484 1485 /** 1486 * 1487 * @return {@link TExpandOnClause Teradata expand on clause} 1488 */ 1489 public TExpandOnClause getExpandOnClause() { 1490 return expandOnClause; 1491 } 1492 1493 /** 1494 * 1495 * The set operators UNION, EXCEPT, and INTERSECT correspond to the relational operators union, difference, and intersection. 1496 * @return set operator of this statement.If a set operator is not used, setOperator_none will be returned. 1497 * otherwise, set operand can be fetched by using getLeftStmt() and getRightStmt(). 1498 * 1499 * @deprecated As of v1.6.4.2, use {@link #getSetOperatorType()} and {@link #isAll()} instead. 1500 */ 1501 public int getSetOperator() { 1502 return setOperator; 1503 } 1504 1505 private int setOperator = 0; 1506 1507 /** 1508 * Valid when {@link #getSetOperator} is not setOperator_none. 1509 * @return left side query expression 1510 */ 1511 public TSelectSqlStatement getLeftStmt() { 1512 return leftStmt; 1513 } 1514 1515 public TSelectSqlStatement getFarLeftStmt() { 1516 TSelectSqlStatement current = leftStmt; 1517 while (current.isCombinedQuery()) { 1518 current = current.getLeftStmt(); 1519 } 1520 return current; 1521 } 1522 1523 /** 1524 * Valid when {@link #getSetOperator} is not setOperator_none. 1525 * @return right side query expression. 1526 */ 1527 public TSelectSqlStatement getRightStmt() { 1528 return rightStmt; 1529 } 1530 1531 private TSelectSqlStatement leftStmt; 1532 private TSelectSqlStatement rightStmt; 1533 1534 private TValueClause valueClause = null; 1535 1536 private String oracleHint; 1537 1538 private String hint; 1539 1540 private boolean isValueClause = false; 1541 1542 public boolean isValueClause() { 1543 return isValueClause; 1544 } 1545 1546 /** 1547 * Hint for Oracle and MySQL 1548 * 1549 * @return hint string 1550 */ 1551 public String getHint() { 1552 return hint; 1553 } 1554 1555 /** 1556 * Hint for Oracle and MySQL 1557 * 1558 * @return hint string. 1559 */ 1560 /** 1561 * @deprecated As of 2.0.4.5, replaced by {@link #getHint()} 1562 */ 1563 public String getOracleHint() { 1564 return oracleHint; 1565 } 1566 1567 private THiveHintClause hiveHintClause; 1568 1569 /** 1570 * 1571 * @return {@link THiveHintClause Hive hint clause} 1572 */ 1573 public THiveHintClause getHiveHintClause() { 1574 return hiveHintClause; 1575 } 1576 1577 private THiveTransformClause transformClause; 1578 1579 /** 1580 * 1581 * @return {@link THiveTransformClause Hive from clause} 1582 */ 1583 public THiveTransformClause getTransformClause() { 1584 return transformClause; 1585 } 1586 1587 private TDistributeBy distributeBy; 1588 1589 /** 1590 * 1591 * @return {@link TDistributeBy Hive distribute by clause} 1592 */ 1593 public TDistributeBy getDistributeBy() { 1594 return distributeBy; 1595 } 1596 1597 /** 1598 * DB2 value clause 1599 * @return {@link TValueClause DB2 value clause} 1600 */ 1601 public TValueClause getValueClause() { 1602 return valueClause; 1603 } 1604 1605 public void setChildOfCombinedQuery(boolean childOfCombinedQuery) { 1606 this.childOfCombinedQuery = childOfCombinedQuery; 1607 } 1608 1609 public boolean isChildOfCombinedQuery() { 1610 1611 return childOfCombinedQuery; 1612 } 1613 1614 private boolean childOfCombinedQuery = false; 1615 1616 1617 @Override 1618 public TreeMap<String,TResultColumn> getExpandedResultColumns() { 1619 if (this.setOperatorType == ESetOperatorType.none){ 1620 return super.getExpandedResultColumns(); 1621 }else{ 1622 return this.getLeftStmt().getExpandedResultColumns(); 1623 } 1624 } 1625 1626 private ArrayList<TSelectSqlStatement> flattenSelects = null; 1627 1628 public ArrayList<TSelectSqlStatement> getFlattenedSelects() { 1629 if (!isCombinedQuery()) return null; 1630 if (this.flattenSelects != null) return this.flattenSelects; 1631 1632 this.flattenSelects = new ArrayList<TSelectSqlStatement>(); 1633 this.flattenSelects.add(this.rightStmt); 1634 doFlattenCombinedSelect(this.leftStmt,this.flattenSelects); 1635 1636 Collections.reverse(this.flattenSelects); 1637 return flattenSelects; 1638 } 1639 1640 void doFlattenCombinedSelect(TSelectSqlStatement select, ArrayList<TSelectSqlStatement> container){ 1641 TSelectSqlStatement current = select; 1642 while (current.isCombinedQuery()){ 1643 container.add(current.getRightStmt()); 1644 current = current.getLeftStmt(); 1645 } 1646 container.add(current); 1647 } 1648 1649 /** 1650 * This function is used internal. DON'T call it explicitly. 1651 * 1652 * @param psql input query. 1653 * @return zero means there is no syntax error detected. 1654 */ 1655 public int doParseStatement(TCustomSqlStatement psql) { 1656 if (rootNode == null) return -1; 1657 1658 if ((rootNode instanceof TSelectSqlNode) 1659 && (this.sourcetokenlist.size() == 0)){ 1660 // subquery nested in other statements. 1661 TSelectSqlNode selectNode = (TSelectSqlNode)rootNode; 1662 this.setStartToken(selectNode.getStartToken()); 1663 this.setEndToken(selectNode.getEndToken()); 1664 } 1665 1666 super.doParseStatement(psql); 1667 1668 if (!(rootNode instanceof TSelectSqlNode)) { 1669 return reportInvalidSelectStatement(); 1670 } 1671 1672 TSelectSqlNode selectNode = (TSelectSqlNode)rootNode; 1673 // TABLE t is SELECT * FROM t: give it that FROM list and select list 1674 // before anything reads them, so it is analyzed exactly like that query. 1675 selectNode.expandTableQuery(); 1676 tableQuery = (selectNode.getRelationExpr() != null) && !selectNode.isCombinedQuery(); 1677 if (hasInvalidResultColumnList(selectNode, psql)) { 1678 return reportInvalidSelectStatement(); 1679 } 1680 1681 this.selectToken = selectNode.getSelectToken(); 1682 parenthesisCount = selectNode.getParenthesisCount(); 1683 parenthesisCountBeforeOrder = selectNode.getParenthissisCountBeforeOrder(); 1684 1685 setOperator = selectNode.getSetOperator(); 1686 initSetOperatorFields(); 1687 1688 if(selectNode.isCombinedQuery()){ 1689 TCustomSqlStatement lcParentSql = psql; 1690 if ((lcParentSql == null)||(!childOfCombinedQuery)){ 1691 lcParentSql = this; 1692 } 1693 1694 if (selectNode.cteList != null){ 1695 this.setCteList(selectNode.cteList); 1696 for(int i=0;i<getCteList().size();i++){ 1697 getCteList().getCTE(i).doParse(this,ESqlClause.cte); 1698 } 1699 } 1700 1701 // Oracle 12c WITH FUNCTION/PROCEDURE support 1702 if (selectNode.getWithPlsqlItems() != null){ 1703 this.setWithPlsqlItems(selectNode.getWithPlsqlItems()); 1704 } 1705 1706 // Iterative construction of the left-recursive UNION/INTERSECT/EXCEPT chain. 1707 // This avoids StackOverflow for queries with many set operations (e.g., 2000+ UNION ALL). 1708 // We collect the chain of combined query nodes, set up their properties top-down, 1709 // then process leaf children and clauses from deepest to shallowest. 1710 1711 ArrayList<TSelectSqlStatement> stmtChain = new ArrayList<>(); 1712 ArrayList<TSelectSqlNode> nodeChain = new ArrayList<>(); 1713 1714 stmtChain.add(this); 1715 nodeChain.add(selectNode); 1716 1717 TSelectSqlStatement currentStmt = this; 1718 TSelectSqlNode currentNode = selectNode; 1719 1720 // Walk down the left chain, creating intermediate TSelectSqlStatements 1721 while (currentNode.getLeftNode() != null && currentNode.getLeftNode().isCombinedQuery()) { 1722 TSelectSqlNode leftNode = currentNode.getLeftNode(); 1723 1724 TSelectSqlStatement nextStmt = new TSelectSqlStatement(dbvendor); 1725 nextStmt.rootNode = leftNode; 1726 nextStmt.setChildOfCombinedQuery(true); 1727 1728 // Wire up parent's leftStmt 1729 currentStmt.leftStmt = nextStmt; 1730 1731 // Inline common setup (equivalent of super.doParseStatement + field init) 1732 if (nextStmt.sourcetokenlist.size() == 0) { 1733 nextStmt.setStartToken(leftNode.getStartToken()); 1734 nextStmt.setEndToken(leftNode.getEndToken()); 1735 } 1736 // Equivalent of TCustomSqlStatement.doParseStatement(lcParentSql) 1737 nextStmt.setParentStmt(lcParentSql); 1738 nextStmt.setFrameStack(lcParentSql.getFrameStack()); 1739 lcParentSql.getStmtScope().incrementCurrentStmtIndex(); 1740 nextStmt.setQueryId(String.format("%s#stmt_%d_%s", 1741 lcParentSql.getQueryId(), 1742 lcParentSql.getStmtScope().getCurrentStmtIndex(), 1743 nextStmt.sqlstatementtype)); 1744 nextStmt.setStmtScope(new TStmtScope(lcParentSql.getStmtScope(), nextStmt)); 1745 if (nextStmt.getStartToken() == null && nextStmt.rootNode != null) { 1746 nextStmt.setStartToken(nextStmt.rootNode.getStartToken()); 1747 } 1748 if (nextStmt.getEndToken() == null && nextStmt.rootNode != null) { 1749 nextStmt.setEndToken(nextStmt.rootNode.getEndToken()); 1750 } 1751 if (nextStmt.getGsqlparser() == null && nextStmt.rootNode != null) { 1752 nextStmt.setGsqlparser(nextStmt.rootNode.getGsqlparser()); 1753 } 1754 1755 nextStmt.selectToken = leftNode.getSelectToken(); 1756 nextStmt.parenthesisCount = leftNode.getParenthesisCount(); 1757 nextStmt.parenthesisCountBeforeOrder = leftNode.getParenthissisCountBeforeOrder(); 1758 nextStmt.setOperator = leftNode.getSetOperator(); 1759 nextStmt.initSetOperatorFields(); 1760 1761 stmtChain.add(nextStmt); 1762 nodeChain.add(leftNode); 1763 1764 currentStmt = nextStmt; 1765 currentNode = leftNode; 1766 } 1767 1768 // Create and process the leftmost leaf (non-combined SELECT) 1769 TSelectSqlStatement leftmostLeaf = new TSelectSqlStatement(dbvendor); 1770 leftmostLeaf.rootNode = currentNode.getLeftNode(); 1771 leftmostLeaf.setChildOfCombinedQuery(true); 1772 currentStmt.leftStmt = leftmostLeaf; 1773 leftmostLeaf.doParseStatement(lcParentSql); 1774 1775 // Process right children and clauses from deepest to shallowest 1776 for (int i = stmtChain.size() - 1; i >= 0; i--) { 1777 TSelectSqlStatement stmt = stmtChain.get(i); 1778 TSelectSqlNode node = nodeChain.get(i); 1779 1780 // Create and process right child (always a leaf for left-recursive grammar) 1781 stmt.rightStmt = new TSelectSqlStatement(dbvendor); 1782 stmt.rightStmt.rootNode = node.getRightNode(); 1783 stmt.rightStmt.setChildOfCombinedQuery(true); 1784 stmt.rightStmt.doParseStatement(lcParentSql); 1785 1786 // Handle clauses for this level 1787 if (node.getOrderbyClause() != null) { 1788 node.getOrderbyClause().doParse(stmt, ESqlClause.orderby); 1789 stmt.orderbyClause = node.getOrderbyClause(); 1790 } 1791 stmt.limitClause = node.getLimitClause(); 1792 if (node.getForupdateClause() != null) { 1793 node.getForupdateClause().doParse(stmt, ESqlClause.forUpdate); 1794 stmt.forUpdateClause = node.getForupdateClause(); 1795 } 1796 if (node.getComputeClause() != null) { 1797 node.getComputeClause().doParse(stmt, ESqlClause.compute); 1798 stmt.computeClause = node.getComputeClause(); 1799 } 1800 stmt.optionClause = node.getOptionClause(); 1801 stmt.timeTravel = node.getTimeTravel(); 1802 stmt.hintClause = node.getHintClause(); 1803 } 1804 1805 return 0; 1806 } 1807 1808 if (selectNode.getValueClause() != null){ 1809 // WITH c AS (...) VALUES (...): the rows may read the CTEs, so the list comes first (Mantis 5017); the 1810 // early return below used to drop it 1811 if (selectNode.cteList != null){ 1812 this.setCteList(selectNode.cteList); 1813 this.getCteList().doParse(this,ESqlClause.cte); 1814 } 1815 this.valueClause = selectNode.getValueClause(); 1816 this.valueClause.doParse(this,ESqlClause.selectValue); 1817 isValueClause = true; 1818 return 0; 1819 } 1820 1821 if (selectNode.getTransformClause() != null){ 1822 this.transformClause = selectNode.getTransformClause(); 1823 this.transformClause.doParse(this,ESqlClause.transformClause); 1824 } 1825 1826 if (selectNode.cteList != null){ 1827 this.setCteList(selectNode.cteList); 1828 this.getCteList().doParse(this,ESqlClause.cte); 1829 } 1830 1831 // Oracle 12c WITH FUNCTION/PROCEDURE support 1832 if (selectNode.getWithPlsqlItems() != null){ 1833 this.setWithPlsqlItems(selectNode.getWithPlsqlItems()); 1834 } 1835 1836 if (selectNode.isHiveFromQuery()){ 1837 if(selectNode.getSelectSqlNodes() != null){ 1838 for(int i=1;i<selectNode.getSelectSqlNodes().size();i++){ 1839 //start from the second, the first select statement is represented by this class instance. 1840 1841 TSelectSqlStatement select = new TSelectSqlStatement(EDbVendor.dbvhive); 1842 select.rootNode = selectNode.getSelectSqlNodes().get(i); 1843 select.doParseStatement(this); 1844 this.getMultiSelectStatements().add(select); 1845 } 1846 } 1847 1848 // Hive: from query insert... 1849// if (selectNode.getFromTableList() != null){ 1850// TFromTable lcFromTable; 1851// TJoin lcJoin; 1852// 1853// for(int i=0; i<selectNode.getFromTableList().size();i++){ 1854// lcFromTable = selectNode.getFromTableList().getFromTable(i); 1855// TTable lcTable = null; 1856// 1857// if (lcFromTable.getFromtableType() != ETableSource.join){ 1858// lcJoin = new TJoin(); 1859// lcTable = analyzeFromTable(lcFromTable,true); 1860// lcTable.setEffectType(ETableEffectType.tetSelect); 1861// lcJoin.setTable(lcTable); 1862// lcJoin.setStartToken(lcJoin.getTable().getStartToken()); 1863// lcJoin.setEndToken(lcJoin.getTable().getEndToken()); 1864// lcJoin.setGsqlparser(getGsqlparser()); 1865// }else{ 1866// lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true); 1867// lcJoin.doParse(this, ESqlClause.join); 1868// 1869// if (lcFromTable.getLateralViewList() != null){ 1870// for(TLateralView lateralView:lcFromTable.getLateralViewList()){ 1871// addToTables(lateralView.createATable(this)); 1872// } 1873// } 1874// } 1875// 1876// joins.addJoin(lcJoin); 1877// } 1878// } 1879 1880 1881// if (selectNode.getHiveBodyList() != null){ 1882// for(int i = 0; i<selectNode.getHiveBodyList().size();i++){ 1883// TParseTreeNode node1 = selectNode.getHiveBodyList().get(i); 1884// switch (node1.getNodeType()){ 1885// case TStatementSqlNode.select: 1886// TSelectSqlStatement select = new TSelectSqlStatement(EDbVendor.dbvhive); 1887// select.rootNode = node1; 1888// select.doParseStatement(this); 1889// this.getHiveBodyList().add(select); 1890// 1891// break; 1892// case TStatementSqlNode.insert: 1893// 1894// TInsertSqlStatement insert = new TInsertSqlStatement(EDbVendor.dbvhive); 1895// insert.rootNode = node1; 1896// insert.doParseStatement(this); 1897// this.getHiveBodyList().add(insert); 1898// break; 1899// default: 1900// break; 1901// } 1902// } 1903// } 1904 // return 0; 1905 } 1906 1907 // get oracle hint 1908 if((dbvendor == EDbVendor.dbvoracle)||isMySQLDialect()){ // MySQL includes an OceanBase MySQL tenant (Mantis 4813) 1909 TSourceToken lcnextst = this.selectToken.container.nextsolidtoken(this.selectToken.posinlist,1,true); 1910 while (lcnextst != null){ 1911 if (!((lcnextst.tokentype == ETokenType.ttsimplecomment) || (lcnextst.tokentype == ETokenType.ttbracketedcomment))) break; 1912 1913 if (lcnextst.tokentype == ETokenType.ttbracketedcomment){ 1914 if (lcnextst.toString().startsWith("/*+")){ 1915 //lcnextst.setDbObjType(TObjectName.ttObjOracleHint); 1916 lcnextst.setDbObjectType(EDbObjectType.oracleHint); 1917 if (oracleHint == null){ 1918 oracleHint = lcnextst.toString(); 1919 }else { 1920 oracleHint = oracleHint + " " + lcnextst.toString(); 1921 } 1922 } 1923 } 1924 1925 if (lcnextst.tokentype == ETokenType.ttsimplecomment){ 1926 if (lcnextst.toString().startsWith("--+")){ 1927 //lcnextst.setDbObjType(TObjectName.ttObjOracleHint); 1928 lcnextst.setDbObjectType(EDbObjectType.oracleHint); 1929 if (oracleHint == null){ 1930 oracleHint = lcnextst.toString(); 1931 }else { 1932 oracleHint = oracleHint + " " + lcnextst.toString(); 1933 } 1934 } 1935 } 1936 1937 lcnextst = lcnextst.container.nextsolidtoken(lcnextst,1,true); 1938 } 1939 1940 hint = oracleHint; 1941 } 1942 1943 if (selectNode.getHiveHintClause() != null){ 1944 hiveHintClause = selectNode.getHiveHintClause(); 1945 } 1946 1947 isConsume = selectNode.isConsume(); 1948 1949 if (selectNode.getTopClause() != null){ 1950 selectNode.getTopClause().doParse(this,ESqlClause.top); 1951 this.setTopClause(selectNode.getTopClause()); 1952 } 1953 1954 // this.skipOffset = selectNode.getSkipOffset(); 1955// this.firstMax = selectNode.getFirstMax(); 1956// this.limitMax = selectNode.getLimitMax(); 1957 1958 if (selectNode.getSelectDistinct() != null){ 1959 this.selectDistinct = selectNode.getSelectDistinct(); 1960 } 1961 1962 this.selectModifiers = selectNode.getSelectModifiers(); 1963 1964 TFromTable lcFromTable = null; 1965 TJoin lcJoin = null; 1966 1967 if (selectNode.getFromTableList() != null){ 1968 fromClause = new TFromClause(this.getRelations()); 1969 fromClause.setStartToken(selectNode.getFromTableList().getStartToken()); 1970 fromClause.setEndToken(selectNode.getFromTableList().getEndToken()); 1971 1972 for(int i=0; i<selectNode.getFromTableList().size();i++){ 1973 lcFromTable = selectNode.getFromTableList().getFromTable(i); 1974 lcJoin = analyzeTableOrJoin(lcFromTable); 1975 joins.addJoin(lcJoin); 1976 } 1977 } 1978 1979 // ClickHouse expression-CTEs (WITH <expr> AS ident) are evaluated in 1980 // this statement's own scope, so their column references can only 1981 // link once the FROM clause above has populated tables — the 1982 // cteList.doParse earlier in this method runs before that. 1983 if ((dbvendor == EDbVendor.dbvclickhouse) && (this.getCteList() != null)){ 1984 for(int i=0;i<getCteList().size();i++){ 1985 TCTE lcCte = getCteList().getCTE(i); 1986 if (lcCte.getExpression() != null){ 1987 lcCte.getExpression().doParse(this,ESqlClause.cte); 1988 } 1989 } 1990 } 1991 1992 // Publish the hierarchical clause before the select list is parsed. 1993 // doParse() for the clause itself still runs in its usual place below; 1994 // this only makes getHierarchicalClause() answer truthfully while the 1995 // result columns are being linked, which is when 1996 // TCustomSqlStatement.isOraclePseudoColumnReference() needs to know 1997 // whether CONNECT_BY_ISLEAF / CONNECT_BY_ISCYCLE are pseudocolumns 1998 // here or ordinary identifiers (Mantis #4675). 1999 if (selectNode.getHierarchicalClause() != null){ 2000 this.hierarchicalClause = selectNode.getHierarchicalClause(); 2001 } 2002 2003 if (selectNode.getResultColumnList() != null){ 2004 this.setResultColumnList(selectNode.getResultColumnList()); 2005 2006// if ((this.getResultColumnList().size() > 10) 2007// &&(this.getTables().size() == 1) 2008// &&(this.getTables().getTable(0).getTableType() == ETableSource.subquery) 2009// &&( this.getTables().getTable(0).getSubquery().getResultColumnList().size() == this.getResultColumnList().size() ) 2010// ){ 2011// TTable t0 = this.getTables().getTable(0); 2012// ArrayList<TResultColumn> targetColumnArrayList = this.getResultColumnList().getSortedColumns(); 2013// ArrayList<TResultColumn> sourceColumnArrayList = t0.getSubquery().getResultColumnList().getSortedColumns(); 2014// int i=0; 2015// for(TResultColumn rc:targetColumnArrayList){ 2016// TObjectName targetColumn = rc.getExpr().getObjectOperand(); 2017// TResultColumn sourceResultColumn = sourceColumnArrayList.get(i++); 2018// //TObjectName sourceColumn = sourceResultColumn.getExpr().getObjectOperand(); 2019// if (targetColumn != null){ 2020// //System.out.println(targetColumn+"\t->\t"+sourceResultColumn.getDisplayName()); 2021// targetColumn.setSourceTable(t0); 2022// t0.getLinkedColumns().addObjectName(targetColumn); 2023// targetColumn.setSourceColumn(sourceResultColumn); 2024// sourceResultColumn.getTargetColumns().addObjectName(targetColumn); 2025// } 2026// } 2027// } 2028 2029 selectNode.getResultColumnList().doParse(this,ESqlClause.selectList); 2030 2031 // Slice 73: link DISTINCT ON expression list (PostgreSQL / 2032 // Greenplum `SELECT DISTINCT ON (cols) ...`) so each 2033 // TObjectName inside gets dbObjectType=column and 2034 // sourceTable populated. Without this, the expressions 2035 // remain EDbObjectType.unknown. The legacy column-linker 2036 // (linkColumnToTable) is invoked here via TExpression.doParse; 2037 // resolver-2 picks the same expressions up via the 2038 // TSelectDistinct.acceptChildren descent that slice 73 2039 // also wires up. Tables are populated by the FROM clause 2040 // loop above so column linking has a relation list to 2041 // resolve against. Mirrors the TGroupBy.doParse → 2042 // items.doParse pattern. 2043 if (this.selectDistinct != null 2044 && this.selectDistinct.getExpressionList() != null) { 2045 TExpressionList distinctOnExprList = 2046 this.selectDistinct.getExpressionList(); 2047 for (int i = 0; i < distinctOnExprList.size(); i++) { 2048 TExpression e = distinctOnExprList.getExpression(i); 2049 if (e != null) { 2050 e.doParse(this, ESqlClause.unknown); 2051 } 2052 } 2053 } 2054 2055 for(int i=0;i<selectNode.getResultColumnList().size();i++){ 2056 TResultColumn resultColumn = selectNode.getResultColumnList().getResultColumn(i); 2057 TExpression expression = resultColumn.getExpr(); 2058 String expressionText = expression.toString(); 2059 if (expressionText.endsWith("*")){ 2060 TTable starSourceTable = null; 2061 //System.out.println(resultColumn.toString()+":"+resultColumn.getStartToken().lineNo+","+resultColumn.getStartToken().columnNo); 2062 if (expressionText.startsWith("*")){ 2063 // add all result columns in from tables 2064 for(int j=0;j<getTables().size();j++){ 2065 if (getTables().getTable(j).getTableType() == ETableSource.subquery){ 2066 getExpandedResultColumns().putAll(getTables().getTable(j).getSubquery().getExpandedResultColumns()); 2067 }else{ 2068 // ToDo for real table 2069 } 2070 //System.out.println("\t"+getTables().getTable(j).toString()+",\t"+getTables().getTable(j).getTableType()+",\t"+getTables().getTable(j).isCTEName()); 2071 } 2072 if (getTables().size() == 1){ 2073 starSourceTable = getTables().getTable(0); 2074 } 2075 2076 }else{ 2077 for(int j=0;j<getTables().size();j++){ 2078 if (getTables().getTable(j).getAliasName().equalsIgnoreCase( resultColumn.toString().split("[.]")[0])){ 2079 if (getTables().getTable(j).getTableType() == ETableSource.subquery){ 2080 getExpandedResultColumns().putAll(getTables().getTable(j).getSubquery().getExpandedResultColumns()); 2081 }else{ 2082 // ToDo for real table 2083 } 2084 starSourceTable = getTables().getTable(j); 2085 break; 2086 } 2087 } 2088 } 2089 if (starSourceTable != null) { 2090 TObjectName objectOperand = expression.getObjectOperand(); 2091 if (objectOperand == null) { 2092 return reportInvalidSelectStatement(); 2093 } 2094 objectOperand.setSourceTable(starSourceTable); 2095 } 2096 }else{ 2097 String expandedKey = IdentifierService.normalizeStatic(this.dbvendor, ESQLDataObjectType.dotColumn,resultColumn.getDisplayName()); 2098 if (expandedKey == null){ 2099 return reportInvalidSelectStatement(); 2100 } 2101 getExpandedResultColumns().put(expandedKey,resultColumn); 2102 } 2103 } 2104 } 2105 2106 if (selectNode.getIntoClause() != null){ 2107 this.intoClause = selectNode.getIntoClause(); 2108 this.intoClause.doParse(this,ESqlClause.selectInto); 2109 } 2110 2111 2112 if (selectNode.getWhereCondition() != null){ 2113 selectNode.getWhereCondition().doParse(this,ESqlClause.where); 2114 this.setWhereClause( selectNode.getWhereCondition()); 2115 } 2116 2117 if (selectNode.getHierarchicalClause() != null){ 2118 selectNode.getHierarchicalClause().doParse(this,ESqlClause.hierarchical); 2119 this.hierarchicalClause = selectNode.getHierarchicalClause(); 2120 } 2121 2122 if (selectNode.getGroupByClause() != null){ 2123 selectNode.getGroupByClause().doParse(this,ESqlClause.groupby); 2124 this.groupByClause = selectNode.getGroupByClause(); 2125 } 2126 2127 if (selectNode.getQualifyClause() != null){ 2128 selectNode.getQualifyClause().doParse(this,ESqlClause.qualify); 2129 this.qualifyClause = selectNode.getQualifyClause(); 2130 } 2131 2132 if (selectNode.getSampleClause() != null){ 2133 selectNode.getSampleClause().doParse(this,ESqlClause.sample); 2134 this.sampleClause = selectNode.getSampleClause(); 2135 } 2136 2137 if (selectNode.getExpandOnClause() != null){ 2138 selectNode.getExpandOnClause().doParse(this,ESqlClause.expandOn); 2139 this.expandOnClause = selectNode.getExpandOnClause(); 2140 } 2141 2142 if (selectNode.getWithClause() != null){ 2143 selectNode.getWithClause().doParse(this,ESqlClause.teradataWith); 2144 this.teradataWithClause = selectNode.getWithClause(); 2145 } 2146 2147 if (selectNode.getOrderbyClause() != null){ 2148 selectNode.getOrderbyClause().doParse(this,ESqlClause.orderby); 2149 this.orderbyClause = selectNode.getOrderbyClause(); 2150 } 2151 2152 if (selectNode.getLockingClauses() != null){ 2153 selectNode.getLockingClauses().doParse(this,ESqlClause.lockingClause); 2154 this.lockingClauses = selectNode.getLockingClauses(); 2155 } 2156 2157 this.sortBy = selectNode.getSortBy(); 2158 if (this.sortBy != null){ 2159 this.sortBy.doParse(this,ESqlClause.sortby); 2160 } 2161 2162 this.clusterBy = selectNode.getClusterBy(); 2163 if (this.clusterBy != null){ 2164 this.clusterBy.doParse(this,ESqlClause.cluster); 2165 } 2166 2167 this.windowClause = selectNode.getWindowClause(); 2168 if (this.windowClause != null){ 2169 this.windowClause.doParse(this,ESqlClause.windowClause); 2170 } 2171 this.limitClause = selectNode.getLimitClause(); 2172 if (this.limitClause != null){ 2173 this.limitClause.doParse(this,ESqlClause.limit); 2174 } 2175 2176 if (selectNode.getForupdateClause() != null){ 2177 selectNode.getForupdateClause().doParse(this,ESqlClause.forUpdate); 2178 this.forUpdateClause = selectNode.getForupdateClause(); 2179 } 2180 2181 if (selectNode.getComputeClause() != null){ 2182 selectNode.getComputeClause().doParse(this,ESqlClause.compute); 2183 this.computeClause = selectNode.getComputeClause(); 2184 } 2185 2186 this.intoTableClause = selectNode.getIntoTableClause(); 2187 2188 if (selectNode.getDistributeBy() != null){ 2189 this.distributeBy = selectNode.getDistributeBy(); 2190 this.distributeBy.doParse(this,ESqlClause.distributeBy); 2191 } 2192 2193 2194 this.isolationClause = selectNode.getIsolationClause(); 2195 2196 this.optionClause = selectNode.getOptionClause(); 2197 2198 this.offsetClause = selectNode.getOffsetClause(); 2199 this.fetchFirstClause = selectNode.getFetchFirstClause(); 2200 2201 this.timeTravel = selectNode.getTimeTravel(); 2202 this.hintClause = selectNode.getHintClause(); 2203 2204 if (selectNode.getForXMLClause() != null){ 2205 if (tables.size() > 0){ 2206 tables.getTable(0).setForXMLClause(selectNode.getForXMLClause()); 2207 } 2208 } 2209 2210 // StarRocks pipe operator support 2211 this.pipeOperators = selectNode.getPipeOperators(); 2212 this.isPipeQuery = selectNode.isPipeQuery(); 2213 2214 return 0; 2215 } 2216 2217 private boolean hasInvalidResultColumnList(TSelectSqlNode selectNode, 2218 TCustomSqlStatement psql) { 2219 TResultColumnList resultColumns = selectNode.getResultColumnList(); 2220 if (resultColumns == null) { 2221 return false; 2222 } 2223 2224 for (int i = 0; i < resultColumns.size(); i++) { 2225 TResultColumn resultColumn = resultColumns.getResultColumn(i); 2226 if ((resultColumn == null) || (resultColumn.getExpr() == null)) { 2227 return true; 2228 } 2229 2230 TExpression expression = resultColumn.getExpr(); 2231 String expressionText = expression.toString(); 2232 if (expressionText == null) { 2233 return true; 2234 } 2235 if (!expressionText.endsWith("*") 2236 && (resultColumn.getDisplayName() == null)) { 2237 return true; 2238 } 2239 } 2240 2241 if (((dbvendor == EDbVendor.dbvmssql) 2242 || (dbvendor == EDbVendor.dbvoracle)) 2243 && (psql instanceof TInsertSqlStatement) 2244 && (resultColumns.getEndToken() != null) 2245 && (resultColumns.getEndToken().container != null)) { 2246 TSourceToken resultListEnd = resultColumns.getEndToken(); 2247 TSourceToken nextToken = resultListEnd.container 2248 .nextsolidtoken(resultListEnd, 1, true); 2249 if ((nextToken != null) && (nextToken.tokencode == ',')) { 2250 TSourceToken tokenAfterComma = nextToken.container 2251 .nextsolidtoken(nextToken, 1, true); 2252 if ((tokenAfterComma != null) 2253 && (tokenAfterComma.tokencode == TBaseType.rrw_from)) { 2254 return true; 2255 } 2256 } 2257 } 2258 2259 return false; 2260 } 2261 2262 private int reportInvalidSelectStatement() { 2263 TSourceToken errorToken = rootNode.getStartToken(); 2264 if ((errorToken == null) && (sourcetokenlist.size() > 0)) { 2265 errorToken = sourcetokenlist.get(0); 2266 } 2267 if (errorToken != null) { 2268 parseerrormessagehandle(new TSyntaxError(errorToken, 2269 "invalid SELECT statement", EErrorType.sperror, 2270 TBaseType.MSG_ERROR_SYNTAX_ERROR, this)); 2271 } else { 2272 parseerrormessagehandle(new TSyntaxError("SELECT", 0, 0, 2273 "invalid SELECT statement", EErrorType.sperror, 2274 TBaseType.MSG_ERROR_SYNTAX_ERROR, this, -1)); 2275 } 2276 return TBaseType.MSG_ERROR_SYNTAX_ERROR; 2277 } 2278 2279 /** 2280 * Determine whether The UNION, EXCEPT and INTERSECT operators were used. 2281 * @return true if one of those operators were used. 2282 */ 2283 public boolean isCombinedQuery(){ 2284 // combine multiple queries using the set operators UNION, UNION ALL, INTERSECT, and MINUS. 2285 return (setOperator > 0); 2286 } 2287 2288 /** 2289 * Initialize setOperatorType, all, and setOpDistinct fields from setOperator value. 2290 * Used by doParseStatement's iterative combined query construction. 2291 */ 2292 private void initSetOperatorFields() { 2293 switch (setOperator) { 2294 case SET_OPERATOR_NONE: 2295 setOperatorType = ESetOperatorType.none; all = false; break; 2296 case setOperator_union: 2297 setOperatorType = ESetOperatorType.union; all = false; break; 2298 case setOperator_unionall: 2299 setOperatorType = ESetOperatorType.union; all = true; break; 2300 case SET_OPERATOR_UNIONDISTINCT: 2301 setOperatorType = ESetOperatorType.union; setOpDistinct = true; break; 2302 case setOperator_intersect: 2303 setOperatorType = ESetOperatorType.intersect; all = false; break; 2304 case setOperator_intersectall: 2305 setOperatorType = ESetOperatorType.intersect; all = true; break; 2306 case setOperator_except: 2307 setOperatorType = ESetOperatorType.except; all = false; break; 2308 case setOperator_exceptall: 2309 setOperatorType = ESetOperatorType.except; all = true; break; 2310 case setOperator_minus: 2311 setOperatorType = ESetOperatorType.minus; all = false; break; 2312 case setOperator_minusall: 2313 setOperatorType = ESetOperatorType.minus; all = true; break; 2314 case SET_OPERATOR_INTERSECTDISTINCT: 2315 setOperatorType = ESetOperatorType.intersect; setOpDistinct = true; break; 2316 case SET_OPERATOR_EXCEPTDISTINCT: 2317 setOperatorType = ESetOperatorType.except; setOpDistinct = true; break; 2318 } 2319 } 2320 2321 public void accept(TParseTreeVisitor v) 2322 { 2323 v.preVisit(this); 2324 v.postVisit(this); 2325 } 2326 2327 /** 2328 * Accept visitor to visit this class. 2329 * @param v user defined visitor. 2330 */ 2331 public void acceptChildren(TParseTreeVisitor v) 2332 { 2333 2334 if(this.isCombinedQuery()){ 2335 2336 // Iterative traversal for combined queries to avoid StackOverflow 2337 // on deeply nested left-recursive UNION/INTERSECT/EXCEPT chains. 2338 // Collect the left-recursive chain of combined query nodes. 2339 ArrayList<TSelectSqlStatement> chain = new ArrayList<>(); 2340 TSelectSqlStatement current = this; 2341 while (current.isCombinedQuery()) { 2342 chain.add(current); 2343 current = current.getLeftStmt(); 2344 } 2345 // 'current' is now the leftmost leaf (non-combined SELECT) 2346 2347 // Phase 1: preVisit all combined nodes and their CTEs, from root to deepest 2348 for (int i = 0; i < chain.size(); i++) { 2349 TSelectSqlStatement node = chain.get(i); 2350 v.preVisit(node); 2351 if (node.getCteList() != null) { 2352 node.getCteList().acceptChildren(v); 2353 } 2354 } 2355 2356 // Phase 2: Visit leftmost leaf SELECT 2357 current.acceptChildren(v); 2358 2359 // Phase 3: Visit right branches and postVisit, from deepest to root 2360 for (int i = chain.size() - 1; i >= 0; i--) { 2361 TSelectSqlStatement node = chain.get(i); 2362 node.getRightStmt().acceptChildren(v); 2363 2364 if (node.getOrderbyClause() != null) { 2365 node.getOrderbyClause().acceptChildren(v); 2366 } 2367 if (node.getLimitClause() != null) { 2368 node.getLimitClause().acceptChildren(v); 2369 } 2370 if (node.getForUpdateClause() != null) { 2371 node.getForUpdateClause().acceptChildren(v); 2372 } 2373 if (node.getComputeClause() != null) { 2374 node.getComputeClause().acceptChildren(v); 2375 } 2376 v.postVisit(node); 2377 } 2378 2379 return ; 2380 } 2381 2382 // System.out.println(this.toString().hashCode()+" "+ this.toString().substring(0,50)); 2383 2384 v.preVisit(this); 2385 2386 if (this.getTransformClause() != null){ 2387 this.getTransformClause().acceptChildren(v); 2388 } 2389 2390 if (this.getCteList() != null){ 2391 this.getCteList().acceptChildren(v); 2392 } 2393 2394 if (TBaseType.USE_JOINEXPR_INSTEAD_OF_JOIN){ 2395// fromClause.acceptChildren(v); 2396 v.preVisit(fromClause); 2397 for(TTable table:getRelations()){ 2398 table.acceptChildren(v); 2399 } 2400 v.postVisit(fromClause); 2401 }else{ 2402 if (this.getJoins() != null){ 2403 this.getJoins().acceptChildren(v); 2404 } 2405 } 2406 2407 if (this.getHiveHintClause() != null){ 2408 this.getHiveHintClause().acceptChildren(v); 2409 } 2410 2411 2412 if (this.getTopClause() != null){ 2413 this.getTopClause().acceptChildren(v); 2414 } 2415 2416 if (this.getSelectDistinct() != null){ 2417 this.getSelectDistinct().acceptChildren(v); 2418 } 2419 2420 if (this.getResultColumnList() != null){ 2421 this.getResultColumnList().acceptChildren(v); 2422 } 2423 2424 if (this.getIntoClause() != null){ 2425 this.getIntoClause().acceptChildren(v); 2426 } 2427 2428 2429 if (this.getWhereClause() != null){ 2430 this.getWhereClause().acceptChildren(v); 2431 } 2432 2433 if (this.getHierarchicalClause() != null){ 2434 this.getHierarchicalClause().acceptChildren(v); 2435 } 2436 2437 if (this.getGroupByClause() != null){ 2438 this.getGroupByClause().acceptChildren(v); 2439 } 2440 2441 if (this.getQualifyClause() != null){ 2442 this.getQualifyClause().acceptChildren(v); 2443 } 2444 2445 if (this.getSampleClause() != null){ 2446 this.getSampleClause().acceptChildren(v); 2447 } 2448 2449 if (this.getExpandOnClause() != null){ 2450 this.getExpandOnClause().acceptChildren(v); 2451 } 2452 2453 if (this.getTeradataWithClause() != null){ 2454 this.getTeradataWithClause().acceptChildren(v); 2455 } 2456 2457 if (this.getOrderbyClause() != null){ 2458 this.getOrderbyClause().acceptChildren(v); 2459 } 2460 2461 if (this.getLockingClauses() != null){ 2462 this.getLockingClauses().acceptChildren(v); 2463 } 2464 2465 if (this.getSortBy() != null){ 2466 this.getSortBy().acceptChildren(v); 2467 } 2468 2469 if (this.getClusterBy() != null){ 2470 this.getClusterBy().acceptChildren(v); 2471 } 2472 2473 if (this.getWindowClause() != null){ 2474 this.getWindowClause().acceptChildren(v); 2475 } 2476 2477 if (this.getLimitClause() != null){ 2478 this.getLimitClause().acceptChildren(v); 2479 } 2480 2481 if (this.getForUpdateClause() != null){ 2482 this.getForUpdateClause().acceptChildren(v); 2483 } 2484 2485 if (this.getComputeClause() != null){ 2486 this.getComputeClause().acceptChildren(v); 2487 } 2488 2489 if (this.getIntoTableClause() != null){ 2490 this.getIntoTableClause().acceptChildren(v); 2491 } 2492 2493 if (this.getDistributeBy() != null){ 2494 this.getDistributeBy().acceptChildren(v); 2495 } 2496 2497 if (this.getIsolationClause() != null){ 2498 this.getIsolationClause().acceptChildren(v); 2499 } 2500 2501 if (this.getOptionClause() != null){ 2502 this.getOptionClause().acceptChildren(v); 2503 } 2504 2505 if (this.getOffsetClause() != null){ 2506 this.getOffsetClause().acceptChildren(v); 2507 } 2508 2509 if (this.getFetchFirstClause() != null){ 2510 this.getFetchFirstClause().acceptChildren(v); 2511 } 2512 2513 if (this.getTimeTravel() != null){ 2514 this.getTimeTravel().acceptChildren(v); 2515 } 2516 2517 if (this.getHintClause() != null){ 2518 this.getHintClause().acceptChildren(v); 2519 } 2520 2521 v.postVisit(this); 2522 return ; 2523 2524 }; 2525 2526 /** 2527 * Add an order by clause to this class. 2528 * @param orderByStr new order by string 2529 * @return added order by clause. 2530 */ 2531 public TOrderBy addOrderBy(String orderByStr){ 2532 if (this.getOrderbyClause() != null){ 2533 this.getOrderbyClause().addOrderByItem(orderByStr); 2534 }else{ 2535 2536 TOrderBy orderBy = new TOrderBy(); 2537 orderBy.setGsqlparser(this.getGsqlparser()); 2538 orderBy.setString(" order by "+orderByStr); 2539 this.orderbyClause = orderBy; 2540 TSourceToken last_token = null; 2541 if (this.getGroupByClause() != null){ 2542 last_token = this.getGroupByClause().getEndToken(); 2543 }else if (this.getWhereClause() != null){ 2544 last_token = this.getWhereClause().getEndToken(); 2545 }else{ 2546 last_token = joins.getEndToken(); 2547 } 2548 2549 orderbyClause.addAllMyTokensToTokenList(last_token.container, last_token.posinlist+1); 2550 2551 for(int i=0;i<last_token.getNodesEndWithThisToken().size();i++){ 2552 TParseTreeNode node = last_token.getNodesEndWithThisToken().get(i); 2553 if (node instanceof TSelectSqlStatement) 2554 { 2555 // change all end token of parse tree node except the last order by item 2556 node.setEndToken(orderbyClause.getEndToken()); 2557 } 2558 } 2559 } 2560 2561 return this.getOrderbyClause(); 2562 } 2563 2564 /** 2565 * this function is alias of addWhereClause 2566 * @param condition new condition 2567 * @return new where clause 2568 */ 2569 public TWhereClause addCondition(String condition){ 2570 return addWhereClause(condition); 2571 } 2572 2573 public TWhereClause addConditionOR(String condition){ 2574 return addWhereClauseOR(condition); 2575 } 2576 2577 public TWhereClause addWhereClause(String condition){ 2578 return doAddWhereClause(condition,true); 2579 } 2580 2581 public TWhereClause addWhereClauseOR(String condition){ 2582 return doAddWhereClause(condition,false); 2583 } 2584 2585 protected TWhereClause doAddWhereClause(String condition, boolean isAnd){ 2586 2587 if (this.getWhereClause() != null){ 2588 if (isAnd){ 2589 this.getWhereClause().getCondition().addANDCondition(condition); 2590 }else{ 2591 this.getWhereClause().getCondition().addORCondition(condition); 2592 } 2593 2594 }else{ 2595 TWhereClause whereClause = new TWhereClause(); 2596 whereClause.setGsqlparser(this.getGsqlparser()); 2597 whereClause.setString(" where "+condition); 2598 this.setWhereClause(whereClause); 2599 2600 TSourceToken last_token = null; 2601 TJoin lastjoin = joins.getJoin(joins.size()-1); 2602 if (lastjoin.getJoinItems().size() > 0){ 2603 TJoinItem lastitem = lastjoin.getJoinItems().getJoinItem(lastjoin.getJoinItems().size()-1); 2604 last_token = lastitem.getEndToken(); 2605 }else { 2606 last_token = joins.getEndToken(); 2607 } 2608 2609 whereClause.addAllMyTokensToTokenList(last_token.container, last_token.posinlist+1); 2610 2611 for(int i=0;i<last_token.getNodesEndWithThisToken().size();i++){ 2612 TParseTreeNode node = last_token.getNodesEndWithThisToken().get(i); 2613 if (!((node instanceof TJoinList) 2614 ||(node instanceof TJoin) 2615 ||(node instanceof TJoinItemList) 2616 ||(node instanceof TJoinItem) 2617 )) 2618 { 2619 // change all end token of parse tree node except the last order by item 2620 node.setEndToken(whereClause.getEndToken()); 2621 } 2622 } 2623 2624 } 2625 return this.getWhereClause(); 2626 } 2627 2628 private ArrayList<String> columnsInFromClause = null; 2629 2630 2631 @Override 2632 public TFromClause getFromClause() { 2633 // #todo , select union 类型的 sql 语句,需要穿透到低层的各个 子 select 语句,需要进一步完善 2634 TFromClause ret = super.getFromClause(); 2635 if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){ 2636 return this.getRightStmt().getFromClause(); 2637 }else{ 2638 return ret; 2639 } 2640 } 2641 2642 public TResultColumnList getResultColumnList(boolean useColumnsFromLeftmost) { 2643 TResultColumnList ret = super.getResultColumnList(); 2644 if (ret != null) return ret; 2645 2646 if (isCombinedQuery()){ 2647 if (useColumnsFromLeftmost) { 2648 return this.getFarLeftStmt().getResultColumnList(); 2649 } else { 2650 return this.getRightStmt().getResultColumnList(); 2651 } 2652 } 2653 return ret; 2654 2655 2656// if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){ 2657// return this.getRightStmt().getResultColumnList(); 2658// }else{ 2659// return ret; 2660// } 2661 } 2662 2663 @Override 2664 public TResultColumnList getResultColumnList() { 2665 return getResultColumnList(false); 2666 2667// TResultColumnList ret = super.getResultColumnList(); 2668// if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){ 2669// return this.getRightStmt().getResultColumnList(); 2670// }else{ 2671// return ret; 2672// } 2673 } 2674 2675 public ArrayList<String> getColumnsInFromClause() { 2676 if (columnsInFromClause != null) return columnsInFromClause; 2677 columnsInFromClause = new ArrayList<String>(); 2678 TTable lcTable; 2679 for(int j=0;j<tables.size();j++){ 2680 lcTable = tables.getTable(j); 2681 switch (lcTable.getTableType()){ 2682 case objectname: 2683 break; 2684 case subquery: 2685 TSelectSqlStatement subQuery = lcTable.getSubquery(); 2686 if (subQuery.getResultColumnList() != null) 2687 for(int i=0;i<subQuery.getResultColumnList().size();i++){ 2688 TResultColumn resultColumn = subQuery.getResultColumnList().getResultColumn(i); 2689 String aliasName = null; 2690 if (resultColumn.getAliasClause() != null){ 2691 aliasName = resultColumn.getAliasClause().getAliasName().toString(); 2692 }else{ 2693 if (resultColumn.getExpr().getObjectOperand() != null){ 2694 aliasName = resultColumn.getExpr().getObjectOperand().toString(); 2695 } 2696 } 2697 if (aliasName != null){ 2698 columnsInFromClause.add(TSQLEnv.getObjectName(aliasName)); 2699 } 2700 } 2701 break; 2702 } 2703 } 2704 return columnsInFromClause; 2705 } 2706 2707 public void addColumnInSelectListToSQLEnv(TSQLTable sqlTable){ 2708 2709 if (sqlTable == null) return; 2710 if (this.getValueClause() != null) return; 2711 2712 if (this.getResultColumnList() != null) 2713 for(int i=0;i<this.getResultColumnList().size();i++){ 2714 TResultColumn resultColumn = this.getResultColumnList().getResultColumn(i); 2715 String aliasName = null; 2716 if ((resultColumn.getAliasClause() != null) && (resultColumn.getAliasClause().getAliasName() == null)){ 2717 // A tuple alias of Hive and Spark SQL, stack(...) AS (k, v): a column of each name. 2718 TObjectNameList tupleColumns = resultColumn.getAliasClause().getColumns(); 2719 for (int k = 0; (tupleColumns != null) && (k < tupleColumns.size()); k++){ 2720 sqlTable.addColumn(TSQLEnv.getObjectName(tupleColumns.getObjectName(k).toString())); 2721 } 2722 continue; 2723 } 2724 if (resultColumn.getAliasClause() != null){ 2725 aliasName = resultColumn.getAliasClause().getAliasName().toString(); 2726 }else{ 2727 if (resultColumn.getExpr().getObjectOperand() != null){ 2728 aliasName = resultColumn.getExpr().getObjectOperand().toString(); 2729 } 2730 } 2731 if (aliasName != null){ 2732 TObjectName operand = resultColumn.getAliasClause() == null ? resultColumn.getExpr().getObjectOperand() : null; 2733 if (operand != null && operand.getPartToken() != null 2734 && operand.getPartToken().tokentype == ETokenType.ttasterisk) { 2735 // The view's width is not known here: a star, not a column named *. 2736 sqlTable.addUnresolvedStar(); 2737 } else { 2738 sqlTable.addColumn(TSQLEnv.getObjectName(aliasName)); 2739 } 2740 } 2741 } 2742 } 2743 2744 /** 2745 * search column in the select list 2746 * 2747 * Internal function, DON'T call it explicitly. 2748 * @param pColumn 2749 * @param pMustIn 2750 * @return true if found. 2751 */ 2752 public boolean searchColumnInResultSet(TObjectName pColumn,boolean pMustIn){ 2753 boolean lcResult = false; 2754 int candidateTableCnt = 0; 2755 int numOfColumnStar = 0; 2756 TResultColumn columnStar = null; 2757 2758 2759 2760 TResultColumn c = null; 2761 String lookupKey = IdentifierService.normalizeStatic(this.dbvendor, ESQLDataObjectType.dotColumn,pColumn.getColumnNameOnly()); 2762 if ( (lookupKey != null) && (c= this.getExpandedResultColumns().get(lookupKey)) != null) 2763 { 2764 //System.out.println("Found:"+pColumn.toString()); 2765 pColumn.setSourceColumn(c); 2766 c.getTargetColumns().addObjectName(pColumn); 2767 2768 return true; 2769 }else{ 2770 // System.out.println("NotCatch:"+pColumn.toString()); 2771 } 2772 2773 if (isCombinedQuery()){ 2774 boolean lcResult1;//,lcResult2; 2775 // search column in all select 2776 lcResult1 = getFarLeftStmt().searchColumnInResultSet(pColumn,pMustIn); 2777 if (!lcResult1) 2778 lcResult1 = rightStmt.searchColumnInResultSet(pColumn,pMustIn); 2779 return lcResult1; 2780 } 2781 2782 if (getResultColumnList() == null) return false; 2783 2784 if (pColumn.toString().endsWith("*")){ 2785 // pColumn here is o1.* 2786 // select o1.*, o2.c1 2787 // from (select c123, c345 from some_table) o1, other_table o2 2788 pColumn.setColumnsLinkedToStar(this.getResultColumnList()); 2789 return true; 2790 } 2791 2792 // search columns in select list, skip t.* but count it for later use 2793 for(int i=0;i<getResultColumnList().size();i++){ 2794 TResultColumn lcField = getResultColumnList().getResultColumn(i); 2795 if (lcField.toString().endsWith("*")){ 2796 numOfColumnStar++; 2797 columnStar = lcField; 2798 continue; 2799 } 2800 lcResult = lcField.isMatchedWithResultColumn(this.dbvendor, pColumn); 2801 if (lcResult){ 2802 pColumn.setSourceColumn(lcField); 2803 lcField.getTargetColumns().addObjectName(pColumn); 2804 break; 2805 } 2806 } 2807 2808 if (lcResult) return true; 2809 2810// // search in * column, including t.* and * 2811 for(int i=0;i<getResultColumnList().size();i++){ 2812 TResultColumn lcField = getResultColumnList().getResultColumn(i); 2813 if (lcField.toString().endsWith("*")){ 2814 // search column in t.*, have to check column in table t 2815 String prefixTableName = ""; 2816 if (lcField.toString().endsWith(".*")){ 2817 String[] a = lcField.toString().split("[.]"); 2818 prefixTableName = a[a.length - 2]; 2819 } 2820 for(int j=0;j<tables.size();j++){ 2821 lcResult = tables.getTable(j).searchColumn(this,prefixTableName,pColumn,false); 2822 if (lcResult) { 2823// tables.getTable(j).getLinkedColumns().addObjectName(pColumn); 2824// pColumn.setSourceTable(tables.getTable(j)); 2825 pColumn.setSourceColumn(lcField); 2826 lcField.getTargetColumns().addObjectName(pColumn); 2827 break; 2828 } 2829 } 2830 }else{ 2831 continue; 2832 } 2833 if (lcResult) break; 2834 } 2835 2836 if (lcResult) return true; 2837 2838 if (pMustIn){ 2839 if (tables.size() == 1){ // only a single table in from clause 2840 lcResult = true; 2841 boolean inStarColumn = false; 2842// tables.getTable(0).getLinkedColumns().addObjectName(pColumn); 2843// pColumn.setSourceTable(tables.getTable(0)); 2844 for(int i=0;i<getResultColumnList().size();i++) { 2845 TResultColumn lcField = getResultColumnList().getResultColumn(i); 2846 if (lcField.toString().endsWith("*")) { 2847 String prefixTableName = ""; 2848 if (lcField.toString().endsWith(".*")){ 2849 String[] a = lcField.toString().split("[.]"); 2850 prefixTableName = a[a.length - 2]; 2851 } 2852 tables.getTable(0).searchColumn(this,prefixTableName,pColumn,true); 2853 pColumn.setSourceColumn(lcField); 2854 lcField.getTargetColumns().addObjectName(pColumn); 2855 inStarColumn = true; 2856 break; 2857 } 2858 } 2859 if (!inStarColumn){ 2860 2861 if (!locateVariableOrParameter(pColumn)){ 2862 // check variable before raise error 2863 2864 // raise 2865 TSyntaxError err = new TSyntaxError(pColumn.getStartToken().toString() 2866 ,pColumn.getStartToken().lineNo,pColumn.getStartToken().columnNo 2867 ,String.format("Column %s is not found in subquery",pColumn.toString()) 2868 ,EErrorType.sphint ,TBaseType.MSG_ERROR_COLUMN_NOT_FOUND,this,pColumn.getStartToken().posinlist); 2869 this.parseerrormessagehandle( err); 2870 } 2871 2872 } 2873 }else if (numOfColumnStar == 1){// only a single * column in select list, but more than one table in from clause 2874 2875 pColumn.setSourceColumn(columnStar); 2876 columnStar.getTargetColumns().addObjectName(pColumn); 2877 if (columnStar.toString().endsWith(".*")){ 2878 lcResult = true; 2879 String[] a = columnStar.toString().split("[.]"); 2880 String prefixTableName = a[a.length - 2]; 2881 for(int i=0;i<tables.size();i++){ 2882 if (tables.getTable(i).checkTableByName(prefixTableName)){ 2883 tables.getTable(i).searchColumn(this,prefixTableName,pColumn,true); 2884// tables.getTable(i).getLinkedColumns().addObjectName(pColumn); 2885// pColumn.setSourceTable(tables.getTable(i)); 2886 pColumn.setSourceColumn(columnStar); 2887 columnStar.getTargetColumns().addObjectName(pColumn); 2888 break; 2889 } 2890 } 2891 }else{ 2892 lcResult = false; 2893 // * column, no table prefix, this column can only be in one of tables 2894 for(int i=0;i<tables.size();i++){ 2895 lcResult = tables.getTable(i).searchColumn(this,"",pColumn,false); 2896 //tables.getTable(i).getLinkedColumns().addObjectName(pColumn); 2897 //pColumn.setSourceTable(tables.getTable(i)); 2898 pColumn.setSourceColumn(columnStar); 2899 columnStar.getTargetColumns().addObjectName(pColumn); 2900 } 2901 } 2902 if (!lcResult) { 2903 lcResult = linkToFirstTable(pColumn,0); 2904 } 2905 }else{ 2906 // multi tables in from clause and multi * column in select list. 2907 lcResult = linkToFirstTable(pColumn,0); 2908 } 2909 } 2910 2911 return lcResult; 2912 2913 //if (lcResult) return true; 2914 2915 // From now on, let's search in * column, there maybe more than one * column in the select list, such as t1.*, t2.* 2916// TResultColumn resultColumn = getResultColumnList().getResultColumn(0); 2917// if ((getResultColumnList().size() == 1) &&(resultColumn.toString().equalsIgnoreCase("*") )){ 2918// // search in * or t1.* in the select list 2919// int tableCntInFromClause = 0; 2920// TTable tableInFromClause = null; 2921// for(int i=0;i<tables.size();i++){ 2922// TTable tn = tables.getTable(i); 2923// if (tn.getEffectType() == ETableEffectType.tetTeradataReference) continue; 2924// tableInFromClause = tn; 2925// tableCntInFromClause++; 2926// } 2927// //if (tables.size() == 1){ 2928// if (tableCntInFromClause == 1){ 2929// //TTable t0 = tables.getTable(0); 2930// TTable t0 = tableInFromClause; 2931// 2932// if (t0.isBaseTable()){ 2933// lcResult = fireOnMetaDatabaseTableColumn(t0.getPrefixServer(),t0.getPrefixDatabase(),t0.getPrefixSchema(),t0.getName(),pColumn.getColumnNameOnly()); 2934// if (! lcResult) candidateTableCnt++; 2935// }else{ 2936// if (t0.getTableType() == ETableSource.subquery){ 2937// if (t0.isIncludeColumnAlias()){ 2938// lcResult = t0.searchColumnInAlias(pColumn); 2939// }else{ 2940// lcResult = t0.getSubquery().searchColumnInResultSet(pColumn,pMustIn); 2941// if (! lcResult) candidateTableCnt++; 2942// } 2943// }else if (t0.isCTEName()){ 2944// lcResult = t0.getCTE().searchColumnInResultSet(this,t0,pColumn,pMustIn); 2945// if (! lcResult) candidateTableCnt++; 2946// } 2947// } 2948// if (pMustIn) lcResult = true; 2949// if (lcResult){ 2950// t0.getLinkedColumns().addObjectName(pColumn); 2951// pColumn.setSourceTable(t0); 2952// pColumn.setSourceColumn(resultColumn); 2953// resultColumn.getTargetColumns().addObjectName(pColumn); 2954// } 2955// }else{ // more than one table 2956// candidateTableCnt = 0; 2957// for(int i=0;i<tables.size();i++){ 2958// TTable tn = tables.getTable(i); 2959// if (tn.isBaseTable()){ 2960// lcResult = fireOnMetaDatabaseTableColumn(tn.getPrefixServer(),tn.getPrefixDatabase(),tn.getPrefixSchema(),tn.getName(),pColumn.getColumnNameOnly()); 2961// if (!lcResult) candidateTableCnt++; 2962// }else{ 2963// if (tn.getTableType() == ETableSource.subquery){ 2964// if (tn.isIncludeColumnAlias()){ 2965// lcResult = tn.searchColumnInAlias(pColumn); 2966// }else{ 2967// lcResult = tn.getSubquery().searchColumnInResultSet(pColumn,false); 2968// if (!lcResult) candidateTableCnt++; 2969// } 2970// }else if (tn.isCTEName()){ 2971// lcResult = tn.getCTE().searchColumnInResultSet(this,tn,pColumn,false); 2972// if (!lcResult) candidateTableCnt++; 2973// } 2974// } 2975// 2976// if (lcResult){ 2977// tn.getLinkedColumns().addObjectName(pColumn); 2978// pColumn.setSourceTable(tn); 2979// pColumn.setSourceColumn(resultColumn); 2980// resultColumn.getTargetColumns().addObjectName(pColumn); 2981// break; 2982// } 2983// } 2984// if ((!lcResult) && (pMustIn)) linkToFirstTable(pColumn,candidateTableCnt); 2985// } 2986// // } 2987// } 2988// 2989// if (lcResult) return true; 2990// 2991// // search t.* 2992// //int starColumnPos = 0, 2993// int numOfTableDotStar=0; 2994// for (int i=0;i<getResultColumnList().size();i++){ 2995// if (getResultColumnList().getResultColumn(i).toString().endsWith(".*")){ 2996// numOfTableDotStar++; 2997// } 2998// } 2999// 3000// TResultColumn rc = null; 3001// TTable tn = null; 3002// for (int i=0;i<getResultColumnList().size();i++){ 3003// if (!getResultColumnList().getResultColumn(i).toString().endsWith(".*")) continue; 3004// rc = getResultColumnList().getResultColumn(i); 3005// // starColumnPos = i; 3006// 3007// for (int j=0;j<tables.size();j++){ 3008// if (! tables.getTable(j).equalByName(rc.getPrefixTable())) continue; 3009// tn = tables.getTable(j); 3010// 3011// if (tn.isBaseTable()){ 3012// lcResult = fireOnMetaDatabaseTableColumn(tn.getPrefixServer(),tn.getPrefixDatabase(),tn.getPrefixSchema(),tn.getName(),pColumn.getColumnNameOnly()); 3013// if (!lcResult) candidateTableCnt++; 3014// }else{ 3015// if (tn.getTableType() == ETableSource.subquery){ 3016// if (tn.isIncludeColumnAlias()){ 3017// lcResult = tn.searchColumnInAlias(pColumn); 3018// }else{ 3019// lcResult = tn.getSubquery().searchColumnInResultSet(pColumn,((pMustIn)&&(numOfTableDotStar == 1))); 3020// if (!lcResult) candidateTableCnt++; 3021// } 3022// }else if (tn.isCTEName()){ 3023// lcResult = tn.getCTE().searchColumnInResultSet(this,tn,pColumn,((pMustIn)&&(numOfTableDotStar == 1))); 3024// if (!lcResult) candidateTableCnt++; 3025// } 3026// } 3027// 3028// if (lcResult){ 3029// tn.getLinkedColumns().addObjectName(pColumn); 3030// pColumn.setSourceTable(tn); 3031// pColumn.setSourceColumn(rc); 3032// rc.getTargetColumns().addObjectName(pColumn); 3033// break; 3034// } 3035// } 3036// if (lcResult) break; 3037// } 3038// 3039// if (lcResult) return true; 3040// 3041// if ((pMustIn) && (numOfTableDotStar == 1) && (tn != null)){ 3042// tn.getLinkedColumns().addObjectName(pColumn); 3043// pColumn.setSourceTable(tn); 3044// pColumn.setSourceColumn(rc); 3045// rc.getTargetColumns().addObjectName(pColumn); 3046// lcResult = true; 3047// } 3048// 3049// if (lcResult) return true; 3050// 3051// if ((pMustIn) && (numOfTableDotStar > 0)) lcResult = linkToFirstTable(pColumn,candidateTableCnt); 3052// 3053// if ((pMustIn)&&(!lcResult)) try { 3054// throw new Exception(" column must be found in the select list:"+pColumn.toString()); 3055// } catch (Exception e) { 3056// e.printStackTrace(); 3057// } 3058// 3059// return lcResult; 3060 } 3061 3062 3063}