001package gudusoft.gsqlparser;
002
003import gudusoft.gsqlparser.compiler.TASTEvaluator;
004import gudusoft.gsqlparser.compiler.TContext;
005import gudusoft.gsqlparser.compiler.TGlobalScope;
006import gudusoft.gsqlparser.compiler.TFrame;
007import gudusoft.gsqlparser.nodes.*;
008import gudusoft.gsqlparser.nodes.teradata.TTeradataHelper;
009import gudusoft.gsqlparser.resolver.*;
010import gudusoft.gsqlparser.resolver2.TSQLResolver2;
011import gudusoft.gsqlparser.resolver2.TSQLResolverConfig;
012import gudusoft.gsqlparser.sqlcmds.ISqlCmds;
013import gudusoft.gsqlparser.sqlcmds.SqlCmdsFactory;
014import gudusoft.gsqlparser.sqlenv.TSQLEnv;
015import gudusoft.gsqlparser.stmt.*;
016import gudusoft.gsqlparser.stmt.dax.TDaxEvaluateStmt;
017import gudusoft.gsqlparser.stmt.dax.TDaxExprStmt;
018import gudusoft.gsqlparser.stmt.greenplum.TSlashCommand;
019import gudusoft.gsqlparser.stmt.mssql.TMssqlBlock;
020import gudusoft.gsqlparser.stmt.mssql.TMssqlCreateProcedure;
021import gudusoft.gsqlparser.stmt.mssql.TMssqlExecute;
022import gudusoft.gsqlparser.stmt.mysql.TMySQLSource;
023import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreatePackage;
024import gudusoft.gsqlparser.stmt.oracle.TSqlplusCmdStatement;
025import gudusoft.gsqlparser.stmt.snowflake.TCreateTaskStmt;
026import gudusoft.gsqlparser.stmt.teradata.TTeradataBTEQCmd;
027import gudusoft.gsqlparser.stmt.teradata.TTeradataFastExportCmd;
028import gudusoft.gsqlparser.stmt.teradata.TTeradataFastLoadCmd;
029import gudusoft.gsqlparser.stmt.teradata.TTeradataMultiLoadCmd;
030import gudusoft.gsqlparser.stmt.teradata.utilities.BteqCmdType;
031import gudusoft.gsqlparser.stmt.teradata.utilities.TeradataUtilityType;
032import gudusoft.gsqlparser.util.TSnowflakeParameterChecker;
033import gudusoft.gsqlparser.parser.SqlParser;
034import gudusoft.gsqlparser.parser.ParserContext;
035import gudusoft.gsqlparser.parser.SqlParseResult;
036import gudusoft.gsqlparser.parser.AbstractSqlParser;
037
038
039import java.io.*;
040import java.nio.charset.Charset;
041import java.security.MessageDigest;
042import java.security.NoSuchAlgorithmException;
043import java.text.DateFormat;
044import java.text.ParseException;
045import java.util.*;
046
047import static gudusoft.gsqlparser.ESqlStatementType.*;
048
049
050/**
051 * This is the first class people start to use this SQL parser library.
052 * This class includes a lexer and a parser. The lexer is used to tokenize the input SQL, turn the input SQL text
053 * into a list of source tokens. The parser use this list source token as input, using the grammar rule of the specified
054 * database vendor to check the syntax of the input SQL and build the parse tree of this SQL if there is no syntax error
055 * in the input SQL.
056 * <p></p>
057 * Creating a SQL parser by specifing {@link gudusoft.gsqlparser.EDbObjectType a database vendor},
058 * then set SQL script text via {@link #setSqltext} method or reading the input SQL from a file via
059 * {@link #setSqlfilename} method.
060 * <p></p>
061 * After that, call one of the following methods to achieve what you need:
062 * <ul>
063 *  <li>{@link #tokenizeSqltext}, turns the input SQL into a sequence of token which is the
064 *  basic lexis element of SQL syntax. Token is categorized as keyword, identifier,
065 *  number, operator, whitespace and other types. All source tokens can be fetched
066 *  via the {@link #getSourcetokenlist()} method</li>
067 *
068 *  <li>{@link #getrawsqlstatements}, separates the SQL statements in the input SQL script without
069 *  doing syntax check, use the {@link #getSqlstatements()} method to get a list of SQL statements
070 *  which is the sub-class of {@link TCustomSqlStatement}, get SQL statement type
071 *  via the {@link TCustomSqlStatement#sqlstatementtype} field, and string representation of
072 *  each SQL statement via the {@link TCustomSqlStatement#toString} method. All source tokens in this SQL statement
073 *  is available by using {@link TCustomSqlStatement#sourcetokenlist} filed.
074 *  Since no parse tree is built by calling this method, no further detailed information about the SQL statement is available.
075 *  </li>
076 *
077 *  <li>{@link #parse}, Check syntax of the input SQL, doing some kind of semantic analysis without connecting to
078 *  a real database.
079 *  This method will do a in-depth analysis of the input SQL such as building the link between table and columns.
080 *  The parse tree of the input SQL is available after calling this method.
081 *  </li>
082 *  </ul>
083 *
084 *  The parser checks the syntax of those SQL statements one by one. If syntax error is found in a SQL statement,
085 *  an error will be logged, no parse tree will be built for this SQL statement,
086 *  the error message can be fetched using the {@link #getErrormessage()} method.
087 *  <p></p>
088 *  The syntax error in one SQL statement doesn't prevent the parser continue to check the syntax of the next SQL statement.
089 *  After checking syntax of all SQL statements, use the {@link #getErrorCount()} method to get the total number of errors.
090 *  <p></p>
091 *  A syntax error in a SQL stored procedure will cease this parser to check syntax of the rest SQL statements
092 *  in this stored procedure.
093 *
094 * <p>Format SQL script can be done after calling {@link #parse()}.
095 * <code>
096 *
097 *      int ret = sqlparser.parse();
098 *       if (ret == 0){
099 *           GFmtOpt option = GFmtOptFactory.newInstance();
100 *           String result = FormatterFactory.pp(sqlparser, option);
101 *           System.out.println(result);
102 *       }else{
103 *           System.out.println(sqlparser.getErrormessage());
104 *       }
105 *
106 * </code>
107 *
108 * <p> After paring SQL script, all parse tree nodes are available for use, some of use cases
109 * are:
110 * <ul>
111 *     <li>Table/column impact analysis</li>
112 *     <li>SQL rewriting</li>
113 *     <li>SQL translate between different databases</li>
114 *     <li>SQL migration analysis</li>
115 *     <li>Help to anti SQL injection</li>
116 *     <li><a href="http://support.sqlparser.com/">More use cases</a></li>
117 *     </ul>
118 *
119 * <p>Typically, SQL parse tree nodes generated by this SQL Parser were closely related to SQL
120 * elements defined in database vendor's SQL reference book. here is a brief summary of some
121 * most used SQL elements and corresponding classes defined in this SQL parser.
122 * <ul>
123 *     <li>SQL identifier: {@link gudusoft.gsqlparser.nodes.TObjectName}</li>
124 *     <li>SQL literal: {@link gudusoft.gsqlparser.nodes.TConstant}</li>
125 *     <li>SQL datatype: {@link gudusoft.gsqlparser.nodes.TTypeName}</li>
126 *     <li>SQL function: {@link gudusoft.gsqlparser.nodes.TFunctionCall}</li>
127 *     <li>SQL constraint: {@link gudusoft.gsqlparser.nodes.TConstraint}</li>
128 *     <li>SQL expression/condition: {@link gudusoft.gsqlparser.nodes.TExpression}</li>
129 *     <li>SQL select list item: {@link gudusoft.gsqlparser.nodes.TResultColumn}</li>
130 *      <li>More: {@link gudusoft.gsqlparser.nodes}</li>
131 * </ul>
132 *
133 * <p> Some major SQL statements:
134 * <ul>
135 *      <li>Select: {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement}</li>
136 *      <li>Delete: {@link gudusoft.gsqlparser.stmt.TDeleteSqlStatement}</li>
137 *      <li>Insert: {@link gudusoft.gsqlparser.stmt.TInsertSqlStatement}</li>
138 *      <li>Update: {@link gudusoft.gsqlparser.stmt.TUpdateSqlStatement}</li>
139 *      <li>Create table: {@link gudusoft.gsqlparser.stmt.TCreateTableSqlStatement}</li>
140 *      <li>More: {@link   gudusoft.gsqlparser.stmt}</li>
141 * </ul>
142 *
143 * <p>Stored procedure</p>
144 * <ul>
145 *     <li>Create function: {@link gudusoft.gsqlparser.stmt.db2.TDb2CreateFunction },
146 *          {@link gudusoft.gsqlparser.stmt.mssql.TMssqlCreateProcedure},
147 *          {@link gudusoft.gsqlparser.stmt.mysql.TMySQLCreateFunction},
148 *          {@link gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateFunction}</li>
149 *     <li>Create procedure: {@link gudusoft.gsqlparser.stmt.db2.TDb2CreateProcedure},
150 *          {@link gudusoft.gsqlparser.stmt.mssql.TMssqlCreateProcedure},
151 *          {@link gudusoft.gsqlparser.stmt.mysql.TMySQLCreateProcedure},
152 *          {@link gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateProcedure}</li>
153 *     <li>Create trigger: {@link gudusoft.gsqlparser.stmt.TCreateTriggerStmt},
154 *          {@link gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateTrigger}</li>
155 *     <li>Create package: {@link gudusoft.gsqlparser.stmt.oracle.TPlsqlCreatePackage}</li>
156 * </ul>
157 *
158 * For all available SQL parse tree node classes, please check the API reference.
159 *
160 *
161 */
162public class TGSqlParser {
163
164
165
166
167    public void setSqlCharset(String sqlCharset) {
168        this.sqlCharset = sqlCharset;
169    }
170
171    public String getSqlCharset() {
172        return sqlCharset;
173    }
174
175    private String sqlCharset = null;
176
177    public static EDbVendor currentDBVendor = EDbVendor.dbvoracle;
178
179
180    /**
181     * Turn the string name of database to dbvendor
182     * <ul>
183     *     <li>access: EDbVendor.dbvaccess</li>
184     *     <li>ansi: EDbVendor.dbvansi</li>
185     *     <li>bigquery: EDbVendor.dbvbigquery</li>
186     *     <li>clickhouse: EDbVendor.dbvclickhouse</li>
187     *     <li>couchbase: EDbVendor.dbvcouchbase</li>
188     *     <li>dax: EDbVendor.dbvdax</li>
189     *     <li>db2: EDbVendor.dbvdb2</li>
190     *     <li>firebird: EDbVendor.dbvfirebird</li>
191     *     <li>generic: EDbVendor.dbvgeneric</li>
192     *     <li>greenplum: EDbVendor.dbvgreenplum</li>
193     *     <li>hana: EDbVendor.dbvhana</li>
194     *     <li>hive: EDbVendor.dbvhive</li>
195     *     <li>impala: EDbVendor.dbvimpala</li>
196     *     <li>informix: EDbVendor.dbvinformix</li>
197     *     <li>mdx: EDbVendor.dbvmdx</li>
198     *     <li>mssql or sqlserver: EDbVendor.dbvmssql</li>
199     *     <li>mysql: EDbVendor.dbvmysql</li>
200     *     <li>netezza: EDbVendor.dbvnetezza</li>
201     *     <li>odbc: EDbVendor.dbvodbc</li>
202     *     <li>openedge: EDbVendor.dbvopenedge</li>
203     *     <li>oracle: EDbVendor.dbvoracle</li>
204     *     <li>postgresql or postgres: EDbVendor.dbvpostgresql</li>
205     *     <li>redshift: EDbVendor.dbvredshift</li>
206     *     <li>snowflake: EDbVendor.dbvsnowflake</li>
207     *     <li>sybase: EDbVendor.dbvsybase</li>
208     *     <li>teradata: EDbVendor.dbvteradata</li>
209     *     <li>vertica: EDbVendor.dbvvertica</li>
210     * </ul>
211     * @param dbVendorName
212     * @return dbvendor
213     */
214    public static EDbVendor getDBVendorByName(String dbVendorName){
215        return  EDbVendor.valueOfWithDefault(dbVendorName);
216    }
217
218//    public void  teradataCmds(){
219//       // int cnt = 0;
220//        //((TLexerTeradata)getFlexer()).
221////         for(int i=0;i<TLexerTeradata.bteqCmdList.size();i++){
222////             for(int j=0;j<TLexerTeradata.multiLoadCmdList.size();j++){
223////                 if (TLexerTeradata.bteqCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.multiLoadCmdList.get(j).toString())){
224////                   System.out.println("multiLoad: "+TLexerTeradata.bteqCmdList.get(i).toString());
225////                 }
226////             }
227////             for(int j=0;j<TLexerTeradata.fastExportCmdList.size();j++){
228////                 if (TLexerTeradata.bteqCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.fastExportCmdList.get(j).toString())){
229////                     System.out.println("fastExport: "+TLexerTeradata.bteqCmdList.get(i).toString());
230////                 }
231////             }
232////             for(int j=0;j<TLexerTeradata.fastLoadCmdList.size();j++){
233////                 if (TLexerTeradata.bteqCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.fastLoadCmdList.get(j).toString())){
234////                     System.out.println("FastLoad: "+TLexerTeradata.bteqCmdList.get(i).toString());
235////                 }
236////             }
237////         } //bteqCmdList
238//
239////        for(int i=0;i<TLexerTeradata.fastLoadCmdList.size();i++){
240////            for(int j=0;j<TLexerTeradata.multiLoadCmdList.size();j++){
241////                if (TLexerTeradata.fastLoadCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.multiLoadCmdList.get(j).toString())){
242////                    System.out.println("multiLoad: "+TLexerTeradata.fastLoadCmdList.get(i).toString());
243////                }
244////            }
245////            for(int j=0;j<TLexerTeradata.fastExportCmdList.size();j++){
246////                if (TLexerTeradata.fastLoadCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.fastExportCmdList.get(j).toString())){
247////                    System.out.println("fastExport: "+TLexerTeradata.fastLoadCmdList.get(i).toString());
248////                }
249////            }
250////
251////        }
252//
253//    }
254
255    private Stack<TFrame> frameStack = null;
256
257    public Stack<TFrame> getFrameStack(){
258        if (frameStack == null){
259            frameStack = new Stack<TFrame>();
260        }
261
262        return  frameStack;
263    }
264
265    public void setFrameStack(Stack<TFrame> frameStack) {
266        this.frameStack = frameStack;
267    }
268
269    void closeFileStream(){
270        if (streamFromSqlFile != null) {
271            try {
272                streamFromSqlFile.close();
273            } catch (IOException e) {
274                e.printStackTrace();
275            }
276        }
277    }
278
279    FileInputStream streamFromSqlFile = null;
280    InputStreamReader sqlStreamReader = null;
281    /**
282     * A sequence of source tokens created by the lexer after tokenize the input SQL
283     *
284     * @return a sequence of source tokens
285     */
286    public TSourceTokenList getSourcetokenlist() {
287        return sourcetokenlist;
288    }
289
290    /**
291     * A list of SQL statements created by the parser.
292     * If this list is created after calling the {@link #getrawsqlstatements} method, the syntax of each SQL statement
293     * is not checked and the parse tree of each statement is not created. If the {@link #parse} method is called to build
294     * this SQL statement list, then every thing is ready.
295     *
296     * @return a list of SQL statement
297     */
298    public TStatementList getSqlstatements() {
299        return sqlstatements;
300    }
301
302    enum stored_procedure_status {start,is_as,body,bodyend,end, cursor_declare};
303    enum stored_procedure_type {function,procedure,package_spec,package_body, block_with_begin,block_with_declare,
304        create_trigger,create_library,cursor_in_package_spec,others};
305
306    static final int stored_procedure_nested_level = 1024;
307
308    /**
309    ** The input SQL Text.
310    ** If {@link #sqlfilename} is specified, then this field will be ignored.
311    */
312    public String sqltext;
313
314    /**
315     * set the input SQL text, If {@link #sqlfilename} is specified before this method, the parser will using
316     * the SQL text in this field instead of read SQL from {@link #sqlfilename}.
317     *
318     * @param sqltext the input SQL text
319     */
320    public void setSqltext(String sqltext) {
321        this.sqltext = sqltext;
322        this.sqlfilename = "";
323        this.sqlInputStream = null;
324    }
325
326    /**
327     *  The SQL text that being processed.
328     *
329     * @return the SQL text that being processed
330     */
331    public String getSqltext() {
332        return sqltext;
333    }
334
335
336    /**
337    ** The input SQL will be read from this file
338     *
339    ** If field is specified, then {@link #sqltext} will be ignored.
340     * This must be the full path to the file, relative path doesn't work.
341    */
342    public String sqlfilename;
343
344
345    /**
346     * set the filename from which the input SQL will be read.
347     *
348     * @param sqlfilename the SQL file name from which the input SQL will be read
349     */
350    public void setSqlfilename(String sqlfilename) {
351        this.sqlfilename = sqlfilename;
352        this.sqltext = "";
353        this.sqlInputStream = null;
354    }
355
356    /**
357     * The input SQL filename. This parser can process the unicode encoded SQL file.
358     *
359     * @return the input SQL filename
360     */
361    public String getSqlfilename() {
362        return sqlfilename;
363    }
364
365    /**
366     * set the InputStream from which SQL will be read.
367     * If this method is called, {@link #sqlfilename} and {@link #sqltext} will be ignored.
368     *
369     * @param sqlInputStream the InputStream from which SQL will be read
370     */
371    public void setSqlInputStream(InputStream sqlInputStream) {
372        if (sqlInputStream instanceof BufferedInputStream){
373            this.sqlInputStream = (BufferedInputStream)sqlInputStream;
374        }else{
375            this.sqlInputStream = new BufferedInputStream(sqlInputStream);
376        }
377
378        this.sqlfilename = "";
379        this.sqltext = "";
380    }
381
382    private BufferedInputStream  sqlInputStream;
383
384    /**
385     *  the InputStream from which SQL will be read
386     * @return the InputStream from which SQL will be read
387     */
388    public InputStream getSqlInputStream() {
389        return sqlInputStream;
390    }
391
392    /**
393    ** Tokens generated by lexer from the input SQL script.
394     * Tokens are always available even if there are syntax errors in input the SQL script.
395    */
396    public TSourceTokenList sourcetokenlist;
397
398    /**
399    ** SQL statements generated by this parser from the input SQL script.
400     * statements are always available even if there are syntax errors in input SQL script.
401     * if there is no syntax error in a statement, you can access the parse tree of the statement to fetch more information
402     * such as tables, columns, etc.
403    */
404    public TStatementList sqlstatements;
405
406    /**
407     * The TSQLResolver2 instance used for name resolution when ENABLE_RESOLVER2 is set.
408     * Unlike TSQLResolver which is created as a local variable, TSQLResolver2 is stored
409     * as a property so users can retrieve name resolution results after parsing.
410     *
411     * Usage:
412     * <pre>
413     * TBaseType.setEnableResolver(false);  // Disable old resolver
414     * TBaseType.setEnableResolver2(true);  // Enable new resolver
415     *
416     * TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle);
417     * parser.sqltext = sqlContent;
418     * int ret = parser.parse();
419     *
420     * // Access resolver2 results
421     * TSQLResolver2 resolver2 = parser.getResolver2();
422     * if (resolver2 != null) {
423     *     // Use TSQLResolver2ResultFormatter to generate output
424     *     TSQLResolver2ResultFormatter formatter = new TSQLResolver2ResultFormatter(resolver2, config);
425     *     String result = formatter.format();
426     * }
427     * </pre>
428     */
429    private TSQLResolver2 resolver2;
430
431    /**
432     * Get the TSQLResolver2 instance used for name resolution.
433     * Returns null if resolver2 was not used or if parsing failed.
434     *
435     * @return the TSQLResolver2 instance or null
436     */
437    public TSQLResolver2 getResolver2() {
438        return resolver2;
439    }
440
441    /**
442     * The resolver type to use for name resolution.
443     * Default is EResolverType.DEFAULT which uses TBaseType settings.
444     */
445    private EResolverType resolverType = EResolverType.DEFAULT;
446
447    /**
448     * Get the resolver type used for name resolution.
449     *
450     * @return the resolver type
451     */
452    public EResolverType getResolverType() {
453        return resolverType;
454    }
455
456    /**
457     * Set the resolver type to use for name resolution.
458     *
459     * <p>This instance-level setting takes precedence over global TBaseType settings.
460     * When set to DEFAULT (the default value), behavior is determined by
461     * TBaseType.isEnableResolver() and TBaseType.isEnableResolver2().</p>
462     *
463     * <h3>Usage Example:</h3>
464     * <pre>
465     * TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle);
466     * parser.setResolverType(EResolverType.RESOLVER2);  // Use new resolver
467     * parser.sqltext = "SELECT * FROM employees";
468     * parser.parse();
469     *
470     * // Access resolver2 results
471     * TSQLResolver2 resolver = parser.getResolver2();
472     * </pre>
473     *
474     * @param resolverType the resolver type to use
475     * @see EResolverType
476     */
477    public void setResolverType(EResolverType resolverType) {
478        this.resolverType = resolverType != null ? resolverType : EResolverType.DEFAULT;
479    }
480
481    /**
482     * Optional configuration for TSQLResolver2.
483     * If null, a default configuration will be created during parsing.
484     */
485    private TSQLResolverConfig resolver2Config;
486
487    /**
488     * Get the TSQLResolverConfig used for resolver2.
489     * Returns null if not explicitly set (default config will be used during parsing).
490     *
491     * @return the resolver2 config or null
492     */
493    public TSQLResolverConfig getResolver2Config() {
494        return resolver2Config;
495    }
496
497    /**
498     * Set the TSQLResolverConfig to use for resolver2.
499     *
500     * <p>This allows customizing resolver2 behavior such as:</p>
501     * <ul>
502     *   <li>guessColumnStrategy - how to handle ambiguous columns</li>
503     *   <li>legacyCompatibilityEnabled - sync results to legacy structures</li>
504     *   <li>maxIterations - maximum iterations for iterative resolution</li>
505     * </ul>
506     *
507     * <p>If not set, a default configuration will be created during parsing
508     * with the database vendor automatically set.</p>
509     *
510     * <h3>Usage Example:</h3>
511     * <pre>
512     * TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle);
513     * parser.setResolverType(EResolverType.RESOLVER2);
514     *
515     * // Configure resolver2 to not pick ambiguous columns
516     * TSQLResolverConfig config = new TSQLResolverConfig();
517     * config.setGuessColumnStrategy(TSQLResolverConfig.GUESS_COLUMN_STRATEGY_NOT_PICKUP);
518     * parser.setResolver2Config(config);
519     *
520     * parser.sqltext = "SELECT id FROM users, orders";
521     * parser.parse();
522     * </pre>
523     *
524     * @param config the resolver2 configuration, or null for default
525     * @see TSQLResolverConfig
526     */
527    public void setResolver2Config(TSQLResolverConfig config) {
528        this.resolver2Config = config;
529    }
530
531    /**
532     * The array of syntax error generated by the parser during checking the syntax of the input SQL,
533     * element of this list is type of {@link TSyntaxError}
534     *
535     * @return the array of errors
536     */
537    public ArrayList <TSyntaxError> getSyntaxErrors() {
538        return syntaxErrors;
539    }
540
541    private ArrayList <TSyntaxError> syntaxErrors;
542
543//    public ArrayList<TSyntaxError> getSyntaxHints() {
544//        return syntaxHints;
545//    }
546
547    //private ArrayList <TSyntaxError> syntaxHints;
548
549    /**
550     * The database vendor specified when creating this parser.
551     * The grammar rule of this database vendor will be used to validate the syntax of the input SQL.
552     *
553     * @return the database vendor
554     */
555    public EDbVendor getDbVendor() {
556        return dbVendor;
557    }
558
559    /**
560     * @deprecated As of v1.4.3.4
561     * enable GSP to parse the rest of sql statements inside stored procedure
562     * when a SQL statement in the stored procedure cannot be parsed
563     *
564     * <p>Available to parse sybase stored procedure currently.
565     *
566     * @param enablePartialParsing set true to enable this partial parsing, default is false
567     */
568    public void setEnablePartialParsing(boolean enablePartialParsing) {
569        this.enablePartialParsing = enablePartialParsing;
570    }
571
572    /**
573     * enable GSP to parse the rest of sql statements inside stored procedure
574     * when a SQL statement in the stored procedure cannot be parsed
575     *
576     * <p>Available to parse sybase stored procedure currently.
577     *
578     * <p> default is false;
579     *
580     *  @deprecated As of v1.4.3.4
581     */
582    private boolean isEnablePartialParsing() {
583
584        return enablePartialParsing;
585    }
586
587    private boolean enablePartialParsing = false;
588
589    private boolean isSinglePLBlock = false;
590
591    public void setSinglePLBlock(boolean singlePLBlock) {
592        isSinglePLBlock = singlePLBlock;
593    }
594
595    private static String userName;
596    private static String machineId = null;
597    private static String licenseKey;
598    private static String licenseType;
599    private static boolean licenseOK = false;
600    private static String licenseMessage;
601
602    /**
603     * Not used.
604     *
605     * @return the user name
606     */
607    public static String getUserName() {
608        return userName;
609    }
610
611    /**
612     * Not used.
613     *
614     * @return the machine id
615     */
616    public static String getMachineId() {
617
618        return machineId;
619    }
620
621    /**
622     * Not used.
623     *
624     * @return the license message
625     */
626    public static String getLicenseMessage() {
627        return licenseMessage;
628    }
629
630
631    static {
632        licenseOK = validateLicense();
633    }
634
635    /**
636     * Not used.
637     *
638     * @return trial license or developer license or distribution license
639     */
640    public static String getLicenseType() {
641        return licenseType;
642    }
643
644    private EDbVendor dbVendor;
645    private String errormessage;
646
647    /**
648     * The lexer which is used to tokenize the input SQL.
649     * For delegated vendors (MSSQL), lazily creates the vendor parser to get its lexer.
650     *
651     * @return the lexer
652     */
653    public TCustomLexer getFlexer() {
654        if (flexer == null) {
655            // Lazily create vendor parser to get its lexer
656            SqlParser vp = getOrCreateVendorParser();
657            if (vp instanceof gudusoft.gsqlparser.parser.MssqlSqlParser) {
658                // Cache the flexer from vendor parser
659                flexer = ((gudusoft.gsqlparser.parser.MssqlSqlParser) vp).flexer;
660            } else if (vp instanceof gudusoft.gsqlparser.parser.MySqlSqlParser) {
661                // Cache the flexer from vendor parser
662                flexer = ((gudusoft.gsqlparser.parser.MySqlSqlParser) vp).flexer;
663            } else if (vp instanceof gudusoft.gsqlparser.parser.PostgreSqlParser) {
664                // Cache the flexer from vendor parser
665                flexer = ((gudusoft.gsqlparser.parser.PostgreSqlParser) vp).flexer;
666            } else if (vp instanceof gudusoft.gsqlparser.parser.OracleSqlParser) {
667                // Cache the flexer from vendor parser
668                flexer = ((gudusoft.gsqlparser.parser.OracleSqlParser) vp).flexer;
669            } else if (vp instanceof gudusoft.gsqlparser.parser.BigQuerySqlParser) {
670                // Cache the flexer from vendor parser
671                flexer = ((gudusoft.gsqlparser.parser.BigQuerySqlParser) vp).flexer;
672            } else if (vp instanceof gudusoft.gsqlparser.parser.AthenaSqlParser) {
673                // Cache the flexer from vendor parser
674                flexer = ((gudusoft.gsqlparser.parser.AthenaSqlParser) vp).flexer;
675            } else if (vp instanceof gudusoft.gsqlparser.parser.CouchbaseSqlParser) {
676                // Cache the flexer from vendor parser
677                flexer = ((gudusoft.gsqlparser.parser.CouchbaseSqlParser) vp).flexer;
678            } else if (vp instanceof gudusoft.gsqlparser.parser.DatabricksSqlParser) {
679                // Cache the flexer from vendor parser
680                flexer = ((gudusoft.gsqlparser.parser.DatabricksSqlParser) vp).flexer;
681            } else if (vp instanceof gudusoft.gsqlparser.parser.DaxSqlParser) {
682                // Cache the flexer from vendor parser
683                flexer = ((gudusoft.gsqlparser.parser.DaxSqlParser) vp).flexer;
684            } else if (vp instanceof gudusoft.gsqlparser.parser.Db2SqlParser) {
685                // Cache the flexer from vendor parser
686                flexer = ((gudusoft.gsqlparser.parser.Db2SqlParser) vp).flexer;
687            } else if (vp instanceof gudusoft.gsqlparser.parser.GaussDbSqlParser) {
688                // Cache the flexer from vendor parser
689                flexer = ((gudusoft.gsqlparser.parser.GaussDbSqlParser) vp).flexer;
690            } else if (vp instanceof gudusoft.gsqlparser.parser.GreenplumSqlParser) {
691                // Cache the flexer from vendor parser
692                flexer = ((gudusoft.gsqlparser.parser.GreenplumSqlParser) vp).flexer;
693            } else if (vp instanceof gudusoft.gsqlparser.parser.HiveSqlParser) {
694                // Cache the flexer from vendor parser
695                flexer = ((gudusoft.gsqlparser.parser.HiveSqlParser) vp).flexer;
696            } else if (vp instanceof gudusoft.gsqlparser.parser.HanaSqlParser) {
697                // Cache the flexer from vendor parser
698                flexer = ((gudusoft.gsqlparser.parser.HanaSqlParser) vp).flexer;
699            } else if (vp instanceof gudusoft.gsqlparser.parser.ImpalaSqlParser) {
700                // Cache the flexer from vendor parser
701                flexer = ((gudusoft.gsqlparser.parser.ImpalaSqlParser) vp).flexer;
702            } else if (vp instanceof gudusoft.gsqlparser.parser.InformixSqlParser) {
703                // Cache the flexer from vendor parser
704                flexer = ((gudusoft.gsqlparser.parser.InformixSqlParser) vp).flexer;
705            } else if (vp instanceof gudusoft.gsqlparser.parser.MdxSqlParser) {
706                // Cache the flexer from vendor parser
707                flexer = ((gudusoft.gsqlparser.parser.MdxSqlParser) vp).flexer;
708            } else if (vp instanceof gudusoft.gsqlparser.parser.NetezzaSqlParser) {
709                // Cache the flexer from vendor parser
710                flexer = ((gudusoft.gsqlparser.parser.NetezzaSqlParser) vp).flexer;
711            } else if (vp instanceof gudusoft.gsqlparser.parser.OdbcSqlParser) {
712                // Cache the flexer from vendor parser
713                flexer = ((gudusoft.gsqlparser.parser.OdbcSqlParser) vp).flexer;
714            } else if (vp instanceof gudusoft.gsqlparser.parser.OpenEdgeSqlParser) {
715                // Cache the flexer from vendor parser
716                flexer = ((gudusoft.gsqlparser.parser.OpenEdgeSqlParser) vp).flexer;
717            } else if (vp instanceof gudusoft.gsqlparser.parser.PrestoSqlParser) {
718                // Cache the flexer from vendor parser
719                flexer = ((gudusoft.gsqlparser.parser.PrestoSqlParser) vp).flexer;
720            } else if (vp instanceof gudusoft.gsqlparser.parser.RedshiftSqlParser) {
721                // Cache the flexer from vendor parser
722                flexer = ((gudusoft.gsqlparser.parser.RedshiftSqlParser) vp).flexer;
723            } else if (vp instanceof gudusoft.gsqlparser.parser.SnowflakeSqlParser) {
724                // Cache the flexer from vendor parser
725                flexer = ((gudusoft.gsqlparser.parser.SnowflakeSqlParser) vp).flexer;
726            } else if (vp instanceof gudusoft.gsqlparser.parser.SoqlSqlParser) {
727                // Cache the flexer from vendor parser
728                flexer = ((gudusoft.gsqlparser.parser.SoqlSqlParser) vp).flexer;
729            } else if (vp instanceof gudusoft.gsqlparser.parser.SparksqlSqlParser) {
730                // Cache the flexer from vendor parser
731                flexer = ((gudusoft.gsqlparser.parser.SparksqlSqlParser) vp).flexer;
732            } else if (vp instanceof gudusoft.gsqlparser.parser.SybaseSqlParser) {
733                // Cache the flexer from vendor parser
734                flexer = ((gudusoft.gsqlparser.parser.SybaseSqlParser) vp).flexer;
735            } else if (vp instanceof gudusoft.gsqlparser.parser.VerticaSqlParser) {
736                // Cache the flexer from vendor parser
737                flexer = ((gudusoft.gsqlparser.parser.VerticaSqlParser) vp).flexer;
738            }
739        }
740        return flexer;
741    }
742
743    private TCustomLexer flexer;
744
745    TCustomParser fparser,fplsqlparser;
746
747    // Cached vendor-specific parser for delegated parsing (MSSQL, etc.)
748    // Created lazily in getFlexer() and reused in parse()
749    private SqlParser vendorParser;
750
751    BufferedReader finputstream = null; //used by lexer
752    TCustomSqlStatement gcurrentsqlstatement,nextStmt;
753    // Vendor-specific SQL command resolver
754    ISqlCmds sqlcmds;
755
756    HashMap sqlpluskeywordList;
757
758    char delimiterchar;
759    String defaultDelimiterStr;
760
761    /**
762     * Returns the delimiter character used to separate SQL statements.
763     * Uses the flexer's delimiter if available (lexer-dependent), otherwise falls back to parser's value.
764     * @return the delimiter character
765     */
766    public char getDelimiterChar() {
767        if (flexer != null) {
768            return flexer.delimiterchar;
769        }
770        return delimiterchar;
771    }
772
773    private ISQLStatementHandle sqlStatementHandle = null;
774
775    public void setSqlStatementHandle(ISQLStatementHandle sqlStatementHandle) {
776        this.sqlStatementHandle = sqlStatementHandle;
777    }
778
779    private ITokenHandle tokenHandle = null;
780
781    /**
782     * Set an event handler which will be fired when a new source token is created by the lexer during tokenize the
783     * input SQL.
784     *
785     * @param tokenHandle the event handler to process the new created source token
786     */
787    public void setTokenHandle(ITokenHandle tokenHandle) {
788        this.tokenHandle = tokenHandle;
789    }
790
791    private ITokenListHandle tokenListHandle = null;
792
793    public void setTokenListHandle(ITokenListHandle tokenListHandle) {
794        this.tokenListHandle = tokenListHandle;
795    }
796
797    private IMetaDatabase metaDatabase = null;
798
799    /**
800     * @deprecated As of v2.0.3.1, please use {@link #getSqlEnv()} instead
801     *
802     *  set an instance of a class which implement the interface: {@link IMetaDatabase}.
803     *  The parser will call {@link IMetaDatabase#checkColumn} method when it needs to know
804     *  whether a column is belonged to a table.
805     *  <p></p>
806     *  The class that implements the interface: {@link IMetaDatabase} usually fetch the metadata from the database
807     *  by connecting to a database instance.
808     *  <p></p>
809     *  If the class is not provided, the parser has to guess the relationship between a un-qualified column and table
810     *  in the input SQL which may lead to a un-determined result between the column and table.
811     *
812     * @param metaDatabase a new instance of the class which implements the {@link IMetaDatabase} interface
813     * @see IMetaDatabase
814     */
815    public void setMetaDatabase(IMetaDatabase metaDatabase) {
816        this.metaDatabase = metaDatabase;
817    }
818
819    /**
820     * @deprecated As of v2.0.3.1, please use {@link #getSqlEnv()} instead
821     *
822     * a new instance of the class which implements the {@link IMetaDatabase} interface
823     *
824     * @return a new instance of the class which implements the {@link IMetaDatabase} interface
825     * @see #setMetaDatabase
826     */
827    public IMetaDatabase getMetaDatabase() {
828
829        return metaDatabase;
830    }
831
832    /**
833     * Not used.
834     *
835     */
836    public void freeParseTable() {
837        flexer.yystack = null;
838        flexer.yytextbuf = null;
839        flexer.buf = null;
840
841//        TLexerOracle.yyk = null;
842//        TLexerOracle.yykl = null;
843//        TLexerOracle.yykh = null;
844//        TLexerOracle.yym = null;
845//        TLexerOracle.yyml = null;
846//        TLexerOracle.yymh = null;
847//        TLexerOracle.yyt = null;
848//        TLexerOracle.yytl = null;
849//        TLexerOracle.yyth = null;
850//        TParserOracleSql.yyah = null;
851//        TParserOracleSql.yyal = null;
852//        TParserOracleSql.yygh = null;
853//        TParserOracleSql.yygl = null;
854//        TParserOracleSql.yyd = null;
855//        TParserOracleSql.yya_sym= null;
856//        TParserOracleSql.yya_act= null;
857//        TParserOracleSql.yyr_len= null;
858//        TParserOracleSql.yyr_sym= null;
859//        TParserOracleSql.yyg_sym= null;
860//        TParserOracleSql.yyg_act= null;
861//
862//        TParserOraclePLSql.yyah = null;
863//        TParserOraclePLSql.yyal = null;
864//        TParserOraclePLSql.yygh = null;
865//        TParserOraclePLSql.yygl = null;
866//        TParserOraclePLSql.yyd = null;
867//        TParserOraclePLSql.yya_sym= null;
868//        TParserOraclePLSql.yya_act= null;
869//        TParserOraclePLSql.yyr_len= null;
870//        TParserOraclePLSql.yyr_sym= null;
871//        TParserOraclePLSql.yyg_sym= null;
872//        TParserOraclePLSql.yyg_act= null;
873//
874//        TLexerMssql.yyk = null;
875//        TLexerMssql.yykl = null;
876//        TLexerMssql.yykh = null;
877//        TLexerMssql.yym = null;
878//        TLexerMssql.yyml = null;
879//        TLexerMssql.yymh = null;
880//        TLexerMssql.yyt = null;
881//        TLexerMssql.yytl = null;
882//        TLexerMssql.yyth = null;
883//        TParserMssqlSql.yyah = null;
884//        TParserMssqlSql.yyal = null;
885//        TParserMssqlSql.yygh = null;
886//        TParserMssqlSql.yygl = null;
887//        TParserMssqlSql.yyd = null;
888//        TParserMssqlSql.yya_sym= null;
889//        TParserMssqlSql.yya_act= null;
890//        TParserMssqlSql.yyr_len= null;
891//        TParserMssqlSql.yyr_sym= null;
892//        TParserMssqlSql.yyg_sym= null;
893//        TParserMssqlSql.yyg_act= null;
894//
895//        TLexerMysql.yyk = null;
896//        TLexerMysql.yykl = null;
897//        TLexerMysql.yykh = null;
898//        TLexerMysql.yym = null;
899//        TLexerMysql.yyml = null;
900//        TLexerMysql.yymh = null;
901//        TLexerMysql.yyt = null;
902//        TLexerMysql.yytl = null;
903//        TLexerMysql.yyth = null;
904//        TParserMysqlSql.yyah = null;
905//        TParserMysqlSql.yyal = null;
906//        TParserMysqlSql.yygh = null;
907//        TParserMysqlSql.yygl = null;
908//        TParserMysqlSql.yyd = null;
909//        TParserMysqlSql.yya_sym= null;
910//        TParserMysqlSql.yya_act= null;
911//        TParserMysqlSql.yyr_len= null;
912//        TParserMysqlSql.yyr_sym= null;
913//        TParserMysqlSql.yyg_sym= null;
914//        TParserMysqlSql.yyg_act= null;
915    }
916
917    /**
918     *  Class constructor, create a new instance of the parser by setting the database vendor
919     *
920     * @param pdbvendor the database vendor whose grammar rule will be used to validate the syntax of the input SQL
921     */
922    public TGSqlParser(EDbVendor pdbvendor) {
923        dbVendor = pdbvendor;
924        sqltext = "";
925        sqlfilename = "";
926
927        delimiterchar = ';';
928        defaultDelimiterStr = ";";
929        switch(pdbvendor){
930            case dbvmssql:
931            case dbvazuresql:
932                // MSSQL and Azure SQL are delegated to MssqlSqlParser for tokenization
933                // - flexer is accessed via getFlexer() which lazily creates MssqlSqlParser
934                // - fparser is set in doDelegatedRawParse() from vendor parser result
935                if (pdbvendor == EDbVendor.dbvazuresql) {
936                    dbVendor = EDbVendor.dbvmssql;
937                }
938                break;
939            case dbvaccess:
940                // Access uses MSSQL lexer/parser but is NOT delegated
941                if (TBaseType.enterprise_edition || (!TBaseType.full_edition) || TBaseType.sqlserver_edition || TBaseType.azuresql_edition) {
942                    flexer = new TLexerMssql();
943                    flexer.delimiterchar = delimiterchar;
944                    flexer.defaultDelimiterStr = defaultDelimiterStr;
945                    fparser = new TParserMssqlSql(null);
946                    fparser.lexer = flexer;
947                }
948                break;
949            case dbvsybase:{
950                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.sybase_edition){
951                    flexer = new TLexerSybase();
952                    flexer.delimiterchar = delimiterchar;
953                    flexer.defaultDelimiterStr = defaultDelimiterStr;
954                    fparser = new TParserSybase(null);
955                    fparser.lexer = flexer;
956                }
957                enablePartialParsing = false;
958                break;
959            }
960            case dbvinformix:{
961                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.informix_edition){
962                    flexer = new TLexerInformix();
963                    flexer.delimiterchar = delimiterchar;
964                    flexer.defaultDelimiterStr = defaultDelimiterStr;
965                    fparser = new TParserInformix(null);
966                    fparser.lexer = flexer;
967                }
968                enablePartialParsing = false;
969                break;
970            }
971            case dbvoracle:
972                // Oracle is delegated to OracleSqlParser for tokenization and parsing
973                // - flexer is accessed via getFlexer() which lazily creates OracleSqlParser
974                // - fparser and fplsqlparser are set in doDelegatedRawParse() from vendor parser result
975                delimiterchar = '/';
976                break;
977            case dbvdb2 :{
978                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.db2_edition){
979                    delimiterchar = '@';
980                    flexer = new TLexerDb2();
981                    flexer.delimiterchar = delimiterchar;
982                    flexer.defaultDelimiterStr = defaultDelimiterStr;
983                    fparser = new TParserDb2Sql(null);
984                    fparser.lexer = flexer;
985                }
986                break;
987            }
988            case dbvmysql :{
989                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.mysql_edition){
990                    delimiterchar = '$';
991                    defaultDelimiterStr = "$";
992                    flexer = new TLexerMysql();
993                    flexer.delimiterchar = delimiterchar;
994                    flexer.defaultDelimiterStr = defaultDelimiterStr;
995                    fparser = new TParserMysqlSql(null);
996                    fparser.lexer = flexer;
997                }
998                break;
999            }
1000            case dbvteradata :{
1001                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.teradata_edition){
1002                    delimiterchar = '/';
1003                    flexer = new TLexerTeradata();
1004                    flexer.delimiterchar = delimiterchar;
1005                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1006                    fparser = new TParserTeradata(null);
1007                    fparser.lexer = flexer;
1008                }
1009                break;
1010            }
1011            case dbvpostgresql:{
1012                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.postgresql_edition){
1013                    delimiterchar = '/';
1014                    flexer = new TLexerPostgresql();
1015                    flexer.delimiterchar = delimiterchar;
1016                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1017                    fparser = new TParserPostgresql(null);
1018                    fparser.lexer = flexer;
1019                }
1020                break;
1021            }
1022            case dbvredshift:{
1023                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.redshift_edition){
1024                    delimiterchar = '/';
1025                    flexer = new TLexerRedshift();
1026                    flexer.delimiterchar = delimiterchar;
1027                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1028                    fparser = new TParserRedshift(null);
1029                    fparser.lexer = flexer;
1030                }
1031                break;
1032            }
1033            case dbvgreenplum:{
1034                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.greenplum_edition){
1035                    delimiterchar = '/';
1036                    flexer = new TLexerGreenplum();
1037                    flexer.delimiterchar = delimiterchar;
1038                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1039                    fparser = new TParserGreenplum(null);
1040                    fparser.lexer = flexer;
1041                }
1042                break;
1043            }
1044            case dbvmdx:{
1045                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.mdx_edition){
1046                    delimiterchar = ';';
1047                    flexer = new TLexerMdx();
1048                    flexer.delimiterchar = delimiterchar;
1049                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1050                    fparser = new TParserMdx(null);
1051                    fparser.lexer = flexer;
1052                }
1053                break;
1054            }
1055            case dbvnetezza:{
1056                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.netezza_edition){
1057                    delimiterchar = ';';
1058                    flexer = new TLexerNetezza();
1059                    flexer.delimiterchar = delimiterchar;
1060                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1061                    fparser = new TParserNetezza(null);
1062                    fparser.lexer = flexer;
1063                }
1064                break;
1065            }
1066            case dbvhive:{
1067                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.hive_edition){
1068                    delimiterchar = ';';
1069                    flexer = new TLexerHive();
1070                    flexer.delimiterchar = delimiterchar;
1071                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1072                    fparser = new TParserHive(null);
1073                    fparser.lexer = flexer;
1074                }
1075                break;
1076            }
1077            case dbvimpala:{
1078                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.impala_edition){
1079                    delimiterchar = ';';
1080                    flexer = new TLexerImpala();
1081                    flexer.delimiterchar = delimiterchar;
1082                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1083                    fparser = new TParserImpala(null);
1084                    fparser.lexer = flexer;
1085                }
1086                break;
1087            }
1088            case dbvhana:{
1089                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.hana_edition){
1090                    delimiterchar = ';';
1091                    flexer = new TLexerHana();
1092                    flexer.delimiterchar = delimiterchar;
1093                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1094                    fparser = new TParserHana(null);
1095                    fparser.lexer = flexer;
1096                }
1097                break;
1098            }
1099            case dbvdax:{
1100                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.dax_edition){
1101                    delimiterchar = ';';
1102                    flexer = new TLexerDax();
1103                    flexer.delimiterchar = delimiterchar;
1104                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1105                    fparser = new TParserDax(null);
1106                    fparser.lexer = flexer;
1107                }
1108                break;
1109            }
1110            case dbvodbc:{
1111                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.odbc_edition){
1112                    delimiterchar = ';';
1113                    flexer = new TLexerOdbc();
1114                    flexer.delimiterchar = delimiterchar;
1115                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1116                    fparser = new TParserOdbc(null);
1117                    fparser.lexer = flexer;
1118                }
1119                break;
1120            }
1121            case dbvvertica:{
1122                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.vertica_edition){
1123                    delimiterchar = ';';
1124                    flexer = new TLexerVertica();
1125                    flexer.delimiterchar = delimiterchar;
1126                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1127                    fparser = new TParserVertica(null);
1128                    fparser.lexer = flexer;
1129                }
1130                break;
1131            }
1132            case dbvopenedge:{
1133                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.openedge_edition){
1134                    delimiterchar = ';';
1135                    flexer = new TLexerOpenedge();
1136                    flexer.delimiterchar = delimiterchar;
1137                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1138                    fparser = new TParserOpenedge(null);
1139                    fparser.lexer = flexer;
1140                }
1141                break;
1142            }
1143            case dbvcouchbase:{
1144                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.couchbase_edition){
1145                    delimiterchar = ';';
1146                    flexer = new TLexerCouchbase();
1147                    flexer.delimiterchar = delimiterchar;
1148                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1149                    fparser = new TParserCouchbase(null);
1150                    fparser.lexer = flexer;
1151                }
1152                break;
1153            }
1154            case dbvsnowflake:{
1155                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.snowflake_edition){
1156                    delimiterchar = ';';
1157                    flexer = new TLexerSnowflake();
1158                    flexer.delimiterchar = delimiterchar;
1159                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1160                    fparser = new TParserSnowflake(null);
1161                    fparser.lexer = flexer;
1162                }
1163                break;
1164            }
1165            case dbvbigquery:{
1166                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.bigquery_edition){
1167                    delimiterchar = ';';
1168                    flexer = new TLexerBigquery();
1169                    flexer.delimiterchar = delimiterchar;
1170                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1171                    fparser = new TParserBigquery(null);
1172                    fparser.lexer = flexer;
1173                }
1174                break;
1175            }
1176            case dbvclickhouse:{
1177                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.clickhouse_edition){
1178                    delimiterchar = '/';
1179                    flexer = new TLexerClickhouse();
1180                    flexer.delimiterchar = delimiterchar;
1181                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1182                    fparser = new TParserClickhouse(null);
1183                    fparser.lexer = flexer;
1184                }
1185                break;
1186            }
1187            case dbvansi:
1188                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.ansi_edition){
1189                    delimiterchar = ';';
1190                    flexer = new TLexerAnsi();
1191                    flexer.delimiterchar = delimiterchar;
1192                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1193                    fparser = new TParserAnsi(null);
1194                    fparser.lexer = flexer;
1195                }
1196                break;
1197            case dbvgeneric: {
1198                if (TBaseType.enterprise_edition || (!TBaseType.full_edition) || TBaseType.generic_edition) {
1199                    flexer = new TLexerMssql();
1200                    flexer.delimiterchar = delimiterchar;
1201                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1202                    fparser = new TParserMssqlSql(null);
1203                    fparser.lexer = flexer;
1204                }
1205                break;
1206            }
1207            case dbvsoql:{
1208                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.soql_edition){
1209                    delimiterchar = ';';
1210                    flexer = new TLexerSoql();
1211                    flexer.delimiterchar = delimiterchar;
1212                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1213                    fparser = new TParserSoql(null);
1214                    fparser.lexer = flexer;
1215                }
1216                break;
1217            }
1218            case dbvsparksql:{
1219                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.sparksql_edition){
1220                    delimiterchar = ';';
1221                    flexer = new TLexerSparksql();
1222                    flexer.delimiterchar = delimiterchar;
1223                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1224                    fparser = new TParserSparksql(null);
1225                    fparser.lexer = flexer;
1226                }
1227                break;
1228            }
1229            case dbvathena:
1230                {
1231                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.athena_edition){
1232                    delimiterchar = ';';
1233                    flexer = new TLexerathena();
1234                    flexer.delimiterchar = delimiterchar;
1235                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1236                    fparser = new TParserAthena(null);
1237                    fparser.lexer = flexer;
1238                }
1239                break;
1240            }
1241            case dbvpresto:
1242            {
1243                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.presto_edition){
1244                    delimiterchar = ';';
1245                    flexer = new TLexerPresto();
1246                    flexer.delimiterchar = delimiterchar;
1247                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1248                    fparser = new TParserPresto(null);
1249                    fparser.lexer = flexer;
1250                }
1251                break;
1252            }
1253            case dbvtrino:
1254            {
1255                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.trino_edition){
1256                    delimiterchar = ';';
1257                    flexer = new TLexerPresto();
1258                    flexer.delimiterchar = delimiterchar;
1259                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1260                    fparser = new TParserPresto(null);
1261                    fparser.lexer = flexer;
1262                }
1263                break;
1264            }
1265            case dbvdatabricks:
1266            {
1267                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.databricks_edition){
1268                    delimiterchar = ';';
1269                    flexer = new TLexerDatabricks();
1270                    flexer.delimiterchar = delimiterchar;
1271                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1272                    fparser = new TParserDatabricks(null);
1273                    fparser.lexer = flexer;
1274                }
1275                break;
1276            }
1277            case dbvgaussdb:
1278            {
1279                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.gaussdb_edition){
1280                    delimiterchar = ';';
1281                    flexer = new TLexerGaussDB();
1282                    flexer.delimiterchar = delimiterchar;
1283                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1284                    fparser = new TParserGaussDB(null);
1285                    fparser.lexer = flexer;
1286                   // fplsqlparser = new TParserOraclePLSql(null);
1287                   // fplsqlparser.lexer = new TLexerOracle();// must use oracle lexer, not gauss lexer
1288                }
1289                break;
1290            }
1291            default:  {
1292                if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.sqlserver_edition){
1293                    flexer = new TLexerMssql();
1294                    flexer.delimiterchar = delimiterchar;
1295                    flexer.defaultDelimiterStr = defaultDelimiterStr;
1296                    fparser = new TParserMssqlSql(null);
1297                    fparser.lexer = flexer;
1298                }
1299                break;
1300            }
1301        }
1302
1303        // For delegated vendors (e.g., MSSQL), fparser may be null here
1304        // It will be set later in doDelegatedRawParse() from vendor parser result
1305        if (fparser != null) {
1306            fparser.getNf().setGsqlParser(this);
1307        }
1308
1309        sourcetokenlist = new TSourceTokenList();
1310        sourcetokenlist.setGsqlparser(this);
1311        sqlstatements = new TStatementList();
1312        // Inject vendor-specific command resolver
1313        sqlcmds = SqlCmdsFactory.get(dbVendor);
1314        if (fparser != null) {
1315            fparser.sqlcmds = sqlcmds;
1316        }
1317        sqlpluskeywordList = new HashMap();
1318        syntaxErrors = new ArrayList();
1319        //syntaxHints = new ArrayList();
1320
1321
1322        errormessage = "";
1323
1324        if (TBaseType.license_expired_check){
1325            if (!check_license_time()) {
1326                flexer = null;
1327                fparser = null;
1328               // System.out.println("license is expired");
1329            }
1330        }
1331
1332        TGSqlParser.currentDBVendor = dbVendor;
1333    }
1334
1335    TContext globalContext;
1336
1337
1338    /**
1339     * Create a select statement object from the parameter: subquery
1340     *
1341     * @param subquery a plain text select statement which need to be converted to a {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement} object
1342     * @return a select statement object, return null if the input select string is syntax invalid.
1343     */
1344    public TSelectSqlStatement parseSubquery(String subquery){
1345        return parseSubquery(this.dbVendor,subquery);
1346    }
1347
1348    /**
1349     * this method is thread safe.
1350     * 
1351     * C:\prg\gsp_java\gsp_java_core\src\test\java\gudusoft\gsqlparser\ParseSubqueryThreadSafetyTest.java
1352     * 
1353     */
1354    public static TSelectSqlStatement parseSubquery(EDbVendor dbVendor, String subquery){
1355//        TGSqlParser localParser = new TGSqlParser(dbVendor);
1356//        localParser.sqltext = subquery;
1357//        int iRet = localParser.doparse();
1358//        if (iRet != 0) {
1359//            return null;
1360//        }
1361
1362        TSingletonParser singletonParser = TSingletonParser.getInstance();
1363        TStatementList statements = singletonParser.getStmts(dbVendor,subquery);
1364        if (statements.size() == 0) return null;
1365
1366        return (TSelectSqlStatement)statements.get(0);
1367    }
1368
1369    /**
1370     * Create an expression object from the parameter: expr
1371     *
1372     * @param expr a plain text expression which will be converted to {@link gudusoft.gsqlparser.nodes.TExpression} object
1373     * @return an expression object, return null if the input expression string is not syntax valid.
1374     */
1375    public TExpression parseExpression(String expr){
1376        return parseExpression(this.dbVendor,expr);
1377    }
1378
1379    /*
1380     * this method is thread safe.
1381     * 
1382     * getStmts() is synchronized - only one thread can execute it at a time
1383     * getParser() is also synchronized
1384     * Each thread gets a new TStatementList instance
1385
1386     * this is the test case for this method.
1387     * C:\prg\gsp_java\gsp_java_core\src\test\java\gudusoft\gsqlparser\ParseExpressionThreadSafetyTest.java
1388     */
1389    public static TExpression parseExpression(EDbVendor dbVendor, String expr){
1390        TSingletonParser singletonParser = TSingletonParser.getInstance();
1391
1392        boolean e = TBaseType.isEnableResolver();
1393        TBaseType.setEnableResolver(false);
1394        TStatementList statements;
1395        try{
1396            statements  = singletonParser.getStmts(dbVendor,"select 1 from t where "+TBaseType.newline+expr);
1397        }finally {
1398            TBaseType.setEnableResolver(e);
1399        }
1400
1401        if (statements.size() == 0) return null;
1402
1403//        TGSqlParser localParser = new TGSqlParser(dbVendor);
1404//        localParser.sqltext = "select 1 from t where "+TBaseType.newline+expr;
1405//        int iRet = localParser.doparse();
1406//        if (iRet != 0) {
1407//            return null;
1408//        }
1409
1410        return ((TSelectSqlStatement)statements.get(0)).getWhereClause().getCondition();
1411    }
1412
1413    /**
1414     *  Create a function object from the parameter: newFunction
1415     *
1416     * @param newFunction a plain text function which will be converted to {@link gudusoft.gsqlparser.nodes.TFunctionCall} object
1417     * @return a function object, or return null if the input string is not a valid function call.
1418     */
1419    public TFunctionCall parseFunctionCall(String newFunction){
1420        return parseFunctionCall(this.dbVendor,newFunction);
1421    }
1422
1423    public static TFunctionCall parseFunctionCall(EDbVendor dbVendor, String newFunction){
1424        TSingletonParser singletonParser = TSingletonParser.getInstance();
1425        TStatementList statements = singletonParser.getStmts(dbVendor,"select"+TBaseType.newline+newFunction+TBaseType.newline+"from t");
1426        if (statements.size() == 0) return null;
1427
1428
1429//        TGSqlParser localParser = new TGSqlParser(dbVendor);
1430//        localParser.sqltext = "select"+TBaseType.newline+newFunction+TBaseType.newline+"from t";
1431//        int iRet = localParser.doparse();
1432//        if (iRet!= 0) {
1433//            return null;
1434//        }
1435
1436        return statements.get(0).getResultColumnList().getResultColumn(0).getExpr().getFunctionCall();
1437    }
1438
1439    /**
1440     * Create a database objectName from the parameter: newObjectName
1441     *
1442     * @param newObjectName a plain text objectName which will be converted to {@link gudusoft.gsqlparser.nodes.TObjectName} object
1443     * @return a database objectName object, return null is the input string is not a valid objectName.
1444     */
1445    public TObjectName parseObjectName(String newObjectName){
1446        //return parseObjectName(this.dbVendor,newObjectName);
1447        return TObjectName.createObjectName(this.dbVendor,EDbObjectType.column,newObjectName);
1448    }
1449
1450
1451
1452    /**
1453     *
1454     * @param dbVendor
1455     * @param newObjectName
1456     * @return
1457     */
1458    public static TObjectName parseObjectName(EDbVendor dbVendor, String newObjectName){
1459
1460        TSingletonParser singletonParser = TSingletonParser.getInstance();
1461        TStatementList statements = singletonParser.getStmts(dbVendor,"select"+TBaseType.newline+newObjectName+TBaseType.newline+"from t");
1462        if (statements.size() == 0) return null;
1463        TExpression e = statements.get(0).getResultColumnList().getResultColumn(0).getExpr();
1464
1465//        TGSqlParser localParser = new TGSqlParser(dbVendor);
1466//        localParser.sqltext = "select"+TBaseType.newline+newObjectName+TBaseType.newline+"from t";
1467//        int iRet = localParser.doparse();
1468//        if (iRet!= 0) {
1469//            return null;
1470//        }
1471//        TExpression e = ((TSelectSqlStatement)localParser.sqlstatements.get(0)).getResultColumnList().getResultColumn(0).getExpr();
1472
1473        TObjectName lcResult = null;
1474        switch (e.getExpressionType()){
1475            case simple_object_name_t:
1476                lcResult = e.getObjectOperand();
1477                break;
1478            case simple_constant_t:
1479                lcResult = new TObjectName();
1480                lcResult.init(e.getConstantOperand().getValueToken());
1481                break;
1482            default:
1483                break;
1484        }
1485
1486        return lcResult;
1487    }
1488
1489    /**
1490     * Create an constant object from the parameter: newConstant
1491     *
1492     * @param newConstant a plian text constant which will be converted to {@link gudusoft.gsqlparser.nodes.TConstant} object
1493     * @return new constant object, returns null if the input is not a valid constant string.
1494     */
1495    public TConstant parseConstant(String newConstant){
1496        return parseConstant(this.dbVendor,newConstant);
1497    }
1498
1499    public static TConstant parseConstant(EDbVendor dbVendor, String newConstant){
1500//        TGSqlParser localParser = new TGSqlParser(dbVendor);
1501//        localParser.sqltext = "select"+TBaseType.newline+newConstant+TBaseType.newline+"from t";
1502//        int iRet = localParser.doparse();
1503//        if (iRet!= 0) {
1504//            return null;
1505//        }
1506
1507        TSingletonParser singletonParser = TSingletonParser.getInstance();
1508        TStatementList statements = singletonParser.getStmts(dbVendor,"select"+TBaseType.newline+newConstant+TBaseType.newline+"from t");
1509        if (statements.size() == 0) return null;
1510
1511        return statements.get(0).getResultColumnList().getResultColumn(0).getExpr().getConstantOperand();
1512    }
1513
1514
1515    /**
1516     * The total number of syntax errors founded in the input SQL script.
1517     * <br>Only the first syntax error in a SQL statement is counted if there are more than one syntax errors in
1518     * a single SQL statement.
1519     * <br> In a SQL script, only the first syntax error in each SQL statement is counted.
1520     *
1521     * @return The total number of syntax errors founded in the input SQL script. Returns 0 if no syntax error is founded.
1522     */
1523    public int getErrorCount(){
1524        return   syntaxErrors.size();
1525    }
1526
1527    /**
1528     * The text of error message generated by iterating all items in {@link #getSyntaxErrors}.
1529     * User may generate error message in their own format by iterating all items in {@link #getSyntaxErrors}.
1530     *
1531     * @return error message
1532     */
1533    public String getErrormessage(){
1534
1535        String s="",hint="Syntax error";
1536        TSyntaxError t;
1537        for (int i= 0; i< syntaxErrors.size(); i++)
1538        {
1539            t = (TSyntaxError) syntaxErrors.get(i);
1540            if (t.hint.length() > 0) hint = t.hint;
1541            s= s+hint+"("+t.errorno+") near: "+t.tokentext;
1542            s=s+"("+t.lineNo;
1543            s=s+","+t.columnNo +", token code:"+t.tokencode+")";
1544                //s=s+" expected tokentext:"+t.hint;
1545
1546           // break;//get only one message, remove this one and uncomment next line to get all error messages
1547            if (i !=  syntaxErrors.size() - 1)
1548              s = s +TBaseType.linebreak;
1549        }
1550
1551        if (errormessage.length() > 0){
1552            s = errormessage+TBaseType.linebreak+s; 
1553        }
1554        return s;
1555
1556    }
1557
1558    /**
1559     * check syntax of the input SQL. This method works exactly the same as {@link #parse} method.
1560     *
1561     * @return   0 means parse SQL script successfully, otherwise, use {@link #getErrorCount}, {@link #getErrormessage}
1562     * to get detailed error information.
1563     * @see #parse
1564     */
1565    public int checkSyntax(){
1566        return doparse();
1567    }
1568
1569    /**
1570     *   Check syntax of the input SQL, doing some kind of semantic analysis without connecting to a real database.
1571     *   <p></p>
1572     *  This method will do a in-depth analysis of the input SQL such as building the link between table and columns.
1573     *  The parse tree of the input SQL is available after calling this method.
1574     *
1575     *  The parser checks the syntax of those SQL statements one by one. If syntax error is found in a SQL statement,
1576     *  an error will be logged, no parse tree will be built for this SQL statement,
1577     *  the error message can be fetched using the {@link #getErrormessage()} method.
1578     *  <p></p>
1579     *  The syntax error in one SQL statement doesn't prevent the parser continue to check the syntax of the next SQL statement.
1580     *  After checking syntax of all SQL statements, use the {@link #getErrorCount()} method to get the total number of errors.
1581     *  <p></p>
1582     *  A syntax error in a SQL stored procedure will cease this parser to check syntax of the rest SQL statements
1583     *  in this stored procedure.
1584     *
1585     * @return   0 means parse SQL script successfully, otherwise, use {@link #getErrorCount}, {@link #getErrormessage}
1586     * to get detailed error information.
1587     * @see #getSyntaxErrors
1588     */
1589
1590    public int parse(){
1591        return doparse();
1592    }
1593
1594    public int validate(){
1595        if (sqlstatements.size() == 0) return 0;
1596
1597        TRelationValidator relationValidate = new TRelationValidator(globalContext);
1598        for(TCustomSqlStatement sqlStatement:sqlstatements){
1599            sqlStatement.acceptChildren(relationValidate);
1600        }
1601        return 0;
1602    }
1603
1604    void setdelimiterchar(char ch){
1605        delimiterchar = ch;
1606        flexer.delimiterchar = ch;
1607    }
1608    char curdelimiterchar;
1609    String userDelimiterStr ="";
1610
1611    boolean includesqlstatementtype(ESqlStatementType search, ESqlStatementType[] src){
1612        boolean ret = false;
1613        for(int i=0;i<src.length;i++){
1614            if (src[i] == search){
1615                ret = true;
1616                break;
1617            }
1618        }
1619        return ret;
1620    }
1621
1622    // private int getfileEncodingType(FileInputStream inputStream){
1623    //     BufferedInputStream fr = new BufferedInputStream(inputStream,8);
1624    //     return getfileEncodingType(fr);
1625    // }
1626
1627    private int getfileEncodingType(BufferedInputStream fr){
1628        int ret = 0; // default, 1: utf-16, 2: utf-32
1629       // BufferedInputStream fr = new BufferedInputStream(inputStream,8);
1630        try {
1631            byte[] bom = new byte[4];
1632            fr.mark(bom.length+1);
1633
1634            fr.read(bom,0,bom.length);
1635            if ( ((bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE))
1636                    ||((bom[0] == (byte)0xFE) && (bom[1] == (byte)0xFF))
1637                    )
1638            {
1639                ret = 1;
1640                if ( ((bom[2] == (byte)0xFF) && (bom[3] == (byte)0xFE))
1641                        ||((bom[2] == (byte)0xFE) && (bom[3] == (byte)0xFF))
1642                        ){
1643                    ret = 2;
1644                }
1645            }else{
1646                if ((bom[0] == (byte)0xEF) && (bom[1] == (byte)0xBB)&& (bom[2] == (byte)0xBF)){
1647                    ret = 3; //UTF-8,EF BB BF
1648                }
1649            }
1650            fr.reset();
1651        } catch (FileNotFoundException e) {
1652            // e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1653        } catch (IOException e) {
1654            //e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1655        }
1656        return ret;
1657    }
1658
1659    // private int getfileEncodingType(String fn){
1660    //     int ret = 0; // default, 1: utf-16, 2: utf-32
1661    //     try {
1662    //         FileInputStream fr =   new FileInputStream(fn);
1663    //         ret = getfileEncodingType(fr);
1664    //         fr.close();
1665
1666    //     } catch (FileNotFoundException e) {
1667    //        // e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1668    //     } catch (IOException e) {
1669    //         //e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1670    //     }
1671    //     return ret;
1672    // }
1673
1674    int readsql(){
1675        int ret  = 0;
1676
1677        syntaxErrors.clear();
1678        //syntaxHints.clear();
1679
1680        if (((!TBaseType.full_edition))||(!TBaseType.need_license_file)){
1681            if (!TBaseType.need_license_file){
1682                licenseType = TBaseType.license_type_dist;
1683                userName = "dist";
1684            }else {
1685                licenseType = TBaseType.license_type_trial;
1686                userName = TBaseType.license_trail_username;
1687            }
1688           // machineId = new HardwareBinder().getMachineIdString();
1689        }else {
1690            if (!licenseOK){
1691                errormessage = licenseMessage;
1692                return -1;
1693            }
1694        }
1695
1696        try{
1697            if (finputstream != null) finputstream.close();
1698            if (flexer == null){
1699                ret = -1;
1700                errormessage = "requested database not supported:"+this.dbVendor.toString();
1701                return ret;
1702            }
1703            if (flexer.yyinput != null)    flexer.yyinput.close();
1704
1705        }catch(IOException e){
1706            ret = -1;
1707            errormessage = "requested database not supported";
1708        }
1709        
1710        if (sqltext.length() > 0){
1711            finputstream = new BufferedReader(new StringReader(sqltext), TBaseType.LEXER_INPUT_BUFFER_SIZE);
1712            if ((!TBaseType.full_edition) && (sqltext.length() > TBaseType.query_size_limitation)){
1713                errormessage = TBaseType.trail_version_query_message;
1714                ret = -1;
1715            }
1716        }else if (sqlfilename.length() > 0){
1717            try{
1718
1719             streamFromSqlFile =   new FileInputStream(sqlfilename);
1720            // Buffer it for mark/reset support
1721            BufferedInputStream bufferedStream = new BufferedInputStream(streamFromSqlFile,8);             
1722            int encodingtype = getfileEncodingType(bufferedStream);
1723            streamFromSqlFile.getChannel().position(0);
1724
1725           if(encodingtype == 1){
1726                sqlStreamReader = new InputStreamReader(streamFromSqlFile,"UTF-16");
1727           }else if(encodingtype == 2){
1728                sqlStreamReader = new InputStreamReader(streamFromSqlFile,"UTF-32");
1729           }else if(encodingtype == 3){
1730              // System.out.println("utf-8");
1731                sqlStreamReader = new InputStreamReader(streamFromSqlFile,"UTF-8");
1732           }
1733           else{
1734               if (sqlCharset == null){
1735                   sqlCharset = Charset.defaultCharset().name();
1736                   //System.out.println("Charset used: "+Charset.defaultCharset().name());
1737               }
1738                sqlStreamReader = new InputStreamReader(streamFromSqlFile, sqlCharset);
1739              // isr = new InputStreamReader(fr,"Cp737");
1740           }
1741
1742            finputstream =  new BufferedReader(sqlStreamReader, TBaseType.LEXER_INPUT_BUFFER_SIZE);
1743            if (encodingtype == 3){
1744                //EF BB BF was not stripped by the InputStreamReader, so we do it
1745                finputstream.skip(1);
1746            }
1747
1748            if ((!TBaseType.full_edition)){
1749                File file = new File(sqlfilename);
1750                if (!file.exists() || !file.isFile()) {
1751                    ret = -1;
1752                    errormessage = "not a valid sql file.";
1753                }else{
1754                    if (file.length() > TBaseType.query_size_limitation){
1755                        errormessage = TBaseType.trail_version_file_message;
1756                        ret = -1;
1757                    }
1758                }
1759            }
1760
1761            }catch(FileNotFoundException e){
1762                ret = -1;
1763                errormessage = e.toString();
1764            } catch (UnsupportedEncodingException e) {
1765                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1766            } catch (IOException e) {
1767                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1768            }
1769
1770        }else if(this.sqlInputStream != null){
1771            int encodingtype = getfileEncodingType(sqlInputStream);
1772            InputStream fr =   sqlInputStream;
1773
1774            InputStreamReader isr = null;
1775            try{
1776
1777                if(encodingtype == 1){
1778                    isr = new InputStreamReader(fr,"UTF-16");
1779                }else if(encodingtype == 2){
1780                    isr = new InputStreamReader(fr,"UTF-32");
1781                }else if(encodingtype == 3){
1782                    // System.out.println("utf-8");
1783                    isr = new InputStreamReader(fr,"UTF-8");
1784                }
1785                else{
1786                    if (sqlCharset == null){
1787                        sqlCharset = Charset.defaultCharset().name();
1788                    }
1789
1790                    isr = new InputStreamReader(fr, sqlCharset);
1791                }
1792
1793                finputstream =  new BufferedReader(isr, TBaseType.LEXER_INPUT_BUFFER_SIZE);
1794                if (encodingtype == 3){
1795                    //EF BB BF was not stripped by the InputStreamReader, so we do it
1796                    finputstream.skip(1);
1797                }
1798
1799            }catch(FileNotFoundException e){
1800                ret = -1;
1801                errormessage = e.toString();
1802            } catch (UnsupportedEncodingException e) {
1803                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1804            } catch (IOException e) {
1805                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1806            }
1807
1808            try {
1809                if ((!TBaseType.full_edition) && (sqlInputStream.available() > TBaseType.query_size_limitation)){
1810                    errormessage = TBaseType.trail_version_query_message;
1811                    ret = -1;
1812                }
1813            } catch (IOException e) {
1814                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
1815            }
1816        }
1817
1818       if (finputstream == null) ret = -1;
1819
1820       if (ret == 0)
1821       {
1822           flexer.yyinput =  finputstream;
1823           flexer.setSqlCharset(this.sqlCharset);
1824           flexer.reset();
1825       }
1826
1827        sourcetokenlist.clear();
1828        sourcetokenlist.curpos = -1;
1829
1830       flexer.resetTokenTable();
1831
1832
1833        return ret;
1834    }
1835
1836    TSourceToken getanewsourcetoken(){
1837        TSourceToken pst = null,prevst;
1838        
1839        while (true) {
1840            pst = new TSourceToken("");
1841            if (flexer.yylexwrap(pst) == 0) { pst = null; break;}
1842            
1843            pst.setDbvendor(dbVendor);
1844            pst.tokenstatus = ETokenStatus.tsoriginal;
1845            if (pst.tokentype == ETokenType.ttreturn){
1846               pst.setAstext(towinlinebreak(pst.getAstext()));
1847            }
1848            //combine space && linebreak after a linebreak into one
1849            if ( (pst.tokentype == ETokenType.ttwhitespace)
1850             && (sourcetokenlist.curpos >= 0) )
1851              {
1852                prevst =  sourcetokenlist.get(sourcetokenlist.curpos);
1853                if ( prevst.tokentype == ETokenType.ttreturn )
1854                  {
1855                    //can't discard  whitespace after linebreak, it will be used
1856                    // to judge whether / at the { of the line is a sqlplus cmd or not
1857                    // check isvalidplacefordivtosqlpluscmd for more
1858                    prevst.setAstext(prevst.getAstext() + pst.getAstext());
1859                    //newst.free;
1860                    //newst = nil;
1861                    continue;
1862                  }
1863              }
1864
1865            if ( (pst.tokentype == ETokenType.ttreturn)
1866             && (sourcetokenlist.curpos >= 0) )
1867              {
1868                prevst =  sourcetokenlist.get(sourcetokenlist.curpos);
1869
1870                if ( prevst.tokentype == ETokenType.ttreturn )
1871                  {
1872                    prevst.setAstext(prevst.getAstext() + pst.getAstext());
1873                    //newst.free;
1874                    //newst = nil;
1875                    continue;
1876                  }
1877
1878                if ( prevst.tokentype == ETokenType.ttwhitespace )
1879                  {
1880                    //merge previous whitespace with this linebreak
1881                    //doesn't work for sqlplus cmd
1882
1883                   // prevst.sourcecode = newst.sourcecode;
1884                   // prevst.tokentype = newst.tokentype;
1885                   // prevst.tokencode = newst.tokencode;
1886                   // newst.free;
1887                   // newst = nil;
1888                   // continue;
1889
1890                   //prevst.prevsourcecode = prevst.astext;
1891                   //prevst.astext =  "";
1892                  }
1893              }
1894
1895            break;
1896
1897        }
1898
1899        if (pst != null){
1900            pst.container = sourcetokenlist;
1901            sourcetokenlist.curpos = sourcetokenlist.curpos+1;
1902            pst.posinlist = sourcetokenlist.curpos;
1903            if (tokenHandle != null){
1904                tokenHandle.processToken(pst);
1905            }
1906        }
1907
1908       // System.out.println(pst);
1909      //  flexer.setTokenTableValue(pst);
1910        return pst;
1911        
1912    }
1913
1914  String towinlinebreak(String s){
1915      return s;
1916// todo not implemented yet     
1917  }
1918
1919void checkconstarinttoken(TSourceToken lcprevtoken){
1920    TSourceTokenList lcStList = lcprevtoken.container;
1921    if (TBaseType.assigned(lcStList))
1922    {
1923         TSourceToken lcPPToken = lcStList.nextsolidtoken(lcprevtoken.posinlist,-2,false);
1924         if (TBaseType.assigned(lcPPToken))
1925        {
1926
1927             if (lcPPToken.tokencode == flexer.getkeywordvalue("constraint"))
1928             {
1929                 //System.out.println(lcPPToken);
1930                 lcPPToken.tokencode = TBaseType.rw_constraint2;
1931             }
1932        }
1933    }
1934
1935}
1936
1937TSourceToken getprevtoken(TSourceToken ptoken){
1938   // ETokenType[] lcnonsolidtokenset = {ETokenType.ttwhitespace,ETokenType.ttreturn,ETokenType.ttsimplecomment,ETokenType.ttbracketedcomment} ;
1939    TSourceTokenList lcstlist = ptoken.container;
1940    if (TBaseType.assigned(lcstlist)){
1941        if ((ptoken.posinlist > 0)  && (lcstlist.size() > ptoken.posinlist-1))
1942        {
1943            if (!(
1944                    (lcstlist.get(ptoken.posinlist-1).tokentype ==  ETokenType.ttwhitespace)
1945                    ||(lcstlist.get(ptoken.posinlist-1).tokentype ==  ETokenType.ttreturn)
1946                    ||(lcstlist.get(ptoken.posinlist-1).tokentype ==  ETokenType.ttsimplecomment)
1947                    ||(lcstlist.get(ptoken.posinlist-1).tokentype ==  ETokenType.ttbracketedcomment)
1948                    )
1949                )
1950            {return lcstlist.get(ptoken.posinlist-1);}
1951            else{
1952            { return lcstlist.nextsolidtoken(ptoken.posinlist-1,-1,false);}
1953        }
1954        }
1955    }
1956    
1957    return null;
1958}
1959
1960void doinformixtexttotokenlist(){
1961      TSourceToken lcprevtoken = null;
1962      int lcsteps = 0;
1963      TSourceToken asourcetoken,lctoken, lctoken2,lctoken3;
1964      int yychar;
1965      boolean iskeywordgo;
1966
1967      asourcetoken = getanewsourcetoken();
1968
1969      if ( asourcetoken == null ) return;
1970
1971      yychar = asourcetoken.tokencode;
1972
1973
1974      boolean lcinopenrowset = false;
1975      int lcnested = 0;
1976
1977      while (yychar > 0)
1978        {
1979
1980          if ( asourcetoken.tokencode == TBaseType.rrw_openrowset )
1981            {
1982              // openrowset(....)
1983              lcinopenrowset = true;
1984              lcnested = 0;
1985            }
1986          else if ( asourcetoken.tokentype == ETokenType.ttleftparenthesis)
1987            {
1988              if ( (lcsteps > 0) && TBaseType.assigned(lcprevtoken))
1989                {
1990                  if ( lcprevtoken.tokencode == TBaseType.rrw_primary )
1991                    {
1992                     lcprevtoken.tokencode = TBaseType.rrw_select - 2;  //rw_primary2
1993                     //checkconstarinttoken(lcprevtoken);
1994                    }
1995                  else if ( lcprevtoken.tokencode == TBaseType.rrw_foreign )
1996                    {
1997                     lcprevtoken.tokencode = TBaseType.rrw_select - 4;  //rw_foreign2
1998                     //checkconstarinttoken(lcprevtoken);
1999                    }
2000                  else if ( lcprevtoken.tokencode == TBaseType.rrw_unique )
2001                    {
2002                      lcprevtoken.tokencode = TBaseType.rrw_select - 1;  //rw_unique2
2003                     // checkconstarinttoken(lcprevtoken);
2004                    }
2005                  else if ( lcprevtoken.tokencode == TBaseType.rrw_distinct )
2006                    {
2007                      lcprevtoken.tokencode = TBaseType.rrw_select - 6;  //rw_distinct2
2008                      //checkconstarinttoken(lcprevtoken);
2009                    }
2010                  lcprevtoken = null;
2011                  lcsteps = 0;
2012                }
2013
2014              // openrowset(....)
2015              if ( lcinopenrowset )
2016                lcnested++;
2017            }
2018          else if ( asourcetoken.tokentype == ETokenType.ttrightparenthesis)
2019            {
2020              // openrowset(....)
2021              if ( lcinopenrowset  )
2022                {
2023                  if ( (lcnested > 0) )
2024                    lcnested--;
2025                  if ( lcnested == 0 )
2026                    lcinopenrowset = false;
2027                }
2028            }
2029          else if ( asourcetoken.tokentype == ETokenType.ttsemicolon )
2030            {
2031              if ( lcinopenrowset ){
2032                asourcetoken.tokentype = ETokenType.ttsemicolon2;
2033              }else{
2034                lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin,-1);
2035                  if (lctoken2 != null){
2036                     asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
2037                     asourcetoken.tokentype = ETokenType.ttsemicolon3;
2038                  }else{
2039                      lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try,-1);
2040                      if (lctoken2 == null){
2041                          lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch,-1);
2042                      }
2043                      if (lctoken2 != null){
2044                          lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin,-2);
2045                          if (lctoken3 != null){
2046                              asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
2047                              asourcetoken.tokentype = ETokenType.ttsemicolon3;
2048                          }
2049                      }
2050                  }
2051              }
2052            }
2053          else if ( asourcetoken.tokentype == ETokenType.ttperiod)
2054            {
2055              lctoken = getprevtoken(asourcetoken);
2056             //  System.out.println(lctoken);
2057              if ( TBaseType.assigned(lctoken) )
2058                { // go.fieldname, go is a table alias, not a go statement
2059                  if ( lctoken.tokencode == TBaseType.rrw_go )
2060                    {
2061                      lctoken.tokencode = TBaseType.ident;
2062                      lctoken.tokentype = ETokenType.ttidentifier;
2063                    }
2064                }
2065            }
2066          else if ( asourcetoken.tokencode == TBaseType.rrw_table ){
2067              lctoken = getprevtoken(asourcetoken);
2068              if (TBaseType.assigned(lctoken))
2069              {
2070                  if (lctoken.tokencode == TBaseType.rrw_lock )
2071                  {
2072                      lctoken.tokencode = TBaseType.rw_locktable; //TBaseType.rw_locktable
2073                  }
2074              }
2075          }
2076          else if ( asourcetoken.tokencode == TBaseType.rrw_to ){
2077              lctoken = getprevtoken(asourcetoken);
2078              if (TBaseType.assigned(lctoken))
2079              {
2080                  if (lctoken.tokencode == TBaseType.rrw_connect )
2081                  {
2082                      lctoken.tokencode = TBaseType.rrw_informix_connect_to;//connect to statement
2083                  }
2084              }
2085          }
2086          else if ( asourcetoken.tokencode == TBaseType.rrw_go )
2087            {
2088              iskeywordgo = true;
2089              lctoken = getprevtoken(asourcetoken);
2090              if ( TBaseType.assigned(lctoken) )
2091                { // go should not at same line as other sql statement
2092                  if ( lctoken.lineNo == asourcetoken.lineNo)
2093                    {
2094                      iskeywordgo = false;
2095                    }
2096                }
2097
2098              if ( iskeywordgo )
2099                {
2100                  lcinopenrowset = false;
2101                  lcnested = 0;
2102                  lcprevtoken = asourcetoken;
2103                }
2104              else
2105                {
2106                  //  System.out.println(asourcetoken);
2107                  asourcetoken.tokencode = TBaseType.ident;
2108                  asourcetoken.tokentype = ETokenType.ttidentifier;
2109                }
2110            }
2111          else if ( asourcetoken.tokencode == TBaseType.rrw_primary )
2112            {
2113              // primary key [clustered | nonclustered ] ( column list)
2114              lcsteps = 2;
2115              lcprevtoken = asourcetoken;
2116            }
2117          else if ( asourcetoken.tokencode == TBaseType.rrw_foreign )
2118            {
2119              // foreign key [clustered | nonclustered ] ( column list)
2120              lcsteps = 2;
2121              lcprevtoken = asourcetoken;
2122            }
2123          else if ( asourcetoken.tokencode == TBaseType.rrw_unique )
2124            {
2125              // unique [clustered | nonclustered ] ( column list)
2126              lcsteps = 1;
2127              lcprevtoken = asourcetoken;
2128            }
2129          else if ( asourcetoken.issolidtoken() )
2130            {
2131              if ( lcsteps > 0 )
2132                {
2133                  if (  !(TBaseType.mysametext("clustered",asourcetoken.toString())
2134                     || TBaseType.mysametext("nonclustered",asourcetoken.toString())) )
2135                    lcsteps--;
2136                }
2137            }
2138
2139           //System.out.println(asourcetoken);
2140           sourcetokenlist.add(asourcetoken);
2141
2142
2143          //flexer.yylexwrap(asourcetoken);
2144          asourcetoken = getanewsourcetoken();
2145          if (asourcetoken != null){
2146              yychar = asourcetoken.tokencode;
2147          }else{
2148            yychar = 0;
2149          }
2150
2151        }
2152
2153  }
2154
2155  void domssqlsqltexttotokenlist(){
2156      TSourceToken lcprevtoken = null;
2157      int lcsteps = 0;
2158      TSourceToken asourcetoken,lctoken, lctoken2,lctoken3;
2159      int yychar;
2160      boolean iskeywordgo;
2161
2162      asourcetoken = getanewsourcetoken();
2163      
2164      if ( asourcetoken == null ) return;
2165
2166      yychar = asourcetoken.tokencode;
2167
2168
2169      boolean lcinopenrowset = false;
2170      int lcnested = 0;
2171
2172      while (yychar > 0)
2173        {
2174
2175          if ( asourcetoken.tokencode == TBaseType.rrw_openrowset )
2176            {
2177              // openrowset(....)
2178              lcinopenrowset = true;
2179              lcnested = 0;
2180            }
2181          else if ( asourcetoken.tokentype == ETokenType.ttleftparenthesis)
2182            {
2183              if ( (lcsteps > 0) && TBaseType.assigned(lcprevtoken))
2184                {
2185                  if ( lcprevtoken.tokencode == TBaseType.rrw_primary )
2186                    {
2187                     lcprevtoken.tokencode = TBaseType.rrw_select - 2;  //rw_primary2
2188                     checkconstarinttoken(lcprevtoken);
2189                    }
2190                  else if ( lcprevtoken.tokencode == TBaseType.rrw_foreign )
2191                    {
2192                     lcprevtoken.tokencode = TBaseType.rrw_select - 4;  //rw_foreign2
2193                     checkconstarinttoken(lcprevtoken);
2194                    }
2195                  else if ( lcprevtoken.tokencode == TBaseType.rrw_unique )
2196                    {
2197                      lcprevtoken.tokencode = TBaseType.rrw_select - 1;  //rw_unique2
2198                      checkconstarinttoken(lcprevtoken);
2199                    }
2200                  lcprevtoken = null;
2201                  lcsteps = 0;
2202                }
2203
2204              // openrowset(....)
2205              if ( lcinopenrowset )
2206                lcnested++;
2207            }
2208          else if ( asourcetoken.tokentype == ETokenType.ttrightparenthesis)
2209            {
2210              // openrowset(....)
2211              if ( lcinopenrowset  )
2212                {
2213                  if ( (lcnested > 0) )
2214                    lcnested--;
2215                  if ( lcnested == 0 )
2216                    lcinopenrowset = false;
2217                }
2218            }
2219          else if ( asourcetoken.tokentype == ETokenType.ttsemicolon )
2220            {
2221              if ( lcinopenrowset ){
2222                asourcetoken.tokentype = ETokenType.ttsemicolon2;
2223              }else{
2224                lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin,-1);
2225                  if (lctoken2 != null){
2226                     asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
2227                     asourcetoken.tokentype = ETokenType.ttsemicolon3;
2228                  }else{
2229                      lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try,-1);
2230                      if (lctoken2 == null){
2231                          lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch,-1);
2232                      }
2233                      if (lctoken2 != null){
2234                          lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin,-2);
2235                          if (lctoken3 != null){
2236                              asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
2237                              asourcetoken.tokentype = ETokenType.ttsemicolon3;
2238                          }
2239                      }
2240                  }
2241              }
2242
2243                lctoken = getprevtoken(asourcetoken);
2244                if ((lctoken != null)){
2245                    if (lctoken.tokentype == ETokenType.ttsemicolon){
2246                        // treat this semicolon as a whitespace
2247                        asourcetoken.tokencode = TBaseType.lexspace;
2248                    }
2249                }
2250            }
2251          else if ( asourcetoken.tokentype == ETokenType.ttperiod)
2252            {
2253              lctoken = getprevtoken(asourcetoken);
2254             //  System.out.println(lctoken);
2255              if ( TBaseType.assigned(lctoken) )
2256                { // go.fieldname, go is a table alias, not a go statement
2257                  if ( lctoken.tokencode == TBaseType.rrw_go )
2258                    {
2259                      lctoken.tokencode = TBaseType.ident;
2260                      lctoken.tokentype = ETokenType.ttidentifier;
2261                    }
2262                }
2263            }
2264          else if ( asourcetoken.tokencode == TBaseType.rrw_table ){
2265              lctoken = getprevtoken(asourcetoken);
2266              if (TBaseType.assigned(lctoken))
2267              {
2268                  if (lctoken.tokencode == TBaseType.rrw_lock )
2269                  {
2270                      lctoken.tokencode = TBaseType.rw_locktable; //TBaseType.rw_locktable
2271                  }
2272              }
2273          }
2274          else if ( asourcetoken.tokencode == TBaseType.rrw_into ){
2275              lctoken = getprevtoken(asourcetoken);
2276              if (TBaseType.assigned(lctoken))
2277              {
2278                  if (lctoken.tokencode == TBaseType.rrw_sqlserver_copy )
2279                  {
2280                     lctoken.tokencode = TBaseType.rrw_sqlserver_copyinto;
2281                  }
2282              }
2283          }
2284          else if ( asourcetoken.tokencode == TBaseType.rrw_sqlserver_column ){
2285              lctoken = getprevtoken(asourcetoken);
2286              if (TBaseType.assigned(lctoken))
2287              {
2288                  if (lctoken.tokencode == TBaseType.rrw_drop )
2289                  {
2290                      asourcetoken.tokencode = TBaseType.rrw_sqlserver_drop_column;
2291                  }
2292              }
2293          }
2294          else if ( asourcetoken.tokencode == TBaseType.rrw_go )
2295            {
2296              iskeywordgo = true;
2297              lctoken = getprevtoken(asourcetoken);
2298              if ( TBaseType.assigned(lctoken) )
2299                { // go should not at same line as other sql statement
2300                  if (( lctoken.lineNo == asourcetoken.lineNo)&&(lctoken.tokencode != ';'))
2301                    {
2302                      iskeywordgo = false;
2303                    }
2304                }
2305
2306              if ( iskeywordgo )
2307                {
2308                  lcinopenrowset = false;
2309                  lcnested = 0;
2310                  lcprevtoken = asourcetoken;
2311                }
2312              else
2313                {
2314                  //  System.out.println(asourcetoken);
2315                  asourcetoken.tokencode = TBaseType.ident;
2316                  asourcetoken.tokentype = ETokenType.ttidentifier;
2317                }
2318            }
2319          else if ( asourcetoken.tokencode == TBaseType.rrw_primary )
2320            {
2321              // primary key [clustered | nonclustered ] [hash] ( column list)
2322              lcsteps = 2;
2323              lcprevtoken = asourcetoken;
2324            }
2325          else if ( asourcetoken.tokencode == TBaseType.rrw_foreign )
2326            {
2327              // foreign key [clustered | nonclustered ] ( column list)
2328              lcsteps = 2;
2329              lcprevtoken = asourcetoken;
2330            }
2331          else if ( asourcetoken.tokencode == TBaseType.rrw_unique )
2332            {
2333              // unique [clustered | nonclustered ] [hash] ( column list)
2334              lcsteps = 1;
2335              lcprevtoken = asourcetoken;
2336            }
2337          else if ( asourcetoken.issolidtoken() )
2338            {
2339              if ( lcsteps > 0 )
2340                {
2341                  if (  !(TBaseType.mysametext("clustered",asourcetoken.toString())
2342                     || TBaseType.mysametext("nonclustered",asourcetoken.toString())
2343                     || TBaseType.mysametext("hash",asourcetoken.toString())
2344                  ) )
2345                    lcsteps--;
2346                }
2347            }
2348
2349           //System.out.println(asourcetoken); 
2350           sourcetokenlist.add(asourcetoken);
2351
2352
2353          //flexer.yylexwrap(asourcetoken);
2354          asourcetoken = getanewsourcetoken();
2355          if (asourcetoken != null){
2356              yychar = asourcetoken.tokencode;
2357          }else{
2358            yychar = 0;
2359          }
2360
2361        }
2362
2363  }
2364
2365  void dosybasesqltexttotokenlist(){
2366      TSourceToken lcprevtoken = null;
2367      int lcsteps = 0;
2368      TSourceToken asourcetoken,lctoken, lctoken2,lctoken3;
2369      int yychar;
2370      boolean iskeywordgo;
2371
2372
2373      asourcetoken = getanewsourcetoken();
2374
2375      if ( asourcetoken == null ) return;
2376
2377      yychar = asourcetoken.tokencode;
2378
2379
2380      boolean lcinopenrowset = false;
2381      int lcnested = 0;
2382
2383      while (yychar > 0)
2384        {
2385
2386          if ( asourcetoken.tokencode == TBaseType.rrw_openrowset )
2387            {
2388              // openrowset(....)
2389              lcinopenrowset = true;
2390              lcnested = 0;
2391            }
2392          else if ( asourcetoken.tokentype == ETokenType.ttleftparenthesis)
2393            {
2394              if ( (lcsteps > 0) && TBaseType.assigned(lcprevtoken))
2395                {
2396                  if ( lcprevtoken.tokencode == TBaseType.rrw_primary )
2397                    {
2398                     lcprevtoken.tokencode = TBaseType.rrw_select - 2;  //rw_primary2
2399                     checkconstarinttoken(lcprevtoken);
2400                    }
2401                  else if ( lcprevtoken.tokencode == TBaseType.rrw_foreign )
2402                    {
2403                     lcprevtoken.tokencode = TBaseType.rrw_select - 4;  //rw_foreign2
2404                     checkconstarinttoken(lcprevtoken);
2405                    }
2406                  else if ( lcprevtoken.tokencode == TBaseType.rrw_unique )
2407                    {
2408                      lcprevtoken.tokencode = TBaseType.rrw_select - 1;  //rw_unique2
2409                      checkconstarinttoken(lcprevtoken);
2410                    }
2411                  lcprevtoken = null;
2412                  lcsteps = 0;
2413                }
2414
2415              // openrowset(....)
2416              if ( lcinopenrowset )
2417                lcnested++;
2418            }
2419          else if ( asourcetoken.tokentype == ETokenType.ttrightparenthesis)
2420            {
2421              // openrowset(....)
2422              if ( lcinopenrowset  )
2423                {
2424                  if ( (lcnested > 0) )
2425                    lcnested--;
2426                  if ( lcnested == 0 )
2427                    lcinopenrowset = false;
2428                }
2429            }
2430          else if ( asourcetoken.tokentype == ETokenType.ttsemicolon )
2431            {
2432              if ( lcinopenrowset ){
2433                asourcetoken.tokentype = ETokenType.ttsemicolon2;
2434              }else{
2435                lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin,-1);
2436                  if (lctoken2 != null){
2437                     asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
2438                     asourcetoken.tokentype = ETokenType.ttsemicolon3;
2439                  }else{
2440                      lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try,-1);
2441                      if (lctoken2 == null){
2442                          lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch,-1);
2443                      }
2444                      if (lctoken2 != null){
2445                          lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin,-2);
2446                          if (lctoken3 != null){
2447                              asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
2448                              asourcetoken.tokentype = ETokenType.ttsemicolon3;
2449                          }
2450                      }
2451                  }
2452              }
2453            }
2454          else if ( asourcetoken.tokentype == ETokenType.ttperiod)
2455            {
2456              lctoken = getprevtoken(asourcetoken);
2457             //  System.out.println(lctoken);
2458              if ( TBaseType.assigned(lctoken) )
2459                { // go.fieldname, go is a table alias, not a go statement
2460                  if ( lctoken.tokencode == TBaseType.rrw_go )
2461                    {
2462                      lctoken.tokencode = TBaseType.ident;
2463                      lctoken.tokentype = ETokenType.ttidentifier;
2464                    }
2465                }
2466            }
2467          else if ( asourcetoken.tokencode == TBaseType.rrw_table ){
2468              lctoken = getprevtoken(asourcetoken);
2469              if (TBaseType.assigned(lctoken))
2470              {
2471                  if (lctoken.tokencode == TBaseType.rrw_lock )
2472                  {
2473                      lctoken.tokencode = TBaseType.rw_locktable; //TBaseType.rw_locktable
2474                  }
2475              }
2476          }
2477          else if ( asourcetoken.tokencode == TBaseType.rrw_sybase_isolation ){
2478              lctoken = getprevtoken(asourcetoken);
2479              if (TBaseType.assigned(lctoken))
2480              {
2481                  if (lctoken.tokencode == TBaseType.rrw_sybase_at )
2482                  {
2483                      lctoken.tokencode = TBaseType.rw_sybase_at1; //TBaseType.rw_locktable
2484                  }
2485              }
2486          }
2487          else if ( asourcetoken.tokencode == TBaseType.rrw_update ){
2488              lctoken = getprevtoken(asourcetoken);
2489              if (TBaseType.assigned(lctoken))
2490              {
2491                  if ((lctoken.tokencode == TBaseType.rrw_not )
2492                          ||(lctoken.tokencode == TBaseType.rrw_and )
2493                          ||(lctoken.tokencode == TBaseType.rrw_or )
2494                          ||(lctoken.tokencode == TBaseType.rrw_if )
2495                      )
2496                  {
2497                      // this is update(column) in create trigger
2498                      asourcetoken.tokencode = TBaseType.rw_sybase_update1;
2499                  }
2500              }
2501          }
2502          else if ( asourcetoken.tokencode == TBaseType.rrw_go )
2503            {
2504              iskeywordgo = true;
2505              lctoken = getprevtoken(asourcetoken);
2506              if ( TBaseType.assigned(lctoken) )
2507                { // go should not at same line as other sql statement
2508                  if ( lctoken.lineNo == asourcetoken.lineNo)
2509                    {
2510                      iskeywordgo = false;
2511                    }
2512                }
2513
2514              if ( iskeywordgo )
2515                {
2516                  lcinopenrowset = false;
2517                  lcnested = 0;
2518                  lcprevtoken = asourcetoken;
2519                }
2520              else
2521                {
2522                  //  System.out.println(asourcetoken);
2523                  asourcetoken.tokencode = TBaseType.ident;
2524                  asourcetoken.tokentype = ETokenType.ttidentifier;
2525                }
2526            }
2527          else if ( asourcetoken.tokencode == TBaseType.rrw_primary )
2528            {
2529              // primary key [clustered | nonclustered ] ( column list)
2530              lcsteps = 2;
2531              lcprevtoken = asourcetoken;
2532            }
2533          else if ( asourcetoken.tokencode == TBaseType.rrw_foreign )
2534            {
2535              // foreign key [clustered | nonclustered ] ( column list)
2536              lcsteps = 2;
2537              lcprevtoken = asourcetoken;
2538            }
2539          else if ( asourcetoken.tokencode == TBaseType.rrw_unique )
2540            {
2541              // unique [clustered | nonclustered ] ( column list)
2542              lcsteps = 1;
2543              lcprevtoken = asourcetoken;
2544            }
2545          else if ( asourcetoken.issolidtoken() )
2546            {
2547              if ( lcsteps > 0 )
2548                {
2549                  if (  !(TBaseType.mysametext("clustered",asourcetoken.toString())
2550                     || TBaseType.mysametext("nonclustered",asourcetoken.toString())) )
2551                    lcsteps--;
2552                }
2553            }
2554
2555           //System.out.println(asourcetoken);
2556           sourcetokenlist.add(asourcetoken);
2557
2558
2559          //flexer.yylexwrap(asourcetoken);
2560          asourcetoken = getanewsourcetoken();
2561          if (asourcetoken != null){
2562              yychar = asourcetoken.tokencode;
2563          }else{
2564            yychar = 0;
2565          }
2566
2567        }
2568
2569  }
2570
2571boolean IsValidPlaceForDivToSqlplusCmd(TSourceTokenList pstlist, int pPos){
2572   boolean ret = false;
2573
2574    if ((pPos <= 0) || (pPos > pstlist.size() - 1 ) ) return ret;
2575    //tokentext directly before div must be ttreturn without space appending it
2576    TSourceToken lcst = pstlist.get(pPos - 1);
2577    if (lcst.tokentype != ETokenType.ttreturn) { return ret;}
2578
2579    //I := Length(lcst.AsText);
2580    //if not (lcst.AsText[I] = ' ') then result := true;
2581
2582    if (!(lcst.getAstext().charAt(lcst.getAstext().length()-1) == ' ')) {ret = true;}
2583
2584    return ret;
2585}
2586
2587// place holder function, always return false
2588boolean isvalidsqlpluscmdInPostgresql(String astr){
2589    return false;
2590}
2591
2592//boolean isvalidsqlpluscmd(String astr){
2593//    boolean ret = false;
2594//    if (sqlpluskeywordList.size() == 0){
2595//    sqlpluskeywordList.put("ACC","1");
2596//        sqlpluskeywordList.put("ACCEPT","1");
2597//        sqlpluskeywordList.put("A","1");
2598//        sqlpluskeywordList.put("APPEND","1");
2599//        sqlpluskeywordList.put("ATTRIBUTE","1");
2600//        sqlpluskeywordList.put("BRE","1");
2601//        sqlpluskeywordList.put("BREAK","1");
2602//        sqlpluskeywordList.put("BTI","1");
2603//        sqlpluskeywordList.put("BTITLE","1");
2604//        sqlpluskeywordList.put("C","1");
2605//        sqlpluskeywordList.put("CHANGE","1");
2606//        sqlpluskeywordList.put("CL","1");
2607//        sqlpluskeywordList.put("CLEAR","1");
2608//        sqlpluskeywordList.put("COL","1");
2609//        sqlpluskeywordList.put("COLUMN","1");
2610//        sqlpluskeywordList.put("COMP","1");
2611//        sqlpluskeywordList.put("COMPUTE","1");
2612//        sqlpluskeywordList.put("CONN","1");
2613//        sqlpluskeywordList.put("CONNECT","1");
2614//        sqlpluskeywordList.put("COPY","1");
2615//        sqlpluskeywordList.put("DEF","1");
2616//        sqlpluskeywordList.put("DEFINE","1");
2617//        sqlpluskeywordList.put("DEL","1");
2618//        sqlpluskeywordList.put("DESC","1");
2619//        sqlpluskeywordList.put("DESCRIBE","1");
2620//        sqlpluskeywordList.put("DISC","1");
2621//        sqlpluskeywordList.put("DISCONNECT","1");
2622//        sqlpluskeywordList.put("ED","1");
2623//        sqlpluskeywordList.put("EDIT","1");
2624//        sqlpluskeywordList.put("EXEC","1");
2625//        sqlpluskeywordList.put("EXIT","1");
2626//        sqlpluskeywordList.put("QUIT","1");
2627//        sqlpluskeywordList.put("GET","1");
2628//        sqlpluskeywordList.put("HELP","1");
2629//        sqlpluskeywordList.put("HO","1");
2630//        sqlpluskeywordList.put("HOST","1");
2631//        sqlpluskeywordList.put("I","1");
2632//        sqlpluskeywordList.put("INPUT","1");
2633//        sqlpluskeywordList.put("L","1");
2634//        sqlpluskeywordList.put("LIST","1");
2635//        sqlpluskeywordList.put("PASSW","1");
2636//        sqlpluskeywordList.put("PASSWORD","1");
2637//        sqlpluskeywordList.put("PAU","1");
2638//        sqlpluskeywordList.put("PAUSE","1");
2639//        sqlpluskeywordList.put("PRI","1");
2640//        sqlpluskeywordList.put("PRINT","1");
2641//        sqlpluskeywordList.put("PROMPT","1");
2642//        sqlpluskeywordList.put("REM","1");
2643//        sqlpluskeywordList.put("REMARK","1");
2644//        sqlpluskeywordList.put("REPF","1");
2645//        sqlpluskeywordList.put("REPFOOTER","1");
2646//        sqlpluskeywordList.put("REPH","1");
2647//        sqlpluskeywordList.put("REPHEADER","1");
2648//        sqlpluskeywordList.put("R","1");
2649//        sqlpluskeywordList.put("RUN","1");
2650//        sqlpluskeywordList.put("SAV","1");
2651//        sqlpluskeywordList.put("SAVE","1");
2652//        sqlpluskeywordList.put("SET","1");
2653//        sqlpluskeywordList.put("SHO","1");
2654//        sqlpluskeywordList.put("SHOW","1");
2655//        sqlpluskeywordList.put("SPO","1");
2656//        sqlpluskeywordList.put("SPOOL","1");
2657//        sqlpluskeywordList.put("STA","1");
2658//        sqlpluskeywordList.put("START","1");
2659//        sqlpluskeywordList.put("STORE","1");
2660//        sqlpluskeywordList.put("TIMI","1");
2661//        sqlpluskeywordList.put("TIMING","1");
2662//        sqlpluskeywordList.put("TTI","1");
2663//        sqlpluskeywordList.put("TTITLE","1");
2664//        sqlpluskeywordList.put("UNDEF","1");
2665//        sqlpluskeywordList.put("UNDEFINE","1");
2666//        sqlpluskeywordList.put("VAR","1");
2667//        sqlpluskeywordList.put("VARIABLE","1");
2668//        sqlpluskeywordList.put("WHENEVER","1");
2669//        sqlpluskeywordList.put("@","1");
2670//        sqlpluskeywordList.put("@@","1");
2671//    }
2672//
2673//    try{
2674//     ret =   (Integer.parseInt( (String) sqlpluskeywordList.get(astr.toUpperCase()) ) ) == 1 ;
2675//    }catch(NumberFormatException e){
2676//        ret = false;
2677//    }
2678//
2679//    return ret;
2680//}
2681
2682TSourceToken getprevsolidtoken(TSourceToken ptoken){
2683    TSourceToken ret = null;
2684    TSourceTokenList lctokenlist = ptoken.container;
2685    if (lctokenlist != null){
2686        if ((ptoken.posinlist > 0)  &&  (lctokenlist.size() > ptoken.posinlist-1))
2687        {
2688            if( !(
2689                    (lctokenlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttwhitespace)
2690                    ||(lctokenlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttreturn)
2691                ||(lctokenlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttsimplecomment)
2692                ||(lctokenlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttbracketedcomment)
2693            ))
2694            { ret = lctokenlist.get(ptoken.posinlist-1);}
2695            else
2696            { ret = lctokenlist.nextsolidtoken(ptoken.posinlist-1,-1,false);}
2697        }
2698    }
2699    return ret;
2700}
2701
2702    void doredshifttexttotokenlist(){
2703
2704        boolean insqlpluscmd = false;
2705        boolean isvalidplace = true;
2706        boolean waitingreturnforfloatdiv = false;
2707        boolean waitingreturnforsemicolon = false;
2708        boolean continuesqlplusatnewline = false;
2709
2710
2711        TSourceToken lct = null, prevst = null;
2712
2713        TSourceToken asourcetoken,lcprevst;
2714        int yychar;
2715
2716        asourcetoken = getanewsourcetoken();
2717        if ( asourcetoken == null ) return;
2718        yychar = asourcetoken.tokencode;
2719
2720        while (yychar > 0)
2721        {
2722
2723
2724            sourcetokenlist.add(asourcetoken);
2725            switch(yychar){
2726                case TBaseType.cmtdoublehyphen:
2727                case TBaseType.cmtslashstar:
2728                case TBaseType.lexspace:{
2729                    if (insqlpluscmd){
2730                        asourcetoken.insqlpluscmd = true;
2731                    }
2732                    break;
2733                }
2734                case TBaseType.lexnewline:{
2735                    if (insqlpluscmd){
2736                        insqlpluscmd = false;
2737                        isvalidplace = true;
2738
2739                        if (continuesqlplusatnewline) {
2740                            insqlpluscmd = true;
2741                            isvalidplace = false;
2742                            asourcetoken.insqlpluscmd = true ;
2743                        }
2744                    }
2745
2746                    if (waitingreturnforsemicolon){
2747                        isvalidplace = true;
2748                    }
2749                    if (waitingreturnforfloatdiv)
2750                    {
2751                        isvalidplace = true;
2752                        lct.tokencode = TBaseType.sqlpluscmd;
2753                        if (lct.tokentype != ETokenType.ttslash){
2754                            lct.tokentype = ETokenType.ttsqlpluscmd;
2755                        }
2756                    }
2757                    flexer.insqlpluscmd = insqlpluscmd;
2758                    break;
2759                } //case newline
2760                default:{
2761                    //solid tokentext
2762                    continuesqlplusatnewline = false;
2763                    waitingreturnforsemicolon = false;
2764                    waitingreturnforfloatdiv = false;
2765                    if (insqlpluscmd)
2766                    {
2767                        asourcetoken.insqlpluscmd = true ;
2768                        if (asourcetoken.toString().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;}
2769                    }
2770                    else
2771                    {
2772                        if (asourcetoken.tokentype == ETokenType.ttsemicolon)
2773                        {waitingreturnforsemicolon = true;}
2774                        if ( (asourcetoken.tokentype == ETokenType.ttslash)
2775                                // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then
2776                                && (isvalidplace ||  (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) )
2777                        {
2778                            lct = asourcetoken;
2779                            waitingreturnforfloatdiv = true;
2780                        }
2781                        if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) )
2782                        {
2783                            asourcetoken.tokencode = TBaseType.sqlpluscmd;
2784                            if (asourcetoken.tokentype != ETokenType.ttslash)
2785                            {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;}
2786                            insqlpluscmd = true;
2787                            flexer.insqlpluscmd = insqlpluscmd;
2788                        }
2789                    }
2790                    isvalidplace = false;
2791
2792                    if (asourcetoken.tokencode == TBaseType.rrw_redshift_rowtype) {
2793                        TSourceToken stPercent = asourcetoken.searchToken('%', -1);
2794                        if (stPercent != null) {
2795                            stPercent.tokencode = TBaseType.rowtype_operator;
2796                        }
2797                    }
2798
2799                }
2800            }
2801
2802            //flexer.yylexwrap(asourcetoken);
2803            asourcetoken = getanewsourcetoken();
2804            if (asourcetoken != null){
2805                yychar = asourcetoken.tokencode;
2806            }else{
2807                yychar = 0;
2808
2809                if (waitingreturnforfloatdiv)
2810                { // / at the end of line treat as sqlplus command
2811                    //isvalidplace = true;
2812                    lct.tokencode = TBaseType.sqlpluscmd;
2813                    if (lct.tokentype != ETokenType.ttslash){
2814                        lct.tokentype = ETokenType.ttsqlpluscmd;
2815                    }
2816                }
2817            }
2818
2819            if ((yychar == 0) && (prevst != null))
2820            {
2821            }
2822
2823        }// while
2824    }
2825
2826    void doansitexttotokenlist(){
2827        dodb2sqltexttotokenlist();
2828    }
2829    void dogaussdbtexttotokenlist(){
2830
2831        boolean insqlpluscmd = false;
2832        boolean isvalidplace = true;
2833        boolean waitingreturnforfloatdiv = false;
2834        boolean waitingreturnforsemicolon = false;
2835        boolean continuesqlplusatnewline = false;
2836
2837        TSourceToken lct = null, prevst = null;
2838
2839        TSourceToken asourcetoken,lcprevst;
2840        int yychar;
2841
2842        asourcetoken = getanewsourcetoken();
2843        if ( asourcetoken == null ) return;
2844        yychar = asourcetoken.tokencode;
2845
2846        while (yychar > 0)
2847        {
2848            sourcetokenlist.add(asourcetoken);
2849            switch(yychar){
2850                case TBaseType.cmtdoublehyphen:
2851                case TBaseType.cmtslashstar:
2852                case TBaseType.lexspace:{
2853                    if (insqlpluscmd){
2854                        asourcetoken.insqlpluscmd = true;
2855                    }
2856                    break;
2857                }
2858                case TBaseType.lexnewline:{
2859                    if (insqlpluscmd){
2860                        insqlpluscmd = false;
2861                        isvalidplace = true;
2862
2863                        if (continuesqlplusatnewline) {
2864                            insqlpluscmd = true;
2865                            isvalidplace = false;
2866                            asourcetoken.insqlpluscmd = true ;
2867                        }
2868                    }
2869
2870                    if (waitingreturnforsemicolon){
2871                        isvalidplace = true;
2872                    }
2873                    if (waitingreturnforfloatdiv)
2874                    {
2875                        isvalidplace = true;
2876                        lct.tokencode = TBaseType.sqlpluscmd;
2877                        if (lct.tokentype != ETokenType.ttslash){
2878                            lct.tokentype = ETokenType.ttsqlpluscmd;
2879                        }
2880                    }
2881                    flexer.insqlpluscmd = insqlpluscmd;
2882                    break;
2883                } //case newline
2884                default:{
2885                    //solid tokentext
2886                    continuesqlplusatnewline = false;
2887                    waitingreturnforsemicolon = false;
2888                    waitingreturnforfloatdiv = false;
2889                    if (insqlpluscmd)
2890                    {
2891                        asourcetoken.insqlpluscmd = true ;
2892                        if (asourcetoken.toString().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;}
2893                    }
2894                    else
2895                    {
2896                        if (asourcetoken.tokentype == ETokenType.ttsemicolon)
2897                        {waitingreturnforsemicolon = true;}
2898                        if ( (asourcetoken.tokentype == ETokenType.ttslash)
2899                                && (isvalidplace ||  (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) )
2900                        {
2901                            lct = asourcetoken;
2902                            waitingreturnforfloatdiv = true;
2903                        }
2904                        if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) )
2905                        {
2906                            asourcetoken.tokencode = TBaseType.sqlpluscmd;
2907                            if (asourcetoken.tokentype != ETokenType.ttslash)
2908                            {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;}
2909                            insqlpluscmd = true;
2910                            flexer.insqlpluscmd = insqlpluscmd;
2911                        }
2912                    }
2913                    isvalidplace = false;
2914
2915                    // the inner keyword tokentext should be converted to TBaseType.ident when
2916                    // next solid tokentext is not join
2917
2918                    if (prevst != null)
2919                    {
2920                        if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER"))
2921                        {
2922                            if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN"))
2923                            {prevst.tokencode = TBaseType.ident;}
2924                        }
2925
2926
2927                        if ((prevst.tokencode == TBaseType.rrw_not)
2928                                && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE")))
2929                        {
2930                            prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE");
2931                        }
2932
2933                    }
2934
2935                    if (asourcetoken.tokencode == TBaseType.rrw_inner)
2936                    {
2937                        prevst = asourcetoken;
2938                    }
2939                    else if (asourcetoken.tokencode == TBaseType.rrw_not)
2940                    {
2941                        prevst = asourcetoken;
2942                    }
2943                    else
2944                    { prevst = null;}
2945
2946                    if ((asourcetoken.tokencode == flexer.getkeywordvalue("DIRECT_LOAD"))
2947                            ||  (asourcetoken.tokencode == flexer.getkeywordvalue("ALL")) )
2948                    {
2949                        // RW_COMPRESS RW_FOR RW_ALL RW_OPERATIONS
2950                        // RW_COMPRESS RW_FOR RW_DIRECT_LOAD RW_OPERATIONS
2951                        // change rw_for to TBaseType.rw_for1, it conflicts with compress for update in create materialized view
2952
2953                        lcprevst = getprevsolidtoken(asourcetoken);
2954                        if (lcprevst != null)
2955                        {
2956                            if (lcprevst.tokencode == TBaseType.rrw_for)
2957                                lcprevst.tokencode = TBaseType.rw_for1;
2958                        }
2959                    }
2960
2961                    if (asourcetoken.tokencode == TBaseType.rrw_dense_rank){
2962                        //keep keyword can be column alias, make keep in keep_denserankclause as a different token code
2963                        TSourceToken stKeep  = asourcetoken.searchToken(TBaseType.rrw_keep,-2);
2964                        if ( stKeep != null){
2965                            stKeep.tokencode = TBaseType.rrw_keep_before_dense_rank;
2966                        }
2967                    }
2968
2969                    if ((asourcetoken.tokencode == TBaseType.rrw_postgresql_rowtype)||(asourcetoken.tokencode == TBaseType.rrw_postgresql_type)) {
2970                        TSourceToken stPercent = asourcetoken.searchToken('%', -1);
2971                        if (stPercent != null) {
2972                            stPercent.tokencode = TBaseType.rowtype_operator;
2973                        }
2974                    }
2975
2976                    if (asourcetoken.tokencode == TBaseType.JSON_EXIST) {
2977                        TSourceToken stPercent = asourcetoken.searchToken('=', -1);
2978                        if (stPercent != null) {    // = ?, ? after = should not be treated as json exist operator
2979                            asourcetoken.tokencode = TBaseType.ident;
2980                        }
2981                    }
2982
2983                    if (asourcetoken.tokencode == TBaseType.rrw_update) { // on conflict do update in insert statement
2984                        TSourceToken stDo = asourcetoken.searchToken(TBaseType.rrw_do, -1);
2985                        if (stDo != null) {
2986                            asourcetoken.tokencode = TBaseType.rrw_postgresql_do_update;
2987                        }
2988                    }
2989
2990
2991                }
2992            }
2993
2994            //flexer.yylexwrap(asourcetoken);
2995            asourcetoken = getanewsourcetoken();
2996            if (asourcetoken != null){
2997                yychar = asourcetoken.tokencode;
2998            }else{
2999                yychar = 0;
3000
3001                if (waitingreturnforfloatdiv)
3002                { // / at the end of line treat as sqlplus command
3003                    //isvalidplace = true;
3004                    lct.tokencode = TBaseType.sqlpluscmd;
3005                    if (lct.tokentype != ETokenType.ttslash){
3006                        lct.tokentype = ETokenType.ttsqlpluscmd;
3007                    }
3008                }
3009
3010            }
3011
3012            if ((yychar == 0) && (prevst != null))
3013            {
3014                if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER"))
3015                { prevst.tokencode = TBaseType.ident;}
3016            }
3017
3018
3019        }
3020
3021
3022    }
3023    void dopostgresqltexttotokenlist(){
3024
3025        boolean insqlpluscmd = false;
3026        boolean isvalidplace = true;
3027        boolean waitingreturnforfloatdiv = false;
3028        boolean waitingreturnforsemicolon = false;
3029        boolean continuesqlplusatnewline = false;
3030
3031        TSourceToken lct = null, prevst = null;
3032
3033        TSourceToken asourcetoken,lcprevst;
3034        int yychar;
3035
3036        asourcetoken = getanewsourcetoken();
3037        if ( asourcetoken == null ) return;
3038        yychar = asourcetoken.tokencode;
3039
3040        while (yychar > 0)
3041        {
3042            sourcetokenlist.add(asourcetoken);
3043            switch(yychar){
3044                case TBaseType.cmtdoublehyphen:
3045                case TBaseType.cmtslashstar:
3046                case TBaseType.lexspace:{
3047                    if (insqlpluscmd){
3048                        asourcetoken.insqlpluscmd = true;
3049                    }
3050                    break;
3051                }
3052                case TBaseType.lexnewline:{
3053                    if (insqlpluscmd){
3054                        insqlpluscmd = false;
3055                        isvalidplace = true;
3056
3057                        if (continuesqlplusatnewline) {
3058                            insqlpluscmd = true;
3059                            isvalidplace = false;
3060                            asourcetoken.insqlpluscmd = true ;
3061                        }
3062                    }
3063
3064                    if (waitingreturnforsemicolon){
3065                        isvalidplace = true;
3066                    }
3067                    if (waitingreturnforfloatdiv)
3068                    {
3069                        isvalidplace = true;
3070                        lct.tokencode = TBaseType.sqlpluscmd;
3071                        if (lct.tokentype != ETokenType.ttslash){
3072                            lct.tokentype = ETokenType.ttsqlpluscmd;
3073                        }
3074                    }
3075                    flexer.insqlpluscmd = insqlpluscmd;
3076                    break;
3077                } //case newline
3078                default:{
3079                    //solid tokentext
3080                    continuesqlplusatnewline = false;
3081                    waitingreturnforsemicolon = false;
3082                    waitingreturnforfloatdiv = false;
3083                    if (insqlpluscmd)
3084                    {
3085                        asourcetoken.insqlpluscmd = true ;
3086                        if (asourcetoken.toString().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;}
3087                    }
3088                    else
3089                    {
3090                        if (asourcetoken.tokentype == ETokenType.ttsemicolon)
3091                        {waitingreturnforsemicolon = true;}
3092                        if ( (asourcetoken.tokentype == ETokenType.ttslash)
3093                                // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then
3094                                && (isvalidplace ||  (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) )
3095                        {
3096                            lct = asourcetoken;
3097                            waitingreturnforfloatdiv = true;
3098                        }
3099                        if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) )
3100                        {
3101                            asourcetoken.tokencode = TBaseType.sqlpluscmd;
3102                            if (asourcetoken.tokentype != ETokenType.ttslash)
3103                            {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;}
3104                            insqlpluscmd = true;
3105                            flexer.insqlpluscmd = insqlpluscmd;
3106                        }
3107                    }
3108                    isvalidplace = false;
3109
3110                    // the inner keyword tokentext should be convert to TBaseType.ident when
3111                    // next solid tokentext is not join
3112
3113                    if (prevst != null)
3114                    {
3115                        if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER"))
3116                        {
3117                            if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN"))
3118                            {prevst.tokencode = TBaseType.ident;}
3119                        }
3120
3121
3122                        if ((prevst.tokencode == TBaseType.rrw_not)
3123                                && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE")))
3124                        {
3125                            prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE");
3126                        }
3127
3128                    }
3129
3130                    if (asourcetoken.tokencode == TBaseType.rrw_inner)
3131                    {
3132                        prevst = asourcetoken;
3133                    }
3134                    else if (asourcetoken.tokencode == TBaseType.rrw_not)
3135                    {
3136                        prevst = asourcetoken;
3137                    }
3138                    else
3139                    { prevst = null;}
3140
3141                    if ((asourcetoken.tokencode == flexer.getkeywordvalue("DIRECT_LOAD"))
3142                            ||  (asourcetoken.tokencode == flexer.getkeywordvalue("ALL")) )
3143                    {
3144                        // RW_COMPRESS RW_FOR RW_ALL RW_OPERATIONS
3145                        // RW_COMPRESS RW_FOR RW_DIRECT_LOAD RW_OPERATIONS
3146                        // change rw_for to TBaseType.rw_for1, it conflicts with compress for update in create materialized view
3147
3148                        lcprevst = getprevsolidtoken(asourcetoken);
3149                        if (lcprevst != null)
3150                        {
3151                            if (lcprevst.tokencode == TBaseType.rrw_for)
3152                                lcprevst.tokencode = TBaseType.rw_for1;
3153                        }
3154                    }
3155
3156                    if (asourcetoken.tokencode == TBaseType.rrw_dense_rank){
3157                        //keep keyword can be column alias, make keep in keep_denserankclause as a different token code
3158                        TSourceToken stKeep  = asourcetoken.searchToken(TBaseType.rrw_keep,-2);
3159                        if ( stKeep != null){
3160                            stKeep.tokencode = TBaseType.rrw_keep_before_dense_rank;
3161                        }
3162                    }
3163
3164                    if ((asourcetoken.tokencode == TBaseType.rrw_postgresql_rowtype)||(asourcetoken.tokencode == TBaseType.rrw_postgresql_type)) {
3165                        TSourceToken stPercent = asourcetoken.searchToken('%', -1);
3166                        if (stPercent != null) {
3167                            stPercent.tokencode = TBaseType.rowtype_operator;
3168                        }
3169                    }
3170
3171                    if (asourcetoken.tokencode == TBaseType.JSON_EXIST) {
3172                        TSourceToken stPercent = asourcetoken.searchToken('=', -1);
3173                        if (stPercent != null) {    // = ?, ? after = should not be treated as json exist operator
3174                            asourcetoken.tokencode = TBaseType.ident;
3175                        }
3176                    }
3177
3178                    if (asourcetoken.tokencode == TBaseType.rrw_update) { // on conflict do update in insert statement
3179                        TSourceToken stDo = asourcetoken.searchToken(TBaseType.rrw_do, -1);
3180                        if (stDo != null) {
3181                            asourcetoken.tokencode = TBaseType.rrw_postgresql_do_update;
3182                        }
3183                    }
3184
3185
3186                }
3187            }
3188
3189            //flexer.yylexwrap(asourcetoken);
3190            asourcetoken = getanewsourcetoken();
3191            if (asourcetoken != null){
3192                yychar = asourcetoken.tokencode;
3193            }else{
3194                yychar = 0;
3195
3196                if (waitingreturnforfloatdiv)
3197                { // / at the end of line treat as sqlplus command
3198                    //isvalidplace = true;
3199                    lct.tokencode = TBaseType.sqlpluscmd;
3200                    if (lct.tokentype != ETokenType.ttslash){
3201                        lct.tokentype = ETokenType.ttsqlpluscmd;
3202                    }
3203                }
3204
3205            }
3206
3207            if ((yychar == 0) && (prevst != null))
3208            {
3209                if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER"))
3210                { prevst.tokencode = TBaseType.ident;}
3211            }
3212
3213
3214        }
3215
3216
3217    }
3218
3219void dosnowflakesqltexttotokenlist(){
3220
3221    boolean insqlpluscmd = false;
3222    boolean isvalidplace = true;
3223    boolean waitingreturnforfloatdiv = false;
3224    boolean waitingreturnforsemicolon = false;
3225    boolean continuesqlplusatnewline = false;
3226
3227    TSourceToken lct = null, prevst = null;
3228
3229    TSourceToken asourcetoken,lcprevst;
3230    int yychar;
3231
3232    asourcetoken = getanewsourcetoken();
3233    if ( asourcetoken == null ) return;
3234    yychar = asourcetoken.tokencode;
3235
3236    while (yychar > 0)
3237      {
3238        sourcetokenlist.add(asourcetoken);
3239        switch(yychar){
3240            case TBaseType.cmtdoublehyphen:
3241            case TBaseType.cmtslashstar:
3242            case TBaseType.lexspace:{
3243               if (insqlpluscmd){
3244                   asourcetoken.insqlpluscmd = true;
3245               }
3246               break;
3247            }
3248            case TBaseType.lexnewline:{
3249                if (insqlpluscmd){
3250                    insqlpluscmd = false;
3251                    isvalidplace = true;
3252
3253                    if (continuesqlplusatnewline) {
3254                        insqlpluscmd = true;
3255                        isvalidplace = false;
3256                        asourcetoken.insqlpluscmd = true ;
3257                    }
3258                }
3259
3260                if (waitingreturnforsemicolon){
3261                  isvalidplace = true;
3262                }
3263                if (waitingreturnforfloatdiv)
3264                {
3265                    isvalidplace = true;
3266                    lct.tokencode = TBaseType.sqlpluscmd;
3267                    if (lct.tokentype != ETokenType.ttslash){
3268                      lct.tokentype = ETokenType.ttsqlpluscmd;
3269                    }
3270                }
3271                flexer.insqlpluscmd = insqlpluscmd;
3272                break;
3273            } //case newline
3274            default:{
3275                //solid tokentext
3276                continuesqlplusatnewline = false;
3277                waitingreturnforsemicolon = false;
3278                waitingreturnforfloatdiv = false;
3279                if (insqlpluscmd)
3280                {
3281                    asourcetoken.insqlpluscmd = true ;
3282                    if (asourcetoken.getAstext().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;}
3283                }
3284                else
3285                {
3286                    if (asourcetoken.tokentype == ETokenType.ttsemicolon)
3287                    {waitingreturnforsemicolon = true;}
3288                    if ( (asourcetoken.tokentype == ETokenType.ttslash)
3289                      // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then
3290                       && (isvalidplace ||  (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) )
3291                    {
3292                        lct = asourcetoken;
3293                        waitingreturnforfloatdiv = true;
3294                    }
3295                    if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) )
3296                    {
3297                        asourcetoken.tokencode = TBaseType.sqlpluscmd;
3298                        if (asourcetoken.tokentype != ETokenType.ttslash)
3299                        {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;}
3300                        insqlpluscmd = true;
3301                        flexer.insqlpluscmd = insqlpluscmd;
3302                    }
3303                }
3304                isvalidplace = false;
3305
3306                // the inner keyword tokentext should be convert to TBaseType.ident when
3307                // next solid tokentext is not join
3308
3309                 if (prevst != null)
3310                 {
3311                    if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER"))
3312                    {
3313                        if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN"))
3314                        {prevst.tokencode = TBaseType.ident;}
3315                    }
3316
3317
3318                    if ((prevst.tokencode == TBaseType.rrw_not)
3319                    && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE")))
3320                    {
3321                          prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE");
3322                    }
3323
3324                 }
3325
3326                if (asourcetoken.tokencode == TBaseType.rrw_inner)
3327                {
3328                    prevst = asourcetoken;
3329                }
3330                else if (asourcetoken.tokencode == TBaseType.rrw_not)
3331                {
3332                     prevst = asourcetoken;
3333                }
3334                else
3335                { prevst = null;}
3336
3337
3338            }
3339        }
3340
3341         //flexer.yylexwrap(asourcetoken);
3342         asourcetoken = getanewsourcetoken();
3343         if (asourcetoken != null){
3344             yychar = asourcetoken.tokencode;
3345         }else{
3346           yychar = 0;
3347
3348             if (waitingreturnforfloatdiv)
3349             { // / at the end of line treat as sqlplus command
3350                 //isvalidplace = true;
3351                 lct.tokencode = TBaseType.sqlpluscmd;
3352                 if (lct.tokentype != ETokenType.ttslash){
3353                   lct.tokentype = ETokenType.ttsqlpluscmd;
3354                 }
3355             }
3356
3357         }
3358
3359          if ((yychar == 0) && (prevst != null))
3360          {
3361              if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER"))
3362              { prevst.tokencode = TBaseType.ident;}
3363          }
3364
3365
3366      } // while
3367
3368
3369}
3370
3371    void doverticatexttotokenlist(){
3372        dopostgresqltexttotokenlist();
3373    }
3374
3375    void docouchbasesqltexttotokenlist(){
3376        dopostgresqltexttotokenlist();
3377    }
3378
3379    void doclickhousesqltexttotokenlist(){
3380        dopostgresqltexttotokenlist();
3381    }
3382
3383    /**
3384     * Turn one token: `schema.table_name` into 3 tokens: `schema` . `table_name`
3385     * @param asourcetoken
3386     * @return
3387     */
3388    int splitQualifiedNameInBacktick(TSourceToken asourcetoken){
3389        int yychar = 0;
3390
3391        List<String> elephantList = Arrays.asList(TBaseType.getTextWithoutQuoted(asourcetoken.toString()).split("\\."));
3392        int p = 0,offset=0;
3393        for(String s:elephantList){
3394            TSourceToken pst = new TSourceToken("`"+s+"`");
3395            pst.tokencode = asourcetoken.tokencode;
3396            pst.tokentype =  asourcetoken.tokentype;
3397            pst.tokenstatus = asourcetoken.tokenstatus;
3398            pst.lineNo = asourcetoken.lineNo;
3399            pst.columnNo = asourcetoken.columnNo+offset;
3400            if (p==0) offset++;// this count the first ` token
3401            offset = offset+s.length();
3402            pst.container = sourcetokenlist;
3403            if (p>0){// 第一个token使用被拆分前那个token的位置,从第二个开始的token,需要先把列表的位置指针加 1
3404                sourcetokenlist.curpos = sourcetokenlist.curpos+1;
3405            }
3406            pst.posinlist = sourcetokenlist.curpos;
3407
3408            sourcetokenlist.add(pst);
3409            yychar = pst.tokencode;
3410
3411            if (p != elephantList.size()-1){
3412                //`schema.table_name`, add period token in the middle of the backtick included identifier.
3413                TSourceToken periodst = new TSourceToken(".");
3414                periodst.tokencode = '.';
3415                periodst.tokentype =  ETokenType.ttperiod;
3416                periodst.tokenstatus = asourcetoken.tokenstatus;
3417                periodst.lineNo = asourcetoken.lineNo;
3418                periodst.columnNo = asourcetoken.columnNo + offset;
3419                offset++;
3420                periodst.container = sourcetokenlist;
3421                sourcetokenlist.curpos = sourcetokenlist.curpos+1;
3422                periodst.posinlist = sourcetokenlist.curpos;
3423                sourcetokenlist.add(periodst);
3424                yychar = periodst.tokencode;
3425            }
3426
3427            p++;
3428            //System.out.println(s);
3429        }
3430
3431        return yychar;
3432
3433    }
3434
3435    void dobigquerysqltexttotokenlist(){
3436        TSourceToken asourcetoken,lcprevst;
3437        int yychar;
3438
3439
3440        flexer.tmpDelimiter = "";
3441
3442        asourcetoken = getanewsourcetoken();
3443        if ( asourcetoken == null ) return;
3444        yychar = asourcetoken.tokencode;
3445
3446        while (yychar > 0)
3447        {
3448            if (asourcetoken != null){
3449                sourcetokenlist.add(asourcetoken);
3450            }
3451
3452            asourcetoken = getanewsourcetoken();
3453            if ( asourcetoken == null ) break;
3454            yychar = asourcetoken.tokencode;
3455
3456            // `schema.table_name`
3457            if ((asourcetoken.tokencode == TBaseType.ident)
3458                    && (asourcetoken.toString().startsWith("`"))&& (asourcetoken.toString().endsWith("`"))
3459                    && (asourcetoken.toString().indexOf(".")>0)
3460            ){
3461                yychar = splitQualifiedNameInBacktick(asourcetoken);
3462                asourcetoken = null;
3463            }
3464        }
3465    }
3466
3467    void dosoqlsqltexttotokenlist(){
3468        domssqlsqltexttotokenlist();
3469    }
3470
3471void dogreenplumtexttotokenlist(){
3472
3473        boolean insqlpluscmd = false;
3474        boolean isvalidplace = true;
3475        boolean waitingreturnforfloatdiv = false;
3476        boolean waitingreturnforsemicolon = false;
3477        boolean continuesqlplusatnewline = false;
3478
3479        TSourceToken lct = null, prevst = null;
3480
3481        TSourceToken asourcetoken,lcprevst;
3482        int yychar;
3483
3484        asourcetoken = getanewsourcetoken();
3485        if ( asourcetoken == null ) return;
3486        yychar = asourcetoken.tokencode;
3487
3488        while (yychar > 0)
3489          {
3490            sourcetokenlist.add(asourcetoken);
3491            switch(yychar){
3492                case TBaseType.cmtdoublehyphen:
3493                case TBaseType.cmtslashstar:
3494                case TBaseType.lexspace:{
3495                   if (insqlpluscmd){
3496                       asourcetoken.insqlpluscmd = true;
3497                   }
3498                   break;
3499                }
3500                case TBaseType.lexnewline:{
3501                    if (insqlpluscmd){
3502                        insqlpluscmd = false;
3503                        isvalidplace = true;
3504
3505                        if (continuesqlplusatnewline) {
3506                            insqlpluscmd = true;
3507                            isvalidplace = false;
3508                            asourcetoken.insqlpluscmd = true ;
3509                        }
3510                    }
3511
3512                    if (waitingreturnforsemicolon){
3513                      isvalidplace = true;
3514                    }
3515                    if (waitingreturnforfloatdiv)
3516                    {
3517                        isvalidplace = true;
3518                        lct.tokencode = TBaseType.sqlpluscmd;
3519                        if (lct.tokentype != ETokenType.ttslash){
3520                          lct.tokentype = ETokenType.ttsqlpluscmd;
3521                        }
3522                    }
3523                    flexer.insqlpluscmd = insqlpluscmd;
3524                    break;
3525                } //case newline
3526                default:{
3527                    //solid tokentext
3528                    continuesqlplusatnewline = false;
3529                    waitingreturnforsemicolon = false;
3530                    waitingreturnforfloatdiv = false;
3531                    if (insqlpluscmd)
3532                    {
3533                        asourcetoken.insqlpluscmd = true ;
3534                        if (asourcetoken.toString().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;}
3535                    }
3536                    else
3537                    {
3538                        if (asourcetoken.tokentype == ETokenType.ttsemicolon)
3539                        {waitingreturnforsemicolon = true;}
3540                        if ( (asourcetoken.tokentype == ETokenType.ttslash)
3541                          // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then
3542                           && (isvalidplace ||  (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) )
3543                        {
3544                            lct = asourcetoken;
3545                            waitingreturnforfloatdiv = true;
3546                        }
3547                        if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) )
3548                        {
3549                            asourcetoken.tokencode = TBaseType.sqlpluscmd;
3550                            if (asourcetoken.tokentype != ETokenType.ttslash)
3551                            {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;}
3552                            insqlpluscmd = true;
3553                            flexer.insqlpluscmd = insqlpluscmd;
3554                        }
3555                    }
3556                    isvalidplace = false;
3557
3558                    // the inner keyword tokentext should be convert to TBaseType.ident when
3559                    // next solid tokentext is not join
3560
3561                     if (prevst != null)
3562                     {
3563                        if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER"))
3564                        {
3565                            if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN"))
3566                            {prevst.tokencode = TBaseType.ident;}
3567                        }
3568
3569
3570                        if ((prevst.tokencode == TBaseType.rrw_not)
3571                        && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE")))
3572                        {
3573                              prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE");
3574                        }
3575
3576                     }
3577
3578                    if (asourcetoken.tokencode == TBaseType.rrw_inner)
3579                    {
3580                        prevst = asourcetoken;
3581                    }
3582                    else if (asourcetoken.tokencode == TBaseType.rrw_not)
3583                    {
3584                         prevst = asourcetoken;
3585                    }
3586                    else
3587                    { prevst = null;}
3588
3589                    if ((asourcetoken.tokencode == flexer.getkeywordvalue("DIRECT_LOAD"))
3590                    ||  (asourcetoken.tokencode == flexer.getkeywordvalue("ALL")) )
3591                    {
3592                        // RW_COMPRESS RW_FOR RW_ALL RW_OPERATIONS
3593                        // RW_COMPRESS RW_FOR RW_DIRECT_LOAD RW_OPERATIONS
3594                        // change rw_for to TBaseType.rw_for1, it conflicts with compress for update in create materialized view
3595
3596                        lcprevst = getprevsolidtoken(asourcetoken);
3597                        if (lcprevst != null)
3598                        {
3599                            if (lcprevst.tokencode == TBaseType.rrw_for)
3600                              lcprevst.tokencode = TBaseType.rw_for1;
3601                        }
3602                    }
3603
3604                    if (asourcetoken.tokencode == TBaseType.rrw_dense_rank){
3605                        //keep keyword can be column alias, make keep in keep_denserankclause as a different token code
3606                        TSourceToken stKeep  = asourcetoken.searchToken(TBaseType.rrw_keep,-2);
3607                        if ( stKeep != null){
3608                            stKeep.tokencode = TBaseType.rrw_keep_before_dense_rank;
3609                        }
3610                    }
3611
3612                    if (asourcetoken.tokencode == TBaseType.rrw_greenplum_rowtype) {
3613                        TSourceToken stPercent = asourcetoken.searchToken('%', -1);
3614                        if (stPercent != null) {
3615                            stPercent.tokencode = TBaseType.rowtype_operator;
3616                        }
3617                    }
3618
3619
3620                }
3621            }
3622
3623             //flexer.yylexwrap(asourcetoken);
3624             asourcetoken = getanewsourcetoken();
3625             if (asourcetoken != null){
3626                 yychar = asourcetoken.tokencode;
3627             }else{
3628               yychar = 0;
3629
3630                 if (waitingreturnforfloatdiv)
3631                 { // / at the end of line treat as sqlplus command
3632                     //isvalidplace = true;
3633                     lct.tokencode = TBaseType.sqlpluscmd;
3634                     if (lct.tokentype != ETokenType.ttslash){
3635                       lct.tokentype = ETokenType.ttsqlpluscmd;
3636                     }
3637                 }
3638
3639             }
3640
3641              if ((yychar == 0) && (prevst != null))
3642              {
3643                  if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER"))
3644                  { prevst.tokencode = TBaseType.ident;}
3645              }
3646
3647
3648          }
3649
3650
3651    }
3652
3653void donetezzatexttotokenlist(){
3654
3655    boolean insqlpluscmd = false;
3656    boolean isvalidplace = true;
3657    boolean waitingreturnforfloatdiv = false;
3658    boolean waitingreturnforsemicolon = false;
3659    boolean continuesqlplusatnewline = false;
3660
3661    TSourceToken lct = null, prevst = null;
3662
3663    TSourceToken asourcetoken,lcprevst;
3664    int yychar;
3665
3666    asourcetoken = getanewsourcetoken();
3667    if ( asourcetoken == null ) return;
3668    yychar = asourcetoken.tokencode;
3669
3670    while (yychar > 0)
3671      {
3672        sourcetokenlist.add(asourcetoken);
3673        switch(yychar){
3674            case TBaseType.cmtdoublehyphen:
3675            case TBaseType.cmtslashstar:
3676            case TBaseType.lexspace:{
3677               if (insqlpluscmd){
3678                   asourcetoken.insqlpluscmd = true;
3679               }
3680               break;
3681            }
3682            case TBaseType.lexnewline:{
3683                if (insqlpluscmd){
3684                    insqlpluscmd = false;
3685                    isvalidplace = true;
3686
3687                    if (continuesqlplusatnewline) {
3688                        insqlpluscmd = true;
3689                        isvalidplace = false;
3690                        asourcetoken.insqlpluscmd = true ;
3691                    }
3692                }
3693
3694                if (waitingreturnforsemicolon){
3695                  isvalidplace = true;
3696                }
3697                if (waitingreturnforfloatdiv)
3698                {
3699                    isvalidplace = true;
3700                    lct.tokencode = TBaseType.sqlpluscmd;
3701                    if (lct.tokentype != ETokenType.ttslash){
3702                      lct.tokentype = ETokenType.ttsqlpluscmd;
3703                    }
3704                }
3705                flexer.insqlpluscmd = insqlpluscmd;
3706                break;
3707            } //case newline
3708            default:{
3709                //solid tokentext
3710                continuesqlplusatnewline = false;
3711                waitingreturnforsemicolon = false;
3712                waitingreturnforfloatdiv = false;
3713                if (insqlpluscmd)
3714                {
3715                    asourcetoken.insqlpluscmd = true ;
3716                    if (asourcetoken.getAstext().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;}
3717                }
3718                else
3719                {
3720                    if (asourcetoken.tokentype == ETokenType.ttsemicolon)
3721                    {waitingreturnforsemicolon = true;}
3722                    if ( (asourcetoken.tokentype == ETokenType.ttslash)
3723                      // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then
3724                       && (isvalidplace ||  (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) )
3725                    {
3726                        lct = asourcetoken;
3727                        waitingreturnforfloatdiv = true;
3728                    }
3729                    if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) )
3730                    {
3731                        asourcetoken.tokencode = TBaseType.sqlpluscmd;
3732                        if (asourcetoken.tokentype != ETokenType.ttslash)
3733                        {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;}
3734                        insqlpluscmd = true;
3735                        flexer.insqlpluscmd = insqlpluscmd;
3736                    }
3737                }
3738                isvalidplace = false;
3739
3740                // the inner keyword tokentext should be convert to TBaseType.ident when
3741                // next solid tokentext is not join
3742
3743                 if (prevst != null)
3744                 {
3745                    if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER"))
3746                    {
3747                        if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN"))
3748                        {prevst.tokencode = TBaseType.ident;}
3749                    }
3750
3751
3752                    if ((prevst.tokencode == TBaseType.rrw_not)
3753                    && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE")))
3754                    {
3755                          prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE");
3756                    }
3757
3758                 }
3759
3760                if (asourcetoken.tokencode == TBaseType.rrw_inner)
3761                {
3762                    prevst = asourcetoken;
3763                }
3764                else if (asourcetoken.tokencode == TBaseType.rrw_not)
3765                {
3766                     prevst = asourcetoken;
3767                }
3768                else
3769                { prevst = null;}
3770
3771                if ((asourcetoken.tokencode == flexer.getkeywordvalue("DIRECT_LOAD"))
3772                ||  (asourcetoken.tokencode == flexer.getkeywordvalue("ALL")) )
3773                {
3774                    // RW_COMPRESS RW_FOR RW_ALL RW_OPERATIONS
3775                    // RW_COMPRESS RW_FOR RW_DIRECT_LOAD RW_OPERATIONS
3776                    // change rw_for to TBaseType.rw_for1, it conflicts with compress for update in create materialized view
3777
3778                    lcprevst = getprevsolidtoken(asourcetoken);
3779                    if (lcprevst != null)
3780                    {
3781                        if (lcprevst.tokencode == TBaseType.rrw_for)
3782                          lcprevst.tokencode = TBaseType.rw_for1;
3783                    }
3784                }
3785
3786                if (asourcetoken.tokencode == TBaseType.rrw_dense_rank){
3787                    //keep keyword can be column alias, make keep in keep_denserankclause as a different token code
3788                    TSourceToken stKeep  = asourcetoken.searchToken(TBaseType.rrw_keep,-2);
3789                    if ( stKeep != null){
3790                        stKeep.tokencode = TBaseType.rrw_keep_before_dense_rank;
3791                    }
3792                }
3793
3794
3795            }
3796        }
3797
3798         //flexer.yylexwrap(asourcetoken);
3799         asourcetoken = getanewsourcetoken();
3800         if (asourcetoken != null){
3801             yychar = asourcetoken.tokencode;
3802         }else{
3803           yychar = 0;
3804
3805             if (waitingreturnforfloatdiv)
3806             { // / at the end of line treat as sqlplus command
3807                 //isvalidplace = true;
3808                 lct.tokencode = TBaseType.sqlpluscmd;
3809                 if (lct.tokentype != ETokenType.ttslash){
3810                   lct.tokentype = ETokenType.ttsqlpluscmd;
3811                 }
3812             }
3813
3814         }
3815
3816          if ((yychar == 0) && (prevst != null))
3817          {
3818              if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER"))
3819              { prevst.tokencode = TBaseType.ident;}
3820          }
3821
3822
3823      }
3824}
3825
3826private boolean spaceAtTheEndOfReturnToken(String s){
3827    int pos = 0;
3828    if (s == null) return false;
3829    if (s.length() == 0) return false;
3830
3831    return ((s.charAt(s.length() -1 ) == ' ')||(s.charAt(s.length() -1 ) == '\t'));
3832}
3833
3834private int countLines(String s){
3835    int pos = 0, lf = 0, cr = 0;
3836
3837    while (pos < s.length()) {
3838        if (s.charAt(pos) == '\r') {
3839            cr++;
3840            pos++;
3841            continue;
3842        }
3843        if (s.charAt(pos) == '\n') {
3844            lf++;
3845            pos++;
3846            continue;
3847        }
3848
3849        if (s.charAt(pos) == ' ') {
3850            pos++;
3851            continue;
3852        }
3853        break;
3854    }
3855
3856    if (lf >= cr) return lf;
3857    else return  cr;
3858
3859 }
3860
3861
3862void dodb2sqltexttotokenlist(){
3863// treat echo, ! of db2 at the begin of each line as
3864// oracle sqlplus command
3865
3866    boolean insqlpluscmd = false;
3867    boolean isvalidplace = true;
3868    int jdbc_escape_nest = 0;
3869//  isSolidTokenStart := false;
3870
3871//  tempsourcetokenlist.clear;
3872
3873    TSourceToken asourcetoken,lcprevst;
3874    int yychar;
3875
3876    asourcetoken = getanewsourcetoken();
3877    
3878    if ( asourcetoken == null ) return;
3879    yychar = asourcetoken.tokencode;
3880
3881
3882    while (yychar > 0)
3883    {
3884
3885        switch (yychar){
3886          case TBaseType.lexnewline:
3887          {
3888              insqlpluscmd = false;
3889              isvalidplace = true;
3890              break;
3891          }
3892          case TBaseType.cmtdoublehyphen:
3893          {
3894              if (asourcetoken.toString().toLowerCase().indexOf("scriptoptions")>=0)
3895              {
3896                  asourcetoken.tokencode = TBaseType.scriptoptions;
3897                  asourcetoken.tokentype = ETokenType.ttidentifier;
3898              }
3899
3900              if (insqlpluscmd)
3901              {
3902                  asourcetoken.insqlpluscmd = true;
3903              }
3904            break;
3905          }
3906          case TBaseType.rrw_jdbc_escape_fn: {
3907              jdbc_escape_nest++;
3908              asourcetoken.tokencode = TBaseType.lexspace;
3909            break;
3910          }
3911          case TBaseType.rrw_jdbc_escape_end: {
3912                jdbc_escape_nest--;
3913                asourcetoken.tokencode = TBaseType.lexspace;
3914                break;
3915          }
3916          default: //solid tokentext
3917          {
3918              if ((asourcetoken.tokencode == TBaseType.rrw_rr)
3919                    || (asourcetoken.tokencode ==  TBaseType.rrw_rs)
3920                    || (asourcetoken.tokencode ==  TBaseType.rrw_cs)
3921                    || (asourcetoken.tokencode ==  TBaseType.rrw_ur)
3922                  )
3923              {
3924                 // change with keyword in isolation clause to rrw_with_isolation
3925                  // so opt_restriction_clause in create view worked correctly
3926                  lcprevst = getprevsolidtoken(asourcetoken);
3927                  if (lcprevst != null)
3928                  {
3929                      if (lcprevst.tokencode == TBaseType.rrw_with)
3930                        lcprevst.tokencode = TBaseType.rrw_with_isolation;
3931                  }
3932              }
3933
3934              if (insqlpluscmd)
3935              {
3936                  //asourcetoken.TokenCode := TBaseType.sqlpluscmd;
3937                  asourcetoken.insqlpluscmd = true;
3938              }
3939              else
3940              {
3941                  if (isvalidplace){
3942                   // System.out.println(asourcetoken.astext);
3943                  if (TBaseType.mycomparetext(asourcetoken.toString().toLowerCase(),"echo") == 0 )
3944                  {
3945                     // System.out.println("finded ");
3946                      asourcetoken.tokencode = TBaseType.sqlpluscmd;
3947                      if (asourcetoken.tokentype != ETokenType.ttslash)
3948                      {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;}
3949                      asourcetoken.insqlpluscmd = true;
3950                      insqlpluscmd = true;
3951                  }
3952                }
3953              }
3954              isvalidplace = false;
3955
3956              break;
3957          } //end of solid tokentext
3958        } //switch
3959
3960//  TBaseType.lexnewline
3961
3962        sourcetokenlist.add(asourcetoken);
3963
3964        asourcetoken = getanewsourcetoken();
3965        if ( asourcetoken == null ) break;
3966        yychar = asourcetoken.tokencode;
3967
3968    } //while
3969
3970}
3971
3972    void doteradatatexttotokenlist(){
3973
3974        TSourceToken asourcetoken,lcprevst;
3975        int yychar;
3976
3977        asourcetoken = getanewsourcetoken();
3978        if ( asourcetoken == null ) return;
3979        yychar = asourcetoken.tokencode;
3980
3981        while (yychar > 0)
3982        {
3983            sourcetokenlist.add(asourcetoken);
3984            asourcetoken = getanewsourcetoken();
3985            if ( asourcetoken == null ) break;
3986
3987            if ((asourcetoken.tokencode == TBaseType.rrw_casespecific)
3988                ||(asourcetoken.tokencode == TBaseType.rrw_teradata_cs))
3989            {
3990                    /* change not to not1 to make "not null column constriants" work correctly */
3991                //      |RW_NOT1 RW_CASESPECIFIC
3992
3993                lcprevst = getprevsolidtoken(asourcetoken);
3994                if (lcprevst != null)
3995                {
3996                    if (lcprevst.tokencode == TBaseType.rrw_not)
3997                      lcprevst.tokencode = TBaseType.rw_not1;
3998                }
3999            } else if (asourcetoken.tokencode == ';'){
4000                lcprevst = getprevsolidtoken(asourcetoken);
4001                if (lcprevst != null)
4002                {
4003                    if (lcprevst.tokencode == ';')
4004                        asourcetoken.tokencode = TBaseType.sqlpluscmd;
4005                }
4006            } else if (asourcetoken.tokencode == TBaseType.variable){ // mantisbt/view.php?id=972
4007                if (asourcetoken.toString().toLowerCase().endsWith("begin")){ //MYPROC :BEGIN
4008                    asourcetoken.tokencode = TBaseType.rrw_begin;
4009                    asourcetoken.tokentype = ETokenType.ttkeyword;
4010
4011                    lcprevst = getprevsolidtoken(asourcetoken);
4012                    if (lcprevst != null)
4013                    {
4014                        lcprevst.tokencode = TBaseType.mslabel;
4015                    }
4016
4017                }
4018            }else if (asourcetoken.tokencode == TCustomLexer.UNICODE_ENCODE_ID){
4019                if (asourcetoken.toString().endsWith("008D")){ // REVERSE LINE FEED, https://codepoints.net/U+008D?lang=en
4020                    asourcetoken.tokencode = TBaseType.lexspace;
4021                }else{
4022                    asourcetoken.tokencode = TBaseType.ident;
4023                }
4024            }
4025
4026
4027            yychar = asourcetoken.tokencode;
4028        }
4029
4030    }
4031
4032void  docommonsqltexttotokenlist(){
4033
4034    TSourceToken asourcetoken,lcprevst;
4035    int yychar;
4036
4037    asourcetoken = getanewsourcetoken();
4038    if ( asourcetoken == null ) return;
4039    yychar = asourcetoken.tokencode;
4040
4041    while (yychar > 0)
4042    {
4043        sourcetokenlist.add(asourcetoken);
4044        asourcetoken = getanewsourcetoken();
4045        if ( asourcetoken == null ) break;
4046        yychar = asourcetoken.tokencode;
4047    }
4048
4049}
4050    void  doodbcsqltexttotokenlist(){
4051        boolean insideODBC = false;
4052        TSourceToken odbcPrefix = null;
4053        domssqlsqltexttotokenlist();
4054        for (int i=0 ; i<sourcetokenlist.size();i++) {
4055            TSourceToken ast = sourcetokenlist.get(i);
4056            if ((ast.tokencode == '{')||(ast.tokencode == TBaseType.odbc_esc_prefix))
4057            {
4058                insideODBC = true;
4059                odbcPrefix = ast;
4060            }
4061            if ((ast.tokencode == '}')||(ast.tokencode == TBaseType.odbc_esc_terminator))
4062            {
4063                insideODBC = false;
4064                odbcPrefix = null;
4065            }
4066            if (((ast.tokencode == TBaseType.rrw_odbc_d)
4067                    ||(ast.tokencode == TBaseType.rrw_odbc_t)
4068                    ||(ast.tokencode == TBaseType.rrw_odbc_ts)
4069                    ||(ast.tokencode == TBaseType.rrw_odbc_fn)
4070                    ||(ast.tokencode == TBaseType.rrw_odbc_oj)
4071                )&&(!insideODBC)) {
4072                ast.tokencode = TBaseType.ident;
4073            }
4074
4075            if ((ast.tokencode == TBaseType.rrw_call)&&(insideODBC)){
4076                odbcPrefix.setLinkToken(ast);
4077            }
4078        }
4079    }
4080
4081void  dodaxsqltexttotokenlist(){
4082
4083    TSourceToken asourcetoken,lcprevst;
4084    int yychar;
4085
4086    asourcetoken = getanewsourcetoken();
4087    if ( asourcetoken == null ) return;
4088    yychar = asourcetoken.tokencode;
4089
4090    while (yychar > 0)
4091    {
4092        sourcetokenlist.add(asourcetoken);
4093        asourcetoken = getanewsourcetoken();
4094        if ( asourcetoken == null ) break;
4095        yychar = asourcetoken.tokencode;
4096    }
4097
4098}
4099
4100
4101void  dohanasqltexttotokenlist(){
4102
4103    TSourceToken asourcetoken,lcprevst;
4104    int yychar;
4105
4106    asourcetoken = getanewsourcetoken();
4107    if ( asourcetoken == null ) return;
4108    yychar = asourcetoken.tokencode;
4109
4110    while (yychar > 0)
4111    {
4112        sourcetokenlist.add(asourcetoken);
4113        asourcetoken = getanewsourcetoken();
4114        if ( asourcetoken == null ) break;
4115        yychar = asourcetoken.tokencode;
4116    }
4117
4118}
4119
4120void  dohivetexttotokenlist(){
4121
4122    TSourceToken asourcetoken,lcprevst;
4123    int yychar;
4124
4125    asourcetoken = getanewsourcetoken();
4126    if ( asourcetoken == null ) return;
4127    yychar = asourcetoken.tokencode;
4128
4129    while (yychar > 0)
4130    {
4131        if (asourcetoken != null){
4132            sourcetokenlist.add(asourcetoken);
4133        }
4134        asourcetoken = getanewsourcetoken();
4135        if ( asourcetoken == null ) break;
4136        if (asourcetoken.tokencode == TBaseType.rrw_map){
4137            TSourceToken token = asourcetoken.searchToken(')',-1);
4138            if (token != null){
4139                asourcetoken.tokencode = TBaseType.ident;
4140            }
4141        }else if (asourcetoken.tokencode == '('){
4142//            TSourceToken token = asourcetoken.searchToken(TBaseType.ident,-1);
4143//            if (token != null){
4144//                token.tokencode = TBaseType.HIVE_FUNC_IDENT;
4145//            }
4146        }
4147        yychar = asourcetoken.tokencode;
4148
4149        // `schema.table_name`
4150        if ((asourcetoken.tokencode == TBaseType.ident)
4151                && (asourcetoken.toString().startsWith("`"))&& (asourcetoken.toString().endsWith("`"))
4152                && (asourcetoken.toString().indexOf(".")>0)
4153        ){
4154            yychar = splitQualifiedNameInBacktick(asourcetoken);
4155            asourcetoken = null;
4156        }
4157
4158    }
4159
4160}
4161
4162void  doimpalatexttotokenlist(){
4163    dohivetexttotokenlist();
4164}
4165
4166void checkMySQLCommentToken(TSourceToken cmtToken){
4167//    if (cmtToken.tokencode == TBaseType.cmtdoublehyphen){
4168//        if ((cmtToken.toString().startsWith("--"))){
4169//            if (cmtToken.toString().length() > 2){
4170//                if (cmtToken.toString().charAt(2) != ' '){
4171//                   this.syntaxErrors.add(new TSyntaxError(cmtToken.toString(),
4172//                           cmtToken.lineNo,
4173//                           cmtToken.columnNo,
4174//                           "requires a space after the initial \"--\" ",EErrorType.sperror,10010
4175//                           ));
4176//                }
4177//            }
4178//            // there should be
4179//        }
4180//    }
4181}
4182    void dosparksqltexttotokenlist(){
4183        TSourceToken asourcetoken,lcprevst;
4184        int yychar;
4185        boolean startDelimiter = false;
4186
4187        flexer.tmpDelimiter = "";
4188
4189        asourcetoken = getanewsourcetoken();
4190        if ( asourcetoken == null ) return;
4191        yychar = asourcetoken.tokencode;
4192
4193
4194
4195
4196        while (yychar > 0)
4197        {
4198            sourcetokenlist.add(asourcetoken);
4199            asourcetoken = getanewsourcetoken();
4200            if ( asourcetoken == null ) break;
4201            checkMySQLCommentToken(asourcetoken);
4202
4203            if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){
4204                startDelimiter = false;
4205                flexer.tmpDelimiter  = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext();
4206            }
4207
4208
4209            if (asourcetoken.tokencode == TBaseType.rrw_rollup)
4210            {
4211                //      with rollup
4212
4213                lcprevst = getprevsolidtoken(asourcetoken);
4214                if (lcprevst != null)
4215                {
4216                    if (lcprevst.tokencode == TBaseType.rrw_with)
4217                        lcprevst.tokencode = TBaseType.with_rollup;
4218                }
4219            }
4220
4221            yychar = asourcetoken.tokencode;
4222        }
4223
4224    }
4225
4226    void doathenatexttotokenlist(){
4227        TSourceToken asourcetoken,lcprevst;
4228        int yychar;
4229        boolean startDelimiter = false;
4230
4231        flexer.tmpDelimiter = "";
4232
4233        asourcetoken = getanewsourcetoken();
4234        if ( asourcetoken == null ) return;
4235        yychar = asourcetoken.tokencode;
4236
4237
4238
4239
4240        while (yychar > 0)
4241        {
4242            sourcetokenlist.add(asourcetoken);
4243            asourcetoken = getanewsourcetoken();
4244            if ( asourcetoken == null ) break;
4245            checkMySQLCommentToken(asourcetoken);
4246
4247            if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){
4248                startDelimiter = false;
4249                flexer.tmpDelimiter  = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext();
4250            }
4251
4252
4253            yychar = asourcetoken.tokencode;
4254        }
4255
4256    }
4257
4258    void dodatabrickstexttotokenlist(){
4259        TSourceToken asourcetoken,lcprevst;
4260        int yychar;
4261        boolean startDelimiter = false;
4262
4263        flexer.tmpDelimiter = "";
4264
4265        asourcetoken = getanewsourcetoken();
4266        if ( asourcetoken == null ) return;
4267        yychar = asourcetoken.tokencode;
4268
4269
4270
4271
4272        while (yychar > 0)
4273        {
4274            sourcetokenlist.add(asourcetoken);
4275            asourcetoken = getanewsourcetoken();
4276            if ( asourcetoken == null ) break;
4277            checkMySQLCommentToken(asourcetoken);
4278
4279            if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){
4280                startDelimiter = false;
4281                flexer.tmpDelimiter  = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext();
4282            }
4283
4284
4285            yychar = asourcetoken.tokencode;
4286        }
4287
4288    }
4289    void doprestotexttotokenlist(){
4290        TSourceToken asourcetoken,lcprevst;
4291        int yychar;
4292        boolean startDelimiter = false;
4293
4294        flexer.tmpDelimiter = "";
4295
4296        asourcetoken = getanewsourcetoken();
4297        if ( asourcetoken == null ) return;
4298        yychar = asourcetoken.tokencode;
4299
4300
4301
4302
4303        while (yychar > 0)
4304        {
4305            sourcetokenlist.add(asourcetoken);
4306            asourcetoken = getanewsourcetoken();
4307            if ( asourcetoken == null ) break;
4308            checkMySQLCommentToken(asourcetoken);
4309
4310            if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){
4311                startDelimiter = false;
4312                flexer.tmpDelimiter  = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext();
4313            }
4314
4315
4316            yychar = asourcetoken.tokencode;
4317        }
4318
4319    }
4320
4321void  domysqltexttotokenlist(){
4322
4323        TSourceToken asourcetoken,lcprevst;
4324        int yychar;
4325        boolean startDelimiter = false;
4326
4327        flexer.tmpDelimiter = "";
4328
4329        asourcetoken = getanewsourcetoken();
4330        if ( asourcetoken == null ) return;
4331        yychar = asourcetoken.tokencode;
4332        checkMySQLCommentToken(asourcetoken);
4333
4334        if ((asourcetoken.tokencode == TBaseType.rrw_mysql_delimiter)){
4335            startDelimiter = true;
4336        }
4337
4338        while (yychar > 0)
4339        {
4340            sourcetokenlist.add(asourcetoken);
4341            asourcetoken = getanewsourcetoken();
4342            if ( asourcetoken == null ) break;
4343            checkMySQLCommentToken(asourcetoken);
4344
4345            if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){
4346                startDelimiter = false;
4347                flexer.tmpDelimiter  = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext();
4348            }
4349
4350            if ((asourcetoken.tokencode == TBaseType.rrw_mysql_delimiter)){
4351                startDelimiter = true;
4352            }
4353
4354            if (asourcetoken.tokencode == TBaseType.rrw_rollup)
4355            {
4356                //      with rollup
4357
4358                lcprevst = getprevsolidtoken(asourcetoken);
4359                if (lcprevst != null)
4360                {
4361                    if (lcprevst.tokencode == TBaseType.rrw_with)
4362                      lcprevst.tokencode = TBaseType.with_rollup;
4363                }
4364            }
4365
4366            if( (asourcetoken.tokencode == TBaseType.rrw_mysql_d)
4367                    ||(asourcetoken.tokencode == TBaseType.rrw_mysql_t)
4368                    ||(asourcetoken.tokencode == TBaseType.rrw_mysql_ts)
4369                    )
4370            {
4371                //      odbc date constant { d 'str' }
4372                lcprevst = getprevsolidtoken(asourcetoken);
4373                if (lcprevst != null)
4374                {
4375                    if (lcprevst.tokencode != '{')
4376                        asourcetoken.tokencode = TBaseType.ident;
4377                }
4378            }
4379
4380
4381            yychar = asourcetoken.tokencode;
4382        }
4383
4384    }
4385
4386void  doMdxtexttotokenlist(){
4387
4388    TSourceToken asourcetoken,lcprevst;
4389    int yychar;
4390
4391    asourcetoken = getanewsourcetoken();
4392    if ( asourcetoken == null ) return;
4393    yychar = asourcetoken.tokencode;
4394
4395    while (yychar > 0)
4396    {
4397        sourcetokenlist.add(asourcetoken);
4398        asourcetoken = getanewsourcetoken();
4399        if ( asourcetoken == null ) break;
4400        yychar = asourcetoken.tokencode;
4401    }
4402
4403}
4404
4405void dosqltexttotokenlist(){
4406    switch(dbVendor){
4407        case dbvmssql:
4408        case dbvazuresql:
4409         {
4410            domssqlsqltexttotokenlist();
4411            break;
4412        }
4413        case dbvinformix:{
4414            doinformixtexttotokenlist();
4415            break;
4416        }
4417        case dbvsybase:{
4418            dosybasesqltexttotokenlist();
4419            break;
4420        }
4421        case dbvdb2:{
4422            dodb2sqltexttotokenlist();
4423            break;
4424        }
4425        case dbvteradata:{
4426            doteradatatexttotokenlist();
4427            break;
4428        }
4429        case dbvpostgresql:{
4430            dopostgresqltexttotokenlist();
4431            break;
4432        }
4433        case dbvredshift:{
4434            doredshifttexttotokenlist();
4435            break;
4436        }
4437        case dbvgreenplum:{
4438            dogreenplumtexttotokenlist();
4439            break;
4440        }
4441        case dbvmdx: {
4442            doMdxtexttotokenlist();
4443            break;
4444        }
4445        case dbvnetezza:{
4446            donetezzatexttotokenlist();
4447            break;
4448        }
4449        case dbvhive:{
4450            dohivetexttotokenlist();
4451            break;
4452        }
4453        case dbvimpala:{
4454            doimpalatexttotokenlist();
4455            break;
4456        }
4457        case dbvmysql:{
4458            domysqltexttotokenlist();
4459            break;
4460        }
4461        case dbvhana:{
4462            dohanasqltexttotokenlist();
4463            break;
4464        }
4465        case dbvdax:{
4466            dodaxsqltexttotokenlist();
4467            break;
4468        }
4469        case dbvodbc:{
4470            doodbcsqltexttotokenlist();
4471            break;
4472        }
4473        case dbvvertica:{
4474            doverticatexttotokenlist();
4475            break;
4476        }
4477        case dbvopenedge:{
4478            domssqlsqltexttotokenlist();
4479            break;
4480        }
4481        case dbvcouchbase:{
4482            docouchbasesqltexttotokenlist();
4483            break;
4484        }
4485        case dbvsnowflake:{
4486            dosnowflakesqltexttotokenlist();
4487            break;
4488        }
4489        case dbvbigquery:{
4490            dobigquerysqltexttotokenlist();
4491            break;
4492        }
4493        case dbvclickhouse:{
4494            doclickhousesqltexttotokenlist();
4495            break;
4496        }
4497        case dbvsoql:{
4498            dosoqlsqltexttotokenlist();
4499            break;
4500        }
4501        case dbvsparksql:{
4502            dosparksqltexttotokenlist();
4503            break;
4504        }
4505        case dbvpresto:{
4506            doprestotexttotokenlist();
4507            break;
4508        }
4509        case dbvathena:{
4510            doathenatexttotokenlist();
4511            break;
4512        }
4513        case dbvdatabricks:{
4514            dodatabrickstexttotokenlist();
4515            break;
4516        }
4517        case dbvgaussdb:{
4518            dogaussdbtexttotokenlist();
4519            break;
4520        }
4521        case dbvansi:{
4522            doansitexttotokenlist();
4523            break;
4524        }
4525        default:{
4526            docommonsqltexttotokenlist();            
4527        }
4528    }
4529
4530    doAfterTokenize();
4531
4532    TBaseType.resetTokenChain(sourcetokenlist,0);
4533
4534    processTokensInTokenTable(dbVendor);
4535    processTokensBeforeParse(dbVendor);
4536
4537    closeFileStream();
4538
4539    if (tokenListHandle != null){
4540        tokenListHandle.processTokenList(sourcetokenlist);
4541    }
4542}
4543
4544void doAfterTokenize(){
4545
4546    int leftParenCount = 0;
4547    int rightParenCount = 0;
4548    int leftIndex = 0;
4549    int rightIndex = sourcetokenlist.size() - 1;
4550
4551    // Count opening parentheses at the beginning
4552    while (leftIndex < sourcetokenlist.size() && sourcetokenlist.get(leftIndex).tokencode == '(') {
4553        leftParenCount++;
4554        leftIndex++;
4555    }
4556
4557    // Count closing parentheses at the end
4558    while (rightIndex >= 0 && sourcetokenlist.get(rightIndex).tokencode == ')') {
4559        rightParenCount++;
4560        rightIndex--;
4561    }
4562
4563    // Set matching parentheses to be ignored
4564    int parensToIgnore = Math.min(leftParenCount, rightParenCount);
4565    // if there is a semicolon before the right parenthesis, set the semicolon to be ignored
4566    // mantisbt/view.php?id=3690
4567
4568    if ((parensToIgnore > 0) && (sourcetokenlist.get(sourcetokenlist.size() - 1 - (parensToIgnore - 1) - 1).tokencode == ';')){
4569        // set to whitespace that this semicolon will be ignored during getting raw sql
4570        sourcetokenlist.get(sourcetokenlist.size() - 1 - (parensToIgnore - 1) - 1).tokentype = ETokenType.ttwhitespace;
4571        // set to ignore by yacc that this semicolon will be ignored during parsing
4572        sourcetokenlist.get(sourcetokenlist.size() - 1 - (parensToIgnore - 1) - 1).tokenstatus = ETokenStatus.tsignorebyyacc;
4573    }
4574//    for (int i = 0; i < parensToIgnore; i++) {
4575//        //sourcetokenlist.get(i).tokenstatus = ETokenStatus.tsignorebyyacc;
4576//        sourcetokenlist.get(i).tokencode = TBaseType.lexspace;
4577//
4578//       // sourcetokenlist.get(sourcetokenlist.size() - 1 - i).tokenstatus = ETokenStatus.tsignorebyyacc;
4579//        sourcetokenlist.get(sourcetokenlist.size() - 1 - i).tokencode = TBaseType.lexspace;
4580//    }
4581
4582}
4583
4584
4585
4586void processTokensBeforeParse(EDbVendor dbVendor){
4587
4588        // 为确保性能,只在snowflake数据库中处理,因为目前只有snowflake数据库中有连续的分号有用户提出这个需求,其他数据库中暂时不处理
4589   if (dbVendor != EDbVendor.dbvsnowflake) return;
4590
4591        // mantisbt/view.php?id=3579
4592        // if there are consecutive semicolon tokens, mark the second semi colon token as deleted token
4593    for(int i=0;i<sourcetokenlist.size();i++){
4594        TSourceToken st = sourcetokenlist.get(i);
4595        if (st.tokencode == ';'){
4596            TSourceToken nextToken = st.nextSolidToken();
4597            if (nextToken != null){
4598                if (nextToken.tokencode == ';'){
4599                    nextToken.tokenstatus = ETokenStatus.tsdeleted;
4600                }
4601            }
4602        }
4603    }
4604
4605}
4606
4607void processTokensInTokenTable(EDbVendor dbVendor){
4608    // 获得所有token后,根据需要对token code进行预处理, token table是 TBaseType.TOKEN_TABLE
4609     long[][] TOKEN_TABLE1 = flexer.TOKEN_TABLE;
4610
4611    switch (dbVendor){
4612        case dbvbigquery:
4613        case dbvsnowflake:
4614            // case 1, DO 关键字如果没有发现对于的 FOR, WHILE 等关键字,把 DO 关键字的token code设置为 TBaseType.ident
4615
4616            if (TOKEN_TABLE1[TBaseType.rrw_do][0] > 0){
4617                if ((TOKEN_TABLE1[TBaseType.rrw_while][0] == 0)&&(TOKEN_TABLE1[TBaseType.rrw_for][0] == 0)){
4618                    for(int i=0;i<sourcetokenlist.size();i++){
4619                        TSourceToken st = sourcetokenlist.get(i);
4620                        if (st.tokencode == TBaseType.rrw_do){
4621                            st.tokencode = TBaseType.ident;
4622                        }
4623                    }
4624                }
4625            }
4626
4627            break;
4628    }
4629
4630}
4631
4632boolean isDollarFunctionDelimiter(int tokencode, EDbVendor dbVendor){
4633        return ((tokencode == TBaseType.rrw_postgresql_function_delimiter)&&(dbVendor == EDbVendor.dbvpostgresql))
4634                ||((tokencode == TBaseType.rrw_greenplum_function_delimiter)&&(dbVendor == EDbVendor.dbvgreenplum))
4635                ||((tokencode == TBaseType.rrw_redshift_function_delimiter)&&(dbVendor == EDbVendor.dbvredshift))
4636                ||((tokencode == TBaseType.rrw_snowflake_function_delimiter)&&(dbVendor == EDbVendor.dbvsnowflake))
4637                ||((tokencode == TBaseType.rrw_clickhouse_function_delimiter)&&(dbVendor == EDbVendor.dbvclickhouse));
4638}
4639
4640/**
4641 * Returns the 1-based line number of the end of the last SQL statement that
4642 * was successfully recognized during raw-statement separation (e.g. via
4643 * vendor-specific {@code do*getrawsqlstatements} routines).
4644 * <p>
4645 * The value corresponds to the ending line of the last validated statement in
4646 * the most recent parse operation. Any trailing, incomplete statement at the
4647 * end of the input is intentionally excluded and will not affect this value.
4648 * <p>
4649 * Notes:
4650 * <ul>
4651 * <li>The line number is relative to the current input provided to the
4652 * parser (not an absolute position in an external, larger file).</li>
4653 * <li>This is useful when splitting huge SQL files by safe statement
4654 * boundaries — callers can cut the source at this line without risking a
4655 * partial statement.</li>
4656 * </ul>
4657 *
4658 * @return the 1-based line number of the last validated statement's ending
4659 *         line, or {@code -1} if no statement has been validated yet
4660 */
4661public int getLastLineNoOfLastStatementBeenValidated(){
4662        if (lastTokenOfStatementBeenValidated != null){
4663            return (int)lastTokenOfStatementBeenValidated.lineNo;
4664        }
4665        return -1;
4666}
4667
4668private TSourceToken lastTokenOfStatementBeenValidated;
4669
4670
4671void doongetrawsqlstatementevent(TCustomSqlStatement pcsqlstatement){
4672        doongetrawsqlstatementevent(pcsqlstatement,false);
4673}
4674
4675void doongetrawsqlstatementevent(TCustomSqlStatement pcsqlstatement, boolean isLastSQL){
4676    pcsqlstatement.setGsqlparser(this);
4677    pcsqlstatement.parser = this.fparser;
4678    pcsqlstatement.plsqlparser = this.fplsqlparser;
4679    pcsqlstatement.setStartToken(pcsqlstatement.sourcetokenlist.get(0));
4680    pcsqlstatement.setEndToken(pcsqlstatement.sourcetokenlist.get(pcsqlstatement.sourcetokenlist.size()-1));
4681    sqlstatements.add(pcsqlstatement);
4682
4683    if (!isLastSQL){ // 最后一个语句没有经过验证,只是在结束的时候强行加入的,很有可能是语法不正确的,因此我们这里只记录非最后的语句
4684        lastTokenOfStatementBeenValidated = pcsqlstatement.getEndToken();
4685    }
4686
4687    // if stored procedure body is not written in sql or plsql, then, set the token in body to
4688    if (    ((this.dbVendor == EDbVendor.dbvpostgresql)||(this.dbVendor == EDbVendor.dbvgreenplum) ||(this.dbVendor == EDbVendor.dbvredshift) ||(this.dbVendor == EDbVendor.dbvsnowflake) ||(this.dbVendor == EDbVendor.dbvclickhouse) )
4689             && (pcsqlstatement instanceof TRoutine)
4690       ){
4691         if (!((TRoutine)pcsqlstatement).isBodyInSQL()){
4692             TSourceToken st;
4693             boolean inBody = false;
4694             String routineBodyStr = "";
4695             for(int i=0;i<pcsqlstatement.sourcetokenlist.size();i++){
4696                 st = pcsqlstatement.sourcetokenlist.get(i);
4697                 if (isDollarFunctionDelimiter(st.tokencode,this.dbVendor)
4698//                         ((st.tokencode == TBaseType.rrw_postgresql_function_delimiter)&&(this.dbVendor == EDbVendor.dbvpostgresql))
4699//                        ||((st.tokencode == TBaseType.rrw_greenplum_function_delimiter)&&(this.dbVendor == EDbVendor.dbvgreenplum))
4700//                         ||((st.tokencode == TBaseType.rrw_redshift_function_delimiter)&&(this.dbVendor == EDbVendor.dbvredshift))
4701//                         ||((st.tokencode == TBaseType.rrw_snowflake_function_delimiter)&&(this.dbVendor == EDbVendor.dbvsnowflake))
4702                 ){
4703                     if (!inBody){
4704                         inBody = true;
4705                         routineBodyStr = st.toString();
4706                     }else{
4707                         inBody = false;
4708                         routineBodyStr += st.toString();
4709                         break;
4710                     }
4711                     continue;
4712                 }
4713
4714                 if (inBody){
4715                     st.tokencode = TBaseType.sqlpluscmd;
4716                     routineBodyStr += st.toString();
4717                 }
4718             }
4719
4720             ((TRoutine)pcsqlstatement).setRoutineBody(routineBodyStr);
4721         }
4722    }
4723}
4724
4725    int doclickhousegetrawsqlstatements(){
4726        return dopostgresqlgetrawsqlstatements();
4727    }
4728
4729    boolean checkTokenPairWithEnd(int tokencode){
4730        return    ((tokencode == TBaseType.rrw_if)||(tokencode == TBaseType.rrw_case)
4731                ||(tokencode == TBaseType.rrw_loop)||(tokencode == TBaseType.rrw_repeat)
4732                ||(tokencode == TBaseType.rrw_while)||(tokencode == TBaseType.rrw_for)
4733                ||(tokencode == TBaseType.rrw_case)
4734        );
4735    }
4736
4737    int dopostgresqlgetrawsqlstatements(){
4738        int waitingEnd = 0;
4739        boolean foundEnd = false, enterDeclare = false;
4740
4741
4742
4743        if ( TBaseType.assigned(sqlstatements) ) sqlstatements.clear();
4744        if ( ! TBaseType.assigned(sourcetokenlist) ) return -1;
4745
4746        gcurrentsqlstatement = null;
4747        EFindSqlStateType gst = EFindSqlStateType.stnormal;
4748        TSourceToken lcprevsolidtoken = null,ast = null;
4749
4750        if (isSinglePLBlock){
4751            gcurrentsqlstatement = new TCommonBlock(EDbVendor.dbvpostgresql);
4752        }
4753
4754        for (int i=0 ; i < sourcetokenlist.size();i++)
4755        {
4756
4757            if ( (ast != null ) && (ast.issolidtoken() ))
4758                lcprevsolidtoken = ast;
4759
4760            ast = sourcetokenlist.get(i);
4761            sourcetokenlist.curpos = i;
4762            if (isSinglePLBlock){
4763                gcurrentsqlstatement.sourcetokenlist.add(ast);
4764                continue;
4765            }
4766
4767            if (ast.tokencode == TBaseType.JSON_EXIST){
4768                TSourceToken stConstant  = ast.searchToken(TBaseType.sconst,1);
4769                if (stConstant == null){
4770                    ast.tokencode = TBaseType.ident;
4771                }
4772            }
4773            else if (ast.tokencode == TBaseType.rrw_postgresql_POSITION) {
4774                TSourceToken st1 = ast.nextSolidToken(); //ast.searchToken('(',1);
4775                if (st1 != null) {
4776                    if (st1.tokencode == '(') {
4777                        ast.tokencode = TBaseType.rrw_postgresql_POSITION_FUNCTION;
4778                    }
4779                }
4780            }else  if (ast.tokencode == TBaseType.rrw_postgresql_ordinality) {
4781                TSourceToken lcprevst = getprevsolidtoken(ast);
4782
4783                if (lcprevst != null) {
4784                    if (lcprevst.tokencode == TBaseType.rrw_with) {
4785                        TSourceToken lcnextst = ast.nextSolidToken();
4786                        if ((lcnextst != null)&&(lcnextst.tokencode == TBaseType.rrw_as)){
4787                            //  with ordinality as (select 1 as x) select * from ordinality;
4788                            // don't change with to rrw_postgresql_with_lookahead
4789                        }else{
4790                            lcprevst.tokencode = TBaseType.rrw_postgresql_with_lookahead;
4791                        }
4792
4793                    }
4794                }
4795            }
4796            else if (ast.tokencode == TBaseType.rrw_postgresql_filter) {
4797                TSourceToken st1 = ast.nextSolidToken(); //ast.searchToken('(',1);
4798                if (st1 != null) {
4799                    if (st1.tokencode == '(') {
4800
4801                    }else{
4802                        ast.tokencode = TBaseType.ident;
4803                    }
4804                }
4805            }
4806            else if (ast.tokencode == TBaseType.rrw_postgresql_jsonb) {
4807                TSourceToken st1 = ast.nextSolidToken(); //ast.searchToken('(',1);
4808                if (st1 != null) {
4809                    if (st1.tokencode == '?') {
4810                        st1.tokencode = TBaseType.OP_JSONB_QUESTION;
4811                    }
4812                }
4813            }
4814            else if (ast.tokencode == '?') {
4815                TSourceToken st1 = ast.nextSolidToken(); //ast.searchToken('(',1);
4816                if (st1 != null) {
4817                    if (st1.tokencode == TBaseType.sconst) {
4818                        ast.tokencode = TBaseType.OP_JSONB_QUESTION;
4819                    }
4820                }
4821            }
4822            else if (ast.tokencode == TBaseType.rrw_values) {
4823                TSourceToken stParen =  ast.searchToken('(',1);
4824                if (stParen != null){
4825                    TSourceToken stInsert  = ast.searchToken(TBaseType.rrw_insert,-ast.posinlist);
4826                    if (stInsert != null){
4827                        TSourceToken stSemiColon  = ast.searchToken(';',-ast.posinlist);
4828                        if ((stSemiColon != null)&&(stSemiColon.posinlist > stInsert.posinlist)){
4829//                            INSERT INTO test values (16,1), (8,2), (4,4), (2,0), (97, 16);
4830//                            VALUES (1);
4831                            // don't treat values(1) as insert values
4832
4833                        }else{
4834                            TSourceToken stFrom  = ast.searchToken(TBaseType.rrw_from,-ast.posinlist);
4835                            if ((stFrom != null)&&(stFrom.posinlist > stInsert.posinlist)){
4836                                // don't treat values after from keyword as an insert values
4837
4838                                // insert into inserttest values(10, 20, '40'), (-1, 2, DEFAULT),  ((select 2), (select i from (values(3) ) as foo (i)), 'values are fun!');
4839
4840                            }else{
4841                                ast.tokencode = TBaseType.rrw_postgresql_insert_values;
4842                            }
4843
4844                        }
4845
4846                    }
4847                }
4848            }
4849
4850            switch(gst){
4851                case sterror:{
4852                    if (ast.tokentype ==  ETokenType.ttsemicolon)
4853                    {
4854                        gcurrentsqlstatement.sourcetokenlist.add(ast);
4855                        doongetrawsqlstatementevent(gcurrentsqlstatement);
4856                        gst = EFindSqlStateType.stnormal;
4857                    }
4858                    else
4859                    {
4860                        gcurrentsqlstatement.sourcetokenlist.add(ast);
4861                    }
4862                    break;
4863                } //sterror
4864
4865                case stnormal:{
4866                    if ((ast.tokencode  == TBaseType.cmtdoublehyphen)
4867                            || (ast.tokencode  == TBaseType.cmtslashstar)
4868                            || (ast.tokencode  == TBaseType.lexspace)
4869                            || (ast.tokencode  == TBaseType.lexnewline)
4870                            || (ast.tokentype  == ETokenType.ttsemicolon) )
4871                    {
4872                        if (gcurrentsqlstatement != null)
4873                        {
4874                            gcurrentsqlstatement.addtokentolist(ast);
4875                        }
4876
4877                        if ((lcprevsolidtoken != null) && (ast.tokentype == ETokenType.ttsemicolon))
4878                        {
4879                            if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon )
4880                            {
4881                                // ;;;; continuous semicolon,treat it as comment
4882                                ast.tokentype = ETokenType.ttsimplecomment;
4883                                ast.tokencode =  TBaseType.cmtdoublehyphen;
4884                            }
4885                        }
4886
4887                        continue;
4888                    }
4889
4890                    if (ast.tokencode == TBaseType.sqlpluscmd )
4891                    {
4892                        gst = EFindSqlStateType.stsqlplus;
4893                        gcurrentsqlstatement = new TSqlplusCmdStatement(dbVendor);
4894                        gcurrentsqlstatement.addtokentolist(ast);
4895                        continue;
4896                    }
4897
4898                    // find a tokentext to start sql or plsql mode
4899                    gcurrentsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement);
4900
4901                    if (gcurrentsqlstatement != null)
4902                    {
4903                        enterDeclare = false;
4904                        if (gcurrentsqlstatement.ispgplsql())
4905                        {
4906                            gst = EFindSqlStateType.ststoredprocedure;
4907                            gcurrentsqlstatement.addtokentolist(ast);
4908                            foundEnd = false;
4909                            if   ((ast.tokencode == TBaseType.rrw_begin)
4910                                    ||(ast.tokencode == TBaseType.rrw_package)
4911                                    || (ast.searchToken(TBaseType.rrw_package,4) != null)
4912                                    )
4913                            {
4914                                waitingEnd = 1;
4915                            }
4916                            else if (ast.tokencode == TBaseType.rrw_declare){
4917                                enterDeclare = true;
4918                            }
4919                        }
4920                        else
4921                        {
4922                            gst = EFindSqlStateType.stsql;
4923                            gcurrentsqlstatement.addtokentolist(ast);
4924                        }
4925                    }else{
4926                        //error tokentext found
4927
4928                        this.syntaxErrors.add( new TSyntaxError(ast.getAstext(),ast.lineNo,(ast.columnNo < 0 ? 0:ast.columnNo)
4929                                ,"Error when tokenlize", EErrorType.spwarning,TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE,null,ast.posinlist));
4930
4931                        ast.tokentype = ETokenType.tttokenlizererrortoken;
4932                        gst = EFindSqlStateType.sterror;
4933
4934                        gcurrentsqlstatement = new TUnknownSqlStatement(dbVendor);
4935                        gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid;
4936                        gcurrentsqlstatement.addtokentolist(ast);
4937
4938                    }
4939
4940                    break;
4941                } // stnormal
4942
4943                case stsqlplus:{
4944                    if  (ast.insqlpluscmd)
4945                    {gcurrentsqlstatement.addtokentolist(ast);}
4946                    else
4947                    {
4948                        gst = EFindSqlStateType.stnormal; //this tokentext must be newline,
4949                        gcurrentsqlstatement.addtokentolist(ast); // so add it here
4950                        doongetrawsqlstatementevent(gcurrentsqlstatement);
4951                    }
4952
4953                    break;
4954                }//case stsqlplus
4955
4956                case stsql:{
4957                    if (ast.tokentype == ETokenType.ttsemicolon)
4958                    {
4959                        gst = EFindSqlStateType.stnormal;
4960                        gcurrentsqlstatement.addtokentolist(ast);
4961                        gcurrentsqlstatement.semicolonended = ast;
4962                        doongetrawsqlstatementevent(gcurrentsqlstatement);
4963                        continue;
4964                    }
4965
4966                    if  (sourcetokenlist.sqlplusaftercurtoken() ) //most probaly is / cmd
4967                    {
4968                        gst = EFindSqlStateType.stnormal;
4969                        gcurrentsqlstatement.addtokentolist(ast);
4970                        doongetrawsqlstatementevent(gcurrentsqlstatement);
4971                        continue;
4972                    }
4973
4974                    if (ast.tokencode  == TBaseType.cmtdoublehyphen){
4975                        if (ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)){ // -- sqlflow-delimiter
4976                            gst = EFindSqlStateType.stnormal;
4977                            doongetrawsqlstatementevent(gcurrentsqlstatement);
4978                            continue;
4979                        }
4980                    }
4981
4982                    gcurrentsqlstatement.addtokentolist(ast);
4983                    break;
4984                }//case stsql
4985
4986                case ststoredprocedure:{
4987                    if (ast.tokencode == TBaseType.rrw_postgresql_function_delimiter){
4988                        gcurrentsqlstatement.addtokentolist(ast);
4989                        gst = EFindSqlStateType.ststoredprocedurePgStartBody;
4990
4991                        continue;
4992                    }
4993
4994                    if (ast.tokencode == TBaseType.rrw_postgresql_language){
4995                        // check next token which is the language used by this stored procedure
4996                        TSourceToken nextSt = ast.nextSolidToken();
4997                        if (nextSt != null){
4998                            if (gcurrentsqlstatement instanceof TRoutine){  // can be TCreateProcedureStmt or TCreateFunctionStmt
4999                                TRoutine p = (TRoutine) gcurrentsqlstatement;
5000                                p.setRoutineLanguage(nextSt.toString());
5001                            }
5002                        }
5003                    }
5004
5005                    if ((ast.tokentype == ETokenType.ttsemicolon) && (waitingEnd == 0) && (!enterDeclare))
5006                    {
5007                        gst = EFindSqlStateType.stnormal;
5008                        gcurrentsqlstatement.addtokentolist(ast);
5009                        gcurrentsqlstatement.semicolonended = ast;
5010                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5011                        continue;
5012                    }
5013
5014                    if   ((ast.tokencode == TBaseType.rrw_begin)
5015                        //||(ast.tokencode == TBaseType.rrw_between)
5016                            )
5017                    {
5018                        waitingEnd++;
5019                        enterDeclare = false;
5020                    }
5021                    else if   (
5022                            (ast.tokencode == TBaseType.rrw_declare)
5023                    ){
5024                        enterDeclare = true;
5025                    }
5026                    else if   (
5027                            (ast.tokencode == TBaseType.rrw_if)
5028                            ){
5029                        if (ast.searchToken(TBaseType.rrw_end,-1) == null){
5030                            //this is not if after END
5031                            waitingEnd++;
5032                        }
5033                    }
5034                    else if   (
5035                            (ast.tokencode == TBaseType.rrw_case)
5036                            ){
5037                        if (ast.searchToken(TBaseType.rrw_end,-1) == null){
5038                            //this is not case after END
5039                            waitingEnd++;
5040                        }
5041                    }
5042                    else if   (
5043                            (ast.tokencode == TBaseType.rrw_loop)
5044                            ){
5045                        if (ast.searchToken(TBaseType.rrw_end,-1) == null){
5046                            //this is not loop after END
5047                            waitingEnd++;
5048                        }
5049                    }
5050                    else if (ast.tokencode == TBaseType.rrw_end){
5051                        foundEnd = true;
5052                        waitingEnd--;
5053                        if (waitingEnd < 0) { waitingEnd = 0;}
5054                    }
5055
5056                    if ((ast.tokentype == ETokenType.ttslash)  && (ast.tokencode == TBaseType.sqlpluscmd) ) //and (prevst.NewlineIsLastTokenInTailerToken)) then
5057                    {
5058                        // TPlsqlStatementParse(asqlstatement).TerminatorToken := ast;
5059                        ast.tokenstatus = ETokenStatus.tsignorebyyacc;
5060                        gst = EFindSqlStateType.stnormal;
5061                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5062
5063                        //make / a sqlplus cmd
5064                        gcurrentsqlstatement = new TSqlplusCmdStatement(dbVendor);
5065                        gcurrentsqlstatement.addtokentolist(ast);
5066                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5067                    }
5068                    else  if ((ast.tokentype == ETokenType.ttperiod)  && (sourcetokenlist.returnaftercurtoken(false)) && (sourcetokenlist.returnbeforecurtoken(false)))
5069                    {    // single dot at a seperate line
5070                        ast.tokenstatus = ETokenStatus.tsignorebyyacc;
5071                        gst = EFindSqlStateType.stnormal;
5072                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5073
5074                        //make ttperiod a sqlplus cmd
5075                        gcurrentsqlstatement = new TSqlplusCmdStatement(dbVendor);
5076                        gcurrentsqlstatement.addtokentolist(ast);
5077                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5078                    }
5079                    else
5080                    {
5081                        gcurrentsqlstatement.addtokentolist(ast);
5082                        if ((ast.tokentype == ETokenType.ttsemicolon) && (waitingEnd == 0)
5083                                && (foundEnd)
5084                        //        && (gcurrentsqlstatement.OracleStatementCanBeSeparatedByBeginEndPair())
5085                        ){
5086                            gst = EFindSqlStateType.stnormal;
5087                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5088                        }
5089                    }
5090
5091                    if (ast.tokencode == TBaseType.sqlpluscmd)
5092                    {
5093                        //change tokencode back to keyword or TBaseType.ident, because sqlplus cmd
5094                        //in a sql statement(almost is plsql block) is not really a sqlplus cmd
5095                        int m = flexer.getkeywordvalue(ast.getAstext());
5096                        if (m != 0)
5097                        {ast.tokencode = m;}
5098                        else
5099                        {ast.tokencode = TBaseType.ident;}
5100                    }
5101
5102                    if (( gst == EFindSqlStateType.ststoredprocedure ) && (ast.tokencode  == TBaseType.cmtdoublehyphen)){
5103                        if (ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)){ // -- sqlflow-delimiter
5104                            gst = EFindSqlStateType.stnormal;
5105                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5106                        }
5107                    }
5108
5109                    break;
5110                } //ststoredprocedure
5111
5112                case ststoredprocedurePgStartBody:{
5113                    gcurrentsqlstatement.addtokentolist(ast);
5114
5115                    if (ast.tokencode == TBaseType.rrw_postgresql_function_delimiter){
5116                        if (gcurrentsqlstatement.sqlstatementtype == sstDoExecuteBlock){
5117                            gst = EFindSqlStateType.stnormal;
5118                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5119                            continue;
5120
5121                        }else{
5122                            gst = EFindSqlStateType.ststoredprocedurePgEndBody;
5123                            continue;
5124                        }
5125                    }
5126
5127                    break;
5128                }
5129
5130                case ststoredprocedurePgEndBody:{
5131
5132                    if (ast.tokentype == ETokenType.ttsemicolon)
5133                    {
5134                        gst = EFindSqlStateType.stnormal;
5135                        gcurrentsqlstatement.addtokentolist(ast);
5136                        gcurrentsqlstatement.semicolonended = ast;
5137                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5138                        continue;
5139                    }
5140                    else if (ast.tokencode  == TBaseType.cmtdoublehyphen){
5141                        if (ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)){ // -- sqlflow-delimiter
5142                            gst = EFindSqlStateType.stnormal;
5143                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5144                            continue;
5145                        }
5146                    }
5147
5148                    gcurrentsqlstatement.addtokentolist(ast);
5149
5150                    if (ast.tokencode == TBaseType.rrw_postgresql_language){
5151                        // check next token which is the language used by this stored procedure
5152                        TSourceToken nextSt = ast.nextSolidToken();
5153                        if (nextSt != null){
5154                            if (gcurrentsqlstatement instanceof TRoutine){  // can be TCreateProcedureStmt or TCreateFunctionStmt
5155                                TRoutine p = (TRoutine) gcurrentsqlstatement;
5156                                p.setRoutineLanguage(nextSt.toString());
5157                            }
5158                        }
5159                    }
5160
5161                    break;
5162                }
5163            } //switch
5164        }//for
5165
5166        //last statement
5167        if ((gcurrentsqlstatement != null) &&
5168                ((gst == EFindSqlStateType.stsqlplus) ||  (gst == EFindSqlStateType.stsql)
5169                        || (gst == EFindSqlStateType.ststoredprocedure)
5170                        || (gst == EFindSqlStateType.ststoredprocedurePgEndBody)
5171                        ||(gst == EFindSqlStateType.sterror)||(isSinglePLBlock)
5172                ))
5173        {
5174            doongetrawsqlstatementevent(gcurrentsqlstatement,true);
5175        }
5176
5177        return syntaxErrors.size();
5178    }
5179
5180    /**
5181     * Functionality
5182     * Target Identification:
5183     * Scans for CREATE PROCEDURE and CREATE FUNCTION statements
5184     * Verifies the language is SQL (for procedures)
5185     * Identifies dollar-quoted strings ($$...$$) and single-quoted strings after AS keywords
5186     * Token Expansion:
5187     * For each identified string literal:
5188     * Extracts the content between the quotes
5189     * Tokenizes the extracted SQL code
5190     * Verifies it's a valid code block (starts with DECLARE or BEGIN)
5191     * Replaces the original quoted string with expanded tokens in the source token list
5192     * Special Transformations:
5193     * Converts BEGIN; to BEGIN TRANSACTION;
5194     * Handles BEGIN WORK; similarly
5195     * Special handling for semicolons after END statements
5196     * Token Chain Management:
5197     * Preserves original quotes as space tokens
5198     * Maintains proper token positioning and chaining
5199     * Resets the token chain to ensure correct output during toString() operations
5200     * Implementation Details
5201     * Processes statements in reverse order to maintain correct token positions
5202     * Uses TBaseType.getStringInsideLiteral() to extract content between quotes
5203     * Marks original dollar-quoted tokens as deleted (using tsdeleted)
5204     * Handles multi-line SQL blocks within stored procedure/function bodies
5205     */
5206    void expandDollarString(){
5207        // snowflake, expand dollar string into token list
5208        TSourceToken st;
5209        TCustomSqlStatement sql;
5210        ArrayList<TSourceToken> dollarTokens = new ArrayList<>();
5211        boolean isSQLLanguage = true;
5212
5213        // Iterate all create procedure and create function, other sql staetment just skipped
5214        for(int i=0;i<sqlstatements.size();i++){
5215            sql = sqlstatements.get(i);
5216            if (!((sql.sqlstatementtype == sstcreateprocedure)||(sql.sqlstatementtype == sstcreatefunction))) continue;
5217            isSQLLanguage = true;
5218            for(int j=0;j<sql.sourcetokenlist.size();j++){
5219                st = sql.sourcetokenlist.get(j);
5220
5221                if (sql.sqlstatementtype == sstcreateprocedure){
5222                    if (st.tokencode == TBaseType.rrw_snowflake_language){
5223                        TSourceToken lang = st.nextSolidToken();
5224                        if ((lang != null)&&(!lang.toString().equalsIgnoreCase("sql"))){
5225                            isSQLLanguage = false;
5226                        }
5227                    }
5228                }
5229
5230                if (!isSQLLanguage) break;
5231
5232                if (st.tokencode == TBaseType.sconst){
5233                    if (st.toString().startsWith("$$")){
5234                        dollarTokens.add(st); // TODO: 可能会有多个 $$ token? 这种情况再哪个场景下会出现?需要找到对应的测试用例和SQL脚本。否则,uncomment next line
5235                        // break; // only one $$ token per sql, if we found one, then just break this sql and continue for next sql
5236                    }else if (st.toString().startsWith("'")){
5237                        // https://docs.snowflake.com/en/sql-reference/sql/create-procedure
5238                        // string literal delimiter can be $ or '
5239                        if (st.prevSolidToken().tokencode == TBaseType.rrw_as){
5240                            dollarTokens.add(st); // TODO: 可能会有多个 $$ token? 这种情况再哪个场景下会出现?需要找到对应的测试用例和SQL脚本。否则,uncomment next line
5241                            // break; // only one single quote token per sql, if we found one, then just break this sql and continue for next sql
5242                        }
5243                    }
5244                }
5245            }//check tokens
5246
5247            for(int m= dollarTokens.size() - 1; m>=0;m--){
5248
5249                // Token Expansion:
5250                // For each identified string literal:
5251                // Extracts the content between the quotes
5252                // Tokenizes the extracted SQL code
5253                // Verifies it's a valid code block (starts with DECLARE or BEGIN)
5254                // Replaces the original quoted string with expanded tokens in the source token list
5255
5256                st = dollarTokens.get(m);
5257
5258                TGSqlParser parser = new TGSqlParser(this.dbVendor);
5259                //parser.sqltext = TBaseType.stringBlock((int)st.lineNo - 1,(int)st.columnNo)+ TBaseType.getStringInsideLiteral(st.toString());
5260                // 如果在前面补充空行,会导致 toString() 重新拼接时多出空行;
5261                // 同时,因为不需要进行解析,所以不需要在前面补充空行以获得准确的错误定位? 这个说法是错误的,因为不加需要的空行,会导致定位不准确 #TODO
5262                parser.sqltext = TBaseType.getStringInsideLiteral(st.toString()); 
5263                TSourceToken startQuote = new TSourceToken(st.toString().substring(0,1));
5264                startQuote.tokencode = TBaseType.lexspace; // 设置为 space,可以在解析时忽略该token,同时在 toString() 时会被原样输出
5265                TSourceToken endQuote = new TSourceToken(st.toString().substring(0,1));
5266                endQuote.tokencode = TBaseType.lexspace;
5267
5268                // use getrawsqlstatements() instead of tokenizeSqltext() to get the source token list because
5269                // some token will be transformed to other token, which will be processed in dosnowflakegetrawsqlstatements()
5270                parser.getrawsqlstatements();
5271                //parser.tokenizeSqltext();
5272
5273                TSourceToken st2;
5274                boolean isValidBlock = false;
5275                for(int k=0;k<parser.sourcetokenlist.size();k++){
5276                    st2 = parser.sourcetokenlist.get(k);
5277                    if (st2.isnonsolidtoken()) continue;
5278                    if ((st2.tokencode == TBaseType.rrw_declare)||(st2.tokencode == TBaseType.rrw_begin)){
5279                        isValidBlock = true;
5280                    }else{
5281                        //
5282                    }
5283                    break;
5284                    //System.out.println(st2.lineNo+","+st2.columnNo+":"+st2.toString());
5285                }
5286
5287                if (isValidBlock){
5288                    TSourceToken semiColon = null;
5289                    st.tokenstatus = ETokenStatus.tsdeleted;
5290                    int startPosOfThisSQl = sql.getStartToken().posinlist;
5291
5292                    sql.sourcetokenlist.add((st.posinlist++) - startPosOfThisSQl,startQuote); // 补上开始引号
5293                    for(int k=0;k<parser.sourcetokenlist.size();k++) {
5294                        st2 = parser.sourcetokenlist.get(k);
5295                        if (st2.tokencode == ';'){
5296                            semiColon = st2;
5297                            TSourceToken prevSolidToken = st2.prevSolidToken();
5298                            if ((prevSolidToken != null) && (prevSolidToken.tokencode == TBaseType.rrw_begin)){
5299                                // begin;  => begin transaction;
5300                                prevSolidToken.tokencode = TBaseType.rrw_snowflake_begin_transaction;
5301                            }
5302                        }
5303                        if ((st2.tokencode == TBaseType.rrw_snowflake_work)||(st2.tokencode == TBaseType.rrw_snowflake_transaction)){
5304                            // begin work;  => begin transaction;
5305                            TSourceToken prevSolidToken = st2.prevSolidToken();
5306                            if ((prevSolidToken != null) && (prevSolidToken.tokencode == TBaseType.rrw_begin)){
5307                                // begin;  => begin transaction;
5308                                prevSolidToken.tokencode = TBaseType.rrw_snowflake_begin_transaction;
5309                            }
5310                        }
5311                        sql.sourcetokenlist.add( (st.posinlist++) - startPosOfThisSQl,st2);
5312                        //st.posinlist++;
5313                    }
5314                    if (semiColon != null){
5315                        if (semiColon.prevSolidToken().tokencode == TBaseType.rrw_end){
5316                            // 设置为 space,可以在解析时忽略该token,同时在 toString() 时会被原样输出
5317                            // semiColon.tokenstatus = ETokenStatus.tsdeleted;
5318                            semiColon.tokencode = TBaseType.lexspace;
5319                        }
5320                    }
5321
5322                    sql.sourcetokenlist.add( (st.posinlist++) - startPosOfThisSQl,endQuote); // 补上结束引号
5323                    TBaseType.resetTokenChain(sql.sourcetokenlist,0); // 重新设置token链,确保新插入的token在 toString() 时能被访问到,从而确保 toString() 输出正确结果
5324                }
5325            }
5326
5327            dollarTokens.clear();
5328        }//statement
5329
5330    }
5331
5332    int domssqlgetrawsqlstatements(){
5333
5334        // Original implementation follows...
5335        int errorcount = 0;
5336        int case_end_nest = 0;
5337
5338        if ( TBaseType.assigned(sqlstatements) ) sqlstatements.clear();
5339        if ( ! TBaseType.assigned(sourcetokenlist) ) return -1;
5340
5341        gcurrentsqlstatement = null;
5342        EFindSqlStateType gst = EFindSqlStateType.stnormal;
5343        int lcblocklevel = 0;
5344        int lctrycatchlevel = 0;
5345        TSourceToken lcprevsolidtoken = null,lcnextsolidtoken,lcnnextsolidtoken;
5346        TSourceToken ast = null;
5347        int i,lcMergeInSelectNested = 0;
5348        boolean lcisendconversation, lcstillinsql,lcMergeInSelect = false;
5349
5350        for (i=0 ; i < sourcetokenlist.size();i++)
5351        {
5352
5353            if ( (ast != null ) && (ast.issolidtoken() ))
5354                lcprevsolidtoken = ast;
5355
5356            ast = sourcetokenlist.get(i);
5357            sourcetokenlist.curpos = i;
5358
5359            if (ast.tokencode == TBaseType.rrw_for){
5360                TSourceToken st1 = ast.nextSolidToken();
5361                if ((st1 != null) && (st1.tokencode == TBaseType.rrw_system_time)){
5362                    ast.tokencode = TBaseType.rw_for_system_time;
5363                }
5364            }
5365
5366            if (lcMergeInSelect){
5367                if (ast.tokencode == '(') lcMergeInSelectNested++;
5368                if (ast.tokencode == ')'){
5369                    lcMergeInSelectNested--;
5370                    if (lcMergeInSelectNested == 0){
5371                        lcMergeInSelect = false;
5372                    }
5373                }
5374                gcurrentsqlstatement.sourcetokenlist.add(ast);
5375                continue;
5376            }
5377            if ( ast.tokenstatus == ETokenStatus.tsignoredbygetrawstatement )
5378            {
5379                //tsignoredbygetrawstatement is set when cte is found in dbcmds.findcte function
5380                gcurrentsqlstatement.sourcetokenlist.add(ast);
5381                continue;
5382            }
5383
5384            if (ast.tokencode == TBaseType.rrw_minus){
5385                TSourceToken st1 = ast.searchToken('(',1);
5386                if (st1 == null){
5387                    st1 = ast.searchToken(TBaseType.rrw_select,1);
5388                    if (st1 == null){
5389                        ast.tokencode = TBaseType.ident;
5390                    }
5391                }
5392            }else if (ast.tokencode == TBaseType.rrw_merge){
5393                TSourceToken st1 = ast.nextSolidToken();
5394                if (st1.tokencode == TBaseType.rrw_join){
5395                    ast.tokencode = TBaseType.rrw_merge2_sqlserver;
5396                }
5397                if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '(')){
5398                    lcMergeInSelect = true;
5399                    lcMergeInSelectNested++;
5400                    gcurrentsqlstatement.addtokentolist(ast);
5401                    continue;
5402                }
5403            }else if (ast.tokencode == TBaseType.rrw_sqlserver_value){
5404                if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){
5405                    TSourceToken st1 = ast.searchToken('(',1);
5406                    if (st1 != null) {
5407                        ast.tokencode = TBaseType.rrw_xml_value;
5408                    }
5409                }
5410            }else if (ast.tokencode == TBaseType.rrw_sqlserver_modify){
5411                if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){
5412                    TSourceToken st1 = ast.searchToken('(',1);
5413                    if (st1 != null) {
5414                        ast.tokencode = TBaseType.rrw_xml_modify;
5415                    }
5416                }
5417            }else if (ast.tokencode == TBaseType.rrw_sqlserver_query){
5418                if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){
5419                    TSourceToken st1 = ast.searchToken('(',1);
5420                    if (st1 != null) {
5421                        ast.tokencode = TBaseType.rrw_xml_query;
5422                    }
5423                }
5424            }else if (ast.tokencode == TBaseType.rrw_sqlserver_exist){
5425                if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){
5426                    TSourceToken st1 = ast.searchToken('(',1);
5427                    if (st1 != null) {
5428                        ast.tokencode = TBaseType.rrw_xml_exist;
5429                    }
5430                }
5431            }else if (ast.tokencode == TBaseType.rrw_sqlserver_nodes){
5432                if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){
5433                    TSourceToken st1 = ast.searchToken('(',1);
5434                    if (st1 != null) {
5435                        ast.tokencode = TBaseType.rrw_xml_nodes;
5436                    }
5437                }
5438            }else if (ast.tokencode == TBaseType.rrw_check){
5439                if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == TBaseType.rrw_with)){
5440                    lcprevsolidtoken.tokencode = TBaseType.rrw_sqlserver_check_with;
5441                }
5442//            }else if (ast.tokencode == TBaseType.rrw_for){
5443//                TSourceToken st1 = ast.nextSolidToken();
5444//                if ((st1 != null) && (st1.tokencode == TBaseType.rrw_system_time)){
5445//                    ast.tokencode = TBaseType.rw_for_system_time;
5446//                }
5447            }else if (ast.tokencode == TBaseType.rrw_sqlserver_next){
5448                TSourceToken st1 = ast.nextSolidToken();
5449                if ((st1 != null) && (st1.tokencode == '.')){
5450                    ast.tokencode = TBaseType.ident;
5451                }
5452            }else if (ast.tokencode == TBaseType.rrw_fetch){
5453                if ((lcprevsolidtoken != null)&&((lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_row)||(lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_rows))){
5454                      TSourceToken prev2 = lcprevsolidtoken.searchToken(TBaseType.rrw_open,-1);
5455                      if (prev2 == null){
5456                          ast.tokencode = TBaseType.rrw_sqlserver_offset_fetch;
5457                      }else{
5458                          // don't turn fetch to TBaseType.rrw_sqlserver_offset_fetch
5459                          //open row
5460                          //fetch row into @msg
5461                      }
5462
5463                }
5464            }else if((ast.tokencode == TBaseType.rrw_exec)||(ast.tokencode == TBaseType.rrw_execute)){
5465                // search ;2 after execute
5466                // EXECUTE ApxSQL_Test_Triggers_Add;2  @TableName, @AddFlag
5467                int searchRange = 4;
5468                TSourceToken endTokenInSameLine = ast.searchTokenAtTheEndOfSameLine();
5469                if (endTokenInSameLine != null){
5470                    searchRange = endTokenInSameLine.posinlist - ast.posinlist;
5471                }
5472                TSourceToken st1 = ast.searchToken(';',searchRange);
5473                if (st1 != null){
5474                    TSourceToken numSt = st1.nextSolidToken();
5475                    if ((numSt != null)&&(numSt.tokentype == ETokenType.ttnumber)){
5476                        st1.tokencode = TBaseType.rrw_sqlserver_semicolon_module_number;
5477                        st1.tokentype = ETokenType.ttidentifier;
5478                    }
5479                }
5480            }
5481            else if (ast.tokencode == TBaseType.rrw_sqlserver_trim){
5482                TSourceToken st1 =  ast.nextSolidToken();
5483                if (st1 != null){
5484                    if (st1.tokencode == '('){
5485
5486                    }else{
5487                        ast.tokencode = TBaseType.ident; // change trim keyword to identifier if not followed by (), trim()
5488                    }
5489                }
5490            }
5491
5492            if (dbVendor == EDbVendor.dbvopenedge){
5493                if (ast.tokencode == TBaseType.rrw_order){
5494                        TSourceToken st1 = ast.searchToken(TBaseType.rrw_by,1);
5495                        if (st1 == null) {
5496                            ast.tokencode = TBaseType.ident;
5497                        }
5498                }else if (ast.tokencode == TBaseType.rrw_with){
5499                        TSourceToken st1 = ast.searchToken(TBaseType.rrw_check,1);
5500                        if (st1 != null) {
5501                            ast.tokencode = TBaseType.rrw_openedge_with_check;
5502                        }
5503                }
5504            }
5505
5506            if ( gst == EFindSqlStateType.ststoredprocedurebody )
5507            {
5508                if ( !(
5509                        (ast.tokencode == TBaseType.rrw_go)
5510                                || (ast.tokencode == TBaseType.rrw_create)
5511                                || (ast.tokencode == TBaseType.rrw_alter) )
5512                        )
5513                {
5514                    gcurrentsqlstatement.sourcetokenlist.add(ast);
5515                    continue;
5516                }
5517            }
5518
5519            TCustomSqlStatement lcnextsqlstatement =  sqlcmds.issql(ast, gst, gcurrentsqlstatement);
5520
5521            switch(gst){
5522                case sterror:
5523                {
5524                    if ( TBaseType.assigned(lcnextsqlstatement) )
5525                    {
5526                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5527                        gcurrentsqlstatement = lcnextsqlstatement;
5528                        gcurrentsqlstatement.sourcetokenlist.add(ast);
5529                        gst = EFindSqlStateType.stsql;
5530                    }
5531                    else if ( (ast.tokentype == ETokenType.ttsemicolon) )
5532                    {
5533                        gcurrentsqlstatement.sourcetokenlist.add(ast);
5534                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5535                        gst = EFindSqlStateType.stnormal;
5536                    }
5537                    else
5538                    {
5539                        gcurrentsqlstatement.sourcetokenlist.add(ast);
5540                    }
5541                    break;
5542                }
5543                case stnormal :
5544                {
5545                    if ( (ast.tokencode  == TBaseType.cmtdoublehyphen)
5546                            || (ast.tokencode  == TBaseType.cmtslashstar)
5547                            || (ast.tokencode  == TBaseType.lexspace)
5548                            || (ast.tokencode  == TBaseType.lexnewline)
5549                            || (ast.tokentype  == ETokenType.ttsemicolon) )
5550                    {
5551                        if ( TBaseType.assigned(gcurrentsqlstatement) )
5552                        {
5553                            gcurrentsqlstatement.addtokentolist(ast);
5554                        }
5555
5556                        if ( TBaseType.assigned(lcprevsolidtoken) && (ast.tokentype == ETokenType.ttsemicolon) )
5557                        {
5558                            if ( lcprevsolidtoken.tokentype == ETokenType.ttsemicolon )
5559                            {
5560                                // ;;;; continuous semicolon,treat it as comment
5561                                ast.tokentype = ETokenType.ttsimplecomment;
5562                                ast.tokencode =  TBaseType.cmtdoublehyphen;
5563                            }
5564                            else
5565                            {
5566                            }
5567
5568                        }
5569
5570                        continue;
5571                    }
5572
5573                    gcurrentsqlstatement = lcnextsqlstatement; //isstoredprocedure(ast,dbvendor,gst,sqlstatements);
5574
5575                    if ( TBaseType.assigned(gcurrentsqlstatement) )
5576                    {
5577                        switch(gcurrentsqlstatement.sqlstatementtype){    //
5578                            case sstmssqlcreateprocedure:
5579                            case sstmssqlcreatefunction:
5580                            //case sstmssqlcreatetrigger:
5581                            case sstcreatetrigger:
5582                            case sstmssqlalterprocedure:
5583                            case   sstmssqlalterfunction:
5584                            case sstmssqlaltertrigger:
5585                            {
5586                                gcurrentsqlstatement.addtokentolist(ast);
5587                                gst = EFindSqlStateType.ststoredprocedure;
5588                                break;
5589                            }
5590                            case sstmssqlbegintry:
5591                            case sstmssqlbegincatch:
5592                            {
5593                                gcurrentsqlstatement.addtokentolist(ast);
5594                                gst = EFindSqlStateType.sttrycatch;
5595                                lctrycatchlevel = 0;
5596                                break;
5597                            }
5598                            case sstmssqlgo:
5599                            {
5600                                gcurrentsqlstatement.addtokentolist(ast);
5601                                doongetrawsqlstatementevent(gcurrentsqlstatement);
5602                                gst = EFindSqlStateType.stnormal;
5603                                break;
5604                            }
5605                            default:
5606                            {
5607                                gcurrentsqlstatement.addtokentolist(ast);
5608                                gst = EFindSqlStateType.stsql;
5609                                break;
5610                            }
5611                        }    // case
5612                    }
5613                    else
5614                    {
5615                        if ( ast.tokencode == TBaseType.rrw_begin )
5616                        {
5617                            gcurrentsqlstatement = new TMssqlBlock(dbVendor);
5618                            gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock;
5619                            gcurrentsqlstatement.addtokentolist(ast);
5620                            gst = EFindSqlStateType.stblock;
5621                        }
5622                        else
5623                        {
5624                            if ( sqlstatements.size() == 0 )
5625                            {
5626                                //first statement of mssql batch, treat it as exec sp
5627                                gst = EFindSqlStateType.stsql;
5628                                gcurrentsqlstatement = new TMssqlExecute(dbVendor);
5629                                //tmssqlexecute(gcurrentsqlstatement).exectype = metnoexeckeyword;
5630// todo need previous line need to be implemented
5631                                gcurrentsqlstatement.addtokentolist(ast);
5632                            }
5633                            else if ( sqlstatements.get(sqlstatements.size() -1).sqlstatementtype == ESqlStatementType.sstmssqlgo )
5634                            {
5635                                // prev sql is go, treat it as exec sp
5636                                gst = EFindSqlStateType.stsql;
5637                                gcurrentsqlstatement = new TMssqlExecute(dbVendor);
5638                                //todo need to be implemented: tmssqlexecute(gcurrentsqlstatement).exectype = metnoexeckeyword;
5639                                gcurrentsqlstatement.addtokentolist(ast);
5640                            }
5641                            else
5642                            {
5643                            }
5644                        }
5645                    }
5646
5647
5648                    if (  !TBaseType.assigned(gcurrentsqlstatement)  ) //error tokentext found
5649                    {
5650
5651
5652                        this.syntaxErrors.add( new TSyntaxError(ast.getAstext(),ast.lineNo,(ast.columnNo < 0 ? 0:ast.columnNo)
5653                                ,"Error when tokenlize", EErrorType.spwarning,TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE,null,ast.posinlist));
5654
5655
5656                        ast.tokentype = ETokenType.tttokenlizererrortoken;
5657                        gst = EFindSqlStateType.sterror;
5658
5659                        gcurrentsqlstatement = new TUnknownSqlStatement(dbVendor);
5660                        gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid;
5661                        gcurrentsqlstatement.addtokentolist(ast);
5662                    }
5663                    break;
5664                }
5665                case stblock:
5666                {
5667                    if ( TBaseType.assigned(lcnextsqlstatement) )
5668                    {
5669                        if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo )
5670                        {
5671                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5672                            gcurrentsqlstatement = lcnextsqlstatement;
5673                            gcurrentsqlstatement.addtokentolist(ast);
5674                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5675                            gst = EFindSqlStateType.stnormal;
5676                        }
5677                        else
5678                        {
5679                            lcnextsqlstatement = null;
5680                        }
5681                    }
5682
5683                    if ( gst == EFindSqlStateType.stblock )
5684                    {
5685                        gcurrentsqlstatement.addtokentolist(ast);
5686                        if ( ast.tokencode == TBaseType.rrw_begin )
5687                        {
5688                            // { [distributed] transaxtion/trans statement
5689                            // { dialog [ conversation ]
5690                            // { conversation timer
5691                            //  doesn't start block ({ .. })
5692                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i,1,false);
5693                            if ( TBaseType.assigned(lcnextsolidtoken) )
5694                            {
5695                                if ( ! ( (lcnextsolidtoken.tokencode ==  TBaseType.rrw_sqlserver_tran)
5696                                        || (lcnextsolidtoken.tokencode ==  TBaseType.rrw_sqlserver_transaction)
5697                                        || (lcnextsolidtoken.tokencode ==  TBaseType.rrw_sqlserver_distributed)
5698                                        || (lcnextsolidtoken.tokencode ==  TBaseType.rrw_sqlserver_dialog)
5699                                        || (lcnextsolidtoken.tokencode ==  TBaseType.rrw_sqlserver_conversation)
5700                                ) )
5701                                    lcblocklevel++;
5702                            }
5703                            else
5704                                lcblocklevel++;
5705
5706                        }
5707                        else if ( ast.tokencode == TBaseType.rrw_case )  // case ... }
5708                            lcblocklevel++;
5709                        else if ( ast.tokencode == TBaseType.rrw_end )
5710                        {
5711
5712                            lcisendconversation = false;
5713
5714
5715                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i,1,false);
5716                            if ( TBaseType.assigned(lcnextsolidtoken) )
5717                            {
5718                                if ( lcnextsolidtoken.tokencode ==  TBaseType.rrw_sqlserver_conversation)
5719                                    lcisendconversation = true; // } conversation statement
5720                            }
5721
5722
5723                            if ( ! lcisendconversation )
5724                            {
5725
5726                                if ( lcblocklevel == 0 )
5727                                {
5728                                    if ( gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif )
5729                                    {
5730                                        if ( TBaseType.assigned(lcnextsolidtoken) )
5731                                        {
5732                                            if ( lcnextsolidtoken.tokencode == TBaseType.rrw_else )
5733                                            {
5734                                                // { .. } else
5735                                                gst = EFindSqlStateType.stsql;
5736                                            }
5737                                            else if ( lcnextsolidtoken.tokentype == ETokenType.ttsemicolon )
5738                                            {
5739                                                lcnnextsolidtoken = sourcetokenlist.nextsolidtoken(lcnextsolidtoken.posinlist,1,false);
5740                                                if ( TBaseType.assigned(lcnnextsolidtoken) )
5741                                                {
5742                                                    if ( lcnnextsolidtoken.tokencode == TBaseType.rrw_else )
5743                                                    {
5744                                                        // { .. } else
5745                                                        gst = EFindSqlStateType.stsql;
5746                                                    }
5747                                                }
5748                                            }
5749                                        }
5750                                    }
5751
5752                                    if ( gst != EFindSqlStateType.stsql )
5753                                    {
5754                                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5755                                        gst = EFindSqlStateType.stnormal;
5756                                    }
5757
5758                                }
5759                                else
5760                                {
5761                                    lcblocklevel--;
5762                                }
5763
5764                            }
5765                        }
5766                    }
5767                    break;
5768                }
5769                case sttrycatch:
5770                {
5771
5772                    if ( TBaseType.assigned(lcnextsqlstatement) )
5773                    {
5774                        if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo )
5775                        {
5776                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5777                            gcurrentsqlstatement = lcnextsqlstatement;
5778                            gcurrentsqlstatement.addtokentolist(ast);
5779                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5780                            gst = EFindSqlStateType.stnormal;
5781                        }
5782                        else
5783                        {
5784                            if (
5785                                    (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)
5786                                            ||(lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch)
5787                                    )
5788                                lctrycatchlevel++;
5789                            lcnextsqlstatement = null;
5790                        }
5791                    }
5792
5793                    if ( gst == EFindSqlStateType.sttrycatch )
5794                    {
5795                        gcurrentsqlstatement.addtokentolist(ast);
5796                        if ( (ast.tokencode == TBaseType.rrw_try) ||
5797                                (ast.tokencode == TBaseType.rrw_catch) )
5798                        {
5799                            // lcprevsolidtoken = sourcetokenlist.solidtokenbefore(i);
5800                            if ( TBaseType.assigned(lcprevsolidtoken) )
5801                            {
5802                                if ( lcprevsolidtoken.tokencode == TBaseType.rrw_end )
5803                                {
5804                                    if ( lctrycatchlevel == 0 )
5805                                    {
5806                                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5807                                        gst = EFindSqlStateType.stnormal;
5808                                    }
5809                                    else
5810                                        lctrycatchlevel--;
5811                                }
5812                            }
5813                        }
5814                    }
5815                    break;
5816                }
5817                case stprocedureWithReturn:
5818                {
5819                    // found return statement in create procedure/function, which means can be ended with a semicolon
5820
5821                    if ( TBaseType.assigned(lcnextsqlstatement) ) {
5822                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
5823                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5824                            gcurrentsqlstatement = lcnextsqlstatement;
5825                            gcurrentsqlstatement.addtokentolist(ast);
5826                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5827                            gst = EFindSqlStateType.stnormal;
5828                            break;
5829                        }
5830                    }
5831
5832                    gcurrentsqlstatement.addtokentolist(ast);
5833                    if ((gst == EFindSqlStateType.stprocedureWithReturn) && (ast.tokentype == ETokenType.ttsemicolon)){
5834
5835                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5836                        gst = EFindSqlStateType.stnormal;
5837                    }
5838                    break;
5839                }
5840                case stsql :
5841                {
5842                    if ( (ast.tokentype == ETokenType.ttsemicolon)   )
5843                    {
5844                        lcstillinsql = false;
5845                        if ( gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif )
5846                        {
5847                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i,1,false);
5848                            if ( TBaseType.assigned(lcnextsolidtoken) )
5849                            {
5850                                if ( lcnextsolidtoken.tokencode == TBaseType.rrw_else )
5851                                {
5852                                    // if ( expr stmt; else
5853                                    gcurrentsqlstatement.addtokentolist(ast);
5854                                    lcstillinsql = true;
5855                                }
5856
5857                            }
5858                        }
5859
5860                        if (  !lcstillinsql )
5861                        {
5862                            gst = EFindSqlStateType.stnormal;
5863                            gcurrentsqlstatement.addtokentolist(ast);
5864                            gcurrentsqlstatement.semicolonended = ast;
5865                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5866                        }
5867
5868                    }
5869                    else if ( TBaseType.assigned(lcnextsqlstatement) )
5870                    {
5871
5872                        if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo )
5873                        {
5874                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5875                            gcurrentsqlstatement = lcnextsqlstatement;
5876                            gcurrentsqlstatement.addtokentolist(ast);
5877                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5878                            gst = EFindSqlStateType.stnormal;
5879                            continue;
5880                        }
5881
5882                        switch(gcurrentsqlstatement.sqlstatementtype){    //
5883                            case sstmssqlif:
5884                            case sstmssqlwhile:
5885                            {
5886                                if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch)
5887                                        ||(lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry))
5888                                {
5889                                    gcurrentsqlstatement.addtokentolist(ast);
5890                                    gst = EFindSqlStateType.stblock;
5891                                    lcblocklevel = 1;
5892                                    lcnextsqlstatement = null;
5893                                    continue;
5894
5895                                }
5896                                // if ( || while only contain one sql(not closed by {/} pair)
5897                                // so will still in if ( || while statement
5898                                else if ( gcurrentsqlstatement.dummytag == 1 )
5899                                {
5900                                    // if ( cond ^stmt nextstmt (^ stands for current pos)
5901                                    gcurrentsqlstatement.addtokentolist(ast);
5902
5903                                    if ( (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
5904                                            || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)
5905                                            )
5906                                        gcurrentsqlstatement.dummytag = 1;
5907                                    else
5908                                        gcurrentsqlstatement.dummytag = 0;
5909
5910
5911                                    lcnextsqlstatement = null;
5912                                    continue;
5913                                }else{
5914                                    // 在 if statement 中,已经遇见过第一个sql语句,现在是碰到第二个,正常情况下这个第二个
5915                                    //IF EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'[DF_TEST]') AND type = 'D')
5916                                    //ALTER TABLE test DROP CONSTRAINT IF EXISTS DF_TEST;
5917
5918                                    if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif){
5919                                        // 上例中的第二个 IF EXISTS 不是真正的 sql, 忽略它
5920                                        if ((ast.nextSolidToken() != null)&&(ast.nextSolidToken().tokencode == TBaseType.rrw_sqlserver_exists)){
5921                                            gcurrentsqlstatement.addtokentolist(ast);
5922                                            lcnextsqlstatement = null;
5923                                            continue;
5924                                        }
5925                                    }
5926                                }
5927                                break;
5928                            }//
5929                            case sstmssqlalterqueue:
5930                            {
5931                                if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlexec )
5932                                {
5933                                    // execute can't be used to delimite alter queue
5934                                    gcurrentsqlstatement.addtokentolist(ast);
5935                                    lcnextsqlstatement = null;
5936                                    continue;
5937
5938                                }
5939                                break;
5940                            }
5941                            case sstmssqlcreateschema:
5942                            {
5943                                gcurrentsqlstatement.addtokentolist(ast);
5944                                lcnextsqlstatement = null;
5945                                continue;
5946                            }
5947                        }//case
5948
5949                        doongetrawsqlstatementevent(gcurrentsqlstatement);
5950                        gcurrentsqlstatement = lcnextsqlstatement;
5951                        gcurrentsqlstatement.addtokentolist(ast);
5952
5953                        switch(gcurrentsqlstatement.sqlstatementtype){    //
5954                            case sstmssqlcreateprocedure:
5955                            case sstmssqlcreatefunction:
5956                            //case sstmssqlcreatetrigger:
5957                            case sstcreatetrigger:
5958                            case sstmssqlalterprocedure:
5959                            case sstmssqlalterfunction:
5960                            case sstmssqlaltertrigger:
5961                            {
5962                                gst = EFindSqlStateType.ststoredprocedure;
5963                                break;
5964                            }
5965                            case sstmssqlbegintry:
5966                            case sstmssqlbegincatch:
5967                            {
5968                                gst = EFindSqlStateType.sttrycatch;
5969                                lctrycatchlevel = 0;
5970                                break;
5971                            }
5972                            case sstmssqlgo:
5973                            {
5974                                gst = EFindSqlStateType.stnormal;
5975                                break;
5976                            }
5977                            default:
5978                            {
5979                                gst = EFindSqlStateType.stsql;
5980                                break;
5981                            }
5982                        }    // case
5983
5984                    }//TBaseType.assigned(lcnextsqlstatement)
5985                    else if ( (ast.tokencode == TBaseType.rrw_begin) )
5986                    {
5987                        if ( (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
5988                                || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)
5989                                )
5990                        {
5991                            // start block of if ( || while statement
5992                            gst = EFindSqlStateType.stblock;
5993                            lcblocklevel = 0;
5994                            gcurrentsqlstatement.addtokentolist(ast);
5995                        }
5996                        else if ( gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqldeclare )
5997                        {
5998                            doongetrawsqlstatementevent(gcurrentsqlstatement);
5999                            gcurrentsqlstatement = new TMssqlBlock(dbVendor);
6000                            gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock;
6001                            gcurrentsqlstatement.addtokentolist(ast);
6002                            gst = EFindSqlStateType.stblock;
6003                        }
6004                        else
6005                        {
6006                            gcurrentsqlstatement.addtokentolist(ast);
6007                        }
6008                    }
6009                    else if ( (ast.tokencode == TBaseType.rrw_case) ){
6010                        case_end_nest++;
6011                        gcurrentsqlstatement.addtokentolist(ast);
6012                    }
6013                    else if ( (ast.tokencode == TBaseType.rrw_end) ){
6014                        if (case_end_nest > 0){
6015                            case_end_nest--;
6016                        }
6017                        gcurrentsqlstatement.addtokentolist(ast);
6018                    }
6019                    else if ( (ast.tokencode == TBaseType.rrw_else) )
6020                    {
6021                        gcurrentsqlstatement.addtokentolist(ast);
6022                        // if ( cond stmt ^else stmt
6023                        if (( (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
6024                                || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)
6025                        ) && (case_end_nest == 0))
6026                            gcurrentsqlstatement.dummytag = 1; // reduce to 1 while stmt after else is found: if ( cond stmt ^else stmt
6027                    }
6028                    else
6029                    {
6030                        gcurrentsqlstatement.addtokentolist(ast);
6031                    }
6032                    break;
6033                }
6034                case ststoredprocedure:
6035                {
6036                    if ( TBaseType.assigned(lcnextsqlstatement) )
6037                    {
6038                        if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo )
6039                        {
6040                            doongetrawsqlstatementevent(gcurrentsqlstatement);
6041                            gcurrentsqlstatement = lcnextsqlstatement;
6042                            gcurrentsqlstatement.addtokentolist(ast);
6043                            doongetrawsqlstatementevent(gcurrentsqlstatement);
6044                            gst = EFindSqlStateType.stnormal;
6045                        }
6046                        else if (lcnextsqlstatement.sqlstatementtype == sstmssqlreturn)
6047                        {
6048                            gst = EFindSqlStateType.stprocedureWithReturn;
6049                            gcurrentsqlstatement.addtokentolist(ast);
6050                            lcnextsqlstatement = null;
6051                        }
6052                        else
6053                        {
6054                            gst = EFindSqlStateType.ststoredprocedurebody;
6055                            gcurrentsqlstatement.addtokentolist(ast);
6056
6057                            lcnextsqlstatement = null;
6058                        }
6059                    }
6060
6061                    if ( gst == EFindSqlStateType.ststoredprocedure )
6062                    {
6063                        gcurrentsqlstatement.addtokentolist(ast);
6064                        if ( ast.tokencode == TBaseType.rrw_begin )
6065                        {
6066                            gst = EFindSqlStateType.stblock;
6067                        }
6068                    }
6069                    break;
6070                } //stplsql
6071                case ststoredprocedurebody:
6072                {
6073                    if ( TBaseType.assigned(lcnextsqlstatement) )
6074                    {
6075                        switch(lcnextsqlstatement.sqlstatementtype){    //
6076                            case sstmssqlgo:
6077                            {
6078                                doongetrawsqlstatementevent(gcurrentsqlstatement);
6079                                gcurrentsqlstatement = lcnextsqlstatement;
6080                                gcurrentsqlstatement.addtokentolist(ast);
6081                                doongetrawsqlstatementevent(gcurrentsqlstatement);
6082                                gst = EFindSqlStateType.stnormal;
6083                                break;
6084                            }
6085                            case sstmssqlcreateprocedure:
6086                            case sstmssqlcreatefunction:
6087                            //case sstmssqlcreatetrigger:
6088                            case sstcreatetrigger:
6089                            case sstmssqlalterprocedure:
6090                            case sstmssqlalterfunction:
6091                            case sstmssqlaltertrigger:
6092                            {
6093                                doongetrawsqlstatementevent(gcurrentsqlstatement);
6094                                gcurrentsqlstatement = lcnextsqlstatement;
6095                                gcurrentsqlstatement.addtokentolist(ast);
6096                                gst = EFindSqlStateType.ststoredprocedure;
6097                                break;
6098                            }
6099                            case sstcreateview:
6100                            case sstcreatetable:
6101                            {
6102
6103                                boolean readForNewStmt = false;
6104                                TSourceToken st1 = ast.searchToken(';',-1);
6105                                if (st1 != null) {
6106                                    TSourceToken st2 = ast.searchToken(TBaseType.rrw_end,-2);
6107                                    if (st2 != null){
6108                                        readForNewStmt = true;
6109                                    }
6110                                }
6111
6112                                if (readForNewStmt){
6113                                    doongetrawsqlstatementevent(gcurrentsqlstatement);
6114                                    gcurrentsqlstatement = lcnextsqlstatement;
6115                                    gcurrentsqlstatement.addtokentolist(ast);
6116                                    gst = EFindSqlStateType.stsql;
6117                                }else{
6118                                    lcnextsqlstatement = null;
6119                                }
6120                                break;
6121                            }
6122                            case sstmssqlDropSecurityPolicy:
6123                            case sstmssqlAlterSecurityPolicy:
6124                            case sstmssqlCreateSecurityPolicy:
6125                                doongetrawsqlstatementevent(gcurrentsqlstatement);
6126                                gcurrentsqlstatement = lcnextsqlstatement;
6127                                gcurrentsqlstatement.addtokentolist(ast);
6128                                gst = EFindSqlStateType.stsql;
6129
6130                                    break;
6131                            default:
6132                            {
6133                                lcnextsqlstatement = null;
6134                                break;
6135                            }
6136                        }//case
6137                    }
6138
6139                    if ( gst == EFindSqlStateType.ststoredprocedurebody )
6140                        gcurrentsqlstatement.addtokentolist(ast);
6141                }
6142                break;
6143            } //case
6144        } //for
6145
6146
6147        //last statement
6148        if ( TBaseType.assigned(gcurrentsqlstatement) &&  (gst != EFindSqlStateType.stnormal))
6149        {
6150            doongetrawsqlstatementevent(gcurrentsqlstatement,true);
6151        }
6152
6153        return errorcount;
6154
6155    }
6156
6157
6158    private TCustomSqlStatement startDaxStmt(TSourceToken currToken,TCustomSqlStatement currStmt){
6159        TCustomSqlStatement newStmt = null;
6160        if (currToken == null) return null;
6161        if ((currToken.tokencode == '=')&&(currToken.isFirstTokenOfLine())){
6162            currToken.tokencode = TBaseType.equal_start_expr;
6163            newStmt = new TDaxExprStmt(EDbVendor.dbvdax);
6164        }else if ((currToken.tokencode == TBaseType.rrw_dax_define)&&(currToken.isFirstTokenOfLine())){
6165            newStmt = new TDaxEvaluateStmt(EDbVendor.dbvdax);
6166            ((TDaxEvaluateStmt)newStmt).setStartWithDefine(true);
6167        }else if ((currToken.tokencode == TBaseType.rrw_dax_evaluate)&&(currToken.isFirstTokenOfLine())){
6168            if ((currStmt != null)&&(currStmt instanceof TDaxEvaluateStmt)){
6169                TDaxEvaluateStmt tmp = (TDaxEvaluateStmt)currStmt;
6170                if (tmp.isStartWithDefine()) return  null;
6171            }
6172            newStmt = new TDaxEvaluateStmt(EDbVendor.dbvdax);
6173        }
6174
6175        if (newStmt == null){
6176            // let's check is this the first token of query
6177            boolean isFirst = currToken.isFirstTokenOfLine();
6178            TSourceToken prevToken = currToken.prevSolidToken();
6179            if ((isFirst)&&(prevToken == null)){
6180                newStmt = new TDaxExprStmt(EDbVendor.dbvdax);
6181            }
6182        }
6183        return newStmt;
6184    }
6185
6186int dogetrawsqlstatements(){
6187
6188    sqlstatements.clear();
6189    if (sourcetokenlist.size() == 0) return -1;
6190
6191    switch(dbVendor){
6192        case dbvpostgresql:{
6193            return dopostgresqlgetrawsqlstatements();
6194        }
6195        case dbvclickhouse:{
6196            return doclickhousegetrawsqlstatements();
6197        }
6198        default:{
6199            return domssqlgetrawsqlstatements();
6200        }
6201    }
6202
6203}
6204
6205    /**
6206     *  separates the SQL statements in the input SQL script without doing syntax check.
6207     *  <p></p>
6208     *  Use the {@link #getSqlstatements()} method to get the list of SQL statements.
6209     *  The SQL statement object is the instance of the sub-class of {@link TCustomSqlStatement}, get SQL statement type
6210     *  via the {@link TCustomSqlStatement#sqlstatementtype} field, get string representation of
6211     *  each SQL statement via the {@link TCustomSqlStatement#toString} method.
6212     *  <p></p>
6213     *  All source tokens in this SQL statement
6214     *  is available by using {@link TCustomSqlStatement#sourcetokenlist} filed.
6215     *  Since no parse tree is built by calling this method, no further detailed information about the SQL statement is available.
6216     *
6217      * @return 0 if get SQL statements successfully
6218     */
6219public int getrawsqlstatements(){
6220    // Check for vendor parser delegation (MSSQL, etc.)
6221    // This ensures raw-split logic is maintained in only one place (vendor parser)
6222    SqlParser vp = getOrCreateVendorParser();
6223    if (vp != null) {
6224        return doDelegatedRawParse(vp);
6225    }
6226
6227    // Legacy path for non-delegated vendors
6228    int ret = readsql();
6229    if (ret != 0) return ret;
6230    dosqltexttotokenlist();
6231
6232    return dogetrawsqlstatements();
6233}
6234
6235    /**
6236     *  turns the input SQL into a sequence of token which is the
6237     *  basic lexis element of SQL syntax. Token is categorized as keyword, identifier,
6238     *  number, operator, whitespace and other types. All source tokens can be fetched
6239     *  via the {@link #getSourcetokenlist()} method.
6240     *
6241     */
6242public void tokenizeSqltext(){
6243    // Check for vendor parser delegation (MSSQL, etc.)
6244    // This ensures tokenization logic is maintained in only one place (vendor parser)
6245    SqlParser vp = getOrCreateVendorParser();
6246    if (vp != null) {
6247        doDelegatedTokenize(vp);
6248        return;
6249    }
6250
6251    // Legacy path for non-delegated vendors
6252    getFlexer();
6253    readsql();
6254    dosqltexttotokenlist();
6255}
6256
6257/**
6258 * Delegate tokenization to vendor parser and backfill results.
6259 * Similar to doDelegatedRawParse but only performs tokenization.
6260 */
6261private void doDelegatedTokenize(SqlParser vendorParser) {
6262    // Build context for vendor parser
6263    ParserContext context = buildContext();
6264
6265    // Delegate tokenization to vendor parser
6266    SqlParseResult tokenResult = vendorParser.tokenize(context);
6267
6268    // Copy results back to TGSqlParser fields for backward compatibility
6269    if (tokenResult.getSourceTokenList() != null) {
6270        this.sourcetokenlist = tokenResult.getSourceTokenList();
6271    }
6272    if (tokenResult.getLexer() != null) {
6273        this.flexer = tokenResult.getLexer();
6274    }
6275}
6276
6277
6278
6279void findAllSyntaxErrorsInPlsql(TCustomSqlStatement psql){
6280    if (psql.getErrorCount() > 0){
6281        copyerrormsg(psql);
6282    }
6283
6284    for (int k=0;k<psql.getStatements().size();k++){
6285        findAllSyntaxErrorsInPlsql(psql.getStatements().get(k));
6286    }
6287
6288}
6289
6290private TSQLEnv sqlEnv = null;
6291
6292    /**
6293     * SQL environment includes the database metadata such as procedure, function, trigger, table and etc.
6294     *
6295     * In order to link column to table correctly without connecting to database,
6296     * we need to provide a class which implements {@link TSQLEnv} to TGSqlParser.
6297     * this class tells TGSqlParser the relationship between column and table.
6298     *
6299     * <p>Take this SQL for example:
6300     * <pre>
6301     * SELECT Quantity,b.Time,c.Description
6302     * FROM
6303     * (SELECT ID2,Time FROM bTab) b
6304     * INNER JOIN aTab a on a.ID=b.ID
6305     * INNER JOIN cTab c on a.ID=c.ID
6306     * </pre>
6307     *
6308     * <p>General SQL Parser can build relationship between column: ID2 and table: bTable
6309     * correctly without metadata information from database because there is only one table
6310     * in from clause. But it can't judge column: Quantity belong to table: aTab or cTab,
6311     * since no table alias was prefixed to column: Quantity. If no metadata provided,
6312     * General SQL Parser will link column: Quantity to the first valid table (here it is aTab)
6313     *
6314     * <p>If we create a class  TRealDatabaseSQLEnv implements {@link TSQLEnv},then
6315     *  {@link #setSqlEnv(TSQLEnv)}, General SQL Parser can take this advantage to create
6316     *  a correct relationship between column and tables.
6317     *
6318     *<pre>
6319     * class TSQLServerEnv extends TSQLEnv{
6320     *
6321     *  public TSQLServerEnv(){
6322     *          super(EDbVendor.dbvmssql);
6323     *          initSQLEnv();
6324     *        }
6325     *
6326     *    &#64;Override
6327     *    public void initSQLEnv() {
6328     *
6329     *          // add a new database: master
6330     *          TSQLCatalog sqlCatalog = createSQLCatalog("master");
6331     *          // add a new schema: dbo
6332     *          TSQLSchema sqlSchema = sqlCatalog.createSchema("dbo");
6333     *          //add a new table: aTab
6334     *          TSQLTable aTab = sqlSchema.createTable("aTab");
6335     *          aTab.addColumn("Quantity1");
6336     *
6337     *          //add a new table: bTab
6338     *          TSQLTable bTab = sqlSchema.createTable("bTab");
6339     *          bTab.addColumn("Quantity2");
6340     *
6341     *          //add a new table: cTab
6342     *          TSQLTable cTab = sqlSchema.createTable("cTab");
6343     *          cTab.addColumn("Quantity");
6344     *
6345     *    }
6346     * }
6347     * </pre>
6348     *
6349     * @return SQL environment
6350     */
6351    public TSQLEnv getSqlEnv() {
6352        return sqlEnv;
6353    }
6354
6355    private boolean onlyNeedRawParseTree = false;
6356
6357    public void setOnlyNeedRawParseTree(boolean onlyNeedRawParseTree) {
6358        this.onlyNeedRawParseTree = onlyNeedRawParseTree;
6359    }
6360
6361    public void setSqlEnv(TSQLEnv sqlEnv) {
6362        this.sqlEnv = sqlEnv;
6363    }
6364
6365
6366     // Time tracking variables
6367     private boolean enableTimeLogging = false;
6368     private long rawSqlStatementsTime = 0;
6369     private long parsingTime = 0;
6370     private long semanticAnalysisTime = 0;
6371     private long interpreterTime = 0;
6372     
6373     /**
6374      * Enable or disable time logging for parser steps
6375      * @param enable true to enable time logging, false to disable
6376      */
6377     public void setEnableTimeLogging(boolean enable) {
6378         this.enableTimeLogging = enable;
6379     }
6380     
6381     /**
6382      * Check if time logging is enabled
6383      * @return true if time logging is enabled, false otherwise
6384      */
6385     public boolean isTimeLoggingEnabled() {
6386         return this.enableTimeLogging;
6387     }
6388     
6389     /**
6390      * Reset all accumulated time counters to zero
6391      */
6392     public void resetTimeCounters() {
6393         rawSqlStatementsTime = 0;
6394         parsingTime = 0;
6395         semanticAnalysisTime = 0;
6396         interpreterTime = 0;
6397     }
6398     
6399     /**
6400      * Get accumulated time spent getting raw SQL statements in milliseconds
6401      * @return time in milliseconds
6402      */
6403     public long getRawSqlStatementsTime() {
6404         return rawSqlStatementsTime;
6405     }
6406     
6407     /**
6408      * Get accumulated time spent parsing in milliseconds
6409      * @return time in milliseconds
6410      */
6411     public long getParsingTime() {
6412         return parsingTime;
6413     }
6414     
6415     /**
6416      * Get accumulated time spent on semantic analysis in milliseconds
6417      * @return time in milliseconds
6418      */
6419     public long getSemanticAnalysisTime() {
6420         return semanticAnalysisTime;
6421     }
6422     
6423     /**
6424      * Get accumulated time spent in interpreter in milliseconds
6425      * @return time in milliseconds
6426      */
6427     public long getInterpreterTime() {
6428         return interpreterTime;
6429     }
6430     
6431     /**
6432      * Get total accumulated time spent in all steps
6433      * @return total time in milliseconds
6434      */
6435     public long getTotalTime() {
6436         return rawSqlStatementsTime + parsingTime + semanticAnalysisTime + interpreterTime;
6437     }
6438
6439    /**
6440     * Get or create the vendor-specific parser for delegation.
6441     * The parser is cached in vendorParser field and reused for subsequent calls.
6442     * This allows getFlexer() to lazily create the parser to access its lexer.
6443     *
6444     * @return vendor-specific SqlParser or null if not a delegated vendor
6445     * @since 3.2.0.0
6446     */
6447    private SqlParser getOrCreateVendorParser() {
6448        // Return cached parser if available
6449        if (vendorParser != null) {
6450            return vendorParser;
6451        }
6452
6453        // Create new vendor parser based on database vendor
6454        switch (dbVendor) {
6455            case dbvmssql:
6456            case dbvazuresql:
6457                vendorParser = new gudusoft.gsqlparser.parser.MssqlSqlParser();
6458                break;
6459            case dbvmysql:
6460                vendorParser = new gudusoft.gsqlparser.parser.MySqlSqlParser();
6461                break;
6462            case dbvpostgresql:
6463                vendorParser = new gudusoft.gsqlparser.parser.PostgreSqlParser();
6464                break;
6465            case dbvoracle:
6466                vendorParser = new gudusoft.gsqlparser.parser.OracleSqlParser();
6467                break;
6468            case dbvbigquery:
6469                vendorParser = new gudusoft.gsqlparser.parser.BigQuerySqlParser();
6470                break;
6471            case dbvathena:
6472                vendorParser = new gudusoft.gsqlparser.parser.AthenaSqlParser();
6473                break;
6474            case dbvcouchbase:
6475                vendorParser = new gudusoft.gsqlparser.parser.CouchbaseSqlParser();
6476                break;
6477            case dbvdatabricks:
6478                vendorParser = new gudusoft.gsqlparser.parser.DatabricksSqlParser();
6479                break;
6480            case dbvdax:
6481                vendorParser = new gudusoft.gsqlparser.parser.DaxSqlParser();
6482                break;
6483            case dbvdb2:
6484                vendorParser = new gudusoft.gsqlparser.parser.Db2SqlParser();
6485                break;
6486            case dbvgaussdb:
6487                vendorParser = new gudusoft.gsqlparser.parser.GaussDbSqlParser();
6488                break;
6489            case dbvgreenplum:
6490                vendorParser = new gudusoft.gsqlparser.parser.GreenplumSqlParser();
6491                break;
6492            case dbvhive:
6493                vendorParser = new gudusoft.gsqlparser.parser.HiveSqlParser();
6494                break;
6495            case dbvhana:
6496                vendorParser = new gudusoft.gsqlparser.parser.HanaSqlParser();
6497                break;
6498            case dbvimpala:
6499                vendorParser = new gudusoft.gsqlparser.parser.ImpalaSqlParser();
6500                break;
6501            case dbvinformix:
6502                vendorParser = new gudusoft.gsqlparser.parser.InformixSqlParser();
6503                break;
6504            case dbvmdx:
6505                vendorParser = new gudusoft.gsqlparser.parser.MdxSqlParser();
6506                break;
6507            case dbvnetezza:
6508                vendorParser = new gudusoft.gsqlparser.parser.NetezzaSqlParser();
6509                break;
6510            case dbvodbc:
6511                vendorParser = new gudusoft.gsqlparser.parser.OdbcSqlParser();
6512                break;
6513            case dbvopenedge:
6514                vendorParser = new gudusoft.gsqlparser.parser.OpenEdgeSqlParser();
6515                break;
6516            case dbvpresto:
6517                vendorParser = new gudusoft.gsqlparser.parser.PrestoSqlParser();
6518                break;
6519            case dbvredshift:
6520                vendorParser = new gudusoft.gsqlparser.parser.RedshiftSqlParser();
6521                break;
6522            case dbvsnowflake:
6523                vendorParser = new gudusoft.gsqlparser.parser.SnowflakeSqlParser();
6524                break;
6525            case dbvsoql:
6526                vendorParser = new gudusoft.gsqlparser.parser.SoqlSqlParser();
6527                break;
6528            case dbvsparksql:
6529                vendorParser = new gudusoft.gsqlparser.parser.SparksqlSqlParser();
6530                break;
6531            case dbvsybase:
6532                vendorParser = new gudusoft.gsqlparser.parser.SybaseSqlParser();
6533                break;
6534            case dbvteradata:
6535                vendorParser = new gudusoft.gsqlparser.parser.TeradataSqlParser();
6536                break;
6537            case dbvvertica:
6538                vendorParser = new gudusoft.gsqlparser.parser.VerticaSqlParser();
6539                break;
6540            case dbvansi:
6541                vendorParser = new gudusoft.gsqlparser.parser.AnsiSqlParser();
6542                break;
6543            default:
6544                return null;
6545        }
6546        return vendorParser;
6547    }
6548
6549    /**
6550     * Prepare this parser for reuse by clearing cached state.
6551     * This is useful when reusing a TGSqlParser instance (e.g., in TExecImmeStmt)
6552     * to avoid state pollution between parsing operations.
6553     *
6554     * Clears: vendorParser, sqlEnv, sqlfilename, and resets parsing options.
6555     *
6556     * @since 3.2.0.0
6557     */
6558    public void prepareForReuse() {
6559        // Clear cached vendor parser to force recreation
6560        this.vendorParser = null;
6561        // Clear SQL environment to avoid old schema information affecting new parse
6562        this.sqlEnv = null;
6563        // Clear filename in case it was set previously
6564        this.sqlfilename = null;
6565        // Reset parsing options to defaults
6566        this.isSinglePLBlock = false;
6567        // Clear statement list
6568        if (this.sqlstatements != null) {
6569            this.sqlstatements.clear();
6570        }
6571        // Clear error state
6572        this.syntaxErrors.clear();
6573    }
6574
6575    /**
6576     * Build a ParserContext from current TGSqlParser state.
6577     * This creates an immutable context for delegation to vendor parsers.
6578     *
6579     * @return immutable ParserContext
6580     * @since 3.2.0.0
6581     */
6582    private ParserContext buildContext() {
6583        ParserContext.Builder builder = new ParserContext.Builder(this.dbVendor);
6584
6585        // Set SQL text source (only one will be non-null or non-empty)
6586        // CRITICAL: Check for non-null AND non-empty because TGSqlParser initializes sqltext=""
6587        // which would cause vendor parser to use empty string instead of reading from file
6588        if (this.sqltext != null && !this.sqltext.isEmpty()) {
6589            builder.sqlText(this.sqltext);
6590        }
6591        if (this.sqlfilename != null && !this.sqlfilename.isEmpty()) {
6592            builder.sqlFilename(this.sqlfilename);
6593        }
6594
6595        // Set charset
6596        if (this.sqlCharset != null) {
6597            builder.sqlCharset(this.sqlCharset);
6598        }
6599
6600        // Set parsing options
6601        builder.enablePartialParsing(this.isEnablePartialParsing());
6602        builder.singlePLBlock(this.isSinglePLBlock);
6603
6604        // Set gsqlparser reference for backward compatibility
6605        builder.gsqlparser(this);
6606
6607        // Set SQL environment if available
6608        if (this.sqlEnv != null) {
6609            builder.sqlEnv(this.sqlEnv);
6610        }
6611
6612        // Set token handle for callback during tokenization
6613        if (this.tokenHandle != null) {
6614            builder.tokenHandle(this.tokenHandle);
6615        }
6616
6617        return builder.build();
6618    }
6619
6620     /**
6621      * Returns time statistics as a formatted string
6622      * @return formatted string with time statistics
6623      */
6624     public String getTimeStatistics() {
6625         if (!enableTimeLogging) {
6626             return "Time logging is disabled";
6627         }
6628         
6629         StringBuilder sb = new StringBuilder();
6630         sb.append(String.format("Time statistics for TGSqlParser version: %s, released at: %s, dbvendor: %s:\n", TBaseType.versionid,TBaseType.releaseDate, this.dbVendor));
6631         sb.append(String.format("1. Raw SQL statements: %d ms (%.2f%%)\n", 
6632                 rawSqlStatementsTime,
6633                 getTotalTime() > 0 ? 100.0 * rawSqlStatementsTime / getTotalTime() : 0));
6634         sb.append(String.format("2. Parsing: %d ms (%.2f%%)\n", 
6635                 parsingTime,
6636                 getTotalTime() > 0 ? 100.0 * parsingTime / getTotalTime() : 0));
6637         sb.append(String.format("3. Semantic analysis: %d ms (%.2f%%)\n", 
6638                 semanticAnalysisTime,
6639                 getTotalTime() > 0 ? 100.0 * semanticAnalysisTime / getTotalTime() : 0));
6640         sb.append(String.format("4. Interpreter: %d ms (%.2f%%)\n", 
6641                 interpreterTime,
6642                 getTotalTime() > 0 ? 100.0 * interpreterTime / getTotalTime() : 0));
6643         sb.append(String.format("Total: %d ms", getTotalTime()));
6644         return sb.toString();
6645     }
6646
6647    /**
6648     * Delegate only tokenization and raw statement extraction to vendor parser.
6649     * The actual AST parsing is done by the common parsing loop in doparse().
6650     * This architecture ensures that:
6651     * 1. Vendor-specific tokenization/lexing is handled by vendor parser
6652     * 2. Raw statement extraction (splitting SQL text into statements) is vendor-specific
6653     * 3. AST parsing (building parse tree for each statement) uses common code path
6654     *
6655     * @param vendorParser the vendor-specific parser to use
6656     * @return 0 if successful, non-zero on error
6657     */
6658    private int doDelegatedRawParse(SqlParser vendorParser) {
6659        long phaseStart, phaseEnd;
6660
6661        // Build context for vendor parser
6662        ParserContext context = buildContext();
6663
6664        // Delegate only tokenization + raw statement extraction to vendor parser
6665        phaseStart = enableTimeLogging ? System.currentTimeMillis() : 0;
6666        SqlParseResult rawResult = vendorParser.getrawsqlstatements(context);
6667        if (enableTimeLogging) {
6668            phaseEnd = System.currentTimeMillis();
6669            rawSqlStatementsTime += (phaseEnd - phaseStart);
6670        }
6671
6672        // Copy results back to TGSqlParser fields for backward compatibility
6673        if (rawResult.getSourceTokenList() != null) {
6674            this.sourcetokenlist = rawResult.getSourceTokenList();
6675            this.sourcetokenlist.setGsqlparser(this);
6676        }
6677        if (rawResult.getLexer() != null) {
6678            this.flexer = rawResult.getLexer();
6679        }
6680        // Copy parser from vendor parser result - needed for parsestatement()
6681        if (rawResult.getParser() != null) {
6682            this.fparser = rawResult.getParser();
6683            // CRITICAL: Set gsqlparser on NodeFactory for correct AST construction
6684            this.fparser.getNf().setGsqlParser(this);
6685        }
6686        // Copy secondary parser (for Oracle PL/SQL) and set its NodeFactory
6687        if (rawResult.getSecondaryParser() != null) {
6688            this.fplsqlparser = rawResult.getSecondaryParser();
6689            // CRITICAL: Also set gsqlparser on secondary parser's NodeFactory
6690            // This is needed for Oracle PL/SQL statements which use fplsqlparser for parsing
6691            this.fplsqlparser.getNf().setGsqlParser(this);
6692        }
6693        if (rawResult.getSqlStatements() != null) {
6694            this.sqlstatements = rawResult.getSqlStatements();
6695        }
6696
6697        // Copy any tokenization errors
6698        if (rawResult.getSyntaxErrors() != null) {
6699            for (TSyntaxError error : rawResult.getSyntaxErrors()) {
6700                this.syntaxErrors.add(error);
6701            }
6702        }
6703
6704        return rawResult.getErrorCode();
6705    }
6706
6707     int doparse() {
6708         int j;
6709         long startTime, endTime;
6710         boolean useDelegatedRawParse = false;
6711
6712         // 1. Get raw SQL statements
6713         // For delegated vendors, use vendor parser for tokenization + raw extraction
6714         // The parsing loop below is common for all vendors
6715         SqlParser vp = getOrCreateVendorParser();
6716         if (vp != null) {
6717             int ret = doDelegatedRawParse(vp);
6718             if (ret != 0) {
6719                 // Tokenization/extraction failed, return error
6720                 return ret;
6721             }
6722             useDelegatedRawParse = true;
6723             // Continue to common parsing loop below
6724         }
6725
6726         // Legacy path: get raw statements for non-delegated vendors
6727         if (!useDelegatedRawParse) {
6728             startTime = enableTimeLogging ? System.currentTimeMillis() : 0;
6729
6730             int ret = getrawsqlstatements();
6731
6732             if (enableTimeLogging) {
6733                 endTime = System.currentTimeMillis();
6734                 rawSqlStatementsTime += (endTime - startTime);
6735             }
6736         }
6737
6738         boolean isPushGloablStack = false;
6739         //if (ret != 0) return ret;
6740         TFrame firstFrame = null;
6741 
6742         globalContext = new TContext();
6743 
6744         if (this.sqlEnv == null) {
6745             this.sqlEnv = new TSQLEnv(this.dbVendor) {
6746                 @Override
6747                 public void initSQLEnv() {
6748                 }
6749             };
6750             // this.sqlEnv.setEnableGetMetadataFromDDL(false);
6751         }
6752         globalContext.setSqlEnv(this.sqlEnv, this.sqlstatements);
6753 
6754         //TStackFrame stackFrame = new TStackFrame(new TGlobalScope());
6755         if (getFrameStack().size() == 0) { // stack passed from outside gsqlparser will contain frames
6756             //getFrameStack().push(new TStackFrame(new TGlobalScope()));
6757             TGlobalScope globalScope = new TGlobalScope();
6758             globalScope.resetCurrentStmtIndex();
6759 
6760             globalScope.setSqlEnv(this.sqlEnv);
6761             firstFrame = new TFrame(globalScope);
6762             firstFrame.pushMeToStack(getFrameStack());
6763             isPushGloablStack = true;
6764         }
6765 
6766         // 2. start parsing
6767         startTime = enableTimeLogging ? System.currentTimeMillis() : 0;
6768         
6769         for (int i = 0; i < sqlstatements.size(); i++) {
6770             sqlstatements.getRawSql(i).setFrameStack(frameStack);
6771             j = sqlstatements.getRawSql(i).parsestatement(null, false, onlyNeedRawParseTree);
6772
6773             // NOTE: No need for setGsqlparserRecursively() here for delegated vendors.
6774             // The gsqlparser reference is already set on all AST nodes through two mechanisms:
6775             // 1. doDelegatedRawParse() sets fparser.getNf().setGsqlParser(this) and
6776             //    fplsqlparser.getNf().setGsqlParser(this) BEFORE parsestatement() is called
6777             // 2. TNodeFactory.createNode() propagates gsqlparser to every node it creates
6778             // The recursive walk was causing 4-5x performance degradation for Oracle parsing
6779             // by redundantly traversing the entire AST after parsing.
6780
6781             TCustomSqlStatement sql0 = null;
6782             if (sqlstatements.get(i).isoracleplsql()) {
6783                 // check syntax error in select/insert statement inside plsql
6784                 sql0 = sqlstatements.get(i);
6785                 findAllSyntaxErrorsInPlsql(sql0);
6786             }
6787 
6788             boolean doRecover = TBaseType.ENABLE_ERROR_RECOVER_IN_CREATE_TABLE;
6789 
6790             if (doRecover && ((j != 0) || (sqlstatements.get(i).getErrorCount() > 0))) {
6791                 if (((sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstcreatetable)
6792                         || ((sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstcreateindex) && (dbVendor != EDbVendor.dbvcouchbase))
6793                         ) && (!TBaseType.c_createTableStrictParsing)
6794                 ) {
6795                     // only parse main body of create table,
6796                     TCustomSqlStatement errorSqlStatement = (TCustomSqlStatement) sqlstatements.get(i);
6797 
6798                     int nested = 0;
6799                     boolean isIgnore = false, isFoundIgnoreToken = false;
6800                     TSourceToken firstIgnoreToken = null;
6801                     for (int k = 0; k < errorSqlStatement.sourcetokenlist.size(); k++) {
6802                         TSourceToken st = errorSqlStatement.sourcetokenlist.get(k);
6803                         if (isIgnore) {
6804                             if (st.issolidtoken() && (st.tokencode != ';')) {
6805                                 isFoundIgnoreToken = true;
6806                                 if (firstIgnoreToken == null) {
6807                                     firstIgnoreToken = st;
6808                                 }
6809                             }
6810                             if (st.tokencode != ';') {
6811                                 st.tokencode = TBaseType.sqlpluscmd;
6812                             }
6813                             continue;
6814                         }
6815                         if (st.tokencode == (int) ')') {
6816                             nested--;
6817                             if (nested == 0) {
6818                                 //let's check is next token is
6819                                 // as ( select
6820                                 boolean isSelect = false;
6821                                 TSourceToken st1 = st.searchToken(TBaseType.rrw_as, 1);
6822                                 if (st1 != null) {
6823                                     TSourceToken st2 = st.searchToken((int) '(', 2);
6824                                     if (st2 != null) {
6825                                         TSourceToken st3 = st.searchToken(TBaseType.rrw_select, 3);
6826                                         isSelect = (st3 != null);
6827                                     }
6828                                 }
6829                                 if (!isSelect) isIgnore = true;
6830                             }
6831                         }
6832                         if ((st.tokencode == (int) '(') || (st.tokencode == TBaseType.left_parenthesis_2)) {
6833                             nested++;
6834                         }
6835                     }
6836 
6837                     if ((dbVendor == EDbVendor.dbvoracle) && ((firstIgnoreToken != null) && (!TBaseType.searchOracleTablePros(firstIgnoreToken.toString())))) {
6838                         // if it is not the valid Oracle table properties option, let raise the error.
6839                         isFoundIgnoreToken = false;
6840                     }
6841                     if (isFoundIgnoreToken) {
6842                         errorSqlStatement.clearError();
6843                         j = sqlstatements.get(i).parsestatement(null, false);
6844                     }
6845                 }
6846 
6847                 if (((sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstcreatetrigger)
6848                         || (sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstcreatefunction)
6849                         || (sqlstatements.get(i).sqlstatementtype == sstcreateprocedure)
6850                         ) && (dbVendor == EDbVendor.dbvdb2)) { 
6851                     // db2 can handle Oracle pl/sql code, so we give it a try here
6852                     TCustomSqlStatement stmt = sqlstatements.get(i);
6853                     StringBuffer stmtStr = new StringBuffer(1024);
6854                     for (int k = 0; k < stmt.sourcetokenlist.size(); k++) {
6855                         stmtStr.append(stmt.sourcetokenlist.get(k).getAstext());
6856                     }
6857 
6858                     TGSqlParser lc_sqlparser = new TGSqlParser(EDbVendor.dbvoracle);
6859                     lc_sqlparser.sqltext = stmtStr.toString();
6860                     int iRet = lc_sqlparser.parse();
6861                     if (iRet == 0) {
6862                         sqlstatements.remove(i);
6863                         sqlstatements.add(i, lc_sqlparser.sqlstatements.get(0));
6864                         continue;
6865                     }
6866                 }
6867             }
6868 
6869             if ((j != 0) || (sqlstatements.get(i).getErrorCount() > 0)) {
6870                 copyerrormsg(sqlstatements.get(i));
6871 
6872                 if ((isEnablePartialParsing()) && (dbVendor == EDbVendor.dbvsybase) && (sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstmssqlcreateprocedure)) {
6873                     TMssqlCreateProcedure createProcedure = (TMssqlCreateProcedure) sqlstatements.get(i);
6874 
6875                     StringBuffer storedProcedure = new StringBuffer(1024);
6876                     boolean ASKeyword = false;
6877                     for (int k = 0; k < createProcedure.sourcetokenlist.size(); k++) {
6878                         if ((!ASKeyword) && (createProcedure.sourcetokenlist.get(k).tokencode == TBaseType.rrw_as)) {
6879                             ASKeyword = true;
6880                             continue;
6881                         }
6882                         if (ASKeyword) {
6883                             storedProcedure.append(createProcedure.sourcetokenlist.get(k).getAstext());
6884                         }
6885                     }
6886 
6887                     TGSqlParser lc_sqlparser = new TGSqlParser(dbVendor);
6888                     lc_sqlparser.sqltext = storedProcedure.toString();
6889                     lc_sqlparser.parse();
6890                     for (int k = 0; k < lc_sqlparser.sqlstatements.size(); k++) {
6891                         createProcedure.getBodyStatements().add(lc_sqlparser.sqlstatements.get(k));
6892                     }
6893                 }
6894             }
6895 
6896             // fire SQL Statement handle event if set, if return true, stop parsing
6897             if (sqlStatementHandle != null) {
6898                 if (sqlStatementHandle.processSQLStatement(sqlstatements.get(i), this)) break;
6899             }
6900         }
6901         
6902         if (enableTimeLogging) {
6903             endTime = System.currentTimeMillis();
6904             parsingTime += (endTime - startTime);
6905         }
6906 
6907         if (isPushGloablStack) {
6908             firstFrame.popMeFromStack(getFrameStack());
6909         }
6910 
6911         // 3. start semantic analysis
6912         startTime = enableTimeLogging ? System.currentTimeMillis() : 0;
6913
6914         // Reset resolver2 for each parse
6915         this.resolver2 = null;
6916
6917         // Determine effective resolver type (instance setting takes precedence over TBaseType)
6918         EResolverType effectiveResolverType = this.resolverType;
6919         if (effectiveResolverType == EResolverType.DEFAULT) {
6920             // Fall back to TBaseType settings for backward compatibility
6921             if (TBaseType.isEnableResolver2()) {
6922                 effectiveResolverType = EResolverType.RESOLVER2;
6923             } else if (TBaseType.isEnableResolver()) {
6924                 effectiveResolverType = EResolverType.RESOLVER;
6925             } else {
6926                 effectiveResolverType = EResolverType.NONE;
6927             }
6928         }
6929
6930         // Run the appropriate resolver based on effective type
6931         if (getErrorCount() == 0) {
6932             switch (effectiveResolverType) {
6933                 case RESOLVER:
6934                     TSQLResolver resolver = new TSQLResolver(globalContext, sqlstatements);
6935                     if (!resolver.resolve()) {
6936                         // Handle resolution errors
6937                         // addErrors(resolver.getLog().getErrors());
6938                     }
6939                     break;
6940
6941                 case RESOLVER2:
6942                     // Use provided config or create default
6943                     TSQLResolverConfig config = this.resolver2Config;
6944                     if (config == null) {
6945                         config = new TSQLResolverConfig();
6946                     }
6947                     // Always set vendor on config (needed for vendor-specific resolution like struct-field fallback)
6948                     config.setVendor(dbVendor);
6949                     // Pass null as globalContext to match original TSQLResolver2 behavior
6950                     this.resolver2 = new TSQLResolver2(null, sqlstatements, config);
6951                     // Pass sqlEnv to resolver2 for metadata lookup
6952                     if (this.sqlEnv != null) {
6953                         this.resolver2.setSqlEnv(this.sqlEnv);
6954                     }
6955                     if (!this.resolver2.resolve()) {
6956                         // Handle resolution errors if needed
6957                     }
6958                     break;
6959
6960                 case NONE:
6961                 default:
6962                     // No resolution
6963                     break;
6964             }
6965         }
6966
6967         if (enableTimeLogging) {
6968             endTime = System.currentTimeMillis();
6969             semanticAnalysisTime += (endTime - startTime);
6970         }
6971 
6972         // 4. start interpreter
6973         startTime = enableTimeLogging ? System.currentTimeMillis() : 0;
6974         
6975         if ((TBaseType.ENABLE_INTERPRETER) && (getErrorCount() == 0)) {
6976             TLog.clearLogs();
6977             TGlobalScope globalScope = new TGlobalScope(sqlEnv);
6978             TLog.enableInterpreterLogOnly();
6979 
6980             TASTEvaluator astEvaluator = new TASTEvaluator(this.sqlstatements, globalScope);
6981             astEvaluator.eval();
6982         }
6983         
6984         if (enableTimeLogging) {
6985             endTime = System.currentTimeMillis();
6986             interpreterTime += (endTime - startTime);
6987         }
6988 
6989         return getErrorCount();
6990     }
6991
6992     
6993void copyerrormsg(TCustomSqlStatement sql){
6994    for (int i = 0; i<sql.getSyntaxErrors().size(); i++){
6995            this.syntaxErrors.add(new TSyntaxError( (TSyntaxError)sql.getSyntaxErrors().get(i) ));
6996    }
6997//    for (int i = 0; i<sql.getSyntaxHints().size(); i++){
6998//            this.syntaxHints.add(new TSyntaxError( (TSyntaxError)sql.getSyntaxHints().get(i) ));
6999//    }
7000}
7001
7002private static String calculateLicenseKey(boolean ignoreMachineId){
7003
7004    if (userName == null) return null;
7005    if (machineId == null) return null;
7006
7007    byte[] bytesOfMessage=null;
7008    String licenseStr = "I love sql pretty printer, yeah!"+userName.toLowerCase();
7009    if (!ignoreMachineId){
7010        licenseStr += machineId.toLowerCase();
7011    }
7012    try {
7013        bytesOfMessage = licenseStr.getBytes("UTF-8");
7014    } catch (UnsupportedEncodingException e) {
7015        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
7016    }
7017
7018    MessageDigest md = null;
7019    try {
7020        md = MessageDigest.getInstance("MD5");
7021    } catch (NoSuchAlgorithmException e) {
7022        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
7023    }
7024    byte[] digest = md.digest(bytesOfMessage);
7025
7026    return null;//HardwareBinder.getHex(digest);
7027}
7028
7029private static boolean validateLicense(){
7030
7031    int ret = 0;
7032    return ret == 0;
7033
7034}
7035
7036private static boolean check_license_time(){
7037
7038    boolean  ret = false;
7039
7040    String toDate = TBaseType.license_expired_date;
7041
7042    DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
7043    Calendar currDtCal = Calendar.getInstance();
7044
7045    // Zero out the hour, minute, second, and millisecond
7046    currDtCal.set(Calendar.HOUR_OF_DAY, 0);
7047    currDtCal.set(Calendar.MINUTE, 0);
7048    currDtCal.set(Calendar.SECOND, 0);
7049    currDtCal.set(Calendar.MILLISECOND, 0);
7050
7051    Date currDt = currDtCal.getTime();
7052
7053    Date toDt;
7054    try {
7055        toDt = df.parse(toDate);
7056    } catch (ParseException e) {
7057        toDt = null;
7058        // Print some error message back to the user
7059    }
7060
7061    if (toDt != null){
7062        int results = toDt.compareTo(currDt);
7063        ret = results > 0;
7064    }
7065
7066    return ret;
7067}
7068
7069    public void setTeradataUtilityType(TeradataUtilityType teradataUtilityType) {
7070        if ((this.getFlexer() != null) && (this.getFlexer() instanceof TLexerTeradata)){
7071            ((TLexerTeradata)this.getFlexer()).setTeradataUtilityType(teradataUtilityType);
7072        }
7073    }
7074    
7075    /**
7076     * Dispose of parser resources and clean up references.
7077     * 
7078     * <p>This method releases internal resources used by the parser.
7079     * After calling this method, the parser should not be used further.</p>
7080     * 
7081     * <p>If a ManagedSourceBuffer was set, the source text remains in the buffer
7082     * so that tokens can still access it. The user is responsible for calling 
7083     * {@link ManagedSourceBuffer#release()} when all tokens are no longer needed.</p>
7084     * 
7085     * <p>Note: Tokens created by this parser will remain usable after dispose()
7086     * if a ManagedSourceBuffer was used, as they reference the buffer by ID
7087     * rather than holding direct parser references.</p>
7088     * 
7089     * @since 3.1.0.9
7090     */
7091    public void dispose() {
7092        // Note: We intentionally do NOT remove the source from managed buffer
7093        // This allows tokens to remain usable after parser disposal
7094        // The user must call buffer.release() when done with all tokens
7095        
7096        // Clear references to help GC
7097        flexer = null;
7098        fparser = null;
7099        fplsqlparser = null;
7100        finputstream = null;
7101        sqlInputStream = null;
7102        gcurrentsqlstatement = null;
7103        nextStmt = null;
7104        sqlstatements = null;
7105        sourcetokenlist = null;
7106        syntaxErrors = null;
7107    }
7108
7109}