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     * , '&lt;contains_search_condition&gt;'
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     * , '&lt;contains_search_condition&gt;'
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 = '&lt;Root&gt;
558     *     &lt;ProductDescription ProductID="1" ProductName="Road Bike"&gt;
559     *     &lt;Features&gt;
560     *     &lt;Warranty&gt;1 year parts and labor &lt;/Warranty&gt;
561     *     &lt;Maintenance&gt;3 year parts and labor extended maintenance is available &lt;/Maintenance&gt;
562     *     &lt;/Features&gt;
563     *     &lt;/ProductDescription&gt;
564     *     &lt;/Root&gt;'
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}