001package gudusoft.gsqlparser.stmt; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.nodes.*; 005 006import java.util.ArrayList; 007import java.util.HashMap; 008 009/** 010 * The EXECUTE IMMEDIATE statement builds and executes a dynamic SQL statement in 011 * a single operation. 012 */ 013public class TExecImmeStmt extends TBlockSqlStatement { 014 015 private TExpression dynamicStringExpr = null; 016 private TBindArgumentList bindArguments = null; 017 private TExpressionList intoVariables = null; 018 private TObjectNameList returnNames = null; 019 private String dynamicSQL = null; 020 private TStatementList dynamicStatements = null; 021 022 public ArrayList<String> getEvaluatedDynamicSQLs() { 023 return evaluatedDynamicSQLs; 024 } 025 026 private ArrayList <String> evaluatedDynamicSQLs = new ArrayList<String>(); 027 028 // Static parser instance for performance - reused across all dynamic SQL parsing 029 private static TGSqlParser sqlparser = null; 030 static { 031 sqlparser = new TGSqlParser(EDbVendor.dbvoracle); 032 } 033 034 /** 035 * 036 * @return sql statement instance that generated dynamically based on {@link #dynamicSQL} 037 */ 038 public synchronized TStatementList getDynamicStatements() { 039 if (this.dynamicStatements != null) return this.dynamicStatements; 040 if (this.getDynamicSQL() == null) return null; 041 042 String query = this.getDynamicSQL(); 043 044 if(this.getDynamicStringExpr().getPlainTextLineNo() != -1){ 045 long lineNo = this.getDynamicStringExpr().getPlainTextLineNo(); 046 long columnNo = this.getDynamicStringExpr().getPlainTextColumnNo(); 047 query = TBaseType.stringBlock((int)lineNo - 1,(int)columnNo)+ this.getDynamicSQL(); 048 } 049 050 // Prepare parser for reuse by clearing cached state 051 // This resets vendorParser, sqlEnv, sqlfilename, and parsing options 052 sqlparser.prepareForReuse(); 053 sqlparser.sqltext = query; 054 int ret = sqlparser.parse(); 055 056 if ( ret != 0){ 057 for(int j=0;j<sqlparser.getErrorCount();j++){ 058 this.parseerrormessagehandle(sqlparser.getSyntaxErrors().get(j)); 059 } 060 061 return null; 062 } 063 064 this.dynamicStatements = new TStatementList(); 065 for(int i=0;i<sqlparser.sqlstatements.size();i++){ 066 if (this.getParentStmt() == null){ 067 sqlparser.sqlstatements.get(i).setParentStmt(this); 068 }else{ 069 sqlparser.sqlstatements.get(i).setParentStmt(this.getParentStmt()); 070 } 071 072 this.dynamicStatements.add(sqlparser.sqlstatements.get(i)); 073 } 074 return dynamicStatements; 075 } 076 077 /** 078 * 079 * @return String representation of dynamic sql statement. if there is a variable in 080 * {@link #dynamicStringExpr}, value of this variable will be returned. 081 */ 082 083 public String getDynamicSQL() { 084 if (!this.getEvaluatedDynamicSQLs().isEmpty()){ 085 // 使用 TASTEvaluator 计算动态 SQL 后,将结果保存在 evaluatedDynamicSQLs 中,如果有值,采用这个更精确的 SQL 值 086 StringBuilder concatenatedSQL = new StringBuilder(); 087 088 for (int i = 0; i < this.getEvaluatedDynamicSQLs().size(); i++) { 089 String sql = this.getEvaluatedDynamicSQLs().get(i); 090 concatenatedSQL.append(sql); 091 if (i < this.getEvaluatedDynamicSQLs().size() - 1) { 092 concatenatedSQL.append(";"); 093 concatenatedSQL.append(TBaseType.newline); 094 } 095 } 096 097 this.dynamicSQL = concatenatedSQL.toString(); 098 } 099 return this.dynamicSQL; 100 101// if (this.dynamicSQL != null) return this.dynamicSQL; 102// 103// if (dynamicStringExpr.getExpressionType() == EExpressionType.simple_constant_t) 104// { 105// this.dynamicSQL = TBaseType.getStringInsideLiteral(this.dynamicStringExpr.toString()); 106// }else if (dynamicStringExpr.getExpressionType() == EExpressionType.simple_object_name_t){ 107// // this is a variable, we have to search 108// String lcvar = this.getDynamicStringExpr().toString(); 109// TCustomSqlStatement topsql = this.getTopStatement(); 110// if (topsql instanceof TBlockSqlStatement){ 111// TCustomSqlStatement stmt = null; 112// for(int i=0;i< ((TBlockSqlStatement)topsql).getBodyStatements().size();i++){ 113// stmt = ((TBlockSqlStatement)topsql).getBodyStatements().get(i); 114// if (stmt instanceof TAssignStmt){ 115// if ( ((TAssignStmt)stmt).getLeft().toString().compareToIgnoreCase(lcvar) == 0 ) 116// { 117// if (((TAssignStmt)stmt).getExpression().getExpressionType() == EExpressionType.simple_constant_t){ 118// this.dynamicSQL = ((TAssignStmt)stmt).getExpression().toString().substring(1,((TAssignStmt)stmt).getExpression().toString().length() - 1); 119// }else{ 120// this.dynamicSQL = null; 121// } 122// break; 123// } 124// } 125// } 126// } 127// if ((this.getParentStmt() instanceof TBlockSqlStatement)&&(this.dynamicSQL == null)){ 128// TBlockSqlStatement blockSqlStatement = (TBlockSqlStatement)this.getParentStmt(); 129// for(int i=0;i< blockSqlStatement.getBodyStatements().size();i++){ 130// TCustomSqlStatement stmt = blockSqlStatement.getBodyStatements().get(i); 131// if (stmt instanceof TAssignStmt){ 132// if ( ((TAssignStmt)stmt).getLeft().toString().compareToIgnoreCase(lcvar) == 0 ) 133// { 134// if (((TAssignStmt)stmt).getExpression().getExpressionType() == EExpressionType.simple_constant_t){ 135// this.dynamicSQL = ((TAssignStmt)stmt).getExpression().toString().substring(1,((TAssignStmt)stmt).getExpression().toString().length() - 1); 136// }else{ 137// this.dynamicSQL = null; 138// } 139// break; 140// } 141// } 142// } 143// } 144// 145// }else{ 146// calculateExprVisitor cv = new calculateExprVisitor(); 147// this.dynamicStringExpr.postOrderTraverse(cv); 148// //this.dynamicStringExpr.evaluate(); 149// 150// this.dynamicSQL = this.dynamicStringExpr.getPlainText(); 151//// if (this.dynamicSQL.charAt(0) == '\''){ 152//// this.dynamicSQL = this.dynamicSQL.substring(1,this.dynamicSQL.toString().length() - 2); 153//// } 154// } 155// return this.dynamicSQL ; 156 } 157 158 /** 159 * bind arguments 160 * @return bind arguments in using clause. 161 */ 162 public TBindArgumentList getBindArguments() { 163 return bindArguments; 164 } 165 166 /** 167 * String expr 168 * 169 * @return A string literal, string variable, or string expression that represents any SQL statement. 170 * this is the original string of dynamic sql statement. 171 */ 172 173 public TExpression getDynamicStringExpr() { 174 return dynamicStringExpr; 175 } 176 177 /** 178 * Into variable 179 * 180 * @return variable names in the into clause. 181 */ 182 public TExpressionList getIntoVariables() { 183 return intoVariables; 184 } 185 186 /** 187 * 188 * Used if and only if dynamic_sql_stmt has a RETURNING INTO clause, this clause 189 * returns the column values of the rows affected by dynamic_sql_stmt, in either 190 * individual variables or records 191 * 192 * @return 193 */ 194 195 public TObjectNameList getReturnNames() { 196 return returnNames; 197 } 198 199 public TExecImmeStmt(EDbVendor dbvendor){ 200 super(dbvendor); 201 sqlstatementtype = ESqlStatementType.sstplsql_execimmestmt ; 202 } 203 204 void buildsql() { 205 } 206 207 void clear() { 208 } 209 210 String getasprettytext() { 211 return ""; 212 } 213 214 void iterate(TVisitorAbs pvisitor) { 215 } 216 217 public int doParseStatement(TCustomSqlStatement psql) { 218 if (rootNode == null) return -1; 219 super.doParseStatement(psql); 220 221 TExecImmeNode execImmeNode = (TExecImmeNode)rootNode; 222 this.bindArguments = execImmeNode.getBindArguments(); 223 this.intoVariables = execImmeNode.getIntoVariables(); 224 this.dynamicStringExpr = execImmeNode.getDynamicStringExpr(); 225 this.returnNames = execImmeNode.getReturnNames(); 226 227 this.dynamicStringExpr.evaluate(this.getFrameStack(),this); 228 this.dynamicSQL = this.dynamicStringExpr.getPlainText(); 229 230 //TODO parse the dynamicSQL, 先不在这里解析动态 SQL, 考虑和 TASTEvaluator 结合 231 // getDynamicStatements(); 232 233 return 0; 234 } 235 236 public void accept(TParseTreeVisitor v){ 237 v.preVisit(this); 238 v.postVisit(this); 239 } 240 241 public void acceptChildren(TParseTreeVisitor v){ 242 v.preVisit(this); 243 this.dynamicStringExpr.acceptChildren(v); 244 v.postVisit(this); 245 } 246 247 public void setDynamicStringExpr(TExpression dynamicStringExpr) { 248 this.dynamicStringExpr = dynamicStringExpr; 249 } 250 251 public void setBindArguments(TBindArgumentList bindArguments) { 252 this.bindArguments = bindArguments; 253 } 254 255 public void setIntoVariables(TExpressionList intoVariables) { 256 this.intoVariables = intoVariables; 257 } 258 259 public void setReturnNames(TObjectNameList returnNames) { 260 this.returnNames = returnNames; 261 } 262 263 public void setDynamicSQL(String dynamicSQL) { 264 this.dynamicSQL = dynamicSQL; 265 } 266 267 public void setDynamicStatements(TStatementList dynamicStatements) { 268 this.dynamicStatements = dynamicStatements; 269 } 270 271// private String EvaluateExpr(){ 272// if (this.dynamicStringExpr == null) return ""; 273// return this.dynamicStringExpr.getPlainText(); 274// } 275} 276 277//class calculateExprVisitor implements IExpressionVisitor { 278// Stack<TExpression> expressionStack = new Stack<>(); 279// 280// public boolean exprVisit(TParseTreeNode pNode,boolean isLeafNode){ 281// if (isLeafNode){ 282// expressionStack.push((TExpression)pNode); 283// } 284// 285// TExpression expr = (TExpression)pNode; 286// switch (expr.getExpressionType()){ 287// case concatenate_t: 288// TExpression expr1 = expressionStack.pop(); 289// TExpression expr2 = expressionStack.pop(); 290// 291// String expr1Str = expr1.getPlainText(); 292// String expr2Str = expr2.getPlainText(); 293// switch (expr1.getExpressionType()){ 294// case simple_constant_t: 295// expr1Str = TBaseType.getStringInsideLiteral(expr1Str); 296// break; 297// case function_t: 298// expr1Str = expr1.getFunctionCall().getFunctionName().toString(); 299// break; 300// case simple_object_name_t: 301// expr1Str = expr1Str.replace(".","_"); 302// break; 303// default: 304// break; 305// } 306// 307// switch (expr2.getExpressionType()){ 308// case simple_constant_t: 309// expr2Str = TBaseType.getStringInsideLiteral(expr2Str); 310// break; 311// case function_t: 312// expr2Str = expr2.getFunctionCall().getFunctionName().toString(); 313// break; 314// case simple_object_name_t: 315// expr2Str = expr2Str.replace(".","_"); 316// break; 317// default: 318// break; 319// } 320// 321// 322// //TExpression expr3 = expressionStack.peek(); 323// ((TExpression)pNode).setPlainText(expr2Str+expr1Str); 324// 325// expressionStack.push((TExpression)pNode); 326// 327// break; 328// } 329// return true; 330// }; 331// 332//} 333