diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/BaseSemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/BaseSemanticAnalyzer.java index 59130cadd4..070696b0f3 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/BaseSemanticAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/BaseSemanticAnalyzer.java @@ -1065,9 +1065,14 @@ else if(child.getToken().getType() == HiveParser.TOK_CHECK_CONSTRAINT) { + "Please use NOVALIDATE instead.")); } - for (String columnName : columnNames) { - cstrInfos.add(new ConstraintInfo(columnName, constraintName, - enable, validate, rely, checkOrDefaultValue)); + if(columnNames == null) { + cstrInfos.add(new ConstraintInfo(null, constraintName, + enable, validate, rely, checkOrDefaultValue)); + } else { + for (String columnName : columnNames) { + cstrInfos.add(new ConstraintInfo(columnName, constraintName, + enable, validate, rely, checkOrDefaultValue)); + } } } diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java index 49a3464776..df0ca1b358 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java @@ -2165,6 +2165,7 @@ private void analyzeAlterTableAddConstraint(ASTNode ast, String tableName) List primaryKeys = new ArrayList<>(); List foreignKeys = new ArrayList<>(); List uniqueConstraints = new ArrayList<>(); + List checkConstraints = new ArrayList<>(); switch (child.getToken().getType()) { case HiveParser.TOK_UNIQUE: @@ -2179,12 +2180,17 @@ private void analyzeAlterTableAddConstraint(ASTNode ast, String tableName) BaseSemanticAnalyzer.processForeignKeys(qualifiedTabName[0], qualifiedTabName[1], child, foreignKeys); break; + case HiveParser.TOK_CHECK_CONSTRAINT: + BaseSemanticAnalyzer.processCheckConstraints(catName, qualifiedTabName[0], qualifiedTabName[1], + child, null,checkConstraints, child, + this.ctx.getTokenRewriteStream()); + break; default: throw new SemanticException(ErrorMsg.NOT_RECOGNIZED_CONSTRAINT.getMsg( child.getToken().getText())); } AlterTableDesc alterTblDesc = new AlterTableDesc(tableName, primaryKeys, foreignKeys, - uniqueConstraints, null); + uniqueConstraints, null, null, checkConstraints, null); rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(), alterTblDesc))); diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g b/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g index 925783b499..18cddfed54 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g @@ -2220,8 +2220,24 @@ createConstraint alterConstraintWithName @init { pushMsg("pk or uk or nn constraint with name", state); } @after { popMsg(state); } - : KW_CONSTRAINT constraintName=identifier tableConstraintType pkCols=columnParenthesesList constraintOptsAlter? - -> ^(tableConstraintType $pkCols ^(TOK_CONSTRAINT_NAME $constraintName) constraintOptsAlter?) + : KW_CONSTRAINT constraintName=identifier (alterPkUkConstraint | checkConstraint)constraintOptsAlter? + -> {$alterPkUkConstraint.tree != null}? + ^({$alterPkUkConstraint.tree} ^(TOK_CONSTRAINT_NAME $constraintName) constraintOptsAlter?) + ->^({$checkConstraint.tree} ^(TOK_CONSTRAINT_NAME $constraintName) constraintOptsAlter?) + ; + +alterPkUkConstraint +@init { pushMsg("pk or uk table level constraint", state); } +@after { popMsg(state); } + : tableConstraintType pkCols=columnParenthesesList + -> ^(tableConstraintType $pkCols) + ; + +checkConstraint +@init { pushMsg("CHECK constraint", state); } +@after { popMsg(state); } + : KW_CHECK expression + -> ^(TOK_CHECK_CONSTRAINT expression) ; createForeignKey @@ -2426,7 +2442,7 @@ alterColConstraint columnConstraintType : KW_NOT KW_NULL -> TOK_NOT_NULL | KW_DEFAULT defaultVal-> ^(TOK_DEFAULT_VALUE defaultVal) - | KW_CHECK expression -> ^(TOK_CHECK_CONSTRAINT expression) + | checkConstraint | tableConstraintType ; diff --git a/ql/src/test/queries/clientpositive/check_constraint.q b/ql/src/test/queries/clientpositive/check_constraint.q index c758cd438b..896fb98b85 100644 --- a/ql/src/test/queries/clientpositive/check_constraint.q +++ b/ql/src/test/queries/clientpositive/check_constraint.q @@ -37,6 +37,15 @@ DESC formatted tmulti; EXPLAIN INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018'); INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018'); Select * from tmulti; + +-- alter table add constraint +truncate table tmulti; +alter table tmulti add constraint chk1 CHECK (userName != NULL); +alter table tmulti add constraint chk2 CHECK (numClicks <= 10000 AND userName != ''); +DESC formatted tmulti; +EXPLAIN INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018'); +INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018'); +Select * from tmulti; Drop table tmulti; -- case insentivity diff --git a/ql/src/test/results/clientpositive/llap/check_constraint.q.out b/ql/src/test/results/clientpositive/llap/check_constraint.q.out index dd352737f4..6226f95c28 100644 --- a/ql/src/test/results/clientpositive/llap/check_constraint.q.out +++ b/ql/src/test/results/clientpositive/llap/check_constraint.q.out @@ -518,6 +518,164 @@ STAGE PLANS: serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe name: default.tmulti +PREHOOK: query: INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018') +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +PREHOOK: Output: default@tmulti +POSTHOOK: query: INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018') +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +POSTHOOK: Output: default@tmulti +POSTHOOK: Lineage: tmulti.d SCRIPT [] +POSTHOOK: Lineage: tmulti.numclicks SCRIPT [] +POSTHOOK: Lineage: tmulti.url SCRIPT [] +POSTHOOK: Lineage: tmulti.username SCRIPT [] +PREHOOK: query: Select * from tmulti +PREHOOK: type: QUERY +PREHOOK: Input: default@tmulti +#### A masked pattern was here #### +POSTHOOK: query: Select * from tmulti +POSTHOOK: type: QUERY +POSTHOOK: Input: default@tmulti +#### A masked pattern was here #### +hive.apache.com user1 48 NULL +PREHOOK: query: truncate table tmulti +PREHOOK: type: TRUNCATETABLE +PREHOOK: Output: default@tmulti +POSTHOOK: query: truncate table tmulti +POSTHOOK: type: TRUNCATETABLE +POSTHOOK: Output: default@tmulti +PREHOOK: query: alter table tmulti add constraint chk1 CHECK (userName != NULL) +PREHOOK: type: ALTERTABLE_ADDCONSTRAINT +POSTHOOK: query: alter table tmulti add constraint chk1 CHECK (userName != NULL) +POSTHOOK: type: ALTERTABLE_ADDCONSTRAINT +PREHOOK: query: alter table tmulti add constraint chk2 CHECK (numClicks <= 10000 AND userName != '') +PREHOOK: type: ALTERTABLE_ADDCONSTRAINT +POSTHOOK: query: alter table tmulti add constraint chk2 CHECK (numClicks <= 10000 AND userName != '') +POSTHOOK: type: ALTERTABLE_ADDCONSTRAINT +PREHOOK: query: DESC formatted tmulti +PREHOOK: type: DESCTABLE +PREHOOK: Input: default@tmulti +POSTHOOK: query: DESC formatted tmulti +POSTHOOK: type: DESCTABLE +POSTHOOK: Input: default@tmulti +# col_name data_type comment +url string +username string +numclicks int +d date + +# Detailed Table Information +Database: default +#### A masked pattern was here #### +Retention: 0 +#### A masked pattern was here #### +Table Type: MANAGED_TABLE +Table Parameters: + COLUMN_STATS_ACCURATE {\"BASIC_STATS\":\"true\"} + numFiles 0 + totalSize 0 +#### A masked pattern was here #### + +# Storage Information +SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe +InputFormat: org.apache.hadoop.mapred.TextInputFormat +OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat +Compressed: No +Num Buckets: -1 +Bucket Columns: [] +Sort Columns: [] +Storage Desc Params: + serialization.format 1 + +# Constraints + +# Unique Constraints +Table: default.tmulti +Constraint Name: un1 +Column Name:username Key Sequence:1 +Column Name:numclicks Key Sequence:2 + + +# Not Null Constraints +Table: default.tmulti +Constraint Name: #### A masked pattern was here #### +Column Name: url + + +# Check Constraints +Table: default.tmulti +Constraint Name: chk1 +Column Name:null Check Value:(userName != NULL) + +Constraint Name: chk2 +Column Name:null Check Value:(numClicks <= 10000 AND userName != '') + +Constraint Name: #### A masked pattern was here #### +Column Name:numclicks Check Value:numClicks > 0 + +PREHOOK: query: EXPLAIN INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018') +PREHOOK: type: QUERY +POSTHOOK: query: EXPLAIN INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018') +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-1 is a root stage + Stage-2 depends on stages: Stage-1 + Stage-0 depends on stages: Stage-2 + +STAGE PLANS: + Stage: Stage-1 + Tez +#### A masked pattern was here #### + Vertices: + Map 1 + Map Operator Tree: + TableScan + alias: _dummy_table + Row Limit Per Split: 1 + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: COMPLETE + Select Operator + expressions: array(const struct('hive.apache.com','user1',48,'12-01-2018')) (type: array>) + outputColumnNames: _col0 + Statistics: Num rows: 1 Data size: 48 Basic stats: COMPLETE Column stats: COMPLETE + UDTF Operator + Statistics: Num rows: 1 Data size: 48 Basic stats: COMPLETE Column stats: COMPLETE + function name: inline + Select Operator + expressions: col1 (type: string), col2 (type: string), col3 (type: int), col4 (type: string) + outputColumnNames: _col0, _col1, _col2, _col3 + Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE + Filter Operator + predicate: enforce_constraint((_col0 is not null and (((_col2 > 0) is not false and (_col1 <> null) is not false) and ((_col2 <= 10000) and (_col1 <> '')) is not false))) (type: boolean) + Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE + Select Operator + expressions: _col0 (type: string), _col1 (type: string), _col2 (type: int), CAST( _col3 AS DATE) (type: date) + outputColumnNames: _col0, _col1, _col2, _col3 + Statistics: Num rows: 1 Data size: 56 Basic stats: COMPLETE Column stats: COMPLETE + File Output Operator + compressed: false + Statistics: Num rows: 1 Data size: 56 Basic stats: COMPLETE Column stats: COMPLETE + table: + input format: org.apache.hadoop.mapred.TextInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + name: default.tmulti + Execution mode: llap + LLAP IO: no inputs + + Stage: Stage-2 + Dependency Collection + + Stage: Stage-0 + Move Operator + tables: + replace: false + table: + input format: org.apache.hadoop.mapred.TextInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + name: default.tmulti + PREHOOK: query: INSERT INTO tmulti values('hive.apache.com', 'user1', 48, '12-01-2018') PREHOOK: type: QUERY PREHOOK: Input: _dummy_database@_dummy_table diff --git a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java index c5da7b5d34..75d2dc5f13 100644 --- a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java +++ b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java @@ -4703,7 +4703,8 @@ private static String generateColNameTypeSignature(String colName, String colTyp final String catName = normalizeIdentifier(cc.get(i).getCatName()); final String tableDB = normalizeIdentifier(cc.get(i).getTable_db()); final String tableName = normalizeIdentifier(cc.get(i).getTable_name()); - final String columnName = normalizeIdentifier(cc.get(i).getColumn_name()); + final String columnName = cc.get(i).getColumn_name() == null? null + : normalizeIdentifier(cc.get(i).getColumn_name()); final String ccName = cc.get(i).getDc_name(); boolean isEnable = cc.get(i).isEnable_cstr(); boolean isValidate = cc.get(i).isValidate_cstr(); @@ -4737,9 +4738,6 @@ private void addConstraint(String catName, String tableDB, String tableName, Str parentCD = null; parentIntegerIndex = getColumnIndexFromTableColumns(parentTable.getPartitionKeys(), columnName); } - if (parentIntegerIndex == -1) { - throw new InvalidObjectException("Parent column not found: " + columnName); - } } if (ccName == null) { constraintName = generateConstraintName(tableDB, tableName, columnName, "dc"); diff --git a/standalone-metastore/src/main/sql/derby/hive-schema-3.0.0.derby.sql b/standalone-metastore/src/main/sql/derby/hive-schema-3.0.0.derby.sql index 240a282f17..adfa4c596e 100644 --- a/standalone-metastore/src/main/sql/derby/hive-schema-3.0.0.derby.sql +++ b/standalone-metastore/src/main/sql/derby/hive-schema-3.0.0.derby.sql @@ -178,7 +178,7 @@ CREATE TABLE "APP"."NOTIFICATION_LOG" ( CREATE TABLE "APP"."NOTIFICATION_SEQUENCE" ("NNI_ID" BIGINT NOT NULL, "NEXT_EVENT_ID" BIGINT NOT NULL); -CREATE TABLE "APP"."KEY_CONSTRAINTS" ("CHILD_CD_ID" BIGINT, "CHILD_INTEGER_IDX" INTEGER, "CHILD_TBL_ID" BIGINT, "PARENT_CD_ID" BIGINT NOT NULL, "PARENT_INTEGER_IDX" INTEGER, "PARENT_TBL_ID" BIGINT NOT NULL, "POSITION" BIGINT NOT NULL, "CONSTRAINT_NAME" VARCHAR(400) NOT NULL, "CONSTRAINT_TYPE" SMALLINT NOT NULL, "UPDATE_RULE" SMALLINT, "DELETE_RULE" SMALLINT, "ENABLE_VALIDATE_RELY" SMALLINT NOT NULL, "DEFAULT_VALUE" VARCHAR(400)); +CREATE TABLE "APP"."KEY_CONSTRAINTS" ("CHILD_CD_ID" BIGINT, "CHILD_INTEGER_IDX" INTEGER, "CHILD_TBL_ID" BIGINT, "PARENT_CD_ID" BIGINT , "PARENT_INTEGER_IDX" INTEGER, "PARENT_TBL_ID" BIGINT NOT NULL, "POSITION" BIGINT NOT NULL, "CONSTRAINT_NAME" VARCHAR(400) NOT NULL, "CONSTRAINT_TYPE" SMALLINT NOT NULL, "UPDATE_RULE" SMALLINT, "DELETE_RULE" SMALLINT, "ENABLE_VALIDATE_RELY" SMALLINT NOT NULL, "DEFAULT_VALUE" VARCHAR(400)); CREATE TABLE "APP"."METASTORE_DB_PROPERTIES" ("PROPERTY_KEY" VARCHAR(255) NOT NULL, "PROPERTY_VALUE" VARCHAR(1000) NOT NULL, "DESCRIPTION" VARCHAR(1000)); diff --git a/standalone-metastore/src/main/sql/mssql/hive-schema-3.0.0.mssql.sql b/standalone-metastore/src/main/sql/mssql/hive-schema-3.0.0.mssql.sql index e15fc2e31c..91c581c22f 100644 --- a/standalone-metastore/src/main/sql/mssql/hive-schema-3.0.0.mssql.sql +++ b/standalone-metastore/src/main/sql/mssql/hive-schema-3.0.0.mssql.sql @@ -1118,7 +1118,7 @@ CREATE TABLE KEY_CONSTRAINTS CHILD_CD_ID BIGINT, CHILD_INTEGER_IDX INT, CHILD_TBL_ID BIGINT, - PARENT_CD_ID BIGINT NOT NULL, + PARENT_CD_ID BIGINT, PARENT_INTEGER_IDX INT NOT NULL, PARENT_TBL_ID BIGINT NOT NULL, POSITION INT NOT NULL, diff --git a/standalone-metastore/src/main/sql/mysql/hive-schema-3.0.0.mysql.sql b/standalone-metastore/src/main/sql/mysql/hive-schema-3.0.0.mysql.sql index f9efd56833..7e2a57a70c 100644 --- a/standalone-metastore/src/main/sql/mysql/hive-schema-3.0.0.mysql.sql +++ b/standalone-metastore/src/main/sql/mysql/hive-schema-3.0.0.mysql.sql @@ -872,7 +872,7 @@ CREATE TABLE IF NOT EXISTS `KEY_CONSTRAINTS` `CHILD_CD_ID` BIGINT, `CHILD_INTEGER_IDX` INT(11), `CHILD_TBL_ID` BIGINT, - `PARENT_CD_ID` BIGINT NOT NULL, + `PARENT_CD_ID` BIGINT, `PARENT_INTEGER_IDX` INT(11) NOT NULL, `PARENT_TBL_ID` BIGINT NOT NULL, `POSITION` BIGINT NOT NULL, diff --git a/standalone-metastore/src/main/sql/oracle/hive-schema-3.0.0.oracle.sql b/standalone-metastore/src/main/sql/oracle/hive-schema-3.0.0.oracle.sql index a87e4464d5..42a972fad0 100644 --- a/standalone-metastore/src/main/sql/oracle/hive-schema-3.0.0.oracle.sql +++ b/standalone-metastore/src/main/sql/oracle/hive-schema-3.0.0.oracle.sql @@ -885,7 +885,7 @@ CREATE TABLE KEY_CONSTRAINTS CHILD_CD_ID NUMBER, CHILD_INTEGER_IDX NUMBER, CHILD_TBL_ID NUMBER, - PARENT_CD_ID NUMBER NOT NULL, + PARENT_CD_ID NUMBER, PARENT_INTEGER_IDX NUMBER NOT NULL, PARENT_TBL_ID NUMBER NOT NULL, POSITION NUMBER NOT NULL, diff --git a/standalone-metastore/src/main/sql/postgres/hive-schema-3.0.0.postgres.sql b/standalone-metastore/src/main/sql/postgres/hive-schema-3.0.0.postgres.sql index 07dd83d747..6fed0722b1 100644 --- a/standalone-metastore/src/main/sql/postgres/hive-schema-3.0.0.postgres.sql +++ b/standalone-metastore/src/main/sql/postgres/hive-schema-3.0.0.postgres.sql @@ -633,7 +633,7 @@ CREATE TABLE "KEY_CONSTRAINTS" "CHILD_CD_ID" BIGINT, "CHILD_INTEGER_IDX" BIGINT, "CHILD_TBL_ID" BIGINT, - "PARENT_CD_ID" BIGINT NOT NULL, + "PARENT_CD_ID" BIGINT, "PARENT_INTEGER_IDX" BIGINT NOT NULL, "PARENT_TBL_ID" BIGINT NOT NULL, "POSITION" BIGINT NOT NULL,