Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ catch (RecognitionException e) {
//-----------------------------------------------------------------------------------

tableAllColumns
: STAR
-> ^(TOK_ALLCOLREF)
| tableName DOT STAR
-> ^(TOK_ALLCOLREF tableName)
: STAR (KW_EXCLUDE LPAREN columnNameList RPAREN)?
-> ^(TOK_ALLCOLREF columnNameList?)
| tableName DOT STAR (KW_EXCLUDE LPAREN columnNameList RPAREN)?
-> ^(TOK_ALLCOLREF tableName columnNameList?)
;

// (table|column)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ KW_SPEC: 'SPEC';
KW_SYSTEM_TIME: 'SYSTEM_TIME';
KW_SYSTEM_VERSION: 'SYSTEM_VERSION';
KW_EXPIRE_SNAPSHOTS: 'EXPIRE_SNAPSHOTS';
KW_EXCLUDE: 'EXCLUDE';
KW_SET_CURRENT_SNAPSHOT: 'SET_CURRENT_SNAPSHOT';
KW_BRANCH: 'BRANCH';
KW_SNAPSHOTS: 'SNAPSHOTS';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,7 @@ nonReserved
| KW_TRIM
| KW_SPEC
| KW_SYSTEM_TIME | KW_SYSTEM_VERSION
| KW_EXCLUDE
| KW_EXPIRE_SNAPSHOTS
| KW_SET_CURRENT_SNAPSHOT
| KW_BRANCH | KW_SNAPSHOTS | KW_RETAIN | KW_RETENTION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4366,8 +4366,9 @@ private Pair<RelNode, RowResolver> internalGenSelectLogicalPlan(QB qb, RelNode s

// 6.4 Build ExprNode corresponding to colums
if (expr.getType() == HiveParser.TOK_ALLCOLREF) {
pos = genRexNodeRegex(".*",
expr.getChildCount() == 0 ? null : getUnescapedName((ASTNode) expr.getChild(0)).toLowerCase(),
// Parse SELECT * EXCLUDE columns and pass them to the Calcite engine for exclusion
String starTabAlias = SemanticAnalyzer.processAllColRefAndExclude(expr, inputRR, excludedColumns);
pos = genRexNodeRegex(".*", starTabAlias,
expr, columnList, excludedColumns, inputRR, starRR, pos, outputRR, qb.getAliases(), true);
} else if (expr.getType() == HiveParser.TOK_TABLE_OR_COL
&& !hasAsClause
Expand Down
41 changes: 38 additions & 3 deletions ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4733,6 +4733,35 @@ static boolean isRegex(String pattern, HiveConf conf) {
return false;
}

public static String processAllColRefAndExclude(
ASTNode expr, RowResolver inputRR, Set<ColumnInfo> excludedColumns) throws SemanticException {
// Check if the query uses SELECT * EXCLUDE. If it does, grab the table
// alias (like t.*) and build a list of the columns the user wants to exclude.
String starTabAlias = null;
ASTNode excludeNode = null;
if (expr.getChildCount() > 0) {
ASTNode firstChild = (ASTNode) expr.getChild(0);
if (firstChild.getType() == HiveParser.TOK_TABCOLNAME) {
excludeNode = firstChild;
} else {
starTabAlias = getUnescapedName(firstChild).toLowerCase();
if (expr.getChildCount() > 1) {
excludeNode = (ASTNode) expr.getChild(1);
}
}
}

if (excludeNode != null) {
for (int e = 0; e < excludeNode.getChildCount(); e++) {
String excludeColName = unescapeIdentifier(excludeNode.getChild(e).getText()).toLowerCase();
ColumnInfo colInfo = inputRR.get(starTabAlias, excludeColName);
if (colInfo != null) {
excludedColumns.add(colInfo);
}
}
}
return starTabAlias;
}

private Operator<?> genSelectPlan(String dest, QB qb, Operator<?> input,
Operator<?> inputForSelectStar) throws SemanticException {
Expand Down Expand Up @@ -4910,9 +4939,15 @@ private Operator<?> genSelectPlan(String dest, ASTNode selExprList, QB qb, Opera
// The real expression
if (expr.getType() == HiveParser.TOK_ALLCOLREF) {
int initPos = pos;
pos = genExprNodeDescRegex(".*", expr.getChildCount() == 0 ? null
: getUnescapedName((ASTNode) expr.getChild(0)).toLowerCase(),
expr, colList, null, inputRR, starRR, pos, out_rwsch, qb.getAliases(), false);

Set<ColumnInfo> excludeCols = new HashSet<>();
String starTabAlias = processAllColRefAndExclude(expr, inputRR, excludeCols);
if (excludeCols.isEmpty()) {
excludeCols = null;
}

pos = genExprNodeDescRegex(".*", starTabAlias,
expr, colList, excludeCols, inputRR, starRR, pos, out_rwsch, qb.getAliases(), false);
if (unparseTranslator.isEnabled()) {
offset += pos - initPos - 1;
}
Expand Down
37 changes: 37 additions & 0 deletions ql/src/test/queries/clientpositive/select_exclude.q
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
CREATE TABLE test_exclude (
id INT,
name STRING,
email STRING,
address STRING,
phone STRING
);

INSERT INTO test_exclude VALUES (1, 'Alice', 'alice@test.com', '123 Apple St', '555-0100');
INSERT INTO test_exclude VALUES (2, 'Bob', 'bob@test.com', '456 Banana Ave', '555-0200');

-- Exclude a single column
EXPLAIN SELECT * EXCLUDE (email) FROM test_exclude;
SELECT * EXCLUDE (email) FROM test_exclude;

-- Exclude multiple columns
EXPLAIN SELECT * EXCLUDE (email, address, phone) FROM test_exclude;
SELECT * EXCLUDE (email, address, phone) FROM test_exclude;

-- Exclude with table alias
EXPLAIN SELECT t.* EXCLUDE (id, phone) FROM test_exclude t;
SELECT t.* EXCLUDE (id, phone) FROM test_exclude t;

-- Exclude with JOIN
CREATE TABLE test_exclude_join (
id INT,
department STRING
);
INSERT INTO test_exclude_join VALUES (1, 'Engineering');
INSERT INTO test_exclude_join VALUES (2, 'Sales');

EXPLAIN
SELECT a.* EXCLUDE (address, phone), b.* EXCLUDE (id)
FROM test_exclude a JOIN test_exclude_join b ON a.id = b.id;

SELECT a.* EXCLUDE (address, phone), b.* EXCLUDE (id)
FROM test_exclude a JOIN test_exclude_join b ON a.id = b.id;
Loading
Loading