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}