Unverified 提交 c3befc2c authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1613 from katzyn/table

Add explicit table query
...@@ -238,6 +238,19 @@ Lists the schemas, tables, or the columns of a table. ...@@ -238,6 +238,19 @@ Lists the schemas, tables, or the columns of a table.
SHOW TABLES SHOW TABLES
" "
"Commands (DML)","Explicit TABLE","
TABLE [schemaName.]tableName
","
Selects data from a table.
This command is an equivalent to SELECT * FROM tableName.
FROM, WHERE, GROUP BY, HAVING, and WINDOW clauses from the SELECT command are not allowed.
","
TABLE TEST;
TABLE TEST ORDER BY ID FETCH FIRST ROW ONLY;
"
"Commands (DML)","WITH"," "Commands (DML)","WITH","
WITH [ RECURSIVE ] { name [( columnName [,...] )] AS ( select ) [,...] } WITH [ RECURSIVE ] { name [( columnName [,...] )] AS ( select ) [,...] }
{ select | insert | update | merge | delete | createTable } { select | insert | update | merge | delete | createTable }
...@@ -4538,9 +4551,10 @@ CURRENT_DATE ...@@ -4538,9 +4551,10 @@ CURRENT_DATE
" "
"Functions (Time and Date)","CURRENT_TIME"," "Functions (Time and Date)","CURRENT_TIME","
{ CURRENT_TIME [ (int) ] | LOCALTIME [ (int) ] | CURTIME([ int ]) } CURRENT_TIME [ (int) ]
"," ","
Returns the current time. Returns the current time.
The returned value does not have time zone information, because TIME WITH TIME ZONE data type is not supported in H2.
If fractional seconds precision is specified it should be from 0 to 9, 0 is default. If fractional seconds precision is specified it should be from 0 to 9, 0 is default.
The specified value can be used only to limit precision of a result. The specified value can be used only to limit precision of a result.
The actual maximum available precision depends on operating system and JVM and can be 3 (milliseconds) or higher. The actual maximum available precision depends on operating system and JVM and can be 3 (milliseconds) or higher.
...@@ -4549,8 +4563,7 @@ These methods always return the same value within a transaction (default) ...@@ -4549,8 +4563,7 @@ These methods always return the same value within a transaction (default)
or within a command depending on database mode. or within a command depending on database mode.
"," ","
CURRENT_TIME CURRENT_TIME
LOCALTIME CURRENT_TIME(9)
LOCALTIME(9)
" "
"Functions (Time and Date)","CURRENT_TIMESTAMP"," "Functions (Time and Date)","CURRENT_TIMESTAMP","
...@@ -4569,10 +4582,25 @@ CURRENT_TIMESTAMP ...@@ -4569,10 +4582,25 @@ CURRENT_TIMESTAMP
CURRENT_TIMESTAMP(9) CURRENT_TIMESTAMP(9)
" "
"Functions (Time and Date)","LOCALTIME","
{ LOCALTIME [ (int) ] | CURTIME([ int ]) }
","
Returns the current time.
If fractional seconds precision is specified it should be from 0 to 9, 0 is default.
The specified value can be used only to limit precision of a result.
The actual maximum available precision depends on operating system and JVM and can be 3 (milliseconds) or higher.
Higher precision is not available before Java 9.
These methods always return the same value within a transaction (default)
or within a command depending on database mode.
","
LOCALTIME
LOCALTIME(9)
"
"Functions (Time and Date)","LOCALTIMESTAMP"," "Functions (Time and Date)","LOCALTIMESTAMP","
{ LOCALTIMESTAMP [ (int) ] | NOW( [ int ] ) } { LOCALTIMESTAMP [ (int) ] | NOW( [ int ] ) }
"," ","
Returns the current timestamp. Returns the current timestamp without time zone.
If fractional seconds precision is specified it should be from 0 to 9, 6 is default. If fractional seconds precision is specified it should be from 0 to 9, 6 is default.
The specified value can be used only to limit precision of a result. The specified value can be used only to limit precision of a result.
The actual maximum available precision depends on operating system and JVM and can be 3 (milliseconds) or higher. The actual maximum available precision depends on operating system and JVM and can be 3 (milliseconds) or higher.
......
...@@ -481,8 +481,8 @@ EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING, ...@@ -481,8 +481,8 @@ EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING,
IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE, IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE,
LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL,
OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE, OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE,
SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, VALUES, SYSTIME, SYSTIMESTAMP, TABLE, TODAY, TOP, TRUE, UNION, UNIQUE,
WHERE, WINDOW, WITH VALUES, WHERE, WINDOW, WITH
</code> </code>
</p><p> </p><p>
Certain words of this list are keywords because they are functions that can be used without '()', Certain words of this list are keywords because they are functions that can be used without '()',
......
...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>PR #1613: Add explicit table query
</li>
<li>Issue #1608: ARRAY and row value expression should not be the same <li>Issue #1608: ARRAY and row value expression should not be the same
</li> </li>
<li>Issue #1606: Quantified comparison predicate doesn't work correctly on primary key column <li>Issue #1606: Quantified comparison predicate doesn't work correctly on primary key column
......
...@@ -52,6 +52,7 @@ import static org.h2.util.ParserUtil.PRIMARY; ...@@ -52,6 +52,7 @@ import static org.h2.util.ParserUtil.PRIMARY;
import static org.h2.util.ParserUtil.ROW; import static org.h2.util.ParserUtil.ROW;
import static org.h2.util.ParserUtil.ROWNUM; import static org.h2.util.ParserUtil.ROWNUM;
import static org.h2.util.ParserUtil.SELECT; import static org.h2.util.ParserUtil.SELECT;
import static org.h2.util.ParserUtil.TABLE;
import static org.h2.util.ParserUtil.TRUE; import static org.h2.util.ParserUtil.TRUE;
import static org.h2.util.ParserUtil.UNION; import static org.h2.util.ParserUtil.UNION;
import static org.h2.util.ParserUtil.UNIQUE; import static org.h2.util.ParserUtil.UNIQUE;
...@@ -251,7 +252,7 @@ import org.h2.value.ValueTimestampTimeZone; ...@@ -251,7 +252,7 @@ import org.h2.value.ValueTimestampTimeZone;
public class Parser { public class Parser {
private static final String WITH_STATEMENT_SUPPORTS_LIMITED_SUB_STATEMENTS = private static final String WITH_STATEMENT_SUPPORTS_LIMITED_SUB_STATEMENTS =
"WITH statement supports only SELECT, CREATE TABLE, INSERT, UPDATE, MERGE or DELETE statements"; "WITH statement supports only SELECT, TABLE, CREATE TABLE, INSERT, UPDATE, MERGE or DELETE statements";
// used during the tokenizer phase // used during the tokenizer phase
private static final int CHAR_END = 1, CHAR_VALUE = 2, CHAR_QUOTED = 3; private static final int CHAR_END = 1, CHAR_VALUE = 2, CHAR_QUOTED = 3;
...@@ -510,6 +511,8 @@ public class Parser { ...@@ -510,6 +511,8 @@ public class Parser {
"ROWNUM", "ROWNUM",
// SELECT // SELECT
"SELECT", "SELECT",
// TABLE
"TABLE",
// TRUE // TRUE
"TRUE", "TRUE",
// UNION // UNION
...@@ -745,6 +748,7 @@ public class Parser { ...@@ -745,6 +748,7 @@ public class Parser {
case OPEN_PAREN: case OPEN_PAREN:
case FROM: case FROM:
case SELECT: case SELECT:
case TABLE:
c = parseSelect(); c = parseSelect();
break; break;
case VALUES: case VALUES:
...@@ -944,7 +948,7 @@ public class Parser { ...@@ -944,7 +948,7 @@ public class Parser {
private Prepared parseAnalyze() { private Prepared parseAnalyze() {
Analyze command = new Analyze(session); Analyze command = new Analyze(session);
if (readIf("TABLE")) { if (readIf(TABLE)) {
Table table = readTableOrView(); Table table = readTableOrView();
command.setTable(table); command.setTable(table);
} }
...@@ -1436,7 +1440,20 @@ public class Parser { ...@@ -1436,7 +1440,20 @@ public class Parser {
// need to read ahead, it could be a nested union: // need to read ahead, it could be a nested union:
// ((select 1) union (select 1)) // ((select 1) union (select 1))
} }
boolean select = isToken(SELECT) || isToken(FROM) || isToken(WITH); boolean select;
switch (currentTokenType) {
case FROM:
case SELECT:
case WITH:
select = true;
break;
case TABLE:
read();
select = !readIf(OPEN_PAREN);
break;
default:
select = false;
}
parseIndex = start; parseIndex = start;
read(); read();
return select; return select;
...@@ -1761,6 +1778,9 @@ public class Parser { ...@@ -1761,6 +1778,9 @@ public class Parser {
} }
} else if (readIf(VALUES)) { } else if (readIf(VALUES)) {
table = parseValuesTable(0).getTable(); table = parseValuesTable(0).getTable();
} else if (readIf(TABLE)) {
read(OPEN_PAREN);
table = readTableFunction("TABLE", null, database.getSchema(Constants.SCHEMA_MAIN));
} else { } else {
String tableName = readIdentifierWithSchema(null); String tableName = readIdentifierWithSchema(null);
Schema schema; Schema schema;
...@@ -1801,15 +1821,7 @@ public class Parser { ...@@ -1801,15 +1821,7 @@ public class Parser {
table = new RangeTable(mainSchema, min, max, false); table = new RangeTable(mainSchema, min, max, false);
} }
} else { } else {
Expression expr = readFunction(schema, tableName); table = readTableFunction(tableName, schema, mainSchema);
if (!(expr instanceof FunctionCall)) {
throw getSyntaxError();
}
FunctionCall call = (FunctionCall) expr;
if (!call.isDeterministic()) {
recompileAlways = true;
}
table = new FunctionTable(mainSchema, session, expr, call);
} }
} else { } else {
table = readTableOrView(tableName); table = readTableOrView(tableName);
...@@ -1853,6 +1865,18 @@ public class Parser { ...@@ -1853,6 +1865,18 @@ public class Parser {
return filter; return filter;
} }
private Table readTableFunction(String tableName, Schema schema, Schema mainSchema) {
Expression expr = readFunction(schema, tableName);
if (!(expr instanceof FunctionCall)) {
throw getSyntaxError();
}
FunctionCall call = (FunctionCall) expr;
if (!call.isDeterministic()) {
recompileAlways = true;
}
return new FunctionTable(mainSchema, session, expr, call);
}
private IndexHints parseIndexHints(Table table) { private IndexHints parseIndexHints(Table table) {
read(OPEN_PAREN); read(OPEN_PAREN);
LinkedHashSet<String> indexNames = new LinkedHashSet<>(); LinkedHashSet<String> indexNames = new LinkedHashSet<>();
...@@ -1919,7 +1943,7 @@ public class Parser { ...@@ -1919,7 +1943,7 @@ public class Parser {
} }
private Prepared parseTruncate() { private Prepared parseTruncate() {
read("TABLE"); read(TABLE);
Table table = readTableOrView(); Table table = readTableOrView();
boolean restart; boolean restart;
if (readIf("CONTINUE")) { if (readIf("CONTINUE")) {
...@@ -1949,7 +1973,7 @@ public class Parser { ...@@ -1949,7 +1973,7 @@ public class Parser {
int type = 0; int type = 0;
read(ON); read(ON);
boolean column = false; boolean column = false;
if (readIf("TABLE") || readIf("VIEW")) { if (readIf(TABLE) || readIf("VIEW")) {
type = DbObject.TABLE_OR_VIEW; type = DbObject.TABLE_OR_VIEW;
} else if (readIf("COLUMN")) { } else if (readIf("COLUMN")) {
column = true; column = true;
...@@ -2016,7 +2040,7 @@ public class Parser { ...@@ -2016,7 +2040,7 @@ public class Parser {
} }
private Prepared parseDrop() { private Prepared parseDrop() {
if (readIf("TABLE")) { if (readIf(TABLE)) {
boolean ifExists = readIfExists(false); boolean ifExists = readIfExists(false);
String tableName = readIdentifierWithSchema(); String tableName = readIdentifierWithSchema();
DropTable command = new DropTable(session, getSchema()); DropTable command = new DropTable(session, getSchema());
...@@ -2316,11 +2340,18 @@ public class Parser { ...@@ -2316,11 +2340,18 @@ public class Parser {
readIf(FOR); readIf(FOR);
} }
} }
if (isToken(SELECT) || isToken(FROM) || isToken(OPEN_PAREN) || isToken(WITH)) { switch (currentTokenType) {
case FROM:
case SELECT:
case TABLE:
case WITH:
case OPEN_PAREN:
Query query = parseSelect(); Query query = parseSelect();
query.setNeverLazy(true); query.setNeverLazy(true);
command.setCommand(query); command.setCommand(query);
} else if (readIf("DELETE")) { break;
default:
if (readIf("DELETE")) {
command.setCommand(parseDelete()); command.setCommand(parseDelete());
} else if (readIf("UPDATE")) { } else if (readIf("UPDATE")) {
command.setCommand(parseUpdate()); command.setCommand(parseUpdate());
...@@ -2331,6 +2362,7 @@ public class Parser { ...@@ -2331,6 +2362,7 @@ public class Parser {
} else { } else {
throw getSyntaxError(); throw getSyntaxError();
} }
}
return command; return command;
} }
...@@ -2647,6 +2679,18 @@ public class Parser { ...@@ -2647,6 +2679,18 @@ public class Parser {
fromFirst = false; fromFirst = false;
} else if (readIf(FROM)) { } else if (readIf(FROM)) {
fromFirst = true; fromFirst = true;
} else if (readIf(TABLE)) {
int start = lastParseIndex;
Table table = readTableOrView();
Select command = new Select(session);
TableFilter filter = new TableFilter(session, table, null, rightsChecked,
command, orderInFrom++, null);
command.addTableFilter(filter, true);
ArrayList<Expression> expressions = new ArrayList<>();
expressions.add(new Wildcard(null, null));
command.setExpressions(expressions);
setSQL(command, "TABLE", start);
return command;
} else { } else {
throw getSyntaxError(); throw getSyntaxError();
} }
...@@ -3760,6 +3804,17 @@ public class Parser { ...@@ -3760,6 +3804,17 @@ public class Parser {
case WITH: case WITH:
r = new Subquery(parseSelect()); r = new Subquery(parseSelect());
break; break;
case TABLE:
int index = lastParseIndex;
read();
if (readIf(OPEN_PAREN)) {
r = readFunction(null, "TABLE");
} else {
parseIndex = index;
read();
r = new Subquery(parseSelect());
}
break;
case IDENTIFIER: case IDENTIFIER:
String name = currentToken; String name = currentToken;
if (currentTokenQuoted) { if (currentTokenQuoted) {
...@@ -4289,32 +4344,17 @@ public class Parser { ...@@ -4289,32 +4344,17 @@ public class Parser {
// TODO: why does this function allow defaultSchemaName=null - which resets // TODO: why does this function allow defaultSchemaName=null - which resets
// the parser schemaName for everyone ? // the parser schemaName for everyone ?
private String readIdentifierWithSchema(String defaultSchemaName) { private String readIdentifierWithSchema(String defaultSchemaName) {
if (currentTokenType != IDENTIFIER) { String s = readColumnIdentifier();
throw DbException.getSyntaxError(sqlCommand, parseIndex,
"identifier");
}
String s = currentToken;
read();
schemaName = defaultSchemaName; schemaName = defaultSchemaName;
if (readIf(DOT)) { if (readIf(DOT)) {
schemaName = s; schemaName = s;
if (currentTokenType != IDENTIFIER) { s = readColumnIdentifier();
throw DbException.getSyntaxError(sqlCommand, parseIndex,
"identifier");
}
s = currentToken;
read();
} }
if (currentTokenType == DOT) { if (currentTokenType == DOT) {
if (equalsToken(schemaName, database.getShortName())) { if (equalsToken(schemaName, database.getShortName())) {
read(); read();
schemaName = s; schemaName = s;
if (currentTokenType != IDENTIFIER) { s = readColumnIdentifier();
throw DbException.getSyntaxError(sqlCommand, parseIndex,
"identifier");
}
s = currentToken;
read();
} }
} }
return s; return s;
...@@ -4334,8 +4374,17 @@ public class Parser { ...@@ -4334,8 +4374,17 @@ public class Parser {
private String readColumnIdentifier() { private String readColumnIdentifier() {
if (currentTokenType != IDENTIFIER) { if (currentTokenType != IDENTIFIER) {
throw DbException.getSyntaxError(sqlCommand, parseIndex, /*
"identifier"); * Sometimes a new keywords are introduced. During metadata
* initialization phase keywords are accepted as identifiers to
* allow migration from older versions.
*
* PageStore's LobStorageBackend also needs this in databases that
* were created in 1.4.197 and older versions.
*/
if (!session.getDatabase().isStarting() || !isKeyword(currentToken)) {
throw DbException.getSyntaxError(sqlCommand, parseIndex, "identifier");
}
} }
String s = currentToken; String s = currentToken;
read(); read();
...@@ -5592,22 +5641,22 @@ public class Parser { ...@@ -5592,22 +5641,22 @@ public class Parser {
if (readIf("LINKED")) { if (readIf("LINKED")) {
return parseCreateLinkedTable(true, false, force); return parseCreateLinkedTable(true, false, force);
} }
read("TABLE"); read(TABLE);
return parseCreateTable(true, false, cached); return parseCreateTable(true, false, cached);
} else if (readIf("GLOBAL")) { } else if (readIf("GLOBAL")) {
read("TEMPORARY"); read("TEMPORARY");
if (readIf("LINKED")) { if (readIf("LINKED")) {
return parseCreateLinkedTable(true, true, force); return parseCreateLinkedTable(true, true, force);
} }
read("TABLE"); read(TABLE);
return parseCreateTable(true, true, cached); return parseCreateTable(true, true, cached);
} else if (readIf("TEMP") || readIf("TEMPORARY")) { } else if (readIf("TEMP") || readIf("TEMPORARY")) {
if (readIf("LINKED")) { if (readIf("LINKED")) {
return parseCreateLinkedTable(true, true, force); return parseCreateLinkedTable(true, true, force);
} }
read("TABLE"); read(TABLE);
return parseCreateTable(true, true, cached); return parseCreateTable(true, true, cached);
} else if (readIf("TABLE")) { } else if (readIf(TABLE)) {
if (!cached && !memory) { if (!cached && !memory) {
cached = database.getDefaultTableType() == Table.TYPE_CACHED; cached = database.getDefaultTableType() == Table.TYPE_CACHED;
} }
...@@ -6110,10 +6159,17 @@ public class Parser { ...@@ -6110,10 +6159,17 @@ public class Parser {
parentheses++; parentheses++;
} }
if (isToken(SELECT)) { if (isToken(SELECT)) {
Query query = parseSelectUnion(); p = parseWithQuery();
query.setPrepareAlways(true); } else if (isToken(TABLE)) {
query.setNeverLazy(true); int index = lastParseIndex;
p = query; read();
if (!isToken(OPEN_PAREN)) {
parseIndex = index;
read();
p = parseWithQuery();
} else {
throw DbException.get(ErrorCode.SYNTAX_ERROR_1, WITH_STATEMENT_SUPPORTS_LIMITED_SUB_STATEMENTS);
}
} else if (readIf("INSERT")) { } else if (readIf("INSERT")) {
p = parseInsert(); p = parseInsert();
p.setPrepareAlways(true); p.setPrepareAlways(true);
...@@ -6127,7 +6183,7 @@ public class Parser { ...@@ -6127,7 +6183,7 @@ public class Parser {
p = parseDelete(); p = parseDelete();
p.setPrepareAlways(true); p.setPrepareAlways(true);
} else if (readIf("CREATE")) { } else if (readIf("CREATE")) {
if (!isToken("TABLE")) { if (!isToken(TABLE)) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_1, throw DbException.get(ErrorCode.SYNTAX_ERROR_1,
WITH_STATEMENT_SUPPORTS_LIMITED_SUB_STATEMENTS); WITH_STATEMENT_SUPPORTS_LIMITED_SUB_STATEMENTS);
...@@ -6150,6 +6206,13 @@ public class Parser { ...@@ -6150,6 +6206,13 @@ public class Parser {
return p; return p;
} }
private Prepared parseWithQuery() {
Query query = parseSelectUnion();
query.setPrepareAlways(true);
query.setNeverLazy(true);
return query;
}
private TableView parseSingleCommonTableExpression(boolean isTemporary) { private TableView parseSingleCommonTableExpression(boolean isTemporary) {
String cteViewName = readIdentifierWithSchema(); String cteViewName = readIdentifierWithSchema();
Schema schema = getSchema(); Schema schema = getSchema();
...@@ -6328,7 +6391,7 @@ public class Parser { ...@@ -6328,7 +6391,7 @@ public class Parser {
} }
private Prepared parseAlter() { private Prepared parseAlter() {
if (readIf("TABLE")) { if (readIf(TABLE)) {
return parseAlterTable(); return parseAlterTable();
} else if (readIf("USER")) { } else if (readIf("USER")) {
return parseAlterUser(); return parseAlterUser();
...@@ -6864,7 +6927,7 @@ public class Parser { ...@@ -6864,7 +6927,7 @@ public class Parser {
schemaNames.add(readUniqueIdentifier()); schemaNames.add(readUniqueIdentifier());
} while (readIf(COMMA)); } while (readIf(COMMA));
command.setSchemaNames(schemaNames); command.setSchemaNames(schemaNames);
} else if (readIf("TABLE")) { } else if (readIf(TABLE)) {
ArrayList<Table> tables = Utils.newSmallArrayList(); ArrayList<Table> tables = Utils.newSmallArrayList();
do { do {
tables.add(readTableOrView()); tables.add(readTableOrView());
...@@ -7506,7 +7569,7 @@ public class Parser { ...@@ -7506,7 +7569,7 @@ public class Parser {
private CreateLinkedTable parseCreateLinkedTable(boolean temp, private CreateLinkedTable parseCreateLinkedTable(boolean temp,
boolean globalTemp, boolean force) { boolean globalTemp, boolean force) {
read("TABLE"); read(TABLE);
boolean ifNotExists = readIfNotExists(); boolean ifNotExists = readIfNotExists();
String tableName = readIdentifierWithSchema(); String tableName = readIdentifierWithSchema();
CreateLinkedTable command = new CreateLinkedTable(session, getSchema()); CreateLinkedTable command = new CreateLinkedTable(session, getSchema());
......
...@@ -222,7 +222,7 @@ public class Update extends Prepared { ...@@ -222,7 +222,7 @@ public class Update extends Prepared {
builder.append(",\n "); builder.append(",\n ");
} }
Column c = columns.get(i); Column c = columns.get(i);
builder.append(c.getName()).append(" = "); builder.append(c.getSQL()).append(" = ");
expressionMap.get(c).getSQL(builder); expressionMap.get(c).getSQL(builder);
} }
if (condition != null) { if (condition != null) {
......
...@@ -110,8 +110,8 @@ public class FullText { ...@@ -110,8 +110,8 @@ public class FullText {
stat.execute("CREATE SCHEMA IF NOT EXISTS " + SCHEMA); stat.execute("CREATE SCHEMA IF NOT EXISTS " + SCHEMA);
stat.execute("CREATE TABLE IF NOT EXISTS " + SCHEMA + stat.execute("CREATE TABLE IF NOT EXISTS " + SCHEMA +
".INDEXES(ID INT AUTO_INCREMENT PRIMARY KEY, " + ".INDEXES(ID INT AUTO_INCREMENT PRIMARY KEY, " +
"SCHEMA VARCHAR, TABLE VARCHAR, COLUMNS VARCHAR, " + "SCHEMA VARCHAR, \"TABLE\" VARCHAR, COLUMNS VARCHAR, " +
"UNIQUE(SCHEMA, TABLE))"); "UNIQUE(SCHEMA, \"TABLE\"))");
stat.execute("CREATE TABLE IF NOT EXISTS " + SCHEMA + stat.execute("CREATE TABLE IF NOT EXISTS " + SCHEMA +
".WORDS(ID INT AUTO_INCREMENT PRIMARY KEY, " + ".WORDS(ID INT AUTO_INCREMENT PRIMARY KEY, " +
"NAME VARCHAR, UNIQUE(NAME))"); "NAME VARCHAR, UNIQUE(NAME))");
...@@ -176,7 +176,7 @@ public class FullText { ...@@ -176,7 +176,7 @@ public class FullText {
String table, String columnList) throws SQLException { String table, String columnList) throws SQLException {
init(conn); init(conn);
PreparedStatement prep = conn.prepareStatement("INSERT INTO " + SCHEMA PreparedStatement prep = conn.prepareStatement("INSERT INTO " + SCHEMA
+ ".INDEXES(SCHEMA, TABLE, COLUMNS) VALUES(?, ?, ?)"); + ".INDEXES(SCHEMA, \"TABLE\", COLUMNS) VALUES(?, ?, ?)");
prep.setString(1, schema); prep.setString(1, schema);
prep.setString(2, table); prep.setString(2, table);
prep.setString(3, columnList); prep.setString(3, columnList);
...@@ -221,7 +221,7 @@ public class FullText { ...@@ -221,7 +221,7 @@ public class FullText {
throws SQLException { throws SQLException {
init(conn); init(conn);
PreparedStatement prep = conn.prepareStatement("SELECT ID FROM " + SCHEMA PreparedStatement prep = conn.prepareStatement("SELECT ID FROM " + SCHEMA
+ ".INDEXES WHERE SCHEMA=? AND TABLE=?"); + ".INDEXES WHERE SCHEMA=? AND \"TABLE\"=?");
prep.setString(1, schema); prep.setString(1, schema);
prep.setString(2, table); prep.setString(2, table);
ResultSet rs = prep.executeQuery(); ResultSet rs = prep.executeQuery();
...@@ -929,7 +929,7 @@ public class FullText { ...@@ -929,7 +929,7 @@ public class FullText {
ArrayList<String> indexList = Utils.newSmallArrayList(); ArrayList<String> indexList = Utils.newSmallArrayList();
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = conn.prepareStatement(
"SELECT ID, COLUMNS FROM " + SCHEMA + ".INDEXES" + "SELECT ID, COLUMNS FROM " + SCHEMA + ".INDEXES" +
" WHERE SCHEMA=? AND TABLE=?"); " WHERE SCHEMA=? AND \"TABLE\"=?");
prep.setString(1, schemaName); prep.setString(1, schemaName);
prep.setString(2, tableName); prep.setString(2, tableName);
rs = prep.executeQuery(); rs = prep.executeQuery();
......
...@@ -114,8 +114,8 @@ public class FullTextLucene extends FullText { ...@@ -114,8 +114,8 @@ public class FullTextLucene extends FullText {
try (Statement stat = conn.createStatement()) { try (Statement stat = conn.createStatement()) {
stat.execute("CREATE SCHEMA IF NOT EXISTS " + SCHEMA); stat.execute("CREATE SCHEMA IF NOT EXISTS " + SCHEMA);
stat.execute("CREATE TABLE IF NOT EXISTS " + SCHEMA + stat.execute("CREATE TABLE IF NOT EXISTS " + SCHEMA +
".INDEXES(SCHEMA VARCHAR, TABLE VARCHAR, " + ".INDEXES(SCHEMA VARCHAR, \"TABLE\" VARCHAR, " +
"COLUMNS VARCHAR, PRIMARY KEY(SCHEMA, TABLE))"); "COLUMNS VARCHAR, PRIMARY KEY(SCHEMA, \"TABLE\"))");
stat.execute("CREATE ALIAS IF NOT EXISTS FTL_CREATE_INDEX FOR \"" + stat.execute("CREATE ALIAS IF NOT EXISTS FTL_CREATE_INDEX FOR \"" +
FullTextLucene.class.getName() + ".createIndex\""); FullTextLucene.class.getName() + ".createIndex\"");
stat.execute("CREATE ALIAS IF NOT EXISTS FTL_DROP_INDEX FOR \"" + stat.execute("CREATE ALIAS IF NOT EXISTS FTL_DROP_INDEX FOR \"" +
...@@ -144,7 +144,7 @@ public class FullTextLucene extends FullText { ...@@ -144,7 +144,7 @@ public class FullTextLucene extends FullText {
String table, String columnList) throws SQLException { String table, String columnList) throws SQLException {
init(conn); init(conn);
PreparedStatement prep = conn.prepareStatement("INSERT INTO " + SCHEMA PreparedStatement prep = conn.prepareStatement("INSERT INTO " + SCHEMA
+ ".INDEXES(SCHEMA, TABLE, COLUMNS) VALUES(?, ?, ?)"); + ".INDEXES(SCHEMA, \"TABLE\", COLUMNS) VALUES(?, ?, ?)");
prep.setString(1, schema); prep.setString(1, schema);
prep.setString(2, table); prep.setString(2, table);
prep.setString(3, columnList); prep.setString(3, columnList);
...@@ -166,7 +166,7 @@ public class FullTextLucene extends FullText { ...@@ -166,7 +166,7 @@ public class FullTextLucene extends FullText {
init(conn); init(conn);
PreparedStatement prep = conn.prepareStatement("DELETE FROM " + SCHEMA PreparedStatement prep = conn.prepareStatement("DELETE FROM " + SCHEMA
+ ".INDEXES WHERE SCHEMA=? AND TABLE=?"); + ".INDEXES WHERE SCHEMA=? AND \"TABLE\"=?");
prep.setString(1, schema); prep.setString(1, schema);
prep.setString(2, table); prep.setString(2, table);
int rowCount = prep.executeUpdate(); int rowCount = prep.executeUpdate();
...@@ -548,7 +548,7 @@ public class FullTextLucene extends FullText { ...@@ -548,7 +548,7 @@ public class FullTextLucene extends FullText {
ArrayList<String> indexList = Utils.newSmallArrayList(); ArrayList<String> indexList = Utils.newSmallArrayList();
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = conn.prepareStatement(
"SELECT COLUMNS FROM " + SCHEMA "SELECT COLUMNS FROM " + SCHEMA
+ ".INDEXES WHERE SCHEMA=? AND TABLE=?"); + ".INDEXES WHERE SCHEMA=? AND \"TABLE\"=?");
prep.setString(1, schemaName); prep.setString(1, schemaName);
prep.setString(2, tableName); prep.setString(2, tableName);
rs = prep.executeQuery(); rs = prep.executeQuery();
......
...@@ -1553,8 +1553,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements ...@@ -1553,8 +1553,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements
* IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE, * IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE,
* LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, * LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL,
* OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE, * OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE,
* SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, VALUES, * SYSTIME, SYSTIMESTAMP, TABLE, TODAY, TOP, TRUE, UNION, UNIQUE,
* WHERE, WINDOW, WITH * VALUES, WHERE, WINDOW, WITH
* </pre> * </pre>
* *
* @return a list of additional the keywords * @return a list of additional the keywords
......
...@@ -59,6 +59,10 @@ import org.h2.value.ValueUuid; ...@@ -59,6 +59,10 @@ import org.h2.value.ValueUuid;
*/ */
public class ValueDataType implements DataType { public class ValueDataType implements DataType {
/**
* Storage type for ValueRow.
*/
private static final int ROW = 27;
private static final int INT_0_15 = 32; private static final int INT_0_15 = 32;
private static final int LONG_0_7 = 48; private static final int LONG_0_7 = 48;
private static final int DECIMAL_0_1 = 56; private static final int DECIMAL_0_1 = 56;
...@@ -74,7 +78,6 @@ public class ValueDataType implements DataType { ...@@ -74,7 +78,6 @@ public class ValueDataType implements DataType {
private static final int BYTES_0_31 = 100; private static final int BYTES_0_31 = 100;
private static final int SPATIAL_KEY_2D = 132; private static final int SPATIAL_KEY_2D = 132;
private static final int CUSTOM_DATA_TYPE = 133; private static final int CUSTOM_DATA_TYPE = 133;
private static final int ROW = 27;
final DataHandler handler; final DataHandler handler;
final CompareMode compareMode; final CompareMode compareMode;
...@@ -399,7 +402,8 @@ public class ValueDataType implements DataType { ...@@ -399,7 +402,8 @@ public class ValueDataType implements DataType {
case Value.ARRAY: case Value.ARRAY:
case Value.ROW: { case Value.ROW: {
Value[] list = ((ValueCollectionBase) v).getList(); Value[] list = ((ValueCollectionBase) v).getList();
buff.put((byte) (type == Value.ARRAY ? Value.ARRAY : ROW)).putVarInt(list.length); buff.put((byte) (type == Value.ARRAY ? Value.ARRAY : /* Special storage type for ValueRow */ ROW))
.putVarInt(list.length);
for (Value x : list) { for (Value x : list) {
writeValue(buff, x); writeValue(buff, x);
} }
...@@ -615,7 +619,8 @@ public class ValueDataType implements DataType { ...@@ -615,7 +619,8 @@ public class ValueDataType implements DataType {
} }
} }
case Value.ARRAY: case Value.ARRAY:
case ROW: { case ROW: // Special storage type for ValueRow
{
int len = readVarInt(buff); int len = readVarInt(buff);
Value[] list = new Value[len]; Value[] list = new Value[len];
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
......
...@@ -75,6 +75,10 @@ public class Data { ...@@ -75,6 +75,10 @@ public class Data {
*/ */
private static final int LENGTH_LONG = 8; private static final int LENGTH_LONG = 8;
/**
* Storage type for ValueRow.
*/
private static final int ROW = 27;
private static final int INT_0_15 = 32; private static final int INT_0_15 = 32;
private static final int LONG_0_7 = 48; private static final int LONG_0_7 = 48;
private static final int DECIMAL_0_1 = 56; private static final int DECIMAL_0_1 = 56;
...@@ -92,7 +96,6 @@ public class Data { ...@@ -92,7 +96,6 @@ public class Data {
private static final int LOCAL_DATE = 133; private static final int LOCAL_DATE = 133;
private static final int LOCAL_TIMESTAMP = 134; private static final int LOCAL_TIMESTAMP = 134;
private static final byte CUSTOM_DATA_TYPE = (byte)135; private static final byte CUSTOM_DATA_TYPE = (byte)135;
private static final int ROW = 27;
private static final long MILLIS_PER_MINUTE = 1000 * 60; private static final long MILLIS_PER_MINUTE = 1000 * 60;
...@@ -622,7 +625,7 @@ public class Data { ...@@ -622,7 +625,7 @@ public class Data {
} }
case Value.ARRAY: case Value.ARRAY:
case Value.ROW: { case Value.ROW: {
writeByte((byte) (type == Value.ARRAY ? Value.ARRAY : ROW)); writeByte((byte) (type == Value.ARRAY ? Value.ARRAY : /* Special storage type for ValueRow */ ROW));
Value[] list = ((ValueCollectionBase) v).getList(); Value[] list = ((ValueCollectionBase) v).getList();
writeVarInt(list.length); writeVarInt(list.length);
for (Value x : list) { for (Value x : list) {
...@@ -853,7 +856,8 @@ public class Data { ...@@ -853,7 +856,8 @@ public class Data {
} }
} }
case Value.ARRAY: case Value.ARRAY:
case ROW: { case ROW: // Special storage type for ValueRow
{
int len = readVarInt(); int len = readVarInt();
Value[] list = new Value[len]; Value[] list = new Value[len];
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
......
...@@ -139,10 +139,10 @@ public class LobStorageBackend implements LobStorageInterface { ...@@ -139,10 +139,10 @@ public class LobStorageBackend implements LobStorageInterface {
} }
if (create) { if (create) {
stat.execute("CREATE CACHED TABLE IF NOT EXISTS " + LOBS + stat.execute("CREATE CACHED TABLE IF NOT EXISTS " + LOBS +
"(ID BIGINT PRIMARY KEY, BYTE_COUNT BIGINT, TABLE INT) HIDDEN"); "(ID BIGINT PRIMARY KEY, BYTE_COUNT BIGINT, \"TABLE\" INT) HIDDEN");
stat.execute("CREATE INDEX IF NOT EXISTS " + stat.execute("CREATE INDEX IF NOT EXISTS " +
"INFORMATION_SCHEMA.INDEX_LOB_TABLE ON " + "INFORMATION_SCHEMA.INDEX_LOB_TABLE ON " +
LOBS + "(TABLE)"); LOBS + "(\"TABLE\")");
stat.execute("CREATE CACHED TABLE IF NOT EXISTS " + LOB_MAP + stat.execute("CREATE CACHED TABLE IF NOT EXISTS " + LOB_MAP +
"(LOB BIGINT, SEQ INT, POS BIGINT, HASH INT, " + "(LOB BIGINT, SEQ INT, POS BIGINT, HASH INT, " +
"BLOCK BIGINT, PRIMARY KEY(LOB, SEQ)) HIDDEN"); "BLOCK BIGINT, PRIMARY KEY(LOB, SEQ)) HIDDEN");
...@@ -191,7 +191,7 @@ public class LobStorageBackend implements LobStorageInterface { ...@@ -191,7 +191,7 @@ public class LobStorageBackend implements LobStorageInterface {
public void removeAllForTable(int tableId) { public void removeAllForTable(int tableId) {
init(); init();
try { try {
String sql = "SELECT ID FROM " + LOBS + " WHERE TABLE = ?"; String sql = "SELECT ID FROM " + LOBS + " WHERE \"TABLE\" = ?";
PreparedStatement prep = prepare(sql); PreparedStatement prep = prepare(sql);
prep.setInt(1, tableId); prep.setInt(1, tableId);
ResultSet rs = prep.executeQuery(); ResultSet rs = prep.executeQuery();
...@@ -414,7 +414,7 @@ public class LobStorageBackend implements LobStorageInterface { ...@@ -414,7 +414,7 @@ public class LobStorageBackend implements LobStorageInterface {
synchronized (database) { synchronized (database) {
synchronized (conn.getSession()) { synchronized (conn.getSession()) {
String sql = "INSERT INTO " + LOBS + String sql = "INSERT INTO " + LOBS +
"(ID, BYTE_COUNT, TABLE) VALUES(?, ?, ?)"; "(ID, BYTE_COUNT, \"TABLE\") VALUES(?, ?, ?)";
PreparedStatement prep = prepare(sql); PreparedStatement prep = prepare(sql);
prep.setLong(1, lobId); prep.setLong(1, lobId);
prep.setLong(2, byteCount); prep.setLong(2, byteCount);
...@@ -456,7 +456,7 @@ public class LobStorageBackend implements LobStorageInterface { ...@@ -456,7 +456,7 @@ public class LobStorageBackend implements LobStorageInterface {
reuse(sql, prep); reuse(sql, prep);
sql = "INSERT INTO " + LOBS + sql = "INSERT INTO " + LOBS +
"(ID, BYTE_COUNT, TABLE) " + "(ID, BYTE_COUNT, \"TABLE\") " +
"SELECT ?, BYTE_COUNT, ? FROM " + LOBS + "SELECT ?, BYTE_COUNT, ? FROM " + LOBS +
" WHERE ID = ?"; " WHERE ID = ?";
prep = prepare(sql); prep = prepare(sql);
......
...@@ -1568,7 +1568,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -1568,7 +1568,7 @@ public class Recover extends Tool implements DataHandler {
writer.println("DELETE FROM " + name + ";"); writer.println("DELETE FROM " + name + ";");
writer.println("INSERT INTO " + name + " SELECT * FROM " + storageName + ";"); writer.println("INSERT INTO " + name + " SELECT * FROM " + storageName + ";");
if (name.startsWith("INFORMATION_SCHEMA.LOBS")) { if (name.startsWith("INFORMATION_SCHEMA.LOBS")) {
writer.println("UPDATE " + name + " SET TABLE = " + writer.println("UPDATE " + name + " SET \"TABLE\" = " +
LobStorageFrontend.TABLE_TEMP + ";"); LobStorageFrontend.TABLE_TEMP + ";");
deleteLobs = true; deleteLobs = true;
} }
...@@ -1595,7 +1595,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -1595,7 +1595,7 @@ public class Recover extends Tool implements DataHandler {
writer.println("DROP ALIAS READ_BLOB_DB;"); writer.println("DROP ALIAS READ_BLOB_DB;");
writer.println("DROP ALIAS READ_CLOB_DB;"); writer.println("DROP ALIAS READ_CLOB_DB;");
if (deleteLobs) { if (deleteLobs) {
writer.println("DELETE FROM INFORMATION_SCHEMA.LOBS WHERE TABLE = " + writer.println("DELETE FROM INFORMATION_SCHEMA.LOBS WHERE \"TABLE\" = " +
LobStorageFrontend.TABLE_TEMP + ";"); LobStorageFrontend.TABLE_TEMP + ";");
} }
for (MetaRecord m : schema) { for (MetaRecord m : schema) {
......
...@@ -232,10 +232,15 @@ public class ParserUtil { ...@@ -232,10 +232,15 @@ public class ParserUtil {
*/ */
public static final int SELECT = ROWNUM + 1; public static final int SELECT = ROWNUM + 1;
/**
* The token "TABLE".
*/
public static final int TABLE = SELECT + 1;
/** /**
* The token "TRUE". * The token "TRUE".
*/ */
public static final int TRUE = SELECT + 1; public static final int TRUE = TABLE + 1;
/** /**
* The token "UNION". * The token "UNION".
...@@ -490,7 +495,9 @@ public class ParserUtil { ...@@ -490,7 +495,9 @@ public class ParserUtil {
} }
return IDENTIFIER; return IDENTIFIER;
case 'T': case 'T':
if (eq("TRUE", s, ignoreCase, start, end)) { if (eq("TABLE", s, ignoreCase, start, end)) {
return TABLE;
} else if (eq("TRUE", s, ignoreCase, start, end)) {
return TRUE; return TRUE;
} }
if (additionalKeywords) { if (additionalKeywords) {
......
...@@ -155,7 +155,7 @@ public class TestScript extends TestDb { ...@@ -155,7 +155,7 @@ public class TestScript extends TestDb {
testScript("ddl/" + s + ".sql"); testScript("ddl/" + s + ".sql");
} }
for (String s : new String[] { "delete", "error_reporting", "insertIgnore", "merge", "mergeUsing", "replace", for (String s : new String[] { "delete", "error_reporting", "insertIgnore", "merge", "mergeUsing", "replace",
"script", "select", "show", "with" }) { "script", "select", "show", "table", "with" }) {
testScript("dml/" + s + ".sql"); testScript("dml/" + s + ".sql");
} }
for (String s : new String[] { "help" }) { for (String s : new String[] { "help" }) {
......
-- 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
--
CREATE TABLE TEST(A INT, B INT, C INT);
> ok
INSERT INTO TEST VALUES (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 1), (1, 2, 2), (1, 2, 3),
(2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 2, 1), (2, 2, 2), (2, 2, 3);
> update count: 12
TABLE TEST ORDER BY A, B;
> A B C
> - - -
> 1 1 1
> 1 1 2
> 1 1 3
> 1 2 1
> 1 2 2
> 1 2 3
> 2 1 1
> 2 1 2
> 2 1 3
> 2 2 1
> 2 2 2
> 2 2 3
> rows (partially ordered): 12
TABLE TEST ORDER BY A, B, C FETCH FIRST 4 ROWS ONLY;
> A B C
> - - -
> 1 1 1
> 1 1 2
> 1 1 3
> 1 2 1
> rows (ordered): 4
SELECT * FROM (TABLE TEST) ORDER BY A, B, C FETCH FIRST ROW ONLY;
> A B C
> - - -
> 1 1 1
> rows (ordered): 1
SELECT (1, 2, 3) IN (TABLE TEST);
>> TRUE
SELECT (TABLE TEST FETCH FIRST ROW ONLY) "ROW";
> ROW
> -------------
> ROW (1, 1, 1)
> rows: 1
DROP TABLE TEST;
> ok
...@@ -130,3 +130,21 @@ WITH CTE_TEST AS (SELECT 1, 2) ((SELECT * FROM CTE_TEST)); ...@@ -130,3 +130,21 @@ WITH CTE_TEST AS (SELECT 1, 2) ((SELECT * FROM CTE_TEST));
> - - > - -
> 1 2 > 1 2
> rows: 1 > rows: 1
CREATE TABLE TEST(A INT, B INT) AS SELECT 1, 2;
> ok
WITH CTE_TEST AS (TABLE TEST) ((SELECT * FROM CTE_TEST));
> A B
> - -
> 1 2
> rows: 1
WITH CTE_TEST AS (TABLE TEST) ((TABLE CTE_TEST));
> A B
> - -
> 1 2
> rows: 1
DROP TABLE TEST;
> ok
...@@ -31,11 +31,17 @@ SELECT * FROM (SELECT * FROM TEST) x ORDER BY id; ...@@ -31,11 +31,17 @@ SELECT * FROM (SELECT * FROM TEST) x ORDER BY id;
drop table test; drop table test;
> ok > ok
call table(id int = (1));
> ID
> --
> 1
> rows: 1
explain select * from table(id int = (1, 2), name varchar=('Hello', 'World')); explain select * from table(id int = (1, 2), name varchar=('Hello', 'World'));
>> SELECT TABLE.ID, TABLE.NAME FROM TABLE(ID INT=ROW (1, 2), NAME VARCHAR=ROW ('Hello', 'World')) /* function */ >> SELECT "TABLE".ID, "TABLE".NAME FROM TABLE(ID INT=ROW (1, 2), NAME VARCHAR=ROW ('Hello', 'World')) /* function */
explain select * from table(id int = ARRAY[1, 2], name varchar=ARRAY['Hello', 'World']); explain select * from table(id int = ARRAY[1, 2], name varchar=ARRAY['Hello', 'World']);
>> SELECT TABLE.ID, TABLE.NAME FROM TABLE(ID INT=ARRAY [1, 2], NAME VARCHAR=ARRAY ['Hello', 'World']) /* function */ >> SELECT "TABLE".ID, "TABLE".NAME FROM TABLE(ID INT=ARRAY [1, 2], NAME VARCHAR=ARRAY ['Hello', 'World']) /* function */
select * from table(id int=(1, 2), name varchar=('Hello', 'World')) x order by id; select * from table(id int=(1, 2), name varchar=('Hello', 'World')) x order by id;
> ID NAME > ID NAME
...@@ -43,3 +49,10 @@ select * from table(id int=(1, 2), name varchar=('Hello', 'World')) x order by i ...@@ -43,3 +49,10 @@ select * from table(id int=(1, 2), name varchar=('Hello', 'World')) x order by i
> 1 Hello > 1 Hello
> 2 World > 2 World
> rows (ordered): 2 > rows (ordered): 2
SELECT * FROM (TABLE(ID INT = (1, 2)));
> ID
> --
> 1
> 2
> rows: 2
...@@ -16,11 +16,11 @@ HELP ABCDE EF_GH; ...@@ -16,11 +16,11 @@ HELP ABCDE EF_GH;
HELP HELP; HELP HELP;
> ID SECTION TOPIC SYNTAX TEXT > ID SECTION TOPIC SYNTAX TEXT
> -- ---------------- ----- ----------------------- ---------------------------------------------------- > -- ---------------- ----- ----------------------- ----------------------------------------------------
> 65 Commands (Other) HELP HELP [ anything [...] ] Displays the help pages of SQL commands or keywords. > 66 Commands (Other) HELP HELP [ anything [...] ] Displays the help pages of SQL commands or keywords.
> rows: 1 > rows: 1
HELP he lp; HELP he lp;
> ID SECTION TOPIC SYNTAX TEXT > ID SECTION TOPIC SYNTAX TEXT
> -- ---------------- ----- ----------------------- ---------------------------------------------------- > -- ---------------- ----- ----------------------- ----------------------------------------------------
> 65 Commands (Other) HELP HELP [ anything [...] ] Displays the help pages of SQL commands or keywords. > 66 Commands (Other) HELP HELP [ anything [...] ] Displays the help pages of SQL commands or keywords.
> rows: 1 > rows: 1
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论