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
"
"Other Grammar","Table Expression","
{ [ schemaName. ] tableName | ( select ) | valuesExpression } [ [ AS ] newTableAlias ]
{ [ schemaName. ] tableName | ( select ) | valuesExpression }
[ [ AS ] newTableAlias [ ( columnName [,...] ) ] ]
[ USE INDEX ([ indexName [,...] ]) ]
[ { { LEFT | RIGHT } [ OUTER ] | [ INNER ] | CROSS | NATURAL }
JOIN tableExpression [ ON expression ] ]
......
......@@ -1374,6 +1374,10 @@ public class Parser {
alias = readFromAlias(null);
if (alias != null) {
top.setAlias(alias);
ArrayList<String> derivedColumnNames = readDerivedColumnNames();
if (derivedColumnNames != null) {
top.setDerivedColumns(derivedColumnNames);
}
}
return top;
}
......@@ -1426,6 +1430,7 @@ public class Parser {
table = readTableOrView(tableName);
}
}
ArrayList<String> derivedColumnNames = null;
IndexHints indexHints = null;
// for backward compatibility, handle case where USE is a table alias
if (readIf("USE")) {
......@@ -1433,10 +1438,12 @@ public class Parser {
indexHints = parseIndexHints(table);
} else {
alias = "USE";
derivedColumnNames = readDerivedColumnNames();
}
} else {
alias = readFromAlias(alias);
if (alias != null) {
derivedColumnNames = readDerivedColumnNames();
// if alias present, a second chance to parse index hints
if (readIf("USE")) {
read("INDEX");
......@@ -1448,8 +1455,12 @@ public class Parser {
if (table.isView() && table.isTableExpression() && alias == null) {
alias = table.getName();
}
return new TableFilter(session, table, alias, rightsChecked,
TableFilter filter = new TableFilter(session, table, alias, rightsChecked,
currentSelect, orderInFrom++, indexHints);
if (derivedColumnNames != null) {
filter.setDerivedColumns(derivedColumnNames);
}
return filter;
}
private IndexHints parseIndexHints(Table table) {
......@@ -1485,6 +1496,18 @@ public class Parser {
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() {
read("TABLE");
Table table = readTableOrView();
......
......@@ -737,8 +737,9 @@ public class Select extends Query {
if (filter.isNaturalJoinColumn(c)) {
continue;
}
String name = filter.getDerivedColumnName(c);
ExpressionColumn ec = new ExpressionColumn(
session.getDatabase(), null, alias, c.getName());
session.getDatabase(), null, alias, name != null ? name : c.getName());
expressions.add(index++, ec);
}
return index;
......
......@@ -52,6 +52,11 @@ public class SelectListColumnResolver implements ColumnResolver {
return columns;
}
@Override
public String getDerivedColumnName(Column column) {
return null;
}
@Override
public String getSchemaName() {
return null;
......
......@@ -33,7 +33,7 @@ public class ExpressionColumn extends Expression {
private final Database database;
private final String schemaName;
private final String tableAlias;
private final String columnName;
private String columnName;
private ColumnResolver columnResolver;
private int queryLevel;
private Column column;
......@@ -89,7 +89,10 @@ public class ExpressionColumn extends Expression {
return;
}
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)) {
mapColumn(resolver, col, level);
return;
......@@ -253,6 +256,12 @@ public class ExpressionColumn extends Expression {
@Override
public String getAlias() {
if (column != null) {
if (columnResolver != null) {
String name = columnResolver.getDerivedColumnName(column);
if (name != null) {
return name;
}
}
return column.getName();
}
if (tableAlias != null) {
......
......@@ -30,6 +30,14 @@ public interface ColumnResolver {
*/
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.
*
......
......@@ -42,6 +42,11 @@ public class SingleColumnResolver implements ColumnResolver {
return new Column[] { column };
}
@Override
public String getDerivedColumnName(Column column) {
return null;
}
@Override
public String getSchemaName() {
return null;
......
......@@ -39,7 +39,7 @@ public abstract class TableBase extends Table {
if (data.tableEngineParams != null) {
this.tableEngineParams = data.tableEngineParams;
} else {
this.tableEngineParams = Collections.EMPTY_LIST;
this.tableEngineParams = Collections.emptyList();
}
setTemporary(data.temporary);
Column[] cols = data.columns.toArray(new Column[0]);
......
......@@ -6,6 +6,7 @@
package org.h2.table;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import org.h2.api.ErrorCode;
import org.h2.command.Parser;
......@@ -117,6 +118,8 @@ public class TableFilter implements ColumnResolver {
private final int hashCode;
private final int orderInFrom;
private HashMap<Column, String> derivedColumnMap;
/**
* Create a new table filter object.
*
......@@ -992,6 +995,12 @@ public class TableFilter implements ColumnResolver {
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
* compatibility with other databases. The columns are only returned if the
......@@ -1056,6 +1065,30 @@ public class TableFilter implements ColumnResolver {
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
public Expression optimize(ExpressionColumn expressionColumn, Column column) {
return expressionColumn;
......
......@@ -712,7 +712,7 @@ public class TestIndex extends TestBase {
public static ResultSet testFunctionIndexFunction() {
// There are additional callers like JdbcConnection.prepareCommand() and
// CommandContainer.recompileIfReqired()
// CommandContainer.recompileIfRequired()
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getClassName().startsWith(Select.class.getName())) {
testFunctionIndexCounter++;
......
......@@ -82,6 +82,7 @@ public class TestScript extends TestBase {
reconnectOften = !config.memory && config.big;
testScript("testScript.sql");
testScript("derived-column-names.sql");
testScript("joins.sql");
testScript("altertable-index-reuse.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);
INSERT INTO T5 VALUES (NULL);
SELECT T1.X1, T2.X2, T3.X3, T4.X4, T5.X5 FROM (
T1 INNER JOIN (
T2 LEFT OUTER JOIN (
T3 INNER JOIN T4 ON T3.X3 = T4.X4
) ON T2.X2 = T4.X4
) ON T1.X1 = T2.X2
T1 INNER JOIN (
T2 LEFT OUTER JOIN (
T3 INNER JOIN T4 ON T3.X3 = T4.X4
) ON T2.X2 = T4.X4
) ON T1.X1 = T2.X2
) INNER JOIN T5 ON T2.X2 = T5.X5;
> X1 X2 X3 X4 X5
> -- -- -- -- --
......
......@@ -765,4 +765,4 @@ jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt d
interpolated thead
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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论