package javaxt.sql;
import java.sql.ResultSet;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import javax.sql.ConnectionPoolDataSource;
//******************************************************************************
//** Database
//******************************************************************************
/**
* Used to encapsulate database connection information, open connections to
* the database, and execute queries.
*
******************************************************************************/
public class Database implements Cloneable {
private String name; //name of the catalog used to store tables, views, etc.
private String host;
private Integer port;
private String username;
private String password;
private Driver driver;
private java.util.Properties properties;
private String querystring;
private ConnectionPoolDataSource ConnectionPoolDataSource;
private static final Class>[] stringType = { String.class };
private static final Class>[] integerType = { Integer.TYPE };
private ConnectionPool connectionPool;
private int maxConnections = 15;
private Table[] tables = null;
private String[] catalogs = null;
private boolean cacheMetadata = false;
//**************************************************************************
//** Constructor
//**************************************************************************
/** Creates a new instance of this class. Note that you will need to set the
* name, host, port, username, password, and driver in order to create a
* connection to the database.
*/
public Database(){
}
//**************************************************************************
//** Constructor
//**************************************************************************
/** Creates a new instance of this class.
* @param name Name of the catalog used to store tables, views, etc.
* @param host Server name or IP address.
* @param port Port number used to establish connections to the database.
* @param username Username used to log into the database
* @param password Password used to log into the database
*/
public Database(String name, String host, int port, String username, String password, Driver driver) {
this.name = name;
this.host = host;
this.port = port>0 ? port : null;
this.username = username;
this.password = password;
this.driver = driver;
}
//**************************************************************************
//** Constructor
//**************************************************************************
/** Creates a new instance of this class using a java.sql.Connection.
*/
public Database(java.sql.Connection conn){
try{
DatabaseMetaData dbmd = conn.getMetaData();
this.name = conn.getCatalog();
this.username = dbmd.getUserName();
parseURL(dbmd.getURL());
//dbmd.getDriverName();
}
catch(Exception e){
//e.printStackTrace();
}
}
//**************************************************************************
//** Constructor
//**************************************************************************
/** Creates a new instance of this class using a jdbc connection string.
* Username and password may be appended to the end of the connection string
* in the property list.
* @param connStr A jdbc connection string/url. All connection URLs
* have the following form:
*
jdbc:[dbVendor]://[dbName][propertyList]
*
* Examples:
* Derby:
* jdbc:derby://temp/my.db;user=admin;password=mypassword
* SQL Server:
* jdbc:sqlserver://192.168.0.80;databaseName=master;user=admin;password=mypassword
*/
public Database(String connStr){
parseURL(connStr);
}
//**************************************************************************
//** parseURL
//**************************************************************************
/** Used to parse a JDBC connection string (url)
*/
private void parseURL(String connStr){
String[] arrConnStr = connStr.split(";");
String jdbcURL = arrConnStr[0];
//Update jdbc url for URL parser
if (!jdbcURL.contains("//")){
String protocol = jdbcURL.substring(jdbcURL.indexOf(":")+1);
protocol = "jdbc:" + protocol.substring(0, protocol.indexOf(":")) + ":";
String path = jdbcURL.substring(protocol.length());
jdbcURL = protocol + "//" + path;
}
//Parse url and extract connection parameters
javaxt.utils.URL url = new javaxt.utils.URL(jdbcURL);
host = url.getHost();
port = url.getPort();
driver = Driver.findDriver(url.getProtocol());
if (driver==null){
driver = new Driver(null, null, url.getProtocol());
}
if (name==null){
name = url.getPath();
if (this.name!=null && this.name.startsWith("/")){
this.name = this.name.substring(1);
}
}
querystring = url.getQueryString();
if (querystring.length()==0) querystring = null;
//Extract additional connection parameters
for (int i=1; i0) server += ":" + port;
String vendor = driver.getVendor();
if (vendor==null) vendor = "";
if (vendor.equals("Derby") || vendor.equals("SQLite")){
server = ":" + server;
}
//Update Initial Catalog
String database = "";
if (name!=null) {
if (name.trim().length()>0){
if (vendor.equals("SQLServer")){
database = ";databaseName=" + name;
}
else if (vendor.equals("Oracle")){
database = ":" + name; //only tested with thin driver
}
else if (vendor.equals("Derby")){
database = ";databaseName=" + name;
}
else{
database = "/" + name;
}
}
}
//Append querystring as needed
if (querystring!=null) database += "?" + querystring;
//Set Path
String path = driver.getProtocol() + "://";
//Update path as needed
if (vendor.equals("Sybase")){
if (path.toLowerCase().contains((CharSequence) "tds:")==false){
path = driver.getProtocol() + "Tds:";
}
}
else if (vendor.equals("Oracle")){
path = driver.getProtocol() + ":thin:@"; //only tested with thin driver
}
else if (vendor.equals("Derby") || vendor.equals("SQLite")){
path = driver.getProtocol();
}
else if (vendor.equals("H2")){
//Special case for newer versions of H2. In the 2.x releases of H2,
//the protocol changed for embedded file databases. The following
//logic will update the path to set the correct protocol depending
//on which version of the driver we have.
if (driver.getProtocol().equals("jdbc:h2")){
java.sql.Driver d = driver.getDriver();
try{
if (d==null) d = driver.load();
if (d.getMajorVersion()>1){
if (host == null || host.trim().isEmpty() || host.equalsIgnoreCase("memory")) {
path = driver.getProtocol() + ":mem:";
} else {
path = driver.getProtocol() + ":file:";
}
}
}
catch(Exception e){
}
}
}
//Assemble Connection String
String url = path + server + database;
if (appendProperties){
StringBuilder props = new StringBuilder();
if (properties!=null){
java.util.Iterator it = properties.keySet().iterator();
while (it.hasNext()){
Object key = it.next();
Object val = properties.get(key);
props.append(";" + key + "=" + val);
}
}
url+= props.toString();
}
return url;
}
//**************************************************************************
//** getConnection
//**************************************************************************
/** Returns a connection to the database. If a connection pool has been
* initialized, a connection is returned from the pool. Otherwise, a new
* connection is created. In either case, the connection must be closed
* immediately after use. See Connection.close() for details.
*/
public Connection getConnection() throws SQLException {
Connection connection = new Connection();
connection.open(this);
return connection;
}
//**************************************************************************
//** initConnectionPool
//**************************************************************************
/** Used to initialize a connection pool. Subsequent called to the
* getConnection() method will return connections from the pool.
*/
public void initConnectionPool() throws SQLException {
if (connectionPool!=null) return;
initConnectionPool(new ConnectionPool(this, maxConnections));
}
//**************************************************************************
//** initConnectionPool
//**************************************************************************
/** Used to configure the Database class to use a specific instance of a
* javaxt.sql.ConnectionPool. Subsequent called to the getConnection()
* method will return connections from the pool.
* @param cp An instance of a javaxt.sql.ConnectionPool.
*/
public void initConnectionPool(ConnectionPool cp) throws SQLException {
if (connectionPool!=null) return;
connectionPool = cp;
//Create Shutdown Hook to clean up the connection pool on exit
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
if (connectionPool!=null){
//System.out.println("\r\nShutting down connection pool...");
try{
connectionPool.close();
}
catch(Exception e){
//e.printStackTrace();
}
}
}
});
}
//**************************************************************************
//** terminateConnectionPool
//**************************************************************************
/** Used to terminate the connection pool, closing all active connections.
*/
public void terminateConnectionPool() throws SQLException {
if (connectionPool!=null){
connectionPool.close();
connectionPool = null;
}
}
//**************************************************************************
//** setConnectionPoolSize
//**************************************************************************
/** Used to specify the size of the connection pool. The pool size must be
* set before initializing the connection pool. If the pool size is not
* defined, the connection pool will default to 15.
*/
public void setConnectionPoolSize(int maxConnections){
if (connectionPool!=null) return;
this.maxConnections = maxConnections;
}
//**************************************************************************
//** getConnectionPoolSize
//**************************************************************************
/** Returns the size of the connection pool.
*/
public int getConnectionPoolSize(){
return maxConnections;
}
//**************************************************************************
//** getConnectionPool
//**************************************************************************
/** Returns the connection pool that was created via the initConnectionPool
* method. Returns null if the connection pool has not been not initialized
* or if the connection pool has been terminated.
*/
public ConnectionPool getConnectionPool(){
return connectionPool;
}
//**************************************************************************
//** setConnectionPoolDataSource
//**************************************************************************
/** Used to set the ConnectionPoolDataSource for the database. Typically,
* the getConnectionPoolDataSource() method is used to create a
* ConnectionPoolDataSource. This method allows you to specify a different
* ConnectionPoolDataSource.
*/
public void setConnectionPoolDataSource(ConnectionPoolDataSource dataSource){
this.ConnectionPoolDataSource = dataSource;
}
//**************************************************************************
//** getConnectionPoolDataSource
//**************************************************************************
/** Used to instantiate a ConnectionPoolDataSource for the database. The
* ConnectionPoolDataSource is typically used to create a JDBC Connection
* Pool.
*/
public ConnectionPoolDataSource getConnectionPoolDataSource() throws SQLException {
if (ConnectionPoolDataSource!=null) return ConnectionPoolDataSource;
if (driver==null) throw new SQLException(
"Failed to create a ConnectionPoolDataSource. Please specify a driver.");
String className = null;
java.util.HashMap methods = new java.util.HashMap<>();
if (driver.equals("sqlite")){
className = "org.sqlite.SQLiteConnectionPoolDataSource";
methods.put("setUrl", "jdbc:sqlite:" + host);
/*
javax.sql.DataSource sqliteDS = new DataSource();
sqliteDS.setURL ("jdbc:sqlite://" + name);
dataSource = sqliteDS;
*/
}
else if (driver.equals("derby")){
className = ("org.apache.derby.jdbc.EmbeddedConnectionPoolDataSource");
methods.put("setDatabaseName", host);
methods.put("setCreateDatabase", "create");
}
else if (driver.equals("h2")){
className = ("org.h2.jdbcx.JdbcDataSource");
//URL requirements changed from 1.x to 2.x. Starting with 2.x, we
//now have to add properties to the end of the url
String url = null;
java.sql.Driver d = driver.getDriver();
try{
if (d==null) d = driver.load();
if (d.getMajorVersion()>1){
url = getURL(true);
}
}
catch(Exception e){}
methods.put("setURL", url==null ? getURL(false) : url);
methods.put("setUser", username);
methods.put("setPassword", password);
}
else if (driver.equals("sqlserver")){ //mssql
className = ("com.microsoft.sqlserver.jdbc.SQLServerXADataSource");
methods.put("setDatabaseName", name);
methods.put("setServerName", host);
methods.put("setUser", username);
methods.put("setPassword", password);
}
else if (driver.equals("postgresql")){ //pgsql
className = ("org.postgresql.ds.PGConnectionPoolDataSource");
methods.put("setDatabaseName", name);
methods.put("setServerName", host);
methods.put("setPortNumber", port);
methods.put("setUser", username);
methods.put("setPassword", password);
}
else if (driver.equals("mysql")){
className = ("com.mysql.cj.jdbc.MysqlConnectionPoolDataSource");
methods.put("setDatabaseName", name);
methods.put("setServerName", host);
methods.put("setPortNumber", port); //setPort?
methods.put("setUser", username);
methods.put("setPassword", password);
}
else if (driver.equals("oracle")){
String connDriver = "thin";
String connService = "";
className = ("oracle.jdbc.pool.OracleConnectionPoolDataSource");
methods.put("setDriverType", connDriver);
methods.put("setServerName", host);
methods.put("setPortNumber", port);
methods.put("setServiceName", connService);
methods.put("setUser", username);
methods.put("setPassword", password);
}
else if (driver.equals("jtds")){
className = ("net.sourceforge.jtds.jdbcx.JtdsDataSource");
methods.put("setDatabaseName", name);
methods.put("setServerName", host);
methods.put("setUser", username);
methods.put("setPassword", password);
}
//Instantiate the ConnectionPoolDataSource
if (className!=null){
try{
Class classToLoad = Class.forName(className);
Object instance = classToLoad.newInstance();
java.util.Iterator it = methods.keySet().iterator();
while (it.hasNext()){
String methodName = it.next();
Object parameter = methods.get(methodName);
if (parameter!=null){
java.lang.reflect.Method method = null;
if (parameter instanceof String)
method = classToLoad.getMethod(methodName, stringType);
else if (parameter instanceof Integer)
method = classToLoad.getMethod(methodName, integerType);
if (method!=null) method.invoke(instance, new Object[] { parameter });
}
}
ConnectionPoolDataSource = (ConnectionPoolDataSource) instance;
return ConnectionPoolDataSource;
}
catch(Exception e){
throw new SQLException("Failed to instantiate the ConnectionPoolDataSource.", e);
}
}
throw new SQLException("Failed to find a suitable ConnectionPoolDataSource.");
}
//**************************************************************************
//** getRecord
//**************************************************************************
/** Used to retrieve a single record from this database.
*/
public javaxt.sql.Record getRecord(String sql) throws SQLException {
try (Connection conn = getConnection()){
return conn.getRecord(sql);
}
}
//**************************************************************************
//** getRecords
//**************************************************************************
/** Used to retrieve records from this database. Note that this method
* relies on a Generator to yield records. This is fine for relatively
* small record sets. However, for large record sets, we recommend opening
* a database connection first and calling Connection.getRecords() like
* this:
try (Connection conn = database.getConnection()){
return conn.getRecords(sql);
}
*/
public Iterable getRecords(String sql) throws SQLException {
return new javaxt.utils.Generator(){
public void run() throws InterruptedException {
try (Connection conn = getConnection()){
for (javaxt.sql.Record record : conn.getRecords(sql)){
try{
this.yield(record);
}
catch(InterruptedException e){
return;
}
}
}
catch(Exception e){
RuntimeException ex = new RuntimeException(e.getMessage());
ex.setStackTrace(e.getStackTrace());
throw ex;
}
}
};
}
//**************************************************************************
//** getTables
//**************************************************************************
/** Used to retrieve an array of tables and columns found in this database.
*/
public Table[] getTables() throws SQLException {
if (tables!=null) return tables;
try (Connection conn = getConnection()){
return getTables(conn);
}
}
//**************************************************************************
//** getTables
//**************************************************************************
/** Used to retrieve an array of tables and columns found in a database.
*/
public static Table[] getTables(Connection conn){
Database database = conn.getDatabase();
if (database!=null){
if (database.tables!=null) return database.tables;
}
java.util.ArrayList tables = new java.util.ArrayList<>();
try{
DatabaseMetaData dbmd = conn.getConnection().getMetaData();
try(ResultSet rs = dbmd.getTables(null,null,null,getTableFilter(database))){
while (rs.next()) {
tables.add(new Table(rs, dbmd));
}
}
}
catch(Exception e){
}
Table[] arr = tables.toArray(new Table[tables.size()]);
if (database!=null){
if (database.cacheMetadata) database.tables = arr;
}
return arr;
}
//**************************************************************************
//** getTableNames
//**************************************************************************
/** Used to retrieve an array of table names found in the database. If a
* table is part of a schema, the schema name is prepended to the table
* name. This method is significantly faster than the getTables() method
* which returns the full metadata for each table.
*/
public String[] getTableNames() throws SQLException {
java.util.ArrayList tableNames = new java.util.ArrayList<>();
if (tables!=null){
for (Table table : tables){
javaxt.utils.Record record = new javaxt.utils.Record();
record.set("schema", table.getSchema());
record.set("table", table.getName());
tableNames.add(record);
}
}
else{
try (Connection conn = getConnection()){
DatabaseMetaData dbmd = conn.getConnection().getMetaData();
try (ResultSet rs = dbmd.getTables(null,null,null,getTableFilter(this))){
while (rs.next()) {
javaxt.utils.Record record = new javaxt.utils.Record();
record.set("schema", rs.getString("TABLE_SCHEM"));
record.set("table", rs.getString("TABLE_NAME"));
tableNames.add(record);
}
}
}
}
String[] arr = new String[tableNames.size()];
for (int i=0; i catalogs = new java.util.TreeSet();
try{
DatabaseMetaData dbmd = conn.getConnection().getMetaData();
try (ResultSet rs = dbmd.getCatalogs()){
while (rs.next()) {
catalogs.add(rs.getString(1));
}
}
}
catch(Exception e){
return null;
}
String[] arr = catalogs.toArray(new String[catalogs.size()]);
if (database!=null){
if (database.cacheMetadata) database.catalogs = arr;
}
return arr;
}
//**************************************************************************
//** getReservedKeywords
//**************************************************************************
/** Returns a list of reserved keywords for the current database.
*/
public String[] getReservedKeywords() throws Exception {
try(Connection conn = this.getConnection()){
return getReservedKeywords(conn);
}
}
//**************************************************************************
//** getReservedKeywords
//**************************************************************************
/** Returns a list of reserved keywords for a given database.
*/
public static String[] getReservedKeywords(Connection conn){
Database database = conn.getDatabase();
javaxt.sql.Driver driver = database.getDriver();
if (driver==null) driver = new Driver("","","");
if (driver.equals("Firebird")){
return fbKeywords;
}
else if (driver.equals("SQLServer")){
return msKeywords;
}
else if (driver.equals("H2")){
//Check if a "MODE" is set
String mode = "";
java.util.Properties properties = database.getProperties();
if (properties!=null){
Object o = properties.get("MODE");
if (o!=null) mode = o.toString();
}
if (mode.equalsIgnoreCase("PostgreSQL")){
return java.util.stream.Stream.concat(
java.util.Arrays.stream(h2Keywords),
java.util.Arrays.stream(pgKeywords)
).toArray(String[]::new);
}
else{
return h2Keywords;
}
}
else if (driver.equals("PostgreSQL")){
//Try to get reserved keywords from the database. Note that in PostgreSQL
//"non-reserved" keywords are key words that are explicitly known to
//the parser but are allowed as column or table names. Therefore, we
//will ignore "non-reserved" keywords from our query.
if (pgKeywords==null){
java.util.HashSet arr = new java.util.HashSet<>();
try (java.sql.Statement stmt = conn.getConnection().createStatement(
java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY,
java.sql.ResultSet.FETCH_FORWARD)){
try (java.sql.ResultSet rs = stmt.executeQuery(
"select word from pg_get_keywords() where catcode='R'")){
while(rs.next()){
arr.add(rs.getString(1));
}
}
}
catch(java.sql.SQLException e){
e.printStackTrace();
}
String[] keywords = new String[arr.size()];
int i=0;
java.util.Iterator it = arr.iterator();
while (it.hasNext()){
keywords[i] = it.next();
i++;
}
pgKeywords = keywords;
}
return pgKeywords;
}
else{
return ansiKeywords;
}
}
//**************************************************************************
//** enableMetadataCache
//**************************************************************************
/** Used to enable/disable metadata caching. If caching is enabled, calls
* to getTables() and getCatalogs() will return cached results. This is
* appropriate if the database schema doesn't change often and may increase
* performance when inserting and updating records via the Recordset class.
* @param b If true, will cache database metadata. If false, will disable
* metadata caching and delete any information than was previously cached.
*/
public void enableMetadataCache(boolean b){
cacheMetadata = b;
if (b==false){
tables = null;
catalogs = null;
}
}
//**************************************************************************
//** addModel
//**************************************************************************
/** Used to register a javaxt.sql.Model with the database. The model is
* initialized and associated with the database connection pool. Once the
* model is initialized, it can be used to find records in the database
* and execute CRUD operations.
* @param c A Java class that extends the javaxt.sql.Model abstract class.
*/
public void addModel(Class c) throws SQLException {
//Check if class is a model
if (!Model.class.isAssignableFrom(c)){
throw new IllegalArgumentException();
}
//Initialize connectionPool as needed
if (connectionPool==null) initConnectionPool();
if (connectionPool==null){
throw new SQLException("Connection pool has not been initialized");
}
Model.init(c, connectionPool);
}
//**************************************************************************
//** displayDbProperties
//**************************************************************************
public static void displayDbProperties(Connection conn){
if (conn==null){
System.out.println("Error: Connection is null");
return;
}
try{
java.sql.DatabaseMetaData dm = conn.getConnection().getMetaData();
System.out.println("Driver Information");
System.out.println("\tDriver Name: "+ dm.getDriverName());
System.out.println("\tDriver Version: "+ dm.getDriverVersion ());
System.out.println("\nDatabase Information ");
System.out.println("\tDatabase Name: "+ dm.getDatabaseProductName());
System.out.println("\tDatabase Version: "+ dm.getDatabaseProductVersion());
System.out.println("Avalilable Catalogs ");
try (java.sql.ResultSet rs = dm.getCatalogs()){
while(rs.next()){
System.out.println("\tcatalog: "+ rs.getString(1));
}
}
}
catch(Exception e){
e.printStackTrace();
}
}
//**************************************************************************
//** toString
//**************************************************************************
/** Returns database connection information encapsulated by this class.
*/
public String toString(){
StringBuffer str = new StringBuffer();
str.append("Name: " + name + "\r\n");
str.append("Host: " + host + "\r\n");
str.append("Port: " + port + "\r\n");
str.append("UserName: " + username + "\r\n");
str.append("Driver: " + driver + "\r\n");
str.append("URL: " + getURL(false) + "\r\n");
str.append("ConnStr: " + this.getConnectionString());
return str.toString();
}
//**************************************************************************
//** clone
//**************************************************************************
public Database clone(){
Database db = new Database(name, host, port==null ? -1 : port, username, password, driver);
if (properties!=null) db.properties = (java.util.Properties) properties.clone();
db.querystring = querystring;
return db;
}
/** Firebird reserved keywords. */
private static final String[] fbKeywords = new String[]{
"ADD","ADMIN","ALL","ALTER","AND","ANY","AS","AT","AVG","BEGIN","BETWEEN",
"BIGINT","BIT_LENGTH","BLOB","BOTH","BY","CASE","CAST","CHAR","CHAR_LENGTH",
"CHARACTER","CHARACTER_LENGTH","CHECK","CLOSE","COLLATE","COLUMN","COMMIT",
"CONNECT","CONSTRAINT","COUNT","CREATE","CROSS","CURRENT","CURRENT_CONNECTION",
"CURRENT_DATE","CURRENT_ROLE","CURRENT_TIME","CURRENT_TIMESTAMP",
"CURRENT_TRANSACTION","CURRENT_USER","CURSOR","DATE","DAY","DEC","DECIMAL",
"DECLARE","DEFAULT","DELETE","DISCONNECT","DISTINCT","DOUBLE","DROP","ELSE",
"END","ESCAPE","EXECUTE","EXISTS","EXTERNAL","EXTRACT","FETCH","FILTER",
"FLOAT","FOR","FOREIGN","FROM","FULL","FUNCTION","GDSCODE","GLOBAL","GRANT",
"GROUP","HAVING","HOUR","IN","INDEX","INNER","INSENSITIVE","INSERT","INT",
"INTEGER","INTO","IS","JOIN","LEADING","LEFT","LIKE","LONG","LOWER","MAX",
"MAXIMUM_SEGMENT","MERGE","MIN","MINUTE","MONTH","NATIONAL","NATURAL","NCHAR",
"NO","NOT","NULL","NUMERIC","OCTET_LENGTH","OF","ON","ONLY","OPEN","OR",
"ORDER","OUTER","PARAMETER","PLAN","POSITION","POST_EVENT","PRECISION",
"PRIMARY","PROCEDURE","RDB$DB_KEY","REAL","RECORD_VERSION","RECREATE",
"RECURSIVE","REFERENCES","RELEASE","RETURNING_VALUES","RETURNS","REVOKE",
"RIGHT","ROLLBACK","ROW_COUNT","ROWS","SAVEPOINT","SECOND","SELECT","SENSITIVE",
"SET","SIMILAR","SMALLINT","SOME","SQLCODE","SQLSTATE","START","SUM","TABLE",
"THEN","TIME","TIMESTAMP","TO","TRAILING","TRIGGER","TRIM","UNION","UNIQUE",
"UPDATE","UPPER","USER","USING","VALUE","VALUES","VARCHAR","VARIABLE","VARYING",
"VIEW","WHEN","WHERE","WHILE","WITH","YEAR"
};
/** SQLServer reserved keywords. Source:
* https://msdn.microsoft.com/en-us/library/ms189822.aspx
*/
private static final String[] msKeywords = new String[]{
"ADD","ALL","ALTER","AND","ANY","AS","ASC","AUTHORIZATION","BACKUP","BEGIN",
"BETWEEN","BREAK","BROWSE","BULK","BY","CASCADE","CASE","CHECK","CHECKPOINT",
"CLOSE","CLUSTERED","COALESCE","COLLATE","COLUMN","COMMIT","COMPUTE",
"CONSTRAINT","CONTAINS","CONTAINSTABLE","CONTINUE","CONVERT","CREATE","CROSS",
"CURRENT","CURRENT_DATE","CURRENT_TIME","CURRENT_TIMESTAMP","CURRENT_USER",
"CURSOR","DATABASE","DBCC","DEALLOCATE","DECLARE","DEFAULT","DELETE","DENY",
"DESC","DISK","DISTINCT","DISTRIBUTED","DOUBLE","DROP","DUMP","ELSE","END",
"ERRLVL","ESCAPE","EXCEPT","EXEC","EXECUTE","EXISTS","EXIT","EXTERNAL",
"FETCH","FILE","FILLFACTOR","FOR","FOREIGN","FREETEXT","FREETEXTTABLE",
"FROM","FULL","FUNCTION","GOTO","GRANT","GROUP","HAVING","HOLDLOCK","IDENTITY",
"IDENTITY_INSERT","IDENTITYCOL","IF","IN","INDEX","INNER","INSERT","INTERSECT",
"INTO","IS","JOIN","KEY","KILL","LEFT","LIKE","LINENO","LOAD","MERGE","NATIONAL",
"NOCHECK","NONCLUSTERED","NOT","NULL","NULLIF","OF","OFF","OFFSETS","ON",
"OPEN","OPENDATASOURCE","OPENQUERY","OPENROWSET","OPENXML","OPTION","OR",
"ORDER","OUTER","OVER","PERCENT","PIVOT","PLAN","PRECISION","PRIMARY","PRINT",
"PROC","PROCEDURE","PUBLIC","RAISERROR","READ","READTEXT","RECONFIGURE",
"REFERENCES","REPLICATION","RESTORE","RESTRICT","RETURN","REVERT","REVOKE",
"RIGHT","ROLLBACK","ROWCOUNT","ROWGUIDCOL","RULE","SAVE","SCHEMA","SECURITYAUDIT",
"SELECT","SEMANTICKEYPHRASETABLE","SEMANTICSIMILARITYDETAILSTABLE",
"SEMANTICSIMILARITYTABLE","SESSION_USER","SET","SETUSER","SHUTDOWN","SOME",
"STATISTICS","SYSTEM_USER","TABLE","TABLESAMPLE","TEXTSIZE","THEN","TO",
"TOP","TRAN","TRANSACTION","TRIGGER","TRUNCATE","TRY_CONVERT","TSEQUAL",
"UNION","UNIQUE","UNPIVOT","UPDATE","UPDATETEXT","USE","USER","VALUES",
"VARYING","VIEW","WAITFOR","WHEN","WHERE","WHILE","WITH","WITHIN GROUP",
"WRITETEXT"
};
/** H2 reserved keywords. Source:
* http://www.h2database.com/html/advanced.html#keywords
*/
private static final String[] h2Keywords = new String[]{
"ALL","AND","ARRAY","AS","BETWEEN","BOTH","CASE","CHECK","CONSTRAINT",
"CROSS","CURRENT_DATE","CURRENT_TIME","CURRENT_TIMESTAMP","CURRENT_USER",
"DISTINCT","EXCEPT","EXISTS","FALSE","FETCH","FILTER","FOR","FOREIGN",
"FROM","FULL","GROUP","GROUPS","HAVING","IF","ILIKE","IN","INNER",
"INTERSECT","INTERSECTS","INTERVAL","IS","JOIN","KEY","LEADING","LEFT","LIKE",
"LIMIT","LOCALTIME","LOCALTIMESTAMP","MINUS","NATURAL","NOT","NULL","OFFSET",
"ON","OR","ORDER","OVER","PARTITION","PRIMARY","QUALIFY","RANGE","REGEXP",
"RIGHT","ROW","_ROWID_","ROWNUM","ROWS","SELECT","SYSDATE","SYSTIME",
"SYSTIMESTAMP","TABLE","TODAY","TOP","TRAILING","TRUE","UNION","UNIQUE",
"VALUE","VALUES","WHERE","WINDOW","WITH","YEAR"
};
/** PostgreSQL reserved keywords generated via the following query using PG15:
select string_agg('"' || UPPER(word) || '"', ',') from pg_get_keywords() where catcode='R';
*/
private static String[] pgKeywords = new String[]{
"ALL","ANALYSE","ANALYZE","AND","ANY","ARRAY","AS","ASC","ASYMMETRIC",
"BOTH","CASE","CAST","CHECK","COLLATE","COLUMN","CONSTRAINT","CREATE",
"CURRENT_CATALOG","CURRENT_DATE","CURRENT_ROLE","CURRENT_TIME",
"CURRENT_TIMESTAMP","CURRENT_USER","DEFAULT","DEFERRABLE","DESC",
"DISTINCT","DO","ELSE","END","EXCEPT","FALSE","FETCH","FOR","FOREIGN",
"FROM","GRANT","GROUP","HAVING","IN","INITIALLY","INTERSECT","INTO",
"LATERAL","LEADING","LIMIT","LOCALTIME","LOCALTIMESTAMP","NOT","NULL",
"OFFSET","ON","ONLY","OR","ORDER","PLACING","PRIMARY","REFERENCES",
"RETURNING","SELECT","SESSION_USER","SOME","SYMMETRIC","TABLE","THEN",
"TO","TRAILING","TRUE","UNION","UNIQUE","USER","USING","VARIADIC",
"WHEN","WHERE","WINDOW","WITH"
};
/** Superset of SQL-92, SQL-99, SQL-2003 reserved keywords. */
private static String[] ansiKeywords = new String[]{
"ABSOLUTE","ACTION","ADD","AFTER","ALL","ALLOCATE","ALTER","AND","ANY","ARE",
"ARRAY","AS","ASC","ASENSITIVE","ASSERTION","ASYMMETRIC","AT","ATOMIC",
"AUTHORIZATION","AVG","BEFORE","BEGIN","BETWEEN","BIGINT","BINARY","BIT",
"BIT_LENGTH","BLOB","BOOLEAN","BOTH","BREADTH","BY","CALL","CALLED","CASCADE",
"CASCADED","CASE","CAST","CATALOG","CHAR","CHAR_LENGTH","CHARACTER","CHARACTER_LENGTH",
"CHECK","CLOB","CLOSE","COALESCE","COLLATE","COLLATION","COLUMN","COMMIT",
"CONDITION","CONNECT","CONNECTION","CONSTRAINT","CONSTRAINTS","CONSTRUCTOR",
"CONTAINS","CONTINUE","CONVERT","CORRESPONDING","COUNT","CREATE","CROSS",
"CUBE","CURRENT","CURRENT_DATE","CURRENT_DEFAULT_TRANSFORM_GROUP","CURRENT_PATH",
"CURRENT_ROLE","CURRENT_TIME","CURRENT_TIMESTAMP","CURRENT_TRANSFORM_GROUP_FOR_TYPE",
"CURRENT_USER","CURSOR","CYCLE","DATA","DATE","DAY","DEALLOCATE","DEC","DECIMAL",
"DECLARE","DEFAULT","DEFERRABLE","DEFERRED","DELETE","DEPTH","DEREF","DESC",
"DESCRIBE","DESCRIPTOR","DETERMINISTIC","DIAGNOSTICS","DISCONNECT","DISTINCT",
"DO","DOMAIN","DOUBLE","DROP","DYNAMIC","EACH","ELEMENT","ELSE","ELSEIF",
"END","EQUALS","ESCAPE","EXCEPT","EXCEPTION","EXEC","EXECUTE","EXISTS","EXIT",
"EXTERNAL","EXTRACT","FALSE","FETCH","FILTER","FIRST","FLOAT","FOR","FOREIGN",
"FOUND","FREE","FROM","FULL","FUNCTION","GENERAL","GET","GLOBAL","GO","GOTO",
"GRANT","GROUP","GROUPING","HANDLER","HAVING","HOLD","HOUR","IDENTITY","IF",
"IMMEDIATE","IN","INDICATOR","INITIALLY","INNER","INOUT","INPUT","INSENSITIVE",
"INSERT","INT","INTEGER","INTERSECT","INTERVAL","INTO","IS","ISOLATION",
"ITERATE","JOIN","KEY","LANGUAGE","LARGE","LAST","LATERAL","LEADING","LEAVE",
"LEFT","LEVEL","LIKE","LOCAL","LOCALTIME","LOCALTIMESTAMP","LOCATOR","LOOP",
"LOWER","MAP","MATCH","MAX","MEMBER","MERGE","METHOD","MIN","MINUTE","MODIFIES",
"MODULE","MONTH","MULTISET","NAMES","NATIONAL","NATURAL","NCHAR","NCLOB",
"NEW","NEXT","NO","NONE","NOT","NULL","NULLIF","NUMERIC","OBJECT","OCTET_LENGTH",
"OF","OLD","ON","ONLY","OPEN","OPTION","OR","ORDER","ORDINALITY","OUT","OUTER",
"OUTPUT","OVER","OVERLAPS","PAD","PARAMETER","PARTIAL","PARTITION","PATH",
"POSITION","PRECISION","PREPARE","PRESERVE","PRIMARY","PRIOR","PRIVILEGES",
"PROCEDURE","PUBLIC","RANGE","READ","READS","REAL","RECURSIVE","REF","REFERENCES",
"REFERENCING","RELATIVE","RELEASE","REPEAT","RESIGNAL","RESTRICT","RESULT",
"RETURN","RETURNS","REVOKE","RIGHT","ROLE","ROLLBACK","ROLLUP","ROUTINE",
"ROW","ROWS","SAVEPOINT","SCHEMA","SCOPE","SCROLL","SEARCH","SECOND","SECTION",
"SELECT","SENSITIVE","SESSION","SESSION_USER","SET","SETS","SIGNAL","SIMILAR",
"SIZE","SMALLINT","SOME","SPACE","SPECIFIC","SPECIFICTYPE","SQL","SQLCODE",
"SQLERROR","SQLEXCEPTION","SQLSTATE","SQLWARNING","START","STATE","STATIC",
"SUBMULTISET","SUBSTRING","SUM","SYMMETRIC","SYSTEM","SYSTEM_USER","TABLE",
"TABLESAMPLE","TEMPORARY","THEN","TIME","TIMESTAMP","TIMEZONE_HOUR","TIMEZONE_MINUTE",
"TO","TRAILING","TRANSACTION","TRANSLATE","TRANSLATION","TREAT","TRIGGER",
"TRIM","TRUE","UNDER","UNDO","UNION","UNIQUE","UNKNOWN","UNNEST","UNTIL",
"UPDATE","UPPER","USAGE","USER","USING","VALUE","VALUES","VARCHAR","VARYING",
"VIEW","WHEN","WHENEVER","WHERE","WHILE","WINDOW","WITH","WITHIN","WITHOUT",
"WORK","WRITE","YEAR","ZONE"
};
}