Unverified 提交 c7668d41 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #909 from katzyn/derived_column_list

Derived column list
...@@ -2256,7 +2256,8 @@ ID + 20 ...@@ -2256,7 +2256,8 @@ ID + 20
" "
"Other Grammar","Table Expression"," "Other Grammar","Table Expression","
{ [ schemaName. ] tableName | ( select ) | valuesExpression } [ [ AS ] newTableAlias ] { [ schemaName. ] tableName | ( select ) | valuesExpression }
[ [ AS ] newTableAlias [ ( columnName [,...] ) ] ]
[ USE INDEX ([ indexName [,...] ]) ] [ USE INDEX ([ indexName [,...] ]) ]
[ { { LEFT | RIGHT } [ OUTER ] | [ INNER ] | CROSS | NATURAL } [ { { LEFT | RIGHT } [ OUTER ] | [ INNER ] | CROSS | NATURAL }
JOIN tableExpression [ ON expression ] ] JOIN tableExpression [ ON expression ] ]
......
...@@ -1374,6 +1374,10 @@ public class Parser { ...@@ -1374,6 +1374,10 @@ public class Parser {
alias = readFromAlias(null); alias = readFromAlias(null);
if (alias != null) { if (alias != null) {
top.setAlias(alias); top.setAlias(alias);
ArrayList<String> derivedColumnNames = readDerivedColumnNames();
if (derivedColumnNames != null) {
top.setDerivedColumns(derivedColumnNames);
}
} }
return top; return top;
} }
...@@ -1426,6 +1430,7 @@ public class Parser { ...@@ -1426,6 +1430,7 @@ public class Parser {
table = readTableOrView(tableName); table = readTableOrView(tableName);
} }
} }
ArrayList<String> derivedColumnNames = null;
IndexHints indexHints = null; IndexHints indexHints = null;
// for backward compatibility, handle case where USE is a table alias // for backward compatibility, handle case where USE is a table alias
if (readIf("USE")) { if (readIf("USE")) {
...@@ -1433,10 +1438,12 @@ public class Parser { ...@@ -1433,10 +1438,12 @@ public class Parser {
indexHints = parseIndexHints(table); indexHints = parseIndexHints(table);
} else { } else {
alias = "USE"; alias = "USE";
derivedColumnNames = readDerivedColumnNames();
} }
} else { } else {
alias = readFromAlias(alias); alias = readFromAlias(alias);
if (alias != null) { if (alias != null) {
derivedColumnNames = readDerivedColumnNames();
// if alias present, a second chance to parse index hints // if alias present, a second chance to parse index hints
if (readIf("USE")) { if (readIf("USE")) {
read("INDEX"); read("INDEX");
...@@ -1448,8 +1455,12 @@ public class Parser { ...@@ -1448,8 +1455,12 @@ public class Parser {
if (table.isView() && table.isTableExpression() && alias == null) { if (table.isView() && table.isTableExpression() && alias == null) {
alias = table.getName(); alias = table.getName();
} }
return new TableFilter(session, table, alias, rightsChecked, TableFilter filter = new TableFilter(session, table, alias, rightsChecked,
currentSelect, orderInFrom++, indexHints); currentSelect, orderInFrom++, indexHints);
if (derivedColumnNames != null) {
filter.setDerivedColumns(derivedColumnNames);
}
return filter;
} }
private IndexHints parseIndexHints(Table table) { private IndexHints parseIndexHints(Table table) {
...@@ -1485,6 +1496,18 @@ public class Parser { ...@@ -1485,6 +1496,18 @@ public class Parser {
return readFromAlias(alias, excludeIdentifiers); return readFromAlias(alias, excludeIdentifiers);
} }
private ArrayList<String> readDerivedColumnNames() {
if (readIf("(")) {
ArrayList<String> derivedColumnNames = New.arrayList();
do {
derivedColumnNames.add(readAliasIdentifier());
} while (readIf(","));
read(")");
return derivedColumnNames;
}
return null;
}
private Prepared parseTruncate() { private Prepared parseTruncate() {
read("TABLE"); read("TABLE");
Table table = readTableOrView(); Table table = readTableOrView();
......
...@@ -737,8 +737,9 @@ public class Select extends Query { ...@@ -737,8 +737,9 @@ public class Select extends Query {
if (filter.isNaturalJoinColumn(c)) { if (filter.isNaturalJoinColumn(c)) {
continue; continue;
} }
String name = filter.getDerivedColumnName(c);
ExpressionColumn ec = new ExpressionColumn( ExpressionColumn ec = new ExpressionColumn(
session.getDatabase(), null, alias, c.getName()); session.getDatabase(), null, alias, name != null ? name : c.getName());
expressions.add(index++, ec); expressions.add(index++, ec);
} }
return index; return index;
......
...@@ -52,6 +52,11 @@ public class SelectListColumnResolver implements ColumnResolver { ...@@ -52,6 +52,11 @@ public class SelectListColumnResolver implements ColumnResolver {
return columns; return columns;
} }
@Override
public String getDerivedColumnName(Column column) {
return null;
}
@Override @Override
public String getSchemaName() { public String getSchemaName() {
return null; return null;
......
...@@ -33,7 +33,7 @@ public class ExpressionColumn extends Expression { ...@@ -33,7 +33,7 @@ public class ExpressionColumn extends Expression {
private final Database database; private final Database database;
private final String schemaName; private final String schemaName;
private final String tableAlias; private final String tableAlias;
private final String columnName; private String columnName;
private ColumnResolver columnResolver; private ColumnResolver columnResolver;
private int queryLevel; private int queryLevel;
private Column column; private Column column;
...@@ -89,7 +89,10 @@ public class ExpressionColumn extends Expression { ...@@ -89,7 +89,10 @@ public class ExpressionColumn extends Expression {
return; return;
} }
for (Column col : resolver.getColumns()) { for (Column col : resolver.getColumns()) {
String n = col.getName(); String n = resolver.getDerivedColumnName(col);
if (n == null) {
n = col.getName();
}
if (database.equalsIdentifiers(columnName, n)) { if (database.equalsIdentifiers(columnName, n)) {
mapColumn(resolver, col, level); mapColumn(resolver, col, level);
return; return;
...@@ -253,6 +256,12 @@ public class ExpressionColumn extends Expression { ...@@ -253,6 +256,12 @@ public class ExpressionColumn extends Expression {
@Override @Override
public String getAlias() { public String getAlias() {
if (column != null) { if (column != null) {
if (columnResolver != null) {
String name = columnResolver.getDerivedColumnName(column);
if (name != null) {
return name;
}
}
return column.getName(); return column.getName();
} }
if (tableAlias != null) { if (tableAlias != null) {
......
...@@ -30,6 +30,14 @@ public interface ColumnResolver { ...@@ -30,6 +30,14 @@ public interface ColumnResolver {
*/ */
Column[] getColumns(); Column[] getColumns();
/**
* Get derived column name, or {@code null}.
*
* @param column column
* @return derived column name, or {@code null}
*/
String getDerivedColumnName(Column column);
/** /**
* Get the list of system columns, if any. * Get the list of system columns, if any.
* *
......
...@@ -42,6 +42,11 @@ public class SingleColumnResolver implements ColumnResolver { ...@@ -42,6 +42,11 @@ public class SingleColumnResolver implements ColumnResolver {
return new Column[] { column }; return new Column[] { column };
} }
@Override
public String getDerivedColumnName(Column column) {
return null;
}
@Override @Override
public String getSchemaName() { public String getSchemaName() {
return null; return null;
......
...@@ -39,7 +39,7 @@ public abstract class TableBase extends Table { ...@@ -39,7 +39,7 @@ public abstract class TableBase extends Table {
if (data.tableEngineParams != null) { if (data.tableEngineParams != null) {
this.tableEngineParams = data.tableEngineParams; this.tableEngineParams = data.tableEngineParams;
} else { } else {
this.tableEngineParams = Collections.EMPTY_LIST; this.tableEngineParams = Collections.emptyList();
} }
setTemporary(data.temporary); setTemporary(data.temporary);
Column[] cols = data.columns.toArray(new Column[0]); Column[] cols = data.columns.toArray(new Column[0]);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.table; package org.h2.table;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Parser; import org.h2.command.Parser;
...@@ -117,6 +118,8 @@ public class TableFilter implements ColumnResolver { ...@@ -117,6 +118,8 @@ public class TableFilter implements ColumnResolver {
private final int hashCode; private final int hashCode;
private final int orderInFrom; private final int orderInFrom;
private HashMap<Column, String> derivedColumnMap;
/** /**
* Create a new table filter object. * Create a new table filter object.
* *
...@@ -992,6 +995,12 @@ public class TableFilter implements ColumnResolver { ...@@ -992,6 +995,12 @@ public class TableFilter implements ColumnResolver {
return table.getColumns(); return table.getColumns();
} }
@Override
public String getDerivedColumnName(Column column) {
HashMap<Column, String> map = derivedColumnMap;
return map != null ? map.get(column) : null;
}
/** /**
* Get the system columns that this table understands. This is used for * Get the system columns that this table understands. This is used for
* compatibility with other databases. The columns are only returned if the * compatibility with other databases. The columns are only returned if the
...@@ -1056,6 +1065,30 @@ public class TableFilter implements ColumnResolver { ...@@ -1056,6 +1065,30 @@ public class TableFilter implements ColumnResolver {
this.alias = alias; this.alias = alias;
} }
/**
* Set derived column list.
*
* @param derivedColumnNames names of derived columns
*/
public void setDerivedColumns(ArrayList<String> derivedColumnNames) {
Column[] columns = getColumns();
int count = columns.length;
if (count != derivedColumnNames.size()) {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
}
HashMap<Column, String> map = new HashMap<>(count);
for (int i = 0; i < count; i++) {
String alias = derivedColumnNames.get(i);
for (int j = 0; j < i; j++) {
if (alias.equals(derivedColumnNames.get(j))) {
throw DbException.get(ErrorCode.DUPLICATE_COLUMN_NAME_1, alias);
}
}
map.put(columns[i], alias);
}
this.derivedColumnMap = map;
}
@Override @Override
public Expression optimize(ExpressionColumn expressionColumn, Column column) { public Expression optimize(ExpressionColumn expressionColumn, Column column) {
return expressionColumn; return expressionColumn;
......
...@@ -712,7 +712,7 @@ public class TestIndex extends TestBase { ...@@ -712,7 +712,7 @@ public class TestIndex extends TestBase {
public static ResultSet testFunctionIndexFunction() { public static ResultSet testFunctionIndexFunction() {
// There are additional callers like JdbcConnection.prepareCommand() and // There are additional callers like JdbcConnection.prepareCommand() and
// CommandContainer.recompileIfReqired() // CommandContainer.recompileIfRequired()
for (StackTraceElement element : Thread.currentThread().getStackTrace()) { for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getClassName().startsWith(Select.class.getName())) { if (element.getClassName().startsWith(Select.class.getName())) {
testFunctionIndexCounter++; testFunctionIndexCounter++;
......
...@@ -82,6 +82,7 @@ public class TestScript extends TestBase { ...@@ -82,6 +82,7 @@ public class TestScript extends TestBase {
reconnectOften = !config.memory && config.big; reconnectOften = !config.memory && config.big;
testScript("testScript.sql"); testScript("testScript.sql");
testScript("derived-column-names.sql");
testScript("joins.sql"); testScript("joins.sql");
testScript("altertable-index-reuse.sql"); testScript("altertable-index-reuse.sql");
testScript("query-optimisations.sql"); testScript("query-optimisations.sql");
......
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
SELECT * FROM (VALUES(1, 2));
> C1 C2
> -- --
> 1 2
> rows: 1
SELECT * FROM (VALUES(1, 2)) AS T;
> C1 C2
> -- --
> 1 2
> rows: 1
SELECT * FROM (VALUES(1, 2)) AS T(A, B);
> A B
> - -
> 1 2
> rows: 1
SELECT A AS A1, B AS B1 FROM (VALUES(1, 2)) AS T(A, B);
> A1 B1
> -- --
> 1 2
> rows: 1
SELECT A AS A1, B AS B1 FROM (VALUES(1, 2)) AS T(A, B) WHERE A <> B;
> A1 B1
> -- --
> 1 2
> rows: 1
SELECT A AS A1, B AS B1 FROM (VALUES(1, 2)) AS T(A, B) WHERE A1 <> B1;
> exception
SELECT * FROM (VALUES(1, 2)) AS T(A);
> exception
SELECT * FROM (VALUES(1, 2)) AS T(A, a);
> exception
SELECT * FROM (VALUES(1, 2)) AS T(A, B, C);
> exception
SELECT V AS V1, A AS A1, B AS B1 FROM (VALUES (1)) T1(V) INNER JOIN (VALUES(1, 2)) T2(A, B) ON V = A;
> V1 A1 B1
> -- -- --
> 1 1 2
> rows: 1
CREATE TABLE TEST(I INT, J INT);
> ok
CREATE INDEX TEST_I_IDX ON TEST(I);
> ok
INSERT INTO TEST VALUES (1, 2);
> update count: 1
SELECT * FROM (TEST) AS T(A, B);
> A B
> - -
> 1 2
> rows: 1
SELECT * FROM TEST AS T(A, B);
> A B
> - -
> 1 2
> rows: 1
SELECT * FROM TEST AS T(A, B) USE INDEX (TEST_I_IDX);
> A B
> - -
> 1 2
> rows: 1
DROP TABLE TEST;
> ok
...@@ -781,11 +781,11 @@ INSERT INTO T5 VALUES (1); ...@@ -781,11 +781,11 @@ INSERT INTO T5 VALUES (1);
INSERT INTO T5 VALUES (NULL); INSERT INTO T5 VALUES (NULL);
SELECT T1.X1, T2.X2, T3.X3, T4.X4, T5.X5 FROM ( SELECT T1.X1, T2.X2, T3.X3, T4.X4, T5.X5 FROM (
T1 INNER JOIN ( T1 INNER JOIN (
T2 LEFT OUTER JOIN ( T2 LEFT OUTER JOIN (
T3 INNER JOIN T4 ON T3.X3 = T4.X4 T3 INNER JOIN T4 ON T3.X3 = T4.X4
) ON T2.X2 = T4.X4 ) ON T2.X2 = T4.X4
) ON T1.X1 = T2.X2 ) ON T1.X1 = T2.X2
) INNER JOIN T5 ON T2.X2 = T5.X5; ) INNER JOIN T5 ON T2.X2 = T5.X5;
> X1 X2 X3 X4 X5 > X1 X2 X3 X4 X5
> -- -- -- -- -- > -- -- -- -- --
......
...@@ -765,4 +765,4 @@ jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt d ...@@ -765,4 +765,4 @@ jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt d
interpolated thead interpolated thead
die weekdiff osx subprocess dow proleptic microsecond microseconds divisible cmp denormalized suppressed saturated mcs die weekdiff osx subprocess dow proleptic microsecond microseconds divisible cmp denormalized suppressed saturated mcs
london dfs weekdays intermittent looked msec tstz africa monrovia asia tokyo weekday london dfs weekdays intermittent looked msec tstz africa monrovia asia tokyo weekday joi callers
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论