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