Skip to content

Commit

Permalink
HIVE-1078. CREATE VIEW followup: CREATE OR REPLACE (Charles Chen via …
Browse files Browse the repository at this point in the history
…jvs)

git-svn-id: https://svn.apache.org/repos/asf/hive/trunk@1149727 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
John Sichi committed Jul 22, 2011
1 parent cb2cf8f commit 7366a5d
Show file tree
Hide file tree
Showing 27 changed files with 919 additions and 168 deletions.
Expand Up @@ -30,9 +30,9 @@
import org.apache.hadoop.hive.metastore.api.InvalidObjectException;
import org.apache.hadoop.hive.metastore.api.InvalidOperationException;
import org.apache.hadoop.hive.metastore.api.MetaException;
import org.apache.hadoop.hive.metastore.api.NoSuchObjectException;
import org.apache.hadoop.hive.metastore.api.Partition;
import org.apache.hadoop.hive.metastore.api.Table;
import org.apache.hadoop.hive.metastore.api.NoSuchObjectException;

/**
* Hive specific implementation of alter
Expand Down Expand Up @@ -97,11 +97,13 @@ public void alterTable(RawStore msdb, Warehouse wh, String dbname,
+ newt.getTableName() + " doesn't exist");
}

// check that partition keys have not changed
if (oldt.getPartitionKeys().size() != newt.getPartitionKeys().size()
|| !oldt.getPartitionKeys().containsAll(newt.getPartitionKeys())) {
throw new InvalidOperationException(
"partition keys can not be changed.");
// check that partition keys have not changed, except for virtual views
if(!oldt.getTableType().equals(TableType.VIRTUAL_VIEW.toString())){
if (oldt.getPartitionKeys().size() != newt.getPartitionKeys().size()
|| !oldt.getPartitionKeys().containsAll(newt.getPartitionKeys())) {
throw new InvalidOperationException(
"partition keys can not be changed.");
}
}

// if this alter is a rename, the table is not a virtual view, the user
Expand Down
Expand Up @@ -1664,6 +1664,8 @@ public void alterTable(String dbname, String name, Table newTable)
oldt.setPartitionKeys(newt.getPartitionKeys());
oldt.setTableType(newt.getTableType());
oldt.setLastAccessTime(newt.getLastAccessTime());
oldt.setViewOriginalText(newt.getViewOriginalText());
oldt.setViewExpandedText(newt.getViewExpandedText());

// commit the changes
success = commitTransaction();
Expand Down
83 changes: 61 additions & 22 deletions ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java
Expand Up @@ -3369,31 +3369,70 @@ private int createTableLike(Hive db, CreateTableLikeDesc crtTbl) throws HiveExce
* Throws this exception if an unexpected error occurs.
*/
private int createView(Hive db, CreateViewDesc crtView) throws HiveException {
Table tbl = db.newTable(crtView.getViewName());
tbl.setTableType(TableType.VIRTUAL_VIEW);
tbl.setSerializationLib(null);
tbl.clearSerDeInfo();
tbl.setViewOriginalText(crtView.getViewOriginalText());
tbl.setViewExpandedText(crtView.getViewExpandedText());
tbl.setFields(crtView.getSchema());
if (crtView.getComment() != null) {
tbl.setProperty("comment", crtView.getComment());
}
if (crtView.getTblProps() != null) {
tbl.getTTable().getParameters().putAll(crtView.getTblProps());
}
Table oldview = db.getTable(crtView.getViewName(), false);
if (crtView.getOrReplace() && oldview != null) {
// replace existing view
if (!oldview.getTableType().equals(TableType.VIRTUAL_VIEW)) {
throw new HiveException("Existing table is not a view");
}

if (crtView.getPartCols() == null
|| crtView.getPartCols().isEmpty()
|| !crtView.getPartCols().equals(oldview.getPartCols())) {
// if we are changing partition columns, check that partitions don't exist
if (!oldview.getPartCols().isEmpty() &&
!db.getPartitions(oldview).isEmpty()) {
throw new HiveException(
"Cannot add or drop partition columns with CREATE OR REPLACE VIEW if partitions currently exist");
}
}

if (crtView.getPartCols() != null) {
tbl.setPartCols(crtView.getPartCols());
}
// remove the existing partition columns from the field schema
oldview.setViewOriginalText(crtView.getViewOriginalText());
oldview.setViewExpandedText(crtView.getViewExpandedText());
oldview.setFields(crtView.getSchema());
if (crtView.getComment() != null) {
oldview.setProperty("comment", crtView.getComment());
}
if (crtView.getTblProps() != null) {
oldview.getTTable().getParameters().putAll(crtView.getTblProps());
}
oldview.setPartCols(crtView.getPartCols());
oldview.checkValidity();
try {
db.alterTable(crtView.getViewName(), oldview);
} catch (InvalidOperationException e) {
throw new HiveException(e);
}
work.getOutputs().add(new WriteEntity(oldview));
} else {
// create new view
Table tbl = db.newTable(crtView.getViewName());
tbl.setTableType(TableType.VIRTUAL_VIEW);
tbl.setSerializationLib(null);
tbl.clearSerDeInfo();
tbl.setViewOriginalText(crtView.getViewOriginalText());
tbl.setViewExpandedText(crtView.getViewExpandedText());
tbl.setFields(crtView.getSchema());
if (crtView.getComment() != null) {
tbl.setProperty("comment", crtView.getComment());
}
if (crtView.getTblProps() != null) {
tbl.getTTable().getParameters().putAll(crtView.getTblProps());
}

int rc = setGenericTableAttributes(tbl);
if (rc != 0) {
return rc;
}
if (crtView.getPartCols() != null) {
tbl.setPartCols(crtView.getPartCols());
}

db.createTable(tbl, crtView.getIfNotExists());
work.getOutputs().add(new WriteEntity(tbl));
int rc = setGenericTableAttributes(tbl);
if (rc != 0) {
return rc;
}

db.createTable(tbl, crtView.getIfNotExists());
work.getOutputs().add(new WriteEntity(tbl));
}
return 0;
}

