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

Add optional EXCEPT clause to wildcards

上级 975a9d76
......@@ -2497,7 +2497,7 @@ COMPRESSION LZF
"
"Other Grammar","Select Expression","
* | expression [ [ AS ] columnAlias ] | tableAlias.*
wildcardExpression | expression [ [ AS ] columnAlias ]
","
An expression in a SELECT statement.
","
......@@ -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;
"
"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","
windowName | windowSpecification
","
......
......@@ -2593,7 +2593,7 @@ public class Parser {
ArrayList<Expression> expressions = Utils.newSmallArrayList();
do {
if (readIf(ASTERISK)) {
expressions.add(new Wildcard(null, null));
expressions.add(parseWildcard(null, null));
} else {
Expression expr = readExpression();
if (readIf("AS") || currentTokenType == IDENTIFIER) {
......@@ -3506,7 +3506,7 @@ public class Parser {
private Expression readWildcardOrSequenceValue(String schema,
String objectName) {
if (readIf(ASTERISK)) {
return new Wildcard(schema, objectName);
return parseWildcard(schema, objectName);
}
if (schema == null) {
schema = session.getCurrentSchemaName();
......@@ -3531,6 +3531,38 @@ public class Parser {
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) {
Expression expr = readWildcardOrSequenceValue(null, objectName);
if (expr != null) {
......
......@@ -892,40 +892,67 @@ public class Select extends Query {
}
String schemaName = expr.getSchemaName();
String tableAlias = expr.getTableAlias();
Wildcard w = (Wildcard) expr;
ArrayList<ExpressionColumn> exceptColumns = w.getExceptColumns();
HashMap<Column, ExpressionColumn> exceptTableColumns = null;
if (tableAlias == null) {
if (exceptColumns != null) {
for (TableFilter filter : filters) {
w.mapColumns(filter, 1, Expression.MAP_INITIAL);
}
exceptTableColumns = mapExceptColumns(exceptColumns);
}
expressions.remove(i);
for (TableFilter filter : filters) {
i = expandColumnList(filter, i);
i = expandColumnList(filter, i, exceptTableColumns);
}
i--;
} else {
TableFilter filter = null;
for (TableFilter f : filters) {
if (db.equalsIdentifiers(tableAlias, f.getTableAlias())) {
if (schemaName == null ||
db.equalsIdentifiers(schemaName,
f.getSchemaName())) {
if (schemaName == null || db.equalsIdentifiers(schemaName, f.getSchemaName())) {
if (exceptColumns != null) {
w.mapColumns(f, 1, Expression.MAP_INITIAL);
exceptTableColumns = mapExceptColumns(exceptColumns);
}
filter = f;
break;
}
}
}
if (filter == null) {
throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1,
tableAlias);
throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, tableAlias);
}
expressions.remove(i);
i = expandColumnList(filter, i);
i = expandColumnList(filter, i, exceptTableColumns);
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();
String alias = filter.getTableAlias();
Column[] columns = t.getColumns();
for (Column c : columns) {
if (except != null && except.remove(c) != null) {
continue;
}
if (!c.getVisible()) {
continue;
}
......
......@@ -140,18 +140,22 @@ public class ExpressionColumn extends Expression {
return constant.getValue();
}
}
String name = columnName;
if (tableAlias != null) {
name = tableAlias + "." + name;
if (schemaName != null) {
name = schemaName + "." + name;
}
}
throw DbException.get(ErrorCode.COLUMN_NOT_FOUND_1, name);
throw getColumnException(ErrorCode.COLUMN_NOT_FOUND_1);
}
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
public void updateAggregate(Session session, int stage) {
Select select = columnResolver.getSelect();
......
......@@ -5,6 +5,8 @@
*/
package org.h2.expression;
import java.util.ArrayList;
import org.h2.api.ErrorCode;
import org.h2.engine.Session;
import org.h2.message.DbException;
......@@ -22,11 +24,21 @@ public class Wildcard extends Expression {
private final String schema;
private final String table;
private ArrayList<ExpressionColumn> exceptColumns;
public Wildcard(String schema, String table) {
this.schema = schema;
this.table = table;
}
public ArrayList<ExpressionColumn> getExceptColumns() {
return exceptColumns;
}
public void setExceptColumns(ArrayList<ExpressionColumn> exceptColumns) {
this.exceptColumns = exceptColumns;
}
@Override
public boolean isWildcard() {
return true;
......@@ -44,7 +56,11 @@ public class Wildcard extends Expression {
@Override
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
......@@ -84,10 +100,23 @@ public class Wildcard extends Expression {
@Override
public String getSQL() {
if (table == null) {
return "*";
StringBuilder builder = new StringBuilder();
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
......
......@@ -329,3 +329,81 @@ SELECT * FROM TEST ORDER BY ?, ? FETCH FIRST ROW ONLY;
DROP TABLE TEST;
> 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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论