提交 d98ad361 authored 作者: Thomas Mueller's avatar Thomas Mueller

VALUES is now supported as a standalone command and as a table source: SELECT *…

VALUES is now supported as a standalone command and as a table source: SELECT * FROM (VALUES(1, 'Hello'), (2, 'World')) AS V;
上级 ff7bcccc
......@@ -1916,7 +1916,7 @@ ID + 20
"
"Other Grammar","Table Expression","
{ [ schemaName. ] tableName | ( select ) } [ [ AS ] newTableAlias ]
{ [ schemaName. ] tableName | ( select ) | valuesExpression } [ [ AS ] newTableAlias ]
[ { { LEFT | RIGHT } [ OUTER ] | [ INNER ] | CROSS | NATURAL }
JOIN tableExpression [ ON expression ] ]
","
......@@ -1927,6 +1927,15 @@ columns with the same name.
TEST AS T LEFT JOIN TEST AS T1 ON T.ID = T1.ID
"
"Other Grammar","Values Expression","
VALUES { ( expression [,...] ) } [,...]
","
A list of rows that can be used like a table.
The column list of the resulting table is C1, C2, and so on.
","
SELECT * FROM (VALUES(1, 'Hello'), (2, 'World')) AS V;
"
"Other Grammar","Term","
value
| columnName
......@@ -3122,7 +3131,7 @@ CURRENT_TIMESTAMP()
"
"Functions (Time and Date)","DATEADD","
DATEADD(unitString, addInt, timestamp)
{ DATEADD| TIMESTAMPADD } (unitString, addInt, timestamp)
","
Adds units to a timestamp. The string indicates the unit.
Use negative values to subtract units.
......@@ -3139,7 +3148,6 @@ Returns the the number of crossed unit boundaries between two timestamps.
This method returns a long.
The string indicates the unit.
The same units as in the EXTRACT function are supported.
TIMESTAMPDIFF is supported for MySQL compatibility.
","
DATEDIFF('YEAR', T1.CREATED, T2.CREATED)
"
......
......@@ -426,7 +426,7 @@ public class Parser {
case 'v':
case 'V':
if (readIf("VALUES")) {
c = parseCall();
c = parseValues();
}
break;
case 'w':
......@@ -1037,6 +1037,8 @@ public class Parser {
}
return top;
}
} else if (readIf("VALUES")) {
table = parseValuesTable().getTable();
} else {
String tableName = readIdentifierWithSchema(null);
Schema schema = getSchema();
......@@ -2169,6 +2171,7 @@ public class Parser {
read(")");
break;
}
case Function.DATE_ADD:
case Function.DATE_DIFF: {
if (Function.isDatePart(currentToken)) {
function.setParameter(0, ValueExpression.get(ValueString.get(currentToken)));
......@@ -3874,6 +3877,91 @@ public class Parser {
return command;
}
private Select parseValues() {
Select command = new Select(session);
currentSelect = command;
TableFilter filter = parseValuesTable();
ArrayList<Expression> list = New.arrayList();
list.add(new Wildcard(null, null));
command.setExpressions(list);
command.addTableFilter(filter, true);
command.init();
return command;
}
private TableFilter parseValuesTable() {
Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN);
TableFunction tf = (TableFunction) Function.getFunction(database, "TABLE");
ArrayList<Column> columns = New.arrayList();
ArrayList<ArrayList<Expression>> rows = New.arrayList();
do {
int i = 0;
ArrayList<Expression> row = New.arrayList();
boolean multiColumn = readIf("(");
do {
Expression expr = readExpression();
expr = expr.optimize(session);
int type = expr.getType();
long prec;
int scale, displaySize;
Column column;
String columnName = "C" + (i + 1);
if (rows.size() == 0) {
if (type == Value.UNKNOWN) {
type = Value.STRING;
}
DataType dt = DataType.getDataType(type);
prec = dt.defaultPrecision;
scale = dt.defaultScale;
displaySize = dt.defaultDisplaySize;
column = new Column(columnName, type, prec, scale, displaySize);
columns.add(column);
}
prec = expr.getPrecision();
scale = expr.getScale();
displaySize = expr.getDisplaySize();
Column c = columns.get(i);
type = Value.getHigherOrder(c.getType(), type);
prec = Math.max(c.getPrecision(), prec);
scale = Math.max(c.getScale(), scale);
displaySize = Math.max(c.getDisplaySize(), displaySize);
column = new Column(columnName, type, prec, scale, displaySize);
columns.set(i, column);
row.add(expr);
i++;
} while (multiColumn && readIf(","));
if (multiColumn) {
read(")");
}
rows.add(row);
} while (readIf(","));
int columnCount = columns.size();
int rowCount = rows.size();
for (int i = 0; i < rowCount; i++) {
if (rows.get(i).size() != columnCount) {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH, "row " + (i + 1));
}
}
for (int i = 0; i < columnCount; i++) {
Column c = columns.get(i);
if (c.getType() == Value.UNKNOWN) {
c = new Column(c.getName(), Value.STRING, 0, 0, 0);
columns.set(i, c);
}
Expression[] array = new Expression[rowCount];
for (int j = 0; j < rowCount; j++) {
array[j] = rows.get(j).get(i);
}
ExpressionList list = new ExpressionList(array);
tf.setParameter(i, list);
}
tf.setColumns(columns);
tf.doneWithParameters();
Table table = new FunctionTable(mainSchema, session, tf, tf);
TableFilter filter = new TableFilter(session, table, null, rightsChecked, currentSelect);
return filter;
}
private Call parseCall() {
Call command = new Call(session);
currentPrepared = command;
......
......@@ -44,6 +44,7 @@ public class TestPreparedStatement extends TestBase {
public void test() throws Exception {
deleteDb("preparedStatement");
Connection conn = getConnection("preparedStatement");
testValues(conn);
testToString(conn);
testExecuteUpdateCall(conn);
testPrepareExecute(conn);
......@@ -79,6 +80,34 @@ public class TestPreparedStatement extends TestBase {
deleteDb("preparedStatement");
}
private void testValues(Connection conn) throws SQLException {
PreparedStatement prep = conn.prepareStatement("values(?, ?)");
prep.setInt(1, 1);
prep.setString(2, "Hello");
ResultSet rs = prep.executeQuery();
rs.next();
assertEquals(1, rs.getInt(1));
assertEquals("Hello", rs.getString(2));
prep = conn.prepareStatement("select * from values(?, ?), (2, 'World!')");
prep.setInt(1, 1);
prep.setString(2, "Hello");
rs = prep.executeQuery();
rs.next();
assertEquals(1, rs.getInt(1));
assertEquals("Hello", rs.getString(2));
rs.next();
assertEquals(2, rs.getInt(1));
assertEquals("World!", rs.getString(2));
prep = conn.prepareStatement("values 1, 2");
rs = prep.executeQuery();
rs.next();
assertEquals(1, rs.getInt(1));
rs.next();
assertEquals(2, rs.getInt(1));
}
private void testToString(Connection conn) throws SQLException {
PreparedStatement prep = conn.prepareStatement("call 1");
assertTrue(prep.toString().endsWith(": call 1"));
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论