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){ 229 TSQLFunction functionDef = sqlEnv.searchFunction(this.getFunctionName().toString()); 230 if(functionDef != null && 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 if (avVersions == null || avVersions.isEmpty()) { 597 return false; 598 } 599 return functionChecker.isBuiltInFunction(pName,pDBVendor,avVersions.get(avVersions.size()-1)); 600 } 601 602 private boolean isCheckedBuiltIn = false; 603 private boolean isBuiltIn = false; 604 605 public boolean isBuiltIn(EDbVendor pDBVendor) { 606 if (isCheckedBuiltIn) return isBuiltIn; 607 List<String> avVersions = functionChecker.getAvailableDbVersions(pDBVendor); 608 if (avVersions == null || avVersions.isEmpty()) { 609 isBuiltIn = false; 610 } else { 611 isBuiltIn = functionChecker.isBuiltInFunction(this.functionName.toString(),pDBVendor,avVersions.get(avVersions.size()-1)); 612 } 613 isCheckedBuiltIn = true; 614 return isBuiltIn; 615 } 616 617 private TXMLPassingClause passingClause; 618 619 public void setPassingClause(TXMLPassingClause passingClause) { 620 this.passingClause = passingClause; 621 } 622 623 /** 624 * XMLPassingClause of XMLExists function 625 * @return XMLPassingClause of XMLExists function 626 */ 627 public TXMLPassingClause getPassingClause() { 628 return passingClause; 629 } 630 631 private EAggregateType aggregateType = EAggregateType.none; 632 633 /** 634 * set <code>ALL | DISTINCT | UNIQUE</code> keywords used in an aggregate function. 635 * 636 * @param aggregateType 637 * @see #getAggregateType 638 */ 639 public void setAggregateType(EAggregateType aggregateType) { 640 this.aggregateType = aggregateType; 641 } 642 643 /** 644 * get <code>ALL | DISTINCT | UNIQUE</code> keywords used in an aggregate function. 645 * An aggregate function performs a calculation on a set of values, and returns a single value. 646 * 647 * @return aggregate type, one of those values: none,all,distinct,unique 648 */ 649 public EAggregateType getAggregateType() { 650 651 return aggregateType; 652 } 653 654 private TOrderByItemList orderByList; 655 656 public void setOrderByList(TOrderByItemList orderByList) { 657 this.orderByList = orderByList; 658 } 659 660 /** 661 * arguments in rank(value,...) function. 662 * @return a list of {@link TOrderByItem} in function: rank, csum 663 */ 664 public TOrderByItemList getOrderByList() { 665 666 return orderByList; 667 } 668 669 private TOrderBy sortClause; 670 671 public void setSortClause(TOrderBy sortClause) { 672 this.sortClause = sortClause; 673 } 674 675 public TOrderBy getSortClause() { 676 677 return sortClause; 678 } 679 680 /** 681 * Over clause of analytic function 682 * @return over clause 683 */ 684 public TWindowDef getWindowDef() { 685 return windowDef; 686 } 687 688 public void setWindowDef(TWindowDef windowDef) { 689 690 this.windowDef = windowDef; 691 } 692 693 public void setFunctionOptionsWithDummy(TDummy dummy){ 694 if (dummy == null) return; 695 if (dummy.node2 != null){ 696 setWindowDef((TWindowDef)dummy.node2 ); 697 } 698 if (dummy.node3 != null){ 699 setWithinGroup((TWithinGroup) dummy.node3); 700 } 701 } 702 703 protected TWindowDef windowDef; 704 705// public void setWindowSpecification(TWindowDef windowSpecification) { 706// this.windowSpecification = windowSpecification; 707// } 708 709 /** 710 * @deprecated As of v1.8.6.0, replaced by {@link #windowDef} 711 */ 712 private TWindowSpecification windowSpecification; 713 714 private TDatatypeAttribute datatypeAttribute = null; 715 716 public TWindowSpecification getWindowSpecification() { 717 return windowSpecification; 718 } 719 720 /** 721 * Not used. 722 * 723 * @param datatypeAttribute datatype attribute 724 */ 725 public void setDatatypeAttribute(TDatatypeAttribute datatypeAttribute) { 726 this.datatypeAttribute = datatypeAttribute; 727 } 728 729 /** 730 * Not used. 731 * 732 * @return datatype attribute 733 */ 734 public TDatatypeAttribute getDatatypeAttribute() { 735 736 return datatypeAttribute; 737 } 738 739 /** 740 * one of the YEAR/MONTH/DAY, HOUR/MINUTE/SECOND keywords in extract function 741 * 742 * @return one of the YEAR/MONTH/DAY, HOUR/MINUTE/SECOND keywords in extract function 743 */ 744 public TSourceToken getExtract_time_token() { 745 return extract_time_token; 746 } 747 748 749 /** 750 * set one of the YEAR/MONTH/DAY, HOUR/MINUTE/SECOND keyword in extract function 751 * 752 * @param extract_time_token one of the YEAR/MONTH/DAY, HOUR/MINUTE/SECOND token 753 */ 754 public void setExtract_time_token(TSourceToken extract_time_token) { 755 this.extract_time_token = extract_time_token; 756 } 757 758 759 private TDummy dummy = null; 760 761 /** 762 * Set value for temporary use only 763 * 764 * @param dummy a temporary value from parse tree 765 */ 766 public void setDummy(TDummy dummy) { 767 this.dummy = dummy; 768 } 769 770 /** 771 * Not used 772 * 773 * @return a temporary value 774 */ 775 public TDummy getDummy() { 776 777 return dummy; 778 } 779 780 public void setInExpr(TInExpr inExpr) { 781 this.inExpr = inExpr; 782 } 783 784 public TInExpr getInExpr() { 785 786 return inExpr; 787 } 788 789 private TInExpr inExpr = null; //sql server, used in fntContains, fntFreetext 790 791 public void setExtractXMLArg(TExpressionList exprList){ 792 if (exprList.size() > 1){ 793 this.XMLType_Instance = exprList.getExpression(0); 794 this.XPath_String = exprList.getExpression(1); 795 } 796 797 if (exprList.size() > 2){ 798 this.Namespace_String = exprList.getExpression(2); 799 } 800 801 functionType = EFunctionType.extractxml_t; 802 803 } 804 private TExpression XMLType_Instance = null; 805 806 public TExpression getNamespace_String() { 807 return Namespace_String; 808 } 809 810 public TExpression getXPath_String() { 811 812 return XPath_String; 813 } 814 815 public TExpression getXMLType_Instance() { 816 817 return XMLType_Instance; 818 } 819 820 private TExpression XPath_String = null; 821 private TExpression Namespace_String = null; 822 823 824 private TObjectNameList matchColumns = null; 825 826 /** 827 * column list in match function of MySQL 828 * @return 829 */ 830 public TObjectNameList getMatchColumns() { 831 return matchColumns; 832 } 833 834 /** 835 * against expr in match function of MySQL 836 * <pre> 837 * MATCH (col1,col2,...) AGAINST (expr [search_modifier]) 838 * </pre> 839 * 840 * @return expression after against keyword 841 */ 842 public TExpression getAgainstExpr() { 843 844 return againstExpr; 845 } 846 847 private TExpression againstExpr = null; 848 849 public void setMatchColumns(TObjectNameList matchColumns) { 850 this.matchColumns = matchColumns; 851 } 852 853 /** 854 * against expr in match function of MySQL 855 * <pre> 856 * MATCH (col1,col2,...) AGAINST (expr [search_modifier]) 857 * </pre> 858 * @param againstExpr expression after against keyword 859 */ 860 public void setAgainstExpr(TExpression againstExpr) { 861 862 this.againstExpr = againstExpr; 863 } 864 865 private TTypeName typename = null; 866 867 public void setTypename(TTypeName typename) { 868 this.typename = typename; 869 } 870 871 public TTypeName getTypename() { 872 873 return typename; 874 } 875 876 private TExpression parameter; 877 878 public void setParameter(TExpression parameter) { 879 this.parameter = parameter; 880 } 881 882 public void setStyle(TExpression style) { 883 this.style = style; 884 } 885 886 /** 887 * parameter in function:convert(datetype,parameter,style) 888 * @return 889 */ 890 public TExpression getParameter() { 891 892 return parameter; 893 } 894 895 /** 896 * style in function:convert(datetype,parameter,style) 897 * @return 898 */ 899 public TExpression getStyle() { 900 return style; 901 } 902 903 private TExpression style; 904 905 private TSourceToken extract_time_token = null; 906 907 TExpression expr1 = null; //teradata position function, sql server: convert; oracle convert,translate , mysql substring 908 TExpression expr2 = null; //teradata: position,substring function,, sql server: convert; oracle convert, mysql substring 909 TExpression expr3 = null; //teradata: substring function, for n, mysql substring 910 911 protected EFunctionType functionType = EFunctionType.udf_t; 912 913 public EFunctionType getFunctionType() { 914 if (functionType != EFunctionType.unknown_t){ 915 return functionType; 916 }else if (getFunctionName().toString().toLowerCase().equalsIgnoreCase("contains")){ 917 return EFunctionType.contains_t; 918 }else if (isBuiltIn(this.dbvendor)){ 919 return EFunctionType.builtin_t; 920 }else{ 921 return functionType; 922 } 923 } 924 925 public boolean hasParenthesis() { 926 // 只有一个token,肯定不包含括号 927 if ((this.getStartToken() != null) && (this.getEndToken() != null) && (this.getStartToken() == this.getEndToken())) return false; 928 if (isOracleBuiltinFunction(this.dbvendor, this.getFunctionName().toString())) { 929 return false; 930 } 931 932 // 933 // 补充其他没有括号的情况 934 // 935 936 return true; 937 } 938 939 private boolean isOracleBuiltinFunction(EDbVendor dbvendor, String functionName) { 940 if (dbvendor != EDbVendor.dbvoracle) return false; 941 942 return functionName.equalsIgnoreCase("sysdate") 943 || functionName.equalsIgnoreCase("user") 944 || functionName.equalsIgnoreCase("SYSTIMESTAMP") 945 || functionName.equalsIgnoreCase("CURRENT_DATE") 946 || functionName.equalsIgnoreCase("CURRENT_TIMESTAMP") 947 ; 948 949 } 950 951 TColumnDefinitionList fieldDefs; 952 TResultColumnList fieldValues; 953 954 public TColumnDefinitionList getFieldDefs() { 955 return fieldDefs; 956 } 957 958 public TResultColumnList getFieldValues() { 959 return fieldValues; 960 } 961 962 963 public TObjectName getFunctionName() { 964 return functionName; 965 } 966 967 protected TObjectName functionName; 968 969 public TExpression Trim_Expr = null; 970 public TExpression Trim_From_Expr = null; 971 972 973 public void setTrimArgument(TTrimArgument trimArgument) { 974 this.trimArgument = trimArgument; 975 } 976 977 public TTrimArgument getTrimArgument() { 978 979 return trimArgument; 980 } 981 982 TTrimArgument trimArgument = null; 983 984 985 public void setExpr1(TExpression expr1) { 986 this.expr1 = expr1; 987 } 988 989 public void setExpr2(TExpression expr2) { 990 this.expr2 = expr2; 991 } 992 993 private TTypeName asDatatype; 994 995 /** 996 * datatype defined in Oracle function: <code> XMLSERIALIZE(value_expr as datatype)</code> 997 * 998 * @param asDatatype datatype defined in Oracle function: <code> XMLSERIALIZE(value_expr as datatype)</code> 999 */ 1000 public void setAsDatatype(TTypeName asDatatype) { 1001 this.asDatatype = asDatatype; 1002 } 1003 1004 private TResultColumnList XMLForestValueList; 1005 1006 public void setXMLForestValueList(TResultColumnList XMLForestValueList) { 1007 this.XMLForestValueList = XMLForestValueList; 1008 } 1009 1010 private TExpression XMLElementNameExpr; 1011 1012 public void setXMLElementNameExpr(TExpression XMLElementNameExpr) { 1013 this.XMLElementNameExpr = XMLElementNameExpr; 1014 } 1015 1016 /** 1017 * XMLElement name/evalname expr 1018 * @return XMLElement name/evalname expr 1019 */ 1020 public TExpression getXMLElementNameExpr() { 1021 return XMLElementNameExpr; 1022 1023 } 1024 1025 private TXMLAttributesClause XMLAttributesClause; 1026 1027 public void setXMLAttributesClause(TXMLAttributesClause XMLAttributesClause) { 1028 this.XMLAttributesClause = XMLAttributesClause; 1029 } 1030 1031 public void setXmlPassingClause(TXMLPassingClause xmlPassingClause) { 1032 this.xmlPassingClause = xmlPassingClause; 1033 } 1034 1035 public TXMLPassingClause getXmlPassingClause() { 1036 return xmlPassingClause; 1037 } 1038 1039 TXMLPassingClause xmlPassingClause; 1040 1041 1042 private TResultColumnList XMLElementValueExprList; 1043 1044 public void setXMLElementValueExprList(TResultColumnList XMLElementValueExprList) { 1045 this.XMLElementValueExprList = XMLElementValueExprList; 1046 } 1047 1048 /** 1049 * XMLElement ( value_expr [,XML_attribute_clause] [,value expr list] ) 1050 * @return XMLElement value expr list 1051 */ 1052 public TResultColumnList getXMLElementValueExprList() { 1053 1054 return XMLElementValueExprList; 1055 } 1056 1057 /** 1058 * XMLAttribute clause in xmlelement function 1059 * @return XMLAttribute clause in xmlelement function 1060 */ 1061 public TXMLAttributesClause getXMLAttributesClause() { 1062 1063 return XMLAttributesClause; 1064 } 1065 1066 /** 1067 * XMLFOREST (value_expr [as aliasName], ... ) 1068 * @return XMLFOREST value list 1069 */ 1070 public TResultColumnList getXMLForestValueList() { 1071 1072 return XMLForestValueList; 1073 } 1074 1075 /** 1076 * get datatype defined in Oracle XMLSERIALIZE(value_expr as datatype) 1077 * 1078 * @return datatype defined in oracle XMLSERIALIZE function 1079 */ 1080 public TTypeName getAsDatatype() { 1081 1082 return asDatatype; 1083 } 1084 1085 /** 1086 * paramter of following functions 1087 * <br>teradata: position function, 1088 * <br>sql server: convert; 1089 * <br>oracle: convert,translate,cast,oracle XMLSERIALIZE(value_expr), oracle XMLROOT (value_expr) 1090 * <br>mysql: substring 1091 * @return 1092 */ 1093 public TExpression getExpr1() { 1094 1095 return expr1; 1096 } 1097 1098 public TExpression getExpr2() { 1099 return expr2; 1100 } 1101 1102 public void setExpr3(TExpression expr3) { 1103 this.expr3 = expr3; 1104 } 1105 1106 public TExpression getExpr3() { 1107 1108 return expr3; 1109 } 1110 1111 1112 public void setExprList(TExpressionList exprList) { 1113 this.exprList = exprList; 1114 } 1115 1116 /** 1117 * return TExpressionList instead of TGroupingExpressionItemList after v1.4.3.3 1118 * @return expr list 1119 */ 1120 public TExpressionList getExprList() { 1121 1122 return exprList; 1123 } 1124 1125 private TExpressionList exprList = null;//teradata case_n, range_n 1126 1127 1128 protected TExpressionList Args = null; 1129 1130 public void setArgs(TExpressionList args) { 1131 Args = args; 1132 } 1133 1134 1135 public void init(Object arg1){ 1136 functionName = (TObjectName)arg1; 1137 if (functionName.getDbObjectType() == EDbObjectType.unknown){ 1138 functionName.setObjectType(TObjectName.ttobjFunctionName); 1139 } 1140 } 1141 1142 public void init(Object arg1,Object arg2){ 1143 if (arg1 instanceof EFunctionType){ 1144 functionType = (EFunctionType)arg1; 1145 init(arg2); 1146 } 1147 else if (arg1 instanceof TObjectName){ 1148 functionType = (EFunctionType)arg2; 1149 init(arg1); 1150 } 1151 switch (functionType){ 1152 case xmlmethod_t: 1153 if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_nodes){ 1154 functionType = EFunctionType.xmlnodes_t; 1155 }else if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_query){ 1156 functionType = EFunctionType.xml_sqlserver_query_t; 1157 }else if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_value){ 1158 functionType = EFunctionType.xmlvalue_t; 1159 }else if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_exist){ 1160 functionType = EFunctionType.xmlexists_t; 1161 }else if (functionName.getMethodToken().tokencode == TBaseType.rrw_xml_modify){ 1162 functionType = EFunctionType.xmlmodify_t; 1163 } 1164 break; 1165 case oracle_dbms_package_t: 1166 this.isBuiltIn = true; 1167 break; 1168 default: 1169 break; 1170 } 1171 } 1172 1173 public void init(Object arg1,Object arg2,Object arg3){ 1174 init(arg1,arg2); 1175 // For struct_t functions, store the field values (TResultColumnList) 1176 if (arg3 instanceof TResultColumnList) { 1177 if (this.functionType == EFunctionType.struct_t) { 1178 this.fieldValues = (TResultColumnList) arg3; 1179 } 1180 } 1181 } 1182 1183 public void init(Object arg1,Object arg2,Object arg3,Object arg4){ 1184 init(arg1,arg2,arg3); 1185 // For struct_t functions, store the field values (TResultColumnList) 1186 if (arg4 instanceof TResultColumnList) { 1187 if (this.functionType == EFunctionType.struct_t) { 1188 this.fieldValues = (TResultColumnList) arg4; 1189 } 1190 } 1191 } 1192 1193 1194 public void setAnalyticFunction(TAnalyticFunction analyticFunction) { 1195 this.analyticFunction = analyticFunction; 1196 } 1197 1198 /** 1199 * get the list of parameters defined in this function 1200 * 1201 * @return the list of parameter 1202 */ 1203 public TExpressionList getArgs() { 1204 return Args; 1205 } 1206 1207 protected TAnalyticFunction analyticFunction; 1208 1209 1210 public void doParse(TCustomSqlStatement psql, ESqlClause plocation){ 1211 this.dbvendor = psql.dbvendor; 1212 switch(functionType){ 1213 case unknown_t: 1214 case chr_t: 1215 case udf_t: 1216 case builtin_t: 1217 case listagg_t: 1218 case year_t: 1219 case generate_date_array_t: 1220 if (callTarget != null){ 1221 callTarget.doParse(psql,plocation); 1222 } 1223 if (Args != null){ 1224 // Use TBuiltFunctionUtil to determine which argument positions contain keywords 1225 // This supports datepart keywords like QUARTER, MONTH, YEAR, etc. across all databases 1226 Set<Integer> keywordPositions = null; 1227 if (functionName != null) { 1228 keywordPositions = TBuiltFunctionUtil.argumentsIncludeKeyword( 1229 psql.dbvendor, functionName.toString()); 1230 } 1231 1232 // Legacy check for SQL Server/Sybase/Redshift - kept for backward compatibility 1233 // as not all date functions may be in the properties file yet 1234 boolean legacySkipFirstArg = false; 1235 if ((psql.dbvendor == EDbVendor.dbvsybase)||(psql.dbvendor == EDbVendor.dbvmssql)||(psql.dbvendor == EDbVendor.dbvredshift) 1236 ){ 1237 legacySkipFirstArg = ((functionName.toString().equalsIgnoreCase("dateadd")) 1238 ||(functionName.toString().equalsIgnoreCase("datediff")) 1239 ||(functionName.toString().equalsIgnoreCase("datename")) 1240 ||(functionName.toString().equalsIgnoreCase("datepart")) 1241 ); 1242 } 1243 1244 for(int i=0;i<Args.size();i++){ 1245 // Check if this argument position is marked as a keyword position (1-based in properties) 1246 boolean isKeywordPosition = (keywordPositions != null && keywordPositions.contains(i + 1)); 1247 // Also check legacy hardcoded first-arg handling for backward compatibility 1248 boolean isLegacyFirstArg = (legacySkipFirstArg && i == 0); 1249 1250 if (isKeywordPosition || isLegacyFirstArg) { 1251 // Mark this argument as date_time_part so it's not treated as column reference 1252 setFirstArgAsDateTimePart(i); 1253 continue; 1254 } 1255 Args.getExpression(i).doParse(psql,plocation); 1256 } 1257 } 1258 1259 if (psql.dbvendor == EDbVendor.dbvmssql){ 1260 // check OGC function of sql server 1261// System.out.println("func:"+functionName.toString()); 1262 if (isSQLServerOGCMethod(functionName.getObjectToken())){ 1263 if (functionName.getSchemaToken() != null){ 1264 functionName.getSchemaToken().setDbObjType(TObjectName.ttobjColumn); 1265 if (functionName.getDatabaseToken() != null){ 1266 functionName.getDatabaseToken().setDbObjType(TObjectName.ttobjTable); 1267 } 1268 1269 TObjectName objectName = new TObjectName(); 1270 objectName.init(functionName.getDatabaseToken(),functionName.getSchemaToken()); 1271 objectName.setGsqlparser(psql.getGsqlparser()); // this will make toString work correctly 1272 psql.linkColumnReferenceToTable(objectName,plocation); 1273 psql.linkColumnToTable(objectName,plocation); 1274 } 1275 }else if (isSQLServerFunctionsONXMLColumn()) { 1276 1277 1278// if (functionName.getSchemaToken() != null) { 1279// functionName.getSchemaToken().setDbObjType(TObjectName.ttobjColumn); 1280// functionName.setPartToken(functionName.getSchemaToken()); 1281// functionName.setSchemaToken(null); 1282// if (functionName.getDatabaseToken() != null) { 1283// functionName.getDatabaseToken().setDbObjType(TObjectName.ttobjTable); 1284// functionName.setObjectToken(functionName.getDatabaseToken()); 1285// } 1286// 1287// TObjectName objectName = new TObjectName(); 1288// objectName.init(functionName.getObjectToken(), functionName.getPartToken()); 1289// objectName.setGsqlparser(psql.getGsqlparser()); // this will make toString work correctly 1290// psql.linkColumnReferenceToTable(objectName, plocation); 1291// psql.linkColumnToTable(objectName, plocation); 1292// } 1293 1294 } 1295 } else if (psql.dbvendor == EDbVendor.dbvoracle){ 1296 if (plocation == ESqlClause.spAssignValue){ 1297 if (functionName.getNumberOfPart() == 3){ 1298 // schema1.pkg1.GETCUSTOMERNAME(2) 1299 functionName.setPackageToken(functionName.getSchemaToken()); 1300 functionName.setSchemaToken(functionName.getDatabaseToken()); 1301 functionName.setServerToken(null); 1302 } 1303 } 1304 } else if (psql.dbvendor == EDbVendor.dbvteradata){ 1305 // Handle NPath function - extract ON clause tables for data lineage 1306 if (functionName != null && functionName.toString().equalsIgnoreCase("NPath")){ 1307 analyzeTeradataNPathOnClause(psql, plocation); 1308 } 1309 } 1310 break; 1311 case trim_t: 1312 if (this.trimArgument != null){ 1313 this.trimArgument.doParse(psql,plocation); 1314 } 1315 1316 break; 1317 case cast_t: 1318 if (this.expr1 != null){ 1319 this.expr1.doParse(psql,plocation); 1320 }else{ 1321 this.getArgs().getExpression(0).doParse(psql,plocation); 1322 } 1323 1324 break; 1325 case convert_t: 1326 if (this.typename != null) this.typename.doParse(psql,plocation); 1327 this.parameter.doParse(psql,plocation); 1328 if (this.style != null) 1329 { //sql server 1330 this.style.doParse(psql,plocation); 1331 } 1332 break; 1333 case extract_t: 1334 if (this.expr1 != null){ 1335 this.expr1.doParse(psql,plocation); 1336 } 1337 break; 1338 case treat_t: 1339 this.expr1.doParse(psql,plocation); 1340 break; 1341 case contains_t: 1342 //this.inExpr.doParse(psql,plocation); 1343 1344 this.expr1.doParse(psql,plocation); 1345 this.expr2.doParse(psql,plocation); 1346 break; 1347 case freetext_t: 1348 //inExpr.doParse(psql,plocation); 1349 this.expr1.doParse(psql,plocation); 1350 this.expr2.doParse(psql,plocation); 1351 break; 1352 case case_n_t: 1353 this.getArgs().doParse(psql, plocation); 1354 break; 1355// case range_n_t: 1356// this.expr1.doParse(psql,plocation); 1357// for(TRangeNFunctionItem rangeItem : rangeNFunctionItems){ 1358// rangeItem.doParse(psql,plocation); 1359// } 1360// break; 1361 case position_t: 1362 expr1.doParse(psql,plocation); 1363 expr2.doParse(psql,plocation); 1364 break; 1365 case substring_t: 1366 if (Args != null) 1367 for(int i=0;i<Args.size();i++){ 1368 Args.getExpression(i).doParse(psql,plocation); 1369 } 1370 if (expr1 != null) expr1.doParse(psql,plocation); 1371 if (expr2 != null) expr2.doParse(psql,plocation); 1372 if (expr3 != null){ 1373 expr3.doParse(psql,plocation); 1374 } 1375 break; 1376 case xmlquery_t: 1377 if (xmlPassingClause != null){ 1378 xmlPassingClause.doParse(psql,plocation); 1379 } 1380 break; 1381 case xmlcast_t: 1382 if (typeExpression != null){ 1383 typeExpression.doParse(psql,plocation); 1384 } 1385 break; 1386 case match_against_t: 1387 for(int i=0;i<this.getMatchColumns().size();i++){ 1388 psql.linkColumnReferenceToTable(this.getMatchColumns().getObjectName(i),plocation); 1389 psql.linkColumnToTable(this.getMatchColumns().getObjectName(i),plocation); 1390 } 1391 this.getAgainstExpr().doParse(psql,plocation); 1392 break; 1393 case adddate_t: 1394 case date_add_t: 1395 case subdate_t: 1396 case date_sub_t: 1397 case timestampadd_t: 1398 case timestampdiff_t: 1399 expr1.doParse(psql,plocation); 1400 expr2.doParse(psql,plocation); 1401 break; 1402 case xmlserialize_t: 1403 if (expr1 != null){ 1404 expr1.doParse(psql,plocation); 1405 }else if (typeExpression != null){ 1406 typeExpression.doParse(psql,plocation); 1407 } 1408 break; 1409 case xmlroot_t: 1410 expr1.doParse(psql,plocation); 1411 break; 1412 case xmlforest_t: 1413 XMLForestValueList.doParse(psql, plocation); 1414 break; 1415 case xmlelement_t: 1416 if (XMLElementNameExpr.getExpressionType() == EExpressionType.simple_object_name_t){ 1417 XMLElementNameExpr.getObjectOperand().setDbObjectType(EDbObjectType.xmlElement); 1418 } 1419 XMLElementNameExpr.doParse(psql,ESqlClause.xmlElementName); 1420 if (XMLAttributesClause != null) 1421 XMLAttributesClause.doParse(psql,plocation); 1422 if (XMLElementValueExprList != null) 1423 XMLElementValueExprList.doParse(psql,plocation); 1424 break; 1425 case translate_t: 1426 expr1.doParse(psql,plocation); 1427 if (expr2 != null) expr2.doParse(psql,plocation); 1428 if (expr3 != null) expr3.doParse(psql,plocation); 1429 break; 1430 case group_concat_t: 1431 groupConcatParam.doParse(psql,plocation); 1432 break; 1433 case quantile_t: 1434 this.orderByList.doParse(psql,plocation); 1435 break; 1436 case csum_t: 1437 this.getOrderByList().doParse(psql,plocation); 1438 break; 1439 case rank_t: 1440 if (this.getOrderByList() != null){ 1441 this.getOrderByList().doParse(psql,plocation); 1442 } 1443 1444 break; 1445 case xmlexists_t: 1446 case xmlmodify_t: 1447 case xmlnodes_t: 1448 case xmlvalue_t: 1449 case xml_sqlserver_query_t: 1450 if (callTarget != null){ 1451 callTarget.doParse(psql,plocation); 1452 } 1453 if ((functionName.getObjectToken() != null)&&(functionName.getPartToken() != null)){ 1454 TObjectName objectName = new TObjectName(); 1455 objectName.init(functionName.getObjectToken(), functionName.getPartToken()); 1456 objectName.setGsqlparser(psql.getGsqlparser()); // this will make toString work correctly 1457 psql.linkColumnReferenceToTable(objectName, plocation); 1458 psql.linkColumnToTable(objectName, plocation); 1459 } 1460 break; 1461 case xmlagg_t: 1462 for(int i=0;i<Args.size();i++){ 1463 Args.getExpression(i).doParse(psql,plocation); 1464 } 1465 if (getSortClause() != null){ 1466 getSortClause().doParse(psql,plocation); 1467 } 1468 break; 1469 case if_t: 1470 expr1.doParse(psql,plocation); 1471 expr2.doParse(psql,plocation); 1472 expr3.doParse(psql,plocation); 1473 break; 1474 case array_t: // bigquery array (subquery) 1475 this.getArgs().getExpression(0).doParse(psql,plocation); 1476 break; 1477 case array_agg_t: 1478 this.getArgs().getExpression(0).doParse(psql,plocation); 1479 break; 1480 case string_agg_t: 1481 this.getArgs().getExpression(0).doParse(psql,plocation); 1482 if (getOrderByList() != null){ 1483 getOrderByList().doParse(psql,plocation); 1484 } 1485 break; 1486 default: 1487 if (getArgs() != null){ 1488 for(int i=0;i<getArgs().size();i++){ 1489 Args.getExpression(i).doParse(psql,plocation); 1490 } 1491 } 1492 break; 1493 } 1494 1495 if (withinGroup != null){ 1496 withinGroup.doParse(psql,plocation); 1497 } 1498 if (analyticFunction != null){ 1499 analyticFunction.doParse(psql,plocation); 1500 } 1501 1502 if (filterClause != null){ 1503 filterClause.doParse(psql,plocation); 1504 } 1505 1506 if (windowDef != null){ 1507 windowDef.doParse(psql,plocation); 1508 } 1509 } 1510 1511 1512 /** 1513 * @deprecated As of v1.8.6.3, use {@link #getWindowDef()} instead 1514 * window clause in window function. 1515 * @return a value of {@link TAnalyticFunction} 1516 * @see TAnalyticFunction 1517 */ 1518 public TAnalyticFunction getAnalyticFunction() { 1519 return analyticFunction; 1520 } 1521 1522 public void accept(TParseTreeVisitor v){ 1523 v.preVisit(this); 1524 v.postVisit(this); 1525 } 1526 1527 public void acceptChildren(TParseTreeVisitor v){ 1528 v.preVisit(this); 1529 functionName.acceptChildren(v); 1530 switch(functionType){ 1531 case unknown_t: 1532 if (Args != null){ 1533 Args.acceptChildren(v); 1534 } 1535 break; 1536 case udf_t: 1537 if (Args != null){ 1538 Args.acceptChildren(v); 1539 } 1540 if (analyticFunction != null){ 1541 analyticFunction.acceptChildren(v); 1542 } 1543 break; 1544 case trim_t: 1545 if (this.trimArgument != null){ 1546 this.trimArgument.acceptChildren(v); 1547 } 1548 1549 break; 1550 case cast_t: 1551 if (this.expr1 != null) { 1552 this.expr1.acceptChildren(v); 1553 }else{ 1554 this.getArgs().getExpression(0).acceptChildren(v); 1555 } 1556 1557 break; 1558 case convert_t: 1559 if (this.typename != null) this.typename.acceptChildren(v); 1560 if (this.parameter != null) this.parameter.acceptChildren(v); 1561 if (this.style != null) this.style.acceptChildren(v); 1562// this.expr1.acceptChildren(v); 1563// if (this.expr2 != null) 1564// { //sql server 1565// this.expr2.acceptChildren(v); 1566// } 1567 break; 1568 case extract_t: 1569 if (this.expr1 != null){ 1570 this.expr1.acceptChildren(v); 1571 } 1572 break; 1573 case treat_t: 1574 this.expr1.acceptChildren(v); 1575 break; 1576 case contains_t: 1577 //this.inExpr.acceptChildren(v); 1578 1579 this.expr1.acceptChildren(v); 1580 this.expr2.acceptChildren(v); 1581 break; 1582 case freetext_t: 1583 //inExpr.acceptChildren(v); 1584 this.expr1.acceptChildren(v); 1585 this.expr2.acceptChildren(v); 1586 break; 1587 case case_n_t: 1588 this.getArgs().acceptChildren(v); 1589 break; 1590// case range_n_t: 1591// this.expr1.acceptChildren(v); 1592// for(TRangeNFunctionItem item:rangeNFunctionItems){ 1593// item.acceptChildren(v); 1594// } 1595// 1596// break; 1597 case position_t: 1598 expr1.acceptChildren(v); 1599 expr2.acceptChildren(v); 1600 break; 1601 case substring_t: 1602 if (Args != null){ 1603 Args.acceptChildren(v); 1604 } 1605 if (expr1 != null) expr1.acceptChildren(v); 1606 if (expr2 != null) expr2.acceptChildren(v); 1607 if (expr3 != null){ 1608 expr3.acceptChildren(v); 1609 } 1610 break; 1611 case xmlquery_t: 1612 break; 1613 case xmlcast_t: 1614 break; 1615 case match_against_t: 1616 //for(int i=0;i<this.getMatchColumns().size();i++){ 1617 // psql.linkColumnReferenceToTable(this.getMatchColumns().getObjectName(i),plocation); 1618 //} 1619 this.getAgainstExpr().acceptChildren(v); 1620 break; 1621 case adddate_t: 1622 case date_add_t: 1623 case subdate_t: 1624 case date_sub_t: 1625 case timestampadd_t: 1626 case timestampdiff_t: 1627 expr1.acceptChildren(v); 1628 expr2.acceptChildren(v); 1629 break; 1630 default: 1631 if (Args != null){ 1632 Args.acceptChildren(v); 1633 } 1634 break; 1635 } 1636 1637 if (analyticFunction != null){ 1638 analyticFunction.acceptChildren(v); 1639 } 1640 1641 if (filterClause != null){ 1642 filterClause.acceptChildren(v); 1643 } 1644 1645 if (windowDef != null){ 1646 windowDef.acceptChildren(v); 1647 } 1648 1649 v.postVisit(this); 1650 } 1651 1652 boolean isSQLServerFunctionsONXMLColumn(){ 1653// return ((st.tokencode == TBaseType.rrw_xml_exist) 1654// ||(st.tokencode == TBaseType.rrw_xml_query) 1655// ||(st.tokencode == TBaseType.rrw_xml_modify) 1656// ||(st.tokencode == TBaseType.rrw_xml_nodes) 1657// ||(st.tokencode == TBaseType.rrw_xml_value) 1658// ); 1659 return ((this.functionType == EFunctionType.xmlmodify_t) 1660 ||(this.functionType == EFunctionType.xmlvalue_t) 1661 ||(this.functionType == EFunctionType.xmlnodes_t) 1662 ||(this.functionType == EFunctionType.xmlexists_t) 1663 ||(this.functionType == EFunctionType.xmlquery_t) 1664 ); 1665 } 1666 1667 boolean isSQLServerOGCMethod(TSourceToken st){ 1668 return ((st.tokencode == TBaseType.rrw_starea) 1669 ||(st.tokencode == TBaseType.rrw_stasbinary) 1670 ||(st.tokencode == TBaseType.rrw_stastext) 1671 ||(st.tokencode == TBaseType.rrw_stbuffer) 1672 ||(st.tokencode == TBaseType.rrw_stdimension) 1673 ||(st.tokencode == TBaseType.rrw_stdisjoint) 1674 ||(st.tokencode == TBaseType.rrw_stdistance) 1675 ||(st.tokencode == TBaseType.rrw_stendpoint) 1676 ||(st.tokencode == TBaseType.rrw_stgeometryn) 1677 ||(st.tokencode == TBaseType.rrw_stgeometrytype) 1678 ||(st.tokencode == TBaseType.rrw_stintersection) 1679 ||(st.tokencode == TBaseType.rrw_stintersects) 1680 ||(st.tokencode == TBaseType.rrw_stisclosed) 1681 ||(st.tokencode == TBaseType.rrw_stisempty) 1682 ||(st.tokencode == TBaseType.rrw_stlength) 1683 ||(st.tokencode == TBaseType.rrw_stnumgeometries) 1684 ||(st.tokencode == TBaseType.rrw_stnumpoints) 1685 ||(st.tokencode == TBaseType.rrw_stpointn) 1686 ||(st.tokencode == TBaseType.rrw_stsrid) 1687 ||(st.tokencode == TBaseType.rrw_ststartpoint) 1688 ||(st.tokencode == TBaseType.rrw_stunion) 1689 ); 1690 } 1691 1692 /** 1693 * @deprecated As of v1.4.3.0, replaced by {@link #functionType} 1694 */ 1695 private int funcType = fntUdf; 1696 1697 /** 1698 * @deprecated As of v1.4.3.0 1699 */ 1700 public void setFuncType(int funcType) { 1701 this.funcType = funcType; 1702 1703 } 1704 1705 /** 1706 * @deprecated As of v1.4.3.0, replaced by {@link #getFunctionType()}. 1707 */ 1708 public int getFuncType() { 1709 1710 return funcType; 1711 } 1712 1713 /** 1714 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#udf_t} 1715 */ 1716 public final static int fntUdf = 0; 1717 1718 /** 1719 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#trim_t} 1720 */ 1721 public final static int fntTrim = 1; 1722 1723 /** 1724 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#cast_t} 1725 */ 1726 public final static int fntCast = 2; 1727 1728 /** 1729 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#convert_t} 1730 */ 1731 public final static int fntConvert = 3; 1732 1733 /** 1734 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#extract_t} 1735 */ 1736 public final static int fntExtract = 4; 1737 1738 /** 1739 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#treat_t} 1740 */ 1741 public final static int fntTreat = 5; 1742 1743 /** 1744 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#contains_t} 1745 */ 1746 public final static int fntContains = 6; 1747 1748 /** 1749 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#freetext_t} 1750 */ 1751 public final static int fntFreetext = 7; // 1752 1753 /** 1754 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#case_n_t} 1755 */ 1756 public final static int fntCaseN = 10; //teradata 1757 1758 /** 1759 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#range_n_t} 1760 */ 1761 public final static int fntRangeN = 11; //teradata 1762 1763 /** 1764 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#position_t} 1765 */ 1766 public final static int fntPosition = 12; //teradata 1767 /** 1768 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#substring_t} 1769 */ 1770 public final static int fntSubstring = 13; //teradata 1771 /** 1772 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#translate_t} 1773 */ 1774 public final static int fntTranslate = 14; //teradata ,oracle 1775 /** 1776 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#translate_chk_t} 1777 */ 1778 public final static int fntTranslateCHK = 15; //teradata 1779 /** 1780 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#csum_t} 1781 */ 1782 public final static int fntCSUM = 16; //teradata 1783 /** 1784 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#rank_t} 1785 */ 1786 public final static int fntRank = 17; //teradata 1787 /** 1788 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#xmlquery_t} 1789 */ 1790 public final static int fntXmlQuery= 18; //oracle 1791 1792 /** 1793 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#substring_t} 1794 */ 1795 public final static int fntSubString = 31;//mysql 1796 /** 1797 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#adddate_t} 1798 */ 1799 public final static int fntAddDate = 32;//mysql 1800 /** 1801 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#date_add_t} 1802 */ 1803 public final static int fntDateAdd = 33;//mysql 1804 /** 1805 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#subdate_t} 1806 */ 1807 public final static int fntSubDate = 34;//mysql 1808 /** 1809 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#date_sub_t} 1810 */ 1811 public final static int fntDateSub = 35;//mysql 1812 /** 1813 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#timestampadd_t} 1814 */ 1815 public final static int fntTimestampAdd = 36;//mysql 1816 /** 1817 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#timestampdiff_t} 1818 */ 1819 public final static int fntTimestampDiff = 37;//mysql 1820 /** 1821 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#group_concat_t} 1822 */ 1823 public final static int fntGroupConcat = 38;//mysql 1824 /** 1825 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#match_against_t} 1826 */ 1827 public final static int fntMatchAgainst = 39;//mysql 1828 1829 /** 1830 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#extract_t} 1831 */ 1832 public final static int fntExtractXML = 50;//oracle 1833 1834 1835 /** 1836 * @deprecated As of v1.4.3.0, replaced by {@link EFunctionType#ogc_t} 1837 */ 1838 public final static int fntOGC = 60; 1839 1840 public void setCheckedBuiltIn(boolean isCheckedBuiltIn) { 1841 this.isCheckedBuiltIn = isCheckedBuiltIn; 1842 } 1843 1844 public void setBuiltIn(boolean isBuiltIn) { 1845 this.isBuiltIn = isBuiltIn; 1846 } 1847 1848 public void setXMLType_Instance(TExpression XMLType_Instance) { 1849 this.XMLType_Instance = XMLType_Instance; 1850 } 1851 1852 public void setXPath_String(TExpression XPath_String) { 1853 this.XPath_String = XPath_String; 1854 } 1855 1856 public void setNamespace_String(TExpression namespace_String) { 1857 Namespace_String = namespace_String; 1858 } 1859 1860 public void setFunctionType(EFunctionType functionType) { 1861 this.functionType = functionType; 1862 } 1863 1864 public void setFunctionName(TObjectName functionName) { 1865 this.functionName = functionName; 1866 } 1867 1868 public void setTrim_Expr(TExpression trim_Expr) { 1869 Trim_Expr = trim_Expr; 1870 } 1871 1872 public void setTrim_From_Expr(TExpression trim_From_Expr) { 1873 Trim_From_Expr = trim_From_Expr; 1874 } 1875 1876 /** 1877 * Extracts and analyzes tables from Teradata NPath function's ON clause. 1878 * The NPath function syntax is: NPath(ON table_or_subquery PARTITION BY ... USING ...) 1879 * This method parses the ON clause to extract table references for data lineage. 1880 */ 1881 private void analyzeTeradataNPathOnClause(TCustomSqlStatement psql, ESqlClause plocation) { 1882 String funcText = this.toString(); 1883 if (funcText == null || funcText.isEmpty()) { 1884 return; 1885 } 1886 1887 // Find the ON clause 1888 String upperFuncText = funcText.toUpperCase(); 1889 int onIndex = upperFuncText.indexOf(" ON "); 1890 if (onIndex < 0) { 1891 onIndex = upperFuncText.indexOf("(ON "); 1892 if (onIndex >= 0) { 1893 onIndex++; // Skip the opening parenthesis 1894 } 1895 } 1896 if (onIndex < 0) { 1897 return; 1898 } 1899 1900 // Extract text after ON 1901 String afterOn = funcText.substring(onIndex + 4).trim(); 1902 if (afterOn.isEmpty()) { 1903 return; 1904 } 1905 1906 try { 1907 if (afterOn.startsWith("(")) { 1908 // It's a subquery - find matching closing parenthesis 1909 int depth = 0; 1910 int endPos = -1; 1911 for (int i = 0; i < afterOn.length(); i++) { 1912 char c = afterOn.charAt(i); 1913 if (c == '(') depth++; 1914 else if (c == ')') { 1915 depth--; 1916 if (depth == 0) { 1917 endPos = i + 1; 1918 break; 1919 } 1920 } 1921 } 1922 if (endPos > 0) { 1923 String subqueryText = afterOn.substring(0, endPos); 1924 // Parse the subquery to extract tables 1925 TGSqlParser subParser = new TGSqlParser(EDbVendor.dbvteradata); 1926 subParser.sqltext = "SELECT * FROM " + subqueryText + " __npath_on"; 1927 if (subParser.parse() == 0 && subParser.sqlstatements.size() > 0) { 1928 gudusoft.gsqlparser.stmt.TSelectSqlStatement subSelect = 1929 (gudusoft.gsqlparser.stmt.TSelectSqlStatement) subParser.sqlstatements.get(0); 1930 if (subSelect.tables != null && subSelect.tables.size() > 0) { 1931 TTable onTable = subSelect.tables.getTable(0); 1932 // If it has a subquery, analyze its tables 1933 if (onTable.getSubquery() != null) { 1934 for (int i = 0; i < onTable.getSubquery().tables.size(); i++) { 1935 TTable sourceTable = onTable.getSubquery().tables.getTable(i); 1936 addNPathSourceTable(sourceTable, psql); 1937 } 1938 } 1939 } 1940 } 1941 } 1942 } else { 1943 // It's a direct table reference - extract until whitespace or special char 1944 StringBuilder tableName = new StringBuilder(); 1945 for (int i = 0; i < afterOn.length(); i++) { 1946 char c = afterOn.charAt(i); 1947 if (Character.isWhitespace(c) || c == ')' || c == ',') { 1948 break; 1949 } 1950 tableName.append(c); 1951 } 1952 if (tableName.length() > 0) { 1953 // Parse the table reference 1954 TGSqlParser subParser = new TGSqlParser(EDbVendor.dbvteradata); 1955 subParser.sqltext = "SELECT * FROM " + tableName.toString() + " __npath_on"; 1956 if (subParser.parse() == 0 && subParser.sqlstatements.size() > 0) { 1957 gudusoft.gsqlparser.stmt.TSelectSqlStatement subSelect = 1958 (gudusoft.gsqlparser.stmt.TSelectSqlStatement) subParser.sqlstatements.get(0); 1959 if (subSelect.tables != null && subSelect.tables.size() > 0) { 1960 TTable sourceTable = subSelect.tables.getTable(0); 1961 addNPathSourceTable(sourceTable, psql); 1962 } 1963 } 1964 } 1965 } 1966 } catch (Exception e) { 1967 // Silently ignore parsing errors - the main query still works 1968 } 1969 } 1970 1971 /** 1972 * Adds a source table from NPath ON clause to the current statement's table list. 1973 */ 1974 private void addNPathSourceTable(TTable sourceTable, TCustomSqlStatement psql) { 1975 if (sourceTable == null || psql == null) { 1976 return; 1977 } 1978 // Mark the table as coming from NPath ON clause 1979 sourceTable.setNPathOnClauseTable(true); 1980 // Add to the statement's table list 1981 if (psql.tables == null) { 1982 psql.tables = new TTableList(); 1983 } 1984 psql.tables.addTable(sourceTable); 1985 } 1986 1987}