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 returnTable.addColumn(column.getColumnDefinition().getColumnName().toString()); 510 if (functionTable != null) { 511 functionTable.addReturnColumn(column.getColumnDefinition().getColumnName().toString()); 512 } 513 } 514 } 515 } 516 }else{ 517 this.returnMode = TBaseType.function_return_table; 518 this.returnsType = EFunctionReturnsType.frtInlineTableValue; 519 } 520 } 521 // end sql server 522 523 // push parameterDeclarations into symbolTable 524 if (this.getParameterDeclarations() != null){ 525 for(int i=0;i< this.getParameterDeclarations().size();i++){ 526 this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjParameter,this, this.getParameterDeclarations().getParameterDeclarationItem(i))); 527 TParameterDeclaration parameterDeclaration = this.getParameterDeclarations().getParameterDeclarationItem(i); 528 if (parameterDeclaration.getParameterName() != null){ 529 this.stmtScope.addSymbol(new TVariable(parameterDeclaration.getParameterName(),parameterDeclaration,functionName)); 530 } 531 } 532 } 533 534 535 switch (this.dbvendor){ 536 case dbvsnowflake: 537 if (createFunctionNode.getBlcok() != null){ 538 // $$ body $$ 在这里处理 539 createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown); 540 this.blockBody = createFunctionNode.getBlcok(); 541 }else { 542 // 'body' 在这里处理 543 snowflakeFunctionDefinition(psql,createFunctionNode); 544 } 545 546 break; 547 case dbvpostgresql: 548 case dbvgreenplum: 549 case dbvredshift: 550 if (createFunctionNode.getFunctionBody() != null){ 551 // function body only inside '' will be processed here 552 postgresqlFunctionDefinition(psql,createFunctionNode); 553 }else{ 554 // function body only inside $$ will be processed here 555 556 if (createFunctionNode.getBlcok() != null){ 557 createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown); 558 this.blockBody = createFunctionNode.getBlcok(); 559 }else if (createFunctionNode.getStmt() != null){ 560 createFunctionNode.getStmt().doParse(this, ESqlClause.unknown); 561 this.getBodyStatements().add(createFunctionNode.getStmt().getStmt()); 562 }else { 563 // there is no function body is language is not in sql or plsql, 564 // such as LANGUAGE plpython3u 565 } 566 } 567 break; 568// case dbvgreenplum: 569// postgresqlFunctionDefinition(psql,createFunctionNode); 570// break; 571 case dbvmssql: 572 if (createFunctionNode.getBlcok() != null){ 573 block = new TMssqlBlock(this.dbvendor); 574 block.rootNode = createFunctionNode.getBlcok(); 575 block.doParseStatement(this); 576 this.getBodyStatements().add(block); 577 } 578 579 if (createFunctionNode.getReturnSqlNode() != null){ 580 returnStmt = new TMssqlReturn(this.dbvendor); 581 returnStmt.rootNode = createFunctionNode.getReturnSqlNode(); 582 returnStmt.doParseStatement(this); 583 this.getBodyStatements().add(returnStmt); 584 } 585 586 break; 587 case dbvmysql: 588 if (createFunctionNode.getStmt() != null){ 589 createFunctionNode.getStmt().doParse(this,ESqlClause.unknown); 590 this.getBodyStatements().add(createFunctionNode.getStmt().getStmt()); 591 } 592 else if (createFunctionNode.getBlcok() != null){ 593 createFunctionNode.getBlcok().getStmts().doParse(this,ESqlClause.unknown); 594 595 for(int i=0;i<createFunctionNode.getBlcok().getStmts().size();i++){ 596 this.getBodyStatements().add(createFunctionNode.getBlcok().getStmts().getStatementSqlNode(i).getStmt()); 597 } 598 } 599 break; 600 case dbvbigquery: 601 if (createFunctionNode.getSqlQuery() != null){ 602 sqlQuery = new TSelectSqlStatement(this.dbvendor); 603 sqlQuery.rootNode = createFunctionNode.getSqlQuery(); 604 sqlQuery.doParseStatement(this); 605 this.returnMode = TBaseType.function_return_datatype; 606 this.returnDataType = createFunctionNode.getReturnDataType(); 607 this.returnsType = EFunctionReturnsType.frtInlineTableValue; 608 this.getBodyStatements().add(sqlQuery); 609 } 610 break; 611 case dbvdb2: 612 TCompoundSqlNode compoundSqlNode = createFunctionNode.getCompoundSql(); 613 // TReturnSqlNode returnSqlNode = createFunctionNode.getReturnSqlNode(); 614 615 if (compoundSqlNode != null){ 616 if (compoundSqlNode.getDeclareStmts() != null){ 617 compoundSqlNode.getDeclareStmts().doParse(this,ESqlClause.unknown); 618 619 // push variable declare into symbolTable, and add to declareStatements 620 for(int i=0;i<compoundSqlNode.getDeclareStmts().size();i++){ 621 this.getTopStatement().getSymbolTable().push( new TSymbolTableItem(TObjectName.ttobjVariable,this,compoundSqlNode.getDeclareStmts().getStatementSqlNode(i).getStmt() )); 622 this.getDeclareStatements().add(compoundSqlNode.getDeclareStmts().getStatementSqlNode(i).getStmt()); 623 } 624 } 625 626 if (compoundSqlNode.getStmts() != null){ 627 compoundSqlNode.getStmts().doParse(this,ESqlClause.unknown); 628 629 for(int i= 0; i<compoundSqlNode.getStmts().size();i++){ 630 this.getBodyStatements().add(compoundSqlNode.getStmts().getStatementSqlNode(i).getStmt()); 631 } 632 } 633 634 if (compoundSqlNode.getDeclareStmts() != null){ 635 // pop variable declare from symbolTable 636 for(int i=0;i<compoundSqlNode.getDeclareStmts().size();i++){ 637 this.getTopStatement().getSymbolTable().pop(); 638 } 639 } 640 }else if (createFunctionNode.getReturnSqlNode() != null){ 641 returnStmt = new TMssqlReturn(this.dbvendor); 642 returnStmt.rootNode = createFunctionNode.getReturnSqlNode(); 643 returnStmt.doParseStatement(this); 644 this.getBodyStatements().add(returnStmt); 645 } 646 647 break; 648 default: 649 if (createFunctionNode.getStmt() != null){ 650 createFunctionNode.getStmt().doParse(this, ESqlClause.unknown); 651 this.getBodyStatements().add(createFunctionNode.getStmt().getStmt()); 652// TStatementListSqlNode lcStmts = new TStatementListSqlNode(); 653// lcStmts.addStatementSqlNode(createFunctionNode.getStmt()); 654// this.blockBody = new TBlockSqlNode(); 655// this.blockBody.init(lcStmts); 656 } 657 else if (createFunctionNode.getBlcok() != null){ 658 createFunctionNode.getBlcok().doParse(this,ESqlClause.unknown); 659 //createFunctionNode.getBlcok().getStmts().doParse(this,ESqlClause.unknown); 660// 661// for(int i=0;i<createFunctionNode.getBlcok().getStmts().size();i++){ 662// this.getBodyStatements().add(createFunctionNode.getBlcok().getStmts().getStatementSqlNode(i).getStmt()); 663// } 664 this.blockBody = createFunctionNode.getBlcok(); 665 } 666 break; 667 } 668 669 670 671 672 // pop parameterDeclarations from symbolTable 673 if (this.getParameterDeclarations() != null){ 674 for(int i=0;i< this.getParameterDeclarations().size();i++){ 675 this.getTopStatement().getSymbolTable().pop(); 676 } 677 } 678 679 if (createFunctionNode.getSharedLibraryName() != null){ 680 sharedLibraryName = createFunctionNode.getSharedLibraryName().toString(); 681 } 682 683 functionDefinition = createFunctionNode.getFunctionDefinition(); 684 if (functionDefinition != null){ 685 setRoutineBodyInConstant(functionDefinition); 686 setRoutineBody(functionDefinition.toString()); 687 } 688 689 this.sqlExpression = createFunctionNode.getSqlExpression(); 690 if (this.sqlExpression != null){ 691 this.sqlExpression.doParse(this,ESqlClause.unknown); 692 } 693 694 // StarRocks-specific fields 695 this.starrocksGlobal = createFunctionNode.isStarrocksGlobal(); 696 this.starrocksAggregate = createFunctionNode.isStarrocksAggregate(); 697 this.starrocksTableFunction = createFunctionNode.isStarrocksTableFunction(); 698 this.starrocksOrReplace = createFunctionNode.isStarrocksOrReplace(); 699 this.starrocksIntermediateType = createFunctionNode.getStarrocksIntermediateType(); 700 this.starrocksProperties = createFunctionNode.getStarrocksProperties(); 701 702 //endlabelName = createFunctionNode.getEndlabelName(); 703 currentFrame.popMeFromStack(getFrameStack()); 704 705 return 0; 706 } 707 708 public void accept(TParseTreeVisitor v){ 709 v.preVisit(this); 710 v.postVisit(this); 711 } 712 713 public void acceptChildren(TParseTreeVisitor v){ 714 v.preVisit(this); 715 this.getFunctionName().acceptChildren(v); 716 if (getParameterDeclarations() != null) getParameterDeclarations().acceptChildren(v); 717 if (blockBody != null){ 718 blockBody.acceptChildren(v); 719 }else if (getBodyStatements().size() > 0){ 720 getBodyStatements().acceptChildren(v); 721 } 722 // Visit sqlExpression for BigQuery functions where body is an expression (e.g., AS ((SELECT ...))) 723 // This ensures UNNEST tables and column references inside the expression are collected 724 if (sqlExpression != null) { 725 sqlExpression.acceptChildren(v); 726 } 727 if (returnStmt != null) returnStmt.acceptChildren(v); 728 v.postVisit(this); 729 } 730 731 732 public void setFunctionName(TObjectName functionName) { 733 this.functionName = functionName; 734 } 735 736 public void setBlock(TMssqlBlock block) { 737 this.block = block; 738 } 739 public void setReturnStmt(TMssqlReturn returnStmt) { 740 this.returnStmt = returnStmt; 741 } 742 public void setReturnMode(int returnMode) { 743 this.returnMode = returnMode; 744 } 745 public void setReturnTableVaraible(TObjectName returnTableVaraible) { 746 this.returnTableVaraible = returnTableVaraible; 747 } 748 public void setReturnTableDefinitions(TTableElementList returnTableDefinitions) { 749 this.returnTableDefinitions = returnTableDefinitions; 750 } 751 public void setReturnDataType(TTypeName returnDataType) { 752 this.returnDataType = returnDataType; 753 } 754 public void setFunctionType(int functionType) { 755 this.functionType = functionType; 756 } 757 758 // StarRocks-specific fields 759 private boolean starrocksGlobal = false; 760 private boolean starrocksAggregate = false; 761 private boolean starrocksTableFunction = false; 762 private boolean starrocksOrReplace = false; 763 private TTypeName starrocksIntermediateType = null; 764 private TPTNodeList starrocksProperties = null; 765 766 public boolean isStarrocksGlobal() { return starrocksGlobal; } 767 public boolean isStarrocksAggregate() { return starrocksAggregate; } 768 public boolean isStarrocksTableFunction() { return starrocksTableFunction; } 769 public boolean isStarrocksOrReplace() { return starrocksOrReplace; } 770 public TTypeName getStarrocksIntermediateType() { return starrocksIntermediateType; } 771 public TPTNodeList getStarrocksProperties() { return starrocksProperties; } 772 773}