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
082    public void setFileFormatName(TSourceToken fileFormatName) {
083        this.fileFormatName = fileFormatName.toString();
084    }
085    public void setFileFormatName(TObjectName fileFormatName) {
086        this.fileFormatName = fileFormatName.toString();
087    }
088
089    public void setFileFormatType(TSourceToken fileFormatType) {
090        this.fileFormatType = fileFormatType.toString();
091    }
092
093    public String getFileFormatName() {
094        return fileFormatName;
095    }
096
097    public String getFileFormatType() {
098        return fileFormatType;
099    }
100
101    private TStageLocation stageLocation;
102
103    public void setStageLocation(TStageLocation stageLocation) {
104        this.stageLocation = stageLocation;
105    }
106
107    public TStageLocation getStageLocation() {
108        return stageLocation;
109    }
110
111
112
113    public String getAwsSnsTopic() {
114        return awsSnsTopic;
115    }
116
117    public void setAwsSnsTopic(String awsSnsTopic) {
118        this.awsSnsTopic = awsSnsTopic;
119    }
120
121    public TObjectNameList getPartitionColumnList() {
122        return partitionColumnList;
123    }
124
125    public void setPartitionColumnList(TObjectNameList partitionColumnList) {
126        this.partitionColumnList = partitionColumnList;
127    }
128
129    public String getCompression() {
130        return compression;
131    }
132
133    public void setCompression(String compression) {
134        this.compression = compression;
135    }
136
137    public String getDescription() {
138        return description;
139    }
140
141    public void setDescription(String description) {
142        this.description = description;
143    }
144
145    public String getExpirationTimestamp() {
146        return expirationTimestamp;
147    }
148
149    public void setExpirationTimestamp(String expirationTimestamp) {
150        this.expirationTimestamp = expirationTimestamp;
151    }
152
153    public String getFieldDelimiter() {
154        return fieldDelimiter;
155    }
156
157    public void setFieldDelimiter(String fieldDelimiter) {
158        this.fieldDelimiter = fieldDelimiter;
159    }
160
161    public String getFormat() {
162        return format;
163    }
164
165    public void setFormat(String format) {
166        this.format = format;
167    }
168
169    public List<String> getDecimalTargetTypes() {
170        return decimalTargetTypes;
171    }
172
173    public void setDecimalTargetTypes(List<String> decimalTargetTypes) {
174        this.decimalTargetTypes = decimalTargetTypes;
175    }
176
177    public String getHivePartitionUriPrefix() {
178        return hivePartitionUriPrefix;
179    }
180
181    public void setHivePartitionUriPrefix(String hivePartitionUriPrefix) {
182        this.hivePartitionUriPrefix = hivePartitionUriPrefix;
183    }
184
185    public Boolean getIgnoreUnknownValues() {
186        return ignoreUnknownValues;
187    }
188
189    public void setIgnoreUnknownValues(Boolean ignoreUnknownValues) {
190        this.ignoreUnknownValues = ignoreUnknownValues;
191    }
192
193    public Long getMaxBadRecords() {
194        return maxBadRecords;
195    }
196
197    public void setMaxBadRecords(Long maxBadRecords) {
198        this.maxBadRecords = maxBadRecords;
199    }
200
201    public void setRequireHivePartitionFilter(Boolean requireHivePartitionFilter) {
202        this.requireHivePartitionFilter = requireHivePartitionFilter;
203    }
204
205    public String getNullMarker() {
206        return nullMarker;
207    }
208
209    public void setNullMarker(String nullMarker) {
210        this.nullMarker = nullMarker;
211    }
212
213    public String getProjectionFields() {
214        return projectionFields;
215    }
216
217    public void setProjectionFields(String projectionFields) {
218        this.projectionFields = projectionFields;
219    }
220
221    public String getQuote() {
222        return quote;
223    }
224
225    public void setQuote(String quote) {
226        this.quote = quote;
227    }
228
229    public Boolean getRequireHivePartitionFilter() {
230        return requireHivePartitionFilter;
231    }
232
233    public String getSheetRange() {
234        return sheetRange;
235    }
236
237    public void setSheetRange(String sheetRange) {
238        this.sheetRange = sheetRange;
239    }
240
241    public Long getSkipLeadingRows() {
242        return skipLeadingRows;
243    }
244
245    public void setSkipLeadingRows(Long skipLeadingRows) {
246        this.skipLeadingRows = skipLeadingRows;
247    }
248
249    public List<String> getUris() {
250        return uris;
251    }
252
253    public void setUris(List<String> uris) {
254        this.uris = uris;
255    }
256
257    public Boolean getAllowJaggedRows() {
258        return allowJaggedRows;
259    }
260
261    public void setAllowJaggedRows(Boolean allowJaggedRows) {
262        this.allowJaggedRows = allowJaggedRows;
263    }
264
265    public Boolean getAllowQuotedNewlines() {
266        return allowQuotedNewlines;
267    }
268
269    public void setAllowQuotedNewlines(Boolean allowQuotedNewlines) {
270        this.allowQuotedNewlines = allowQuotedNewlines;
271    }
272
273    public Boolean getEnableLogicalTypes() {
274        return enableLogicalTypes;
275    }
276
277    public void setEnableLogicalTypes(Boolean enableLogicalTypes) {
278        this.enableLogicalTypes = enableLogicalTypes;
279    }
280
281    public String getEncoding() {
282        return encoding;
283    }
284
285    public void setEncoding(String encoding) {
286        this.encoding = encoding;
287    }
288    public void setEncoding(TSourceToken encoding) {
289                this.encoding = encoding.toString();
290    } // added by baffle
291
292    public String getExternalStageURL() {
293        return externalStageURL;
294    }
295
296    public void setExternalStageURL(String externalStageURL) {
297        this.externalStageURL = externalStageURL;
298    }
299
300    public void setPartitionByExpr(TExpression partitionByExpr) {
301        this.partitionByExpr = partitionByExpr;
302    }
303
304    public void setFileFormatName(String fileFormatName) {
305        this.fileFormatName = fileFormatName;
306    }
307
308    public void setFileFormatType(String fileFormatType) {
309        this.fileFormatType = fileFormatType;
310    }
311
312    public void setDateRetentionInDays(TSourceToken dateRetentionInDays) {
313        this.dateRetentionInDays = dateRetentionInDays;
314    }
315
316    public void setCommentToken(TSourceToken commentToken) {
317        this.commentToken = commentToken;
318    }
319
320    public void setStageFileFormat(TDummy stageFileFormat) {
321        this.stageFileFormat = stageFileFormat;
322    }
323
324    public void setCopyOptions(TDummy copyOptions) {
325        this.copyOptions = copyOptions;
326    }
327
328    public void setExpressionList(TExpressionList expressionList) {
329        this.expressionList = expressionList;
330    }
331
332    private TSourceToken dateRetentionInDays;
333
334    public TSourceToken getDateRetentionInDays() {
335        return dateRetentionInDays;
336    }
337
338    private TSourceToken commentToken;
339
340    /**
341     * @deprecated since v 2.8.1.1, please use {@link #getComment()} instead
342     * @return
343     */
344    public TSourceToken getCommentToken() {
345        return commentToken;
346    }
347
348    private TDummy stageFileFormat;
349
350    private TDummy copyOptions;
351
352    public TDummy getCopyOptions() {
353        return copyOptions;
354    }
355
356    protected ECreateTableOption createTableOptionType;
357
358    public void setCreateTableOptionType(ECreateTableOption createTableOptionType) {
359        this.createTableOptionType = createTableOptionType;
360    }
361
362    public ECreateTableOption getCreateTableOptionType() {
363        return createTableOptionType;
364    }
365
366    public void  init(Object arg1){
367        createTableOptionType = (ECreateTableOption)arg1;
368    }
369
370    private TExpressionList expressionList;
371
372    public TExpressionList getExpressionList() {
373        return expressionList;
374    }
375
376    public TDummy getStageFileFormat() {
377        return stageFileFormat;
378    }
379
380    private String externalStageURL=null;
381
382    public void init(Object arg1, Object arg2){
383        init(arg1);
384        switch(createTableOptionType){
385            case etoClusterBy:
386                this.expressionList = (TExpressionList)arg2;
387                break;
388            case etoStageCopyOptions:
389                this.copyOptions = (TDummy)arg2;
390                break;
391            case etoStageFileFormat:
392                this.stageFileFormat = (TDummy)arg2;
393                break;
394            case etoComment:
395                //this.commentToken = (TSourceToken)arg2;
396                this.comment = (TObjectName) arg2;
397                break;
398            case etoDateRetentionTimeInDays:
399                this.dateRetentionInDays = (TSourceToken)arg2;
400                break;
401            case etoPartitionBy:
402                if (arg2 instanceof TObjectNameList){
403                    this.partitionColumnList = (TObjectNameList)arg2;
404                }else if (arg2 instanceof  TExpression){
405                    this.partitionByExpr = (TExpression)arg2;
406                }
407                break;
408            case etoAWSSnsTopic:
409                awsSnsTopic = ((TSourceToken)arg2).toString();
410                break;
411            case etoStageURL:
412                externalStageURL = ((TSourceToken)arg2).toString();
413                break;
414            case etoFiles:
415                this.expressionList = (TExpressionList)arg2;
416                break;
417            case etoDistributeOn:
418            case etoOrganizeOn:
419                this.columnNamelist =(TObjectNameList)arg2;
420                break;
421            case etoReloptions:
422                this.attributeOptions  = (ArrayList<TAttributeOption>)arg2;
423                break;
424            case etoPartitionSpec:
425                this.partitionSpec = (TBaseTablePartition)arg2;
426                break;
427            case etoDistributeBy:
428                this.distributeBy = (TDistributeBy)arg2;
429                break;
430            case etoDistributeByHash:
431                this.columnNamelist = (TObjectNameList)arg2;
432                break;
433            case etoPartitioningKey:
434                this.columnNamelist = (TObjectNameList)arg2;
435                break;
436            case etoOrganizeBy:
437            case etoOrganizeByDimensions:
438                this.valueRowItemList = (TMultiTargetList)arg2;
439                break;
440        }
441    }
442
443    private TMultiTargetList valueRowItemList;
444
445    public TMultiTargetList getValueRowItemList() {
446        return valueRowItemList;
447    }
448
449    public ArrayList<TAttributeOption> getAttributeOptions() {
450        return attributeOptions;
451    }
452
453    private ArrayList<TAttributeOption> attributeOptions ;
454
455    private void parseBigQueryTableOption() {
456        String options = this.toString().trim();
457        if (!options.toUpperCase().startsWith("OPTIONS"))
458            return;
459        options = options.replaceFirst("(?i)OPTIONS", "").trim();
460        options = options.substring(1, options.length() - 1).trim();
461        if (!options.endsWith(",")) {
462            options = options + ",";
463        }
464
465        this.allowJaggedRows = getPatternBoolean(options, "allow_jagged_rows");
466        this.allowQuotedNewlines = getPatternBoolean(options, "allow_quoted_newlines");
467        this.compression = getPatternString(options, "compression");
468        this.description = getPatternString(options, "description");
469        this.enableLogicalTypes = getPatternBoolean(options, "enable_logical_types");
470        this.encoding = getPatternString(options, "encoding");
471        this.expirationTimestamp = getTimestampString(options, "expiration_timestamp");
472        this.fieldDelimiter = getPatternString(options, "field_delimiter");
473        this.format = getPatternString(options, "format");
474        this.decimalTargetTypes = getPatternArray(options, "decimal_target_types");
475        this.hivePartitionUriPrefix = getPatternString(options, "hive_partition_uri_prefix");
476        this.ignoreUnknownValues = getPatternBoolean(options, "ignore_unknown_values");
477        this.maxBadRecords = getPatternLong(options, "max_bad_records");
478        this.nullMarker = getPatternString(options, "null_marker");
479        this.projectionFields = getPatternString(options, "projection_fields");
480        this.quote = getPatternString(options, "quote");
481        this.requireHivePartitionFilter = getPatternBoolean(options, "require_hive_partition_filter");
482        this.sheetRange = getPatternString(options, "sheet_range");
483        this.skipLeadingRows = getPatternLong(options, "skip_leading_rows");
484        this.uris = getPatternArray(options, "uris");
485    }
486
487    private String getTimestampString(String content, String field) {
488        content = content.replaceAll("(\\s*,)+", ",");
489        if (content.matches("(?is).*" + field + "\\s*=(.+?)=.+")) {
490            String patternExp = "(?is)" + field + "\\s*=(.+?)=";
491            Pattern pattern = Pattern.compile(patternExp);
492            Matcher matcher = pattern.matcher(content);
493            if (matcher.find()) {
494                String timestamp = matcher.group(1).trim();
495                timestamp = timestamp.substring(0, timestamp.lastIndexOf(",")).trim();
496                return timestamp;
497            }
498        }
499        else if(content.matches("(?is).*" + field + "\\s*=(.+),")){
500            String patternExp = "(?is)" + field + "\\s*=(.+),";
501            Pattern pattern = Pattern.compile(patternExp);
502            Matcher matcher = pattern.matcher(content);
503            if (matcher.find()) {
504                String timestamp = matcher.group(1).trim();
505                return timestamp;
506            }
507        } 
508        return null;
509    }
510
511    private String getPatternString(String content, String field) {
512        String patternExp = "(?is)" + field + "\\s*=\\s*(\".+?\"),";
513        Pattern pattern = Pattern.compile(patternExp);
514        Matcher matcher = pattern.matcher(content);
515        if (matcher.find()) {
516            return matcher.group(1).trim();
517        }
518        patternExp = "(?is)" + field + "\\s*=\\s*('.+?\'),";
519        pattern = Pattern.compile(patternExp);
520        matcher = pattern.matcher(content);
521        if (matcher.find()) {
522            return matcher.group(1).trim();
523        }
524        return null;
525    }
526
527    private Boolean getPatternBoolean(String content, String field) {
528        String patternExp = "(?is)" + field + "\\s*=(.+?),";
529        Pattern pattern = Pattern.compile(patternExp);
530        Matcher matcher = pattern.matcher(content);
531        if (matcher.find()) {
532            return Boolean.parseBoolean(matcher.group(1).trim());
533        }
534        return null;
535    }
536
537    private Long getPatternLong(String content, String field) {
538        String patternExp = "(?is)" + field + "\\s*=(.+?),";
539        Pattern pattern = Pattern.compile(patternExp);
540        Matcher matcher = pattern.matcher(content);
541        if (matcher.find()) {
542            return Long.parseLong(matcher.group(1).trim());
543        }
544        return null;
545    }
546
547    private List<String> getPatternArray(String content, String field) {
548        String patternExp = "(?is)" + field + "\\s*=\\s*\\[(.+?)\\]\\s*,";
549        Pattern pattern = Pattern.compile(patternExp);
550        Matcher matcher = pattern.matcher(content);
551        if (matcher.find()) {
552            String arrayItems = matcher.group(1).trim();
553            if (arrayItems.startsWith("(") && arrayItems.endsWith(")")) {
554                arrayItems = arrayItems.substring(1, arrayItems.length() - 1).trim();
555            }
556            return Arrays.asList(arrayItems.split("\\s*,\\s*"));
557        }
558        return null;
559    }
560
561    public void doParse(TCustomSqlStatement psql, ESqlClause plocation) {
562
563        if (psql instanceof TCreateTableSqlStatement) {
564            TCreateTableSqlStatement c = (TCreateTableSqlStatement) psql;
565
566            switch (this.createTableOptionType){
567                case etoPartitionBy:
568                    if (this.partitionColumnList != null){
569                        c.setPartitionColumnList(this.partitionColumnList);
570                    }else if (this.partitionByExpr != null){
571                        c.setPartitionByExpr(this.partitionByExpr);
572                        this.partitionByExpr.doParse(c,ESqlClause.createTable);
573                    }
574                    break;
575                case etoPattern:
576                    c.setRegex_pattern(this.getEndToken().toString());
577                    break;
578                case etoComment:
579                    c.setTableComment(TObjectName.createObjectName (psql.dbvendor, EDbObjectType.comment, this.commentToken));
580                    break;
581                case etoWithLocation:
582                    c.setStageLocation(this.getStageLocation());
583                    break;
584                case etoFileFormat:
585                    c.setFileFormatName(this.fileFormatName);
586                    c.setFileFormatType(this.fileFormatType);
587                    break;
588                case etoAWSSnsTopic:
589                    c.setAwsSnsTopic(this.awsSnsTopic);
590                    break;
591                case etoBigQueryExternal:
592                    parseBigQueryTableOption();
593                    break;
594                case etoClusterBy:
595                    if (expressionList != null){
596                        expressionList.doParse(psql,plocation);
597                    }
598                    break;
599                default:
600                    break;
601
602            }
603        }else if(psql instanceof TCreateStageStmt){
604            TCreateStageStmt c = (TCreateStageStmt)psql;
605            switch (this.createTableOptionType){
606                case etoFileFormat:
607                    c.setFileFormatName(this.fileFormatName);
608                    c.setFileFormatType(this.fileFormatType);
609                    break;
610                case etoStageURL:
611                    c.setExternalStageURL(this.externalStageURL);
612                    break;
613                default:
614                    break;
615            }
616        }else if(psql instanceof TSnowflakeCopyIntoStmt){
617            TSnowflakeCopyIntoStmt c = (TSnowflakeCopyIntoStmt)psql;
618            switch (this.createTableOptionType){
619                case etoFileFormat:
620                    c.setFileFormatName(this.fileFormatName);
621                    c.setFileFormatType(this.fileFormatType);
622                    break;
623                case etoStageURL:
624                    break;
625                case etoPattern:
626                    c.setRegex_pattern(this.getEndToken().toString());
627                    break;
628                case etoFiles:
629                    for(TExpression e:this.expressionList){
630                        c.getFileList().add(e.toString());
631                    }
632                    break;
633                default:
634                    break;
635            }
636        }
637    }
638
639    public void accept(TParseTreeVisitor v){
640        v.preVisit(this);
641        v.postVisit(this);
642    }
643    public void acceptChildren(TParseTreeVisitor v){
644        v.preVisit(this);
645        v.postVisit(this);
646    }
647}