package net.sourceforge.mayfly.acceptance;
public class SyntaxTest extends SqlTestCase {
// Should mayfly have a SyntaxException which subclasses SQLException?
public void testBadCommand() throws Exception {
expectExecuteFailure("PICK NOSE", "expected command but got PICK");
}
public void testCommandsAreCaseInsensitive() throws Exception {
expectExecuteFailure("DrOp tAbLe FOo", "no table FOo");
}
public void testColumnsMissingOnCreate() throws Exception {
// Is "must specify columns" any better?
// "expected '('" might be about as good.
// expectExecuteFailure("create table foo", "must specify columns on create");
expectExecuteFailure("create table foo", "expected '(' but got end of file");
expectExecuteFailure("create table foo (a integer", "expected ')' but got end of file");
}
public void testQuotedIdentifier() throws Exception {
String createTableSql = "create table \"join\" (" +
"\"null\" integer, \"=\" integer, \"\u00a1\" integer)";
if (dialect.canQuoteIdentifiers()) {
execute(createTableSql);
execute("insert into \"join\" (" +
"\"null\", \"=\", \"\u00a1\") values (3, 5, 7)");
assertResultSet(new String[] { "7, 5, 3" }, query("select \"\u00a1\", \"=\", \"null\" from \"join\""));
}
else {
expectExecuteFailure(createTableSql, null);
}
}
public void testQuotedIdentifiersCaseSensitive() throws Exception {
// The unquoted one is to be taken as the same as quoted "FOO"
String createTableSql =
"create table foo (foo integer, \"Foo\" integer, \"foo\" integer)";
if (dialect.canQuoteIdentifiers() &&
dialect.quotedIdentifiersAreCaseSensitive()) {
execute(createTableSql);
execute("insert into foo (\"Foo\", \"foo\", \"FOO\") values (3, 5, 7)");
assertResultSet(new String[] { "5, 3, 7" },
query("select \"foo\", \"Foo\", foo from foo"));
}
else {
expectExecuteFailure(createTableSql, "duplicate column Foo");
}
}
public void testTableNamesCaseInsensitive() throws Exception {
if (dialect.tableNamesMightBeCaseSensitive()) {
return;
}
execute("create table foo (x integer)");
execute("insert into Foo (X) values (5)");
assertResultSet(new String[] { " 5 " } , query("select x from FOO"));
assertResultSet(new String[] { " 5 " } , query("select Foo.x from foo"));
assertResultSet(new String[] { " 5 " } , query("select x from foo where FOO.x = 5"));
}
public void testNonReservedWords() throws Exception {
String[] nonReserved = new String[] {
// I believe this list originates from the SQL92 standard
"ADA",
"C", "CATALOG_NAME",
"CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME",
"CHARACTER_SET_SCHEMA", "CLASS_ORIGIN", "COBOL", "COLLATION_CATALOG",
"COLLATION_NAME", "COLLATION_SCHEMA", "COLUMN_NAME", "COMMAND_FUNCTION",
"COMMITTED",
"CONDITION_NUMBER", "CONNECTION_NAME", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME",
"CONSTRAINT_SCHEMA", "CURSOR_NAME",
"DATA", "DATETIME_INTERVAL_CODE",
"DATETIME_INTERVAL_PRECISION", "DYNAMIC_FUNCTION",
"FORTRAN",
"LENGTH",
"MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "MORE", "MUMPS",
"NAME", "NULLABLE", "NUMBER",
"PASCAL", "PLI",
"REPEATABLE", "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH", "RETURNED_SQLSTATE",
"ROW_COUNT",
"SCALE", "SCHEMA_NAME", "SERIALIZABLE", "SERVER_NAME", "SUBCLASS_ORIGIN",
"TABLE_NAME", "TYPE",
"UNCOMMITTED", "UNNAMED"
};
for (int i = 0; i < nonReserved.length; i++) {
assertNotReserved(nonReserved[i]);
}
checkReserved("offset");
// Hypersonic pseudo-user for CREATE SCHEMA
assertNotReserved("dba");
// Derby reserved words (the manual has a longer list)
checkReserved("first");
checkReserved("last");
// Part of DROP TABLE foo IF EXISTS in Mayfly, Hypersonic, and MySQL
checkReserved("if");
checkReserved("generated");
checkReserved("serial");
checkReserved("identity");
checkReserved("auto_increment");
// Part of ALTER TABLE foo MODIFY COLUMN,
// which isn't in SQL92
checkReserved("modify");
// Part of CREATE TABLE, CREATE INDEX, etc
checkReserved("index");
}
private void checkReserved(String word) throws Exception {
if (dialect.isReservedWord(word)) {
assertReserved(word);
}
else {
assertNotReserved(word);
}
}
private void assertNotReserved(String identifier) throws Exception {
execute("create table foo (" + identifier + " integer)");
execute("drop table foo");
}
private void assertReserved(String keyword) throws Exception {
expectExecuteFailure("create table foo (" + keyword + " integer)",
"index".equals(keyword) ?
"expected '(' but got INTEGER" :
"expected column or table constraint but got " +
keyword.toUpperCase()
);
}
public void testWrongIdentifierForNonReserved() throws Exception {
// The current rule is that the wrong identifier just
// doesn't get consumed, so that if an identifier doesn't
// end up being legal there, we'll eventually get another
// syntax error. Is there some reason this won't work?
execute("create table foo (x integer)");
expectExecuteFailure("select x from foo limit 10 ofset 20",
"expected end of file but got ofset");
}
public void testComments() throws Exception {
execute("create table -- single-line comment\n" +
"foo (x integer) ");
String slashStarComment =
"insert into foo /* C-style \n" +
"comment */ (x) values (5)";
if (dialect.haveSlashStarComments()) {
execute(slashStarComment);
}
else {
expectExecuteFailure(slashStarComment, "unexpected character /");
}
}
}