001package gudusoft.gsqlparser.parser;
002
003import gudusoft.gsqlparser.EDbVendor;
004import gudusoft.gsqlparser.TBaseType;
005import gudusoft.gsqlparser.TGSqlParser;
006import gudusoft.gsqlparser.TSourceTokenList;
007import gudusoft.gsqlparser.TStatementList;
008
009/**
010 * Trino SQL parser implementation.
011 *
012 * <p><b>Implementation Status:</b> DELEGATION PHASE
013 * <ul>
014 *   <li><b>Current:</b> Delegates to legacy TGSqlParser</li>
015 *   <li><b>Future:</b> Will extract Trino-specific logic incrementally</li>
016 * </ul>
017 *
018 * @see SqlParser
019 * @see SqlParserFactory
020 * @since 3.2.0.0
021 */
022public class TrinoSqlParser implements SqlParser {
023
024    private final EDbVendor vendor = EDbVendor.dbvtrino;
025
026    @Override
027    public EDbVendor getVendor() {
028        return vendor;
029    }
030
031    @Override
032    public SqlParseResult parse(ParserContext context) {
033        return delegateToLegacy(context, true);
034    }
035
036    @Override
037    public SqlParseResult tokenize(ParserContext context) {
038        return delegateToLegacy(context, false);
039    }
040
041    private SqlParseResult delegateToLegacy(ParserContext context, boolean fullParse) {
042        SqlParseResult.Builder resultBuilder = new SqlParseResult.Builder();
043
044        try {
045            // CRITICAL: Use dbvpresto (not dbvtrino) to avoid infinite recursion.
046            // TGSqlParser(dbvtrino) -> TrinoSqlParser.tokenize() -> delegateToLegacy()
047            // would create another TGSqlParser(dbvtrino), causing StackOverflowError.
048            // Presto has the actual parser implementation that Trino delegates to.
049            TGSqlParser legacyParser = new TGSqlParser(EDbVendor.dbvpresto);
050            transferContext(legacyParser, context);
051
052            long tokenStart = System.currentTimeMillis();
053            legacyParser.tokenizeSqltext();
054            resultBuilder.tokenizationTimeMs(System.currentTimeMillis() - tokenStart);
055
056            if (fullParse) {
057                long parseStart = System.currentTimeMillis();
058                int result = legacyParser.parse();
059                resultBuilder.parsingTimeMs(System.currentTimeMillis() - parseStart);
060
061                if (result != 0) {
062                    resultBuilder.errorCode(result);
063                    resultBuilder.errorMessage("Parsing failed: " + legacyParser.getErrormessage());
064                } else {
065                    resultBuilder.errorCode(0);
066                    resultBuilder.errorMessage("");
067                }
068            } else {
069                int result = legacyParser.getrawsqlstatements();
070                if (result != 0) {
071                    resultBuilder.errorCode(result);
072                    resultBuilder.errorMessage("Tokenization failed: " + legacyParser.getErrormessage());
073                } else {
074                    resultBuilder.errorCode(0);
075                    resultBuilder.errorMessage("");
076                }
077            }
078
079            resultBuilder.sourceTokenList(legacyParser.sourcetokenlist);
080            resultBuilder.sqlStatements(legacyParser.sqlstatements);
081            resultBuilder.lexer(legacyParser.getFlexer());
082
083        } catch (Exception e) {
084            resultBuilder.errorCode(1);
085            resultBuilder.errorMessage("Operation failed: " + e.getMessage());
086        }
087
088        return resultBuilder.build();
089    }
090
091    private void transferContext(TGSqlParser legacyParser, ParserContext context) {
092        if (context.getSqlText() != null && !context.getSqlText().isEmpty()) {
093            legacyParser.sqltext = context.getSqlText();
094        }
095        if (context.getSqlFilename() != null && !context.getSqlFilename().isEmpty()) {
096            legacyParser.sqlfilename = context.getSqlFilename();
097        }
098
099        legacyParser.setEnablePartialParsing(context.isEnablePartialParsing());
100        legacyParser.setSinglePLBlock(context.isSinglePLBlock());
101        legacyParser.setOnlyNeedRawParseTree(context.isOnlyNeedRawParseTree());
102        
103        if (context.getTeradataUtilityType() != null) {
104            legacyParser.setTeradataUtilityType(context.getTeradataUtilityType());
105        }
106        if (context.getMetaDatabase() != null) {
107            legacyParser.setMetaDatabase(context.getMetaDatabase());
108        }
109        if (context.getSqlEnv() != null) {
110            legacyParser.setSqlEnv(context.getSqlEnv());
111        }
112        if (context.isDumpResolverLog()) {
113            TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE = true;
114        }
115    }
116
117    @Override
118    public String toString() {
119        return "TrinoSqlParser{vendor=" + vendor + "}";
120    }
121}