001package gudusoft.gsqlparser.stmt.mssql;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.compiler.TSymbolTableManager;
005import gudusoft.gsqlparser.compiler.TVariable;
006import gudusoft.gsqlparser.nodes.*;
007import gudusoft.gsqlparser.nodes.mssql.TExecuteOption;
008import gudusoft.gsqlparser.stmt.TCreateFunctionStmt;
009import gudusoft.gsqlparser.stmt.TCreateProcedureStmt;
010import gudusoft.gsqlparser.stmt.TRoutine;
011import gudusoft.gsqlparser.stmt.TStoredProcedureSqlStatement;
012
013/**
014 * Execute a stored procedure or function,
015 * or Execute a character string
016 */
017public class TMssqlExecute extends TCustomSqlStatement {
018    public TMssqlExecute (EDbVendor dbvendor){
019        super(dbvendor);
020        sqlstatementtype = ESqlStatementType.sstmssqlexec ;
021        }
022
023    void buildsql() {
024    }
025
026    void clear() {
027    }
028
029    String getasprettytext() {
030        return "";
031    }
032
033    void iterate(TVisitorAbs pvisitor) {
034    }
035
036
037    private String sqlText = null;
038
039    private TObjectName moduleName = null;
040    private TObjectName returnStatus = null;
041    private TExecParameterList parameters = null;
042
043    public String getSqlText() {
044        return sqlText;
045    }
046
047    public TObjectName getModuleName() {
048        return moduleName;
049    }
050
051    public TExecParameterList getParameters() {
052        return parameters;
053    }
054
055    public TObjectName getReturnStatus() {
056        return returnStatus;
057    }
058
059    public TExpressionList getStringValues() {
060        return stringValues;
061    }
062
063    public int getExecType() {
064        return execType;
065    }
066
067    private TExpressionList stringValues = null;
068    private int execType = TBaseType.metExecSp;
069
070    public TExpression getPreparedValue() {
071        return preparedValue;
072    }
073
074    private TExpression preparedValue;//couchbase
075
076    private boolean isValidProcedureCall(TSourceTokenList stList,TSyntaxError err){
077        boolean ret = false;
078
079        if (stList.size() <= 1) return false;
080        TSourceToken st = stList.get(0);
081        if (st.tokencode == TBaseType.rrw_drop){
082            TSourceToken nextst = stList.nextsolidtoken(st,1,false);
083            err.hint = "Unknown object type in drop statement";
084            if (nextst != null){
085                err.tokentext = nextst.toString();
086                err.lineNo = nextst.lineNo;
087                err.columnNo = nextst.columnNo;
088            }
089
090            return false;
091        }
092        if (stList.get(1).tokentype ==  ETokenType.ttperiod) return true;
093        if (st.toString().toLowerCase().startsWith("sp")) return true;
094        if (st.toString().toLowerCase().startsWith("select")) return false;
095        if (st.toString().toLowerCase().startsWith("del")) return false;
096        if (st.toString().toLowerCase().startsWith("update")) return false;
097        if (st.toString().toLowerCase().startsWith("insert")) return false;
098        if (st.toString().toLowerCase().startsWith("create")) return false;
099
100        return ret;
101    }
102    private TExecuteOption executeOption;
103
104    public TExecuteOption getExecuteOption() {
105        return executeOption;
106    }
107
108    public EExecType getExecuteType() {
109        return executeType;
110    }
111
112    private EExecType executeType = EExecType.unknown;
113
114    private TObjectName intoVariable;
115    private TExpressionList usingVariables;
116
117    public TObjectName getIntoVariable() {
118        return intoVariable;
119    }
120
121    public TExpressionList getUsingVariables() {
122        return usingVariables;
123    }
124
125    public int doParseStatement(TCustomSqlStatement psql) {
126       if (rootNode == null) return -1;
127        if (!(rootNode instanceof TExecuteSqlNode)){
128            if (this.sourcetokenlist.size() > 0){
129                TSourceToken st1 = this.sourcetokenlist.get(0);
130                TSyntaxError err = new TSyntaxError(st1.toString(),st1.lineNo,st1.columnNo,"syntax error",EErrorType.sperror
131                        ,TBaseType.MSG_ERROR_SYNTAX_ERROR
132                        ,this,st1.posinlist);
133                if (!isValidProcedureCall(this.sourcetokenlist,err))
134                    this.parseerrormessagehandle(err);
135            }
136            return -1;
137        }
138       TExecuteSqlNode node = (TExecuteSqlNode)rootNode;
139        this.execType = node.getExecType();
140        this.executeType = node.getExecuteType();
141        this.preparedValue = node.getPreparedValue();
142        this.intoVariable = node.getIntoVariable();
143        this.usingVariables = node.getUsingVariables();
144
145        this.executeOption = node.getExecuteOption();
146        super.doParseStatement(psql);
147
148
149        if ((node.getExecType() == TBaseType.metExecSp)){
150            this.moduleName = node.getModuleName();
151            this.parameters = node.getParameters();
152            this.returnStatus = node.getReturnStatus();
153            this.linkServerName = node.getLinkServerName();
154            if ((this.moduleName != null)&&(this.moduleName.toString().equalsIgnoreCase("sp_executesql"))
155                    && (this.parameters != null) && (this.parameters.size() > 0)){
156                TExecParameter parameter = this.parameters.getExecParameter(0);
157                if (parameter.getParameterValue().getExpressionType() == EExpressionType.simple_object_name_t){
158                    TObjectName var = parameter.getParameterValue().getObjectOperand();
159                    if (var.getDbObjectType() == EDbObjectType.variable){
160                        TVariable symbolVariable =  TSymbolTableManager.searchSymbolVariable(this.getFrameStack(),var.toString());
161                        if (symbolVariable != null){
162                            this.sqlText = symbolVariable.getVariableStr();
163                            //System.out.println(this.sqlText);
164                        }
165                    }
166                }else{
167                    parameter.getParameterValue().evaluate(this.getFrameStack(),this);
168                    this.sqlText = parameter.getParameterValue().getPlainText();
169                }
170            }else {
171                // exec a procedure with parameter, put the parameter as a variable into scope
172                TVariable variable = null;
173                int i=0;
174
175                //System.out.println(this.moduleName.toString());
176                if (this.parameters != null){
177                    if (this.parameters.size() > 0){
178                        for(TExecParameter p:this.parameters){
179                            TObjectName variableName =  TObjectName.createObjectName (this.dbvendor,  EDbObjectType.variable, new TSourceToken("$"+i));
180                            variable = new TVariable(variableName,p,this.moduleName);
181                            variable.setVariableStr(TBaseType.getStringInsideLiteral(p.getParameterValue().toString()));
182                            if ((psql != null) && (psql.getStmtScope() != null)) {
183                                psql.getStmtScope().addSymbol(variable);
184                            }else{
185                                //TODO: execute 中的变量应该放在gloabl scope中吗?
186                                this.getGlobalScope().addSymbol(variable);
187                            }
188
189                            i++;
190                            //System.out.println(p.getParameterValue().toString());
191                        }
192                    }
193                }
194            };
195        }else if (node.getExecType() == TBaseType.metExecStringCmd){
196           this.stringValues = node.getStringValues();
197           TExpression execStringExpr = this.stringValues.getExpression(0);
198           TObjectName execStringVar = (execStringExpr.getExpressionType() == EExpressionType.simple_object_name_t)
199                   ? execStringExpr.getObjectOperand() : null;
200           if (execStringVar != null && execStringVar.getDbObjectType() == EDbObjectType.variable){
201               TVariable symbolVariable =  TSymbolTableManager.searchSymbolVariable(this.getFrameStack(),execStringVar.toString());
202               if (symbolVariable != null){
203                   //this.getSqlEnv().getVariableValue(symbolVariable.getQualifiedName(),symbolVariable.getVariableStr());
204                   this.sqlText = symbolVariable.getVariableStr();
205                   //System.out.println(this.sqlText);
206               }
207           } else {
208               // EXEC('<literal>') or a constant concatenation. T-SQL stores the concatenation operands
209               // as separate elements of stringValues (EXEC('a' + 'b') -> ['a','b']). Fold every element
210               // and only adopt the result when ALL parts are fully literal (getVal() set and not
211               // partial), so getSqlText() never becomes a partial / speculative value that every
212               // downstream TMssqlExecute consumer would then try to parse.
213               StringBuilder folded = new StringBuilder();
214               boolean fullyLiteral = true;
215               for (int si = 0; si < this.stringValues.size(); si++){
216                   TExpression part = this.stringValues.getExpression(si);
217                   part.evaluate(this.getFrameStack(), this);
218                   if (part.getVal() != null && !part.isValPartial()){
219                       // append the gated value (unquoted, via getStringInsideLiteral), not the mutable
220                       // plainText display field, so N'...' / escaped quotes fold correctly
221                       folded.append(part.getVal());
222                   } else {
223                       fullyLiteral = false;
224                       break;
225                   }
226               }
227               if (fullyLiteral && folded.length() > 0){
228                   this.sqlText = folded.toString();
229               }
230           }
231           this.linkServerName = node.getLinkServerName();
232           this.executeAsUser = node.getExecuteAsUser();
233           this.executeAsLogin = node.getExecuteAsLogin();
234       }else if (node.getExecType() == TBaseType.metNoExecKeyword){
235            //the first statement in a batch or an osql or sqlcmd script, EXEC is not required.
236            //dbo.uspGetEmployeeManagers @BusinessEntityID = 6;
237            if (this.sourcetokenlist.size() > 0){
238                TSourceToken st1 = this.sourcetokenlist.get(0);
239                String errMsg = "syntax error";
240                TSourceToken errToken = st1;
241                TSyntaxError err = new TSyntaxError(st1.toString(),st1.lineNo,st1.columnNo,"syntax error",EErrorType.sperror
242                        ,TBaseType.MSG_ERROR_SYNTAX_ERROR,this,st1.posinlist);
243                if (!isValidProcedureCall(this.sourcetokenlist,err))
244                    this.parseerrormessagehandle( err);
245
246              //  moduleName = (TObjectName)this.parser.getNf().createNode(ENodeType.T_ObjectName.getId()); //new TObjectName();
247                moduleName = new TObjectName();
248                moduleName.setGsqlparser(this.getGsqlparser());
249                int j = 0;
250                for(int i=0;i<this.sourcetokenlist.size();i++){
251                   if ((this.sourcetokenlist.get(i).tokentype == ETokenType.ttwhitespace)
252                           || (this.sourcetokenlist.get(i).tokentype == ETokenType.ttreturn)
253                           ||(this.sourcetokenlist.get(i).tokentype == ETokenType.ttsemicolon)
254                       ){
255                      break;
256                   }
257                    j++;
258                }
259                switch(j){
260                    case 1:
261                        moduleName.init(this.sourcetokenlist.get(0));
262                        break;
263                    case 3:
264                        moduleName.init(this.sourcetokenlist.get(0),this.sourcetokenlist.get(2));
265                        break;
266                    case 5:
267                        moduleName.init(this.sourcetokenlist.get(0),this.sourcetokenlist.get(2),this.sourcetokenlist.get(4));
268                        break;
269                    case 7:
270                        moduleName.init(this.sourcetokenlist.get(0),this.sourcetokenlist.get(2),this.sourcetokenlist.get(4),this.sourcetokenlist.get(6));
271                        break;
272                    default:
273                        moduleName = null;
274                        break;
275                }
276
277                if (moduleName != null){
278                    //moduleName.setObjectType(TObjectName.ttobjProcedureName);
279                    moduleName.setDbObjectType(EDbObjectType.procedure);
280                }
281
282            }
283
284        }
285      return 0;
286   }
287
288    public TObjectName getLinkServerName() {
289        return linkServerName;
290    }
291
292    private TObjectName linkServerName;
293
294    private TObjectName executeAsUser;
295    private TObjectName executeAsLogin;
296
297    public TObjectName getExecuteAsUser() {
298        return executeAsUser;
299    }
300
301    public TObjectName getExecuteAsLogin() {
302        return executeAsLogin;
303    }
304
305   public void accept(TParseTreeVisitor v){
306       v.preVisit(this);
307       v.postVisit(this);
308   }
309    public void acceptChildren(TParseTreeVisitor v){
310        v.preVisit(this);
311        v.postVisit(this);
312    }
313
314    public void setModuleName(TObjectName moduleName) {
315        this.moduleName = moduleName;
316    }
317
318    public void setReturnStatus(TObjectName returnStatus) {
319        this.returnStatus = returnStatus;
320    }
321
322    public void setParameters(TExecParameterList parameters) {
323        this.parameters = parameters;
324    }
325
326    public void setStringValues(TExpressionList stringValues) {
327        this.stringValues = stringValues;
328    }
329
330    public void setExecType(int execType) {
331        this.execType = execType;
332    }
333}