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

--no commit message

--no commit message
上级 483d9103
...@@ -44,7 +44,8 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -44,7 +44,8 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</ul> </ul>
<h3>Version 1.0 / 2007-08-02</h3><ul> <h3>Version 1.0 / 2007-08-02</h3><ul>
<li>A new tool to help translation has been implemented: src/tools/org/h2/tools/i18n/PrepareTranslation. <li>OpenOffice compatibility: support database name in column names.
</li><li>A new tool to help translation has been implemented: src/tools/org/h2/tools/i18n/PrepareTranslation.
This tool can detect delta changes in the original (English) and prepends '#' in translation if the original This tool can detect delta changes in the original (English) and prepends '#' in translation if the original
text was changed. It can also extract text from the user documentation (however, it is incomplete). text was changed. It can also extract text from the user documentation (however, it is incomplete).
</li><li>The error messages (src/main/org/h2/res/_*.*) can now be translated. </li><li>The error messages (src/main/org/h2/res/_*.*) can now be translated.
...@@ -844,6 +845,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -844,6 +845,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Priority 2</h3> <h3>Priority 2</h3>
<ul> <ul>
<li>Support OSGi: http://oscar-osgi.sourceforge.net, http://incubator.apache.org/felix/index.html <li>Support OSGi: http://oscar-osgi.sourceforge.net, http://incubator.apache.org/felix/index.html
</li><li>Procedural language / script language
</li><li>Change LOB mechanism (less files, keep index of lob files, point to files and row, delete unused files earlier, maybe bundle files into a tar file) </li><li>Change LOB mechanism (less files, keep index of lob files, point to files and row, delete unused files earlier, maybe bundle files into a tar file)
</li><li>Set the database in an 'exclusive' mode (restrict to one user at a time) </li><li>Set the database in an 'exclusive' mode (restrict to one user at a time)
</li><li>Clustering: recovery needs to becomes fully automatic. Global write lock feature. </li><li>Clustering: recovery needs to becomes fully automatic. Global write lock feature.
...@@ -891,7 +893,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -891,7 +893,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>JSON parser and functions </li><li>JSON parser and functions
</li><li>Option for Java functions: constant/isDeterministic to allow early evaluation when all parameters are constant </li><li>Option for Java functions: constant/isDeterministic to allow early evaluation when all parameters are constant
</li><li>Automatic collection of statistics (auto ANALYZE) </li><li>Automatic collection of statistics (auto ANALYZE)
</li><li>Procedural language
</li><li>Server: client ping from time to time (to avoid timeout - is timeout a problem?) </li><li>Server: client ping from time to time (to avoid timeout - is timeout a problem?)
</li><li>Copy database: Tool with config GUI and batch mode, extensible (example: compare) </li><li>Copy database: Tool with config GUI and batch mode, extensible (example: compare)
</li><li>Document, implement tool for long running transactions using user defined compensation statements </li><li>Document, implement tool for long running transactions using user defined compensation statements
...@@ -1098,6 +1099,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -1098,6 +1099,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
Problem: what to do when server stops while others are connected to it. Problem: what to do when server stops while others are connected to it.
</li><li>Access rights: remember the owner of an object. COMMENT: allow owner of object to change it. </li><li>Access rights: remember the owner of an object. COMMENT: allow owner of object to change it.
</li><li>Implement INSTEAD OF trigger. </li><li>Implement INSTEAD OF trigger.
</li><li>Access rights: Finer grained access control (grant access for specific functions)
</li></ul> </li></ul>
<h3>Not Planned</h3> <h3>Not Planned</h3>
......
...@@ -210,7 +210,6 @@ public class Parser { ...@@ -210,7 +210,6 @@ public class Parser {
c = list; c = list;
} }
} else if (currentTokenType != END) { } else if (currentTokenType != END) {
// TODO exception: expected end of command
throw getSyntaxError(); throw getSyntaxError();
} }
return c; return c;
...@@ -385,7 +384,6 @@ public class Parser { ...@@ -385,7 +384,6 @@ public class Parser {
} }
break; break;
default: default:
// TODO exception: unknown command
throw getSyntaxError(); throw getSyntaxError();
} }
if(indexedParameterList != null) { if(indexedParameterList != null) {
...@@ -563,9 +561,26 @@ public class Parser { ...@@ -563,9 +561,26 @@ public class Parser {
if(readIf(".")) { if(readIf(".")) {
tableAlias = columnName; tableAlias = columnName;
columnName = readColumnIdentifier(); columnName = readColumnIdentifier();
} if(readIf(".")) {
if (tableAlias != null && !tableAlias.equals(filter.getTableAlias())) { String schemaName = tableAlias;
throw Message.getSQLException(Message.TABLE_OR_VIEW_NOT_FOUND_1, tableAlias); tableAlias = columnName;
columnName = readColumnIdentifier();
if(readIf(".")) {
String catalogName = schemaName;
schemaName = tableAlias;
tableAlias = columnName;
columnName = readColumnIdentifier();
if(!catalogName.equals(database.getShortName())) {
throw Message.getSQLException(Message.DATABASE_NOT_FOUND_1, catalogName);
}
}
if(!schemaName.equals(filter.getTable().getSchema().getName())) {
throw Message.getSQLException(Message.SCHEMA_NOT_FOUND_1, schemaName);
}
}
if(!tableAlias.equals(filter.getTableAlias())) {
throw Message.getSQLException(Message.TABLE_OR_VIEW_NOT_FOUND_1, tableAlias);
}
} }
return filter.getTable().getColumn(columnName); return filter.getTable().getColumn(columnName);
} }
...@@ -922,7 +937,6 @@ public class Parser { ...@@ -922,7 +937,6 @@ public class Parser {
} else if (readIf("INDEX")) { } else if (readIf("INDEX")) {
boolean ifExists = readIfExists(false); boolean ifExists = readIfExists(false);
String indexName = readIdentifierWithSchema(); String indexName = readIdentifierWithSchema();
// TODO drop index: how to drop a primary key?
DropIndex command = new DropIndex(session, getSchema()); DropIndex command = new DropIndex(session, getSchema());
command.setIndexName(indexName); command.setIndexName(indexName);
ifExists = readIfExists(ifExists); ifExists = readIfExists(ifExists);
...@@ -1172,7 +1186,6 @@ public class Parser { ...@@ -1172,7 +1186,6 @@ public class Parser {
readIf("DISTINCT"); readIf("DISTINCT");
union.setUnionType(SelectUnion.UNION); union.setUnionType(SelectUnion.UNION);
} }
// TODO exceptions: always add the SQL statement to the exception, if possible!
union.setRight(parseSelectSub()); union.setRight(parseSelectSub());
command = union; command = union;
} else if(readIf("MINUS") || readIf("EXCEPT")) { } else if(readIf("MINUS") || readIf("EXCEPT")) {
...@@ -1249,7 +1262,6 @@ public class Parser { ...@@ -1249,7 +1262,6 @@ public class Parser {
if(readIf("FOR")) { if(readIf("FOR")) {
if(readIf("UPDATE")) { if(readIf("UPDATE")) {
if(readIf("OF")) { if(readIf("OF")) {
// TODO parser: select for update of: should do something with the list!
do { do {
readIdentifierWithSchema(); readIdentifierWithSchema();
} while(readIf(",")); } while(readIf(","));
...@@ -1402,7 +1414,6 @@ public class Parser { ...@@ -1402,7 +1414,6 @@ public class Parser {
Expression condition = readExpression(); Expression condition = readExpression();
command.setHaving(condition); command.setHaving(condition);
} }
// TODO optimization: not all parameters may be referenced
command.setParameterList(parameters); command.setParameterList(parameters);
currentSelect = oldSelect; currentSelect = oldSelect;
setSQL(command, "SELECT", start); setSQL(command, "SELECT", start);
...@@ -1480,7 +1491,6 @@ public class Parser { ...@@ -1480,7 +1491,6 @@ public class Parser {
read("NULL"); read("NULL");
r = new Comparison(session, type, r, null); r = new Comparison(session, type, r, null);
} else if (readIf("IN")) { } else if (readIf("IN")) {
// TODO extend IN to support arrays (using setArray?)
if(Constants.OPTIMIZE_IN) { if(Constants.OPTIMIZE_IN) {
recompileAlways = true; recompileAlways = true;
} }
...@@ -1621,7 +1631,6 @@ public class Parser { ...@@ -1621,7 +1631,6 @@ public class Parser {
private Expression readAggregate(int aggregateType) throws SQLException { private Expression readAggregate(int aggregateType) throws SQLException {
if(currentSelect == null) { if(currentSelect == null) {
// TODO exception: function only allowed in a query
throw getSyntaxError(); throw getSyntaxError();
} }
currentSelect.setGroupQuery(); currentSelect.setGroupQuery();
...@@ -1671,7 +1680,7 @@ public class Parser { ...@@ -1671,7 +1680,7 @@ public class Parser {
private JavaFunction readJavaFunction(String name) throws SQLException { private JavaFunction readJavaFunction(String name) throws SQLException {
FunctionAlias functionAlias = database.findFunctionAlias(name); FunctionAlias functionAlias = database.findFunctionAlias(name);
if(functionAlias == null) { if(functionAlias == null) {
// TODO compatibility: maybe support 'on the fly java functions' as HSQLDB ( CALL "java.lang.Math.sqrt"(2.0) ) // TODO compatibility: support 'on the fly java functions' as HSQLDB ( CALL "java.lang.Math.sqrt"(2.0) )
throw Message.getSQLException(Message.FUNCTION_NOT_FOUND_1, name); throw Message.getSQLException(Message.FUNCTION_NOT_FOUND_1, name);
} }
int paramCount = functionAlias.getParameterCount(); int paramCount = functionAlias.getParameterCount();
...@@ -1845,6 +1854,7 @@ public class Parser { ...@@ -1845,6 +1854,7 @@ public class Parser {
return expr; return expr;
} }
String name = readColumnIdentifier(); String name = readColumnIdentifier();
int supportDatabaseSchema;
if(readIf(".")) { if(readIf(".")) {
String schemaName = objectName; String schemaName = objectName;
objectName = name; objectName = name;
...@@ -1853,6 +1863,20 @@ public class Parser { ...@@ -1853,6 +1863,20 @@ public class Parser {
return expr; return expr;
} }
name = readColumnIdentifier(); name = readColumnIdentifier();
if(readIf(".")) {
String databaseName = schemaName;
if(!database.getShortName().equals(databaseName)) {
throw Message.getSQLException(Message.DATABASE_NOT_FOUND_1, databaseName);
}
schemaName = objectName;
objectName = name;
expr = readWildcardOrSequenceValue(schemaName, objectName);
if(expr != null) {
return expr;
}
name = readColumnIdentifier();
return new ExpressionColumn(database, currentSelect, schemaName, objectName, name);
}
return new ExpressionColumn(database, currentSelect, schemaName, objectName, name); return new ExpressionColumn(database, currentSelect, schemaName, objectName, name);
} }
return new ExpressionColumn(database, currentSelect, null, objectName, name); return new ExpressionColumn(database, currentSelect, null, objectName, name);
...@@ -1974,7 +1998,6 @@ public class Parser { ...@@ -1974,7 +1998,6 @@ public class Parser {
if(r.getType() == Value.LONG && r.getValue(session).getLong() == Integer.MIN_VALUE) { if(r.getType() == Value.LONG && r.getValue(session).getLong() == Integer.MIN_VALUE) {
r = ValueExpression.get(ValueInt.get(Integer.MIN_VALUE)); r = ValueExpression.get(ValueInt.get(Integer.MIN_VALUE));
} }
// TODO parser: maybe convert Long.MIN_VALUE from decimal to long?
read(); read();
} else { } else {
r = new Operation(Operation.NEGATE, readTerm(), null); r = new Operation(Operation.NEGATE, readTerm(), null);
...@@ -2045,7 +2068,6 @@ public class Parser { ...@@ -2045,7 +2068,6 @@ public class Parser {
read(); read();
break; break;
default: default:
// TODO exception: expected a term
throw getSyntaxError(); throw getSyntaxError();
} }
if(readIf("[")) { if(readIf("[")) {
...@@ -2149,7 +2171,6 @@ public class Parser { ...@@ -2149,7 +2171,6 @@ public class Parser {
} }
private String readString() throws SQLException { private String readString() throws SQLException {
// TODO parser: readInt/Long could maybe use readExpression as well
Expression expr = readExpression().optimize(session); Expression expr = readExpression().optimize(session);
if(!(expr instanceof ValueExpression)) { if(!(expr instanceof ValueExpression)) {
throw Message.getSyntaxError(sqlCommand, parseIndex, "string"); throw Message.getSyntaxError(sqlCommand, parseIndex, "string");
...@@ -2392,7 +2413,6 @@ public class Parser { ...@@ -2392,7 +2413,6 @@ public class Parser {
parseIndex = i; parseIndex = i;
return; return;
default: default:
// TODO exception: unsupported character
throw getSyntaxError(); throw getSyntaxError();
} }
} }
...@@ -2437,7 +2457,6 @@ public class Parser { ...@@ -2437,7 +2457,6 @@ public class Parser {
i++; i++;
} }
if (types[i] != CHAR_VALUE) { if (types[i] != CHAR_VALUE) {
// TODO exception: error reading value
throw getSyntaxError(); throw getSyntaxError();
} }
while (types[++i] == CHAR_VALUE) { while (types[++i] == CHAR_VALUE) {
...@@ -2638,7 +2657,6 @@ public class Parser { ...@@ -2638,7 +2657,6 @@ public class Parser {
private void checkRunOver(int i, int len, int startLoop) throws SQLException { private void checkRunOver(int i, int len, int startLoop) throws SQLException {
if(i >= len) { if(i >= len) {
parseIndex = startLoop; parseIndex = startLoop;
// TODO exception: unexpected end
throw getSyntaxError(); throw getSyntaxError();
} }
} }
...@@ -2713,7 +2731,6 @@ public class Parser { ...@@ -2713,7 +2731,6 @@ public class Parser {
} }
private int getTokenType(String s) throws SQLException { private int getTokenType(String s) throws SQLException {
// TODO the list of keywords is in the documentation! should be a hash map!
int len = s.length(); int len = s.length();
if(len == 0) { if(len == 0) {
throw getSyntaxError(); throw getSyntaxError();
......
...@@ -2513,6 +2513,7 @@ If the column names are specified (a comma separated list of column names), ...@@ -2513,6 +2513,7 @@ If the column names are specified (a comma separated list of column names),
those are used they are read from the file, otherwise (or if they are set to NULL) the first line those are used they are read from the file, otherwise (or if they are set to NULL) the first line
of the file is interpreted as the column names. of the file is interpreted as the column names.
The default charset is the default value for this system, and the default field separator is a comma. The default charset is the default value for this system, and the default field separator is a comma.
This function can be used like a table: SELECT * FROM CSVREAD(...).
Admin rights are required to execute this command. Admin rights are required to execute this command.
"," ","
CALL CSVREAD('test.csv') CALL CSVREAD('test.csv')
......
...@@ -97,6 +97,14 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2 ...@@ -97,6 +97,14 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
/* /*
create table test(id int);
update test t set t.id=1;
update public.test set public.test.id=1;
select count(test.public.test.id) from test.public.test;
update test.public.test set test.public.test.id=1;
drop table test.public.test;
search from a frame (but usually don't use frames) search from a frame (but usually don't use frames)
Class.forName("org.h2.Driver"); Class.forName("org.h2.Driver");
......
create table test(id int);
insert into scriptSimple.public.test(id) values(1), (2);
update test t set t.id=t.id+1;
update public.test set public.test.id=1;
select count(scriptSimple.public.test.id) from scriptSimple.public.test;
> 2;
update scriptSimple.public.test set scriptSimple.public.test.id=1;
drop table scriptSimple.public.test;
select timestamp '2007-07-26 18:44:26.109000 +02:00'; select timestamp '2007-07-26 18:44:26.109000 +02:00';
> 2007-07-26 18:44:26.109; > 2007-07-26 18:44:26.109;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论