From 5c88ccec5c8519e94b99a5e833568ae0e6dac81d Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 1 May 2015 10:50:29 -0500 Subject: [PATCH] HHH-9768 - Maintain explicit list of ANSI SQL keywords --- .../ExtractedDatabaseMetaDataImpl.java | 11 +- .../env/internal/JdbcEnvironmentImpl.java | 24 +- .../engine/jdbc/env/spi/AnsiSqlKeywords.java | 304 ++++++++++++++++++ libraries.gradle | 1 + 4 files changed, 323 insertions(+), 17 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/AnsiSqlKeywords.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index d91c0bd50d..841f0c1875 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -26,6 +26,7 @@ package org.hibernate.engine.jdbc.env.internal; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; @@ -37,6 +38,8 @@ import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.SQLStateType; import org.hibernate.engine.jdbc.spi.TypeInfo; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.mapping.Collection; /** * Standard implementation of ExtractedDatabaseMetaData @@ -213,10 +216,12 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData } private Set parseKeywords(String extraKeywordsString) { - final Set keywordSet = new HashSet(); - for ( String keyword : extraKeywordsString.split( "," ) ) { - keywordSet.add( keyword.toUpperCase(Locale.ROOT) ); + if ( StringHelper.isEmpty( extraKeywordsString ) ) { + return Collections.emptySet(); } + + final Set keywordSet = new HashSet(); + keywordSet.addAll( Arrays.asList( extraKeywordsString.split( "\\s*,\\s*" ) ) ); return keywordSet; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index 79ae059ea6..cb8e4b4156 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -30,6 +30,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; +import java.util.TreeSet; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.registry.selector.spi.StrategySelector; @@ -37,6 +38,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; +import org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords; import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; @@ -67,8 +69,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { private final LobCreatorBuilderImpl lobCreatorBuilder; private final LinkedHashSet typeInfoSet = new LinkedHashSet(); - // todo : should really maintain a standard list of know ANSI-SQL defined keywords somewhere (currently rely on Dialect) - private final Set reservedWords = new HashSet(); + private final Set reservedWords = new TreeSet( String.CASE_INSENSITIVE_ORDER ); /** * Constructor form used when the JDBC {@link java.sql.DatabaseMetaData} is not available. @@ -88,9 +89,8 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { this.sqlExceptionHelper = buildSqlExceptionHelper( dialect ); this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this ).build(); - for ( String keyword : dialect.getKeywords() ) { - reservedWords.add( keyword.toUpperCase(Locale.ROOT) ); - } + reservedWords.addAll( AnsiSqlKeywords.INSTANCE.sql2003() ); + reservedWords.addAll( dialect.getKeywords() ); final boolean globallyQuoteIdentifiers = serviceRegistry.getService( ConfigurationService.class ) .getSetting( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, StandardConverters.BOOLEAN, false ); @@ -142,10 +142,8 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { nameQualifierSupport = determineNameQualifierSupport( databaseMetaData ); } - for ( String keyword : dialect.getKeywords() ) { - reservedWords.add( keyword.toUpperCase(Locale.ROOT) ); - } - // ExtractedMetaDataSupport already capitalizes them + reservedWords.addAll( AnsiSqlKeywords.INSTANCE.sql2003() ); + reservedWords.addAll( dialect.getKeywords() ); reservedWords.addAll( extractedMetaDataSupport.getExtraKeywords() ); final boolean globallyQuoteIdentifiers = false; @@ -219,10 +217,8 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { nameQualifierSupport = determineNameQualifierSupport( databaseMetaData ); } - for ( String keyword : dialect.getKeywords() ) { - reservedWords.add( keyword.toUpperCase(Locale.ROOT) ); - } - // ExtractedMetaDataSupport already capitalizes them + reservedWords.addAll( AnsiSqlKeywords.INSTANCE.sql2003() ); + reservedWords.addAll( dialect.getKeywords() ); reservedWords.addAll( extractedMetaDataSupport.getExtraKeywords() ); final boolean globallyQuoteIdentifiers = serviceRegistry.getService( ConfigurationService.class ) @@ -336,7 +332,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { @Override public boolean isReservedWord(String word) { - return reservedWords.contains( word.toUpperCase(Locale.ROOT) ); + return reservedWords.contains( word ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/AnsiSqlKeywords.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/AnsiSqlKeywords.java new file mode 100644 index 0000000000..6c40824597 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/AnsiSqlKeywords.java @@ -0,0 +1,304 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2015, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine.jdbc.env.spi; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Maintains the set of ANSI SQL keywords + * + * @author Steve Ebersole + */ +public class AnsiSqlKeywords { + /** + * Singleton access + */ + public static final AnsiSqlKeywords INSTANCE = new AnsiSqlKeywords(); + + private final Set keywordsSql2003; + + public AnsiSqlKeywords() { + final Set keywordsSql2003 = new HashSet(); + keywordsSql2003.add( "ADD" ); + keywordsSql2003.add( "ALL" ); + keywordsSql2003.add( "ALLOCATE" ); + keywordsSql2003.add( "ALTER" ); + keywordsSql2003.add( "AND" ); + keywordsSql2003.add( "ANY" ); + keywordsSql2003.add( "ARE" ); + keywordsSql2003.add( "ARRAY" ); + keywordsSql2003.add( "AS" ); + keywordsSql2003.add( "ASENSITIVE" ); + keywordsSql2003.add( "ASYMMETRIC" ); + keywordsSql2003.add( "AT" ); + keywordsSql2003.add( "ATOMIC" ); + keywordsSql2003.add( "AUTHORIZATION" ); + keywordsSql2003.add( "BEGIN" ); + keywordsSql2003.add( "BETWEEN" ); + keywordsSql2003.add( "BIGINT" ); + keywordsSql2003.add( "BINARY" ); + keywordsSql2003.add( "BLOB" ); + keywordsSql2003.add( "BINARY" ); + keywordsSql2003.add( "BOTH" ); + keywordsSql2003.add( "BY" ); + keywordsSql2003.add( "CALL" ); + keywordsSql2003.add( "CALLED" ); + keywordsSql2003.add( "CASCADED" ); + keywordsSql2003.add( "CASE" ); + keywordsSql2003.add( "CAST" ); + keywordsSql2003.add( "CHAR" ); + keywordsSql2003.add( "CHARACTER" ); + keywordsSql2003.add( "CHECK" ); + keywordsSql2003.add( "CLOB" ); + keywordsSql2003.add( "CLOB" ); + keywordsSql2003.add( "CLOSE" ); + keywordsSql2003.add( "COLLATE" ); + keywordsSql2003.add( "COLUMN" ); + keywordsSql2003.add( "COMMIT" ); + keywordsSql2003.add( "CONDITION" ); + keywordsSql2003.add( "CONNECT" ); + keywordsSql2003.add( "CONSTRAINT" ); + keywordsSql2003.add( "CONTINUE" ); + keywordsSql2003.add( "CORRESPONDING" ); + keywordsSql2003.add( "CREATE" ); + keywordsSql2003.add( "CROSS" ); + keywordsSql2003.add( "CUBE" ); + keywordsSql2003.add( "CURRENT" ); + keywordsSql2003.add( "CURRENT_DATE" ); + keywordsSql2003.add( "CURRENT_PATH" ); + keywordsSql2003.add( "CURRENT_ROLE" ); + keywordsSql2003.add( "CURRENT_TIME" ); + keywordsSql2003.add( "CURRENT_TIMESTAMP" ); + keywordsSql2003.add( "CURRENT_USER" ); + keywordsSql2003.add( "CURSOR" ); + keywordsSql2003.add( "CYCLE" ); + keywordsSql2003.add( "DATE" ); + keywordsSql2003.add( "DAY" ); + keywordsSql2003.add( "DEALLOCATE" ); + keywordsSql2003.add( "DEC" ); + keywordsSql2003.add( "DECIMAL" ); + keywordsSql2003.add( "DECLARE" ); + keywordsSql2003.add( "DEFAULT" ); + keywordsSql2003.add( "DELETE" ); + keywordsSql2003.add( "DEREF" ); + keywordsSql2003.add( "DESCRIBE" ); + keywordsSql2003.add( "DETERMINISTIC" ); + keywordsSql2003.add( "DISCONNECT" ); + keywordsSql2003.add( "DISTINCT" ); + keywordsSql2003.add( "DO" ); + keywordsSql2003.add( "DOUBLE" ); + keywordsSql2003.add( "DROP" ); + keywordsSql2003.add( "DYNAMIC" ); + keywordsSql2003.add( "EACH" ); + keywordsSql2003.add( "ELEMENT" ); + keywordsSql2003.add( "ELSE" ); + keywordsSql2003.add( "ELSIF" ); + keywordsSql2003.add( "END" ); + keywordsSql2003.add( "ESCAPE" ); + keywordsSql2003.add( "EXCEPT" ); + keywordsSql2003.add( "EXEC" ); + keywordsSql2003.add( "EXECUTE" ); + keywordsSql2003.add( "EXISTS" ); + keywordsSql2003.add( "EXIT" ); + keywordsSql2003.add( "EXTERNAL" ); + keywordsSql2003.add( "FALSE" ); + keywordsSql2003.add( "FETCH" ); + keywordsSql2003.add( "FILTER" ); + keywordsSql2003.add( "FLOAT" ); + keywordsSql2003.add( "FOR" ); + keywordsSql2003.add( "FOREIGN" ); + keywordsSql2003.add( "FREE" ); + keywordsSql2003.add( "FROM" ); + keywordsSql2003.add( "FULL" ); + keywordsSql2003.add( "FUNCTION" ); + keywordsSql2003.add( "GET" ); + keywordsSql2003.add( "GLOBAL" ); + keywordsSql2003.add( "GRANT" ); + keywordsSql2003.add( "GROUP" ); + keywordsSql2003.add( "GROUPING" ); + keywordsSql2003.add( "HANDLER" ); + keywordsSql2003.add( "HAVING" ); + keywordsSql2003.add( "HOLD" ); + keywordsSql2003.add( "HOUR" ); + keywordsSql2003.add( "IDENTITY" ); + keywordsSql2003.add( "IF" ); + keywordsSql2003.add( "IMMEDIATE" ); + keywordsSql2003.add( "IN" ); + keywordsSql2003.add( "INDICATOR" ); + keywordsSql2003.add( "INNER" ); + keywordsSql2003.add( "INOUT" ); + keywordsSql2003.add( "INPUT" ); + keywordsSql2003.add( "INSENSITIVE" ); + keywordsSql2003.add( "INSERT" ); + keywordsSql2003.add( "INT" ); + keywordsSql2003.add( "INTEGER" ); + keywordsSql2003.add( "INTERSECT" ); + keywordsSql2003.add( "INTERVAL" ); + keywordsSql2003.add( "INTO" ); + keywordsSql2003.add( "IS" ); + keywordsSql2003.add( "ITERATE" ); + keywordsSql2003.add( "JOIN" ); + keywordsSql2003.add( "LANGUAGE" ); + keywordsSql2003.add( "LARGE" ); + keywordsSql2003.add( "LATERAL" ); + keywordsSql2003.add( "LEADING" ); + keywordsSql2003.add( "LEAVE" ); + keywordsSql2003.add( "LEFT" ); + keywordsSql2003.add( "LIKE" ); + keywordsSql2003.add( "LOCAL" ); + keywordsSql2003.add( "LOCALTIME" ); + keywordsSql2003.add( "LOCALTIMESTAMP" ); + keywordsSql2003.add( "LOOP" ); + keywordsSql2003.add( "MATCH" ); + keywordsSql2003.add( "MEMBER" ); + keywordsSql2003.add( "MERGE" ); + keywordsSql2003.add( "METHOD" ); + keywordsSql2003.add( "MINUTE" ); + keywordsSql2003.add( "MODIFIES" ); + keywordsSql2003.add( "MODULE" ); + keywordsSql2003.add( "MONTH" ); + keywordsSql2003.add( "MULTISET" ); + keywordsSql2003.add( "NATIONAL" ); + keywordsSql2003.add( "NATURAL" ); + keywordsSql2003.add( "NCHAR" ); + keywordsSql2003.add( "NCLOB" ); + keywordsSql2003.add( "NEW" ); + keywordsSql2003.add( "NO" ); + keywordsSql2003.add( "NONE" ); + keywordsSql2003.add( "NOT" ); + keywordsSql2003.add( "NULL" ); + keywordsSql2003.add( "NUMERIC" ); + keywordsSql2003.add( "OF" ); + keywordsSql2003.add( "OLD" ); + keywordsSql2003.add( "ON" ); + keywordsSql2003.add( "ONLY" ); + keywordsSql2003.add( "OPEN" ); + keywordsSql2003.add( "OR" ); + keywordsSql2003.add( "ORDER" ); + keywordsSql2003.add( "OUT" ); + keywordsSql2003.add( "OUTER" ); + keywordsSql2003.add( "OUTPUT" ); + keywordsSql2003.add( "OVER" ); + keywordsSql2003.add( "OVERLAPS" ); + keywordsSql2003.add( "PARAMETER" ); + keywordsSql2003.add( "PARTITION" ); + keywordsSql2003.add( "PRECISION" ); + keywordsSql2003.add( "PREPARE" ); + keywordsSql2003.add( "PRIMARY" ); + keywordsSql2003.add( "PROCEDURE" ); + keywordsSql2003.add( "RANGE" ); + keywordsSql2003.add( "READS" ); + keywordsSql2003.add( "REAL" ); + keywordsSql2003.add( "RECURSIVE" ); + keywordsSql2003.add( "REF" ); + keywordsSql2003.add( "REFERENCES" ); + keywordsSql2003.add( "REFERENCING" ); + keywordsSql2003.add( "RELEASE" ); + keywordsSql2003.add( "REPEAT" ); + keywordsSql2003.add( "RESIGNAL" ); + keywordsSql2003.add( "RESULT" ); + keywordsSql2003.add( "RETURN" ); + keywordsSql2003.add( "RETURNS" ); + keywordsSql2003.add( "REVOKE" ); + keywordsSql2003.add( "RIGHT" ); + keywordsSql2003.add( "ROLLBACK" ); + keywordsSql2003.add( "ROLLUP" ); + keywordsSql2003.add( "ROW" ); + keywordsSql2003.add( "ROWS" ); + keywordsSql2003.add( "SAVEPOINT" ); + keywordsSql2003.add( "SCROLL" ); + keywordsSql2003.add( "SEARCH" ); + keywordsSql2003.add( "SECOND" ); + keywordsSql2003.add( "SELECT" ); + keywordsSql2003.add( "SENSITIVE" ); + keywordsSql2003.add( "SESSION_USE" ); + keywordsSql2003.add( "SET" ); + keywordsSql2003.add( "SIGNAL" ); + keywordsSql2003.add( "SIMILAR" ); + keywordsSql2003.add( "SMALLINT" ); + keywordsSql2003.add( "SOME" ); + keywordsSql2003.add( "SPECIFIC" ); + keywordsSql2003.add( "SPECIFICTYPE" ); + keywordsSql2003.add( "SQL" ); + keywordsSql2003.add( "SQLEXCEPTION" ); + keywordsSql2003.add( "SQLSTATE" ); + keywordsSql2003.add( "SQLWARNING" ); + keywordsSql2003.add( "START" ); + keywordsSql2003.add( "STATIC" ); + keywordsSql2003.add( "SUBMULTISET" ); + keywordsSql2003.add( "SYMMETRIC" ); + keywordsSql2003.add( "SYSTEM" ); + keywordsSql2003.add( "SYSTEM_USER" ); + keywordsSql2003.add( "TABLE" ); + keywordsSql2003.add( "TABLESAMPLE" ); + keywordsSql2003.add( "THEN" ); + keywordsSql2003.add( "TIME" ); + keywordsSql2003.add( "TIMESTAMP" ); + keywordsSql2003.add( "TIMEZONE_HOUR" ); + keywordsSql2003.add( "TIMEZONE_MINUTE" ); + keywordsSql2003.add( "TO" ); + keywordsSql2003.add( "TRAILING" ); + keywordsSql2003.add( "TRANSLATION" ); + keywordsSql2003.add( "TREAT" ); + keywordsSql2003.add( "TRIGGER" ); + keywordsSql2003.add( "TRUE" ); + keywordsSql2003.add( "UNDO" ); + keywordsSql2003.add( "UNION" ); + keywordsSql2003.add( "UNIQUE" ); + keywordsSql2003.add( "UNKNOWN" ); + keywordsSql2003.add( "UNNEST" ); + keywordsSql2003.add( "UNTIL" ); + keywordsSql2003.add( "UPDATE" ); + keywordsSql2003.add( "USER" ); + keywordsSql2003.add( "USING" ); + keywordsSql2003.add( "VALUE" ); + keywordsSql2003.add( "VALUES" ); + keywordsSql2003.add( "VARCHAR" ); + keywordsSql2003.add( "VARYING" ); + keywordsSql2003.add( "WHEN" ); + keywordsSql2003.add( "WHENEVER" ); + keywordsSql2003.add( "WHERE" ); + keywordsSql2003.add( "WHILE" ); + keywordsSql2003.add( "WINDOW" ); + keywordsSql2003.add( "WITH" ); + keywordsSql2003.add( "WITHIN" ); + keywordsSql2003.add( "WITHOUT" ); + keywordsSql2003.add( "YEAR" ); + + this.keywordsSql2003 = Collections.unmodifiableSet( keywordsSql2003 ); + } + + /** + * Retrieve all keywords defined by ANSI SQL:2003 + * + * @return ANSI SQL:2003 keywords + */ + public Set sql2003() { + return keywordsSql2003; + } + + +} diff --git a/libraries.gradle b/libraries.gradle index 3583c63211..8b43fe6663 100644 --- a/libraries.gradle +++ b/libraries.gradle @@ -84,6 +84,7 @@ ext { //Maven plugin framework maven_plugin: 'org.apache.maven:maven-plugin-api:3.0.5', maven_plugin_tools: 'org.apache.maven.plugin-tools:maven-plugin-annotations:3.2', + maven_plugin_tools: 'org.apache.maven.plugin-tools:maven-plugin-annotations:3.2', // ~~~~~~~~~~~~~~~~~~~~~~~~~~ testing