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}