001package gudusoft.gsqlparser.nodes; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.nodes.mysql.TGroupConcatParam; 005import gudusoft.gsqlparser.nodes.oracle.TListaggOverflow; 006import gudusoft.gsqlparser.nodes.teradata.TDataConversionItem; 007import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType; 008import gudusoft.gsqlparser.sqlenv.TSQLEnv; 009import gudusoft.gsqlparser.sqlenv.TSQLFunction; 010import gudusoft.gsqlparser.util.CollectionUtil; 011import gudusoft.gsqlparser.util.SQLUtil; 012import gudusoft.gsqlparser.util.TBuiltFunctionUtil; 013import gudusoft.gsqlparser.util.functionChecker; 014 015import java.io.BufferedReader; 016import java.io.IOException; 017import java.io.InputStreamReader; 018import java.util.*; 019 020 021/** 022 * Represents the database function, all functions are represented by this class no matter what's type of the function. 023 * Maybe it's a better idea to create the specific sub-class for function with different syntax such as the built-in 024 * function extract, convert, substring and others. We may implement this feature in the later version. 025 * 026 * For the most of functions, the arguments are a lists of {@link gudusoft.gsqlparser.nodes.TExpression}. For other 027 * functions with the different syntax in arguments, please check the detailed information below. 028 * 029 * this class includes function name and arguments. 030 * <br>There are 3 types of functions: 031 * <ul> 032 * <li>Arguments is a list of expressions</li> 033 * <li>Analytic function</li> 034 * <li>Function with specific arguments, such as cast function</li> 035 * </ul> 036 * 037 * 038 * <b>1.Arguments is a list of expressions</b> 039 * <br> 040* function([expr,expr, ...]) 041 * <ul> 042 * <li>function name: {@link #getFunctionName()}</li> 043 * <li>args: {@link #getArgs()}</li> 044 * </ul> 045 * <p> 046 * 047 * <b>2.Analytic function</b> 048 * <br> 049 * Use {@link #getWindowDef()} to get over clause information. 050* <p> 051 * <b>3.Function with specific arguments</b> 052* <p><b>trim</b> 053 * <ul> 054 * <li>type: {@link EFunctionType#trim_t}</li> 055 * <li>arg: {@link #getTrimArgument()}</li> 056 * </ul> 057* <p><b>cast(expr as typename)</b>, 058 * <b>cast(expr as typename [,datatypeAttribute])</b>, 059 * <b>cast(expr as datatypeAttribute)</b> 060 * <ul> 061 * <li>type:{@link EFunctionType#cast_t}</li> 062 * <li>expr: {@link #getExpr1()}</li> 063 * <li>typename: {@link #getTypename()}, datatypeAttribute is included in {@link TTypeName} as well</li> 064 * </ul> 065* 066* 067* <p><b>convert(typename,[null|not null] expr1 [,expr2])</b>, 068 * <ul> 069 * <li>type: {@link EFunctionType#convert_t}</li> 070 * <li>expr1: {@link #getExpr1()}</li> 071 * <li>expr2: {@link #getExpr2()}</li> 072 * <li>typename: {@link #getTypename()}</li> 073 * </ul> 074* 075* <p><b>Teradata ( udf(args) RETURNS data_type )</b>, the RETURNS clause of a function with a 076 * TD_ANYTYPE result; <b>TRYCAST(expr) RETURNS data_type</b> is a {@link EFunctionType#cast_t} 077 * like TRYCAST(expr AS data_type) 078 * <ul> 079 * <li>typename: {@link #getTypename()}, the requested result type</li> 080 * </ul> 081* 082* <p><b>extract([time_token from expr])</b>, 083 * <ul> 084 * <li>type: {@link EFunctionType#extract_t}</li> 085 * <li>expr: {@link #getExpr1()}</li> 086 * <li>time_token: {@link #getExtract_time_token()}</li> 087 * </ul> 088* 089* <p>sql server contains function,<b>contains(in_expr, expr [,langTerm])</b>, 090 * <ul> 091 * <li>type: {@link EFunctionType#contains_t}</li> 092 * <li>expr: {@link #getExpr1()}</li> 093 * <li>in_expr: {@link #getInExpr()}</li> 094 * </ul> 095* 096* 097* <p>sql server freetext,freetext(contain in expr, expr [,langTerm])</p>, 098 * <ul> 099 * <li>type: {@link EFunctionType#freetext_t}</li> 100 * <li>expr: {@link #getExpr1()}</li> 101 * <li>in_expr: {@link #getInExpr()}</li> 102 * </ul> 103* 104 * 105* <p>Oracle Extract(XML): <b>extract(XMLType_instance, XPath_string[,namespace_string])</b>, 106 * <ul> 107 * <li>type: {@link EFunctionType#extractxml_t}</li> 108 * <li>XMLType_instance: {@link #getXMLType_Instance()}</li> 109 * <li>XPath_string: {@link #getXPath_String()}</li> 110 * <li>namespace_string: {@link #getNamespace_String()}</li> 111 * </ul> 112 113* <p> <b>Rank(value,...)</b>, 114 * <ul> 115 * <li>type: {@link EFunctionType#rank_t}</li> 116 * <li>value list {@link #getOrderByList()}</li> 117 * </ul> 118 * 119 * <p>XMLPassingClause of XMLExists function</p> 120 * <ul> 121 * <li>type: {@link EFunctionType#xmlexists_t}</li> 122 * <li>value list {@link #getPassingClause()}</li> 123 * </ul> 124 * 125*/ 126public class TFunctionCall extends TParseTreeNode{ 127 128 protected TExpression filterClause; 129 130 /** 131 * spark sql filter clause, postgresql filter clause 132 * 133 * <pre> 134 * SELECT COUNT(*) FILTER (WHERE bid_amount_value < 10000) AS low_range_bid_count_value FROM A 135 * </pre> 136 * 137 * @return 138 */ 139 public TExpression getFilterClause() { 140 return filterClause; 141 } 142 143 public void setFilterClause(TWhereClause filterClause) { 144 if (filterClause == null) return; 145 this.filterClause = filterClause.getCondition(); 146 } 147 148 public void setFilterClause(TDummy filterClause) { 149 if (filterClause == null) return; 150 this.setFilterClause((TWhereClause)filterClause.node1); 151 } 152 153 154 private TIndirection indirection; 155 156 public void setIndirection(TIndirection indirection) { 157 this.indirection = indirection; 158 } 159 160 /** 161 * The expressions inside the subscripts after this call, {@code split(s, ':')[n]}: column references that 162 * TSQLResolver2 and the lineage analyzer read like any other (Mantis 4817). Empty without a subscript. 163 * 164 * @return the subscript expressions, never null 165 */ 166 public java.util.List<TExpression> getSubscriptExpressions() { 167 if (indirection == null) return java.util.Collections.<TExpression>emptyList(); 168 return indirection.getSubscriptExpressions(); 169 } 170 171 /** 172 * databricks, current_version().dbsql_version; 173 * @return 174 */ 175 public TIndirection getIndirection() { 176 return indirection; 177 } 178 179 180 final static Map<EDbVendor, Map<String, Set<String>>> tableFunctionMap = new HashMap<EDbVendor, Map<String, Set<String>>>(); 181 static { 182 tableFunctionMap.put(EDbVendor.dbvmssql, loadTableFunctions(EDbVendor.dbvmssql)); 183 tableFunctionMap.put(EDbVendor.dbvoracle, loadTableFunctions(EDbVendor.dbvoracle)); 184 } 185 186 private static Map<String, Set<String>> loadTableFunctions(EDbVendor vendor) { 187 Map<String, Set<String>> tableFunctionInfoMap = new HashMap<String, Set<String>>(); 188 try { 189 BufferedReader reader = new BufferedReader(new InputStreamReader(TFunctionCall.class.getResourceAsStream( 190 "/gudusoft/gsqlparser/tablefunction/" + vendor.name().replace("dbv", "") + ".txt"))); 191 String line; 192 while ((line = reader.readLine()) != null) { 193 String[] tableFunctionInfo = line.toUpperCase(Locale.ROOT).split("\\s*,\\s*"); 194 if (tableFunctionInfo.length > 1) { 195 tableFunctionInfoMap.put(tableFunctionInfo[0], 196 CollectionUtil.convertArraysToSet(tableFunctionInfo)); 197 tableFunctionInfoMap.get(tableFunctionInfo[0]).remove(tableFunctionInfo[0]); 198 } 199 } 200 } catch (IOException e) { 201 e.printStackTrace(); 202 } 203 return tableFunctionInfoMap; 204 } 205 206 private ArrayList<TDataConversionItem> dataConversionItems; 207 208 public void setDataConversionItems(ArrayList<TDataConversionItem> dataConversionItems) { 209 this.dataConversionItems = dataConversionItems; 210 } 211 212 public ArrayList<TDataConversionItem> getDataConversionItems() { 213 return dataConversionItems; 214 } 215 216 private TListaggOverflow listaggOverflow; 217 218 public void setListaggOverflow(TListaggOverflow listaggOverflow) { 219 this.listaggOverflow = listaggOverflow; 220 } 221 222 public TListaggOverflow getListaggOverflow() { 223 return listaggOverflow; 224 } 225 226 public void setFirstArgAsDateTimePart(int pos){ 227 if (this.getArgs() == null) return; 228 if (this.getArgs().size()<=pos) return; 229 TExpression expression = this.getArgs().getExpression(pos); 230 if (expression.getObjectOperand() != null){ 231 expression.getObjectOperand().setDbObjectType(EDbObjectType.date_time_part); 232 } 233 } 234 public int isColumnInThisTableFunction(TSQLEnv sqlEnv, EDbVendor dbVendor, TObjectName pColumn) { 235 int ret = TBaseType.COLUMN_IN_TABEL_FUNCTION_NOTSURE; 236 String functionNameKey = this.getFunctionName().toString().toUpperCase(Locale.ROOT); 237 functionNameKey = functionNameKey.substring(functionNameKey.lastIndexOf('.') + 1); 238 Map<String, Set<String>> tableFunctionInfoMap = tableFunctionMap.get(dbVendor); 239 if (tableFunctionInfoMap != null && tableFunctionInfoMap.containsKey(functionNameKey)) { 240 if (tableFunctionInfoMap.get(functionNameKey).contains(SQLUtil.getIdentifierNormalName(dbVendor, pColumn.getColumnNameOnly(), ESQLDataObjectType.dotColumn).toUpperCase(Locale.ROOT))) { 241 ret = TBaseType.COLUMN_IN_TABEL_FUNCTION_YES; 242 } else { 243 ret = TBaseType.COLUMN_IN_TABEL_FUNCTION_NO; 244 } 245 } 246 else if(this.functionType == EFunctionType.udf_t && sqlEnv!=null){ 247 TSQLFunction functionDef = sqlEnv.searchFunction(this.getFunctionName().toString()); 248 if (functionDef == null) { 249 // A function the catalog does not know has columns nobody knows either (Mantis 4797). 250 ret = TBaseType.COLUMN_IN_TABEL_FUNCTION_NOTSURE; 251 } 252 else if(functionDef.searchColumnInReturnTable(pColumn.getColumnNameOnly())){ 253 ret = TBaseType.COLUMN_IN_TABEL_FUNCTION_YES; 254 } 255 else { 256 ret = TBaseType.COLUMN_IN_TABEL_FUNCTION_NO; 257 } 258 } 259 else { 260 ret = TBaseType.COLUMN_IN_TABEL_FUNCTION_NOTSURE; 261 } 262 263 return ret; 264 } 265 266 protected TWithinGroup withinGroup; 267 268 public void setWithinGroup(TWithinGroup withinGroup) { 269 this.withinGroup = withinGroup; 270 } 271 272 public TWithinGroup getWithinGroup() { 273 return withinGroup; 274 } 275 276 public void setIntervalUnit(String intervalUnit) { 277 this.intervalUnit = intervalUnit; 278 } 279 280 public String getIntervalUnit() { 281 return intervalUnit; 282 283 } 284 285 private String intervalUnit; 286 287 private TExpression stringExpr; 288 289 public void setStringExpr(TExpression stringExpr) { 290 this.stringExpr = stringExpr; 291 } 292 293 /** 294 * DB2 listagg function 295 * @return the first argument of the listagg function 296 */ 297 public TExpression getStringExpr() { 298 return stringExpr; 299 } 300 301 private TExpression separatorExpr; 302 303 public void setSeparatorExpr(TExpression separatorExpr) { 304 this.separatorExpr = separatorExpr; 305 } 306 307 /** 308 * DB2 listagg function. 309 * @return the second argument of the listagg function. 310 */ 311 public TExpression getSeparatorExpr() { 312 313 return separatorExpr; 314 } 315 316 private TExpression searchCondition; 317 318 /** 319 * contains search condition. or freetext_string in freetext predicate 320 * 321 * @param searchCondition contains search condition. 322 */ 323 public void setSearchCondition(TExpression searchCondition) { 324 this.searchCondition = searchCondition; 325 } 326 327 /** 328 * contains search condition. It usually a string constant or a variable. 329 * SQL Server contains predicate. 330 * <pre> 331 * CONTAINS ( 332 * { 333 * column_name | ( column_list ) 334 * | * 335 * | PROPERTY ( { column_name }, 'property_name' ) 336 * } 337 * , '<contains_search_condition>' 338 * [ , LANGUAGE language_term ] 339 * ) 340 *</pre> 341 * 342 * Or freetext_string in freetext predicate 343 * <pre> 344 * FREETEXT ( { column_name | (column_list) | * } 345 * , 'freetext_string' [ , LANGUAGE language_term ] ) 346 * </pre> 347 * 348 * @return contains search condition 349 */ 350 public TExpression getSearchCondition() { 351 352 return searchCondition; 353 } 354 355 private TExpression columnNameOrListExpression; 356 357 /** 358 * set column name or column list of SQL Server contains predicate or freetext predicate 359 * 360 * @param columnNameOrListExpression column name or column list 361 * @see #getColumnNameOrListExpression 362 */ 363 public void setColumnNameOrListExpression(TExpression columnNameOrListExpression) { 364 this.columnNameOrListExpression = columnNameOrListExpression; 365 } 366 367 /** 368 * get column name or column list in SQL Server contains predicate. 369 * <pre> 370 * CONTAINS ( 371 * { 372 * column_name | ( column_list ) 373 * | * 374 * | PROPERTY ( { column_name }, 'property_name' ) 375 * } 376 * , '<contains_search_condition>' 377 * [ , LANGUAGE language_term ] 378 * ) 379 *</pre> 380 * Or column name or column list in freetext predicate 381 * <pre> 382 * FREETEXT ( { column_name | (column_list) | * } 383 * , 'freetext_string' [ , LANGUAGE language_term ] ) 384 * </pre> 385 * 386 * If this expression represents a column name, then the type of this expression is {@link gudusoft.gsqlparser.EExpressionType#simple_object_name_t}, 387 * if this expression represents a column list, then the type of this expression is {@link gudusoft.gsqlparser.EExpressionType#list_t}, 388 * 389 * 390 * @return column name or column list 391 */ 392 public TExpression getColumnNameOrListExpression() { 393 394 return columnNameOrListExpression; 395 } 396 397 private TExpression startExpression; 398 private TExpression lengthExpression; 399 400 /** 401 * set a start expression that specifies the position within {@link #getSourceExpression} that is to be the first 402 * string unit of the result in substring function. 403 * <pre> 404 * substring(sourceExpression from startExpression [for lengthExpression]) 405 * substring(sourceExpression , startExpression [, lengthExpression]) 406 * </pre> 407 * 408 * @param startExpression an expression that specifies the position within {@link #getSourceExpression} 409 * that is to be the first string unit of the result in substring function 410 * @see #getStartExpression 411 */ 412 public void setStartExpression(TExpression startExpression) { 413 this.startExpression = startExpression; 414 } 415 416 /** 417 * set the length expression in substring function. 418 * <pre> 419 * substring(sourceExpression from startExpression [for lengthExpression]) 420 * substring(sourceExpression , startExpression [, lengthExpression]) 421 * </pre> 422 * 423 * @param lengthExpression the length expression in substring function. 424 * @see #getLengthExpression 425 */ 426 public void setLengthExpression(TExpression lengthExpression) { 427 this.lengthExpression = lengthExpression; 428 } 429 430 /** 431 * A start expression that specifies the position within {@link #getSourceExpression} that is to be the first 432 * string unit of the result in substring function. 433 * <p>substring</p> 434 * <pre> 435 * substring(sourceExpression from startExpression [for lengthExpression]) 436 * substring(sourceExpression , startExpression [, lengthExpression]) 437 * </pre> 438 * 439 * @return an expression that specifies the position within {@link #getSourceExpression} that is to be the first 440 * string unit of the result. 441 */ 442 public TExpression getStartExpression() { 443 444 return startExpression; 445 } 446 447 /** 448 * The length of the {@link #getSourceExpression} string unit to be returned in substring function. 449 * <p>substring</p> 450 * <pre> 451 * substring(sourceExpression from startExpression [for lengthExpression]) 452 * substring(sourceExpression , startExpression [, lengthExpression]) 453 * </pre> 454 * 455 * @return the length of the string unit to be returned. 456 */ 457 public TExpression getLengthExpression() { 458 return lengthExpression; 459 } 460 461 private TExpression sourceExpression; 462 463 /** 464 * set an expression that specifies the string from which the result is derived in substring function. 465 * <pre> 466 * substring(sourceExpression from startExpression [for lengthExpression]) 467 * substring(sourceExpression , startExpression [, lengthExpression]) 468 * </pre> 469 * 470 * @param sourceExpression An expression that specifies the string from which the result is derived 471 * @see #getSourceExpression 472 */ 473 public void setSourceExpression(TExpression sourceExpression) { 474 this.sourceExpression = sourceExpression; 475 } 476 477 /** 478 * An expression that specifies the string from which the result is derived in substring function. 479 * <p>substring: DB2</p> 480 * <pre> 481 * substring(sourceExpression from startExpression [for lengthExpression]) 482 * substring(sourceExpression , startExpression [, lengthExpression]) 483 * </pre> 484 * 485 * @return An expression that specifies the string from which the result is derived 486 */ 487 public TExpression getSourceExpression() { 488 489 return sourceExpression; 490 } 491 492 private TExpression typeExpression; 493 494 /** 495 * a structured type expression in DB2 subtype-treatment: treat. 496 * 497 * @param typeExpression a structured type expression 498 * @see #getTypeExpression 499 */ 500 public void setTypeExpression(TExpression typeExpression) { 501 this.typeExpression = typeExpression; 502 } 503 504 /** 505 * A structured type expression in subtype-treatment. 506 * <p>treat function: DB2, Greenplum</p> 507 * 508 * @return a structured type expression 509 */ 510 public TExpression getTypeExpression() { 511 512 return typeExpression; 513 } 514 515 private TExpression castOperand; 516 517 /** 518 * cast specification, set the first operand in the cast specification 519 * 520 * @param castOperand set the first operand in the cast specification 521 * @see #getCastOperand 522 */ 523 public void setCastOperand(TExpression castOperand) { 524 this.castOperand = castOperand; 525 } 526 527 /** 528 * The first operand in the cast specification. 529 * <p>cast specification: DB2, Greenplum,SQL Server; try_cast function of SQL Server</p> 530 * 531 * @return The first operand in the cast specification 532 */ 533 public TExpression getCastOperand() { 534 535 return castOperand; 536 } 537 538 private TExpression dateExpression; 539 540 /** 541 * set date, time or timestamp expression in extract/extend function. 542 * 543 * @param dateExpression date, time or timestamp expression 544 * @see #getDateExpression 545 */ 546 public void setDateExpression(TExpression dateExpression) { 547 this.dateExpression = dateExpression; 548 } 549 550 /** 551 * date, time or timestamp expression in extract function of DB2, Greenplum. 552 * <p> 553 * datetime or date value expression in extend function of informix. 554 * </p> 555 * 556 * @return date, time or timestamp expression 557 */ 558 public TExpression getDateExpression() { 559 return dateExpression; 560 } 561 562 private TExpressionCallTarget callTarget; 563 564 /** 565 * set expressionCallTarget 566 * 567 * @param callTarget expression call target 568 * @see #getCallTarget 569 */ 570 public void setCallTarget(TExpressionCallTarget callTarget) { 571 this.callTarget = callTarget; 572 } 573 574 /** 575 * get an xml type column, parameter, variable or subquery. 576 * <pre> 577 * DECLARE @myDoc xml 578 * DECLARE @ProdID int 579 * SET @myDoc = '<Root> 580 * <ProductDescription ProductID="1" ProductName="Road Bike"> 581 * <Features> 582 * <Warranty>1 year parts and labor </Warranty> 583 * <Maintenance>3 year parts and labor extended maintenance is available </Maintenance> 584 * </Features> 585 * </ProductDescription> 586 * </Root>' 587 * SET @ProdID = @myDoc.value('(/Root/ProductDescription/@ProductID)[1]', 'int' ) 588 * SELECT @ProdID 589 * </pre> 590 * 591 * the value returned by this method represents <code>@myDoc</code> before the value() function. 592 * 593 * SQL Server value() Method performs an XQuery against the XML and returns a value of SQL type. 594 * <p></p> 595 * You typically use this method to extract a value from an XML instance stored in an xml type 596 * column, parameter, or variable. 597 * 598 * @return expressionCallTarget that represents an xml type column, parameter, variable or subquery 599 */ 600 public TExpressionCallTarget getCallTarget() { 601 602 return callTarget; 603 } 604 605 private TGroupConcatParam groupConcatParam; 606 607 public void setGroupConcatParam(TGroupConcatParam groupConcatParam) { 608 this.groupConcatParam = groupConcatParam; 609 } 610 611 public TGroupConcatParam getGroupConcatParam() { 612 613 return groupConcatParam; 614 } 615 616 public static boolean isBuiltIn(String pName, EDbVendor pDBVendor){ 617 List<String> avVersions = functionChecker.getAvailableDbVersions(pDBVendor); 618 if (avVersions == null || avVersions.isEmpty()) { 619 return false; 620 } 621 return functionChecker.isBuiltInFunction(pName,pDBVendor,avVersions.get(avVersions.size()-1)); 622 } 623 624 private boolean isCheckedBuiltIn = false; 625 private boolean isBuiltIn = false; 626 627 public boolean isBuiltIn(EDbVendor pDBVendor) { 628 if (isCheckedBuiltIn) return isBuiltIn; 629 List<String> avVersions = functionChecker.getAvailableDbVersions(pDBVendor); 630 if (avVersions == null || avVersions.isEmpty()) { 631 isBuiltIn = false; 632 } else { 633 isBuiltIn = functionChecker.isBuiltInFunction(this.functionName.toString(),pDBVendor,avVersions.get(avVersions.size()-1)); 634 } 635 isCheckedBuiltIn = true; 636 return isBuiltIn; 637 } 638 639 private TXMLPassingClause passingClause; 640 641 public void setPassingClause(TXMLPassingClause passingClause) { 642 this.passingClause = passingClause; 643 } 644 645 /** 646 * XMLPassingClause of XMLExists function 647 * @return XMLPassingClause of XMLExists function 648 */ 649 public TXMLPassingClause getPassingClause() { 650 return passingClause; 651 } 652 653 private EAggregateType aggregateType = EAggregateType.none; 654 655 /** 656 * set <code>ALL | DISTINCT | UNIQUE</code> keywords used in an aggregate function. 657 * 658 * @param aggregateType 659 * @see #getAggregateType 660 */ 661 public void setAggregateType(EAggregateType aggregateType) { 662 this.aggregateType = aggregateType; 663 } 664 665 /** 666 * get <code>ALL | DISTINCT | UNIQUE</code> keywords used in an aggregate function. 667 * An aggregate function performs a calculation on a set of values, and returns a single value. 668 * 669 * @return aggregate type, one of those values: none,all,distinct,unique 670 */ 671 public EAggregateType getAggregateType() { 672 673 return aggregateType; 674 } 675 676 private TOrderByItemList orderByList; 677 678 public void setOrderByList(TOrderByItemList orderByList) { 679 this.orderByList = orderByList; 680 } 681 682 /** 683 * arguments in rank(value,...) function. 684 * @return a list of {@link TOrderByItem} in function: rank, csum 685 */ 686 public TOrderByItemList getOrderByList() { 687 688 return orderByList; 689 } 690 691 private TOrderBy sortClause; 692 693 public void setSortClause(TOrderBy sortClause) { 694 this.sortClause = sortClause; 695 } 696 697 /** 698 * ORDER BY inside the argument list of an aggregate, such as 699 * {@code LIST(x, ',' ORDER BY y)} (SQL Anywhere, Sybase IQ) or {@code string_agg(x, ',' ORDER BY y)}. 700 * Its keys are resolved like the arguments of the call, not with the select-list alias rule of a 701 * statement ORDER BY. 702 * @return the ORDER BY clause, or null when the function has none 703 */ 704 public TOrderBy getSortClause() { 705 706 return sortClause; 707 } 708 709 /** 710 * Over clause of analytic function 711 * @return over clause 712 */ 713 public TWindowDef getWindowDef() { 714 return windowDef; 715 } 716 717 public void setWindowDef(TWindowDef windowDef) { 718 719 this.windowDef = windowDef; 720 } 721 722 public void setFunctionOptionsWithDummy(TDummy dummy){ 723 if (dummy == null) return; 724 if (dummy.node2 != null){ 725 setWindowDef((TWindowDef)dummy.node2 ); 726 } 727 if (dummy.node3 != null){ 728 setWithinGroup((TWithinGroup) dummy.node3); 729 } 730 } 731 732 protected TWindowDef windowDef; 733 734// public void setWindowSpecification(TWindowDef windowSpecification) { 735// this.windowSpecification = windowSpecification; 736// } 737 738 /** 739 * @deprecated As of v1.8.6.0, replaced by {@link #windowDef} 740 */ 741 private TWindowSpecification windowSpecification; 742 743 private TDatatypeAttribute datatypeAttribute = null; 744 745 public TWindowSpecification getWindowSpecification() { 746 return windowSpecification; 747 } 748 749 /** 750 * Not used. 751 * 752 * @param datatypeAttribute datatype attribute 753 */ 754 public void setDatatypeAttribute(TDatatypeAttribute datatypeAttribute) { 755 this.datatypeAttribute = datatypeAttribute; 756 } 757 758 /** 759 * Not used. 760 * 761 * @return datatype attribute 762 */ 763 public TDatatypeAttribute getDatatypeAttribute() { 764 765 return datatypeAttribute; 766 } 767 768 /** 769 * one of the YEAR/MONTH/DAY, HOUR/MINUTE/SECOND keywords in extract function 770 * 771 * @return one of the YEAR/MONTH/DAY, HOUR/MINUTE/SECOND keywords in extract function 772 */ 773 public TSourceToken getExtract_time_token() { 774 return extract_time_token; 775 } 776 777 778 /** 779 * set one of the YEAR/MONTH/DAY, HOUR/MINUTE/SECOND keyword in extract function 780 * 781 * @param extract_time_token one of the YEAR/MONTH/DAY, HOUR/MINUTE/SECOND token 782 */ 783 public void setExtract_time_token(TSourceToken extract_time_token) { 784 this.extract_time_token = extract_time_token; 785 } 786 787 788 private TDummy dummy = null; 789 790 /** 791 * Set value for temporary use only 792 * 793 * @param dummy a temporary value from parse tree 794 */ 795 public void setDummy(TDummy dummy) { 796 this.dummy = dummy; 797 } 798 799 /** 800 * Not used 801 * 802 * @return a temporary value 803 */ 804 public TDummy getDummy() { 805 806 return dummy; 807 } 808 809 public void setInExpr(TInExpr inExpr) { 810 this.inExpr = inExpr; 811 } 812 813 public TInExpr getInExpr() { 814 815 return inExpr; 816 } 817 818 private TInExpr inExpr = null; //sql server, used in fntContains, fntFreetext 819 820 public void setExtractXMLArg(TExpressionList exprList){ 821 if (exprList.size() > 1){ 822 this.XMLType_Instance = exprList.getExpression(0); 823 this.XPath_String = exprList.getExpression(1); 824 } 825 826 if (exprList.size() > 2){ 827 this.Namespace_String = exprList.getExpression(2); 828 } 829 830 functionType = EFunctionType.extractxml_t; 831 832 } 833 private TExpression XMLType_Instance = null; 834 835 public TExpression getNamespace_String() { 836 return Namespace_String; 837 } 838 839 public TExpression getXPath_String() { 840 841 return XPath_String; 842 } 843 844 public TExpression getXMLType_Instance() { 845 846 return XMLType_Instance; 847 } 848 849 private TExpression XPath_String = null; 850 private TExpression Namespace_String = null; 851 852 853 private TObjectNameList matchColumns = null; 854 855 /** 856 * column list in match function of MySQL 857 * @return 858 */ 859 public TObjectNameList getMatchColumns() { 860 return matchColumns; 861 } 862 863 /** 864 * against expr in match function of MySQL 865 * <pre> 866 * MATCH (col1,col2,...) AGAINST (expr [search_modifier]) 867 * </pre> 868 * 869 * @return expression after against keyword 870 */ 871 public TExpression getAgainstExpr() { 872 873 return againstExpr; 874 } 875 876 private TExpression againstExpr = null; 877 878 public void setMatchColumns(TObjectNameList matchColumns) { 879 this.matchColumns = matchColumns; 880 } 881 882 /** 883 * against expr in match function of MySQL 884 * <pre> 885 * MATCH (col1,col2,...) AGAINST (expr [search_modifier]) 886 * </pre> 887 * @param againstExpr expression after against keyword 888 */ 889 public void setAgainstExpr(TExpression againstExpr) { 890 891 this.againstExpr = againstExpr; 892 } 893 894 private TTypeName typename = null; 895 896 public void setTypename(TTypeName typename) { 897 this.typename = typename; 898 } 899 900 public TTypeName getTypename() { 901 902 return typename; 903 } 904 905 private TExpression parameter; 906 907 public void setParameter(TExpression parameter) { 908 this.parameter = parameter; 909 } 910 911 public void setStyle(TExpression style) { 912 this.style = style; 913 } 914 915 /** 916 * parameter in function:convert(datetype,parameter,style) 917 * @return 918 */ 919 public TExpression getParameter() { 920 921 return parameter; 922 } 923 924 /** 925 * style in function:convert(datetype,parameter,style) 926 * @return 927 */ 928 public TExpression getStyle() { 929 return style; 930 } 931 932 private TExpression style; 933 934 private TSourceToken extract_time_token = null; 935 936 TExpression expr1 = null; //teradata position function, sql server: convert; oracle convert,translate , mysql substring 937 TExpression expr2 = null; //teradata: position,substring function,, sql server: convert; oracle convert, mysql substring 938 TExpression expr3 = null; //teradata: substring function, for n, mysql substring 939 940 protected EFunctionType functionType = EFunctionType.udf_t; 941 942 /** 943 * The function type as the parser set it. Unlike {@link #getFunctionType()}, it never looks an unknown type up: 944 * that lookup renders the function name and caches a built-in check on this node, so a caller that must not 945 * change the tree (the SQL-LR producer's classifier) reads this instead. The lookup only ever answers 946 * {@code contains_t}, {@code builtin_t} or {@code unknown_t}, so for every other type the two agree. 947 * 948 * @return the parsed function type 949 * @since 4.2.17 950 */ 951 public EFunctionType getParsedFunctionType() { 952 return functionType; 953 } 954 955 public EFunctionType getFunctionType() { 956 if (functionType != EFunctionType.unknown_t){ 957 return functionType; 958 }else if (getFunctionName().toString().toLowerCase(Locale.ROOT).equalsIgnoreCase("contains")){ 959 return EFunctionType.contains_t; 960 }else if (isBuiltIn(this.dbvendor)){ 961 return EFunctionType.builtin_t; 962 }else{ 963 return functionType; 964 } 965 } 966 967 public boolean hasParenthesis() { 968 // 只有一个token,肯定不包含括号 969 if ((this.getStartToken() != null) && (this.getEndToken() != null) && (this.getStartToken() == this.getEndToken())) return false; 970 if (isOracleBuiltinFunction(this.dbvendor, this.getFunctionName().toString())) { 971 return false; 972 } 973 974 // 975 // 补充其他没有括号的情况 976 // 977 978 return true; 979 } 980 981 private boolean isOracleBuiltinFunction(EDbVendor dbvendor, String functionName) { 982 if (dbvendor != EDbVendor.dbvoracle) return false; 983 984 return functionName.equalsIgnoreCase("sysdate") 985 || functionName.equalsIgnoreCase("user") 986 || functionName.equalsIgnoreCase("SYSTIMESTAMP") 987 || functionName.equalsIgnoreCase("CURRENT_DATE") 988 || functionName.equalsIgnoreCase("CURRENT_TIMESTAMP") 989 ; 990 991 } 992 993 TColumnDefinitionList fieldDefs; 994 TResultColumnList fieldValues; 995 996 public TColumnDefinitionList getFieldDefs() { 997 return fieldDefs; 998 } 999 1000 public TResultColumnList getFieldValues() { 1001 return fieldValues; 1002 } 1003 1004 1005 public TObjectName getFunctionName() { 1006 return functionName; 1007 } 1008 1009 protected TObjectName functionName; 1010 1011 public TExpression Trim_Expr = null; 1012 public TExpression Trim_From_Expr = null; 1013 1014 1015 public void setTrimArgument(TTrimArgument trimArgument) { 1016 this.trimArgument = trimArgument; 1017 } 1018 1019 public TTrimArgument getTrimArgument() { 1020 1021 return trimArgument; 1022 } 1023 1024 TTrimArgument trimArgument = null; 1025 1026 1027 public void setExpr1(TExpression expr1) { 1028 this.expr1 = expr1; 1029 } 1030 1031 public void setExpr2(TExpression expr2) { 1032 this.expr2 = expr2; 1033 } 1034 1035 private TTypeName asDatatype; 1036 1037 /** 1038 * datatype defined in Oracle function: <code> XMLSERIALIZE(value_expr as datatype)</code> 1039 * 1040 * @param asDatatype datatype defined in Oracle function: <code> XMLSERIALIZE(value_expr as datatype)</code> 1041 */ 1042 public void setAsDatatype(TTypeName asDatatype) { 1043 this.asDatatype = asDatatype; 1044 } 1045 1046 private TResultColumnList XMLForestValueList; 1047 1048 public void setXMLForestValueList(TResultColumnList XMLForestValueList) { 1049 this.XMLForestValueList = XMLForestValueList; 1050 } 1051 1052 private TExpression XMLElementNameExpr; 1053 1054 public void setXMLElementNameExpr(TExpression XMLElementNameExpr) { 1055 this.XMLElementNameExpr = XMLElementNameExpr; 1056 } 1057 1058 /** 1059 * XMLElement name/evalname expr 1060 * @return XMLElement name/evalname expr 1061 */ 1062 public TExpression getXMLElementNameExpr() { 1063 return XMLElementNameExpr; 1064 1065 } 1066 1067 private TXMLAttributesClause XMLAttributesClause; 1068 1069 public void setXMLAttributesClause(TXMLAttributesClause XMLAttributesClause) { 1070 this.XMLAttributesClause = XMLAttributesClause; 1071 } 1072 1073 public void setXmlPassingClause(TXMLPassingClause xmlPassingClause) { 1074 this.xmlPassingClause = xmlPassingClause; 1075 } 1076 1077 public TXMLPassingClause getXmlPassingClause() { 1078 return xmlPassingClause; 1079 } 1080 1081 TXMLPassingClause xmlPassingClause; 1082 1083 1084 private TResultColumnList XMLElementValueExprList; 1085 1086 public void setXMLElementValueExprList(TResultColumnList XMLElementValueExprList) { 1087 this.XMLElementValueExprList = XMLElementValueExprList; 1088 } 1089 1090 /** 1091 * XMLElement ( value_expr [,XML_attribute_clause] [,value expr list] ) 1092 * @return XMLElement value expr list 1093 */ 1094 public TResultColumnList getXMLElementValueExprList() { 1095 1096 return XMLElementValueExprList; 1097 } 1098 1099 /** 1100 * XMLAttribute clause in xmlelement function 1101 * @return XMLAttribute clause in xmlelement function 1102 */ 1103 public TXMLAttributesClause getXMLAttributesClause() { 1104 1105 return XMLAttributesClause; 1106 } 1107 1108 /** 1109 * XMLFOREST (value_expr [as aliasName], ... ) 1110 * @return XMLFOREST value list 1111 */ 1112 public TResultColumnList getXMLForestValueList() { 1113 1114 return XMLForestValueList; 1115 } 1116 1117 /** 1118 * get datatype defined in Oracle XMLSERIALIZE(value_expr as datatype) 1119 * 1120 * @return datatype defined in oracle XMLSERIALIZE function 1121 */ 1122 public TTypeName getAsDatatype() { 1123 1124 return asDatatype; 1125 } 1126 1127 /** 1128 * paramter of following functions 1129 * <br>teradata: position function, 1130 * <br>sql server: convert; 1131 * <br>oracle: convert,translate,cast,oracle XMLSERIALIZE(value_expr), oracle XMLROOT (value_expr) 1132 * <br>mysql: substring 1133 * @return 1134 */ 1135 public TExpression getExpr1() { 1136 1137 return expr1; 1138 } 1139 1140 public TExpression getExpr2() { 1141 return expr2; 1142 } 1143 1144 public void setExpr3(TExpression expr3) { 1145 this.expr3 = expr3; 1146 } 1147 1148 public TExpression getExpr3() { 1149 1150 return expr3; 1151 } 1152 1153 1154 public void setExprList(TExpressionList exprList) { 1155 this.exprList = exprList; 1156 } 1157 1158 /** 1159 * return TExpressionList instead of TGroupingExpressionItemList after v1.4.3.3 1160 * @return expr list 1161 */ 1162 public TExpressionList getExprList() { 1163 1164 return exprList; 1165 } 1166 1167 private TExpressionList exprList = null;//teradata case_n, range_n 1168 1169 1170 protected TExpressionList Args = null; 1171 1172 public void setArgs(TExpressionList args) { 1173 Args = args; 1174 } 1175 1176 1177 public void init(Object arg1){ 1178 functionName = (TObjectName)arg1; 1179 if (functionName.getDbObjectType() == EDbObjectType.unknown){ 1180 functionName.setObjectType(TObjectName.ttobjFunctionName); 1181 } 1182 } 1183 1184 public void init(Object arg1,Object arg2){ 1185 if (arg1 instanceof EFunctionType){ 1186 functionType = (EFunctionType)arg1; 1187 init(arg2); 1188 } 1189 else if (arg1 instanceof TObjectName){ 1190 functionType = (EFunctionType)arg2; 1191 init(arg1); 1192 } 1193 switch (functionType){ 1194 case xmlmethod_t: 1195 if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_nodes){ 1196 functionType = EFunctionType.xmlnodes_t; 1197 }else if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_query){ 1198 functionType = EFunctionType.xml_sqlserver_query_t; 1199 }else if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_value){ 1200 functionType = EFunctionType.xmlvalue_t; 1201 }else if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_exist){ 1202 functionType = EFunctionType.xmlexists_t; 1203 }else if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_modify){ 1204 functionType = EFunctionType.xmlmodify_t; 1205 } 1206 break; 1207 case oracle_dbms_package_t: 1208 this.isBuiltIn = true; 1209 break; 1210 default: 1211 break; 1212 } 1213 } 1214 1215 public void init(Object arg1,Object arg2,Object arg3){ 1216 init(arg1,arg2); 1217 // For struct_t functions, store the field values (TResultColumnList) 1218 if (arg3 instanceof TResultColumnList) { 1219 if (this.functionType == EFunctionType.struct_t) { 1220 this.fieldValues = (TResultColumnList) arg3; 1221 } 1222 } 1223 } 1224 1225 public void init(Object arg1,Object arg2,Object arg3,Object arg4){ 1226 init(arg1,arg2,arg3); 1227 // For struct_t functions, store the field values (TResultColumnList) 1228 if (arg4 instanceof TResultColumnList) { 1229 if (this.functionType == EFunctionType.struct_t) { 1230 this.fieldValues = (TResultColumnList) arg4; 1231 } 1232 } 1233 } 1234 1235 1236 public void setAnalyticFunction(TAnalyticFunction analyticFunction) { 1237 this.analyticFunction = analyticFunction; 1238 } 1239 1240 /** 1241 * get the list of parameters defined in this function 1242 * 1243 * @return the list of parameter 1244 */ 1245 public TExpressionList getArgs() { 1246 return Args; 1247 } 1248 1249 protected TAnalyticFunction analyticFunction; 1250 1251 1252 public void doParse(TCustomSqlStatement psql, ESqlClause plocation){ 1253 this.dbvendor = psql.dbvendor; 1254 switch(functionType){ 1255 case unknown_t: 1256 case chr_t: 1257 case udf_t: 1258 case builtin_t: 1259 case listagg_t: 1260 case year_t: 1261 case generate_date_array_t: 1262 if (callTarget != null){ 1263 callTarget.doParse(psql,plocation); 1264 } 1265 if (Args != null){ 1266 // Use TBuiltFunctionUtil to determine which argument positions contain keywords 1267 // This supports datepart keywords like QUARTER, MONTH, YEAR, etc. across all databases. 1268 // It is the only list: the old resolver and resolver2 read the same properties files, so a 1269 // function a vendor does not have (Redshift has no DATENAME) is not marked here either. 1270 Set<Integer> keywordPositions = null; 1271 if (functionName != null) { 1272 keywordPositions = TBuiltFunctionUtil.argumentsIncludeKeyword( 1273 psql.dbvendor, functionName.toString()); 1274 } 1275 markColumnOnlyArgument(psql); 1276 1277 for(int i=0;i<Args.size();i++){ 1278 // Check if this argument position is marked as a keyword position (1-based in properties) 1279 boolean isKeywordPosition = (keywordPositions != null && keywordPositions.contains(i + 1)); 1280 1281 if (isKeywordPosition) { 1282 // Mark this argument as date_time_part so it's not treated as column reference 1283 setFirstArgAsDateTimePart(i); 1284 continue; 1285 } 1286 Args.getExpression(i).doParse(psql,plocation); 1287 } 1288 } 1289 1290 if (psql.dbvendor == EDbVendor.dbvmssql){ 1291 // check OGC function of sql server 1292// System.out.println("func:"+functionName.toString()); 1293 if (isSQLServerOGCMethod(functionName.getObjectToken())){ 1294 if (functionName.getSchemaToken() != null){ 1295 functionName.getSchemaToken().setDbObjType(TObjectName.ttobjColumn); 1296 if (functionName.getDatabaseToken() != null){ 1297 functionName.getDatabaseToken().setDbObjType(TObjectName.ttobjTable); 1298 } 1299 1300 TObjectName objectName = new TObjectName(); 1301 objectName.init(functionName.getDatabaseToken(),functionName.getSchemaToken()); 1302 objectName.setGsqlparser(psql.getGsqlparser()); // this will make toString work correctly 1303 psql.linkColumnReferenceToTable(objectName,plocation); 1304 psql.linkColumnToTable(objectName,plocation); 1305 } 1306 }else if (isSQLServerFunctionsONXMLColumn()) { 1307 1308 1309// if (functionName.getSchemaToken() != null) { 1310// functionName.getSchemaToken().setDbObjType(TObjectName.ttobjColumn); 1311// functionName.setPartToken(functionName.getSchemaToken()); 1312// functionName.setSchemaToken(null); 1313// if (functionName.getDatabaseToken() != null) { 1314// functionName.getDatabaseToken().setDbObjType(TObjectName.ttobjTable); 1315// functionName.setObjectToken(functionName.getDatabaseToken()); 1316// } 1317// 1318// TObjectName objectName = new TObjectName(); 1319// objectName.init(functionName.getObjectToken(), functionName.getPartToken()); 1320// objectName.setGsqlparser(psql.getGsqlparser()); // this will make toString work correctly 1321// psql.linkColumnReferenceToTable(objectName, plocation); 1322// psql.linkColumnToTable(objectName, plocation); 1323// } 1324 1325 } 1326 } else if (psql.dbvendor == EDbVendor.dbvoracle){ 1327 if (plocation == ESqlClause.spAssignValue){ 1328 if (functionName.getNumberOfPart() == 3){ 1329 // schema1.pkg1.GETCUSTOMERNAME(2) 1330 functionName.setPackageToken(functionName.getSchemaToken()); 1331 functionName.setSchemaToken(functionName.getDatabaseToken()); 1332 functionName.setServerToken(null); 1333 } 1334 } 1335 } else if (psql.dbvendor == EDbVendor.dbvteradata){ 1336 // Handle NPath function - extract ON clause tables for data lineage 1337 if (functionName != null && functionName.toString().equalsIgnoreCase("NPath")){ 1338 analyzeTeradataNPathOnClause(psql, plocation); 1339 } 1340 } 1341 break; 1342 case trim_t: 1343 if (this.trimArgument != null){ 1344 this.trimArgument.doParse(psql,plocation); 1345 } 1346 1347 break; 1348 case cast_t: 1349 if (this.expr1 != null){ 1350 this.expr1.doParse(psql,plocation); 1351 }else{ 1352 this.getArgs().getExpression(0).doParse(psql,plocation); 1353 } 1354 1355 break; 1356 case convert_t: 1357 if (this.typename != null) this.typename.doParse(psql,plocation); 1358 this.parameter.doParse(psql,plocation); 1359 if (this.style != null) 1360 { //sql server 1361 this.style.doParse(psql,plocation); 1362 } 1363 break; 1364 case extract_t: 1365 if (this.expr1 != null){ 1366 this.expr1.doParse(psql,plocation); 1367 } 1368 break; 1369 case treat_t: 1370 this.expr1.doParse(psql,plocation); 1371 break; 1372 case contains_t: 1373 //this.inExpr.doParse(psql,plocation); 1374 1375 this.expr1.doParse(psql,plocation); 1376 this.expr2.doParse(psql,plocation); 1377 break; 1378 case freetext_t: 1379 //inExpr.doParse(psql,plocation); 1380 this.expr1.doParse(psql,plocation); 1381 this.expr2.doParse(psql,plocation); 1382 break; 1383 case case_n_t: 1384 this.getArgs().doParse(psql, plocation); 1385 break; 1386// case range_n_t: 1387// this.expr1.doParse(psql,plocation); 1388// for(TRangeNFunctionItem rangeItem : rangeNFunctionItems){ 1389// rangeItem.doParse(psql,plocation); 1390// } 1391// break; 1392 case position_t: 1393 expr1.doParse(psql,plocation); 1394 expr2.doParse(psql,plocation); 1395 break; 1396 case substring_t: 1397 if (Args != null) 1398 for(int i=0;i<Args.size();i++){ 1399 Args.getExpression(i).doParse(psql,plocation); 1400 } 1401 if (expr1 != null) expr1.doParse(psql,plocation); 1402 if (expr2 != null) expr2.doParse(psql,plocation); 1403 if (expr3 != null){ 1404 expr3.doParse(psql,plocation); 1405 } 1406 break; 1407 case xmlquery_t: 1408 if (xmlPassingClause != null){ 1409 xmlPassingClause.doParse(psql,plocation); 1410 } 1411 break; 1412 case xmlcast_t: 1413 if (typeExpression != null){ 1414 typeExpression.doParse(psql,plocation); 1415 } 1416 break; 1417 case match_against_t: 1418 for(int i=0;i<this.getMatchColumns().size();i++){ 1419 psql.linkColumnReferenceToTable(this.getMatchColumns().getObjectName(i),plocation); 1420 psql.linkColumnToTable(this.getMatchColumns().getObjectName(i),plocation); 1421 } 1422 this.getAgainstExpr().doParse(psql,plocation); 1423 break; 1424 case adddate_t: 1425 case date_add_t: 1426 case subdate_t: 1427 case date_sub_t: 1428 case timestampadd_t: 1429 case timestampdiff_t: 1430 expr1.doParse(psql,plocation); 1431 expr2.doParse(psql,plocation); 1432 break; 1433 case xmlserialize_t: 1434 if (expr1 != null){ 1435 expr1.doParse(psql,plocation); 1436 }else if (typeExpression != null){ 1437 typeExpression.doParse(psql,plocation); 1438 } 1439 break; 1440 case xmlroot_t: 1441 expr1.doParse(psql,plocation); 1442 break; 1443 case xmlforest_t: 1444 XMLForestValueList.doParse(psql, plocation); 1445 break; 1446 case xmlelement_t: 1447 if (XMLElementNameExpr.getExpressionType() == EExpressionType.simple_object_name_t){ 1448 XMLElementNameExpr.getObjectOperand().setDbObjectType(EDbObjectType.xmlElement); 1449 } 1450 XMLElementNameExpr.doParse(psql,ESqlClause.xmlElementName); 1451 if (XMLAttributesClause != null) 1452 XMLAttributesClause.doParse(psql,plocation); 1453 if (XMLElementValueExprList != null) 1454 XMLElementValueExprList.doParse(psql,plocation); 1455 break; 1456 case translate_t: 1457 expr1.doParse(psql,plocation); 1458 if (expr2 != null) expr2.doParse(psql,plocation); 1459 if (expr3 != null) expr3.doParse(psql,plocation); 1460 break; 1461 case group_concat_t: 1462 groupConcatParam.doParse(psql,plocation); 1463 break; 1464 case quantile_t: 1465 this.orderByList.doParse(psql,plocation); 1466 break; 1467 case csum_t: 1468 this.getOrderByList().doParse(psql,plocation); 1469 break; 1470 case rank_t: 1471 if (this.getOrderByList() != null){ 1472 this.getOrderByList().doParse(psql,plocation); 1473 } 1474 1475 break; 1476 case xmlexists_t: 1477 case xmlmodify_t: 1478 case xmlnodes_t: 1479 case xmlvalue_t: 1480 case xml_sqlserver_query_t: 1481 if (callTarget != null){ 1482 callTarget.doParse(psql,plocation); 1483 } 1484 if ((functionName.getObjectToken() != null)&&(functionName.getPartToken() != null)){ 1485 TObjectName objectName = new TObjectName(); 1486 objectName.init(functionName.getObjectToken(), functionName.getPartToken()); 1487 objectName.setGsqlparser(psql.getGsqlparser()); // this will make toString work correctly 1488 psql.linkColumnReferenceToTable(objectName, plocation); 1489 psql.linkColumnToTable(objectName, plocation); 1490 } 1491 break; 1492 case xmlagg_t: 1493 for(int i=0;i<Args.size();i++){ 1494 Args.getExpression(i).doParse(psql,plocation); 1495 } 1496 break; 1497 case if_t: 1498 expr1.doParse(psql,plocation); 1499 expr2.doParse(psql,plocation); 1500 expr3.doParse(psql,plocation); 1501 break; 1502 case array_t: // bigquery array (subquery) 1503 this.getArgs().getExpression(0).doParse(psql,plocation); 1504 break; 1505 case array_agg_t: 1506 this.getArgs().getExpression(0).doParse(psql,plocation); 1507 break; 1508 case string_agg_t: 1509 this.getArgs().getExpression(0).doParse(psql,plocation); 1510 if (getOrderByList() != null){ 1511 getOrderByList().doParse(psql,plocation); 1512 } 1513 break; 1514 default: 1515 if (getArgs() != null){ 1516 for(int i=0;i<getArgs().size();i++){ 1517 Args.getExpression(i).doParse(psql,plocation); 1518 } 1519 } 1520 break; 1521 } 1522 1523 // ORDER BY inside the argument list, as in LIST(x, ',' ORDER BY y), string_agg(x, ',' ORDER BY y) or 1524 // XMLAGG(x ORDER BY y). Its keys are linked like the arguments, not through TOrderBy.doParse: that 1525 // one applies the rules of a statement ORDER BY, where an unqualified key may name a select-list alias. 1526 if (sortClause != null){ 1527 TOrderByItemList sortItems = sortClause.getItems(); 1528 for(int i=0;i<sortItems.size();i++){ 1529 TExpression sortKey = sortItems.getOrderByItem(i).getSortKey(); 1530 if (sortKey != null){ 1531 sortKey.doParse(psql,plocation); 1532 } 1533 } 1534 } 1535 1536 if (withinGroup != null){ 1537 withinGroup.doParse(psql,plocation); 1538 } 1539 if (analyticFunction != null){ 1540 analyticFunction.doParse(psql,plocation); 1541 } 1542 1543 if (filterClause != null){ 1544 filterClause.doParse(psql,plocation); 1545 } 1546 1547 if (windowDef != null){ 1548 windowDef.doParse(psql,plocation); 1549 } 1550 } 1551 1552 1553 /** 1554 * @deprecated As of v1.8.6.3, use {@link #getWindowDef()} instead 1555 * window clause in window function. 1556 * @return a value of {@link TAnalyticFunction} 1557 * @see TAnalyticFunction 1558 */ 1559 public TAnalyticFunction getAnalyticFunction() { 1560 return analyticFunction; 1561 } 1562 1563 public void accept(TParseTreeVisitor v){ 1564 v.preVisit(this); 1565 v.postVisit(this); 1566 } 1567 1568 public void acceptChildren(TParseTreeVisitor v){ 1569 v.preVisit(this); 1570 // SQL Server method chain T.c.query('.').value('.', 'int') (MantisBT 4897): the call target is the 1571 // inner method call, and it is the only node that names the column, so walk it. The other call 1572 // targets (a column, a variable, a subquery) are not walked, as before. 1573 if ((callTarget != null) && (callTarget.getExpr() != null) 1574 && (callTarget.getExpr().getExpressionType() == EExpressionType.function_t)){ 1575 callTarget.acceptChildren(v); 1576 } 1577 functionName.acceptChildren(v); 1578 switch(functionType){ 1579 case unknown_t: 1580 if (Args != null){ 1581 Args.acceptChildren(v); 1582 } 1583 break; 1584 case udf_t: 1585 if (Args != null){ 1586 Args.acceptChildren(v); 1587 } 1588 if (analyticFunction != null){ 1589 analyticFunction.acceptChildren(v); 1590 } 1591 break; 1592 case trim_t: 1593 if (this.trimArgument != null){ 1594 this.trimArgument.acceptChildren(v); 1595 } 1596 1597 break; 1598 case cast_t: 1599 if (this.expr1 != null) { 1600 this.expr1.acceptChildren(v); 1601 }else{ 1602 this.getArgs().getExpression(0).acceptChildren(v); 1603 } 1604 1605 break; 1606 case convert_t: 1607 if (this.typename != null) this.typename.acceptChildren(v); 1608 if (this.parameter != null) this.parameter.acceptChildren(v); 1609 if (this.style != null) this.style.acceptChildren(v); 1610// this.expr1.acceptChildren(v); 1611// if (this.expr2 != null) 1612// { //sql server 1613// this.expr2.acceptChildren(v); 1614// } 1615 break; 1616 case extract_t: 1617 if (this.expr1 != null){ 1618 this.expr1.acceptChildren(v); 1619 } 1620 break; 1621 case treat_t: 1622 this.expr1.acceptChildren(v); 1623 break; 1624 case contains_t: 1625 //this.inExpr.acceptChildren(v); 1626 1627 this.expr1.acceptChildren(v); 1628 this.expr2.acceptChildren(v); 1629 break; 1630 case freetext_t: 1631 //inExpr.acceptChildren(v); 1632 this.expr1.acceptChildren(v); 1633 this.expr2.acceptChildren(v); 1634 break; 1635 case case_n_t: 1636 this.getArgs().acceptChildren(v); 1637 break; 1638// case range_n_t: 1639// this.expr1.acceptChildren(v); 1640// for(TRangeNFunctionItem item:rangeNFunctionItems){ 1641// item.acceptChildren(v); 1642// } 1643// 1644// break; 1645 case position_t: 1646 expr1.acceptChildren(v); 1647 expr2.acceptChildren(v); 1648 break; 1649 case substring_t: 1650 if (Args != null){ 1651 Args.acceptChildren(v); 1652 } 1653 if (expr1 != null) expr1.acceptChildren(v); 1654 if (expr2 != null) expr2.acceptChildren(v); 1655 if (expr3 != null){ 1656 expr3.acceptChildren(v); 1657 } 1658 break; 1659 case xmlquery_t: 1660 break; 1661 case xmlcast_t: 1662 break; 1663 case match_against_t: 1664 //for(int i=0;i<this.getMatchColumns().size();i++){ 1665 // psql.linkColumnReferenceToTable(this.getMatchColumns().getObjectName(i),plocation); 1666 //} 1667 this.getAgainstExpr().acceptChildren(v); 1668 break; 1669 case adddate_t: 1670 case date_add_t: 1671 case subdate_t: 1672 case date_sub_t: 1673 case timestampadd_t: 1674 case timestampdiff_t: 1675 expr1.acceptChildren(v); 1676 expr2.acceptChildren(v); 1677 break; 1678 default: 1679 if (Args != null){ 1680 Args.acceptChildren(v); 1681 } 1682 break; 1683 } 1684 1685 if (analyticFunction != null){ 1686 analyticFunction.acceptChildren(v); 1687 } 1688 1689 if (filterClause != null){ 1690 filterClause.acceptChildren(v); 1691 } 1692 1693 if (windowDef != null){ 1694 windowDef.acceptChildren(v); 1695 } 1696 1697 v.postVisit(this); 1698 } 1699 1700 boolean isSQLServerFunctionsONXMLColumn(){ 1701// return ((st.tokencode == TBaseType.rrw_xml_exist) 1702// ||(st.tokencode == TBaseType.rrw_xml_query) 1703// ||(st.tokencode == TBaseType.rrw_xml_modify) 1704// ||(st.tokencode == TBaseType.rrw_xml_nodes) 1705// ||(st.tokencode == TBaseType.rrw_xml_value) 1706// ); 1707 return ((this.functionType == EFunctionType.xmlmodify_t) 1708 ||(this.functionType == EFunctionType.xmlvalue_t) 1709 ||(this.functionType == EFunctionType.xmlnodes_t) 1710 ||(this.functionType == EFunctionType.xmlexists_t) 1711 ||(this.functionType == EFunctionType.xmlquery_t) 1712 ); 1713 } 1714 1715 /** 1716 * MySQL {@code VALUES(col)} and {@code DEFAULT(col)} take a column's name, so a variable of that name is never 1717 * read there, though MySQL reads a variable before a column elsewhere (Mantis 4797). 1718 */ 1719 private void markColumnOnlyArgument(TCustomSqlStatement psql){ 1720 if ((!psql.isMySQLDialect()) || (functionName == null) || (functionName.getNumberOfPart() != 1)) return; 1721 if ((Args == null) || (Args.size() != 1)) return; 1722 String name = functionName.toString(); 1723 if (!("VALUES".equalsIgnoreCase(name) // non-identifier-compare: built-in function keyword 1724 || "DEFAULT".equalsIgnoreCase(name))) return; // non-identifier-compare: built-in function keyword 1725 TExpression arg = Args.getExpression(0); 1726 if ((arg != null) && (arg.getExpressionType() == EExpressionType.simple_object_name_t) 1727 && (arg.getObjectOperand() != null)){ 1728 arg.getObjectOperand().setColumnOnly(true); 1729 } 1730 } 1731 1732 boolean isSQLServerOGCMethod(TSourceToken st){ 1733 return ((st.tokencode == TBaseType.rrw_starea) 1734 ||(st.tokencode == TBaseType.rrw_stasbinary) 1735 ||(st.tokencode == TBaseType.rrw_stastext) 1736 ||(st.tokencode == TBaseType.rrw_stbuffer) 1737 ||(st.tokencode == TBaseType.rrw_stdimension) 1738 ||(st.tokencode == TBaseType.rrw_stdisjoint) 1739 ||(st.tokencode == TBaseType.rrw_stdistance) 1740 ||(st.tokencode == TBaseType.rrw_stendpoint) 1741 ||(st.tokencode == TBaseType.rrw_stgeometryn) 1742 ||(st.tokencode == TBaseType.rrw_stgeometrytype) 1743 ||(st.tokencode == TBaseType.rrw_stintersection) 1744 ||(st.tokencode == TBaseType.rrw_stintersects) 1745 ||(st.tokencode == TBaseType.rrw_stisclosed) 1746 ||(st.tokencode == TBaseType.rrw_stisempty) 1747 ||(st.tokencode == TBaseType.rrw_stlength) 1748 ||(st.tokencode == TBaseType.rrw_stnumgeometries) 1749 ||(st.tokencode == TBaseType.rrw_stnumpoints) 1750 ||(st.tokencode == TBaseType.rrw_stpointn) 1751 ||(st.tokencode == TBaseType.rrw_stsrid) 1752 ||(st.tokencode == TBaseType.rrw_ststartpoint) 1753 ||(st.tokencode == TBaseType.rrw_stunion) 1754 ); 1755 } 1756 1757 /** 1758 * @deprecated As of v1.4.3.0, replaced by {@link #functionType} 1759 */ 1760 private int funcType = fntUdf; 1761 1762 /** 1763 * @deprecated As of v1.4.3.0 1764 */ 1765 public void setFuncType(int funcType) { 1766 this.funcType = funcType; 1767 1768 } 1769 1770 /** 1771 * @deprecated As of v1.4.3.0, replaced by {@link #getFunctionType()}. 1772 */ 1773 public int getFuncType() { 1774 1775 return funcType; 1776 } 1777 1778 /** 1779 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#udf_t} 1780 */ 1781 public final static int fntUdf = 0; 1782 1783 /** 1784 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#trim_t} 1785 */ 1786 public final static int fntTrim = 1; 1787 1788 /** 1789 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#cast_t} 1790 */ 1791 public final static int fntCast = 2; 1792 1793 /** 1794 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#convert_t} 1795 */ 1796 public final static int fntConvert = 3; 1797 1798 /** 1799 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#extract_t} 1800 */ 1801 public final static int fntExtract = 4; 1802 1803 /** 1804 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#treat_t} 1805 */ 1806 public final static int fntTreat = 5; 1807 1808 /** 1809 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#contains_t} 1810 */ 1811 public final static int fntContains = 6; 1812 1813 /** 1814 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#freetext_t} 1815 */ 1816 public final static int fntFreetext = 7; // 1817 1818 /** 1819 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#case_n_t} 1820 */ 1821 public final static int fntCaseN = 10; //teradata 1822 1823 /** 1824 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#range_n_t} 1825 */ 1826 public final static int fntRangeN = 11; //teradata 1827 1828 /** 1829 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#position_t} 1830 */ 1831 public final static int fntPosition = 12; //teradata 1832 /** 1833 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#substring_t} 1834 */ 1835 public final static int fntSubstring = 13; //teradata 1836 /** 1837 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#translate_t} 1838 */ 1839 public final static int fntTranslate = 14; //teradata ,oracle 1840 /** 1841 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#translate_chk_t} 1842 */ 1843 public final static int fntTranslateCHK = 15; //teradata 1844 /** 1845 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#csum_t} 1846 */ 1847 public final static int fntCSUM = 16; //teradata 1848 /** 1849 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#rank_t} 1850 */ 1851 public final static int fntRank = 17; //teradata 1852 /** 1853 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#xmlquery_t} 1854 */ 1855 public final static int fntXmlQuery= 18; //oracle 1856 1857 /** 1858 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#substring_t} 1859 */ 1860 public final static int fntSubString = 31;//mysql 1861 /** 1862 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#adddate_t} 1863 */ 1864 public final static int fntAddDate = 32;//mysql 1865 /** 1866 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#date_add_t} 1867 */ 1868 public final static int fntDateAdd = 33;//mysql 1869 /** 1870 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#subdate_t} 1871 */ 1872 public final static int fntSubDate = 34;//mysql 1873 /** 1874 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#date_sub_t} 1875 */ 1876 public final static int fntDateSub = 35;//mysql 1877 /** 1878 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#timestampadd_t} 1879 */ 1880 public final static int fntTimestampAdd = 36;//mysql 1881 /** 1882 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#timestampdiff_t} 1883 */ 1884 public final static int fntTimestampDiff = 37;//mysql 1885 /** 1886 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#group_concat_t} 1887 */ 1888 public final static int fntGroupConcat = 38;//mysql 1889 /** 1890 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#match_against_t} 1891 */ 1892 public final static int fntMatchAgainst = 39;//mysql 1893 1894 /** 1895 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#extract_t} 1896 */ 1897 public final static int fntExtractXML = 50;//oracle 1898 1899 1900 /** 1901 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#ogc_t} 1902 */ 1903 public final static int fntOGC = 60; 1904 1905 public void setCheckedBuiltIn(boolean isCheckedBuiltIn) { 1906 this.isCheckedBuiltIn = isCheckedBuiltIn; 1907 } 1908 1909 public void setBuiltIn(boolean isBuiltIn) { 1910 this.isBuiltIn = isBuiltIn; 1911 } 1912 1913 public void setXMLType_Instance(TExpression XMLType_Instance) { 1914 this.XMLType_Instance = XMLType_Instance; 1915 } 1916 1917 public void setXPath_String(TExpression XPath_String) { 1918 this.XPath_String = XPath_String; 1919 } 1920 1921 public void setNamespace_String(TExpression namespace_String) { 1922 Namespace_String = namespace_String; 1923 } 1924 1925 public void setFunctionType(EFunctionType functionType) { 1926 this.functionType = functionType; 1927 } 1928 1929 public void setFunctionName(TObjectName functionName) { 1930 this.functionName = functionName; 1931 } 1932 1933 public void setTrim_Expr(TExpression trim_Expr) { 1934 Trim_Expr = trim_Expr; 1935 } 1936 1937 public void setTrim_From_Expr(TExpression trim_From_Expr) { 1938 Trim_From_Expr = trim_From_Expr; 1939 } 1940 1941 /** 1942 * Extracts and analyzes tables from Teradata NPath function's ON clause. 1943 * The NPath function syntax is: NPath(ON table_or_subquery PARTITION BY ... USING ...) 1944 * This method parses the ON clause to extract table references for data lineage. 1945 */ 1946 private void analyzeTeradataNPathOnClause(TCustomSqlStatement psql, ESqlClause plocation) { 1947 String funcText = this.toString(); 1948 if (funcText == null || funcText.isEmpty()) { 1949 return; 1950 } 1951 1952 // Find the ON clause 1953 String upperFuncText = funcText.toUpperCase(Locale.ROOT); 1954 int onIndex = upperFuncText.indexOf(" ON "); 1955 if (onIndex < 0) { 1956 onIndex = upperFuncText.indexOf("(ON "); 1957 if (onIndex >= 0) { 1958 onIndex++; // Skip the opening parenthesis 1959 } 1960 } 1961 if (onIndex < 0) { 1962 return; 1963 } 1964 1965 // Extract text after ON 1966 String afterOn = funcText.substring(onIndex + 4).trim(); 1967 if (afterOn.isEmpty()) { 1968 return; 1969 } 1970 1971 try { 1972 if (afterOn.startsWith("(")) { 1973 // It's a subquery - find matching closing parenthesis 1974 int depth = 0; 1975 int endPos = -1; 1976 for (int i = 0; i < afterOn.length(); i++) { 1977 char c = afterOn.charAt(i); 1978 if (c == '(') depth++; 1979 else if (c == ')') { 1980 depth--; 1981 if (depth == 0) { 1982 endPos = i + 1; 1983 break; 1984 } 1985 } 1986 } 1987 if (endPos > 0) { 1988 String subqueryText = afterOn.substring(0, endPos); 1989 // Parse the subquery to extract tables 1990 TGSqlParser subParser = new TGSqlParser(EDbVendor.dbvteradata); 1991 subParser.sqltext = "SELECT * FROM " + subqueryText + " __npath_on"; 1992 if (subParser.parse() == 0 && subParser.sqlstatements.size() > 0) { 1993 gudusoft.gsqlparser.stmt.TSelectSqlStatement subSelect = 1994 (gudusoft.gsqlparser.stmt.TSelectSqlStatement) subParser.sqlstatements.get(0); 1995 if (subSelect.tables != null && subSelect.tables.size() > 0) { 1996 TTable onTable = subSelect.tables.getTable(0); 1997 // If it has a subquery, analyze its tables 1998 if (onTable.getSubquery() != null) { 1999 for (int i = 0; i < onTable.getSubquery().tables.size(); i++) { 2000 TTable sourceTable = onTable.getSubquery().tables.getTable(i); 2001 addNPathSourceTable(sourceTable, psql); 2002 } 2003 } 2004 } 2005 } 2006 } 2007 } else { 2008 // It's a direct table reference - extract until whitespace or special char 2009 StringBuilder tableName = new StringBuilder(); 2010 for (int i = 0; i < afterOn.length(); i++) { 2011 char c = afterOn.charAt(i); 2012 if (Character.isWhitespace(c) || c == ')' || c == ',') { 2013 break; 2014 } 2015 tableName.append(c); 2016 } 2017 if (tableName.length() > 0) { 2018 // Parse the table reference 2019 TGSqlParser subParser = new TGSqlParser(EDbVendor.dbvteradata); 2020 subParser.sqltext = "SELECT * FROM " + tableName.toString() + " __npath_on"; 2021 if (subParser.parse() == 0 && subParser.sqlstatements.size() > 0) { 2022 gudusoft.gsqlparser.stmt.TSelectSqlStatement subSelect = 2023 (gudusoft.gsqlparser.stmt.TSelectSqlStatement) subParser.sqlstatements.get(0); 2024 if (subSelect.tables != null && subSelect.tables.size() > 0) { 2025 TTable sourceTable = subSelect.tables.getTable(0); 2026 addNPathSourceTable(sourceTable, psql); 2027 } 2028 } 2029 } 2030 } 2031 } catch (Exception e) { 2032 // Silently ignore parsing errors - the main query still works 2033 } 2034 } 2035 2036 /** 2037 * Adds a source table from NPath ON clause to the current statement's table list. 2038 */ 2039 private void addNPathSourceTable(TTable sourceTable, TCustomSqlStatement psql) { 2040 if (sourceTable == null || psql == null) { 2041 return; 2042 } 2043 // Mark the table as coming from NPath ON clause 2044 sourceTable.setNPathOnClauseTable(true); 2045 // Add to the statement's table list 2046 if (psql.tables == null) { 2047 psql.tables = new TTableList(); 2048 } 2049 psql.tables.addTable(sourceTable); 2050 } 2051 2052}