提交 0c646e4c authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add optional EXCEPT clause to wildcards

上级 975a9d76
...@@ -2497,7 +2497,7 @@ COMPRESSION LZF ...@@ -2497,7 +2497,7 @@ COMPRESSION LZF
" "
"Other Grammar","Select Expression"," "Other Grammar","Select Expression","
* | expression [ [ AS ] columnAlias ] | tableAlias.* wildcardExpression | expression [ [ AS ] columnAlias ]
"," ","
An expression in a SELECT statement. An expression in a SELECT statement.
"," ","
...@@ -2568,6 +2568,16 @@ The column list of the resulting table is C1, C2, and so on. ...@@ -2568,6 +2568,16 @@ The column list of the resulting table is C1, C2, and so on.
SELECT * FROM (VALUES(1, 'Hello'), (2, 'World')) AS V; SELECT * FROM (VALUES(1, 'Hello'), (2, 'World')) AS V;
" "
"Other Grammar","Wildcard expression","
{* | tableAlias.*} [EXCEPT ([tableAlias.]columnName, [,...])]
","
A wildcard expression in a SELECT statement.
A wildcard expression represents all visible columns. Some columns can be excluded with optional EXCEPT clause.
","
*
* EXCEPT (DATA)
"
"Other Grammar","Window name or specification"," "Other Grammar","Window name or specification","
windowName | windowSpecification windowName | windowSpecification
"," ","
......
...@@ -2593,7 +2593,7 @@ public class Parser { ...@@ -2593,7 +2593,7 @@ public class Parser {
ArrayList<Expression> expressions = Utils.newSmallArrayList(); ArrayList<Expression> expressions = Utils.newSmallArrayList();
do { do {
if (readIf(ASTERISK)) { if (readIf(ASTERISK)) {
expressions.add(new Wildcard(null, null)); expressions.add(parseWildcard(null, null));
} else { } else {
Expression expr = readExpression(); Expression expr = readExpression();
if (readIf("AS") || currentTokenType == IDENTIFIER) { if (readIf("AS") || currentTokenType == IDENTIFIER) {
...@@ -3506,7 +3506,7 @@ public class Parser { ...@@ -3506,7 +3506,7 @@ public class Parser {
private Expression readWildcardOrSequenceValue(String schema, private Expression readWildcardOrSequenceValue(String schema,
String objectName) { String objectName) {
if (readIf(ASTERISK)) { if (readIf(ASTERISK)) {
return new Wildcard(schema, objectName); return parseWildcard(schema, objectName);
} }
if (schema == null) { if (schema == null) {
schema = session.getCurrentSchemaName(); schema = session.getCurrentSchemaName();
...@@ -3531,6 +3531,38 @@ public class Parser { ...@@ -3531,6 +3531,38 @@ public class Parser {
return null; return null;
} }
private Wildcard parseWildcard(String schema, String objectName) {
Wildcard wildcard = new Wildcard(schema, objectName);
if (readIf(EXCEPT)) {
read(OPEN_PAREN);
ArrayList<ExpressionColumn> exceptColumns = Utils.newSmallArrayList();
do {
String s = null, t = null;
String name = readColumnIdentifier();
if (readIf(DOT)) {
t = name;
name = readColumnIdentifier();
if (readIf(DOT)) {
s = t;
t = name;
name = readColumnIdentifier();
if (readIf(DOT)) {
if (!equalsToken(database.getShortName(), s)) {
throw DbException.get(ErrorCode.DATABASE_NOT_FOUND_1, s);
}
s = t;
t = name;
name = readColumnIdentifier();
}
}
}
exceptColumns.add(new ExpressionColumn(database, s, t, name));
} while (readIfMore(true));
wildcard.setExceptColumns(exceptColumns);
}
return wildcard;
}
private Expression readTermObjectDot(String objectName) { private Expression readTermObjectDot(String objectName) {
Expression expr = readWildcardOrSequenceValue(null, objectName); Expression expr = readWildcardOrSequenceValue(null, objectName);
if (expr != null) { if (expr != null) {
......
...@@ -892,40 +892,67 @@ public class Select extends Query { ...@@ -892,40 +892,67 @@ public class Select extends Query {
} }
String schemaName = expr.getSchemaName(); String schemaName = expr.getSchemaName();
String tableAlias = expr.getTableAlias(); String tableAlias = expr.getTableAlias();
Wildcard w = (Wildcard) expr;
ArrayList<ExpressionColumn> exceptColumns = w.getExceptColumns();
HashMap<Column, ExpressionColumn> exceptTableColumns = null;
if (tableAlias == null) { if (tableAlias == null) {
if (exceptColumns != null) {
for (TableFilter filter : filters) {
w.mapColumns(filter, 1, Expression.MAP_INITIAL);
}
exceptTableColumns = mapExceptColumns(exceptColumns);
}
expressions.remove(i); expressions.remove(i);
for (TableFilter filter : filters) { for (TableFilter filter : filters) {
i = expandColumnList(filter, i); i = expandColumnList(filter, i, exceptTableColumns);
} }
i--; i--;
} else { } else {
TableFilter filter = null; TableFilter filter = null;
for (TableFilter f : filters) { for (TableFilter f : filters) {
if (db.equalsIdentifiers(tableAlias, f.getTableAlias())) { if (db.equalsIdentifiers(tableAlias, f.getTableAlias())) {
if (schemaName == null || if (schemaName == null || db.equalsIdentifiers(schemaName, f.getSchemaName())) {
db.equalsIdentifiers(schemaName, if (exceptColumns != null) {
f.getSchemaName())) { w.mapColumns(f, 1, Expression.MAP_INITIAL);
exceptTableColumns = mapExceptColumns(exceptColumns);
}
filter = f; filter = f;
break; break;
} }
} }
} }
if (filter == null) { if (filter == null) {
throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, tableAlias);
tableAlias);
} }
expressions.remove(i); expressions.remove(i);
i = expandColumnList(filter, i); i = expandColumnList(filter, i, exceptTableColumns);
i--; i--;
} }
} }
} }
private int expandColumnList(TableFilter filter, int index) { public HashMap<Column, ExpressionColumn> mapExceptColumns(ArrayList<ExpressionColumn> exceptColumns) {
HashMap<Column, ExpressionColumn> exceptTableColumns = new HashMap<>();
for (ExpressionColumn ec : exceptColumns) {
Column column = ec.getColumn();
if (column == null) {
throw ec.getColumnException(ErrorCode.COLUMN_NOT_FOUND_1);
}
if (exceptTableColumns.put(column, ec) != null) {
throw ec.getColumnException(ErrorCode.DUPLICATE_COLUMN_NAME_1);
}
}
return exceptTableColumns;
}
private int expandColumnList(TableFilter filter, int index, HashMap<Column, ExpressionColumn> except) {
Table t = filter.getTable(); Table t = filter.getTable();
String alias = filter.getTableAlias(); String alias = filter.getTableAlias();
Column[] columns = t.getColumns(); Column[] columns = t.getColumns();
for (Column c : columns) { for (Column c : columns) {
if (except != null && except.remove(c) != null) {
continue;
}
if (!c.getVisible()) { if (!c.getVisible()) {
continue; continue;
} }
......
...@@ -140,18 +140,22 @@ public class ExpressionColumn extends Expression { ...@@ -140,18 +140,22 @@ public class ExpressionColumn extends Expression {
return constant.getValue(); return constant.getValue();
} }
} }
String name = columnName; throw getColumnException(ErrorCode.COLUMN_NOT_FOUND_1);
if (tableAlias != null) {
name = tableAlias + "." + name;
if (schemaName != null) {
name = schemaName + "." + name;
}
}
throw DbException.get(ErrorCode.COLUMN_NOT_FOUND_1, name);
} }
return columnResolver.optimize(this, column); return columnResolver.optimize(this, column);
} }
public DbException getColumnException(int code) {
String name = columnName;
if (tableAlias != null) {
name = tableAlias + '.' + name;
if (schemaName != null) {
name = schemaName + '.' + name;
}
}
return DbException.get(code, name);
}
@Override @Override
public void updateAggregate(Session session, int stage) { public void updateAggregate(Session session, int stage) {
Select select = columnResolver.getSelect(); Select select = columnResolver.getSelect();
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
*/ */
package org.h2.expression; package org.h2.expression;
import java.util.ArrayList;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
...@@ -22,11 +24,21 @@ public class Wildcard extends Expression { ...@@ -22,11 +24,21 @@ public class Wildcard extends Expression {
private final String schema; private final String schema;
private final String table; private final String table;
private ArrayList<ExpressionColumn> exceptColumns;
public Wildcard(String schema, String table) { public Wildcard(String schema, String table) {
this.schema = schema; this.schema = schema;
this.table = table; this.table = table;
} }
public ArrayList<ExpressionColumn> getExceptColumns() {
return exceptColumns;
}
public void setExceptColumns(ArrayList<ExpressionColumn> exceptColumns) {
this.exceptColumns = exceptColumns;
}
@Override @Override
public boolean isWildcard() { public boolean isWildcard() {
return true; return true;
...@@ -44,7 +56,11 @@ public class Wildcard extends Expression { ...@@ -44,7 +56,11 @@ public class Wildcard extends Expression {
@Override @Override
public void mapColumns(ColumnResolver resolver, int level, int state) { public void mapColumns(ColumnResolver resolver, int level, int state) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_1, table); if (exceptColumns != null) {
for (ExpressionColumn column : exceptColumns) {
column.mapColumns(resolver, level, state);
}
}
} }
@Override @Override
...@@ -84,10 +100,23 @@ public class Wildcard extends Expression { ...@@ -84,10 +100,23 @@ public class Wildcard extends Expression {
@Override @Override
public String getSQL() { public String getSQL() {
if (table == null) { StringBuilder builder = new StringBuilder();
return "*"; if (table != null) {
builder.append(StringUtils.quoteIdentifier(table)).append('.');
}
builder.append('*');
if (exceptColumns != null) {
builder.append(" EXCEPT (");
for (int i = 0; i < exceptColumns.size(); i++) {
if (i > 0) {
builder.append(", ");
}
ExpressionColumn ec = exceptColumns.get(i);
builder.append(ec.getSQL());
}
builder.append(')');
} }
return StringUtils.quoteIdentifier(table) + ".*"; return builder.toString();
} }
@Override @Override
......
...@@ -329,3 +329,81 @@ SELECT * FROM TEST ORDER BY ?, ? FETCH FIRST ROW ONLY; ...@@ -329,3 +329,81 @@ SELECT * FROM TEST ORDER BY ?, ? FETCH FIRST ROW ONLY;
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
CREATE TABLE TEST1(A INT, B INT, C INT) AS SELECT 1, 2, 3;
> ok
CREATE TABLE TEST2(A INT, D INT) AS SELECT 4, 5;
> ok
SELECT * FROM TEST1, TEST2;
> A B C A D
> - - - - -
> 1 2 3 4 5
> rows: 1
SELECT * EXCEPT (A) FROM TEST1;
> B C
> - -
> 2 3
> rows: 1
SELECT * EXCEPT (TEST1.A) FROM TEST1;
> B C
> - -
> 2 3
> rows: 1
SELECT * EXCEPT (PUBLIC.TEST1.A) FROM TEST1;
> B C
> - -
> 2 3
> rows: 1
SELECT * EXCEPT (SCRIPT.PUBLIC.TEST1.A) FROM TEST1;
> B C
> - -
> 2 3
> rows: 1
SELECT * EXCEPT (Z) FROM TEST1;
> exception COLUMN_NOT_FOUND_1
SELECT * EXCEPT (B, TEST1.B) FROM TEST1;
> exception DUPLICATE_COLUMN_NAME_1
SELECT * EXCEPT (A) FROM TEST1, TEST2;
> exception AMBIGUOUS_COLUMN_NAME_1
SELECT * EXCEPT (TEST1.A, B, TEST2.D) FROM TEST1, TEST2;
> C A
> - -
> 3 4
> rows: 1
SELECT TEST1.*, TEST2.* FROM TEST1, TEST2;
> A B C A D
> - - - - -
> 1 2 3 4 5
> rows: 1
SELECT TEST1.* EXCEPT (A), TEST2.* EXCEPT (A) FROM TEST1, TEST2;
> B C D
> - - -
> 2 3 5
> rows: 1
SELECT TEST1.* EXCEPT (A), TEST2.* EXCEPT (D) FROM TEST1, TEST2;
> B C A
> - - -
> 2 3 4
> rows: 1
SELECT * EXCEPT (T1.A, T2.D) FROM TEST1 T1, TEST2 T2;
> B C A
> - - -
> 2 3 4
> rows: 1
DROP TABLE TEST1, TEST2;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论