Skip to content

Commit ad3e26a

Browse files
committed
Fix #23 (View with column named 'LEAVE') by adding reserved word 'LEAVE'
1 parent a27d25f commit ad3e26a

File tree

4 files changed

+91
-34
lines changed

4 files changed

+91
-34
lines changed

src/main/java/net/ucanaccess/converters/LoadJet.java

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,8 +1278,8 @@ private final class ViewsLoader {
12781278
private static final int OBJECT_NOT_FOUND = -ErrorCode.X_42501;
12791279
private static final int UNEXPECTED_TOKEN = -ErrorCode.X_42581;
12801280

1281-
private final Map<String, String> notLoaded = new HashMap<>();
1282-
private final Map<String, String> notLoadedProcedure = new HashMap<>();
1281+
private final Map<String, String> notLoaded = new LinkedHashMap<>();
1282+
private final Map<String, String> notLoadedProcedure = new LinkedHashMap<>();
12831283

12841284
private boolean loadView(Query _q) throws SQLException {
12851285
return loadView(_q, null);
@@ -1322,34 +1322,34 @@ private void registerQueryColumns(Query _q, int _seq) throws SQLException {
13221322
}
13231323
}
13241324

1325-
private boolean loadView(Query q, String queryWKT) throws SQLException {
1326-
String qnn = SQLConverter.preEscapingIdentifier(q.getName());
1325+
private boolean loadView(Query _query, String queryWkt) throws SQLException {
1326+
String qnn = SQLConverter.preEscapingIdentifier(_query.getName());
13271327
if (qnn == null) {
13281328
return false;
13291329
}
1330-
int seq = metadata.newTable(q.getName(), qnn, ObjectType.VIEW);
1331-
registerQueryColumns(q, seq);
1330+
int seq = metadata.newTable(_query.getName(), qnn, ObjectType.VIEW);
1331+
registerQueryColumns(_query, seq);
13321332
qnn = SQLConverter.completeEscaping(qnn, false);
13331333
qnn = SQLConverter.checkLang(qnn, conn, false);
13341334
if (qnn.indexOf(' ') > 0) {
1335-
SQLConverter.addWhiteSpacedTableNames(q.getName());
1335+
SQLConverter.addWhiteSpacedTableNames(_query.getName());
13361336
}
13371337

1338-
String querySQL = queryWKT == null ? q.toSQLString() : queryWKT;
1338+
String querySql = Optional.ofNullable(queryWkt).orElse(_query.toSQLString());
13391339
Pivot pivot = null;
1340-
boolean isPivot = q.getType().equals(Query.Type.CROSS_TAB);
1340+
boolean isPivot = _query.getType().equals(Query.Type.CROSS_TAB);
13411341
if (isPivot) {
13421342
pivot = new Pivot(conn);
13431343

1344-
if (!pivot.parsePivot(querySQL) || (querySQL = pivot.toSQL(q.getName())) == null) {
1345-
notLoaded.put(q.getName(), "cannot load this query");
1344+
if (!pivot.parsePivot(querySql) || (querySql = pivot.toSQL(_query.getName())) == null) {
1345+
notLoaded.put(_query.getName(), "cannot load this query");
13461346

13471347
return false;
13481348
}
13491349

13501350
}
1351-
querySQL = new DFunction(conn, querySQL).toSQL();
1352-
StringBuilder sb = new StringBuilder("CREATE VIEW ").append(qnn).append(" AS ").append(querySQL);
1351+
querySql = new DFunction(conn, querySql).toSQL();
1352+
StringBuilder sb = new StringBuilder("CREATE VIEW ").append(qnn).append(" AS ").append(querySql);
13531353
String v = null;
13541354
try {
13551355
v = SQLConverter.convertSQL(sb.toString(), true).getSql();
@@ -1358,25 +1358,25 @@ private boolean loadView(Query q, String queryWKT) throws SQLException {
13581358
v = v.trim().substring(0, v.length() - 1);
13591359
}
13601360
exec(v, false);
1361-
loadedQueries.add(q.getName());
1362-
notLoaded.remove(q.getName());
1361+
loadedQueries.add(_query.getName());
1362+
notLoaded.remove(_query.getName());
13631363
if (pivot != null) {
1364-
pivot.registerPivot(SQLConverter.preEscapingIdentifier(q.getName()));
1364+
pivot.registerPivot(SQLConverter.preEscapingIdentifier(_query.getName()));
13651365
}
13661366
return true;
13671367
} catch (Exception _ex) {
13681368
if (_ex instanceof SQLSyntaxErrorException) {
1369-
if (queryWKT == null && ((SQLSyntaxErrorException) _ex).getErrorCode() == OBJECT_ALREADY_EXISTS) {
1370-
return loadView(q, solveAmbiguous(querySQL));
1369+
if (queryWkt == null && OBJECT_ALREADY_EXISTS == ((SQLSyntaxErrorException) _ex).getErrorCode()) {
1370+
return loadView(_query, solveAmbiguous(querySql));
13711371
} else {
13721372
SQLSyntaxErrorException sqle = (SQLSyntaxErrorException) _ex;
1373-
if (sqle.getErrorCode() == OBJECT_NOT_FOUND || sqle.getErrorCode() == UNEXPECTED_TOKEN) {
1374-
ParametricQuery pq = new ParametricQuery(conn, (QueryImpl) q);
1373+
if (sqle.getErrorCode() == OBJECT_NOT_FOUND || UNEXPECTED_TOKEN == sqle.getErrorCode()) {
1374+
ParametricQuery pq = new ParametricQuery(conn, (QueryImpl) _query);
13751375
pq.setIssueWithParameterName(sqle.getErrorCode() == UNEXPECTED_TOKEN);
13761376
pq.createSelect();
13771377
if (pq.loaded()) {
1378-
loadedQueries.add(q.getName());
1379-
notLoaded.remove(q.getName());
1378+
loadedQueries.add(_query.getName());
1379+
notLoaded.remove(_query.getName());
13801380
return true;
13811381
}
13821382

@@ -1386,12 +1386,11 @@ private boolean loadView(Query q, String queryWKT) throws SQLException {
13861386

13871387
String cause = UcanaccessSQLException.explainCause(_ex);
13881388

1389-
notLoaded.put(q.getName(), ": " + cause);
1389+
notLoaded.put(_query.getName(), ": " + cause);
13901390

13911391
if (!err) {
1392-
logger.log(Level.WARNING, "Error occured at the first loading attempt of {0}", q.getName());
1393-
logger.log(Level.WARNING, "Converted view was: {0}", v);
1394-
logger.log(Level.WARNING, "Error message was: {0}", _ex.getMessage());
1392+
logger.log(Level.WARNING, "Error at first loading attempt of view \''{0}\'', converted view \''{1}\'', error {2}",
1393+
_query.getName(), v, _ex.toString());
13951394
err = true;
13961395
}
13971396
return false;

src/main/java/net/ucanaccess/converters/SQLConverter.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,13 @@ private Patterns() {
6969
private static final String DELETE_ALL = "((?i)DELETE\\s+)(\\*)(\\s+(?i)FROM\\s+)";
7070
private static final String PARAMETERS = "(?i)PARAMETERS([^;]*);";
7171
private static final String BIG_BANG = "1899-12-30";
72-
private static final List<String> KEYWORDS_LIST = List.of("ALL", "AND", "ANY",
73-
"ALTER", "AS", "AT", "AVG", "BETWEEN", "BOTH", "BY", "CALL", "CASE", "CAST", "CHECK", "COALESCE",
74-
"CORRESPONDING", "CONVERT", "COUNT", "CREATE", "CROSS", "DEFAULT", "DISTINCT", "DROP", "ELSE", "EVERY",
75-
"EXISTS", "EXCEPT", "FOR", "FOREIGN", "FROM", "FULL", "GRANT", "GROUP", "HAVING", "IN", "INNER",
76-
"INTERSECT", "INTO", "IS", "JOIN", "LEFT", "LEADING", "LIKE", "MAX", "MIN", "NATURAL", "NOT", "NULLIF",
77-
"ON", "ORDER", "OR", "OUTER", "PRIMARY", "REFERENCES", "RIGHT", "SELECT", "SET", "SOME", "STDDEV_POP",
78-
"STDDEV_SAMP", "SUM", "TABLE", "THEN", "TO", "TRAILING", "TRIGGER", "UNION", "UNIQUE", "USING", "VALUES",
79-
"VAR_POP", "VAR_SAMP", "WHEN", "WHERE", "WITH", "END", "DO", "CONSTRAINT", "USER", "ROW");
72+
private static final List<String> KEYWORDS_LIST = List.of(
73+
"ALL", "ALTER", "AND", "ANY", "AS", "AT", "AVG", "BETWEEN", "BOTH", "BY", "CALL", "CASE", "CAST", "CHECK", "COALESCE", "CONSTRAINT",
74+
"CONVERT", "CORRESPONDING", "COUNT", "CREATE", "CROSS", "DEFAULT", "DISTINCT", "DO", "DROP", "ELSE", "END", "EVERY", "EXCEPT", "EXISTS",
75+
"FOR", "FOREIGN", "FROM", "FULL", "GRANT", "GROUP", "HAVING", "IN", "INNER", "INTERSECT", "INTO", "IS", "JOIN", "LEADING", "LEAVE",
76+
"LEFT", "LIKE", "MAX", "MIN", "NATURAL", "NOT", "NULLIF", "ON", "OR", "ORDER", "OUTER", "PRIMARY", "REFERENCES", "RIGHT", "ROW",
77+
"SELECT", "SET", "SOME", "STDDEV_POP", "STDDEV_SAMP", "SUM", "TABLE", "THEN", "TO", "TRAILING", "TRIGGER", "UNION", "UNIQUE",
78+
"USER", "USING", "VALUES", "VAR_POP", "VAR_SAMP", "WHEN", "WHERE", "WITH");
8079
private static final Pattern PAT_KEYWORD_ALIAS = Pattern.compile(
8180
"(\\s+AS\\s+)("
8281
+ KEYWORDS_LIST.stream()
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package net.ucanaccess.jdbc;
2+
3+
import net.ucanaccess.test.UcanaccessBaseFileTest;
4+
import net.ucanaccess.type.AccessVersion;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.io.File;
8+
import java.lang.System.Logger.Level;
9+
import java.sql.SQLException;
10+
11+
class ReservedWordLeaveTest extends UcanaccessBaseFileTest {
12+
13+
@Test
14+
void testLoadReserved() throws SQLException {
15+
init();
16+
}
17+
18+
@Test
19+
void testCreateTable() throws SQLException {
20+
AccessVersion accessVersion = AccessVersion.V2010;
21+
File fileMdb = createTempFileName(getClass().getSimpleName(), accessVersion.getFileFormat().getFileExtension());
22+
fileMdb.deleteOnExit();
23+
24+
UcanaccessConnectionBuilder builderNew = buildConnection()
25+
.withDbPath(fileMdb.getAbsolutePath())
26+
.withoutUserPass()
27+
.withImmediatelyReleaseResources()
28+
.withNewDatabaseVersion(accessVersion);
29+
getLogger().log(Level.DEBUG, "Database url: {0}", builderNew.getUrl());
30+
31+
String tbl = "t_leave";
32+
33+
try (UcanaccessConnection conn = builderNew.build()) {
34+
getLogger().log(Level.DEBUG, "Database file successfully created: {0}", fileMdb.getAbsolutePath());
35+
36+
try (UcanaccessStatement st = conn.createStatement()) {
37+
executeStatements(st,
38+
"CREATE TABLE " + tbl + " (LEAVE TEXT)",
39+
"INSERT INTO " + tbl + " (LEAVE) VALUES('left')");
40+
dumpQueryResult(() -> st.executeQuery("SELECT * FROM " + tbl));
41+
}
42+
}
43+
44+
UcanaccessConnectionBuilder builderExisting = buildConnection()
45+
.withDbPath(fileMdb.getAbsolutePath())
46+
.withImmediatelyReleaseResources();
47+
48+
try (UcanaccessConnection conn = builderExisting.build()) {
49+
50+
try (UcanaccessStatement st = conn.createStatement()) {
51+
dumpQueryResult(() -> st.executeQuery("SELECT * FROM " + tbl));
52+
st.execute("DROP TABLE " + tbl);
53+
}
54+
}
55+
56+
57+
}
58+
59+
}
Binary file not shown.

0 commit comments

Comments
 (0)