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