001package gudusoft.gsqlparser.stmt;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.nodes.*;
005import gudusoft.gsqlparser.nodes.flink.TFlinkWatermarkClause;
006import gudusoft.gsqlparser.nodes.flink.TFlinkWithClause;
007import gudusoft.gsqlparser.nodes.hive.*;
008import gudusoft.gsqlparser.nodes.netezza.TExternalTableOption;
009import gudusoft.gsqlparser.nodes.oracle.TPhysicalProperties;
010import gudusoft.gsqlparser.nodes.postgresql.TInheritsClause;
011import gudusoft.gsqlparser.nodes.postgresql.TPartitionBoundSpecSqlNode;
012import gudusoft.gsqlparser.nodes.teradata.TIndexDefinition;
013import gudusoft.gsqlparser.nodes.teradata.TTeradataPeriodForClause;
014
015import java.util.*;
016
017/**
018 * SQL create table statement.
019 * <br>
020 * {@link #getTargetTable} returns the created table. {@link #getColumnList()} returns columns created in the table.
021 * <br> {@link #getTableConstraints()} returns table level constraints if any.
022 * <br> {@link #getSubQuery()} returns select statement that generate data for this table.
023 * <br><br>Example:
024 * <pre>
025 *     CREATE TABLE dbo.Employee (EmployeeID int PRIMARY KEY CLUSTERED);
026 * </pre>
027 * Table:dbo.Employee can be fetched from {@link #getTargetTable} or the first element of {@link #tables}
028 * <br> column definitions: can be fetched from {@link #getColumnList}
029 * <br>
030 * table constraints: {@link #getTableConstraints}
031 *
032 */
033public class TCreateTableSqlStatement extends TCustomSqlStatement {
034
035
036    public TInheritsClause getInheritsClause() {
037        return inheritsClause;
038    }
039
040    private TInheritsClause inheritsClause;
041
042    private TBaseTablePartition tablePartition;
043
044
045    public TBaseTablePartition getTablePartition() {
046        return tablePartition;
047    }
048
049    public void setPartitionBoundSpec(TPartitionBoundSpecSqlNode partitionBoundSpec) {
050        this.partitionBoundSpec = partitionBoundSpec;
051    }
052
053    public TPartitionBoundSpecSqlNode getPartitionBoundSpec() {
054        return partitionBoundSpec;
055    }
056
057    /**
058     * postgresql PartitionBoundSpec
059     * https://www.postgresql.org/docs/current/sql-createtable.html
060     */
061    private TPartitionBoundSpecSqlNode partitionBoundSpec;
062
063    public TTableProperties getTableProperties() {
064        return tableProperties;
065    }
066
067    public void setTableProperties(TTableProperties tableProperties) {
068        this.tableProperties = tableProperties;
069    }
070
071    private TTableProperties tableProperties;
072
073    /** Oracle SHARING clause, including its specified attribute and original token range. */
074    private TParseTreeNode sharingClause;
075
076    /** @return the SHARING clause, or null when no sharing attribute was specified */
077    public TParseTreeNode getSharingClause() {
078        return sharingClause;
079    }
080
081
082    public enum TableSourceType  {normal,subquery,like,clone,copy,partitionOf,forExchangeWith,usingTemplate,refreshUsing};
083    private TableSourceType tableSourceType = TableSourceType.normal;
084
085    private List<String> externalTableOptionList = null;
086
087    /**
088     * sql server create external table with options
089     * @return
090     */
091    public  List<String> getExternalTableOptionNames(){
092        return  TBaseType.getOptionNames(externalTableOptionList);
093    }
094
095    /**
096     * sql server create external table with option.
097     *
098     * @param optionName
099     * @return
100     */
101    public String getExternalTableOption(String optionName){
102        return TBaseType.getOption(externalTableOptionList,optionName);
103    }
104
105    public TableSourceType getTableSourceType() {
106        return tableSourceType;
107    }
108
109    private TObjectName cloneSourceTable = null;
110
111    public TObjectName getCloneSourceTable() {
112        return cloneSourceTable;
113    }
114
115    private TExternalTableOption externalTableOption = null;
116
117    public TExternalTableOption getExternalTableOption() {
118        return externalTableOption;
119    }
120
121    private TExpression partitionByExpr;
122
123    public void setPartitionByExpr(TExpression partitionByExpr) {
124        this.partitionByExpr = partitionByExpr;
125    }
126
127    /**
128     * Bigquery partition by expr
129     *
130     * @return expr
131     */
132    public TExpression getPartitionByExpr() {
133        return partitionByExpr;
134    }
135
136    private String awsSnsTopic = null;
137
138    public void setAwsSnsTopic(String awsSnsTopic) {
139        this.awsSnsTopic = awsSnsTopic;
140    }
141
142    public String getAwsSnsTopic() {
143        return awsSnsTopic;
144    }
145
146    private TObjectNameList partitionColumnList;
147
148    public void setPartitionColumnList(TObjectNameList partitionColumnList) {
149        this.partitionColumnList = partitionColumnList;
150    }
151
152    public TObjectNameList getPartitionColumnList() {
153        return partitionColumnList;
154    }
155
156    public void setFileFormatName(String fileFormatName) {
157        this.fileFormatName = fileFormatName;
158    }
159
160    public void setFileFormatType(String fileFormatType) {
161        this.fileFormatType = fileFormatType;
162    }
163
164    public String getFileFormatName() {
165        return fileFormatName;
166    }
167
168    public String getFileFormatType() {
169        return fileFormatType;
170    }
171
172    private String fileFormatName = null;
173    private String fileFormatType = null;
174
175    private String regex_pattern;
176
177    public void setRegex_pattern(String regex_pattern) {
178        this.regex_pattern = regex_pattern;
179    }
180
181    public String getRegex_pattern() {
182        return regex_pattern;
183    }
184
185    private TStageLocation stageLocation;
186
187    public void setStageLocation(TStageLocation stageLocation) {
188        this.stageLocation = stageLocation;
189    }
190
191    public TStageLocation getStageLocation() {
192        return stageLocation;
193    }
194
195    public void setTableOptions(ArrayList<TCreateTableOption> tableOptions) {
196        this.tableOptions = tableOptions;
197    }
198
199    public ArrayList<TCreateTableOption> getTableOptions() {
200        return tableOptions;
201    }
202
203    private ArrayList<TCreateTableOption> tableOptions;
204
205    public void setOnFilegroup(TDummy onFilegroup) {
206        this.onFilegroup = onFilegroup;
207    }
208
209    public TDummy getOnFilegroup() {
210        return onFilegroup;
211    }
212
213    private TDummy onFilegroup = null;
214
215    /**
216     * Oracle physical properties
217     * @return Oracle physical properties
218     */
219    public TPhysicalProperties getPhysicalProperties() {
220        return physicalProperties;
221    }
222
223    private TPhysicalProperties physicalProperties;
224
225    private EnumSet<ETableKind> tableKinds = EnumSet.noneOf(ETableKind.class);
226
227    public void setTableKinds(EnumSet<ETableKind> tableKinds) {
228        this.tableKinds = tableKinds;
229    }
230
231    /**
232     * Type of this table
233     * @return Type of this table
234     */
235    public EnumSet<ETableKind> getTableKinds() {
236        return tableKinds;
237    }
238
239    private TTable asTable;
240
241    /**
242     * Netezza, Teradata, as table name.
243     * @return as table name
244     */
245    public TTable getAsTable() {
246        return asTable;
247    }
248
249    private boolean externalTable;
250
251    /**
252     * @deprecated As of v1.9.7.2 , replace by {@link #isExternal}
253     * <br>
254     * Netezza, whether it is a external table
255     * @return true if it's netezza create external table
256     */
257    public boolean isExternalTable() {
258        return externalTable;
259    }
260
261    private ArrayList <TIndexDefinition> indexDefinitions;
262
263    /**
264     * Teradata index definition
265     *
266     * <pre>UNIQUE PRIMARY INDEX (storeid, productid, salesdate)</pre>
267     * @return  list of index definition
268     */
269    public ArrayList<TIndexDefinition> getIndexDefinitions() {
270        return indexDefinitions;
271    }
272
273    /**
274     * Teradata PERIOD FOR clauses that define derived temporal columns.
275     * A table can have multiple PERIOD FOR clauses (e.g., one for VALIDTIME and one for TRANSACTIONTIME).
276     */
277    private ArrayList<TTeradataPeriodForClause> periodForClauses;
278
279    /**
280     * Returns the list of Teradata PERIOD FOR clauses in this CREATE TABLE statement.
281     * PERIOD FOR clauses define derived columns that represent time periods from two date/timestamp columns.
282     *
283     * @return list of PERIOD FOR clauses, may be null or empty if none are defined
284     */
285    public ArrayList<TTeradataPeriodForClause> getPeriodForClauses() {
286        return periodForClauses;
287    }
288
289    /**
290     * Flink WATERMARK clauses that define event-time processing.
291     * A table typically has at most one WATERMARK clause.
292     */
293    private ArrayList<TFlinkWatermarkClause> watermarkClauses;
294
295    /**
296     * Returns the list of Flink WATERMARK clauses in this CREATE TABLE statement.
297     * WATERMARK clauses define how watermarks are generated for event-time processing.
298     *
299     * @return list of WATERMARK clauses, may be null or empty if none are defined
300     */
301    public ArrayList<TFlinkWatermarkClause> getWatermarkClauses() {
302        return watermarkClauses;
303    }
304
305    /**
306     * Returns the first Flink WATERMARK clause in this CREATE TABLE statement.
307     * Typically only one WATERMARK clause is defined per table.
308     *
309     * @return the first WATERMARK clause, or null if none are defined
310     */
311    public TFlinkWatermarkClause getWatermarkClause() {
312        return (watermarkClauses != null && !watermarkClauses.isEmpty())
313            ? watermarkClauses.get(0)
314            : null;
315    }
316
317    private boolean external;
318    private boolean usingTemplate;
319    private boolean ifNotExists;
320    private TObjectName tableLocation;
321    private TObjectName tableComment;
322    private THiveTableProperties hiveTableProperties;
323    private THiveTablePartition hiveTablePartition;
324    private THiveTableBuckets hiveTableBuckets;
325    private THiveTableSkewed hiveTableSkewed;
326    private THiveRowFormat hiveRowFormat;
327    private THiveTableFileFormat hiveTableFileFormat;
328    private TObjectName likeTableName;
329
330    /**
331     * Flink WITH clause containing connector properties.
332     */
333    private TFlinkWithClause flinkWithClause;
334
335    /**
336     * Get the Flink WITH clause containing connector properties.
337     *
338     * <p>Flink SQL uses the WITH clause to specify connector properties:</p>
339     * <pre>
340     * CREATE TABLE my_table (
341     *   id BIGINT,
342     *   name STRING
343     * ) WITH (
344     *   'connector' = 'kafka',
345     *   'topic' = 'my-topic',
346     *   'properties.bootstrap.servers' = 'localhost:9092',
347     *   'format' = 'json'
348     * );
349     * </pre>
350     *
351     * @return the Flink WITH clause, or null if not present
352     */
353    public TFlinkWithClause getFlinkWithClause() {
354        return flinkWithClause;
355    }
356
357    /**
358     * Set the Flink WITH clause.
359     * @param flinkWithClause the Flink WITH clause
360     */
361    public void setFlinkWithClause(TFlinkWithClause flinkWithClause) {
362        this.flinkWithClause = flinkWithClause;
363    }
364
365    /**
366     * Hive, Impala,Netezza,snowflake whether it is an external table
367     * @return whether it is an external table
368     */
369    public boolean isExternal() {
370        return external;
371    }
372
373    /**
374     * Snowflake: whether this table is created with
375     * {@code CREATE TABLE ... USING TEMPLATE <query>}, where the query result
376     * (typically over INFER_SCHEMA) derives the column definitions.
377     *
378     * @return true if created via USING TEMPLATE
379     */
380    public boolean isUsingTemplate() {
381        return usingTemplate;
382    }
383
384    /**
385     * Hive, impala table row format
386     * @return table row format
387     */
388    public THiveRowFormat getHiveRowFormat() {
389        return hiveRowFormat;
390    }
391
392    /**
393     * Hive, Impala table buckets
394     * @return table buckets
395     */
396    public THiveTableBuckets getHiveTableBuckets() {
397        return hiveTableBuckets;
398    }
399
400    /**
401     * Hive, Impala table file format
402     * @return table file format
403     */
404    public THiveTableFileFormat getHiveTableFileFormat() {
405        return hiveTableFileFormat;
406    }
407
408    /**
409     * Hive, Impala table partition
410     * @return table partition
411     */
412    public THiveTablePartition getHiveTablePartition() {
413        return hiveTablePartition;
414    }
415
416    /**
417     * Hive, Impala table properties
418     * @return table properties
419     */
420    public THiveTableProperties getHiveTableProperties() {
421        return hiveTableProperties;
422    }
423
424    /**
425     * Hive, Impala skewed by clause.
426     * @return skewed by clause.
427     */
428    public THiveTableSkewed getHiveTableSkewed() {
429        return hiveTableSkewed;
430    }
431
432    /**
433     * Hive, Impala, if not exists clause
434     * @return true if not exists clause is used in create table statement
435     */
436    public boolean isIfNotExists() {
437        return ifNotExists;
438    }
439
440    /**
441     * Greenplum, table used in like clause.
442     * <br>Hive, Impala, table used in like clause.
443     * @return table used in like clause.
444     */
445    public TObjectName getLikeTableName() {
446        return likeTableName;
447    }
448
449    /**
450     * Hive, Impala, comment of the table.
451     * @return comment of the table.
452     */
453    public TObjectName getTableComment() {
454        return tableComment;
455    }
456
457    /**
458     * The location of the table, where its files are: {@code 's3://bucket/path/'} in
459     * <ul>
460     * <li>{@code LOCATION 's3://bucket/path/'}: Hive, Impala, Redshift, Spark SQL, Databricks, and Athena;</li>
461     * <li>{@code WITH (external_location = 's3://bucket/path/')}, or {@code location = ...}: Presto, Trino, and
462     * Athena.</li>
463     * </ul>
464     * @return location of the table, null when the statement has none.
465     */
466    public TObjectName getTableLocation() {
467        return tableLocation;
468    }
469
470    /**
471     * Presto, Trino, Athena: the location table property of
472     * {@code CREATE TABLE t (...) WITH (format = 'PARQUET', external_location = 's3://bucket/path/')}. The Hive
473     * connector names it {@code external_location}, the Iceberg and Delta Lake connectors {@code location}. The
474     * grammar does not read the properties, so they are read from the tokens of the WITH clause, which comes before
475     * the query of a CREATE TABLE AS SELECT. Only a property written as a plain name whose value is one string
476     * counts.
477     *
478     * @return the string of the property, or null when there is none
479     */
480    private TObjectName locationTableProperty(TCreateTableSqlNode createTableNode) {
481        if (sourcetokenlist == null) return null;
482        TSourceToken queryStart = (createTableNode.getSubQueryNode() != null)
483                ? createTableNode.getSubQueryNode().getStartToken() : null;
484        int nested = 0;
485        int bracketed = 0; // inside an ARRAY[...] value, where a comma does not start a property
486        boolean inWithClause = false;
487        TSourceToken previous = null;
488        for (int k = 0; k < sourcetokenlist.size(); k++) {
489            TSourceToken st = sourcetokenlist.get(k);
490            if (!st.issolidtoken()) continue;
491            if (st == queryStart) break;
492            if (st.tokencode == '[') {
493                bracketed++;
494            } else if (st.tokencode == ']') {
495                bracketed--;
496            } else if ((st.tokencode == '(') || (st.tokencode == TBaseType.left_parenthesis_2)) {
497                if ((nested == 0) && (previous != null) && (previous.tokencode == TBaseType.rrw_with)) {
498                    inWithClause = true;
499                }
500                nested++;
501            } else if (st.tokencode == ')') {
502                nested--;
503                if ((nested == 0) && inWithClause) break;
504            } else if (inWithClause && (nested == 1) && (bracketed == 0) && (previous != null)
505                    && ((previous.tokencode == '(') || (previous.tokencode == TBaseType.left_parenthesis_2)
506                    || (previous.tokencode == ','))
507                    && isLocationPropertyName(st)) {
508                TSourceToken equal = st.nextSolidToken();
509                TSourceToken value = (equal == null) ? null : equal.nextSolidToken();
510                TSourceToken after = (value == null) ? null : value.nextSolidToken();
511                if ((equal != null) && (equal.tokencode == '=') && (value != null)
512                        && (value.tokentype == ETokenType.ttsqstring)
513                        && (after != null) && ((after.tokencode == ',') || (after.tokencode == ')'))) {
514                    return TObjectName.createObjectName(dbvendor, EDbObjectType.unknown, value);
515                }
516            }
517            previous = st;
518        }
519        return null;
520    }
521
522    private static boolean isLocationPropertyName(TSourceToken st) {
523        String name = st.toString();
524        return "external_location".equalsIgnoreCase(name) // non-identifier-compare: a table property name
525                || "location".equalsIgnoreCase(name); // non-identifier-compare: a table property name
526    }
527
528    private TObjectName rowTypeName;
529    private TObjectName superTableName;
530
531    /**
532     * Informix, typename used in of type clause.
533     *
534     * @return row type name
535     */
536    public TObjectName getRowTypeName() {
537        return rowTypeName;
538    }
539
540    /**
541     * Informix, table name used in the under clause.
542     * @return table name used in the under clause.
543     */
544    public TObjectName getSuperTableName() {
545        return superTableName;
546    }
547
548    /**
549     * Data of the created table is derived from this select statement.
550     *
551     * @return {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement} used in create table.
552     */
553    public TSelectSqlStatement getSubQuery() {
554        return subQuery;
555    }
556
557    private TSelectSqlStatement subQuery = null;
558    private TCustomSqlStatement refreshUsingStatement = null;
559    private TExecuteSqlStatement executePreparedStatement = null;//greenplum
560
561    /**
562     * Snowflake custom incremental dynamic-table refresh logic.
563     *
564     * @return the MERGE or INSERT statement inside REFRESH USING, or null
565     */
566    public TCustomSqlStatement getRefreshUsingStatement() {
567        return refreshUsingStatement;
568    }
569
570    public TExecuteSqlStatement getExecutePreparedStatement() {
571        return executePreparedStatement;
572    }
573
574
575
576    private TPTNodeList <TMySQLCreateTableOption> mySQLTableOptionList;
577
578    /**
579     * MySQL, option used in create table such as engine, auto_increment and etc.
580     * @return option used in create table such as engine, auto_increment and etc.
581     */
582    public TPTNodeList<TMySQLCreateTableOption> getMySQLTableOptionList() {
583        return mySQLTableOptionList;
584    }
585
586    public TCreateTableSqlStatement(EDbVendor dbvendor) {
587        super(dbvendor);
588        sqlstatementtype = ESqlStatementType.sstcreatetable;
589    }
590
591    void buildsql() {
592    }
593
594    void clear() {
595    }
596
597    String getasprettytext() {
598        return "";
599    }
600
601    void iterate(TVisitorAbs pvisitor) {
602    }
603
604    private TObjectName tableName = null;
605
606    /**
607     * The first table in {@link #tables}, this is the same table as {@link #getTargetTable}
608     *
609     * @return The first table in {@link #tables}, or null when the statement was
610     *         only partially parsed and no table was recorded (e.g. a syntax
611     *         error before the table name). Callers treat a missing table name
612     *         as optional, so returning null is preferred over throwing.
613     */
614    public TObjectName getTableName() {
615        if (tables == null || tables.size() == 0 || tables.getTable(0) == null) {
616            return null;
617        }
618        return tables.getTable(0).getTableName();
619    }
620
621    private boolean webTable = false;
622
623    public boolean isWebTable() {
624        return webTable;
625    }
626
627
628    private boolean readable;
629
630    public boolean isReadable() {
631        return readable;
632    }
633
634    public boolean isWritable() {
635        return writable;
636    }
637
638    private boolean writable;
639
640    private TConstant executeCmd;
641
642
643    public TConstant getExecuteCmd() {
644        return executeCmd;
645    }
646
647
648    private ArrayList<TConstant> locationFiles;
649
650    public void setLocationFiles(ArrayList<TConstant> locationFiles) {
651        this.locationFiles = locationFiles;
652    }
653
654    public ArrayList<TConstant> getLocationFiles() {
655        return locationFiles;
656    }
657
658    public int doParseStatement(TCustomSqlStatement psql) {
659       if (rootNode == null) return -1;
660       TCreateTableSqlNode createTableNode = (TCreateTableSqlNode)rootNode;
661       super.doParseStatement(psql);
662       this.tableKinds = createTableNode.getTableKinds();
663       this.tableSourceType = createTableNode.getTableSourceType();
664       this.setTargetTable(createTableNode.getTable());
665
666
667       // move to TMetadataCollector
668
669//       TSQLTable sqlTable = null;
670//        if (getSqlEnv() != null)  {
671//            if (createTableNode.getTable() != null){
672//                sqlTable = getSqlEnv().addTable(createTableNode.getTable().getFullName(),true);
673//            }
674//
675//            if (getSqlEnv().getDefaultCatalogName() != null){
676//                if (createTableNode.getTable().getTableName().getDatabaseToken() == null){
677//                    createTableNode.getTable().getTableName().setDatabaseToken(new TSourceToken(getSqlEnv().getDefaultCatalogName()),true);
678//                }
679//            }
680//
681//            createTableNode.getTable().getTableName().setSqlEnv(getSqlEnv());
682//        }
683
684        // end of move to TMetadataCollector
685
686       externalTable = createTableNode.isExternalTable();
687       physicalProperties = createTableNode.getPhysicalProperties();
688       tableProperties = createTableNode.getTableProperties();
689       sharingClause = createTableNode.getSharingClause();
690       this.tablePartition = createTableNode.getTablePartition();
691
692       if (createTableNode.getNetezzaExternalTableOption() != null){
693           this.externalTableOption = new TExternalTableOption(createTableNode.getNetezzaExternalTableOption().toString());
694       }
695
696       mySQLTableOptionList = createTableNode.getMySQLTableOptionList();
697       tableOptions = createTableNode.getTableOptions();
698       if (tableOptions != null){
699           for(int i=0;i<tableOptions.size();i++){
700               tableOptions.get(i).doParse(this,ESqlClause.unknown);
701           }
702       }
703
704       superTableName = createTableNode.getSuperTableName();
705       rowTypeName = createTableNode.getRowTypeName();
706       onFilegroup = createTableNode.getOnFilegroup();
707       cloneSourceTable = createTableNode.getCloneSourceTable();
708       if (cloneSourceTable != null){
709           cloneSourceTable.setDbObjectType(this.dbvendor,EDbObjectType.table);
710       }
711       likeTableName = createTableNode.getLikeTableName();
712       if (likeTableName != null){
713           likeTableName.setDbObjectType(this.dbvendor,EDbObjectType.table);
714       }
715       partitionBoundSpec = createTableNode.getPartitionBoundSpec();
716
717       tables.addTable(createTableNode.getTable());
718       asTable = createTableNode.getAsTable();
719        if (asTable != null) tables.addTable(asTable);
720       if ((createTableNode.getTableElementList() != null)&&(createTableNode.getTableElementList().size() >0 )){
721           TTableElement te;
722           TColumnDefinition cd;
723           Set<String> columnNames = new LinkedHashSet<String>();
724           for(int i=0; i<createTableNode.getTableElementList().size();i++){
725              te = createTableNode.getTableElementList().getTableElement(i);
726               if (te.getType() == TTableElement.type_column_def) {
727                   cd = te.getColumnDefinition();
728                   this.getColumnList().addColumn(cd);
729
730                   cd.doParse(this, ESqlClause.createTable);
731                   this.getTargetTable().getObjectNameReferences().addObjectName(cd.getColumnName());
732                   cd.getColumnName().setLocation(ESqlClause.createTable);
733                   cd.getColumnName().setLinkedColumnDef(cd);
734                   getTargetTable().getLinkedColumns().addObjectName(cd.getColumnName());
735                   cd.getColumnName().setSourceTable(getTargetTable());
736                   // move to TMetadataCollector
737//                   if (sqlTable != null){
738//                       sqlTable.addColumn(cd.getColumnName().toString(),cd.getDatatype());
739//                       //getTargetTable().setSqlTable(sqlTable);
740//                   }
741                   if (!columnNames.add(cd.getColumnName().toString())){
742                       // find duplicate colum name
743                       TSourceToken st = cd.getColumnName().getStartToken();
744                       this.parseerrormessagehandle(new TSyntaxError(st.getAstext(), st.lineNo, st.columnNo
745                               ,"duplicate column name", EErrorType.spfatalerror
746                               , TBaseType.MSG_ERROR_DUPLICATED_COLUMN_NAME,this,st.posinlist));
747
748                   }
749               }
750               else  if (te.getType() == TTableElement.type_table_like){
751                   likeTableName = te.getParentTable();
752               }else  if (te.getType() == TTableElement.type_supplemental_logging){
753
754               }else  if (te.getType() == TTableElement.type_period_for_clause){
755                   // Teradata PERIOD FOR clause - derived temporal column
756                   if (periodForClauses == null) {
757                       periodForClauses = new ArrayList<TTeradataPeriodForClause>();
758                   }
759                   periodForClauses.add(te.getPeriodForClause());
760               }else  if (te.getType() == TTableElement.type_flink_watermark){
761                   // Flink WATERMARK clause for event-time processing
762                   if (watermarkClauses == null) {
763                       watermarkClauses = new ArrayList<TFlinkWatermarkClause>();
764                   }
765                   watermarkClauses.add(te.getFlinkWatermarkClause());
766               }else{
767                   te.getConstraint().doParse(this,ESqlClause.unknown);
768                   this.getTableConstraints().addConstraint(te.getConstraint());
769               }
770           }
771       }
772
773       // column name list used when create table using a subquery.
774       TColumnDefinition t = null;
775       if ((createTableNode.getColumnList() != null)&&(createTableNode.getColumnList().size() > 0)){
776           for(int i=0;i<createTableNode.getColumnList().size();i++){
777               t = new TColumnDefinition(createTableNode.getColumnList().getObjectName(i));
778               t.setStartToken(t.getColumnName().getStartToken());
779               t.setEndToken(t.getColumnName().getEndToken());
780               this.getColumnList().addColumn(t);
781               this.getTargetTable().getObjectNameReferences().addObjectName(createTableNode.getColumnList().getObjectName(i));
782               getTargetTable().getLinkedColumns().addObjectName(createTableNode.getColumnList().getObjectName(i));
783               createTableNode.getColumnList().getObjectName(i).setSourceTable(getTargetTable());
784               // move to TMetadataCollector
785//               if (sqlTable != null){
786//                   sqlTable.addColumn(createTableNode.getColumnList().getObjectName(i).toString());
787//               }
788           }
789       }
790
791       if((subQuery == null) && (createTableNode.getSubQueryNode() != null)){
792           // CREATE TABLE a AS TABLE b is CREATE TABLE a AS SELECT * FROM b: the TABLE b
793           // query becomes that select (TSelectSqlNode.expandTableQuery), so it takes
794           // the same path and getAsTable() still answers b.
795           subQuery = new TSelectSqlStatement(this.dbvendor);
796           subQuery.rootNode = createTableNode.getSubQueryNode();
797           subQuery.doParseStatement(this);
798           if ((createTableNode.getSubQueryNode().getRelationExpr() != null) && (subQuery.tables.size() > 0)){
799               asTable = subQuery.tables.getTable(0);
800           }
801
802
803           // link column alias in subquery to table in create statement if columnList is not specified.
804           // Skipped for Snowflake USING TEMPLATE: the template query (e.g. ARRAY_AGG over
805           // INFER_SCHEMA) only infers the schema, so its select-list columns must NOT become
806           // columns of the target table the way a CREATE TABLE AS SELECT would.
807           if (createTableNode.getColumnList() == null && !createTableNode.isUsingTemplate()){
808               TSelectSqlStatement viewQuery = subQuery;
809               if (subQuery.isCombinedQuery()){
810                   viewQuery = subQuery.getRightStmt();
811               }
812
813                        if (viewQuery.getResultColumnList() != null) {
814               for(int i=0;i<viewQuery.getResultColumnList().size();i++){
815                   TResultColumn resultColumn = viewQuery.getResultColumnList().getResultColumn(i);
816                   TObjectName aliasName = null;
817                   if (resultColumn.getAliasClause() != null){
818                       if (resultColumn.getAliasClause().getColumns() != null){
819                           // select explode(str_to_map(regexp_replace(regexp_replace(regexp_replace(lower(t.input), '', ''), '',''), '', ''), '', '')) as (`key`, `value`) from B t1
820                            for (int j=0;j<resultColumn.getAliasClause().getColumns().size();j++){
821                                TObjectName aliasName1 =  resultColumn.getAliasClause().getColumns().getObjectName(j);
822                                aliasName1.setLocation(ESqlClause.columnAlias);
823                                resultColumn.getAliasNameList().add(aliasName1);
824                            }
825                       }else {
826                           aliasName = TObjectName.createObjectName (this.dbvendor, EDbObjectType.column,resultColumn.getAliasClause().getAliasName().getStartToken());
827                           aliasName.getReferencedObjects().addObjectName(resultColumn.getAliasClause().getAliasName());
828                           aliasName.setLocation(resultColumn.getAliasClause().getAliasName().getLocation());
829                       }
830                   }else{
831                       if (resultColumn.getExpr().getObjectOperand() != null){
832                           aliasName =  TObjectName.createObjectName (this.dbvendor, EDbObjectType.column,resultColumn.getExpr().getObjectOperand().getPartToken());
833                           aliasName.getReferencedObjects().addObjectName(resultColumn.getExpr().getObjectOperand());
834                           aliasName.setLocation(resultColumn.getExpr().getObjectOperand().getLocation());
835                       }
836                   }
837
838                   if (aliasName != null){
839                       if (aliasName.getLocation() == ESqlClause.unknown){
840                           aliasName.setLocation(ESqlClause.columnAlias);
841                       }
842                       getTargetTable().getLinkedColumns().addObjectName(aliasName);
843                       aliasName.setSourceTable(getTargetTable());
844                       resultColumn.setAliasName(aliasName.toString());
845
846                       // move to TMetadataCollector
847//                       if (sqlTable != null){
848//                           sqlTable.addColumn(TSQLEnv.getObjectName(aliasName.toString()));
849//                       }
850                   }
851               }
852                        }
853           }
854       }
855
856       if (createTableNode.getRefreshUsingStatementNode() != null) {
857           createTableNode.getRefreshUsingStatementNode().doParse(
858                   this, ESqlClause.unknown);
859           refreshUsingStatement = createTableNode
860                   .getRefreshUsingStatementNode().getStmt();
861       }
862
863       if (createTableNode.getExecuteSqlNode() != null){
864           executePreparedStatement = new TExecuteSqlStatement(this.dbvendor);
865           executePreparedStatement.rootNode = createTableNode.getExecuteSqlNode();
866           executePreparedStatement.doParseStatement(this);
867       }
868
869        external = createTableNode.isExternal();
870        usingTemplate = createTableNode.isUsingTemplate();
871       if (!external && tableKinds.contains(ETableKind.etkExternal)){
872           external = true;
873       }
874       if (external){
875           if (createTableNode.getOptionStartParenthesis() != null){
876               externalTableOptionList = TBaseType.getArrayListBetweenTokens(createTableNode.getOptionStartParenthesis(),createTableNode.getOptionEndParenthesis(),false);
877           }
878       }
879        ifNotExists = createTableNode.isIfNotExists();
880        if (createTableNode.getTableComment() != null){
881            tableComment = createTableNode.getTableComment();
882        }
883
884        locationFiles = createTableNode.getLocationFiles();
885        readable = createTableNode.isReadable();
886        writable = createTableNode.isWritable();
887        executeCmd = createTableNode.getExecuteCmd();
888        webTable = createTableNode.isWebTable();
889
890        tableLocation = createTableNode.getTableLocation();
891        if ((tableLocation == null) && ((dbvendor == EDbVendor.dbvpresto) || (dbvendor == EDbVendor.dbvtrino)
892                || (dbvendor == EDbVendor.dbvathena))) {
893            tableLocation = locationTableProperty(createTableNode);
894        }
895        hiveTableProperties = createTableNode.getHiveTableProperties();
896        hiveTablePartition = createTableNode.getHiveTablePartition();
897        hiveTableBuckets = createTableNode.getHiveTableBuckets();
898        hiveRowFormat = createTableNode.getHiveRowFormat();
899        hiveTableSkewed = createTableNode.getHiveTableSkewed();
900        hiveTableFileFormat = createTableNode.getHiveTableFileFormat();
901        flinkWithClause = createTableNode.getFlinkWithClause();
902        if (likeTableName == null){
903            likeTableName = createTableNode.getLikeTableName();
904        }
905        indexDefinitions = createTableNode.getIndexDefinitions();
906        if (indexDefinitions != null){
907            for(int i=0;i<indexDefinitions.size();i++){
908                indexDefinitions.get(i).doParse(this,ESqlClause.tableIndexOption);
909            }
910        }
911
912        inheritsClause = createTableNode.getInheritsClause();
913        if (inheritsClause != null) {
914            for(int i=0;i<inheritsClause.getParentTables().size();i++){
915                inheritsClause.getParentTables().getObjectName(i).setDbObjectType(this.dbvendor, EDbObjectType.table);
916            }
917        }
918
919        // The statements parsed after this one read the declared table (Mantis 4797).
920        gudusoft.gsqlparser.resolver2.metadata.ParseTimeCatalog.declare(this);
921        return 0;
922    }
923
924    /**
925     * table level constraints.
926     * @return List of table constraints of this table.
927     */
928    public TConstraintList getTableConstraints() {
929        if (this.tableConstraints == null){
930            this.tableConstraints = new TConstraintList();
931
932        }
933        
934        return tableConstraints;
935    }
936
937    /**
938     *  columns created in create table statement.
939     *
940     * @return List of column definitions of this table.
941     */
942    public TColumnDefinitionList getColumnList() {
943        if (this.columnList == null){
944            this.columnList = new TColumnDefinitionList();
945
946        }
947        return columnList;
948    }
949
950    private TColumnDefinitionList columnList = null;
951    private TConstraintList tableConstraints = null;
952
953    public void accept(TParseTreeVisitor v){
954        v.preVisit(this);
955        v.postVisit(this);
956    }
957
958    public void acceptChildren(TParseTreeVisitor v){
959        v.preVisit(this);
960        if (sharingClause != null) sharingClause.acceptChildren(v);
961        //tables.acceptChildren(v);
962        if (getTargetTable() != null) {
963            getTargetTable().acceptChildren(v);
964        }
965        this.getColumnList().acceptChildren(v);
966        if ((this.getTableConstraints() != null)&&(this.getTableConstraints().size()>0)){
967            this.getTableConstraints().acceptChildren(v);
968        }
969        if (this.getSubQuery() != null){
970            this.getSubQuery().acceptChildren(v);
971        }
972        if (this.getRefreshUsingStatement() != null){
973            this.getRefreshUsingStatement().acceptChildren(v);
974        }
975        if (getHiveTablePartition() != null){
976            getHiveTablePartition().acceptChildren(v);
977        }
978        v.postVisit(this);
979    }
980
981    public void setColumnList(TColumnDefinitionList columnList) {
982        this.columnList = columnList;
983    }
984
985    public void setAsTable(TTable asTable) {
986        this.asTable = asTable;
987    }
988
989    public void setExternalTable(boolean externalTable) {
990        this.externalTable = externalTable;
991    }
992
993    public void setIndexDefinitions(ArrayList<TIndexDefinition> indexDefinitions) {
994        this.indexDefinitions = indexDefinitions;
995    }
996
997    public void setExternal(boolean external) {
998        this.external = external;
999    }
1000
1001    public void setIfNotExists(boolean ifNotExists) {
1002        this.ifNotExists = ifNotExists;
1003    }
1004
1005    public void setTableLocation(TObjectName tableLocation) {
1006        this.tableLocation = tableLocation;
1007    }
1008
1009    public void setTableComment(TObjectName tableComment) {
1010        this.tableComment = tableComment;
1011    }
1012
1013    public void setHiveTableProperties(THiveTableProperties hiveTableProperties) {
1014        this.hiveTableProperties = hiveTableProperties;
1015    }
1016
1017    public void setHiveTablePartition(THiveTablePartition hiveTablePartition) {
1018        this.hiveTablePartition = hiveTablePartition;
1019    }
1020
1021    public void setHiveTableBuckets(THiveTableBuckets hiveTableBuckets) {
1022        this.hiveTableBuckets = hiveTableBuckets;
1023    }
1024
1025    public void setHiveTableSkewed(THiveTableSkewed hiveTableSkewed) {
1026        this.hiveTableSkewed = hiveTableSkewed;
1027    }
1028
1029    public void setHiveRowFormat(THiveRowFormat hiveRowFormat) {
1030        this.hiveRowFormat = hiveRowFormat;
1031    }
1032
1033    public void setHiveTableFileFormat(THiveTableFileFormat hiveTableFileFormat) {
1034        this.hiveTableFileFormat = hiveTableFileFormat;
1035    }
1036
1037    public void setLikeTableName(TObjectName likeTableName) {
1038        this.likeTableName = likeTableName;
1039    }
1040
1041    public void setRowTypeName(TObjectName rowTypeName) {
1042        this.rowTypeName = rowTypeName;
1043    }
1044
1045    public void setSuperTableName(TObjectName superTableName) {
1046        this.superTableName = superTableName;
1047    }
1048
1049    public void setSubQuery(TSelectSqlStatement subQuery) {
1050        this.subQuery = subQuery;
1051    }
1052
1053    public void setExecutePreparedStatement(TExecuteSqlStatement executePreparedStatement) {
1054        this.executePreparedStatement = executePreparedStatement;
1055    }
1056
1057    public void setMySQLTableOptionList(TPTNodeList<TMySQLCreateTableOption> mySQLTableOptionList) {
1058        this.mySQLTableOptionList = mySQLTableOptionList;
1059    }
1060
1061    public void setTableName(TObjectName tableName) {
1062        this.tableName = tableName;
1063    }
1064
1065    public void setTableConstraints(TConstraintList tableConstraints) {
1066        this.tableConstraints = tableConstraints;
1067    }
1068}