Skip to content

Commit 1754888

Browse files
committed
#908 JDBC 4.5: Firebird-specific implementation of various enquote methods on Connection
1 parent 38d47ce commit 1754888

17 files changed

+689
-173
lines changed

src/main/org/firebirdsql/gds/JaybirdErrorCodes.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: Copyright 2015-2024 Mark Rotteveel
1+
// SPDX-FileCopyrightText: Copyright 2015-2026 Mark Rotteveel
22
// SPDX-FileCopyrightText: Copyright 2019 Vasiliy Yashkov
33
// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause
44
package org.firebirdsql.gds;
@@ -128,6 +128,9 @@ public interface JaybirdErrorCodes {
128128
int jb_socketFactoryClassNotFound = 337248347;
129129
int jb_socketFactoryConstructorNotFound = 337248348;
130130
int jb_socketFactoryFailedToCreateSocket = 337248349;
131+
int jb_invalidIdentifierLength = 337248350;
132+
int jb_invalidIdentifierName = 337248351;
133+
int jb_noDelimitedIdentifiersInDialect1 = 337248352;
131134

132135
@SuppressWarnings("unused")
133136
int jb_range_end = 337264639;

src/main/org/firebirdsql/jaybird/parser/FirebirdReservedWords.java

Lines changed: 136 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
// SPDX-FileCopyrightText: Copyright 2021-2025 Mark Rotteveel
1+
// SPDX-FileCopyrightText: Copyright 2021-2026 Mark Rotteveel
22
// SPDX-License-Identifier: LGPL-2.1-or-later
33
package org.firebirdsql.jaybird.parser;
44

5+
import org.firebirdsql.gds.AbstractVersion;
6+
import org.firebirdsql.jaybird.util.BasicVersion;
57
import org.firebirdsql.util.InternalApi;
68

79
import java.util.Arrays;
@@ -20,9 +22,8 @@
2022
@InternalApi
2123
public enum FirebirdReservedWords implements ReservedWords {
2224

23-
// TODO Add other versions if it turns out we do need reserved words per version
24-
25-
FIREBIRD_5_0("ADD", "ADMIN", "ALL", "ALTER", "AND", "ANY", "AS", "AT", "AVG", "BEGIN", "BETWEEN", "BIGINT",
25+
// Order is intentionally from higher versions to lower versions, see of(AbstractVersion) and latest()
26+
FIREBIRD_5_0(5, 0, "ADD", "ADMIN", "ALL", "ALTER", "AND", "ANY", "AS", "AT", "AVG", "BEGIN", "BETWEEN", "BIGINT",
2627
"BINARY", "BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BY", "CASE", "CAST", "CHAR", "CHARACTER",
2728
"CHARACTER_LENGTH", "CHAR_LENGTH", "CHECK", "CLOSE", "COLLATE", "COLUMN", "COMMENT", "COMMIT", "CONNECT",
2829
"CONSTRAINT", "CORR", "COUNT", "COVAR_POP", "COVAR_SAMP", "CREATE", "CROSS", "CURRENT",
@@ -46,14 +47,108 @@ public enum FirebirdReservedWords implements ReservedWords {
4647
"UNBOUNDED", "UNION", "UNIQUE", "UNKNOWN", "UPDATE", "UPDATING", "UPPER", "USER", "USING", "VALUE",
4748
"VALUES", "VARBINARY", "VARCHAR", "VARIABLE", "VARYING", "VAR_POP", "VAR_SAMP", "VIEW", "WHEN", "WHERE",
4849
"WHILE", "WINDOW", "WITH", "WITHOUT", "YEAR"),
50+
FIREBIRD_4_0(4, 0, "ADD", "ADMIN", "ALL", "ALTER", "AND", "ANY", "AS", "AT", "AVG", "BEGIN", "BETWEEN", "BIGINT",
51+
"BINARY", "BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BY", "CASE", "CAST", "CHAR", "CHARACTER",
52+
"CHARACTER_LENGTH", "CHAR_LENGTH", "CHECK", "CLOSE", "COLLATE", "COLUMN", "COMMENT", "COMMIT", "CONNECT",
53+
"CONSTRAINT", "CORR", "COUNT", "COVAR_POP", "COVAR_SAMP", "CREATE", "CROSS", "CURRENT",
54+
"CURRENT_CONNECTION", "CURRENT_DATE", "CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
55+
"CURRENT_TRANSACTION", "CURRENT_USER", "CURSOR", "DATE", "DAY", "DEC", "DECFLOAT", "DECIMAL", "DECLARE",
56+
"DEFAULT", "DELETE", "DELETING", "DETERMINISTIC", "DISCONNECT", "DISTINCT", "DOUBLE", "DROP", "ELSE", "END",
57+
"ESCAPE", "EXECUTE", "EXISTS", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FILTER", "FLOAT", "FOR", "FOREIGN",
58+
"FROM", "FULL", "FUNCTION", "GDSCODE", "GLOBAL", "GRANT", "GROUP", "HAVING", "HOUR", "IN", "INDEX", "INNER",
59+
"INSENSITIVE", "INSERT", "INSERTING", "INT", "INT128", "INTEGER", "INTO", "IS", "JOIN", "LATERAL",
60+
"LEADING", "LEFT", "LIKE", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LONG", "LOWER", "MAX", "MERGE", "MIN",
61+
"MINUTE", "MONTH", "NATIONAL", "NATURAL", "NCHAR", "NO", "NOT", "NULL", "NUMERIC", "OCTET_LENGTH", "OF",
62+
"OFFSET", "ON", "ONLY", "OPEN", "OR", "ORDER", "OUTER", "OVER", "PARAMETER", "PLAN", "POSITION",
63+
"POST_EVENT", "PRECISION", "PRIMARY", "PROCEDURE", "PUBLICATION", "RDB$DB_KEY", "RDB$ERROR",
64+
"RDB$GET_CONTEXT", "RDB$GET_TRANSACTION_CN", "RDB$RECORD_VERSION", "RDB$ROLE_IN_USE", "RDB$SET_CONTEXT",
65+
"RDB$SYSTEM_PRIVILEGE", "REAL", "RECORD_VERSION", "RECREATE", "RECURSIVE", "REFERENCES", "REGR_AVGX",
66+
"REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY",
67+
"RELEASE", "RESETTING", "RETURN", "RETURNING_VALUES", "RETURNS", "REVOKE", "RIGHT", "ROLLBACK", "ROW",
68+
"ROWS", "ROW_COUNT", "SAVEPOINT", "SCROLL", "SECOND", "SELECT", "SENSITIVE", "SET", "SIMILAR", "SMALLINT",
69+
"SOME", "SQLCODE", "SQLSTATE", "START", "STDDEV_POP", "STDDEV_SAMP", "SUM", "TABLE", "THEN", "TIME",
70+
"TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", "TRAILING", "TRIGGER", "TRIM", "TRUE", "UNBOUNDED",
71+
"UNION", "UNIQUE", "UNKNOWN", "UPDATE", "UPDATING", "UPPER", "USER", "USING", "VALUE", "VALUES",
72+
"VARBINARY", "VARCHAR", "VARIABLE", "VARYING", "VAR_POP", "VAR_SAMP", "VIEW", "WHEN", "WHERE", "WHILE",
73+
"WINDOW", "WITH", "WITHOUT", "YEAR"),
74+
FIREBIRD_3_0(3, 0, "ADD", "ADMIN", "ALL", "ALTER", "AND", "ANY", "AS", "AT", "AVG", "BEGIN", "BETWEEN", "BIGINT",
75+
"BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BY", "CASE", "CAST", "CHAR", "CHARACTER", "CHARACTER_LENGTH",
76+
"CHAR_LENGTH", "CHECK", "CLOSE", "COLLATE", "COLUMN", "COMMIT", "CONNECT", "CONSTRAINT", "CORR", "COUNT",
77+
"COVAR_POP", "COVAR_SAMP", "CREATE", "CROSS", "CURRENT", "CURRENT_CONNECTION", "CURRENT_DATE",
78+
"CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_TRANSACTION", "CURRENT_USER", "CURSOR",
79+
"DATE", "DAY", "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DELETE", "DELETING", "DETERMINISTIC", "DISCONNECT",
80+
"DISTINCT", "DOUBLE", "DROP", "ELSE", "END", "ESCAPE", "EXECUTE", "EXISTS", "EXTERNAL", "EXTRACT", "FALSE",
81+
"FETCH", "FILTER", "FLOAT", "FOR", "FOREIGN", "FROM", "FULL", "FUNCTION", "GDSCODE", "GLOBAL", "GRANT",
82+
"GROUP", "HAVING", "HOUR", "IN", "INDEX", "INNER", "INSENSITIVE", "INSERT", "INSERTING", "INT", "INTEGER",
83+
"INTO", "IS", "JOIN", "LEADING", "LEFT", "LIKE", "LONG", "LOWER", "MAX", "MERGE", "MIN", "MINUTE", "MONTH",
84+
"NATIONAL", "NATURAL", "NCHAR", "NO", "NOT", "NULL", "NUMERIC", "OCTET_LENGTH", "OF", "OFFSET", "ON",
85+
"ONLY", "OPEN", "OR", "ORDER", "OUTER", "OVER", "PARAMETER", "PLAN", "POSITION", "POST_EVENT", "PRECISION",
86+
"PRIMARY", "PROCEDURE", "RDB$DB_KEY", "RDB$RECORD_VERSION", "REAL", "RECORD_VERSION", "RECREATE",
87+
"RECURSIVE", "REFERENCES", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", "REGR_R2",
88+
"REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY", "RELEASE", "RETURN", "RETURNING_VALUES", "RETURNS",
89+
"REVOKE", "RIGHT", "ROLLBACK", "ROW", "ROWS", "ROW_COUNT", "SAVEPOINT", "SCROLL", "SECOND", "SELECT",
90+
"SENSITIVE", "SET", "SIMILAR", "SMALLINT", "SOME", "SQLCODE", "SQLSTATE", "START", "STDDEV_POP",
91+
"STDDEV_SAMP", "SUM", "TABLE", "THEN", "TIME", "TIMESTAMP", "TO", "TRAILING", "TRIGGER", "TRIM", "TRUE",
92+
"UNION", "UNIQUE", "UNKNOWN", "UPDATE", "UPDATING", "UPPER", "USER", "USING", "VALUE", "VALUES", "VARCHAR",
93+
"VARIABLE", "VARYING", "VAR_POP", "VAR_SAMP", "VIEW", "WHEN", "WHERE", "WHILE", "WITH", "YEAR"),
94+
FIREBIRD_2_5(2, 5, "ADD", "ADMIN", "ALL", "ALTER", "AND", "ANY", "AS", "AT", "AVG", "BEGIN", "BETWEEN", "BIGINT",
95+
"BIT_LENGTH", "BLOB", "BOTH", "BY", "CASE", "CAST", "CHAR", "CHARACTER", "CHARACTER_LENGTH", "CHAR_LENGTH",
96+
"CHECK", "CLOSE", "COLLATE", "COLUMN", "COMMIT", "CONNECT", "CONSTRAINT", "COUNT", "CREATE", "CROSS",
97+
"CURRENT", "CURRENT_CONNECTION", "CURRENT_DATE", "CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
98+
"CURRENT_TRANSACTION", "CURRENT_USER", "CURSOR", "DATE", "DAY", "DEC", "DECIMAL", "DECLARE", "DEFAULT",
99+
"DELETE", "DISCONNECT", "DISTINCT", "DOUBLE", "DROP", "ELSE", "END", "ESCAPE", "EXECUTE", "EXISTS",
100+
"EXTERNAL", "EXTRACT", "FETCH", "FILTER", "FLOAT", "FOR", "FOREIGN", "FROM", "FULL", "FUNCTION", "GDSCODE",
101+
"GLOBAL", "GRANT", "GROUP", "HAVING", "HOUR", "IN", "INDEX", "INNER", "INSENSITIVE", "INSERT", "INT",
102+
"INTEGER", "INTO", "IS", "JOIN", "LEADING", "LEFT", "LIKE", "LOCALTIME", "LOCALTIMESTAMP", "LONG", "LOWER",
103+
"MAX", "MAXIMUM_SEGMENT", "MERGE", "MIN", "MINUTE", "MONTH", "NATIONAL", "NATURAL", "NCHAR", "NO", "NOT",
104+
"NULL", "NUMERIC", "OCTET_LENGTH", "OF", "ON", "ONLY", "OPEN", "OR", "ORDER", "OUTER", "PARAMETER", "PLAN",
105+
"POSITION", "POST_EVENT", "PRECISION", "PRIMARY", "PROCEDURE", "RDB$DB_KEY", "REAL", "RECORD_VERSION",
106+
"RECREATE", "RECURSIVE", "REFERENCES", "RELEASE", "RETURNING_VALUES", "RETURNS", "REVOKE", "RIGHT",
107+
"ROLLBACK", "ROWS", "ROW_COUNT", "SAVEPOINT", "SECOND", "SELECT", "SENSITIVE", "SET", "SIMILAR", "SMALLINT",
108+
"SOME", "SQLCODE", "SQLSTATE", "START", "SUM", "TABLE", "THEN", "TIME", "TIMESTAMP", "TO", "TRAILING",
109+
"TRIGGER", "TRIM", "UNION", "UNIQUE", "UPDATE", "UPPER", "USER", "USING", "VALUE", "VALUES", "VARCHAR",
110+
"VARIABLE", "VARYING", "VIEW", "WHEN", "WHERE", "WHILE", "WITH", "YEAR"),
111+
FIREBIRD_2_1(2, 1, "ACTIVE", "ADD", "ADMIN", "AFTER", "ALL", "ALTER", "AND", "ANY", "AS", "ASC", "ASCENDING", "AT",
112+
"AUTO", "AVG", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BIT_LENGTH", "BLOB", "BOTH", "BY", "CASE", "CAST",
113+
"CHAR", "CHARACTER", "CHARACTER_LENGTH", "CHAR_LENGTH", "CHECK", "CLOSE", "COLLATE", "COLUMN", "COMMIT",
114+
"COMMITTED", "COMPUTED", "CONDITIONAL", "CONNECT", "CONSTRAINT", "CONTAINING", "COUNT", "CREATE", "CROSS",
115+
"CSTRING", "CURRENT", "CURRENT_CONNECTION", "CURRENT_DATE", "CURRENT_ROLE", "CURRENT_TIME",
116+
"CURRENT_TIMESTAMP", "CURRENT_TRANSACTION", "CURRENT_USER", "CURSOR", "DATABASE", "DATE", "DAY", "DEBUG",
117+
"DEC", "DECIMAL", "DECLARE", "DEFAULT", "DELETE", "DESC", "DESCENDING", "DISCONNECT", "DISTINCT", "DO",
118+
"DOMAIN", "DOUBLE", "DROP", "ELSE", "END", "ENTRY_POINT", "ESCAPE", "EXCEPTION", "EXECUTE", "EXISTS",
119+
"EXIT", "EXTERNAL", "EXTRACT", "FETCH", "FILE", "FILTER", "FLOAT", "FOR", "FOREIGN", "FROM", "FULL",
120+
"FUNCTION", "GDSCODE", "GENERATOR", "GEN_ID", "GLOBAL", "GRANT", "GROUP", "HAVING", "HOUR", "IF", "IN",
121+
"INACTIVE", "INDEX", "INNER", "INPUT_TYPE", "INSENSITIVE", "INSERT", "INT", "INTEGER", "INTO", "IS",
122+
"ISOLATION", "JOIN", "KEY", "LEADING", "LEFT", "LENGTH", "LEVEL", "LIKE", "LONG", "LOWER", "MANUAL", "MAX",
123+
"MAXIMUM_SEGMENT", "MERGE", "MIN", "MINUTE", "MODULE_NAME", "MONTH", "NAMES", "NATIONAL", "NATURAL",
124+
"NCHAR", "NO", "NOT", "NULL", "NUMERIC", "OCTET_LENGTH", "OF", "ON", "ONLY", "OPEN", "OPTION", "OR",
125+
"ORDER", "OUTER", "OUTPUT_TYPE", "OVERFLOW", "PAGE", "PAGES", "PAGE_SIZE", "PARAMETER", "PASSWORD", "PLAN",
126+
"POSITION", "POST_EVENT", "PRECISION", "PRIMARY", "PRIVILEGES", "PROCEDURE", "PROTECTED", "RDB$DB_KEY",
127+
"READ", "REAL", "RECORD_VERSION", "RECREATE", "RECURSIVE", "REFERENCES", "RELEASE", "RESERV", "RESERVING",
128+
"RETAIN", "RETURNING_VALUES", "RETURNS", "REVOKE", "RIGHT", "ROLLBACK", "ROWS", "ROW_COUNT", "SAVEPOINT",
129+
"SCHEMA", "SECOND", "SEGMENT", "SELECT", "SENSITIVE", "SET", "SHADOW", "SHARED", "SINGULAR", "SIZE",
130+
"SMALLINT", "SNAPSHOT", "SOME", "SORT", "SQLCODE", "STABILITY", "START", "STARTING", "STARTS", "STATISTICS",
131+
"SUB_TYPE", "SUM", "SUSPEND", "TABLE", "THEN", "TIME", "TIMESTAMP", "TO", "TRAILING", "TRANSACTION",
132+
"TRIGGER", "TRIM", "UNCOMMITTED", "UNION", "UNIQUE", "UPDATE", "UPPER", "USER", "USING", "VALUE", "VALUES",
133+
"VARCHAR", "VARIABLE", "VARYING", "VIEW", "WAIT", "WHEN", "WHERE", "WHILE", "WITH", "WORK", "WRITE",
134+
"YEAR"),
49135
;
50136

137+
private final BasicVersion version;
51138
private final Set<CharSequence> reservedWords;
52139

53-
FirebirdReservedWords(CharSequence... reservedWords) {
140+
FirebirdReservedWords(int major, int minor, CharSequence... reservedWords) {
141+
version = BasicVersion.of(major, minor);
54142
this.reservedWords = toUnmodifiableCaseInsensitiveSet(Arrays.asList(reservedWords));
55143
}
56144

145+
/**
146+
* @return Firebird version
147+
*/
148+
final BasicVersion version() {
149+
return version;
150+
}
151+
57152
/**
58153
* Reserved words for latest known Firebird version.
59154
*
@@ -63,14 +158,49 @@ public static FirebirdReservedWords latest() {
63158
return FIREBIRD_5_0;
64159
}
65160

161+
/**
162+
* Reserved words for the specified Firebird version.
163+
*
164+
* @param major
165+
* Firebird major version
166+
* @param minor Firebird minor version
167+
* @return reserved words for the specified version, or the closest known version
168+
* @see #of(AbstractVersion)
169+
* @since 7
170+
*/
171+
public static FirebirdReservedWords of(int major, int minor) {
172+
return of(BasicVersion.of(major, minor));
173+
}
174+
175+
/**
176+
* Reserved words for the specified Firebird version.
177+
*
178+
* @param version
179+
* Firebird version
180+
* @return reserved words for the specified version, or the closest known version
181+
* @see #of(int, int)
182+
* @since 7
183+
*/
184+
public static FirebirdReservedWords of(AbstractVersion version) {
185+
FirebirdReservedWords[] values = values();
186+
for (FirebirdReservedWords reservedWords : values) {
187+
if (version.compareTo(reservedWords.version) >= 0) {
188+
return reservedWords;
189+
}
190+
}
191+
// fall back to the lowest known version
192+
return values[values.length - 1];
193+
}
194+
66195
private static Set<CharSequence> toUnmodifiableCaseInsensitiveSet(Collection<CharSequence> values) {
67196
Set<CharSequence> set = new TreeSet<>(CharSequenceComparison.caseInsensitiveComparator());
68197
set.addAll(values);
69198
return unmodifiableSet(set);
70199
}
71200

72201
@Override
73-
public boolean isReservedWord(CharSequence tokenText) {
202+
public final boolean isReservedWord(CharSequence tokenText) {
74203
return reservedWords.contains(tokenText);
75204
}
205+
76206
}

src/main/org/firebirdsql/jdbc/AbstractStatement.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
SPDX-FileCopyrightText: Copyright 2002-2011 Roman Rokytskyy
44
SPDX-FileCopyrightText: Copyright 2002-2003 Blas Rodriguez Somoza
55
SPDX-FileCopyrightText: Copyright 2005 Gabriel Reid
6-
SPDX-FileCopyrightText: Copyright 2011-2024 Mark Rotteveel
6+
SPDX-FileCopyrightText: Copyright 2011-2026 Mark Rotteveel
77
SPDX-License-Identifier: LGPL-2.1-or-later
88
*/
99
package org.firebirdsql.jdbc;
@@ -362,6 +362,45 @@ protected final void addWarning(SQLWarning warning) {
362362
}
363363
}
364364

365+
/**
366+
* Returns a {@code String} enclosed in single quotes. Any occurrence of a single quote within the string will be
367+
* replaced by two single quotes (for dialect 1, double quotes instead of single quotes).
368+
*
369+
* @see FirebirdConnection#enquoteLiteral(String)
370+
*/
371+
@Override
372+
public final String enquoteLiteral(String val) throws SQLException {
373+
return connection.enquoteLiteral(val);
374+
}
375+
376+
/**
377+
* @see #enquoteLiteral(String)
378+
*/
379+
@Override
380+
public final String enquoteNCharLiteral(String val) throws SQLException {
381+
return enquoteLiteral(val);
382+
}
383+
384+
/**
385+
* Returns a SQL identifier, appropriately delimited if needed.
386+
*
387+
* @see FirebirdConnection#enquoteIdentifier(String, boolean)
388+
*/
389+
@Override
390+
public final String enquoteIdentifier(String identifier, boolean alwaysDelimit) throws SQLException {
391+
return connection.enquoteIdentifier(identifier, alwaysDelimit);
392+
}
393+
394+
/**
395+
* Returns whether {@code identifier} is a simple SQL identifier.
396+
*
397+
* @see FirebirdConnection#isSimpleIdentifier(String)
398+
*/
399+
@Override
400+
public final boolean isSimpleIdentifier(String identifier) throws SQLException {
401+
return connection.isSimpleIdentifier(identifier);
402+
}
403+
365404
@Override
366405
public final int getLocalStatementId() {
367406
return localStatementId;

0 commit comments

Comments
 (0)