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 // Keep only the column padding (stringBlock first arg 0); the line 194 // offset is applied after parsing so it is never capped at 1000. 195 int bodyDeltaLine = (int)createFunctionNode.getFunctionBody().getStartToken().lineNo - 1; 196 newParser.sqltext = 197 TBaseType.stringBlock( 198 0, 199 (int)createFunctionNode.getFunctionBody().getStartToken().columnNo + createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength()-1 200 ) 201 + bodyStr; 202 203 newParser.setFrameStack(getFrameStack()); 204 int iRet = newParser.parse(); 205 TReparseCoordinateShifter.shift(newParser, bodyDeltaLine, 0); 206 if ((iRet == 0)&&(newParser.getSqlstatements().size() >0)){ 207// this.blockBody = new TBlockSqlNode(); 208// this.blockBody.setParsed(true); 209// this.blockBody.getBodyStatements().add(newParser.getSqlstatements().get(0)); 210 211 this.getBodyStatements().add(newParser.getSqlstatements().get(0)); 212 }else { 213 for(int j=0;j<newParser.getErrorCount();j++){ 214 this.parseerrormessagehandle(newParser.getSyntaxErrors().get(j)); 215 } 216 } 217 } 218 219 } 220 221 private void postgresqlFunctionDefinition(TCustomSqlStatement psql,TCreateFunctionSqlNode createFunctionNode){ 222 language = TRoutine.LANGUAGE_UNKNOWN; 223 if ((createFunctionNode.getFunctionBody() != null)&&(getProcedureLanguage()!=null)&&(getProcedureLanguage().toString() !=null)) { 224 if (getProcedureLanguage().toString().equalsIgnoreCase("sql")) language = TRoutine.LANGUAGE_SQL; 225 else if (getProcedureLanguage().toString().equalsIgnoreCase("plpgsql")) language = TRoutine.LANGUAGE_PLPGSQL; 226 else if (getProcedureLanguage().toString().equalsIgnoreCase("'plpgsql'")) language = TRoutine.LANGUAGE_PLPGSQL; 227 228 if ((language == TRoutine.LANGUAGE_SQL)||(language == TRoutine.LANGUAGE_PLPGSQL)) 229 { 230 231 String bodyStr = createFunctionNode.getFunctionBody().getStartToken().getQuotedString();//.trim(); 232 // System.out.println(bodyStr); 233 //long lineNo = createFunctionNode.getFunctionBody().getStartToken().lineNo ; 234 // CREATE OR REPLACE FUNCTION testspg__getString (varchar) RETURNS varchar as ' DECLARE inString alias for $1; begin return ''bob''; end; ' LANGUAGE plpgsql 235 // escaped quotes in string literals 236 // mantisbt/view.php?id=1331 237 if (createFunctionNode.getFunctionBody().getStartToken().toString().startsWith("'")) { 238 bodyStr = bodyStr.replaceAll("''", "'"); 239 } 240 241 242 // System.out.println(bodyStr); 243 //String prefixStr = bodyStr.trim().substring(0, (bodyStr.trim().length() < 9 ? bodyStr.trim().length() : 9)).toLowerCase(); 244 //String suffixStr = bodyStr.trim().length() <= 7 ? bodyStr.trim() : bodyStr.trim().substring(bodyStr.trim().length() - 7); 245 246 String bodyStrTrim = bodyStr.trim(); 247 int bodyStringLength = bodyStrTrim.length(); 248 String prefixStr = bodyStringLength <= 7 ? bodyStrTrim.toLowerCase() : bodyStrTrim.substring(0, 7).toLowerCase(); 249 String suffixStr = bodyStringLength <= 7 ? prefixStr : bodyStrTrim.substring(bodyStringLength - 7).toLowerCase(); 250 251 boolean isSQLBlock = true; 252 TGSqlParser newParser = new TGSqlParser(EDbVendor.dbvpostgresql); 253 // Keep only the column padding (stringBlock first arg 0); the 254 // line offset is applied after parsing so it is never capped at 255 // 1000. The marker line "plpgsql_function_delimiter\n" occupies 256 // parser line 1, so the body starts on parser line 2 and the 257 // delta there is (lineNo - 2); without the marker it is 258 // (lineNo - 1). 259 int bodyDeltaLine; 260 if ((prefixStr.startsWith("declare")) || (prefixStr.startsWith("begin")) || (prefixStr.startsWith("<<")) 261 // || (((suffixStr.toLowerCase().endsWith("end")) || (suffixStr.toLowerCase().endsWith("end;")))&&((!prefixStr.startsWith("select")))) 262 || (((suffixStr.endsWith("end")) || (suffixStr.endsWith("end;")))&&((!prefixStr.startsWith("select")))) 263 ) { 264 //bodyStr.replaceAll("''","'"); 265 //System.out.println(bodyStr); 266 267 bodyDeltaLine = (int) createFunctionNode.getFunctionBody().getStartToken().lineNo - 2; 268 newParser.sqltext = "plpgsql_function_delimiter\n" 269 + TBaseType.stringBlock(0, (int) createFunctionNode.getFunctionBody().getStartToken().columnNo + createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength() - 1) 270 + bodyStr; 271 } else { 272 bodyDeltaLine = (int) createFunctionNode.getFunctionBody().getStartToken().lineNo - 1; 273 newParser.sqltext = 274 TBaseType.stringBlock( 275 0, 276 (int) createFunctionNode.getFunctionBody().getStartToken().columnNo + createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength() - 1) 277 + bodyStr; 278 isSQLBlock = false; 279 } 280 281 newParser.setFrameStack(getFrameStack()); 282 // we only need a raw parse tree 283 // newParser.setOnlyNeedRawParseTree(true); 284 int iRet = newParser.parse(); 285 TReparseCoordinateShifter.shift(newParser, bodyDeltaLine, 0); 286 if ((iRet == 0) && (newParser.getSqlstatements().size() > 0)) { 287 if (isSQLBlock) { 288 TCommonBlock lcBlock = (TCommonBlock) newParser.getSqlstatements().get(0); 289 this.blockBody = lcBlock.getBlockBody(); 290 this.blockBody.setParent(this); 291 292 293// this.setOuterLabelName(lcBlock.getLabelName()); 294// for(int i=0;i<lcBlock.getDeclareStatements().size();i++){ 295// this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjVariable,this,lcBlock.getDeclareStatements().get(i))); 296// this.getDeclareStatements().add(lcBlock.getDeclareStatements().get(i)); 297// } 298// for(int i=0;i<lcBlock.getBodyStatements().size();i++){ 299// lcBlock.getBodyStatements().get(i).setAlreadyAddToParent(false); 300// lcBlock.getBodyStatements().get(i).setParentStmt(this); 301// //commonBlock.getBodyStatements().get(i).doParseStatement(this); 302// this.getBodyStatements().add(lcBlock.getBodyStatements().get(i)); 303// } 304// if (lcBlock.getExceptionClause() != null){ 305// this.setExceptionClause(lcBlock.getExceptionClause()); 306// } 307// for(int i=0;i<lcBlock.getDeclareStatements().size();i++){ 308// this.getTopStatement().getSymbolTable().pop(); 309// } 310 }else{ 311 this.getBodyStatements().add(newParser.getSqlstatements().get(0)); 312// TStatementListSqlNode lcStmts = new TStatementListSqlNode(); 313// TStatementSqlNode lcSqlNode = new TStatementSqlNode(); 314// lcSqlNode.setSqlNode(newParser.getSqlstatements().get(0).rootNode); 315// lcStmts.addStatementSqlNode(lcSqlNode); 316// this.blockBody = new TBlockSqlNode(); 317// this.blockBody.init(lcStmts); 318 } 319 } else { 320 for (int j = 0; j < newParser.getErrorCount(); j++) { 321 this.parseerrormessagehandle(newParser.getSyntaxErrors().get(j)); 322 } 323 } 324 325 } 326 } 327 328 } 329 330 private void snowflakeFunctionDefinition(TCustomSqlStatement psql,TCreateFunctionSqlNode createFunctionNode){ 331 language = TRoutine.LANGUAGE_UNKNOWN; 332 if ((createFunctionNode.getFunctionBody() != null) 333 &&((getProcedureLanguage()==null)||((getProcedureLanguage()!=null)&&(getProcedureLanguage().toString().equalsIgnoreCase("SQL"))))){ 334 language = TRoutine.LANGUAGE_SQL; 335 String bodyStr = createFunctionNode.getFunctionBody().getStartToken().getQuotedString();//.trim(); 336 // CREATE OR REPLACE FUNCTION testspg__getString (varchar) RETURNS varchar as ' DECLARE inString alias for $1; begin return ''bob''; end; ' LANGUAGE plpgsql 337 // escaped quotes in string literals 338 // mantisbt/view.php?id=1331 339 if (createFunctionNode.getFunctionBody().getStartToken().toString().startsWith("'")){ 340 // Unescape C-style backslash escapes (\' -> ') before SQL-standard escapes 341 // Snowflake supports both \' and '' for escaping single quotes in string literals 342 bodyStr = bodyStr.replace("\\'", "'"); 343 bodyStr = bodyStr.replaceAll("''","'"); 344 } 345 346 //System.out.println(bodyStr); 347 String trimmedBody = bodyStr.trim(); 348 349 // Skip re-parsing for non-SQL bodies (e.g., SPCS URL paths like '/echo') 350 if (trimmedBody.length() > 0 && !Character.isLetterOrDigit(trimmedBody.charAt(0)) 351 && trimmedBody.charAt(0) != '(' && trimmedBody.charAt(0) != '-' 352 && trimmedBody.charAt(0) != '+' && trimmedBody.charAt(0) != '\'') { 353 return; 354 } 355 356 int testLen = 9; 357 if (trimmedBody.length() < testLen) testLen = trimmedBody.length(); 358 String prefixStr = trimmedBody.substring(0,testLen).toLowerCase(); 359 boolean isExpression = true; 360 TGSqlParser newParser = new TGSqlParser(this.dbvendor); 361 // Keep only the column padding (stringBlock first arg 0); the 362 // line offset is applied after parsing so it is never capped at 363 // 1000. The marker line "pseudo_expr_sign\n" occupies parser 364 // line 1, so the body starts on parser line 2 and the delta 365 // there is (lineNo - 2); without the marker it is (lineNo - 1). 366 int bodyDeltaLine; 367 if ((prefixStr.startsWith("select"))||(prefixStr.startsWith("insert"))||(prefixStr.startsWith("delete"))||(prefixStr.startsWith("update"))){ 368 bodyDeltaLine = (int)createFunctionNode.getFunctionBody().getStartToken().lineNo - 1; 369 newParser.sqltext = 370 TBaseType.stringBlock( 371 0, 372 (int)createFunctionNode.getFunctionBody().getStartToken().columnNo + createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength()-1) 373 + bodyStr; 374 375 isExpression = false; 376 }else{ 377 bodyDeltaLine = (int)createFunctionNode.getFunctionBody().getStartToken().lineNo - 2; 378 newParser.sqltext = "pseudo_expr_sign\n"+ 379 TBaseType.stringBlock(0 380 ,(int)createFunctionNode.getFunctionBody().getStartToken().columnNo+ createFunctionNode.getFunctionBody().getStartToken().getQuoteSymbolLength()-1) 381 +bodyStr; 382 } 383 384 newParser.setFrameStack(getFrameStack()); 385 int iRet = newParser.parse(); 386 TReparseCoordinateShifter.shift(newParser, bodyDeltaLine, 0); 387 if ((iRet == 0)&&(newParser.getSqlstatements().size() >0)){ 388 this.getBodyStatements().add(newParser.getSqlstatements().get(0)); 389 }else { 390 for(int j=0;j<newParser.getErrorCount();j++){ 391 this.parseerrormessagehandle(newParser.getSyntaxErrors().get(j)); 392 } 393 } 394 } 395 396 } 397 398 private TSelectSqlStatement sqlQuery; 399 400 public TSelectSqlStatement getSqlQuery() { 401 return sqlQuery; 402 } 403 404 public int doParseStatement(TCustomSqlStatement psql) { 405 if (rootNode == null) return -1; 406 TCreateFunctionSqlNode createFunctionNode = (TCreateFunctionSqlNode)rootNode; 407 if (dbvendor == EDbVendor.dbvpostgresql){ 408 if (super.doParseStatement(psql) != 0) return -1; 409 }else 410 super.doParseStatement(psql); 411 412 TFrame currentFrame = new TFrame(this.stmtScope); 413 currentFrame.pushMeToStack(getFrameStack()); 414 415 functionName = createFunctionNode.getFunctionName(); 416 417 if (getSqlEnv() != null) { 418 getSqlEnv().addFunction(functionName,true); 419 420 // move to TDatabaseObjectResolver 421 422// if (getSqlEnv().getDefaultCatalogName() != null){ 423// if (functionName.getDatabaseToken() == null){ 424// functionName.setDatabaseToken(new TSourceToken(getSqlEnv().getDefaultCatalogName())); 425// } 426// } 427 } 428 429 // sql server 430 procedureOptions = createFunctionNode.getProcedureOptions(); 431 //end sql server 432 433 if (createFunctionNode.getProcedureLanguage() != null){ 434 // language name is retrieved through parser 435 procedureLanguage = createFunctionNode.getProcedureLanguage(); 436 setRoutineBodyInConstant(procedureLanguage); 437 setRoutineLanguage(procedureLanguage.toString()); 438 }else if (getRoutineLanguage() != null){ 439 // language name is retrieved during TGsqlParser.dopostgresqlgetrawsqlstatements() 440 } 441 442// procedureLanguage = createFunctionNode.getProcedureLanguage(); 443// if (procedureLanguage != null){ 444// setRoutineBodyInConstant(procedureLanguage); 445// setRoutineLanguage(procedureLanguage.toString()); 446// } 447// 448// // postgresql 449// procedureLanguage = createFunctionNode.getProcedureLanguage(); 450// if (getRoutineLanguage() == null){ 451// // not already set during TGsqlParser.dopostgresqlgetrawsqlstatements() 452// // then we set it here 453// if (procedureLanguage != null){ 454// setRoutineLanguage(procedureLanguage.toString()); 455// } 456// } 457 458 //outerLabelName = createFunctionNode.getLabelName(); 459 objfile = createFunctionNode.getObjfile(); 460 linkSymbol = createFunctionNode.getLinkSymbol(); 461 this.className = createFunctionNode.getClassName(); 462 this.resourceType = createFunctionNode.getResourceType(); 463 this.resourceURI = createFunctionNode.getResourceURI(); 464 465 466 if (createFunctionNode.getReturnDataType() != null){ 467 this.returnMode = TBaseType.function_return_datatype; 468 this.returnDataType = createFunctionNode.getReturnDataType(); 469 }else if (createFunctionNode.getReturnTable() != null){ 470 TDummy dmy = createFunctionNode.getReturnTable(); 471 this.returnMode = TBaseType.function_return_table; 472 if (dmy.list1 instanceof TTableElementList){ // hana includes TParameterDeclarationList type which is not this type 473 this.returnTableDefinitions = (TTableElementList)dmy.list1; 474 this.returnTableDefinitions.doParse(this,ESqlClause.unknown); 475 } 476 } 477 // end of postgresql 478 479 this.setParameterDeclarations(createFunctionNode.getParameters()); 480 481 // sql server 482 if (createFunctionNode.getReturnDataType() != null){ 483 this.returnMode = TBaseType.function_return_datatype; 484 this.returnDataType = createFunctionNode.getReturnDataType(); 485 this.returnsType = EFunctionReturnsType.frtScalar; 486 }else if (createFunctionNode.getReturnTable() != null){ 487 TDummy dmy = createFunctionNode.getReturnTable(); 488 if (dmy.node1 != null){ 489 this.returnsType = EFunctionReturnsType.frtMultiStatementTableValue; 490 this.returnMode = TBaseType.function_return_table_variable; 491 this.returnTableVaraible = (TObjectName)dmy.node1; 492 this.returnTableVaraible.setObjectType(TObjectName.ttobjVariable); 493 this.returnTableDefinitions = (TTableElementList)dmy.list1; 494 this.returnTableDefinitions.doParse(this,ESqlClause.unknown); 495 496 if (getSqlEnv() != null) { 497 TSQLTable returnTable = getSqlEnv().addTable(this.returnTableVaraible.toString(),true); 498 //TSQLFunction functionTable = getSqlEnv().searchFunction(functionName.toString()); 499 TSQLFunction functionTable = getSqlEnv().searchFunction(functionName); 500 501 if (functionTable == null){ 502 TBaseType.log(String.format("Table function: <%s> is not found in SQL Evn", functionName.toString()),TLog.WARNING,functionName); 503 //System.out.println("Function not found:"+functionName.toString()); 504 //System.out.println(getSqlEnv().toString()); 505 } 506 507 for(TTableElement column: this.returnTableDefinitions){ 508 if(column.getColumnDefinition()!=null && column.getColumnDefinition().getColumnName()!=null){ 509 if (returnTable != null) { 510 // addTable returns null when enableGetMetadataFromDDL is off 511 returnTable.addColumn(column.getColumnDefinition().getColumnName().toString()); 512 } 513 if (functionTable != null) { 514 functionTable.addReturnColumn(column.getColumnDefinition().getColumnName().toString()); 515 } 516 } 517 } 518 } 519 }else{ 520 this.returnMode = TBaseType.function_return_table; 521 this.returnsType = EFunctionReturnsType.frtInlineTableValue; 522 } 523 } 524 // end sql server 525 526 // push parameterDeclarations into symbolTable 527 if (this.getParameterDeclarations() != null){ 528 for(int i=0;i< this.getParameterDeclarations().size();i++){ 529 this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjParameter,this, this.getParameterDeclarations().getParameterDeclarationItem(i))); 530 TParameterDeclaration parameterDeclaration = this.getParameterDeclarations().getParameterDeclarationItem(i); 531 if (parameterDeclaration.getParameterName() != null){ 532 this.stmtScope.addSymbol(new TVariable(parameterDeclaration.getParameterName(),parameterDeclaration,functionName)); 533 } 534 } 535 } 536 537 538 switch (this.dbvendor){ 539 case dbvsnowflake: 540 if (createFunctionNode.getBlcok() != null){ 541 // $$ body $$ 在这里处理 542 createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown); 543 this.blockBody = createFunctionNode.getBlcok(); 544 }else { 545 // 'body' 在这里处理 546 snowflakeFunctionDefinition(psql,createFunctionNode); 547 } 548 549 break; 550 case dbvpostgresql: 551 case dbvgreenplum: 552 case dbvredshift: 553 if (createFunctionNode.getFunctionBody() != null){ 554 // function body only inside '' will be processed here 555 postgresqlFunctionDefinition(psql,createFunctionNode); 556 }else{ 557 // function body only inside $$ will be processed here 558 559 if (createFunctionNode.getBlcok() != null){ 560 createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown); 561 this.blockBody = createFunctionNode.getBlcok(); 562 }else if (createFunctionNode.getStmt() != null){ 563 createFunctionNode.getStmt().doParse(this, ESqlClause.unknown); 564 this.getBodyStatements().add(createFunctionNode.getStmt().getStmt()); 565 }else { 566 // there is no function body is language is not in sql or plsql, 567 // such as LANGUAGE plpython3u 568 } 569 } 570 break; 571// case dbvgreenplum: 572// postgresqlFunctionDefinition(psql,createFunctionNode); 573// break; 574 case dbvmssql: 575 if (createFunctionNode.getBlcok() != null){ 576 block = new TMssqlBlock(this.dbvendor); 577 block.rootNode = createFunctionNode.getBlcok(); 578 block.doParseStatement(this); 579 this.getBodyStatements().add(block); 580 } 581 582 if (createFunctionNode.getReturnSqlNode() != null){ 583 returnStmt = new TMssqlReturn(this.dbvendor); 584 returnStmt.rootNode = createFunctionNode.getReturnSqlNode(); 585 returnStmt.doParseStatement(this); 586 this.getBodyStatements().add(returnStmt); 587 } 588 589 break; 590 case dbvmysql: 591 if (createFunctionNode.getStmt() != null){ 592 createFunctionNode.getStmt().doParse(this,ESqlClause.unknown); 593 this.getBodyStatements().add(createFunctionNode.getStmt().getStmt()); 594 } 595 else if (createFunctionNode.getBlcok() != null){ 596 createFunctionNode.getBlcok().getStmts().doParse(this,ESqlClause.unknown); 597 598 for(int i=0;i<createFunctionNode.getBlcok().getStmts().size();i++){ 599 this.getBodyStatements().add(createFunctionNode.getBlcok().getStmts().getStatementSqlNode(i).getStmt()); 600 } 601 } 602 break; 603 case dbvbigquery: 604 if (createFunctionNode.getSqlQuery() != null){ 605 sqlQuery = new TSelectSqlStatement(this.dbvendor); 606 sqlQuery.rootNode = createFunctionNode.getSqlQuery(); 607 sqlQuery.doParseStatement(this); 608 this.returnMode = TBaseType.function_return_datatype; 609 this.returnDataType = createFunctionNode.getReturnDataType(); 610 this.returnsType = EFunctionReturnsType.frtInlineTableValue; 611 this.getBodyStatements().add(sqlQuery); 612 } 613 break; 614 case dbvdb2: 615 TCompoundSqlNode compoundSqlNode = createFunctionNode.getCompoundSql(); 616 // TReturnSqlNode returnSqlNode = createFunctionNode.getReturnSqlNode(); 617 618 if (compoundSqlNode != null){ 619 if (compoundSqlNode.getDeclareStmts() != null){ 620 compoundSqlNode.getDeclareStmts().doParse(this,ESqlClause.unknown); 621 622 // push variable declare into symbolTable, and add to declareStatements 623 for(int i=0;i<compoundSqlNode.getDeclareStmts().size();i++){ 624 this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjVariable,this,compoundSqlNode.getDeclareStmts().getStatementSqlNode(i).getStmt() )); 625 this.getDeclareStatements().add(compoundSqlNode.getDeclareStmts().getStatementSqlNode(i).getStmt()); 626 } 627 } 628 629 if (compoundSqlNode.getStmts() != null){ 630 compoundSqlNode.getStmts().doParse(this,ESqlClause.unknown); 631 632 for(int i= 0; i<compoundSqlNode.getStmts().size();i++){ 633 this.getBodyStatements().add(compoundSqlNode.getStmts().getStatementSqlNode(i).getStmt()); 634 } 635 } 636 637 if (compoundSqlNode.getDeclareStmts() != null){ 638 // pop variable declare from symbolTable 639 for(int i=0;i<compoundSqlNode.getDeclareStmts().size();i++){ 640 this.getTopStatement().getSymbolTable().pop(); 641 } 642 } 643 }else if (createFunctionNode.getReturnSqlNode() != null){ 644 returnStmt = new TMssqlReturn(this.dbvendor); 645 returnStmt.rootNode = createFunctionNode.getReturnSqlNode(); 646 returnStmt.doParseStatement(this); 647 this.getBodyStatements().add(returnStmt); 648 } 649 650 break; 651 default: 652 if (createFunctionNode.getStmt() != null){ 653 createFunctionNode.getStmt().doParse(this, ESqlClause.unknown); 654 this.getBodyStatements().add(createFunctionNode.getStmt().getStmt()); 655// TStatementListSqlNode lcStmts = new TStatementListSqlNode(); 656// lcStmts.addStatementSqlNode(createFunctionNode.getStmt()); 657// this.blockBody = new TBlockSqlNode(); 658// this.blockBody.init(lcStmts); 659 } 660 else if (createFunctionNode.getBlcok() != null){ 661 createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown); 662 //createFunctionNode.getBlcok().getStmts().doParse(this,ESqlClause.unknown); 663// 664// for(int i=0;i<createFunctionNode.getBlcok().getStmts().size();i++){ 665// this.getBodyStatements().add(createFunctionNode.getBlcok().getStmts().getStatementSqlNode(i).getStmt()); 666// } 667 this.blockBody = createFunctionNode.getBlcok(); 668 } 669 break; 670 } 671 672 673 674 675 // pop parameterDeclarations from symbolTable 676 if (this.getParameterDeclarations() != null){ 677 for(int i=0;i< this.getParameterDeclarations().size();i++){ 678 this.getTopStatement().getSymbolTable().pop(); 679 } 680 } 681 682 if (createFunctionNode.getSharedLibraryName() != null){ 683 sharedLibraryName = createFunctionNode.getSharedLibraryName().toString(); 684 } 685 686 functionDefinition = createFunctionNode.getFunctionDefinition(); 687 if (functionDefinition != null){ 688 setRoutineBodyInConstant(functionDefinition); 689 setRoutineBody(functionDefinition.toString()); 690 } 691 692 this.sqlExpression = createFunctionNode.getSqlExpression(); 693 if (this.sqlExpression != null){ 694 this.sqlExpression.doParse(this,ESqlClause.unknown); 695 } 696 697 // StarRocks-specific fields 698 this.starrocksGlobal = createFunctionNode.isStarrocksGlobal(); 699 this.starrocksAggregate = createFunctionNode.isStarrocksAggregate(); 700 this.starrocksTableFunction = createFunctionNode.isStarrocksTableFunction(); 701 this.starrocksOrReplace = createFunctionNode.isStarrocksOrReplace(); 702 this.starrocksIntermediateType = createFunctionNode.getStarrocksIntermediateType(); 703 this.starrocksProperties = createFunctionNode.getStarrocksProperties(); 704 705 //endlabelName = createFunctionNode.getEndlabelName(); 706 currentFrame.popMeFromStack(getFrameStack()); 707 708 return 0; 709 } 710 711 public void accept(TParseTreeVisitor v){ 712 v.preVisit(this); 713 v.postVisit(this); 714 } 715 716 public void acceptChildren(TParseTreeVisitor v){ 717 v.preVisit(this); 718 this.getFunctionName().acceptChildren(v); 719 if (getParameterDeclarations() != null) getParameterDeclarations().acceptChildren(v); 720 if (blockBody != null){ 721 blockBody.acceptChildren(v); 722 }else if (getBodyStatements().size() > 0){ 723 getBodyStatements().acceptChildren(v); 724 } 725 // Visit sqlExpression for BigQuery functions where body is an expression (e.g., AS ((SELECT ...))) 726 // This ensures UNNEST tables and column references inside the expression are collected 727 if (sqlExpression != null) { 728 sqlExpression.acceptChildren(v); 729 } 730 if (returnStmt != null) returnStmt.acceptChildren(v); 731 v.postVisit(this); 732 } 733 734 735 public void setFunctionName(TObjectName functionName) { 736 this.functionName = functionName; 737 } 738 739 public void setBlock(TMssqlBlock block) { 740 this.block = block; 741 } 742 public void setReturnStmt(TMssqlReturn returnStmt) { 743 this.returnStmt = returnStmt; 744 } 745 public void setReturnMode(int returnMode) { 746 this.returnMode = returnMode; 747 } 748 public void setReturnTableVaraible(TObjectName returnTableVaraible) { 749 this.returnTableVaraible = returnTableVaraible; 750 } 751 public void setReturnTableDefinitions(TTableElementList returnTableDefinitions) { 752 this.returnTableDefinitions = returnTableDefinitions; 753 } 754 public void setReturnDataType(TTypeName returnDataType) { 755 this.returnDataType = returnDataType; 756 } 757 public void setFunctionType(int functionType) { 758 this.functionType = functionType; 759 } 760 761 // StarRocks-specific fields 762 private boolean starrocksGlobal = false; 763 private boolean starrocksAggregate = false; 764 private boolean starrocksTableFunction = false; 765 private boolean starrocksOrReplace = false; 766 private TTypeName starrocksIntermediateType = null; 767 private TPTNodeList starrocksProperties = null; 768 769 public boolean isStarrocksGlobal() { return starrocksGlobal; } 770 public boolean isStarrocksAggregate() { return starrocksAggregate; } 771 public boolean isStarrocksTableFunction() { return starrocksTableFunction; } 772 public boolean isStarrocksOrReplace() { return starrocksOrReplace; } 773 public TTypeName getStarrocksIntermediateType() { return starrocksIntermediateType; } 774 public TPTNodeList getStarrocksProperties() { return starrocksProperties; } 775 776}