001package gudusoft.gsqlparser.stmt;
002
003
004import gudusoft.gsqlparser.*;
005import gudusoft.gsqlparser.compiler.TFrame;
006import gudusoft.gsqlparser.compiler.TVariable;
007import gudusoft.gsqlparser.nodes.*;
008import gudusoft.gsqlparser.nodes.mssql.TProcedureOption;
009import gudusoft.gsqlparser.sqlenv.TSQLFunction;
010import gudusoft.gsqlparser.sqlenv.TSQLTable;
011import gudusoft.gsqlparser.stmt.db2.TDb2ReturnStmt;
012import gudusoft.gsqlparser.stmt.mssql.TMssqlBlock;
013import gudusoft.gsqlparser.stmt.mssql.TMssqlReturn;
014
015/**
016 * Create function.
017 *
018 * Supported database:
019 *
020 * <ul>
021 *     <li>BigQuery</li>
022 * </ul>
023 */
024public class TCreateFunctionStmt extends TRoutine{
025
026    private TMssqlBlock block = null;
027    private TMssqlReturn returnStmt = null;
028    private TPTNodeList <TProcedureOption> procedureOptions;
029    private TObjectName returnTableVaraible = null;
030    private TTableElementList returnTableDefinitions = null;
031    private TTypeName returnDataType = null;
032    private int functionType = TBaseType.uftScalar;
033
034    //  private TObjectName outerLabelName = null;
035    private TConstant objfile;
036    private TConstant linkSymbol;
037
038    private String className;
039    private String resourceType;//jar, file
040    private String resourceURI;//
041    private EFunctionReturnsType returnsType = EFunctionReturnsType.frtScalar;
042
043    //private TTypeName returnDataType = null;
044    private int returnMode = TBaseType.function_return_datatype;
045
046    private TExpression sqlExpression;//bigquery
047    private String sharedLibraryName;
048    private TConstant functionDefinition;
049    private TConstant procedureLanguage;
050
051
052    public void setProcedureOptions(TPTNodeList<TProcedureOption> procedureOptions) {
053        this.procedureOptions = procedureOptions;
054    }
055
056    public TPTNodeList<TProcedureOption> getProcedureOptions() {
057        return procedureOptions;
058    }
059
060
061     // TGSqlParser newParser ;
062//    static int gCount;
063//    static {
064//        //newParser = new TGSqlParser(EDbVendor.dbvpostgresql);
065//        gCount = 0;
066//    }
067    public TCreateFunctionStmt (EDbVendor dbvendor){
068        super(dbvendor);
069        sqlstatementtype = ESqlStatementType.sstcreatefunction ;
070       // newParser = new TGSqlParser(EDbVendor.dbvpostgresql);
071    }
072
073    private TObjectName functionName = null;
074    @Override
075    public TObjectName getStoredProcedureName(){
076        return functionName;
077    }
078    /**
079     * The name that you give to the function that you are declaring or defining.
080     * @return
081     */
082    public TObjectName getFunctionName() {
083        return functionName;
084    }
085
086    public EFunctionReturnsType getReturnsType() {
087        return returnsType;
088    }
089
090    public int getReturnMode() {
091        return returnMode;
092    }
093
094    /**
095     *
096     * @return statements in create function
097     */
098    public TMssqlBlock getBlock() {
099        return block;
100    }
101
102    /**
103     *
104     * @return this is the only return statement in create function.
105     */
106    public TMssqlReturn getReturnStmt() {
107        return returnStmt;
108    }
109
110    public TObjectName getReturnTableVaraible() {
111        return returnTableVaraible;
112    }
113
114    /**
115     * when {@link #getReturnsType()} == {@link EFunctionReturnsType#frtMultiStatementTableValue}
116     * returns this table_type_definition
117     *
118     * @return table_type_definition
119     */
120    public TTableElementList getReturnTableDefinitions() {
121        return returnTableDefinitions;
122    }
123    public TTypeName getReturnDataType() {
124        return returnDataType;
125    }
126
127    /**
128     * this is used for backward compatibility  of .NET version TMssqlCreateFunction.functiontype
129     * please use {@link #returnMode} in java version
130     * @return
131     */
132    public int getFunctionType() {
133        int ret = this.functionType;
134        if (this.returnMode == TBaseType.function_return_table_variable){
135            ret = TBaseType.uftMultiStatementTableValued;
136        }else if (this.returnMode == TBaseType.function_return_table){
137            ret = TBaseType.uftInlineTableValued;
138        }
139        return ret;
140    }
141
142    public TConstant getObjfile() {
143        return objfile;
144    }
145    public TConstant getLinkSymbol() {
146        return linkSymbol;
147    }
148    public String getClassName() {
149        return className;
150    }
151    public String getResourceType() {
152        return resourceType;
153    }
154    public String getResourceURI() {
155        return resourceURI;
156    }
157
158    public void setSqlExpression(TExpression sqlExpression) {
159        this.sqlExpression = sqlExpression;
160    }
161    public TExpression getSqlExpression() {
162        return sqlExpression;
163    }
164    public String getSharedLibraryName() {
165        return sharedLibraryName;
166    }
167    public TConstant getFunctionDefinition() {
168        return functionDefinition;
169    }
170    public TConstant getProcedureLanguage() {
171        return procedureLanguage;
172    }
173
174
175    private void redshiftFunctionDefinition(TCustomSqlStatement psql,TCreateFunctionSqlNode createFunctionNode){
176        language = TRoutine.LANGUAGE_UNKNOWN;
177        if ((createFunctionNode.getFunctionBody() != null)&&(getProcedureLanguage().toString().equalsIgnoreCase("sql"))){
178            language = TRoutine.LANGUAGE_SQL;
179            String bodyStr  = createFunctionNode.getFunctionBody().getStartToken().getQuotedString();//.trim();
180            if (createFunctionNode.getFunctionBody().getStartToken().toString().startsWith("'")){
181                bodyStr = bodyStr.replaceAll("''","'");
182            }
183
184
185            //System.out.println(bodyStr);
186            int testLen = 9;
187            if (bodyStr.trim().length() < testLen) testLen = bodyStr.trim().length();
188
189            String prefixStr = bodyStr.trim().substring(0,testLen).toLowerCase();
190            boolean isExpression = true;
191            TGSqlParser newParser = new TGSqlParser(this.dbvendor);
192
193            newParser.sqltext =
194                    TBaseType.stringBlock(
195                            (int)createFunctionNode.getFunctionBody().getStartToken().lineNo - 1,
196                            (int)createFunctionNode.getFunctionBody().getStartToken().columnNo + createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength()-1
197                    )
198                    + bodyStr;
199
200            newParser.setFrameStack(getFrameStack());
201            int iRet = newParser.parse();
202            if ((iRet == 0)&&(newParser.getSqlstatements().size() >0)){
203//                this.blockBody = new TBlockSqlNode();
204//                this.blockBody.setParsed(true);
205//                this.blockBody.getBodyStatements().add(newParser.getSqlstatements().get(0));
206
207               this.getBodyStatements().add(newParser.getSqlstatements().get(0));
208            }else {
209                for(int j=0;j<newParser.getErrorCount();j++){
210                    this.parseerrormessagehandle(newParser.getSyntaxErrors().get(j));
211                }
212            }
213        }
214
215    }
216
217    private void postgresqlFunctionDefinition(TCustomSqlStatement psql,TCreateFunctionSqlNode createFunctionNode){
218        language =  TRoutine.LANGUAGE_UNKNOWN;
219        if ((createFunctionNode.getFunctionBody() != null)&&(getProcedureLanguage()!=null)&&(getProcedureLanguage().toString() !=null)) {
220            if (getProcedureLanguage().toString().equalsIgnoreCase("sql")) language = TRoutine.LANGUAGE_SQL;
221            else if (getProcedureLanguage().toString().equalsIgnoreCase("plpgsql")) language = TRoutine.LANGUAGE_PLPGSQL;
222            else if (getProcedureLanguage().toString().equalsIgnoreCase("'plpgsql'")) language = TRoutine.LANGUAGE_PLPGSQL;
223
224            if ((language == TRoutine.LANGUAGE_SQL)||(language == TRoutine.LANGUAGE_PLPGSQL))
225            {
226
227                String bodyStr = createFunctionNode.getFunctionBody().getStartToken().getQuotedString();//.trim();
228                // System.out.println(bodyStr);
229                //long lineNo = createFunctionNode.getFunctionBody().getStartToken().lineNo ;
230                // CREATE OR REPLACE FUNCTION testspg__getString (varchar) RETURNS varchar as ' DECLARE inString alias for $1; begin return ''bob''; end; ' LANGUAGE plpgsql
231                // escaped quotes in string literals
232                // mantisbt/view.php?id=1331
233                if (createFunctionNode.getFunctionBody().getStartToken().toString().startsWith("'")) {
234                    bodyStr = bodyStr.replaceAll("''", "'");
235                }
236
237
238                // System.out.println(bodyStr);
239                //String prefixStr = bodyStr.trim().substring(0, (bodyStr.trim().length() < 9 ? bodyStr.trim().length() : 9)).toLowerCase();
240                //String suffixStr = bodyStr.trim().length() <= 7 ? bodyStr.trim() : bodyStr.trim().substring(bodyStr.trim().length() - 7);
241                                
242                String bodyStrTrim = bodyStr.trim();
243                int bodyStringLength = bodyStrTrim.length();
244                String prefixStr = bodyStringLength <= 7 ? bodyStrTrim.toLowerCase() : bodyStrTrim.substring(0, 7).toLowerCase();
245                String suffixStr = bodyStringLength <= 7 ? prefixStr : bodyStrTrim.substring(bodyStringLength - 7).toLowerCase();
246                                
247                boolean isSQLBlock = true;
248                TGSqlParser newParser = new TGSqlParser(EDbVendor.dbvpostgresql);
249                if ((prefixStr.startsWith("declare")) || (prefixStr.startsWith("begin")) || (prefixStr.startsWith("<<"))
250                        // || (((suffixStr.toLowerCase().endsWith("end")) || (suffixStr.toLowerCase().endsWith("end;")))&&((!prefixStr.startsWith("select"))))
251                                                   || (((suffixStr.endsWith("end")) || (suffixStr.endsWith("end;")))&&((!prefixStr.startsWith("select"))))
252                ) {
253                    //bodyStr.replaceAll("''","'");
254                    //System.out.println(bodyStr);
255
256                    newParser.sqltext = "plpgsql_function_delimiter\n"
257                            + TBaseType.stringBlock((int) createFunctionNode.getFunctionBody().getStartToken().lineNo - 2, (int) createFunctionNode.getFunctionBody().getStartToken().columnNo + createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength() - 1)
258                            + bodyStr;
259                } else {
260                    newParser.sqltext =
261                            TBaseType.stringBlock(
262                                    (int) createFunctionNode.getFunctionBody().getStartToken().lineNo - 1,
263                                    (int) createFunctionNode.getFunctionBody().getStartToken().columnNo + createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength() - 1)
264                                    + bodyStr;
265                    isSQLBlock = false;
266                }
267
268                newParser.setFrameStack(getFrameStack());
269                // we only need a raw parse tree
270                // newParser.setOnlyNeedRawParseTree(true);
271                int iRet = newParser.parse();
272                if ((iRet == 0) && (newParser.getSqlstatements().size() > 0)) {
273                    if (isSQLBlock) {
274                        TCommonBlock lcBlock = (TCommonBlock) newParser.getSqlstatements().get(0);
275                        this.blockBody = lcBlock.getBlockBody();
276                        this.blockBody.setParent(this);
277
278
279//                        this.setOuterLabelName(lcBlock.getLabelName());
280//                        for(int i=0;i<lcBlock.getDeclareStatements().size();i++){
281//                            this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjVariable,this,lcBlock.getDeclareStatements().get(i)));
282//                            this.getDeclareStatements().add(lcBlock.getDeclareStatements().get(i));
283//                        }
284//                        for(int i=0;i<lcBlock.getBodyStatements().size();i++){
285//                            lcBlock.getBodyStatements().get(i).setAlreadyAddToParent(false);
286//                            lcBlock.getBodyStatements().get(i).setParentStmt(this);
287//                            //commonBlock.getBodyStatements().get(i).doParseStatement(this);
288//                            this.getBodyStatements().add(lcBlock.getBodyStatements().get(i));
289//                        }
290//                        if (lcBlock.getExceptionClause() != null){
291//                            this.setExceptionClause(lcBlock.getExceptionClause());
292//                        }
293//                        for(int i=0;i<lcBlock.getDeclareStatements().size();i++){
294//                            this.getTopStatement().getSymbolTable().pop();
295//                        }
296                    }else{
297                        this.getBodyStatements().add(newParser.getSqlstatements().get(0));
298//                        TStatementListSqlNode lcStmts = new TStatementListSqlNode();
299//                        TStatementSqlNode lcSqlNode = new TStatementSqlNode();
300//                        lcSqlNode.setSqlNode(newParser.getSqlstatements().get(0).rootNode);
301//                        lcStmts.addStatementSqlNode(lcSqlNode);
302//                        this.blockBody = new TBlockSqlNode();
303//                        this.blockBody.init(lcStmts);
304                    }
305                } else {
306                        for (int j = 0; j < newParser.getErrorCount(); j++) {
307                            this.parseerrormessagehandle(newParser.getSyntaxErrors().get(j));
308                        }
309                }
310
311                }
312            }
313
314    }
315
316    private void snowflakeFunctionDefinition(TCustomSqlStatement psql,TCreateFunctionSqlNode createFunctionNode){
317        language = TRoutine.LANGUAGE_UNKNOWN;
318        if ((createFunctionNode.getFunctionBody() != null)
319                &&((getProcedureLanguage()==null)||((getProcedureLanguage()!=null)&&(getProcedureLanguage().toString().equalsIgnoreCase("SQL"))))){
320                language = TRoutine.LANGUAGE_SQL;
321                String bodyStr  = createFunctionNode.getFunctionBody().getStartToken().getQuotedString();//.trim();
322                // CREATE OR REPLACE FUNCTION testspg__getString (varchar) RETURNS varchar as ' DECLARE inString alias for $1; begin return ''bob''; end; ' LANGUAGE plpgsql
323                // escaped quotes in string literals
324                // mantisbt/view.php?id=1331
325                if (createFunctionNode.getFunctionBody().getStartToken().toString().startsWith("'")){
326                    // Unescape C-style backslash escapes (\' -> ') before SQL-standard escapes
327                    // Snowflake supports both \' and '' for escaping single quotes in string literals
328                    bodyStr = bodyStr.replace("\\'", "'");
329                    bodyStr = bodyStr.replaceAll("''","'");
330                }
331
332                //System.out.println(bodyStr);
333                String trimmedBody = bodyStr.trim();
334
335                // Skip re-parsing for non-SQL bodies (e.g., SPCS URL paths like '/echo')
336                if (trimmedBody.length() > 0 && !Character.isLetterOrDigit(trimmedBody.charAt(0))
337                        && trimmedBody.charAt(0) != '(' && trimmedBody.charAt(0) != '-'
338                        && trimmedBody.charAt(0) != '+' && trimmedBody.charAt(0) != '\'') {
339                    return;
340                }
341
342                int testLen = 9;
343                if (trimmedBody.length() < testLen) testLen = trimmedBody.length();
344                String prefixStr = trimmedBody.substring(0,testLen).toLowerCase();
345                boolean isExpression = true;
346                TGSqlParser newParser = new TGSqlParser(this.dbvendor);
347                if ((prefixStr.startsWith("select"))||(prefixStr.startsWith("insert"))||(prefixStr.startsWith("delete"))||(prefixStr.startsWith("update"))){
348                    newParser.sqltext =
349                            TBaseType.stringBlock(
350                                    (int)createFunctionNode.getFunctionBody().getStartToken().lineNo - 1,
351                                    (int)createFunctionNode.getFunctionBody().getStartToken().columnNo + createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength()-1)
352                                + bodyStr;
353
354                    isExpression = false;
355                }else{
356                    newParser.sqltext = "pseudo_expr_sign\n"+
357                             TBaseType.stringBlock((int)createFunctionNode.getFunctionBody().getStartToken().lineNo - 2
358                            ,(int)createFunctionNode.getFunctionBody().getStartToken().columnNo+ createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength()-1)
359                            +bodyStr;
360                }
361
362                newParser.setFrameStack(getFrameStack());
363                int iRet = newParser.parse();
364                if ((iRet == 0)&&(newParser.getSqlstatements().size() >0)){
365                    this.getBodyStatements().add(newParser.getSqlstatements().get(0));
366                }else {
367                    for(int j=0;j<newParser.getErrorCount();j++){
368                        this.parseerrormessagehandle(newParser.getSyntaxErrors().get(j));
369                    }
370                }
371        }
372
373    }
374
375    private TSelectSqlStatement sqlQuery;
376
377    public TSelectSqlStatement getSqlQuery() {
378        return sqlQuery;
379    }
380
381    public int doParseStatement(TCustomSqlStatement psql) {
382        if (rootNode == null) return -1;
383        TCreateFunctionSqlNode createFunctionNode = (TCreateFunctionSqlNode)rootNode;
384        if (dbvendor == EDbVendor.dbvpostgresql){
385            if (super.doParseStatement(psql) != 0) return -1;
386        }else
387            super.doParseStatement(psql);
388
389        TFrame currentFrame = new TFrame(this.stmtScope);
390        currentFrame.pushMeToStack(getFrameStack());
391
392        functionName = createFunctionNode.getFunctionName();
393
394        if (getSqlEnv() != null) {
395            getSqlEnv().addFunction(functionName,true);
396
397            // move to TDatabaseObjectResolver
398
399//            if (getSqlEnv().getDefaultCatalogName() != null){
400//                if (functionName.getDatabaseToken() == null){
401//                    functionName.setDatabaseToken(new TSourceToken(getSqlEnv().getDefaultCatalogName()));
402//                }
403//            }
404        }
405
406        // sql server
407        procedureOptions = createFunctionNode.getProcedureOptions();
408        //end sql server
409
410        if (createFunctionNode.getProcedureLanguage() != null){
411            // language name is retrieved through parser
412            procedureLanguage = createFunctionNode.getProcedureLanguage();
413            setRoutineBodyInConstant(procedureLanguage);
414            setRoutineLanguage(procedureLanguage.toString());
415        }else if (getRoutineLanguage() != null){
416            // language name is retrieved during TGsqlParser.dopostgresqlgetrawsqlstatements()
417        }
418
419//        procedureLanguage = createFunctionNode.getProcedureLanguage();
420//        if (procedureLanguage != null){
421//            setRoutineBodyInConstant(procedureLanguage);
422//            setRoutineLanguage(procedureLanguage.toString());
423//        }
424//
425//        // postgresql
426//        procedureLanguage = createFunctionNode.getProcedureLanguage();
427//        if (getRoutineLanguage() == null){
428//            // not already set during TGsqlParser.dopostgresqlgetrawsqlstatements()
429//            // then we set it here
430//            if (procedureLanguage != null){
431//                setRoutineLanguage(procedureLanguage.toString());
432//            }
433//        }
434
435        //outerLabelName = createFunctionNode.getLabelName();
436        objfile = createFunctionNode.getObjfile();
437        linkSymbol = createFunctionNode.getLinkSymbol();
438        this.className = createFunctionNode.getClassName();
439        this.resourceType = createFunctionNode.getResourceType();
440        this.resourceURI = createFunctionNode.getResourceURI();
441
442
443        if (createFunctionNode.getReturnDataType() != null){
444            this.returnMode = TBaseType.function_return_datatype;
445            this.returnDataType = createFunctionNode.getReturnDataType();
446        }else if (createFunctionNode.getReturnTable() != null){
447            TDummy dmy = createFunctionNode.getReturnTable();
448            this.returnMode = TBaseType.function_return_table;
449            if (dmy.list1 instanceof TTableElementList){ // hana includes TParameterDeclarationList type which is not this type
450                this.returnTableDefinitions = (TTableElementList)dmy.list1;
451                this.returnTableDefinitions.doParse(this,ESqlClause.unknown);
452            }
453        }
454        // end of postgresql
455
456        this.setParameterDeclarations(createFunctionNode.getParameters());
457
458        // sql server
459        if (createFunctionNode.getReturnDataType() != null){
460            this.returnMode = TBaseType.function_return_datatype;
461            this.returnDataType = createFunctionNode.getReturnDataType();
462            this.returnsType = EFunctionReturnsType.frtScalar;
463        }else if (createFunctionNode.getReturnTable() != null){
464            TDummy dmy = createFunctionNode.getReturnTable();
465            if (dmy.node1 != null){
466                this.returnsType = EFunctionReturnsType.frtMultiStatementTableValue;
467                this.returnMode = TBaseType.function_return_table_variable;
468                this.returnTableVaraible = (TObjectName)dmy.node1;
469                this.returnTableVaraible.setObjectType(TObjectName.ttobjVariable);
470                this.returnTableDefinitions = (TTableElementList)dmy.list1;
471                this.returnTableDefinitions.doParse(this,ESqlClause.unknown);
472
473                if (getSqlEnv() != null)  {
474                    TSQLTable returnTable = getSqlEnv().addTable(this.returnTableVaraible.toString(),true);
475                    //TSQLFunction functionTable = getSqlEnv().searchFunction(functionName.toString());
476                    TSQLFunction functionTable = getSqlEnv().searchFunction(functionName);
477
478                    if (functionTable == null){
479                        TBaseType.log(String.format("Table function: <%s> is not found in SQL Evn", functionName.toString()),TLog.WARNING,functionName);
480                        //System.out.println("Function not found:"+functionName.toString());
481                        //System.out.println(getSqlEnv().toString());
482                    }
483
484                    for(TTableElement column: this.returnTableDefinitions){
485                        if(column.getColumnDefinition()!=null && column.getColumnDefinition().getColumnName()!=null){
486                            returnTable.addColumn(column.getColumnDefinition().getColumnName().toString());
487                            if (functionTable != null) {
488                                functionTable.addReturnColumn(column.getColumnDefinition().getColumnName().toString());
489                            }
490                        }
491                    }
492                }
493            }else{
494                this.returnMode = TBaseType.function_return_table;
495                this.returnsType = EFunctionReturnsType.frtInlineTableValue;
496            }
497        }
498        // end sql server
499
500        // push parameterDeclarations into symbolTable
501        if (this.getParameterDeclarations() != null){
502            for(int i=0;i< this.getParameterDeclarations().size();i++){
503                this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjParameter,this, this.getParameterDeclarations().getParameterDeclarationItem(i)));
504                TParameterDeclaration parameterDeclaration = this.getParameterDeclarations().getParameterDeclarationItem(i);
505                if (parameterDeclaration.getParameterName() != null){
506                    this.stmtScope.addSymbol(new TVariable(parameterDeclaration.getParameterName(),parameterDeclaration,functionName));
507                }
508            }
509        }
510
511
512        switch (this.dbvendor){
513            case dbvsnowflake:
514                if (createFunctionNode.getBlcok() != null){
515                    // $$ body $$ 在这里处理
516                    createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown);
517                    this.blockBody = createFunctionNode.getBlcok();
518                }else  {
519                    // 'body' 在这里处理
520                    snowflakeFunctionDefinition(psql,createFunctionNode);
521                }
522
523                break;
524            case dbvpostgresql:
525            case dbvgreenplum:
526            case dbvredshift:
527                if (createFunctionNode.getFunctionBody() != null){
528                    // function body only inside '' will be processed here
529                    postgresqlFunctionDefinition(psql,createFunctionNode);
530                }else{
531                    // function body only inside $$ will be processed here
532
533                    if (createFunctionNode.getBlcok() != null){
534                        createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown);
535                        this.blockBody = createFunctionNode.getBlcok();
536                    }else  if (createFunctionNode.getStmt() != null){
537                        createFunctionNode.getStmt().doParse(this, ESqlClause.unknown);
538                        this.getBodyStatements().add(createFunctionNode.getStmt().getStmt());
539                    }else {
540                        // there is no function body is language is not in sql or plsql,
541                        // such as LANGUAGE plpython3u
542                    }
543                }
544                break;
545//            case dbvgreenplum:
546//                postgresqlFunctionDefinition(psql,createFunctionNode);
547//                break;
548            case dbvmssql:
549                if (createFunctionNode.getBlcok() != null){
550                    block = new TMssqlBlock(this.dbvendor);
551                    block.rootNode = createFunctionNode.getBlcok();
552                    block.doParseStatement(this);
553                    this.getBodyStatements().add(block);
554                }
555
556                if (createFunctionNode.getReturnSqlNode() != null){
557                    returnStmt = new TMssqlReturn(this.dbvendor);
558                    returnStmt.rootNode = createFunctionNode.getReturnSqlNode();
559                    returnStmt.doParseStatement(this);
560                    this.getBodyStatements().add(returnStmt);
561                }
562
563                break;
564            case dbvmysql:
565                if (createFunctionNode.getStmt() != null){
566                    createFunctionNode.getStmt().doParse(this,ESqlClause.unknown);
567                    this.getBodyStatements().add(createFunctionNode.getStmt().getStmt());
568                }
569                else if (createFunctionNode.getBlcok() != null){
570                    createFunctionNode.getBlcok().getStmts().doParse(this,ESqlClause.unknown);
571
572                    for(int i=0;i<createFunctionNode.getBlcok().getStmts().size();i++){
573                        this.getBodyStatements().add(createFunctionNode.getBlcok().getStmts().getStatementSqlNode(i).getStmt());
574                    }
575                }
576                break;
577            case dbvbigquery:
578                if (createFunctionNode.getSqlQuery() != null){
579                    sqlQuery = new TSelectSqlStatement(this.dbvendor);
580                    sqlQuery.rootNode = createFunctionNode.getSqlQuery();
581                    sqlQuery.doParseStatement(this);
582                    this.returnMode = TBaseType.function_return_datatype;
583                    this.returnDataType = createFunctionNode.getReturnDataType();
584                    this.returnsType = EFunctionReturnsType.frtInlineTableValue;
585                    this.getBodyStatements().add(sqlQuery);
586                }
587                break;
588            case dbvdb2:
589                TCompoundSqlNode compoundSqlNode = createFunctionNode.getCompoundSql();
590               // TReturnSqlNode returnSqlNode = createFunctionNode.getReturnSqlNode();
591
592                if (compoundSqlNode != null){
593                    if (compoundSqlNode.getDeclareStmts() != null){
594                        compoundSqlNode.getDeclareStmts().doParse(this,ESqlClause.unknown);
595
596                        // push variable declare into symbolTable, and add to declareStatements
597                        for(int i=0;i<compoundSqlNode.getDeclareStmts().size();i++){
598                            this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjVariable,this,compoundSqlNode.getDeclareStmts().getStatementSqlNode(i).getStmt() ));
599                            this.getDeclareStatements().add(compoundSqlNode.getDeclareStmts().getStatementSqlNode(i).getStmt());
600                        }
601                    }
602
603                    if (compoundSqlNode.getStmts() != null){
604                        compoundSqlNode.getStmts().doParse(this,ESqlClause.unknown);
605
606                        for(int i= 0; i<compoundSqlNode.getStmts().size();i++){
607                            this.getBodyStatements().add(compoundSqlNode.getStmts().getStatementSqlNode(i).getStmt());
608                        }
609                    }
610
611                    if (compoundSqlNode.getDeclareStmts() != null){
612                        // pop variable declare from symbolTable
613                        for(int i=0;i<compoundSqlNode.getDeclareStmts().size();i++){
614                            this.getTopStatement().getSymbolTable().pop();
615                        }
616                    }
617                }else if (createFunctionNode.getReturnSqlNode() != null){
618                    returnStmt = new TMssqlReturn(this.dbvendor);
619                    returnStmt.rootNode = createFunctionNode.getReturnSqlNode();
620                    returnStmt.doParseStatement(this);
621                    this.getBodyStatements().add(returnStmt);
622                }
623
624                break;
625            default:
626                if (createFunctionNode.getStmt() != null){
627                    createFunctionNode.getStmt().doParse(this, ESqlClause.unknown);
628                    this.getBodyStatements().add(createFunctionNode.getStmt().getStmt());
629//                    TStatementListSqlNode lcStmts = new TStatementListSqlNode();
630//                    lcStmts.addStatementSqlNode(createFunctionNode.getStmt());
631//                    this.blockBody = new TBlockSqlNode();
632//                    this.blockBody.init(lcStmts);
633                }
634                else if (createFunctionNode.getBlcok() != null){
635                    createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown);
636                    //createFunctionNode.getBlcok().getStmts().doParse(this,ESqlClause.unknown);
637//
638//                    for(int i=0;i<createFunctionNode.getBlcok().getStmts().size();i++){
639//                        this.getBodyStatements().add(createFunctionNode.getBlcok().getStmts().getStatementSqlNode(i).getStmt());
640//                    }
641                    this.blockBody = createFunctionNode.getBlcok();
642                }
643                break;
644        }
645
646
647
648
649        // pop parameterDeclarations from symbolTable
650        if (this.getParameterDeclarations() != null){
651            for(int i=0;i< this.getParameterDeclarations().size();i++){
652                this.getTopStatement().getSymbolTable().pop();
653            }
654        }
655
656        if (createFunctionNode.getSharedLibraryName() != null){
657            sharedLibraryName = createFunctionNode.getSharedLibraryName().toString();
658        }
659
660        functionDefinition  = createFunctionNode.getFunctionDefinition();
661        if (functionDefinition != null){
662            setRoutineBodyInConstant(functionDefinition);
663            setRoutineBody(functionDefinition.toString());
664        }
665
666        this.sqlExpression = createFunctionNode.getSqlExpression();
667        if (this.sqlExpression != null){
668            this.sqlExpression.doParse(this,ESqlClause.unknown);
669        }
670
671        // StarRocks-specific fields
672        this.starrocksGlobal = createFunctionNode.isStarrocksGlobal();
673        this.starrocksAggregate = createFunctionNode.isStarrocksAggregate();
674        this.starrocksTableFunction = createFunctionNode.isStarrocksTableFunction();
675        this.starrocksOrReplace = createFunctionNode.isStarrocksOrReplace();
676        this.starrocksIntermediateType = createFunctionNode.getStarrocksIntermediateType();
677        this.starrocksProperties = createFunctionNode.getStarrocksProperties();
678
679        //endlabelName = createFunctionNode.getEndlabelName();
680        currentFrame.popMeFromStack(getFrameStack());
681
682        return 0;
683    }
684
685    public void accept(TParseTreeVisitor v){
686        v.preVisit(this);
687        v.postVisit(this);
688    }
689
690    public void acceptChildren(TParseTreeVisitor v){
691        v.preVisit(this);
692        this.getFunctionName().acceptChildren(v);
693        if (getParameterDeclarations() != null) getParameterDeclarations().acceptChildren(v);
694        if (blockBody != null){
695            blockBody.acceptChildren(v);
696        }else if (getBodyStatements().size() > 0){
697            getBodyStatements().acceptChildren(v);
698        }
699        // Visit sqlExpression for BigQuery functions where body is an expression (e.g., AS ((SELECT ...)))
700        // This ensures UNNEST tables and column references inside the expression are collected
701        if (sqlExpression != null) {
702            sqlExpression.acceptChildren(v);
703        }
704        if (returnStmt != null) returnStmt.acceptChildren(v);
705        v.postVisit(this);
706    }
707
708
709    public void setFunctionName(TObjectName functionName) {
710        this.functionName = functionName;
711    }
712
713    public void setBlock(TMssqlBlock block) {
714        this.block = block;
715    }
716    public void setReturnStmt(TMssqlReturn returnStmt) {
717        this.returnStmt = returnStmt;
718    }
719    public void setReturnMode(int returnMode) {
720        this.returnMode = returnMode;
721    }
722    public void setReturnTableVaraible(TObjectName returnTableVaraible) {
723        this.returnTableVaraible = returnTableVaraible;
724    }
725    public void setReturnTableDefinitions(TTableElementList returnTableDefinitions) {
726        this.returnTableDefinitions = returnTableDefinitions;
727    }
728    public void setReturnDataType(TTypeName returnDataType) {
729        this.returnDataType = returnDataType;
730    }
731    public void setFunctionType(int functionType) {
732        this.functionType = functionType;
733    }
734
735    // StarRocks-specific fields
736    private boolean starrocksGlobal = false;
737    private boolean starrocksAggregate = false;
738    private boolean starrocksTableFunction = false;
739    private boolean starrocksOrReplace = false;
740    private TTypeName starrocksIntermediateType = null;
741    private TPTNodeList starrocksProperties = null;
742
743    public boolean isStarrocksGlobal() { return starrocksGlobal; }
744    public boolean isStarrocksAggregate() { return starrocksAggregate; }
745    public boolean isStarrocksTableFunction() { return starrocksTableFunction; }
746    public boolean isStarrocksOrReplace() { return starrocksOrReplace; }
747    public TTypeName getStarrocksIntermediateType() { return starrocksIntermediateType; }
748    public TPTNodeList getStarrocksProperties() { return starrocksProperties; }
749
750}