Expand Down
13 changes: 11 additions & 2 deletions ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g
Expand Up @@ -200,6 +200,7 @@ TOK_LIMIT;
TOK_TABLEPROPERTY;
TOK_IFEXISTS;
TOK_IFNOTEXISTS;
TOK_ORREPLACE;
TOK_HINTLIST;
TOK_HINT;
TOK_MAPJOIN;
Expand Down Expand Up @@ -370,6 +371,13 @@ ifNotExists
-> ^(TOK_IFNOTEXISTS)
;

orReplace
@init { msgs.push("or replace clause"); }
@after { msgs.pop(); }
: KW_OR KW_REPLACE
-> ^(TOK_ORREPLACE)
;


createDatabaseStatement
@init { msgs.push("create database statement"); }
Expand Down Expand Up @@ -997,12 +1005,13 @@ createViewStatement
msgs.push("create view statement");
}
@after { msgs.pop(); }
: KW_CREATE KW_VIEW ifNotExists? name=tableName
: KW_CREATE (orReplace)? KW_VIEW (ifNotExists)? name=tableName
(LPAREN columnNameCommentList RPAREN)? tableComment? viewPartition?
tablePropertiesPrefixed?
KW_AS
selectStatement
-> ^(TOK_CREATEVIEW $name ifNotExists?
-> ^(TOK_CREATEVIEW $name orReplace?
ifNotExists?
columnNameCommentList?
tableComment?
viewPartition?
Expand Down
Expand Up @@ -195,6 +195,7 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer {
Map<String, PrunedPartitionList> prunedPartitions;
private List<FieldSchema> resultSchema;
private CreateViewDesc createVwDesc;
private ArrayList<String> viewsExpanded;
private ASTNode viewSelect;
private final UnparseTranslator unparseTranslator;
private final GlobalLimitCtx globalLimitCtx = new GlobalLimitCtx();
Expand Down Expand Up @@ -873,6 +874,7 @@ public void getMetaData(QB qb) throws SemanticException {
// We have to materialize the table alias list since we might
// modify it in the middle for view rewrite.
List<String> tabAliases = new ArrayList<String>(qb.getTabAliases());
Map<String, String> aliasToViewName = new HashMap<String, String>();
for (String alias : tabAliases) {
String tab_name = qb.getTabNameForAlias(alias);
Table tab = null;
Expand Down Expand Up @@ -911,7 +913,15 @@ public void getMetaData(QB qb) throws SemanticException {
if (qb.getParseInfo().isAnalyzeCommand()) {
throw new SemanticException(ErrorMsg.ANALYZE_VIEW.getMsg());
}
String fullViewName = tab.getDbName()+"."+tab.getTableName();
// Prevent view cycles
if(viewsExpanded.contains(fullViewName)){
throw new SemanticException("Recursive view " + fullViewName +
" detected (cycle: " + StringUtils.join(viewsExpanded, " -> ") +
" -> " + fullViewName + ").");
}
replaceViewReferenceWithDefinition(qb, tab, tab_name, alias);
aliasToViewName.put(alias, fullViewName);
continue;
}

Expand Down Expand Up @@ -940,8 +950,15 @@ public void getMetaData(QB qb) throws SemanticException {
LOG.info("Get metadata for subqueries");
// Go over the subqueries and getMetaData for these
for (String alias : qb.getSubqAliases()) {
boolean wasView = aliasToViewName.containsKey(alias);
if (wasView) {
viewsExpanded.add(aliasToViewName.get(alias));
}
QBExpr qbexpr = qb.getSubqForAlias(alias);
getMetaData(qbexpr);
if (wasView) {
viewsExpanded.remove(viewsExpanded.size()-1);
}
}

LOG.info("Get metadata for destination tables");
Expand Down Expand Up @@ -7124,6 +7141,7 @@ public void analyzeInternal(ASTNode ast) throws SemanticException {
this.qb = qb;
this.ast = ast;
ASTNode child = ast;
viewsExpanded = new ArrayList<String>();

LOG.info("Starting Semantic Analysis");

Expand All @@ -7145,6 +7163,8 @@ public void analyzeInternal(ASTNode ast) throws SemanticException {
return;
}
viewSelect = child;
// prevent view from referencing itself
viewsExpanded.add(db.getCurrentDatabase()+"."+createVwDesc.getViewName());
}

// continue analyzing from the child ASTNode.
Expand Down Expand Up @@ -7778,6 +7798,7 @@ private ASTNode analyzeCreateView(ASTNode ast, QB qb)
String tableName = getUnescapedName((ASTNode)ast.getChild(0));
List<FieldSchema> cols = null;
boolean ifNotExists = false;
boolean orReplace = false;
String comment = null;
ASTNode selectStmt = null;
Map<String, String> tblProps = null;
Expand All @@ -7792,6 +7813,9 @@ private ASTNode analyzeCreateView(ASTNode ast, QB qb)
case HiveParser.TOK_IFNOTEXISTS:
ifNotExists = true;
break;
case HiveParser.TOK_ORREPLACE:
orReplace = true;
break;
case HiveParser.TOK_QUERY:
selectStmt = child;
break;
Expand All @@ -7812,8 +7836,12 @@ private ASTNode analyzeCreateView(ASTNode ast, QB qb)
}
}

if (ifNotExists && orReplace){
throw new SemanticException("Can't combine IF NOT EXISTS and OR REPLACE.");
}

createVwDesc = new CreateViewDesc(
tableName, cols, comment, tblProps, partColNames, ifNotExists);
tableName, cols, comment, tblProps, partColNames, ifNotExists, orReplace);
unparseTranslator.enable();
rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(),
createVwDesc), conf));
Expand Down
15 changes: 13 additions & 2 deletions ql/src/java/org/apache/hadoop/hive/ql/plan/CreateViewDesc.java
Expand Up @@ -42,22 +42,24 @@ public class CreateViewDesc extends DDLDesc implements Serializable {
private List<FieldSchema> partCols;
private String comment;
private boolean ifNotExists;
private boolean orReplace;

/**
* For serialization only.
*/
public CreateViewDesc() {
}

public CreateViewDesc(String viewName, List<FieldSchema> schema,
String comment, Map<String, String> tblProps,
List<String> partColNames, boolean ifNotExists) {
List<String> partColNames, boolean ifNotExists, boolean orReplace) {
this.viewName = viewName;
this.schema = schema;
this.comment = comment;
this.tblProps = tblProps;
this.partColNames = partColNames;
this.ifNotExists = ifNotExists;
this.orReplace = orReplace;
}

@Explain(displayName = "name")
Expand Down Expand Up @@ -147,4 +149,13 @@ public boolean getIfNotExists() {
public void setIfNotExists(boolean ifNotExists) {
this.ifNotExists = ifNotExists;
}

@Explain(displayName = "or replace")
public boolean getOrReplace() {
return orReplace;
}

public void setOrReplace(boolean orReplace) {
this.orReplace = orReplace;
}
}
6 changes: 6 additions & 0 deletions ql/src/test/queries/clientnegative/create_or_replace_view1.q
@@ -0,0 +1,6 @@
-- Cannot add or drop partition columns with CREATE OR REPLACE VIEW if partitions currently exist (must specify partition columns)

drop view v;
create view v partitioned on (ds, hr) as select * from srcpart;
alter view v add partition (ds='1',hr='2');
create or replace view v as select * from srcpart;
6 changes: 6 additions & 0 deletions ql/src/test/queries/clientnegative/create_or_replace_view2.q
@@ -0,0 +1,6 @@
-- Cannot add or drop partition columns with CREATE OR REPLACE VIEW if partitions currently exist

drop view v;
create view v partitioned on (ds, hr) as select * from srcpart;
alter view v add partition (ds='1',hr='2');
create or replace view v partitioned on (hr) as select * from srcpart;
3 changes: 3 additions & 0 deletions ql/src/test/queries/clientnegative/create_or_replace_view3.q
@@ -0,0 +1,3 @@
-- Existing table is not a view

create or replace view src as select ds, hr from srcpart;
5 changes: 5 additions & 0 deletions ql/src/test/queries/clientnegative/create_or_replace_view4.q
@@ -0,0 +1,5 @@
-- View must have at least one non-partition column.

drop view v;
create view v partitioned on (ds, hr) as select * from srcpart;
create or replace view v partitioned on (ds, hr) as select ds, hr from srcpart;
5 changes: 5 additions & 0 deletions ql/src/test/queries/clientnegative/create_or_replace_view5.q
@@ -0,0 +1,5 @@
-- Can't combine IF NOT EXISTS and OR REPLACE.

drop view v;
create view v partitioned on (ds, hr) as select * from srcpart;
create or replace view if not exists v as select * from srcpart;
5 changes: 5 additions & 0 deletions ql/src/test/queries/clientnegative/create_or_replace_view6.q
@@ -0,0 +1,5 @@
-- Can't update view to have an invalid definition

drop view v;
create view v partitioned on (ds, hr) as select * from srcpart;
create or replace view v partitioned on (ds, hr) as blah;
7 changes: 7 additions & 0 deletions ql/src/test/queries/clientnegative/create_or_replace_view7.q
@@ -0,0 +1,7 @@
-- Can't update view to have a view cycle (1)

drop view v;
create view v1 partitioned on (ds, hr) as select * from srcpart;
create view v2 partitioned on (ds, hr) as select * from v1;
create view v3 partitioned on (ds, hr) as select * from v2;
create or replace view v1 partitioned on (ds, hr) as select * from v3;
5 changes: 5 additions & 0 deletions ql/src/test/queries/clientnegative/create_or_replace_view8.q
@@ -0,0 +1,5 @@
-- Can't update view to have a view cycle (2)

drop view v;
create view v1 partitioned on (ds, hr) as select * from srcpart;
create or replace view v1 partitioned on (ds, hr) as select * from v1;
15 changes: 15 additions & 0 deletions ql/src/test/queries/clientnegative/recursive_view.q
@@ -0,0 +1,15 @@
-- Can't have recursive views

drop table t;
drop view r0;
drop view r1;
drop view r2;
drop view r3;
create table t (id int);
create view r0 as select * from t;
create view r1 as select * from r0;
create view r2 as select * from r1;
create view r3 as select * from r2;
drop view r0;
alter view r3 rename to r0;
select * from r0;

0 comments on commit 7366a5d

Please sign in to comment.