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