001/*
002 * Decompiled with CFR 0.152.
003 */
004package gudusoft.gsqlparser.parser;
005
006import gudusoft.gsqlparser.EDataType;
007import gudusoft.gsqlparser.EDbVendor;
008import gudusoft.gsqlparser.EErrorType;
009import gudusoft.gsqlparser.EFindSqlStateType;
010import gudusoft.gsqlparser.ESqlStatementType;
011import gudusoft.gsqlparser.ETokenType;
012import gudusoft.gsqlparser.TBaseType;
013import gudusoft.gsqlparser.TCustomLexer;
014import gudusoft.gsqlparser.TCustomParser;
015import gudusoft.gsqlparser.TCustomSqlStatement;
016import gudusoft.gsqlparser.TLexerTeradata;
017import gudusoft.gsqlparser.TParserTeradata;
018import gudusoft.gsqlparser.TSourceToken;
019import gudusoft.gsqlparser.TSourceTokenList;
020import gudusoft.gsqlparser.TStatementList;
021import gudusoft.gsqlparser.TSyntaxError;
022import gudusoft.gsqlparser.nodes.TDatatypeAttribute;
023import gudusoft.gsqlparser.nodes.TFunctionCall;
024import gudusoft.gsqlparser.nodes.TTypeName;
025import gudusoft.gsqlparser.nodes.teradata.TTeradataHelper;
026import gudusoft.gsqlparser.parser.AbstractSqlParser;
027import gudusoft.gsqlparser.parser.ParserContext;
028import gudusoft.gsqlparser.parser.SqlParseResult;
029import gudusoft.gsqlparser.resolver.TSQLResolver;
030import gudusoft.gsqlparser.sqlcmds.SqlCmdsFactory;
031import gudusoft.gsqlparser.stmt.TUnknownSqlStatement;
032import gudusoft.gsqlparser.stmt.teradata.TTeradataBTEQCmd;
033import gudusoft.gsqlparser.stmt.teradata.TTeradataFastExportCmd;
034import gudusoft.gsqlparser.stmt.teradata.TTeradataFastLoadCmd;
035import gudusoft.gsqlparser.stmt.teradata.TTeradataMultiLoadCmd;
036import gudusoft.gsqlparser.stmt.teradata.utilities.BteqCmdType;
037import java.util.ArrayList;
038
039public class TeradataSqlParser
040extends AbstractSqlParser {
041    public TLexerTeradata flexer;
042    private TParserTeradata fparser;
043    private TCustomSqlStatement gcurrentsqlstatement;
044    private char curdelimiterchar = (char)59;
045
046    // BTEQ state tracking - must persist across token processing
047    private boolean inBTEQComment = false;
048    private boolean isContinueBTEQCmd = false;
049
050    public TeradataSqlParser() {
051        super(EDbVendor.dbvteradata);
052        this.delimiterChar = '/';  // Teradata uses forward slash as delimiter for stored procedures
053        this.defaultDelimiterStr = ";";  // Match TGSqlParser default
054        this.flexer = new TLexerTeradata();
055        this.flexer.delimiterchar = '/';  // Must match TGSqlParser: delimiterchar = '/'
056        this.flexer.defaultDelimiterStr = ";";  // Match TGSqlParser default
057        this.lexer = this.flexer;
058        this.fparser = new TParserTeradata(null);
059        this.fparser.lexer = this.flexer;
060    }
061
062    @Override
063    protected TCustomLexer getLexer(ParserContext context) {
064        // Transfer Teradata utility type from context to lexer
065        if (context.getTeradataUtilityType() != null) {
066            this.flexer.setTeradataUtilityType(context.getTeradataUtilityType());
067        }
068        return this.flexer;
069    }
070
071    @Override
072    protected TCustomParser getParser(ParserContext context, TSourceTokenList tokens) {
073        this.fparser.sourcetokenlist = tokens;
074        return this.fparser;
075    }
076
077    @Override
078    protected TCustomParser getSecondaryParser(ParserContext context, TSourceTokenList tokens) {
079        return null;
080    }
081
082    @Override
083    protected void tokenizeVendorSql() {
084        this.doteradatatexttotokenlist();
085    }
086
087    @Override
088    protected void setupVendorParsersForExtraction() {
089        this.fparser.sqlcmds = this.sqlcmds;
090        this.fparser.sourcetokenlist = this.sourcetokenlist;
091    }
092
093    @Override
094    protected void extractVendorRawStatements(SqlParseResult.Builder builder) {
095        this.doteradatagetrawsqlstatements(builder);
096    }
097
098    private void doteradatatexttotokenlist() {
099        TSourceToken asourcetoken, lcprevst;
100        int yychar;
101
102        asourcetoken = this.getanewsourcetoken();
103        if (asourcetoken == null) {
104            return;
105        }
106        yychar = asourcetoken.tokencode;
107
108        while (yychar > 0) {
109            this.sourcetokenlist.add(asourcetoken);
110            asourcetoken = this.getanewsourcetoken();
111            if (asourcetoken == null) break;
112
113            if ((asourcetoken.tokencode == TBaseType.rrw_casespecific)
114                    || (asourcetoken.tokencode == TBaseType.rrw_teradata_cs)) {
115                // change not to not1 to make "not null column constraints" work correctly
116                // |RW_NOT1 RW_CASESPECIFIC
117                lcprevst = this.getprevsolidtoken(asourcetoken);
118                if (lcprevst != null) {
119                    if (lcprevst.tokencode == TBaseType.rrw_not) {
120                        lcprevst.tokencode = TBaseType.rw_not1;
121                    }
122                }
123            } else if (asourcetoken.tokencode == ';') {
124                lcprevst = this.getprevsolidtoken(asourcetoken);
125                if (lcprevst != null) {
126                    if (lcprevst.tokencode == ';') {
127                        asourcetoken.tokencode = TBaseType.sqlpluscmd;
128                    }
129                }
130            } else if (asourcetoken.tokencode == TBaseType.variable) { // mantisbt/view.php?id=972
131                if (asourcetoken.toString().toLowerCase().endsWith("begin")) { // MYPROC :BEGIN
132                    asourcetoken.tokencode = TBaseType.rrw_begin;
133                    asourcetoken.tokentype = ETokenType.ttkeyword;
134
135                    lcprevst = this.getprevsolidtoken(asourcetoken);
136                    if (lcprevst != null) {
137                        lcprevst.tokencode = TBaseType.mslabel;
138                    }
139                }
140            } else if (asourcetoken.tokencode == TCustomLexer.UNICODE_ENCODE_ID) {
141                if (asourcetoken.toString().endsWith("008D")) { // REVERSE LINE FEED, https://codepoints.net/U+008D?lang=en
142                    asourcetoken.tokencode = TBaseType.lexspace;
143                } else {
144                    asourcetoken.tokencode = TBaseType.ident;
145                }
146            }
147
148            yychar = asourcetoken.tokencode;
149        }
150    }
151
152    private TSourceToken getprevsolidtoken(TSourceToken ptoken) {
153        TSourceToken ret = null;
154        TSourceTokenList lctokenlist = ptoken.container;
155        if (lctokenlist != null && ptoken.posinlist > 0 && lctokenlist.size() > ptoken.posinlist - 1) {
156            ret = lctokenlist.get((int)(ptoken.posinlist - 1)).tokentype != ETokenType.ttwhitespace && lctokenlist.get((int)(ptoken.posinlist - 1)).tokentype != ETokenType.ttreturn && lctokenlist.get((int)(ptoken.posinlist - 1)).tokentype != ETokenType.ttsimplecomment && lctokenlist.get((int)(ptoken.posinlist - 1)).tokentype != ETokenType.ttbracketedcomment ? lctokenlist.get(ptoken.posinlist - 1) : lctokenlist.nextsolidtoken(ptoken.posinlist - 1, -1, false);
157        }
158        return ret;
159    }
160
161    private int doteradatagetrawsqlstatements(SqlParseResult.Builder builder) {
162        this.gcurrentsqlstatement = null;
163        EFindSqlStateType gst = EFindSqlStateType.stnormal;
164        int lcNestedParens = 0;
165        int lcNestedBeginEnd = 0;
166        int lcNestedCase = 0;
167        int lcNestedSample = 0;
168        Object lcprevst = null;
169        Object lcnextst = null;
170        Object lcnextst2 = null;
171        Object lcnextst3 = null;
172        TSourceToken lcprevsolidtoken = null;
173        TSourceToken ast = null;
174        int errorcount = 0;
175        // Note: inBTEQComment and isContinueBTEQCmd are now instance fields
176        this.inBTEQComment = false;
177        this.isContinueBTEQCmd = false;
178        char ch;
179        String lcstr;
180        block10: for (int i = 0; i < this.sourcetokenlist.size(); ++i) {
181            if (ast != null && ast.issolidtoken()) {
182                lcprevsolidtoken = ast;
183            }
184            ast = this.sourcetokenlist.get(i);
185            this.sourcetokenlist.curpos = i;
186            if (ast.tokencode != TBaseType.rrw_time && ast.tokencode != TBaseType.rrw_date && ast.tokencode != TBaseType.rrw_timestamp) {
187                if (ast.tokencode == '(') {
188                    this.handleLeftParenthesisToken(ast, i);
189                } else if (ast.tokencode == TBaseType.rrw_for) {
190                    this.handleForToken(ast);
191                } else if (ast.tokencode == TBaseType.rrw_teradata_last) {
192                    this.handleLastToken(ast);
193                } else if (ast.tokencode == TBaseType.rrw_teradata_pivot) {
194                    this.handlePivotToken(ast);
195                } else if (ast.tokencode == TBaseType.rrw_teradata_period) {
196                    this.handlePeriodToken(ast);
197                } else if (ast.tokencode == TBaseType.rrw_teradata_transaction) {
198                    this.handleTransactionToken(ast);
199                } else if (ast.tokencode == TBaseType.rrw_replace) {
200                    this.handleReplaceToken(ast);
201                } else if (ast.tokencode == TBaseType.rrw_between) {
202                    this.handleBetweenToken(ast);
203                } else if (ast.tokencode == TBaseType.rrw_declare) {
204                    this.handleDeclareToken(ast);
205                } else if (ast.tokencode == TBaseType.rrw_case && ast.tag == 0 && ast.posinlist + 1 < this.sourcetokenlist.size()) {
206                    this.handleCaseToken(ast);
207                } else if (ast.tokencode == TBaseType.rrw_grant) {
208                    this.handleGrantToken(ast);
209                } else if (ast.tokencode == TBaseType.variable) {
210                    this.handleVariableToken(ast);
211                } else if (ast.tokencode == TBaseType.rrw_teradata_sequenced || ast.tokencode == TBaseType.rrw_teradata_nonsequenced) {
212                    this.handleSequencedToken(ast);
213                }
214            }
215            switch (gst) {
216                case sterror: {
217                    if (ast.tokentype == ETokenType.ttsemicolon) {
218                        this.gcurrentsqlstatement.sourcetokenlist.add(ast);
219                        this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
220                        gst = EFindSqlStateType.stnormal;
221                        continue block10;
222                    }
223                    this.gcurrentsqlstatement.sourcetokenlist.add(ast);
224                    continue block10;
225                }
226                case stMultiLoadCmd: {
227                    gst = this.handleMultiLoadCmdState(ast, gst, builder);
228                    continue block10;
229                }
230                case stFastExportCmd: {
231                    gst = this.handleFastExportCmdState(ast, gst, builder);
232                    continue block10;
233                }
234                case stFastLoadCmd: {
235                    gst = this.handleFastLoadCmdState(ast, gst, builder);
236                    continue block10;
237                }
238                case stBTEQCmd: {
239                    gst = this.handleBTEQCmdState(ast, builder);
240                    continue block10;
241                }
242                case stnormal: {
243                    gst = this.handleNormalState(ast, gst, lcprevsolidtoken, builder);
244                    if (gst != EFindSqlStateType.ststoredprocedure) continue block10;
245                    lcNestedParens = 0;
246                    continue block10;
247                }
248                case stsql: {
249                    boolean readyToEnd = true;
250                    if (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstteradatacreatemacro) {
251                        if (ast.tokencode == '(' || ast.tokencode == TBaseType.left_parenthesis_2) {
252                            ++lcNestedParens;
253                        }
254                        if (ast.tokencode == ')') {
255                            --lcNestedParens;
256                            if (lcNestedParens < 0) {
257                                lcNestedParens = 0;
258                            }
259                        }
260                        readyToEnd = lcNestedParens == 0;
261                    }
262                    if (ast.tokentype == ETokenType.ttsemicolon && readyToEnd) {
263                        this.gcurrentsqlstatement.sourcetokenlist.add(ast);
264                        this.gcurrentsqlstatement.semicolonended = ast;
265                        this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
266                        gst = EFindSqlStateType.stnormal;
267                        continue block10;
268                    }
269                    if (ast.tokencode == TBaseType.cmtdoublehyphen && ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)) {
270                        this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
271                        gst = EFindSqlStateType.stnormal;
272                        continue block10;
273                    }
274                    this.gcurrentsqlstatement.sourcetokenlist.add(ast);
275                    continue block10;
276                }
277                case ststoredprocedure: {
278                    boolean readyToEnd = true;
279                    if (ast.tokencode == ';') {
280                        // don't count case..end, sample ... end after ;
281                        lcNestedSample = 0;
282                        lcNestedCase = 0;
283                    } else if (ast.tokencode == TBaseType.rrw_case) { // case ... end
284                        ++lcNestedCase;
285                        TSourceToken prevst = ast.prevSolidToken();
286                        if (prevst != null && prevst.tokencode == TBaseType.rrw_end) {
287                            // don't count: end case
288                            --lcNestedCase;
289                        }
290                    } else if (ast.tokencode == TBaseType.rrw_teradata_sample) { // sample ... end
291                        ++lcNestedSample;
292                    }
293                    if (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatetrigger
294                            || this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreateprocedure
295                            || this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatefunction) {
296                        if (ast.tokencode == '(' || ast.tokencode == TBaseType.left_parenthesis_2) {
297                            ++lcNestedParens;
298                        }
299                        if (ast.tokencode == ')' && --lcNestedParens < 0) {
300                            lcNestedParens = 0;
301                        }
302                        if (ast.tokencode == TBaseType.rrw_begin) {
303                            ++lcNestedBeginEnd;
304                        }
305                        if (ast.tokencode == TBaseType.rrw_end) {
306                            boolean countThisEnd = true;
307                            if (lcNestedSample > 0) {
308                                // don't count sample...end
309                                --lcNestedSample;
310                                countThisEnd = false;
311                            } else if (lcNestedCase > 0) {
312                                // don't count case...end
313                                --lcNestedCase;
314                                countThisEnd = false;
315                            }
316                            if (countThisEnd) {
317                                // don't count end while/if/case/loop/for/repeat
318                                TSourceToken nt = ast.nextSolidToken();
319                                if (nt != null) {
320                                    countThisEnd = nt.tokencode != TBaseType.rrw_while
321                                            && nt.tokencode != TBaseType.rrw_if
322                                            && nt.tokencode != TBaseType.rrw_case
323                                            && nt.tokencode != TBaseType.rrw_loop
324                                            && nt.tokencode != TBaseType.rrw_for
325                                            && nt.tokencode != TBaseType.rrw_repeat;
326                                }
327                            }
328                            if (countThisEnd && --lcNestedBeginEnd < 0) {
329                                lcNestedBeginEnd = 0;
330                            }
331                        }
332                        readyToEnd = lcNestedParens == 0 && lcNestedBeginEnd == 0;
333                    }
334                    // single stmt in function/procedure/trigger may use ; as terminate char
335                    // so default terminate char is ;, if begin is found, then
336                    // set terminate char to DelimiterChar
337                    if (this.curdelimiterchar != this.delimiterChar) {
338                        if (ast.tokencode == TBaseType.rrw_begin) {
339                            this.curdelimiterchar = this.delimiterChar;
340                        } else if (ast.tokencode == TBaseType.mslabel && ast.container.nextsolidtoken(ast, 1, false).tokencode == TBaseType.rrw_begin) {
341                            this.curdelimiterchar = this.delimiterChar;
342                        }
343                    }
344                    if (this.curdelimiterchar == ';') {
345                        this.gcurrentsqlstatement.sourcetokenlist.add(ast);
346                        if (ast.tokentype == ETokenType.ttsemicolon
347                                && (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatetrigger
348                                    || this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreateprocedure)
349                                && readyToEnd) {
350                            gst = EFindSqlStateType.stnormal;
351                            this.gcurrentsqlstatement.semicolonended = ast;
352                            this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
353                            continue block10;
354                        }
355                    } else {
356                        if (ast.getAstext().length() == 1) {
357                            ch = ast.getAstext().charAt(0);
358                        } else if (ast.getAstext().length() > 1) {
359                            ch = ast.getAstext().charAt(ast.getAstext().length() - 1);
360                        } else {
361                            ch = ' ';
362                        }
363                        if (ast.tokencode != TBaseType.cmtslashstar && ast.tokencode != TBaseType.cmtdoublehyphen
364                                && ch == this.curdelimiterchar && ast.isFirstTokenOfLine() && readyToEnd) {
365                            if (ast.getAstext().length() > 1) {
366                                lcstr = ast.getAstext().substring(0, ast.getAstext().length() - 1);
367                                int c2 = this.flexer.getkeywordvalue(lcstr);
368                                if (c2 > 0) {
369                                    ast.tokencode = c2;
370                                }
371                            } else {
372                                this.gcurrentsqlstatement.semicolonended = ast;
373                            }
374                            this.gcurrentsqlstatement.sourcetokenlist.add(ast);
375                            gst = EFindSqlStateType.stnormal;
376                            this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
377                        } else if (ast.searchToken(TBaseType.rrw_create, 1) != null && ast.searchToken(TBaseType.rrw_procedure, 4) != null && readyToEnd) {
378                            gst = EFindSqlStateType.stnormal;
379                            this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
380                        } else if (ast.tokencode == ';') {
381                            this.gcurrentsqlstatement.sourcetokenlist.add(ast);
382                            boolean startNewStatement = false;
383                            if (readyToEnd) {
384                                startNewStatement = this.sqlcmds.issql(ast.nextSolidToken(), gst, this.gcurrentsqlstatement) != null;
385                            }
386                            if (startNewStatement) {
387                                gst = EFindSqlStateType.stnormal;
388                                this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
389                            }
390                        } else {
391                            this.gcurrentsqlstatement.sourcetokenlist.add(ast);
392                        }
393                    }
394                    if (gst == EFindSqlStateType.ststoredprocedure && ast.tokencode == TBaseType.cmtdoublehyphen && ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)) {
395                        gst = EFindSqlStateType.stnormal;
396                        this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
397                    }
398                }
399            }
400        }
401        if (TBaseType.assigned(this.gcurrentsqlstatement) && (gst == EFindSqlStateType.stsql || gst == EFindSqlStateType.stBTEQCmd || gst == EFindSqlStateType.ststoredprocedure || gst == EFindSqlStateType.sterror)) {
402            this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, true, builder);
403        }
404        builder.sqlStatements(this.sqlstatements);
405        builder.syntaxErrors(this.syntaxErrors instanceof ArrayList ? (ArrayList)this.syntaxErrors : new ArrayList(this.syntaxErrors));
406        builder.errorCode(this.syntaxErrors.isEmpty() ? 0 : this.syntaxErrors.size());
407        return errorcount;
408    }
409
410    private void handleLeftParenthesisToken(TSourceToken ast, int i) {
411        TSourceToken lcnextst = this.sourcetokenlist.nextsolidtoken(i, 1, false);
412        TSourceToken lcprevst = this.getprevsolidtoken(ast);
413        if ((lcprevst != null) && (
414                (lcprevst.tokencode == TBaseType.rrw_teradata_cast)
415                || (lcprevst.tokencode == TBaseType.rrw_year) // sample sql: select year(date) - 1 mantisbt/view.php?id=3049
416        )) {
417            lcnextst = null; // don't check next token if prev token is cast. sample: cast(DATETIME as BIGINT)
418        }
419        if ((lcprevst != null) && (TFunctionCall.isBuiltIn(lcprevst.toString(), EDbVendor.dbvteradata))) {
420            if (((lcprevst.tokencode == TBaseType.rrw_end)
421                    || (lcprevst.tokencode == TBaseType.rrw_time)
422                    || (lcprevst.tokencode == TBaseType.rrw_date)
423                    || (lcprevst.tokencode == TBaseType.rrw_timestamp)
424                    || (lcprevst.tokencode == TBaseType.rrw_teradata_type)
425                    || (lcprevst.toString().equalsIgnoreCase("current_date"))
426                    || (lcprevst.toString().equalsIgnoreCase("current_time"))
427                    || (lcprevst.toString().equalsIgnoreCase("current_timestamp"))
428                    || (lcprevst.toString().equalsIgnoreCase("user"))
429                    || (lcprevst.toString().equalsIgnoreCase("current_user"))
430            )) {
431                // Keep lcnextst as is
432            } else {
433                lcnextst = null;
434            }
435        }
436        if (lcnextst != null) {
437            EDataType dataType = TTypeName.searchTeradataTypeByName(lcnextst.toString());
438            if ((dataType != null) && (lcprevst != null) && (lcprevst.tokencode != TBaseType.rrw_teradata_period)) {
439                ast.tokencode = TBaseType.rrw_teradata_start_data_conversion;
440                // lcnextst2 is the token 2 steps after (
441                TSourceToken lcnextst2 = this.sourcetokenlist.nextsolidtoken(i, 2, false);
442                // lcnextst3 is the token 3 steps after (
443                TSourceToken lcnextst3 = this.sourcetokenlist.nextsolidtoken(i, 3, false);
444                if (lcnextst2.tokencode == ',') {
445                    // this is data conversion: (date,format '$xxx'),
446                    // this is not data conversion: trunc(date,'yy')
447                    TSourceToken st1 = lcnextst3;
448                    TSourceToken st2 = this.sourcetokenlist.nextsolidtoken(i, 4, false);
449                    if (TDatatypeAttribute.searchDataTypeAttributeByName(st1, st2) == null) {
450                        // this is not data conversion, such as :trunc(date,'yy')
451                        ast.tokencode = '(';
452                    }
453                } else if (lcnextst2 != null && lcnextst3 != null) {
454                    this.handleDataTypeConversion(ast, dataType, lcnextst2, lcnextst3);
455                }
456            } else {
457                TSourceToken st1 = lcnextst;
458                TSourceToken st2 = this.sourcetokenlist.nextsolidtoken(i, 2, false);
459                if (TDatatypeAttribute.searchDataTypeAttributeByName(st1, st2) != null) {
460                    ast.tokencode = TBaseType.rrw_teradata_start_data_conversion;
461                }
462            }
463        }
464    }
465
466    private void handleDataTypeConversion(TSourceToken ast, EDataType dataType, TSourceToken lcnextst2, TSourceToken lcnextst3) {
467        switch (dataType) {
468            case date_t:
469            case time_t:
470                // next token is: ) or comma or data attribute token
471                if ((lcnextst2.tokencode == ')')
472                        || ((lcnextst2.tokencode == '(') && (lcnextst3.tokencode == TBaseType.iconst))) { // hire_date (time(6))
473                    // (date)
474                    // select (date) from t, here (date) is a function, not a data conversion,
475                } else {
476                    ast.tokencode = '(';
477                }
478                break;
479            case timestamp_t:
480            case interval_t:
481                if (lcnextst2.tokencode == TBaseType.sconst) { // INSERT t1 (TIME '10:44:25.123-08:00',TIMESTAMP '2000-09-20 10:44:25.1234')
482                    ast.tokencode = '(';
483                }
484                break;
485            case period_t:
486                if (lcnextst2.tokencode == '(') {
487                    // 只有 period() 才确保这里 period 是datatype,否则period不是datatype
488                } else {
489                    ast.tokencode = '(';
490                }
491                break;
492            case char_t:
493                if (lcnextst2.tokencode == ')') {
494                    // NULL (CHAR) AS B
495                } else if (lcnextst3.tokencode != TBaseType.iconst) { // INSERT t1 (TIME '10:44:25.123-08:00',TIMESTAMP '2000-09-20 10:44:25.1234')
496                    ast.tokencode = '(';
497                }
498                break;
499            default:
500                break;
501        }
502    }
503
504    private void handleForToken(TSourceToken ast) {
505        TSourceToken nextToken = ast.searchTokenAfterObjectName();
506        if (nextToken != null) {
507            if (nextToken.tokencode == TBaseType.rrw_as) {
508                ast.tokencode = TBaseType.rrw_teradata_for_loop;
509            }
510        }
511    }
512
513    private void handleLastToken(TSourceToken ast) {
514        TSourceToken nextToken = ast.searchToken('(', 1);
515        if (nextToken != null) {
516            ast.tokencode = TBaseType.rrw_last_function;
517        }
518    }
519
520    private void handlePivotToken(TSourceToken ast) {
521        TSourceToken nextToken = ast.searchToken('(', 1);
522        if (nextToken == null) {
523            ast.tokencode = TBaseType.ident;
524        }
525    }
526
527    private void handlePeriodToken(TSourceToken ast) {
528        TSourceToken nextToken = ast.nextSolidToken();
529        if (nextToken == null) {
530            ast.tokencode = TBaseType.ident;
531        } else if (nextToken.tokencode == '(') {
532            // keep it as keyword
533        } else if (nextToken.tokencode == TBaseType.rrw_for) {
534            // keep it as keyword
535        } else if (nextToken.tokencode == TBaseType.sconst) {
536            // sample: DEFAULT PERIOD '(2005-02-03, 2006-02-03)'
537            // keep it as keyword
538        } else {
539            if (ast.prevSolidToken() == null) {
540                ast.tokencode = TBaseType.ident;
541            } else {
542                if (!ast.prevSolidToken().toString().equalsIgnoreCase("anchor")) {
543                    ast.tokencode = TBaseType.ident;
544                }
545            }
546        }
547    }
548
549    private void handleTransactionToken(TSourceToken ast) {
550        TSourceToken lcprevst = this.getprevsolidtoken(ast);
551        if (lcprevst != null) {
552            if (lcprevst.tokencode == TBaseType.rrw_end) {
553                lcprevst.tokencode = TBaseType.rrw_teradata_end_t;
554            }
555        }
556    }
557
558    private void handleReplaceToken(TSourceToken ast) {
559        TSourceToken nextToken = ast.searchToken('(', 1);
560        if (nextToken != null) {
561            ast.tokencode = TBaseType.ident;
562        }
563    }
564
565    private void handleBetweenToken(TSourceToken ast) {
566        TSourceToken nextToken = ast.nextSolidToken();
567        if (nextToken != null) {
568            if ((nextToken.tokencode == TBaseType.rrw_begin) || (nextToken.tokencode == TBaseType.rrw_end)) {
569                // BETWEEN begin(DODD_EFF_PERI)
570                nextToken.tokencode = TBaseType.ident;
571            }
572        }
573    }
574
575    private void handleDeclareToken(TSourceToken ast) {
576        TSourceToken nextToken = ast.nextSolidToken();
577        if (nextToken != null) {
578            TSourceToken nextnextToken = nextToken.nextSolidToken();
579            if (nextnextToken != null) {
580                if ((nextnextToken.toString().equalsIgnoreCase("cursor"))
581                        || (nextnextToken.toString().equalsIgnoreCase("insensitive"))
582                        || (nextnextToken.toString().equalsIgnoreCase("scroll"))
583                        || (nextnextToken.toString().equalsIgnoreCase("no"))) {
584                    nextToken.tokencode = TBaseType.rrw_teradata_cursor_name;
585                } else if ((nextnextToken.toString().equalsIgnoreCase("condition"))) {
586                    nextToken.tokencode = TBaseType.rrw_teradata_condition_name;
587                }
588            }
589        }
590    }
591
592    private void handleCaseToken(TSourceToken ast) {
593        int lcNest = 1;
594        for (int m = ast.posinlist + 1; m < this.sourcetokenlist.size() - 1; m++) {
595            TSourceToken st = this.sourcetokenlist.get(m);
596            if (st.tokencode == TBaseType.rrw_case) {
597                st.tag = 1; // this is nested case keyword, don't check this token later
598                lcNest++;
599            }
600            if (st.tokencode == TBaseType.rrw_end) {
601                lcNest--;
602                if (lcNest == 0) {
603                    TSourceToken caseToken = st.nextSolidToken();
604                    if (caseToken != null) {
605                        if (caseToken.tokencode == TBaseType.rrw_case) {
606                            ast.tokencode = TBaseType.rrw_teradata_case_stmt;
607                            caseToken.tag = 1; // this is case after end, don't check this token later
608                        }
609                    }
610                    // Always break after finding the matching END, whether it's followed by CASE or not
611                    // This prevents CASE expressions from incorrectly matching with later "END CASE" constructs
612                    break;
613                }
614            }
615        }
616    }
617
618    private void handleGrantToken(TSourceToken ast) {
619        TSourceToken prevSolidToken = ast.prevSolidToken();
620        if (prevSolidToken != null) {
621            if (prevSolidToken.tokencode == TBaseType.rrw_with) {
622                prevSolidToken.tokencode = TBaseType.rrw_teradata_with_grant;
623            }
624        }
625    }
626
627    private void handleVariableToken(TSourceToken ast) {
628        // USING ( _spVV8 VARCHAR(1024) CHARACTER SET UNICODE ) SELECT INTO :_spVV8 ;
629        // variable after into keyword treat as identifier
630        TSourceToken prevSolidToken = ast.prevSolidToken();
631        if (prevSolidToken != null) {
632            if (prevSolidToken.tokencode == TBaseType.rrw_into) {
633                ast.tokencode = TBaseType.ident;
634            }
635        }
636    }
637
638    private void handleSequencedToken(TSourceToken ast) {
639        TSourceToken nextSolidToken = ast.nextSolidToken();
640        if (nextSolidToken != null) {
641            if ((nextSolidToken.tokencode == TBaseType.rrw_teradata_validtime)) {
642                TSourceToken nextToken2 = nextSolidToken.nextSolidToken();
643                if (nextToken2 != null) {
644                    if ((nextToken2.tokencode == TBaseType.rrw_select)
645                            || (nextToken2.tokencode == TBaseType.rrw_insert)
646                            || (nextToken2.tokencode == TBaseType.rrw_update)
647                            || (nextToken2.tokencode == TBaseType.rrw_delete)
648                            || (nextToken2.tokencode == TBaseType.rrw_merge)) {
649                        // SEQUENCED VALIDTIME select/insert/update/delete/merge
650                        ast.tokencode = TBaseType.lexspace;
651                        nextSolidToken.tokencode = TBaseType.lexspace;
652                    }
653                }
654            }
655        }
656    }
657
658    private EFindSqlStateType handleMultiLoadCmdState(TSourceToken ast, EFindSqlStateType gst, SqlParseResult.Builder builder) {
659        this.gcurrentsqlstatement.sourcetokenlist.add(ast);
660        if ((ast.tokencode == ';') && (ast.isLastTokenOfLine())) {
661            TSourceToken nextToken = ast.nextSolidToken();
662            TSourceToken nextToken2 = nextToken != null ? nextToken.nextSolidToken() : null;
663            if (nextToken != null && nextToken2 != null &&
664                    nextToken.tokencode == '.' &&
665                    nextToken2.toString().equalsIgnoreCase("FIELD") &&
666                    nextToken.isFirstTokenOfLine()) {
667                // Remain in stMultiLoadCmd state
668            } else {
669                this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
670                gst = EFindSqlStateType.stnormal;
671            }
672        } else if (ast.isLastTokenOfLine()) {
673            // .IF ERRORCODE <> 0 THEN
674            // INSERT INTO Sou_EMP_Tab
675            //        (1, 'bala');
676            String cmdstr = this.gcurrentsqlstatement.sourcetokenlist.get(0).toString();
677            if (this.gcurrentsqlstatement.sourcetokenlist.size() > 1) {
678                cmdstr = cmdstr + this.gcurrentsqlstatement.sourcetokenlist.get(1).toString();
679            }
680            if ((cmdstr.toLowerCase().startsWith(".if")) || (cmdstr.toLowerCase().startsWith(".set")) || (cmdstr.toLowerCase().startsWith("set"))) {
681                this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
682                gst = EFindSqlStateType.stnormal;
683            }
684        }
685        return gst;
686    }
687
688    private EFindSqlStateType handleFastExportCmdState(TSourceToken ast, EFindSqlStateType gst, SqlParseResult.Builder builder) {
689        this.gcurrentsqlstatement.sourcetokenlist.add(ast);
690        if ((ast.tokencode == ';') && (ast.isLastTokenOfLine())) {
691            this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
692            gst = EFindSqlStateType.stnormal;
693        } else {
694            boolean findSQL = false;
695            TSourceToken nextst = ast.nextToken();
696            if (nextst != null) {
697                if (nextst.tokentype == ETokenType.ttreturn) {
698                    findSQL = (this.sqlcmds.issql(ast.nextSolidToken(), gst, this.gcurrentsqlstatement) != null);
699                    if (findSQL) {
700                        this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
701                        gst = EFindSqlStateType.stnormal;
702                    }
703                }
704            }
705        }
706        return gst;
707    }
708
709    private EFindSqlStateType handleFastLoadCmdState(TSourceToken ast, EFindSqlStateType gst, SqlParseResult.Builder builder) {
710        this.gcurrentsqlstatement.sourcetokenlist.add(ast);
711        if ((ast.tokencode == ';') && (ast.isLastTokenOfLine())) {
712            this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
713            gst = EFindSqlStateType.stnormal;
714        } else if (ast.tokencode == TBaseType.lexnewline) {
715            TSourceToken nextst = ast.nextSolidToken();
716            if (nextst != null) {
717                if (nextst.tokencode == TBaseType.BTEQCMD) {
718                    this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
719                    gst = EFindSqlStateType.stFastLoadCmd;
720                } else if (nextst.tokencode == '.') {
721                    this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
722                    gst = EFindSqlStateType.stFastLoadCmd;
723                } else if (this.sqlcmds.issql(nextst, gst, this.gcurrentsqlstatement) != null) {
724                    this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
725                    gst = EFindSqlStateType.stnormal;
726                }
727            }
728        }
729        return gst;
730    }
731
732    private EFindSqlStateType handleBTEQCmdState(TSourceToken ast, SqlParseResult.Builder builder) {
733        EFindSqlStateType gst = EFindSqlStateType.stBTEQCmd;
734        this.gcurrentsqlstatement.sourcetokenlist.add(ast);
735
736        if (ast.tokencode == TBaseType.lexnewline) {
737            if (this.isContinueBTEQCmd) {
738                this.isContinueBTEQCmd = false;
739            } else {
740                if (((TTeradataBTEQCmd)this.gcurrentsqlstatement).getBteqCmdType() == BteqCmdType.LOGON) {
741                    boolean findSQL = (this.sqlcmds.issql(ast.nextSolidToken(), gst, this.gcurrentsqlstatement) != null);
742                    if (findSQL) {
743                        this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
744                        gst = EFindSqlStateType.stnormal;
745                    }
746                } else {
747                    this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
748                    gst = EFindSqlStateType.stnormal;
749                }
750            }
751        } else if ((ast.tokencode == '-') && (ast.isLastTokenOfLine())) {
752            if (!this.inBTEQComment) {
753                this.isContinueBTEQCmd = true;
754            }
755        } else if (ast.tokencode == TBaseType.lexspace) {
756            // Do nothing
757        } else if (ast.tokencode == ';') {
758            this.onRawStatementComplete(this.parserContext, this.gcurrentsqlstatement, this.fparser, null, this.sqlstatements, false, builder);
759            boolean findNewCmdInSameLine = this.checkForNewBTEQCmdInSameLine(ast);
760            if (findNewCmdInSameLine) {
761                gst = EFindSqlStateType.stBTEQCmd;
762            } else {
763                gst = EFindSqlStateType.stnormal;
764            }
765        } else if (ast.tokencode == '*') {
766            this.isContinueBTEQCmd = false;
767        } else { // solid token
768            this.isContinueBTEQCmd = false;
769        }
770        return gst;
771    }
772
773    private boolean checkForNewBTEQCmdInSameLine(TSourceToken ast) {
774        boolean findNewCmdInSameLine = false;
775        if (!ast.isLastTokenOfLine()) {
776            // check if next cmd like below:
777            // .SET SIDETITLES ON; .SET FOLDLINE ON ALL
778            TSourceToken nextst = ast.nextSolidToken();
779            if ((nextst != null) && (nextst.tokencode == '.')) {
780                TSourceToken nextst2 = nextst.nextSolidToken();
781                TSourceToken searchToken = null;
782                if (nextst2 != null) {
783                    if (nextst2.tokencode == TBaseType.rrw_set) {
784                        TSourceToken nextst3 = nextst2.nextSolidToken();
785                        if (nextst3 != null) {
786                            searchToken = nextst3;
787                        }
788                    } else {
789                        searchToken = nextst2;
790                    }
791
792                    BteqCmdType bteqCmdType = BteqCmdType.searchBteqCmd(searchToken);
793                    if (bteqCmdType != null) {
794                        this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor);
795                        ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setBteqCmdType(bteqCmdType);
796                        this.gcurrentsqlstatement.sourcetokenlist.add(ast);
797                        findNewCmdInSameLine = true;
798                    }
799                }
800            }
801        }
802        return findNewCmdInSameLine;
803    }
804
805    private EFindSqlStateType handleNormalState(TSourceToken ast, EFindSqlStateType gst, TSourceToken lcprevsolidtoken, SqlParseResult.Builder builder) {
806        if ((ast.tokencode == TBaseType.cmtdoublehyphen)
807                || (ast.tokencode == TBaseType.cmtslashstar)
808                || (ast.tokencode == TBaseType.lexspace)
809                || (ast.tokencode == TBaseType.lexnewline)
810                || (ast.tokentype == ETokenType.ttsemicolon)) {
811            if (TBaseType.assigned(this.gcurrentsqlstatement)) {
812                this.gcurrentsqlstatement.sourcetokenlist.add(ast);
813            }
814
815            if ((lcprevsolidtoken != null) && (ast.tokentype == ETokenType.ttsemicolon)) {
816                if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon) {
817                    // ;;;; continuous semicolon, treat it as comment
818                    ast.tokentype = ETokenType.ttsimplecomment;
819                    ast.tokencode = TBaseType.cmtdoublehyphen;
820                }
821            }
822
823            return gst;
824        }
825        if ((gst = this.checkForBTEQOrUtilityCommand(ast, gst)) != EFindSqlStateType.stnormal) {
826            return gst;
827        }
828
829        // find a tokentext to start sql or stored procedure mode
830        this.gcurrentsqlstatement = this.sqlcmds.issql(ast, gst, this.gcurrentsqlstatement);
831
832        if (TBaseType.assigned(this.gcurrentsqlstatement)) {
833            ESqlStatementType[] ses = {ESqlStatementType.sstcreateprocedure, ESqlStatementType.sstteradatacreatefunction, ESqlStatementType.sstcreatetrigger};
834            if (this.includesqlstatementtype(this.gcurrentsqlstatement.sqlstatementtype, ses)) {
835                gst = EFindSqlStateType.ststoredprocedure;
836                this.gcurrentsqlstatement.sourcetokenlist.add(ast);
837                if ((this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreateprocedure)
838                        || (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstteradatacreatefunction)
839                        || (this.gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatetrigger)) {
840                    this.curdelimiterchar = ';';
841                }
842            } else {
843                gst = EFindSqlStateType.stsql;
844                this.gcurrentsqlstatement.sourcetokenlist.add(ast);
845            }
846        }
847
848        if ((!TBaseType.assigned(this.gcurrentsqlstatement)) && (ast.isFirstTokenOfLine())) {
849            gst = this.flexer.cmdType(ast);
850            if ((gst == EFindSqlStateType.stMultiLoadCmd) || (gst == EFindSqlStateType.stFastLoadCmd) || (gst == EFindSqlStateType.stFastExportCmd)) {
851                this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor);
852                ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setFindSqlStateType(gst);
853                this.gcurrentsqlstatement.sourcetokenlist.add(ast);
854                return gst;
855            }
856            gst = EFindSqlStateType.stnormal;
857        }
858
859        if (!TBaseType.assigned(this.gcurrentsqlstatement)) { // error tokentext found
860            this.syntaxErrors.add(new TSyntaxError(ast.getAstext(), ast.lineNo, (ast.columnNo < 0 ? 0 : ast.columnNo),
861                    "Error when tokenlize", EErrorType.spwarning, TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE, null, ast.posinlist));
862
863            ast.tokentype = ETokenType.tttokenlizererrortoken;
864            gst = EFindSqlStateType.sterror;
865
866            this.gcurrentsqlstatement = new TUnknownSqlStatement(this.vendor);
867            this.gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid;
868            this.gcurrentsqlstatement.sourcetokenlist.add(ast);
869        }
870        return gst;
871    }
872
873    private EFindSqlStateType checkForBTEQOrUtilityCommand(TSourceToken ast, EFindSqlStateType gst) {
874        // Check for .bteq commands: either "." at start of line, or "." after ";" at start of line
875        boolean isDotAtStartOfLine = (ast.tokencode == '.') && (ast.isFirstTokenOfLine());
876        boolean isDotAfterSemicolonAtStartOfLine = false;
877        if ((ast.tokencode == '.') && !isDotAtStartOfLine) {
878            TSourceToken prevToken = ast.prevSolidToken();
879            if ((prevToken != null) && (prevToken.tokencode == ';') && (prevToken.isFirstTokenOfLine())) {
880                isDotAfterSemicolonAtStartOfLine = true;
881            }
882        }
883
884        if (isDotAtStartOfLine || isDotAfterSemicolonAtStartOfLine) {
885            // .bteq commands
886            TSourceToken nextst = ast.nextSolidToken();
887            if (nextst != null) {
888                gst = this.flexer.cmdType(nextst);
889                boolean foundCmd = false;
890                switch (gst) {
891                    case stMultiLoadCmd:
892                        this.gcurrentsqlstatement = new TTeradataMultiLoadCmd(this.vendor);
893                        gst = EFindSqlStateType.stMultiLoadCmd;
894                        ((TTeradataMultiLoadCmd)this.gcurrentsqlstatement).setCmdType(TTeradataHelper.searchMultiLoadTypeByName(nextst.getAstext()));
895                        foundCmd = true;
896                        break;
897                    case stFastExportCmd:
898                        this.gcurrentsqlstatement = new TTeradataFastExportCmd(this.vendor);
899                        gst = EFindSqlStateType.stFastExportCmd;
900                        foundCmd = true;
901                        break;
902                    case stFastLoadCmd:
903                        this.gcurrentsqlstatement = new TTeradataFastLoadCmd(this.vendor);
904                        gst = EFindSqlStateType.stFastLoadCmd;
905                        foundCmd = true;
906                        break;
907                    case stBTEQCmd:
908                        this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor);
909                        ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setBteqCmdType(BteqCmdType.searchBteqCmd(nextst));
910                        gst = EFindSqlStateType.stBTEQCmd;
911                        foundCmd = true;
912                        break;
913                    default:
914                        break;
915                }
916                if (foundCmd) {
917                    this.gcurrentsqlstatement.sourcetokenlist.add(ast);
918                    return gst;
919                }
920            }
921        } else if ((ast.tokencode == '*') && (ast.isFirstTokenOfLine())) {
922            // BTEQ comment: * comment
923            gst = EFindSqlStateType.stBTEQCmd;
924            this.inBTEQComment = true;  // Mark that we're in a BTEQ comment
925            this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor);
926            ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setBteqCmdType(BteqCmdType.COMMENT);
927            this.gcurrentsqlstatement.sourcetokenlist.add(ast);
928            return gst;
929        } else if ((ast.tokencode == '=') && (ast.isFirstTokenOfLine())) {
930            // BTEQ command starting with =
931            TSourceToken st1 = ast.prevSolidToken();
932            if ((st1 != null) && (st1.tokencode == ';')) {
933                gst = EFindSqlStateType.stBTEQCmd;
934                this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor);
935                ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setFindSqlStateType(gst);
936                this.gcurrentsqlstatement.sourcetokenlist.add(ast);
937                return gst;
938            }
939        } else if ((ast.isFirstTokenOfLine()) && (BteqCmdType.searchBteqCmd(ast) != null)) {
940            TSourceToken st1 = ast.prevSolidToken();
941            if ((st1 != null) && (st1.tokencode == ';')) {
942                gst = EFindSqlStateType.stBTEQCmd;
943                this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor);
944                ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setFindSqlStateType(gst);
945                this.gcurrentsqlstatement.sourcetokenlist.add(ast);
946                return gst;
947            }
948        } else if ((ast.tokencode == '&') && (ast.isFirstTokenOfLine())) {
949            // Teradata macro/substitution variable: &VARIABLE_NAME at start of line
950            // Treat it as a BTEQ-like command that ends at end of line
951            TSourceToken nextst = ast.nextSolidToken();
952            if (nextst != null && (nextst.tokencode == TBaseType.ident || nextst.tokentype == ETokenType.ttidentifier)) {
953                gst = EFindSqlStateType.stBTEQCmd;
954                this.gcurrentsqlstatement = new TTeradataBTEQCmd(this.vendor);
955                ((TTeradataBTEQCmd)this.gcurrentsqlstatement).setFindSqlStateType(gst);
956                this.gcurrentsqlstatement.sourcetokenlist.add(ast);
957                return gst;
958            }
959        }
960        return EFindSqlStateType.stnormal;
961    }
962
963
964    private boolean includesqlstatementtype(ESqlStatementType type, ESqlStatementType[] types) {
965        for (ESqlStatementType t : types) {
966            if (type != t) continue;
967            return true;
968        }
969        return false;
970    }
971
972    @Override
973    protected TStatementList performParsing(ParserContext context, TCustomParser parser, TCustomParser secondaryParser, TSourceTokenList tokens, TStatementList rawStatements) {
974        this.fparser = (TParserTeradata)parser;
975        this.sourcetokenlist = tokens;
976        this.parserContext = context;
977        this.sqlstatements = rawStatements;
978        if (this.sqlstatements == null) {
979            this.sqlstatements = new TStatementList();
980            return this.sqlstatements;
981        }
982        if (this.sqlcmds == null) {
983            this.sqlcmds = SqlCmdsFactory.get(this.vendor);
984        }
985        this.fparser.sqlcmds = this.sqlcmds;
986
987        // Initialize global context for semantic analysis
988        // CRITICAL: When delegated from TGSqlParser, use TGSqlParser's frameStack
989        // so that variables set in SET statements can be found by EXECUTE statements
990        if (context != null && context.getGsqlparser() != null) {
991            gudusoft.gsqlparser.TGSqlParser gsqlparser = (gudusoft.gsqlparser.TGSqlParser) context.getGsqlparser();
992            this.frameStack = gsqlparser.getFrameStack();
993
994            // CRITICAL: Set gsqlparser on the NodeFactory - matches TGSqlParser behavior
995            // This is needed for proper AST node creation during parsing
996            this.fparser.getNf().setGsqlParser(gsqlparser);
997
998            // Create global context if needed
999            this.globalContext = new gudusoft.gsqlparser.compiler.TContext();
1000            this.sqlEnv = new gudusoft.gsqlparser.sqlenv.TSQLEnv(this.vendor) {
1001                @Override
1002                public void initSQLEnv() {
1003                }
1004            };
1005            this.globalContext.setSqlEnv(this.sqlEnv, this.sqlstatements);
1006        } else {
1007            this.initializeGlobalContext();
1008        }
1009
1010        for (int i = 0; i < this.sqlstatements.size(); ++i) {
1011            TCustomSqlStatement stmt = this.sqlstatements.getRawSql(i);
1012            try {
1013                stmt.setFrameStack(this.frameStack);
1014                int parseResult = stmt.parsestatement(null, false, context.isOnlyNeedRawParseTree());
1015                boolean doRecover = TBaseType.ENABLE_ERROR_RECOVER_IN_CREATE_TABLE;
1016                if (doRecover && (parseResult != 0 || stmt.getErrorCount() > 0)) {
1017                    this.handleCreateTableErrorRecovery(stmt);
1018                }
1019                if (parseResult == 0 && stmt.getErrorCount() <= 0) continue;
1020                this.copyErrorsFromStatement(stmt);
1021                continue;
1022            }
1023            catch (Exception ex) {
1024                ex.printStackTrace();
1025                this.handleStatementParsingException(stmt, i, ex);
1026            }
1027        }
1028        if (this.globalFrame != null) {
1029            this.globalFrame.popMeFromStack(this.frameStack);
1030        }
1031        return this.sqlstatements;
1032    }
1033
1034    private void handleCreateTableErrorRecovery(TCustomSqlStatement stmt) {
1035        if (!(stmt.sqlstatementtype != ESqlStatementType.sstcreatetable && stmt.sqlstatementtype != ESqlStatementType.sstcreateindex || TBaseType.c_createTableStrictParsing)) {
1036            int nested = 0;
1037            boolean isIgnore = false;
1038            boolean isFoundIgnoreToken = false;
1039            TSourceToken firstIgnoreToken = null;
1040            for (int k = 0; k < stmt.sourcetokenlist.size(); ++k) {
1041                TSourceToken st = stmt.sourcetokenlist.get(k);
1042                if (isIgnore) {
1043                    if (st.issolidtoken() && st.tokencode != 59) {
1044                        isFoundIgnoreToken = true;
1045                        if (firstIgnoreToken == null) {
1046                            firstIgnoreToken = st;
1047                        }
1048                    }
1049                    if (st.tokencode == 59) continue;
1050                    st.tokencode = 273;
1051                    continue;
1052                }
1053                if (st.tokencode == 41 && --nested == 0) {
1054                    isIgnore = true;
1055                }
1056                if (st.tokencode != 40) continue;
1057                ++nested;
1058            }
1059            if (isFoundIgnoreToken) {
1060                stmt.parsestatement(null, false, this.parserContext.isOnlyNeedRawParseTree());
1061            }
1062        }
1063    }
1064
1065    @Override
1066    protected void performSemanticAnalysis(ParserContext context, TStatementList statements) {
1067        if (!TBaseType.isEnableResolver()) {
1068            return;
1069        }
1070        if (!this.getSyntaxErrors().isEmpty()) {
1071            return;
1072        }
1073        TSQLResolver resolver = new TSQLResolver(this.globalContext, statements);
1074        resolver.resolve();
1075    }
1076
1077    @Override
1078    protected void performInterpreter(ParserContext context, TStatementList statements) {
1079    }
1080
1081    @Override
1082    public String toString() {
1083        return "TeradataSqlParser{vendor=" + (Object)((Object)this.vendor) + "}";
1084    }
1085}