001package gudusoft.gsqlparser.stmt;
002
003
004import gudusoft.gsqlparser.*;
005import gudusoft.gsqlparser.nodes.*;
006import gudusoft.gsqlparser.nodes.mssql.TMssqlStmtStubSqlNode;
007
008public class TCreateSchemaSqlStatement extends TBlockSqlStatement {
009
010   public enum  EFromSource {dataCatalog,hiveMetestore,postgres,mysql,kinesis,redshift,NA};
011
012   private EFromSource fromSource = EFromSource.NA;
013
014    private TObjectName sourceDatabase;
015    private TObjectName sourceSchema;
016
017    public TObjectName getSourceDatabase() {
018        return sourceDatabase;
019    }
020
021    public TObjectName getSourceSchema() {
022        return sourceSchema;
023    }
024
025    public EFromSource getFromSource() {
026        return fromSource;
027    }
028
029    public TCreateSchemaSqlStatement(EDbVendor dbvendor) {
030        super(dbvendor);
031        sqlstatementtype = ESqlStatementType.sstcreateschema;
032    }
033
034    void buildsql() {
035    }
036
037    void clear() {
038    }
039
040    String getasprettytext() {
041        return "";
042    }
043
044    void iterate(TVisitorAbs pvisitor) {
045    }
046
047    private boolean externalSchema;
048
049    public boolean isExternalSchema() {
050        return externalSchema;
051    }
052
053    private TObjectName schemaName = null;
054    private TObjectName ownerName;
055    private TObjectName cloneSourceSchema = null;
056
057    public TObjectName getCloneSourceSchema() {
058        return cloneSourceSchema;
059    }
060
061    public TObjectName getOwnerName() {
062        return ownerName;
063    }
064
065    public TObjectName getSchemaName() {
066        return schemaName;
067    }
068
069    /**
070     * For Vertica, skip grammar-based syntax checking since there's no grammar rule.
071     * We do token-based parsing instead.
072     */
073    @Override
074    protected int dochecksyntax(TCustomSqlStatement psql) {
075        if (dbvendor == EDbVendor.dbvvertica) {
076            isparsed = true;
077            return 0;
078        }
079        return super.dochecksyntax(psql);
080    }
081
082    public int doParseStatement(TCustomSqlStatement psql) {
083        // For Vertica, parse from tokens when rootNode is null (grammar not available)
084        if (rootNode == null && dbvendor == EDbVendor.dbvvertica) {
085            return doParseVerticaFromTokens(psql);
086        }
087        if (rootNode == null) return -1;
088        super.doParseStatement(psql);
089        TDummy node;
090        TCreateSchemaSqlNode schemaNode;
091        switch (dbvendor){
092            case dbvmssql:
093            case dbvpostgresql:
094                schemaNode = (TCreateSchemaSqlNode) rootNode;
095                schemaName = schemaNode.getSchemaName();
096                ownerName = schemaNode.getOwnerName();
097
098                if (schemaNode.getStatementListSqlNode() != null){
099                    schemaNode.getStatementListSqlNode().doParse(this,ESqlClause.unknown);
100
101                    for(int i=0;i<schemaNode.getStatementListSqlNode().size();i++){
102                        this.getBodyStatements().add(schemaNode.getStatementListSqlNode().getStatementSqlNode(i).getStmt());
103                    }
104                }
105                break;
106            case dbvredshift:
107                schemaNode = (TCreateSchemaSqlNode) rootNode;
108                schemaName = schemaNode.getSchemaName();
109                ownerName = schemaNode.getOwnerName();
110                externalSchema = schemaNode.isExternalSchema();
111                fromSource = schemaNode.getFromSource();
112                sourceDatabase = schemaNode.getSourceDatabase();
113                sourceSchema = schemaNode.getSourceSchema();
114                break;
115            case dbvsnowflake:
116                node = (TDummy)rootNode;
117                schemaName = (TObjectName)node.node1;
118                cloneSourceSchema  = (TObjectName)node.node2;
119                break;
120            case dbvhana:
121                node = (TDummy)rootNode;
122                schemaName = (TObjectName)node.node1;
123                break;
124        }
125
126        if((getSqlEnv().getDefaultCatalogName() != null)&&(schemaName != null)){
127            if (schemaName.getDatabaseToken() == null){
128                schemaName.setDatabaseToken(new TSourceToken(getSqlEnv().getDefaultCatalogName()));
129            }
130        }
131
132        return 0;
133    }
134
135    /**
136     * Parse Vertica CREATE SCHEMA from token stream when grammar is not available.
137     * <p>
138     * Vertica CREATE SCHEMA syntax:
139     * CREATE SCHEMA [ IF NOT EXISTS ] [{ database | namespace }.]schema
140     *    [ AUTHORIZATION username]
141     *    [ DEFAULT { INCLUDE | EXCLUDE } [ SCHEMA ] PRIVILEGES ]
142     *    [ DISK_QUOTA quota ]
143     */
144    private int doParseVerticaFromTokens(TCustomSqlStatement psql) {
145        if (sourcetokenlist == null || sourcetokenlist.size() == 0) {
146            return -1;
147        }
148        super.doParseStatement(psql);
149
150        // Find SCHEMA keyword position
151        int schemaKeywordIndex = -1;
152        for (int i = 0; i < sourcetokenlist.size(); i++) {
153            TSourceToken token = sourcetokenlist.get(i);
154            if (token.toString().equalsIgnoreCase("SCHEMA") && schemaKeywordIndex == -1) {
155                schemaKeywordIndex = i;
156                break;
157            }
158        }
159
160        if (schemaKeywordIndex < 0) {
161            return -1;
162        }
163
164        // Find the next solid token after SCHEMA keyword
165        TSourceToken nextToken = sourcetokenlist.nextsolidtoken(schemaKeywordIndex, 1, false);
166        if (nextToken == null) {
167            return -1;
168        }
169
170        // Handle IF NOT EXISTS
171        if (nextToken.toString().equalsIgnoreCase("IF")) {
172            // Skip IF NOT EXISTS
173            TSourceToken notToken = sourcetokenlist.nextsolidtoken(nextToken.posinlist, 1, false);
174            if (notToken != null && notToken.toString().equalsIgnoreCase("NOT")) {
175                TSourceToken existsToken = sourcetokenlist.nextsolidtoken(notToken.posinlist, 1, false);
176                if (existsToken != null && existsToken.toString().equalsIgnoreCase("EXISTS")) {
177                    nextToken = sourcetokenlist.nextsolidtoken(existsToken.posinlist, 1, false);
178                }
179            }
180        }
181
182        if (nextToken == null) {
183            return -1;
184        }
185
186        // Now nextToken should be the schema name (or database.schema)
187        // Skip AUTHORIZATION keyword if present before schema name
188        if (nextToken.toString().equalsIgnoreCase("AUTHORIZATION")) {
189            // AUTHORIZATION username format (no schema name before AUTHORIZATION)
190            TSourceToken ownerToken = sourcetokenlist.nextsolidtoken(nextToken.posinlist, 1, false);
191            if (ownerToken != null && ownerToken.tokentype == ETokenType.ttidentifier) {
192                ownerName = new TObjectName();
193                ownerName.setObjectToken(ownerToken);
194            }
195            return 0;
196        }
197
198        // Parse schema name - could be schema or database.schema
199        if (nextToken.tokentype == ETokenType.ttidentifier || nextToken.tokentype == ETokenType.ttkeyword) {
200            TSourceToken afterName = sourcetokenlist.nextsolidtoken(nextToken.posinlist, 1, false);
201            if (afterName != null && afterName.toString().equals(".")) {
202                // database.schema format
203                TSourceToken schemaToken = sourcetokenlist.nextsolidtoken(afterName.posinlist, 1, false);
204                if (schemaToken != null) {
205                    schemaName = new TObjectName();
206                    schemaName.setSchemaToken(nextToken);
207                    schemaName.setObjectToken(schemaToken);
208
209                    // Check for AUTHORIZATION after schema name
210                    TSourceToken afterSchemaName = sourcetokenlist.nextsolidtoken(schemaToken.posinlist, 1, false);
211                    if (afterSchemaName != null && afterSchemaName.toString().equalsIgnoreCase("AUTHORIZATION")) {
212                        TSourceToken ownerToken = sourcetokenlist.nextsolidtoken(afterSchemaName.posinlist, 1, false);
213                        if (ownerToken != null && ownerToken.tokentype == ETokenType.ttidentifier) {
214                            ownerName = new TObjectName();
215                            ownerName.setObjectToken(ownerToken);
216                        }
217                    }
218                }
219            } else {
220                // Simple schema name
221                schemaName = new TObjectName();
222                schemaName.setObjectToken(nextToken);
223
224                // Check for AUTHORIZATION after schema name
225                if (afterName != null && afterName.toString().equalsIgnoreCase("AUTHORIZATION")) {
226                    TSourceToken ownerToken = sourcetokenlist.nextsolidtoken(afterName.posinlist, 1, false);
227                    if (ownerToken != null && ownerToken.tokentype == ETokenType.ttidentifier) {
228                        ownerName = new TObjectName();
229                        ownerName.setObjectToken(ownerToken);
230                    }
231                }
232            }
233        }
234
235        if((getSqlEnv().getDefaultCatalogName() != null)&&(schemaName != null)){
236            if (schemaName.getDatabaseToken() == null){
237                schemaName.setDatabaseToken(new TSourceToken(getSqlEnv().getDefaultCatalogName()));
238            }
239        }
240
241        return 0;
242    }
243
244    public void accept(TParseTreeVisitor v) {
245        v.preVisit(this);
246        v.postVisit(this);
247    }
248
249
250    public void acceptChildren(TParseTreeVisitor v) {
251        v.preVisit(this);
252        v.postVisit(this);
253    }
254
255    public void setSchemaName(TObjectName schemaName) {
256        this.schemaName = schemaName;
257    }
258}