001package gudusoft.gsqlparser.nodes;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement;
005
006/**
007 * Use a constraint to define an integrity constraint, a rule that restricts the values in a database.
008 * <p>Oracle Database lets you create six types of constraints and lets you declare them in two ways.
009 * <ul>
010 * <li>A NOT NULL constraint prohibits a database value from being null.</li>
011 * <li>A unique constraint prohibits multiple rows from having the same value in the same column or combination of columns but allows some values to be null.
012 * call method {@link #getColumnList()} to result columns of this unique key.
013 * </li>
014 * <li>A primary key constraint combines a NOT NULL constraint and a unique
015 * constraint in a single declaration. It prohibits multiple rows from having the same
016 * value in the same column or combination of columns and prohibits values from being null.
017 * call method {@link #getColumnList()} to result columns of this primary key.
018 * </li>
019 * <li>A foreign key constraint requires values in one table to match values in another table.
020 * call method {@link #getColumnList()} to result columns of this foreign key.
021 * </li>
022 * <li>A check constraint requires a value in the database to comply with a specified condition.
023 * call method {@link #getCheckCondition()} to return this condition.
024 * </li>
025 * <li>A REF column by definition references an object in another object type or in a relational table.
026 * A REF constraint lets you further describe the relationship between the REF column and the object it references.
027 </li>
028 * <li>default constraint is valid in sql server.</li>
029 * </ul>
030 *
031 * @see EConstraintType#notnull
032 * @see EConstraintType#unique
033 * @see EConstraintType#primary_key
034 * @see EConstraintType#foreign_key
035 * @see EConstraintType#check
036 * @see EConstraintType#reference
037 * @see EConstraintType#default_value
038 */
039
040public class TConstraint extends TParseTreeNode {
041
042    private TColumnGeneratedClause columnGeneratedClause;
043
044    public void setColumnGeneratedClause(TColumnGeneratedClause columnGeneratedClause) {
045        this.columnGeneratedClause = columnGeneratedClause;
046    }
047
048    public TColumnGeneratedClause getColumnGeneratedClause() {
049        return columnGeneratedClause;
050    }
051
052    public void setOnFilegroup(TDummy onFilegroup) {
053        this.onFilegroup = onFilegroup;
054    }
055
056    public TDummy getOnFilegroup() {
057        return onFilegroup;
058    }
059
060    private TDummy onFilegroup = null;
061
062    private TDummy withIndexoption = null;
063
064    public void setWithIndexoption(TDummy withIndexoption) {
065        this.withIndexoption = withIndexoption;
066    }
067
068    public TDummy getWithIndexoption() {
069        return withIndexoption;
070    }
071
072    private TObjectName indexName;
073
074    /**
075     * SQL Server, index name of table index when {@link #getConstraint_type} is {@link EConstraintType#table_index}
076     * or index name of column index when {@link #getConstraint_type} is {@link EConstraintType#column_index}
077     *
078     * @return index name
079     */
080    public TObjectName getIndexName() {
081        return indexName;
082    }
083
084    private EConstraintType constraint_type;
085    private TObjectName constraintName = null;
086    private  TPTNodeList <TKeyAction> keyActions;
087
088    private TObjectName commentObject;
089
090    public void setCommentObject(TObjectName commentObject) {
091        this.commentObject = commentObject;
092    }
093
094    private TObjectName forObjectName;
095
096    public void setForObjectName(TObjectName forObjectName) {
097        this.forObjectName = forObjectName;
098    }
099
100    public TObjectName getForObjectName() {
101        return forObjectName;
102    }
103
104    public TObjectName getCommentObject() {
105
106        return commentObject;
107    }
108
109    public void setKeyActions(TPTNodeList<TKeyAction> keyActions) {
110        this.keyActions = keyActions;
111    }
112
113    public TPTNodeList<TKeyAction> getKeyActions() {
114
115        return keyActions;
116    }
117
118    public void setConstraintLevel(int constraintLevel) {
119        this.constraintLevel = constraintLevel;
120    }
121
122    /**
123     *
124     * @return is this a columnn level constraint or table level constraint
125     * TBaseType.constraint_level_table or TBaseType.constraint_level_column.
126
127     */
128    public int getConstraintLevel() {
129        return constraintLevel;
130    }
131
132    private int constraintLevel = TBaseType.constraint_level_table;
133
134    private TExpression defaultExpression = null;
135
136    public void setDefaultExpression(TExpression defaultExpression) {
137        this.defaultExpression = defaultExpression;
138    }
139
140    /**
141     *
142     * @return default expression of sql server.
143     */
144    public TExpression getDefaultExpression() {
145
146        return defaultExpression;
147    }
148
149    public void setConstraintName(TObjectName constraintName) {
150        this.constraintName = constraintName;
151    }
152
153    /**
154     *
155     * @return name for the constraint, it's optional.
156     */
157    public TObjectName getConstraintName() {
158
159        return constraintName;
160    }
161
162    public void setConstraint_type(EConstraintType constraint_type) {
163        this.constraint_type = constraint_type;
164    }
165
166    /**
167     * 
168     * @return type of constraints.
169     * @see EConstraintType#notnull
170     * @see EConstraintType#unique
171     * @see EConstraintType#primary_key
172     * @see EConstraintType#foreign_key
173     * @see EConstraintType#check
174     * @see EConstraintType#reference
175     * @see EConstraintType#default_value
176     */
177    public EConstraintType getConstraint_type() {
178
179        return constraint_type;
180    }
181
182    public void setClustered(boolean clustered) {
183        this.clustered = clustered;
184    }
185
186    public void setClusteredToken(TSourceToken clusteredToken)
187    {
188        if (clusteredToken == null) return;
189        if (clusteredToken.toString().equalsIgnoreCase("clustered")){
190            clustered = true;
191        }else if (clusteredToken.toString().equalsIgnoreCase("nonclustered")){
192            nonClustered = true;
193        }
194    }
195
196    public boolean isClustered() {
197
198        return clustered;
199    }
200
201    private boolean clustered = false;
202    private boolean nonClustered = false;
203    private boolean notEnforced = false;
204
205    public boolean isNonClustered() {
206        return nonClustered;
207    }
208
209    public void setNonClustered(boolean nonClustered) {
210
211        this.nonClustered = nonClustered;
212    }
213
214    /**
215     * Flink SQL: Returns true if the constraint has the NOT ENFORCED modifier.
216     * <p>Flink SQL only supports NOT ENFORCED mode for PRIMARY KEY constraints,
217     * as Flink does not own the data and cannot enforce constraints.</p>
218     *
219     * @return true if NOT ENFORCED was specified, false otherwise
220     */
221    public boolean isNotEnforced() {
222        return notEnforced;
223    }
224
225    /**
226     * Sets the NOT ENFORCED modifier for this constraint.
227     *
228     * @param notEnforced true if NOT ENFORCED is specified
229     */
230    public void setNotEnforced(boolean notEnforced) {
231        this.notEnforced = notEnforced;
232    }
233
234    private TPTNodeList<TColumnWithSortOrder> columnList = null;
235    private TExpression checkCondition = null;
236    private TPTNodeList <TAutomaticProperty>  automaticProperties = null;
237
238    public void setAutomaticProperties(TPTNodeList<TAutomaticProperty> automaticProperties) {
239        this.automaticProperties = automaticProperties;
240    }
241
242    /**
243     *
244     * @return    Automatic Initialization and Updating for TIMESTAMP in MySQL
245     */
246    public TPTNodeList<TAutomaticProperty> getAutomaticProperties() {
247
248        return automaticProperties;
249    }
250
251    /**
252     * 
253     * @return   used in check constraint, requires a value in the database to comply with this specified condition.
254     */
255    public TExpression getCheckCondition() {
256        return checkCondition;
257    }
258
259    /**
260     *
261     * @return column name list used when constraint type is unique, primary key or foreign key.
262     */
263    public TPTNodeList<TColumnWithSortOrder> getColumnList() {
264        return columnList;
265    }
266
267    public void setColumnList(TPTNodeList<TColumnWithSortOrder> columnList) {
268        this.columnList = columnList;
269    }
270
271    private TPTNodeList <TIndexColName> indexCols;
272
273    /**
274     * @deprecated since 1.8.7.2, use {@link #getColumnList()} instead.
275     * @return
276     */
277    public TPTNodeList<TIndexColName> getIndexCols() {
278        return indexCols;
279    }
280
281
282    public void init(Object arg1){
283        if (arg1 instanceof TExpression){
284            this.checkCondition = (TExpression)arg1;
285        }else if (arg1 instanceof TPTNodeList){
286           this.columnList = (TPTNodeList<TColumnWithSortOrder>)arg1;
287        }else if (arg1 instanceof TObjectNameList){
288            // column in TObjectNameList not changed to TPTNodeList<TColumnWithSortOrder> in .y file
289            // so we convert it here
290            this.columnList = new TPTNodeList<TColumnWithSortOrder>();
291            TObjectNameList onl = (TObjectNameList)arg1;
292            for(int i=0;i<onl.size();i++){
293                this.columnList.addElement(new TColumnWithSortOrder(onl.getObjectName(i)));
294            }
295//            indexCols = (TPTNodeList)arg1;
296        }
297    }
298
299    private TObjectName indexColumnName = null;
300
301
302    /**
303     * Snowflake index table constraint: CREATE TABLE t1 (c1 INT, c2 INT, CONSTRAINT c1_idx INDEX (c1));
304     * @return
305     */
306    public TObjectName getIndexColumnName() {
307        return indexColumnName;
308    }
309
310    public void init(Object arg1, Object arg2,Object arg3){
311        init(arg1,arg2);
312        switch (constraint_type){
313            case table_index:
314                indexColumnName = (TObjectName)arg3;
315                indexColumnName.setDbObjectType(EDbObjectType.column);
316                break;
317            default:
318                break;
319        }
320    }
321
322    public void init(Object arg1, Object arg2){
323        constraint_type = (EConstraintType)arg1;
324        switch (constraint_type){
325            case table_index:
326                indexName = (TObjectName)arg2;
327                indexName.setDbObjectType(EDbObjectType.index);
328                break;
329            case cluster:
330                break;
331            case default_value:
332                this.defaultExpression = (TExpression) arg2;
333                break;
334            default:
335                break;
336        }
337    }
338
339    private TObjectName referencedObject = null;
340
341    // Vertica CORRELATION constraint fields
342    private TObjectNameList determinesColumnList = null;
343    private TExpression strengthValue = null;
344
345    /**
346     * Vertica CORRELATION constraint: columns that are determined by the correlation columns.
347     * Syntax: CONSTRAINT name CORRELATION (col1) DETERMINES (col2) STRENGTH 0.95
348     * @return the DETERMINES column list
349     */
350    public TObjectNameList getDeterminesColumnList() {
351        return determinesColumnList;
352    }
353
354    public void setDeterminesColumnList(TObjectNameList determinesColumnList) {
355        this.determinesColumnList = determinesColumnList;
356    }
357
358    /**
359     * Vertica CORRELATION constraint: the strength value indicating correlation coefficient.
360     * @return the STRENGTH value expression
361     */
362    public TExpression getStrengthValue() {
363        return strengthValue;
364    }
365
366    public void setStrengthValue(TExpression strengthValue) {
367        this.strengthValue = strengthValue;
368    }
369
370    public void setReferencedColumnList(TObjectNameList referencedColumnList) {
371        this.referencedColumnList = referencedColumnList;
372    }
373
374    /**
375     * 
376     * @return column name list of referenced object in reference clause when constraint type is REF constraint.
377     */
378    public TObjectNameList getReferencedColumnList() {
379
380        return referencedColumnList;
381    }
382
383    private TObjectNameList referencedColumnList = null;
384
385
386    public void setReferencedObject(TObjectName referencedObject) {
387        this.referencedObject = referencedObject;
388    }
389
390    /**
391     *
392     * @return referenced object in reference clause when constraint type is REF constraint.
393     */
394    public TObjectName getReferencedObject() {
395
396        return referencedObject;
397    }
398
399    private TExpression seed;
400
401    public void setIncrement(TExpression increment) {
402        this.increment = increment;
403    }
404
405    public void setSeed(TExpression seed) {
406        this.seed = seed;
407    }
408
409    /**
410     * Used internal
411     * @return
412     */
413    public TExpression getIncrement() {
414
415        return increment;
416    }
417
418    /**
419     * Used internal
420     * @return
421     */
422    public TExpression getSeed() {
423        return seed;
424    }
425
426    private TExpression increment;
427
428    public void accept(TParseTreeVisitor v){
429        v.preVisit(this);
430        v.postVisit(this);
431    }
432
433    public void acceptChildren(TParseTreeVisitor v){
434        v.preVisit(this);
435        v.postVisit(this);
436    }
437
438    public void doParse(TCustomSqlStatement psql, ESqlClause plocation){
439        switch (getConstraint_type()){
440            case primary_key:
441            case unique:
442                if (getColumnList() != null){
443                    for(int i=0;i<getColumnList().size();i++){
444                        TColumnWithSortOrder colWithSort = getColumnList().getElement(i);
445                        colWithSort.setOwnerConstraint(this);
446                        if (psql instanceof TCreateTableSqlStatement){
447                            colWithSort.setOwnerTable(psql.tables.getTable(0));
448                            // For functional indexes, getColumnName() returns null (use getExpression() instead)
449                            if (colWithSort.getColumnName() != null) {
450                                psql.tables.getTable(0).getLinkedColumns().addObjectName(colWithSort.getColumnName());
451                                colWithSort.getColumnName().setSourceTable(psql.tables.getTable(0));
452                            }
453                        }
454                        psql.getIndexColumns().addElement(colWithSort);
455                    }
456                }
457                break;
458            case correlation:
459                // Vertica CORRELATION constraint: link both CORRELATION and DETERMINES columns to the table
460                if (getColumnList() != null){
461                    for(int i=0;i<getColumnList().size();i++){
462                        TColumnWithSortOrder colWithSort = getColumnList().getElement(i);
463                        colWithSort.setOwnerConstraint(this);
464                        if (psql instanceof TCreateTableSqlStatement){
465                            colWithSort.setOwnerTable(psql.tables.getTable(0));
466                            if (colWithSort.getColumnName() != null) {
467                                psql.tables.getTable(0).getLinkedColumns().addObjectName(colWithSort.getColumnName());
468                                colWithSort.getColumnName().setSourceTable(psql.tables.getTable(0));
469                            }
470                        }
471                    }
472                }
473                if (getDeterminesColumnList() != null){
474                    for(int i=0;i<getDeterminesColumnList().size();i++){
475                        TObjectName colName = getDeterminesColumnList().getObjectName(i);
476                        if (psql instanceof TCreateTableSqlStatement){
477                            psql.tables.getTable(0).getLinkedColumns().addObjectName(colName);
478                            colName.setSourceTable(psql.tables.getTable(0));
479                        }
480                    }
481                }
482                break;
483            case foreign_key:
484            case reference:{
485                if (getColumnList() != null){
486                    for(int i=0;i<getColumnList().size();i++){
487                        TColumnWithSortOrder colWithSort = getColumnList().getElement(i);
488                        colWithSort.setOwnerConstraint(this);
489                        if (psql instanceof TCreateTableSqlStatement){
490                            colWithSort.setOwnerTable(psql.tables.getTable(0));
491                        }
492                        psql.getIndexColumns().addElement(colWithSort);
493                    }
494                }
495
496                TTable lcTable = null;
497                if (referencedObject != null){
498                    referencedObject.setObjectType(TObjectName.ttobjTable);
499
500                    lcTable = new TTable(referencedObject);
501                    lcTable.setPropertyFromObjectName(referencedObject,ETableEffectType.tetConstraintReference);
502//                    lcTable.setStartToken(referencedObject.getStartToken());
503//                    lcTable.setEndToken(referencedObject.getEndToken());
504//                    lcTable.setGsqlparser(referencedObject.getGsqlparser());
505//                    lcTable.setEffectType(ETableEffectType.tetConstraintReference);
506//                    lcTable.setTableType(ETableSource.objectname);
507                    psql.addToTables(lcTable);
508                }
509                if (referencedColumnList!=null){
510                    for(int i=0;i<referencedColumnList.size();i++){
511                        referencedColumnList.getObjectName(i).setLocation(ESqlClause.constraintRef);
512                        lcTable.getLinkedColumns().addObjectName(referencedColumnList.getObjectName(i));
513                    }
514                }
515            };
516            break;
517            case check:
518                if ((checkCondition != null) &&(checkCondition.getBetweenOperand() == null)){
519                    // missing between operand in sql like this in teradata:
520                    // CREATE TABLE tab1 (Id CHAR(9) ,SalaryFactor DOUBLE PRECISION BETWEEN .1 AND 1E1 );
521
522                    // System.out.println(checkCondition.toString());
523                }
524                break;
525            default:;
526        }
527    }
528
529    public void setCheckCondition(TExpression checkCondition) {
530        this.checkCondition = checkCondition;
531    }
532
533    public void setIndexCols(TPTNodeList<TIndexColName> indexCols) {
534        this.indexCols = indexCols;
535    }
536}