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