001package gudusoft.gsqlparser.nodes; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.List; 006import java.util.regex.Matcher; 007import java.util.regex.Pattern; 008 009import gudusoft.gsqlparser.*; 010import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement; 011import gudusoft.gsqlparser.stmt.snowflake.TSnowflakeCopyIntoStmt; 012import gudusoft.gsqlparser.stmt.snowflake.TAlterStageStmt; 013import gudusoft.gsqlparser.stmt.snowflake.TCreateStageStmt; 014 015public class TCreateTableOption extends TParseTreeNode { 016 017 public enum ESecondaryRolesMode { 018 unspecified, 019 all, 020 none, 021 roleList 022 } 023 024 private TObjectName executeAsUser; 025 private TObjectName backfillFrom; 026 private ESecondaryRolesMode secondaryRolesMode = ESecondaryRolesMode.unspecified; 027 private TObjectNameList secondaryRoleList; 028 029 /** 030 * Returns the Snowflake user whose privileges are used to refresh a 031 * dynamic table. 032 */ 033 public TObjectName getExecuteAsUser() { 034 return executeAsUser; 035 } 036 037 public void setExecuteAsUser(TObjectName executeAsUser) { 038 this.executeAsUser = executeAsUser; 039 } 040 041 /** 042 * Returns the Snowflake table used to seed a dynamic table. 043 */ 044 public TObjectName getBackfillFrom() { 045 return backfillFrom; 046 } 047 048 public void setBackfillFrom(TObjectName backfillFrom) { 049 this.backfillFrom = backfillFrom; 050 } 051 052 /** 053 * Returns how USE SECONDARY ROLES is configured for EXECUTE AS USER. 054 */ 055 public ESecondaryRolesMode getSecondaryRolesMode() { 056 return secondaryRolesMode; 057 } 058 059 public void setSecondaryRolesMode(ESecondaryRolesMode secondaryRolesMode) { 060 this.secondaryRolesMode = secondaryRolesMode; 061 } 062 063 /** 064 * Returns the explicit role list when {@link #getSecondaryRolesMode()} 065 * is {@link ESecondaryRolesMode#roleList}. 066 */ 067 public TObjectNameList getSecondaryRoleList() { 068 return secondaryRoleList; 069 } 070 071 public void setSecondaryRoleList(TObjectNameList secondaryRoleList) { 072 this.secondaryRoleList = secondaryRoleList; 073 } 074 075 private TDistributeBy distributeBy; 076 077 public TDistributeBy getDistributeBy() { 078 return distributeBy; 079 } 080 081 private TBaseTablePartition partitionSpec; 082 083 public TBaseTablePartition getPartitionSpec() { 084 return partitionSpec; 085 } 086 087 public TObjectName getComment() { 088 return comment; 089 } 090 091 private TObjectName comment; 092 093 /* 094 * BigQuery external_table_option_list 095 * 096 * @see https://cloud.google.com/bigquery/docs/reference/standard-sql/data- 097 * definition-language#external_table_option_list 098 */ 099 private Boolean allowJaggedRows; 100 private Boolean allowQuotedNewlines; 101 private String compression; 102 private String description; 103 private Boolean enableLogicalTypes; 104 private String encoding; 105 private String expirationTimestamp; 106 private String fieldDelimiter; 107 private String format; 108 private List<String> decimalTargetTypes; 109 private String hivePartitionUriPrefix; 110 private Boolean ignoreUnknownValues; 111 private Long maxBadRecords; 112 private String nullMarker; 113 private String projectionFields; 114 private String quote; 115 private Boolean requireHivePartitionFilter; 116 private String sheetRange; 117 private Long skipLeadingRows; 118 private List<String> uris; 119 120 private TObjectNameList columnNamelist; 121 122 public TObjectNameList getColumnNamelist() { 123 return columnNamelist; 124 } 125 126 private String awsSnsTopic = null; 127 private TObjectNameList partitionColumnList; 128 private TExpression partitionByExpr; 129 130 /** 131 * Bigquery partition by expr 132 * @return expr 133 */ 134 public TExpression getPartitionByExpr() { 135 return partitionByExpr; 136 } 137 138 private String fileFormatName = null; 139 private String fileFormatType = null; 140 private ArrayList<TNameValuePair> fileFormatProperties = null; 141 142 public void setFileFormatName(TSourceToken fileFormatName) { 143 this.fileFormatName = fileFormatName.toString(); 144 } 145 public void setFileFormatName(TObjectName fileFormatName) { 146 this.fileFormatName = fileFormatName.toString(); 147 } 148 149 public void setFileFormatType(TSourceToken fileFormatType) { 150 this.fileFormatType = fileFormatType.toString(); 151 } 152 153 public String getFileFormatName() { 154 return fileFormatName; 155 } 156 157 public String getFileFormatType() { 158 return fileFormatType; 159 } 160 161 /** 162 * Get file format properties list (e.g., TYPE=CSV, FIELD_DELIMITER='|', SKIP_HEADER=1) 163 * Used in Snowflake external table file_format option 164 * @return list of name-value pairs representing file format properties 165 */ 166 public ArrayList<TNameValuePair> getFileFormatProperties() { 167 return fileFormatProperties; 168 } 169 170 /** 171 * Set file format properties list 172 * @param fileFormatProperties list of name-value pairs for file format options 173 */ 174 public void setFileFormatProperties(ArrayList<TNameValuePair> fileFormatProperties) { 175 this.fileFormatProperties = fileFormatProperties; 176 } 177 178 /** 179 * Parse file format string and create name-value pair list 180 * 181 * <p>Parses file format options in formats like:</p> 182 * <ul> 183 * <li>Single line: file_format=(TYPE=CSV FIELD_DELIMITER='|' SKIP_HEADER=1)</li> 184 * <li>Multi-line: FILE_FORMAT = (TYPE = CSV, FIELD_DELIMITER = ',', SKIP_HEADER = 1)</li> 185 * </ul> 186 * 187 * @param fileFormatString the file_format string to parse 188 * @return ArrayList of TNameValuePair objects representing the properties 189 */ 190 public ArrayList<TNameValuePair> parseFileFormatProperties(String fileFormatString) { 191 if (fileFormatString == null || fileFormatString.trim().isEmpty()) { 192 return null; 193 } 194 195 ArrayList<TNameValuePair> properties = new ArrayList<TNameValuePair>(); 196 197 // Normalize the input: remove line breaks and extra spaces 198 String normalized = fileFormatString.replaceAll("\\s+", " ").trim(); 199 200 // Extract content within parentheses 201 // Match pattern: file_format=(...) or FILE_FORMAT = (...) 202 Pattern outerPattern = Pattern.compile("(?i)file_format\\s*=\\s*\\((.+)\\)", Pattern.DOTALL); 203 Matcher outerMatcher = outerPattern.matcher(normalized); 204 205 String content; 206 if (outerMatcher.find()) { 207 content = outerMatcher.group(1).trim(); 208 } else { 209 // Try to match just the content in parentheses (...) 210 Pattern parenthesesPattern = Pattern.compile("\\((.+)\\)", Pattern.DOTALL); 211 Matcher parenthesesMatcher = parenthesesPattern.matcher(normalized); 212 if (parenthesesMatcher.find()) { 213 content = parenthesesMatcher.group(1).trim(); 214 } else { 215 // No parentheses found, assume the whole string is the content 216 content = normalized; 217 } 218 } 219 220 // Split by comma or space, but respect quoted strings and parentheses 221 ArrayList<String> pairs; 222 if (hasUnquotedComma(content)) { 223 // Comma-separated format 224 pairs = splitByComma(content); 225 } else { 226 // Space-separated format 227 pairs = splitBySpace(content); 228 } 229 230 // Parse each name=value pair 231 for (String pair : pairs) { 232 pair = pair.trim(); 233 if (pair.isEmpty()) { 234 continue; 235 } 236 237 // Split by '=' to get name and value 238 int equalsIndex = findEqualsIndex(pair); 239 if (equalsIndex > 0) { 240 String name = pair.substring(0, equalsIndex).trim(); 241 String value = pair.substring(equalsIndex + 1).trim(); 242 243 TNameValuePair nvPair = new TNameValuePair(); 244 nvPair.init(name, value); 245 properties.add(nvPair); 246 } 247 } 248 249 // Store in the field and return 250 this.fileFormatProperties = properties; 251 return properties; 252 } 253 254 /** 255 * Check if the content has any unquoted comma 256 * Helper method for parseFileFormatProperties 257 */ 258 private boolean hasUnquotedComma(String content) { 259 boolean inSingleQuote = false; 260 boolean inDoubleQuote = false; 261 262 for (int i = 0; i < content.length(); i++) { 263 char ch = content.charAt(i); 264 265 if (ch == '\'' && !inDoubleQuote) { 266 inSingleQuote = !inSingleQuote; 267 } else if (ch == '"' && !inSingleQuote) { 268 inDoubleQuote = !inDoubleQuote; 269 } else if (ch == ',' && !inSingleQuote && !inDoubleQuote) { 270 return true; // Found an unquoted comma 271 } 272 } 273 274 return false; 275 } 276 277 /** 278 * Split string by comma, but respect quoted strings and parentheses 279 * Helper method for parseFileFormatProperties 280 */ 281 private ArrayList<String> splitByComma(String content) { 282 ArrayList<String> parts = new ArrayList<String>(); 283 StringBuilder current = new StringBuilder(); 284 boolean inSingleQuote = false; 285 boolean inDoubleQuote = false; 286 int parenthesesDepth = 0; 287 288 for (int i = 0; i < content.length(); i++) { 289 char ch = content.charAt(i); 290 291 if (ch == '\'' && !inDoubleQuote) { 292 inSingleQuote = !inSingleQuote; 293 current.append(ch); 294 } else if (ch == '"' && !inSingleQuote) { 295 inDoubleQuote = !inDoubleQuote; 296 current.append(ch); 297 } else if (ch == '(' && !inSingleQuote && !inDoubleQuote) { 298 parenthesesDepth++; 299 current.append(ch); 300 } else if (ch == ')' && !inSingleQuote && !inDoubleQuote) { 301 parenthesesDepth--; 302 current.append(ch); 303 } else if (ch == ',' && !inSingleQuote && !inDoubleQuote && parenthesesDepth == 0) { 304 // Found a separator comma 305 parts.add(current.toString()); 306 current.setLength(0); // Clear StringBuilder 307 } else { 308 current.append(ch); 309 } 310 } 311 312 // Add the last part 313 if (current.length() > 0) { 314 parts.add(current.toString()); 315 } 316 317 return parts; 318 } 319 320 /** 321 * Split string by space, but respect quoted strings 322 * Helper method for parseFileFormatProperties (for space-separated format) 323 */ 324 private ArrayList<String> splitBySpace(String content) { 325 ArrayList<String> parts = new ArrayList<String>(); 326 StringBuilder current = new StringBuilder(); 327 boolean inSingleQuote = false; 328 boolean inDoubleQuote = false; 329 boolean inValue = false; // Track if we're currently building a value after '=' 330 331 for (int i = 0; i < content.length(); i++) { 332 char ch = content.charAt(i); 333 334 if (ch == '\'' && !inDoubleQuote) { 335 inSingleQuote = !inSingleQuote; 336 current.append(ch); 337 } else if (ch == '"' && !inSingleQuote) { 338 inDoubleQuote = !inDoubleQuote; 339 current.append(ch); 340 } else if (ch == '=' && !inSingleQuote && !inDoubleQuote) { 341 current.append(ch); 342 inValue = true; // After '=', we're in the value part 343 } else if (ch == ' ' && !inSingleQuote && !inDoubleQuote && inValue) { 344 // Space after a value - end current pair 345 parts.add(current.toString()); 346 current.setLength(0); 347 inValue = false; 348 } else if (ch == ' ' && !inSingleQuote && !inDoubleQuote && !inValue) { 349 // Space before '=' - just skip it 350 if (current.length() > 0) { 351 current.append(ch); 352 } 353 } else { 354 current.append(ch); 355 } 356 } 357 358 // Add the last part 359 if (current.length() > 0) { 360 parts.add(current.toString()); 361 } 362 363 return parts; 364 } 365 366 /** 367 * Find the index of the first '=' that is not inside quotes 368 * Helper method for parseFileFormatProperties 369 */ 370 private int findEqualsIndex(String pair) { 371 boolean inSingleQuote = false; 372 boolean inDoubleQuote = false; 373 374 for (int i = 0; i < pair.length(); i++) { 375 char ch = pair.charAt(i); 376 377 if (ch == '\'' && !inDoubleQuote) { 378 inSingleQuote = !inSingleQuote; 379 } else if (ch == '"' && !inSingleQuote) { 380 inDoubleQuote = !inDoubleQuote; 381 } else if (ch == '=' && !inSingleQuote && !inDoubleQuote) { 382 return i; 383 } 384 } 385 386 return -1; // No equals sign found 387 } 388 389 private TStageLocation stageLocation; 390 391 public void setStageLocation(TStageLocation stageLocation) { 392 this.stageLocation = stageLocation; 393 } 394 395 public TStageLocation getStageLocation() { 396 return stageLocation; 397 } 398 399 400 401 public String getAwsSnsTopic() { 402 return awsSnsTopic; 403 } 404 405 public void setAwsSnsTopic(String awsSnsTopic) { 406 this.awsSnsTopic = awsSnsTopic; 407 } 408 409 public TObjectNameList getPartitionColumnList() { 410 return partitionColumnList; 411 } 412 413 public void setPartitionColumnList(TObjectNameList partitionColumnList) { 414 this.partitionColumnList = partitionColumnList; 415 } 416 417 public String getCompression() { 418 return compression; 419 } 420 421 public void setCompression(String compression) { 422 this.compression = compression; 423 } 424 425 public String getDescription() { 426 return description; 427 } 428 429 public void setDescription(String description) { 430 this.description = description; 431 } 432 433 public String getExpirationTimestamp() { 434 return expirationTimestamp; 435 } 436 437 public void setExpirationTimestamp(String expirationTimestamp) { 438 this.expirationTimestamp = expirationTimestamp; 439 } 440 441 public String getFieldDelimiter() { 442 return fieldDelimiter; 443 } 444 445 public void setFieldDelimiter(String fieldDelimiter) { 446 this.fieldDelimiter = fieldDelimiter; 447 } 448 449 public String getFormat() { 450 return format; 451 } 452 453 public void setFormat(String format) { 454 this.format = format; 455 } 456 457 public List<String> getDecimalTargetTypes() { 458 return decimalTargetTypes; 459 } 460 461 public void setDecimalTargetTypes(List<String> decimalTargetTypes) { 462 this.decimalTargetTypes = decimalTargetTypes; 463 } 464 465 public String getHivePartitionUriPrefix() { 466 return hivePartitionUriPrefix; 467 } 468 469 public void setHivePartitionUriPrefix(String hivePartitionUriPrefix) { 470 this.hivePartitionUriPrefix = hivePartitionUriPrefix; 471 } 472 473 public Boolean getIgnoreUnknownValues() { 474 return ignoreUnknownValues; 475 } 476 477 public void setIgnoreUnknownValues(Boolean ignoreUnknownValues) { 478 this.ignoreUnknownValues = ignoreUnknownValues; 479 } 480 481 public Long getMaxBadRecords() { 482 return maxBadRecords; 483 } 484 485 public void setMaxBadRecords(Long maxBadRecords) { 486 this.maxBadRecords = maxBadRecords; 487 } 488 489 public void setRequireHivePartitionFilter(Boolean requireHivePartitionFilter) { 490 this.requireHivePartitionFilter = requireHivePartitionFilter; 491 } 492 493 public String getNullMarker() { 494 return nullMarker; 495 } 496 497 public void setNullMarker(String nullMarker) { 498 this.nullMarker = nullMarker; 499 } 500 501 public String getProjectionFields() { 502 return projectionFields; 503 } 504 505 public void setProjectionFields(String projectionFields) { 506 this.projectionFields = projectionFields; 507 } 508 509 public String getQuote() { 510 return quote; 511 } 512 513 public void setQuote(String quote) { 514 this.quote = quote; 515 } 516 517 public Boolean getRequireHivePartitionFilter() { 518 return requireHivePartitionFilter; 519 } 520 521 public String getSheetRange() { 522 return sheetRange; 523 } 524 525 public void setSheetRange(String sheetRange) { 526 this.sheetRange = sheetRange; 527 } 528 529 public Long getSkipLeadingRows() { 530 return skipLeadingRows; 531 } 532 533 public void setSkipLeadingRows(Long skipLeadingRows) { 534 this.skipLeadingRows = skipLeadingRows; 535 } 536 537 public List<String> getUris() { 538 return uris; 539 } 540 541 public void setUris(List<String> uris) { 542 this.uris = uris; 543 } 544 545 public Boolean getAllowJaggedRows() { 546 return allowJaggedRows; 547 } 548 549 public void setAllowJaggedRows(Boolean allowJaggedRows) { 550 this.allowJaggedRows = allowJaggedRows; 551 } 552 553 public Boolean getAllowQuotedNewlines() { 554 return allowQuotedNewlines; 555 } 556 557 public void setAllowQuotedNewlines(Boolean allowQuotedNewlines) { 558 this.allowQuotedNewlines = allowQuotedNewlines; 559 } 560 561 public Boolean getEnableLogicalTypes() { 562 return enableLogicalTypes; 563 } 564 565 public void setEnableLogicalTypes(Boolean enableLogicalTypes) { 566 this.enableLogicalTypes = enableLogicalTypes; 567 } 568 569 public String getEncoding() { 570 return encoding; 571 } 572 573 public void setEncoding(String encoding) { 574 this.encoding = encoding; 575 } 576 public void setEncoding(TSourceToken encoding) { 577 this.encoding = encoding.toString(); 578 } // added by baffle 579 580 public String getExternalStageURL() { 581 return externalStageURL; 582 } 583 584 public void setExternalStageURL(String externalStageURL) { 585 this.externalStageURL = externalStageURL; 586 } 587 588 public void setPartitionByExpr(TExpression partitionByExpr) { 589 this.partitionByExpr = partitionByExpr; 590 } 591 592 public void setFileFormatName(String fileFormatName) { 593 this.fileFormatName = fileFormatName; 594 } 595 596 public void setFileFormatType(String fileFormatType) { 597 this.fileFormatType = fileFormatType; 598 } 599 600 public void setDateRetentionInDays(TSourceToken dateRetentionInDays) { 601 this.dateRetentionInDays = dateRetentionInDays; 602 } 603 604 public void setCommentToken(TSourceToken commentToken) { 605 this.commentToken = commentToken; 606 } 607 608 public void setStageFileFormat(TDummy stageFileFormat) { 609 this.stageFileFormat = stageFileFormat; 610 } 611 612 public void setCopyOptions(TDummy copyOptions) { 613 this.copyOptions = copyOptions; 614 } 615 616 public void setExpressionList(TExpressionList expressionList) { 617 this.expressionList = expressionList; 618 } 619 620 private TSourceToken dateRetentionInDays; 621 622 public TSourceToken getDateRetentionInDays() { 623 return dateRetentionInDays; 624 } 625 626 private TSourceToken commentToken; 627 628 /** 629 * @deprecated since v 2.8.1.1, please use {@link #getComment()} instead 630 * @return 631 */ 632 public TSourceToken getCommentToken() { 633 return commentToken; 634 } 635 636 private TDummy stageFileFormat; 637 638 private TDummy copyOptions; 639 640 public TDummy getCopyOptions() { 641 return copyOptions; 642 } 643 644 protected ECreateTableOption createTableOptionType; 645 646 public void setCreateTableOptionType(ECreateTableOption createTableOptionType) { 647 this.createTableOptionType = createTableOptionType; 648 } 649 650 public ECreateTableOption getCreateTableOptionType() { 651 return createTableOptionType; 652 } 653 654 public void init(Object arg1){ 655 createTableOptionType = (ECreateTableOption)arg1; 656 } 657 658 private TExpressionList expressionList; 659 660 public TExpressionList getExpressionList() { 661 return expressionList; 662 } 663 664 public TDummy getStageFileFormat() { 665 return stageFileFormat; 666 } 667 668 private String externalStageURL=null; 669 670 private TObjectName tableLocation; 671 672 /** 673 * The path of a {@link ECreateTableOption#etoLocation} option, {@code 's3://bucket/path/'} in 674 * {@code LOCATION 's3://bucket/path/'}: where the files of the table are. Null for any other option. 675 */ 676 public TObjectName getTableLocation() { 677 return tableLocation; 678 } 679 680 public void init(Object arg1, Object arg2){ 681 init(arg1); 682 switch(createTableOptionType){ 683 case etoLocation: 684 this.tableLocation = (TObjectName)arg2; 685 break; 686 case etoClusterBy: 687 this.expressionList = (TExpressionList)arg2; 688 break; 689 case etoStageCopyOptions: 690 this.copyOptions = (TDummy)arg2; 691 break; 692 case etoStageFileFormat: 693 this.stageFileFormat = (TDummy)arg2; 694 break; 695 case etoComment: 696 //this.commentToken = (TSourceToken)arg2; 697 this.comment = (TObjectName) arg2; 698 break; 699 case etoBackfillFrom: 700 this.backfillFrom = (TObjectName) arg2; 701 break; 702 case etoDateRetentionTimeInDays: 703 this.dateRetentionInDays = (TSourceToken)arg2; 704 break; 705 case etoPartitionBy: 706 if (arg2 instanceof TObjectNameList){ 707 this.partitionColumnList = (TObjectNameList)arg2; 708 }else if (arg2 instanceof TExpression){ 709 this.partitionByExpr = (TExpression)arg2; 710 } 711 break; 712 case etoAWSSnsTopic: 713 awsSnsTopic = ((TSourceToken)arg2).toString(); 714 break; 715 case etoStageURL: 716 externalStageURL = ((TSourceToken)arg2).toString(); 717 break; 718 case etoFiles: 719 this.expressionList = (TExpressionList)arg2; 720 break; 721 case etoDistributeOn: 722 case etoOrganizeOn: 723 this.columnNamelist =(TObjectNameList)arg2; 724 break; 725 case etoReloptions: 726 this.attributeOptions = (ArrayList<TAttributeOption>)arg2; 727 break; 728 case etoPartitionSpec: 729 this.partitionSpec = (TBaseTablePartition)arg2; 730 break; 731 case etoDistributeBy: 732 this.distributeBy = (TDistributeBy)arg2; 733 break; 734 case etoDistributeByHash: 735 this.columnNamelist = (TObjectNameList)arg2; 736 break; 737 case etoPartitioningKey: 738 this.columnNamelist = (TObjectNameList)arg2; 739 break; 740 case etoOrganizeBy: 741 case etoOrganizeByDimensions: 742 this.valueRowItemList = (TMultiTargetList)arg2; 743 break; 744 } 745 } 746 747 private TMultiTargetList valueRowItemList; 748 749 public TMultiTargetList getValueRowItemList() { 750 return valueRowItemList; 751 } 752 753 public ArrayList<TAttributeOption> getAttributeOptions() { 754 return attributeOptions; 755 } 756 757 private ArrayList<TAttributeOption> attributeOptions ; 758 759 private void parseBigQueryTableOption() { 760 String options = this.toString().trim(); 761 if (!options.toUpperCase(java.util.Locale.ROOT).startsWith("OPTIONS")) 762 return; 763 options = options.replaceFirst("(?i)OPTIONS", "").trim(); 764 options = options.substring(1, options.length() - 1).trim(); 765 if (!options.endsWith(",")) { 766 options = options + ","; 767 } 768 769 this.allowJaggedRows = getPatternBoolean(options, "allow_jagged_rows"); 770 this.allowQuotedNewlines = getPatternBoolean(options, "allow_quoted_newlines"); 771 this.compression = getPatternString(options, "compression"); 772 this.description = getPatternString(options, "description"); 773 this.enableLogicalTypes = getPatternBoolean(options, "enable_logical_types"); 774 this.encoding = getPatternString(options, "encoding"); 775 this.expirationTimestamp = getTimestampString(options, "expiration_timestamp"); 776 this.fieldDelimiter = getPatternString(options, "field_delimiter"); 777 this.format = getPatternString(options, "format"); 778 this.decimalTargetTypes = getPatternArray(options, "decimal_target_types"); 779 this.hivePartitionUriPrefix = getPatternString(options, "hive_partition_uri_prefix"); 780 this.ignoreUnknownValues = getPatternBoolean(options, "ignore_unknown_values"); 781 this.maxBadRecords = getPatternLong(options, "max_bad_records"); 782 this.nullMarker = getPatternString(options, "null_marker"); 783 this.projectionFields = getPatternString(options, "projection_fields"); 784 this.quote = getPatternString(options, "quote"); 785 this.requireHivePartitionFilter = getPatternBoolean(options, "require_hive_partition_filter"); 786 this.sheetRange = getPatternString(options, "sheet_range"); 787 this.skipLeadingRows = getPatternLong(options, "skip_leading_rows"); 788 this.uris = getPatternArray(options, "uris"); 789 } 790 791 private String getTimestampString(String content, String field) { 792 content = content.replaceAll("(\\s*,)+", ","); 793 if (content.matches("(?is).*" + field + "\\s*=(.+?)=.+")) { 794 String patternExp = "(?is)" + field + "\\s*=(.+?)="; 795 Pattern pattern = Pattern.compile(patternExp); 796 Matcher matcher = pattern.matcher(content); 797 if (matcher.find()) { 798 String timestamp = matcher.group(1).trim(); 799 timestamp = timestamp.substring(0, timestamp.lastIndexOf(",")).trim(); 800 return timestamp; 801 } 802 } 803 else if(content.matches("(?is).*" + field + "\\s*=(.+),")){ 804 String patternExp = "(?is)" + field + "\\s*=(.+),"; 805 Pattern pattern = Pattern.compile(patternExp); 806 Matcher matcher = pattern.matcher(content); 807 if (matcher.find()) { 808 String timestamp = matcher.group(1).trim(); 809 return timestamp; 810 } 811 } 812 return null; 813 } 814 815 private String getPatternString(String content, String field) { 816 String patternExp = "(?is)" + field + "\\s*=\\s*(\".+?\"),"; 817 Pattern pattern = Pattern.compile(patternExp); 818 Matcher matcher = pattern.matcher(content); 819 if (matcher.find()) { 820 return matcher.group(1).trim(); 821 } 822 patternExp = "(?is)" + field + "\\s*=\\s*('.+?\'),"; 823 pattern = Pattern.compile(patternExp); 824 matcher = pattern.matcher(content); 825 if (matcher.find()) { 826 return matcher.group(1).trim(); 827 } 828 return null; 829 } 830 831 private Boolean getPatternBoolean(String content, String field) { 832 String patternExp = "(?is)" + field + "\\s*=(.+?),"; 833 Pattern pattern = Pattern.compile(patternExp); 834 Matcher matcher = pattern.matcher(content); 835 if (matcher.find()) { 836 return Boolean.parseBoolean(matcher.group(1).trim()); 837 } 838 return null; 839 } 840 841 private Long getPatternLong(String content, String field) { 842 String patternExp = "(?is)" + field + "\\s*=(.+?),"; 843 Pattern pattern = Pattern.compile(patternExp); 844 Matcher matcher = pattern.matcher(content); 845 if (matcher.find()) { 846 return Long.parseLong(matcher.group(1).trim()); 847 } 848 return null; 849 } 850 851 private List<String> getPatternArray(String content, String field) { 852 String patternExp = "(?is)" + field + "\\s*=\\s*\\[(.+?)\\]\\s*,"; 853 Pattern pattern = Pattern.compile(patternExp); 854 Matcher matcher = pattern.matcher(content); 855 if (matcher.find()) { 856 String arrayItems = matcher.group(1).trim(); 857 if (arrayItems.startsWith("(") && arrayItems.endsWith(")")) { 858 arrayItems = arrayItems.substring(1, arrayItems.length() - 1).trim(); 859 } 860 return Arrays.asList(arrayItems.split("\\s*,\\s*")); 861 } 862 return null; 863 } 864 865 public void doParse(TCustomSqlStatement psql, ESqlClause plocation) { 866 867 if (psql instanceof TCreateTableSqlStatement) { 868 TCreateTableSqlStatement c = (TCreateTableSqlStatement) psql; 869 870 switch (this.createTableOptionType){ 871 case etoPartitionBy: 872 if (this.partitionColumnList != null){ 873 c.setPartitionColumnList(this.partitionColumnList); 874 }else if (this.partitionByExpr != null){ 875 c.setPartitionByExpr(this.partitionByExpr); 876 this.partitionByExpr.doParse(c,ESqlClause.createTable); 877 } 878 break; 879 case etoPattern: 880 c.setRegex_pattern(this.getEndToken().toString()); 881 break; 882 case etoComment: 883 c.setTableComment(TObjectName.createObjectName (psql.dbvendor, EDbObjectType.comment, this.commentToken)); 884 break; 885 case etoWithLocation: 886 c.setStageLocation(this.getStageLocation()); 887 break; 888 case etoFileFormat: 889 c.setFileFormatName(this.fileFormatName); 890 c.setFileFormatType(this.fileFormatType); 891 fileFormatProperties = parseFileFormatProperties(this.toString()); 892 break; 893 case etoAWSSnsTopic: 894 c.setAwsSnsTopic(this.awsSnsTopic); 895 break; 896 case etoBigQueryExternal: 897 parseBigQueryTableOption(); 898 break; 899 case etoClusterBy: 900 if (expressionList != null){ 901 expressionList.doParse(psql,plocation); 902 } 903 break; 904 case etoBackfillFrom: 905 this.backfillFrom.setDbObjectType( 906 psql.dbvendor, EDbObjectType.table); 907 break; 908 default: 909 break; 910 911 } 912 }else if(psql instanceof TCreateStageStmt){ 913 TCreateStageStmt c = (TCreateStageStmt)psql; 914 switch (this.createTableOptionType){ 915 case etoFileFormat: 916 c.setFileFormatName(this.fileFormatName); 917 c.setFileFormatType(this.fileFormatType); 918 break; 919 case etoStageURL: 920 c.setExternalStageURL(this.externalStageURL); 921 break; 922 default: 923 break; 924 } 925 }else if(psql instanceof TAlterStageStmt){ 926 TAlterStageStmt c = (TAlterStageStmt)psql; 927 switch (this.createTableOptionType){ 928 case etoFileFormat: 929 c.setFileFormatName(this.fileFormatName); 930 c.setFileFormatType(this.fileFormatType); 931 break; 932 case etoStageURL: 933 c.setExternalStageURL(this.externalStageURL); 934 break; 935 default: 936 break; 937 } 938 }else if(psql instanceof TSnowflakeCopyIntoStmt){ 939 TSnowflakeCopyIntoStmt c = (TSnowflakeCopyIntoStmt)psql; 940 switch (this.createTableOptionType){ 941 case etoFileFormat: 942 c.setFileFormatName(this.fileFormatName); 943 c.setFileFormatType(this.fileFormatType); 944 break; 945 case etoStageURL: 946 break; 947 case etoPattern: 948 c.setRegex_pattern(this.getEndToken().toString()); 949 break; 950 case etoFiles: 951 for(TExpression e:this.expressionList){ 952 c.getFileList().add(e.toString()); 953 } 954 break; 955 default: 956 break; 957 } 958 } 959 } 960 961 public void accept(TParseTreeVisitor v){ 962 v.preVisit(this); 963 v.postVisit(this); 964 } 965 public void acceptChildren(TParseTreeVisitor v){ 966 v.preVisit(this); 967 v.postVisit(this); 968 } 969}