diff --git a/src/java.sql/share/classes/java/sql/Array.java b/src/java.sql/share/classes/java/sql/Array.java index 1c42d3e5b7923..8fe84f4f930a7 100644 --- a/src/java.sql/share/classes/java/sql/Array.java +++ b/src/java.sql/share/classes/java/sql/Array.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,13 +61,19 @@ * If the connection's type map or a type map supplied to a method has no entry * for the base type, the elements are mapped according to the standard mapping. *

+ * To release resources used by the {@code Array} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Array} object has been closed, will result in a {@link SQLException} + * being thrown. + *

* All methods on the {@code Array} interface must be fully implemented if the * JDBC driver supports the data type. * * @since 1.2 */ -public interface Array { +public interface Array extends AutoCloseable { /** * Retrieves the SQL type name of the elements in @@ -345,21 +351,35 @@ ResultSet getResultSet (long index, int count, java.util.Map> map) throws SQLException; /** - * This method frees the {@code Array} object and releases the resources that - * it holds. The object is invalid once the {@code free} - * method is called. + * Closes and releases the resources held by this {@code Array} object. *

- * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Array} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Array's resources * @throws SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since 1.6 + * @see #close() */ void free() throws SQLException; + /** + * Closes and releases the resources held by this {@code Array} object. + *

+ * If the {@code Array} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the Array's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Blob.java b/src/java.sql/share/classes/java/sql/Blob.java index 5bf9cfcb7adf5..4f5619616eb3d 100644 --- a/src/java.sql/share/classes/java/sql/Blob.java +++ b/src/java.sql/share/classes/java/sql/Blob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ * the Java programming language of an SQL * {@code BLOB} value. An SQL {@code BLOB} is a built-in type * that stores a Binary Large Object as a column value in a row of - * a database table. By default drivers implement {@code Blob} using + * a database table. By default, drivers implement {@code Blob} using * an SQL {@code locator(BLOB)}, which means that a * {@code Blob} object contains a logical pointer to the * SQL {@code BLOB} data rather than the data itself. @@ -50,13 +50,19 @@ * {@code BLOB} value. In addition, this interface has methods for updating * a {@code BLOB} value. *

+ * To release resources used by the {@code Blob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Blob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

* All methods on the {@code Blob} interface must be fully implemented if the * JDBC driver supports the data type. * * @since 1.2 */ -public interface Blob { +public interface Blob extends AutoCloseable { /** * Returns the number of bytes in the {@code BLOB} value @@ -266,20 +272,17 @@ public interface Blob { void truncate(long len) throws SQLException; /** - * This method frees the {@code Blob} object and releases the resources that - * it holds. The object is invalid once the {@code free} - * method is called. + * Closes and releases the resources held by this {@code Blob} object. *

- * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in an {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Blob} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Blob's resources * @throws SQLFeatureNotSupportedException if the JDBC driver * does not support this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -303,4 +306,23 @@ public interface Blob { * @since 1.6 */ InputStream getBinaryStream(long pos, long length) throws SQLException; + + /** + * Closes and releases the resources held by this {@code Blob} object. + *

+ * If the {@code Blob} object is already closed, then invoking this method + * has no effect. + * + * @implSpec The default implementation calls the {@link #free()} method. + * + * @throws SQLException if an error occurs releasing + * the Blob's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @since 26 + * @see #free() + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Clob.java b/src/java.sql/share/classes/java/sql/Clob.java index 15e6897f71112..141f7de81af4b 100644 --- a/src/java.sql/share/classes/java/sql/Clob.java +++ b/src/java.sql/share/classes/java/sql/Clob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ * An SQL {@code CLOB} is a built-in type * that stores a Character Large Object as a column value in a row of * a database table. - * By default drivers implement a {@code Clob} object using an SQL + * By default, drivers implement a {@code Clob} object using an SQL * {@code locator(CLOB)}, which means that a {@code Clob} object * contains a logical pointer to the SQL {@code CLOB} data rather than * the data itself. A {@code Clob} object is valid for the duration @@ -49,13 +49,19 @@ * access an SQL {@code CLOB} value. In addition, this interface * has methods for updating a {@code CLOB} value. *

+ * To release resources used by the {@code Clob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code Clob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

* All methods on the {@code Clob} interface must be * fully implemented if the JDBC driver supports the data type. * * @since 1.2 */ -public interface Clob { +public interface Clob extends AutoCloseable { /** * Retrieves the number of characters @@ -310,14 +316,10 @@ public interface Clob { void truncate(long len) throws SQLException; /** - * This method releases the resources that the {@code Clob} object - * holds. The object is invalid once the {@code free} method - * is called. + * Closes and releases the resources held by this {@code Clob} object. *

- * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. + * If the {@code Clob} object is already closed, then invoking this method + * has no effect. * * @throws SQLException if an error occurs releasing * the Clob's resources @@ -325,6 +327,7 @@ public interface Clob { * @throws SQLFeatureNotSupportedException if the JDBC driver * does not support this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -350,4 +353,21 @@ public interface Clob { */ Reader getCharacterStream(long pos, long length) throws SQLException; + /** + * Closes and releases the resources held by this {@code Clob} object. + *

+ * If the {@code Clob} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the Clob's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Connection.java b/src/java.sql/share/classes/java/sql/Connection.java index 19f283f576218..946459adf7ba4 100644 --- a/src/java.sql/share/classes/java/sql/Connection.java +++ b/src/java.sql/share/classes/java/sql/Connection.java @@ -43,8 +43,8 @@ * should use the appropriate {@code Connection} method such as * {@code setAutoCommit} or {@code setTransactionIsolation}. * Applications should not invoke SQL commands directly to change the connection's - * configuration when there is a JDBC method available. By default a {@code Connection} object is in - * auto-commit mode, which means that it automatically commits changes + * configuration when there is a JDBC method available. By default, a {@code Connection} + * object is in auto-commit mode, which means that it automatically commits changes * after executing each statement. If auto-commit mode has been * disabled, the method {@code commit} must be called explicitly in * order to commit changes; otherwise, database changes will not be saved. @@ -77,7 +77,7 @@ * con.setTypeMap(map); * * - * @see DriverManager#getConnection + * @see DriverManager#getConnection(String) * @see Statement * @see ResultSet * @see DatabaseMetaData @@ -1505,7 +1505,7 @@ CallableStatement prepareCall(String sql, int resultSetType, * * @throws SQLException if an error occurs * @since 9 - * @see endRequest + * @see #endRequest() * @see javax.sql.PooledConnection */ default void beginRequest() throws SQLException { @@ -1548,7 +1548,7 @@ default void beginRequest() throws SQLException { * * @throws SQLException if an error occurs * @since 9 - * @see beginRequest + * @see #beginRequest() * @see javax.sql.PooledConnection */ default void endRequest() throws SQLException { @@ -1676,5 +1676,311 @@ default void setShardingKey(ShardingKey shardingKey, ShardingKey superShardingKe default void setShardingKey(ShardingKey shardingKey) throws SQLException { throw new SQLFeatureNotSupportedException("setShardingKey not implemented"); } + // JDBC 4.5 + /** + * Returns a {@code String} enclosed in single quotes. Any occurrence of a + * single quote within the string will be replaced by two single quotes. + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
ValueResult
Hello 'Hello'
G'Day 'G''Day'
'G''Day''''G''''Day'''
I'''M 'I''''''M'
+ *
+ * @implSpec + * The default implementation creates the literal as: + * {@code "'" + val.replace("'", "''") + "'"}. + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param val a character string + * @return A string enclosed by single quotes with every single quote + * converted to two single quotes + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default String enquoteLiteral(String val) throws SQLException { + return SQLUtils.enquoteLiteral(val); + } + + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

+ * If {@code identifier} is a simple SQL identifier: + *

+ * + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. + *

+ * A {@code SQLException} will be thrown if {@code identifier} contains any + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. + * + * @implSpec + * The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *

+ * + * The default implementation will throw a {@code SQLException} if: + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
identifieralwaysDelimitResult
HellofalseHello
Hellotrue"Hello"
G'Dayfalse"G'Day"
"Bruce Wayne"false"Bruce Wayne"
"Bruce Wayne"true"Bruce Wayne"
"select"false"select"
"select"true"select"
GoodDay$false"GoodDay$"
Hello"WorldfalseSQLException
"Hello"World"falseSQLException
+ *
+ * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param identifier a SQL identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier + * @return A simple SQL identifier or a delimited identifier + * @throws SQLException if identifier is not a valid identifier + * @throws SQLFeatureNotSupportedException if the datasource does not support + * delimited identifiers + * @throws NullPointerException if identifier is {@code null} + * + * @since 26 + */ + default String enquoteIdentifier(String identifier, boolean alwaysDelimit) throws SQLException { + String delimiter = this.getMetaData().getIdentifierQuoteString(); + return SQLUtils.enquoteIdentifier(delimiter, identifier, alwaysDelimit); + } + + /** + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

+ * The rules for a regular Identifier are: + *

+ *

+ * A datasource may have additional rules for a regular identifier such as: + *

+ * + * @implSpec The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + * + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
identifierSimple Identifier
Hellotrue
G'Dayfalse
"Bruce Wayne"false
GoodDay$false
Hello"Worldfalse
"Hello"World"false
"select"false
"from"false
+ *
+ * @implNote JDBC driver implementations may need to provide their own + * implementation of this method in order to meet the requirements of the + * underlying datasource. + * @param identifier a SQL identifier + * @return true if a simple SQL identifier, false otherwise + * @throws NullPointerException if identifier is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default boolean isSimpleIdentifier(String identifier) throws SQLException { + return SQLUtils.isSimpleIdentifier(identifier); + } + + /** + * Returns a {@code String} representing a National Character Set Literal + * enclosed in single quotes and prefixed with a upper case letter N. + * Any occurrence of a single quote within the string will be replaced + * by two single quotes. + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
ValueResult
Hello N'Hello'
G'Day N'G''Day'
'G''Day'N'''G''''Day'''
I'''M N'I''''''M'
N'Hello' N'N''Hello'''
+ *
+ * @implSpec + * The default implementation creates the literal as: + * {@code "N'" + val.replace("'", "''") + "'"}. + * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. An implementation of enquoteNCharLiteral may accept a different + * set of characters than that accepted by the same drivers implementation of + * enquoteLiteral. + * @param val a character string + * @return the result of replacing every single quote character in the + * argument by two single quote characters where this entire result is + * then prefixed with 'N'. + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * + * @since 26 + */ + default String enquoteNCharLiteral(String val) throws SQLException { + return SQLUtils.enquoteNCharLiteral(val); + } } diff --git a/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java b/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java index c5f5fc30ee904..426a49b7ae025 100644 --- a/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java +++ b/src/java.sql/share/classes/java/sql/DriverPropertyInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,13 @@ package java.sql; +import java.util.Properties; + /** *

Driver properties for making a connection. The - * {@code DriverPropertyInfo} class is of interest only to advanced programmers - * who need to interact with a Driver via the method - * {@code getDriverProperties} to discover - * and supply properties for connections. + * {@code DriverPropertyInfo} class is of interest only to advanced programmers. + * The method {@link Driver#getPropertyInfo(String, Properties)} may be used + * to discover Driver properties. * * @since 1.1 */ diff --git a/src/java.sql/share/classes/java/sql/JDBCType.java b/src/java.sql/share/classes/java/sql/JDBCType.java index 9c9d314b7f117..9da51c2792594 100644 --- a/src/java.sql/share/classes/java/sql/JDBCType.java +++ b/src/java.sql/share/classes/java/sql/JDBCType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,7 +200,21 @@ public enum JDBCType implements SQLType { /** * Identifies the generic SQL type {@code TIMESTAMP_WITH_TIMEZONE}. */ - TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE), + + /* JDBC 4.5 Types */ + + /** + * Identifies the generic SQL type {@code DECFLOAT}. + * @since 26 + */ + DECFLOAT(Types.DECFLOAT), + + /** + * Identifies the generic SQL type {@code JSON}. + * @since 26 + */ + JSON(Types.JSON); /** * The Integer value for the JDBCType. It maps to a value in diff --git a/src/java.sql/share/classes/java/sql/NClob.java b/src/java.sql/share/classes/java/sql/NClob.java index 587f6e1f843c6..0639f8941460d 100644 --- a/src/java.sql/share/classes/java/sql/NClob.java +++ b/src/java.sql/share/classes/java/sql/NClob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,8 @@ * An SQL {@code NCLOB} is a built-in type * that stores a Character Large Object using the National Character Set * as a column value in a row of a database table. - *

The {@code NClob} interface extends the {@code Clob} interface + *

+ * The {@code NClob} interface extends the {@code Clob} interface * which provides methods for getting the * length of an SQL {@code NCLOB} value, * for materializing a {@code NCLOB} value on the client, and for @@ -44,6 +45,12 @@ * access an SQL {@code NCLOB} value. In addition, this interface * has methods for updating a {@code NCLOB} value. *

+ * To release resources used by the {@code NClob} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code NClob} object has been closed, will result in a {@link SQLException} + * being thrown. + *

* All methods on the {@code NClob} interface must be fully implemented if the * JDBC driver supports the data type. * diff --git a/src/java.sql/share/classes/java/sql/SQLPermission.java b/src/java.sql/share/classes/java/sql/SQLPermission.java index 84e41c51a33a2..f9a0c7e2ed6e7 100644 --- a/src/java.sql/share/classes/java/sql/SQLPermission.java +++ b/src/java.sql/share/classes/java/sql/SQLPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,30 +29,14 @@ import java.security.*; /** - * A {@code SQLPermission} object contains - * a name (also referred to as a "target name") but no actions - * list; there is either a named permission or there is not. - * The target name is the name of the permission. The - * naming convention follows the hierarchical property naming convention. - * In addition, an asterisk - * may appear at the end of the name, following a ".", or by itself, to - * signify a wildcard match. For example: {@code loadLibrary.*} - * and {@code *} signify a wildcard match, - * while {@code *loadLibrary} and {@code a*b} do not. - * - * @apiNote - * This permission cannot be used for controlling access to resources - * as the Security Manager is no longer supported. + * This class was only useful in conjunction with the {@link java.lang.SecurityManager}, + * which is no longer supported. There is no replacement for this class. * * @since 1.3 - * @see java.security.BasicPermission - * @see java.security.Permission - * @see java.security.Permissions - * @see java.security.PermissionCollection - * @see java.lang.SecurityManager * + * @deprecated There is no replacement for this class. */ - +@Deprecated(since="26", forRemoval=true) public final class SQLPermission extends BasicPermission { /** diff --git a/src/java.sql/share/classes/java/sql/SQLUtils.java b/src/java.sql/share/classes/java/sql/SQLUtils.java new file mode 100644 index 0000000000000..49757d7e8ad6d --- /dev/null +++ b/src/java.sql/share/classes/java/sql/SQLUtils.java @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.sql; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * Utility class used by the Connection & Statement interfaces for their + * shared default methods. + */ +class SQLUtils { + // Pattern used to verify if an identifier is a Simple SQL identifier + private static final Pattern SIMPLE_IDENTIFIER_PATTERN + = Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*"); + // Pattern to check if an identifier contains a null character or a double quote + private static final Pattern INVALID_IDENTIFIER_CHARACTERS_PATTERN + = Pattern.compile("[^\u0000\"]+"); + // SQL 2023 reserved words + private static final String[] SQL2023_RESERVED_WORDS = { + "ABS", "ABSENT", "ACOS", "ALL", "ALLOCATE", "ALTER", "AND", "ANY", + "ANY_VALUE", "ARE", "ARRAY", "ARRAY_AGG", "ARRAY_MAX_CARDINALITY", + "AS", "ASENSITIVE", "ASIN", "ASYMMETRIC", "AT", "ATAN", + "ATOMIC", "AUTHORIZATION", "AVG", + "BEGIN", "BEGIN_FRAME", "BEGIN_PARTITION", "BETWEEN", "BIGINT", + "BINARY", "BLOB", "BOOLEAN", "BOTH", "BTRIM", "BY", + "CALL", "CALLED", "CARDINALITY", "CASCADED", "CASE", "CAST", "CEIL", + "CEILING", "CHAR", "CHAR_LENGTH", + "CHARACTER", "CHARACTER_LENGTH", "CHECK", "CLASSIFIER", "CLOB", + "CLOSE", "COALESCE", "COLLATE", "COLLECT", "COLUMN", "COMMIT", "CONDITION", + "CONNECT", "CONSTRAINT", "CONTAINS", "CONVERT", "COPY", "CORR", "CORRESPONDING", + "COS", "COSH", "COUNT", "COVAR_POP", "COVAR_SAMP", "CREATE", "CROSS", "CUBE", + "CUME_DIST", "CURRENT", + "CURRENT_CATALOG", "CURRENT_DATE", "CURRENT_DEFAULT_TRANSFORM_GROUP", "CURRENT_PATH", + "CURRENT_ROLE", "CURRENT_SCHEMA", "CURRENT_TIME", "CURRENT_TIMESTAMP", + "CURRENT_TRANSFORM_GROUP_FOR_TYPE", "CURRENT_USER", "CURSOR", "CYCLE", + "DATE", "DAY", "DEALLOCATE", "DEC", "DECFLOAT", "DECIMAL", "DECLARE", "DEFAULT", + "DEFINE", "DELETE", "DENSE_RANK", "DEREF", "DESCRIBE", "DETERMINISTIC", + "DISCONNECT", "DISTINCT", "DOUBLE", "DROP", "DYNAMIC", + "EACH", "ELEMENT", "ELSE", "EMPTY", "END", "END_FRAME", "END_PARTITION", + "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXEC", "EXECUTE", + "EXISTS", "EXP", "EXTERNAL", "EXTRACT", + "FALSE", "FETCH", "FILTER", "FIRST_VALUE", "FLOAT", "FLOOR", "FOR", "FOREIGN", "FRAME_ROW", + "FREE", "FROM", "FULL", "FUNCTION", "FUSION", + "GET", "GLOBAL", "GRANT", "GREATEST", "GROUP", "GROUPING", "GROUPS", + "HAVING", "HOLD", "HOUR", + "IDENTITY", "IN", "INDICATOR", "INITIAL", "INNER", "INOUT", "INSENSITIVE", + "INSERT", "INT", "INTEGER", + "INTERSECT", "INTERSECTION", "INTERVAL", "INTO", "IS", + "JOIN", "JSON", "JSON_ARRAY", "JSON_ARRAYAGG", "JSON_EXISTS", + "JSON_OBJECT", "JSON_OBJECTAGG", "JSON_QUERY", "JSON_SCALAR", + "JSON_SERIALIZE", "JSON_TABLE", "JSON_TABLE_PRIMITIVE", "JSON_VALUE", + "LAG", "LANGUAGE", "LARGE", " LAST_VALUE", "LATERAL", "LEAD", + "LEADING", "LEAST", "LEFT", "LIKE", "LIKE_REGEX", "LISTAGG", + "LN", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOG", "LOG10", + "LOWER", "LPAD", "LTRIM", + "MATCH", "MATCH_NUMBER", "MATCH_RECOGNIZE", "MATCHES", "MAX", + "MEMBER", "MERGE", "METHOD", "MIN", "MINUTE", "MOD", "MODIFIES", + "MODULE", "MONTH", "MULTISET", + "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NO", "NONE", + "NORMALIZE", "NOT", "NTH_VALUE", "NTILE", "NULL", "NULLIF", "NUMERIC", + "OCCURRENCES_REGEX", "OCTET_LENGTH", "OF", "OFFSET", "OLD", "OMIT", + "ON", "ONE", "ONLY", "OPEN", "OR", "ORDER", "OUT", "OUTER", "OUTPUT", + "OVER", "OVERLAPS", "OVERLAY", + "PARAMETER", "PARTITION", "PATTERN", "PER", "PERCENT", "PERCENT_RANK", + "PERCENTILE_CONT", "PERCENTILE_DISC", "PERIOD", "PORTION", "POSITION", + "POSITION_REGEX", "POWER", "PRECEDES", + "PRECISION", "PREPARE", "PRIMARY", "PROCEDURE", "PTF", + "RANGE", "RANK", "READS", "REAL", "RECURSIVE", "REF", "REFERENCES", + "REFERENCING", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", + "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY", + "RELEASE", "RESULT", "RETURN", "RETURNS", "REVOKE", "RIGHT", + "ROLLBACK", "ROLLUP", "ROW", "ROW_NUMBER", "ROWS", "RPAD", "RTRIM", + "RUNNING", + "SAVEPOINT", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SEEK", + "SELECT", "SENSITIVE", "SESSION_USER", "SET", "SHOW", "SIMILAR", + "SIN", "SINH", "SKIP", "SMALLINT", + "SOME", "SPECIFIC", "SPECIFICTYPE", "SQL", "SQLEXCEPTION", "SQLSTATE", + "SQLWARNING", "SQRT", "START", "STATIC", "STDDEV_POP", "STDDEV_SAMP", + "SUBMULTISET", "SUBSET", "SUBSTRING", "SUBSTRING_REGEX", "SUCCEEDS", + "SUM", "SYMMETRIC", "SYSTEM", "SYSTEM_TIME", "SYSTEM_USER", + "TABLE", "TABLESAMPLE", "TAN", "TANH", "THEN", "TIME", "TIMESTAMP", + "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", "TRAILING", "TRANSLATE", + "TRANSLATE_REGEX", "TRANSLATION", "TREAT", "TRIGGER", "TRIM", + "TRIM_ARRAY", "TRUE", "TRUNCATE", + "UESCAPE", "UNION", "UNIQUE", "UNKNOWN", "UNNEST", "UPDATE", "UPPER", + "USER", "USING", + "VALUE", "VALUES", "VALUE_OF", "VAR_POP", "VAR_SAMP", "VARBINARY", + "VARCHAR", "VARYING", "VERSIONING", + "WHEN", "WHENEVER", "WHERE", "WHILE", "WIDTH_BUCKET", "WINDOW", + "WITH", "WITHIN", "WITHOUT", + "YEAR" + }; + private static final Set SQL_RESERVED_WORDS = + new HashSet<>(Arrays.asList(SQL2023_RESERVED_WORDS)); + + /** + * Returns a {@code String} enclosed in single quotes. Any occurrence of a + * single quote within the string will be replaced by two single quotes. + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
ValueResult
Hello 'Hello'
G'Day 'G''Day'
'G''Day''''G''''Day'''
I'''M 'I''''''M'
+ *
+ * + * @param val a character string + * @return A string enclosed by single quotes with every single quote + * converted to two single quotes + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * @implNote JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + */ + static String enquoteLiteral(String val) throws SQLException { + return "'" + val.replace("'", "''") + "'"; + } + + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

+ * If {@code identifier} is a simple SQL identifier: + *

+ * + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. + *

+ * A {@code SQLException} will be thrown if {@code identifier} contains any + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. + * + * @implSpec + * The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + *

+ * + * The default implementation will throw a {@code SQLException} if: + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
identifieralwaysDelimitResult
HellofalseHello
Hellotrue"Hello"
G'Dayfalse"G'Day"
"Bruce Wayne"false"Bruce Wayne"
"Bruce Wayne"true"Bruce Wayne"
"select"false"select"
"select"true"select"
GoodDay$false"GoodDay$"
Hello"WorldfalseSQLException
"Hello"World"falseSQLException
+ *
+ * @implNote + * JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. + * @param identifier a SQL identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier + * @return A simple SQL identifier or a delimited identifier + * @throws SQLException if identifier is not a valid identifier + * @throws SQLFeatureNotSupportedException if the datasource does not support + * delimited identifiers + * @throws NullPointerException if identifier is {@code null} + */ + static String enquoteIdentifier(String delimiter, String identifier, boolean alwaysDelimit) throws SQLException { + int len = identifier.length(); + if (len < 1 || len > 128) { + throw new SQLException("Invalid identifier length"); + } + if (!delimiter.equals("\"")) { + throw new SQLException("Unsupported delimiter"); + } + if (isSimpleIdentifier(identifier)) { + return alwaysDelimit ? "\"" + identifier + "\"" : identifier; + } + if (identifier.matches("^\".+\"$")) { + identifier = identifier.substring(1, len - 1); + } + // Enclose the identifier in double quotes. If the identifier + // contains a null character or a double quote, throw a SQLException + if (INVALID_IDENTIFIER_CHARACTERS_PATTERN.matcher(identifier).matches()) { + return "\"" + identifier + "\""; + } else { + throw new SQLException("Invalid name"); + } + } + + /** + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

+ * The rules for a regular Identifier are: + *

+ *

+ * A datasource may have additional rules for a regular identifier such as: + *

+ * + * @implSpec The default implementation uses the following criteria to + * determine a valid simple SQL identifier: + * + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
identifierSimple Identifier
Hellotrue
G'Dayfalse
"Bruce Wayne"false
GoodDay$false
Hello"Worldfalse
"Hello"World"false
"select"false
"from"false
+ *
+ * @implNote JDBC driver implementations may need to provide their own + * implementation of this method in order to meet the requirements of the + * underlying datasource. + * @param identifier a SQL identifier + * @return true if a simple SQL identifier, false otherwise + * @throws NullPointerException if identifier is {@code null} + * @throws SQLException if a database access error occurs + */ + static boolean isSimpleIdentifier(String identifier) throws SQLException { + int len = identifier.length(); + return !SQL_RESERVED_WORDS.contains(identifier.toUpperCase()) && + len >= 1 && len <= 128 + && SIMPLE_IDENTIFIER_PATTERN.matcher(identifier).matches(); + } + + /** + * Returns a {@code String} representing a National Character Set Literal + * enclosed in single quotes and prefixed with an upper case letter N. + * Any occurrence of a single quote within the string will be replaced + * by two single quotes. + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
ValueResult
Hello N'Hello'
G'Day N'G''Day'
'G''Day'N'''G''''Day'''
I'''M N'I''''''M'
N'Hello' N'N''Hello'''
+ *
+ * + * @param val a character string + * @return the result of replacing every single quote character in the + * argument by two single quote characters where this entire result is + * then prefixed with 'N'. + * @throws NullPointerException if val is {@code null} + * @throws SQLException if a database access error occurs + * @implNote JDBC driver implementations may need to provide their own implementation + * of this method in order to meet the requirements of the underlying + * datasource. An implementation of enquoteNCharLiteral may accept a different + * set of characters than that accepted by the same drivers implementation of + * enquoteLiteral. + */ + static String enquoteNCharLiteral(String val) throws SQLException { + return "N'" + val.replace("'", "''") + "'"; + } +} diff --git a/src/java.sql/share/classes/java/sql/SQLXML.java b/src/java.sql/share/classes/java/sql/SQLXML.java index 3edae8a950881..70d481822e2d3 100644 --- a/src/java.sql/share/classes/java/sql/SQLXML.java +++ b/src/java.sql/share/classes/java/sql/SQLXML.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,14 +170,19 @@ * The conceptual states of writable and not writable determine if one * of the writing APIs will set a value or throw an exception. *

- * The state moves from readable to not readable once free() or any of the + * The state moves from readable to not readable once close(), free() or any of the * reading APIs are called: getBinaryStream(), getCharacterStream(), getSource(), and getString(). * Implementations may also change the state to not writable when this occurs. *

- * The state moves from writable to not writable once free() or any of the + * The state moves from writable to not writable once close(), free() or any of the * writing APIs are called: setBinaryStream(), setCharacterStream(), setResult(), and setString(). * Implementations may also change the state to not readable when this occurs. - * + *

+ * To release resources used by the {@code SQLXML} object, applications must call + * either the {@link #free()} or the {@link #close()} method. Any attempt to + * invoke a method other than {@link #free()} or {@link #close()} after the + * {@code SQLXML} object has been closed, will result in a {@link SQLException} + * being thrown. *

* All methods on the {@code SQLXML} interface must be fully implemented if the * JDBC driver supports the data type. @@ -188,21 +193,19 @@ * @see javax.xml.xpath * @since 1.6 */ -public interface SQLXML +public interface SQLXML extends AutoCloseable { /** - * This method closes this object and releases the resources that it held. - * The SQL XML object becomes invalid and neither readable or writable - * when this method is called. + * Closes and releases the resources held by this {@code SQLXML} object. + *

+ * If the {@code SQLXML} object is already closed, then invoking this method + * has no effect. * - * After {@code free} has been called, any attempt to invoke a - * method other than {@code free} will result in a {@code SQLException} - * being thrown. If {@code free} is called multiple times, the subsequent - * calls to {@code free} are treated as a no-op. * @throws SQLException if there is an error freeing the XML value. * @throws SQLFeatureNotSupportedException if the JDBC driver does not support * this method * @since 1.6 + * @see #close() */ void free() throws SQLException; @@ -424,4 +427,21 @@ public interface SQLXML */ T setResult(Class resultClass) throws SQLException; + /** + * Closes and releases the resources held by this {@code SQLXML} object. + *

+ * If the {@code SQLXML} object is already closed, then invoking this method + * has no effect. + * + * @throws SQLException if an error occurs releasing + * the SQLXML's resources + * @throws SQLFeatureNotSupportedException if the JDBC driver + * does not support this method + * @implSpec The default implementation calls the {@link #free()} method. + * @see #free() + * @since 26 + */ + default void close() throws SQLException { + free(); + }; } diff --git a/src/java.sql/share/classes/java/sql/Statement.java b/src/java.sql/share/classes/java/sql/Statement.java index bb5a5cfd64d96..4da510f6749e8 100644 --- a/src/java.sql/share/classes/java/sql/Statement.java +++ b/src/java.sql/share/classes/java/sql/Statement.java @@ -25,9 +25,6 @@ package java.sql; -import java.util.regex.Pattern; -import static java.util.stream.Collectors.joining; - /** *

The object used for executing a static SQL statement * and returning the results it produces. @@ -1395,6 +1392,9 @@ default long executeLargeUpdate(String sql, String columnNames[]) * * * + * @implSpec + * The default implementation creates the literal as: + * {@code "'" + val.replace("'", "''") + "'"}. * @implNote * JDBC driver implementations may need to provide their own implementation * of this method in order to meet the requirements of the underlying @@ -1407,46 +1407,50 @@ default long executeLargeUpdate(String sql, String columnNames[]) * * @since 9 */ - default String enquoteLiteral(String val) throws SQLException { - return "'" + val.replace("'", "''") + "'"; + default String enquoteLiteral(String val) throws SQLException { + return SQLUtils.enquoteLiteral(val); } - - /** - * Returns a SQL identifier. If {@code identifier} is a simple SQL identifier: + /** + * Returns a {@link #isSimpleIdentifier(String) simple SQL identifier} or a + * delimited identifier. A delimited identifier represents the name of a + * database object such as a table, column, or view that is enclosed by a + * delimiter, which is typically a double quote as defined by the SQL standard. + *

+ * If {@code identifier} is a simple SQL identifier: *

* - * If {@code identifier} is not a simple SQL identifier, {@code identifier} will be - * enclosed in double quotes if not already present. If the datasource does - * not support double quotes for delimited identifiers, the - * identifier should be enclosed by the string returned from - * {@link DatabaseMetaData#getIdentifierQuoteString}. If the datasource - * does not support delimited identifiers, a - * {@code SQLFeatureNotSupportedException} should be thrown. + * If {@code identifier} is not a simple SQL identifier, the delimited + * {@code identifier} to be returned must be enclosed by the delimiter + * returned from {@link DatabaseMetaData#getIdentifierQuoteString}. If + * the datasource does not support delimited identifiers, a + * {@code SQLFeatureNotSupportedException} is thrown. *

* A {@code SQLException} will be thrown if {@code identifier} contains any - * characters invalid in a delimited identifier or the identifier length is - * invalid for the datasource. + * invalid characters within a delimited identifier or the identifier length + * is invalid for the datasource. * * @implSpec * The default implementation uses the following criteria to * determine a valid simple SQL identifier: *

* * The default implementation will throw a {@code SQLException} if: * *
@@ -1455,7 +1459,7 @@ default String enquoteLiteral(String val) throws SQLException { * * * identifier - * alwaysQuote + * alwaysDelimit * Result * * @@ -1485,6 +1489,16 @@ default String enquoteLiteral(String val) throws SQLException { * "Bruce Wayne" * * + * "select" + * false + * "select" + * + * + * "select" + * true + * "select" + * + * * GoodDay$ * false * "GoodDay$" @@ -1507,8 +1521,8 @@ default String enquoteLiteral(String val) throws SQLException { * of this method in order to meet the requirements of the underlying * datasource. * @param identifier a SQL identifier - * @param alwaysQuote indicates if a simple SQL identifier should be - * returned as a quoted identifier + * @param alwaysDelimit indicates if a simple SQL identifier should be + * returned as a delimited identifier * @return A simple SQL identifier or a delimited identifier * @throws SQLException if identifier is not a valid identifier * @throws SQLFeatureNotSupportedException if the datasource does not support @@ -1517,36 +1531,43 @@ default String enquoteLiteral(String val) throws SQLException { * * @since 9 */ - default String enquoteIdentifier(String identifier, boolean alwaysQuote) throws SQLException { - int len = identifier.length(); - if (len < 1 || len > 128) { - throw new SQLException("Invalid name"); - } - if (Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches()) { - return alwaysQuote ? "\"" + identifier + "\"" : identifier; - } - if (identifier.matches("^\".+\"$")) { - identifier = identifier.substring(1, len - 1); - } - if (Pattern.compile("[^\u0000\"]+").matcher(identifier).matches()) { - return "\"" + identifier + "\""; - } else { - throw new SQLException("Invalid name"); - } + default String enquoteIdentifier(String identifier, boolean alwaysDelimit) throws SQLException { + return getConnection().enquoteIdentifier(identifier,alwaysDelimit); } /** - * Retrieves whether {@code identifier} is a simple SQL identifier. + * Returns whether {@code identifier} is a simple SQL identifier. + * A simple SQL identifier is referred to as regular (or ordinary) identifier + * within the SQL standard. A regular identifier represents the name of a database + * object such as a table, column, or view. + *

+ * The rules for a regular Identifier are: + *

+ *

+ * A datasource may have additional rules for a regular identifier such as: + *

* * @implSpec The default implementation uses the following criteria to * determine a valid simple SQL identifier: * * *
@@ -1583,6 +1604,13 @@ default String enquoteIdentifier(String identifier, boolean alwaysQuote) throws * "Hello"World" * false * + * + * "select" + * false + * + * "from" + * false + * * * *
@@ -1590,16 +1618,14 @@ default String enquoteIdentifier(String identifier, boolean alwaysQuote) throws * implementation of this method in order to meet the requirements of the * underlying datasource. * @param identifier a SQL identifier - * @return true if a simple SQL identifier, false otherwise + * @return true if a simple SQL identifier, false otherwise * @throws NullPointerException if identifier is {@code null} * @throws SQLException if a database access error occurs * * @since 9 */ default boolean isSimpleIdentifier(String identifier) throws SQLException { - int len = identifier.length(); - return len >= 1 && len <= 128 - && Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches(); + return SQLUtils.isSimpleIdentifier(identifier); } /** @@ -1628,7 +1654,10 @@ default boolean isSimpleIdentifier(String identifier) throws SQLException { * * *
- * @implNote + * @implSpec + * The default implementation creates the literal as: + * {@code "N'" + val.replace("'", "''") + "'"}. + * @implNote * JDBC driver implementations may need to provide their own implementation * of this method in order to meet the requirements of the underlying * datasource. An implementation of enquoteNCharLiteral may accept a different @@ -1643,7 +1672,7 @@ default boolean isSimpleIdentifier(String identifier) throws SQLException { * * @since 9 */ - default String enquoteNCharLiteral(String val) throws SQLException { - return "N'" + val.replace("'", "''") + "'"; + default String enquoteNCharLiteral(String val) throws SQLException { + return SQLUtils.enquoteNCharLiteral(val); } } diff --git a/src/java.sql/share/classes/java/sql/Timestamp.java b/src/java.sql/share/classes/java/sql/Timestamp.java index a91ab7210c58e..c550291bb9593 100644 --- a/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/src/java.sql/share/classes/java/sql/Timestamp.java @@ -54,10 +54,7 @@ * because the nanos component of a date is unknown. * As a result, the {@code Timestamp.equals(Object)} * method is not symmetric with respect to the - * {@code java.util.Date.equals(Object)} - * method. Also, the {@code hashCode} method uses the underlying - * {@code java.util.Date} - * implementation and therefore does not include nanos in its computation. + * {@code java.util.Date.equals(Object)} method. *

* Due to the differences between the {@code Timestamp} class * and the {@code java.util.Date} @@ -465,10 +462,15 @@ public int compareTo(java.util.Date o) { } /** - * {@inheritDoc} + * Returns a hash code value for this Timestamp. The result is the + * exclusive OR of the two halves of the primitive {@code long} + * value returned by the {@link #getTime} method. That is, + * the hash code is the value of the expression: + * {@snippet : + * (int)(this.getTime()^(this.getTime() >>> 32)) + * } * - * The {@code hashCode} method uses the underlying {@code java.util.Date} - * implementation and therefore does not include nanos in its computation. + * @return a hash code value for this Timestamp. * */ @Override diff --git a/src/java.sql/share/classes/java/sql/Types.java b/src/java.sql/share/classes/java/sql/Types.java index 2b3b571647b13..778d782ddaf85 100644 --- a/src/java.sql/share/classes/java/sql/Types.java +++ b/src/java.sql/share/classes/java/sql/Types.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -339,6 +339,27 @@ public class Types { */ public static final int TIMESTAMP_WITH_TIMEZONE = 2014; + + //--------------------------JDBC 4.5 ----------------------------- + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code DECFLOAT}. + * + * @since 26 + */ + public static final int DECFLOAT = 2015; + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code JSON}. + * + * @since 26 + */ + public static final int JSON = 2016; + // Prevent instantiation private Types() {} } diff --git a/src/java.sql/share/classes/java/sql/package-info.java b/src/java.sql/share/classes/java/sql/package-info.java index 495119effac96..64b23dba76f1a 100644 --- a/src/java.sql/share/classes/java/sql/package-info.java +++ b/src/java.sql/share/classes/java/sql/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,20 +38,22 @@ * use and update data from a spread sheet, flat file, or any other tabular * data source. * - *

What the JDBC 4.3 API Includes

- * The JDBC 4.3 API includes both + *

What the JDBC 4.5 API Includes

+ * The JDBC 4.5 API includes both * the {@code java.sql} package, referred to as the JDBC core API, * and the {@code javax.sql} package, referred to as the JDBC Optional * Package API. This complete JDBC API - * is included in the Java Standard Edition (Java SE), version 7. + * is included in the Java Standard Edition (Java SE). * The {@code javax.sql} package extends the functionality of the JDBC API * from a client-side API to a server-side API, and it is an essential part * of the Java Enterprise Edition * (Java EE) technology. * *

Versions

- * The JDBC 4.3 API incorporates all of the previous JDBC API versions: + * The JDBC 4.5 API incorporates all the previous JDBC API versions: * * + *

{@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.5 API

+ * + *

{@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.4 API

+ * *

{@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 4.3 API

* * - * *

{@code java.sql} and {@code javax.sql} Features Introduced in the JDBC 3.0 API

* * - * *

Custom Mapping of UDTs

* A user-defined type (UDT) defined in SQL can be mapped to a class in the Java * programming language. An SQL structured type or an SQL {@code DISTINCT} @@ -317,7 +342,7 @@ *

Package Specification

* * * *

Related Documentation

@@ -326,7 +351,6 @@ *
  • * Lesson:JDBC Basics(The Java Tutorials > JDBC Database Access) * - *
  • JDBC API Tutorial and Reference, Third Edition” * * @since 1.1 */ diff --git a/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java b/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java index f917b6af4dcc4..7a4fe15ecac1c 100644 --- a/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/CallableStatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,108 @@ */ package test.sql; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; -import util.StubCallableStatement; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; -public class CallableStatementTests extends PreparedStatementTests { +import java.sql.CallableStatement; +import java.sql.SQLException; + +import static org.testng.Assert.assertEquals; + +public class CallableStatementTests extends BaseTest { + private CallableStatement cstmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubCallableStatement(); + cstmt = new StubConnection().prepareCall("{call SuperHero_Proc(?)}"); + } + + @AfterMethod + public void tearDownMethod() throws Exception { + cstmt.close(); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(cstmt.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + cstmt.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(cstmt.enquoteIdentifier(s, alwaysQuote), expected); } + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + cstmt.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + cstmt.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(cstmt.isSimpleIdentifier(s), expected); + } + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + cstmt.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(cstmt.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + cstmt.enquoteNCharLiteral(null); + } } diff --git a/test/jdk/java/sql/testng/test/sql/ConnectionTests.java b/test/jdk/java/sql/testng/test/sql/ConnectionTests.java new file mode 100644 index 0000000000000..f40c2784e4a74 --- /dev/null +++ b/test/jdk/java/sql/testng/test/sql/ConnectionTests.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package test.sql; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; + +import java.sql.SQLException; + +import static org.testng.Assert.*; + +public class ConnectionTests extends BaseTest { + + protected StubConnection conn; + + @BeforeMethod + public void setUpMethod() throws Exception { + conn = new StubConnection(); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(conn.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + conn.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(conn.enquoteIdentifier(s, alwaysQuote), expected); + } + + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + conn.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + conn.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(conn.isSimpleIdentifier(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + conn.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(conn.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + conn.enquoteNCharLiteral(null); + } +} diff --git a/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java b/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java index d54763189c528..7813038361deb 100644 --- a/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/PreparedStatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,14 +22,109 @@ */ package test.sql; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; -import util.StubPreparedStatement; +import org.testng.annotations.Test; +import util.BaseTest; +import util.StubConnection; -public class PreparedStatementTests extends StatementTests { +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import static org.testng.Assert.assertEquals; + +public class PreparedStatementTests extends BaseTest { + + private PreparedStatement pstmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubPreparedStatement(); + pstmt = new StubConnection().prepareStatement("Select * from foo were bar = ?"); + } + + @AfterMethod + public void tearDownMethod() throws Exception { + pstmt.close(); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedLiteralValues") + public void test00(String s, String expected) throws SQLException { + assertEquals(pstmt.enquoteLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test01() throws SQLException { + pstmt.enquoteLiteral(null); + } + + /* + * Validate that enquoteIdentifier returns the expected value + */ + @Test(dataProvider = "validIdentifierValues") + public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { + assertEquals(pstmt.enquoteIdentifier(s, alwaysQuote), expected); } + /* + * Validate that a SQLException is thrown for values that are not valid + * for a SQL identifier + */ + @Test(dataProvider = "invalidIdentifierValues", + expectedExceptions = SQLException.class) + public void test03(String s, boolean alwaysQuote) throws SQLException { + pstmt.enquoteIdentifier(s, alwaysQuote); + } + + /* + * Validate a NullPointerException is thrown is the string passed to + * enquoteIdentiifer is null + */ + @Test(dataProvider = "trueFalse", + expectedExceptions = NullPointerException.class) + public void test04(boolean alwaysQuote) throws SQLException { + pstmt.enquoteIdentifier(null, alwaysQuote); + } + + /* + * Validate that isSimpleIdentifier returns the expected value + */ + @Test(dataProvider = "simpleIdentifierValues") + public void test05(String s, boolean expected) throws SQLException { + assertEquals(pstmt.isSimpleIdentifier(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * isSimpleIdentifier is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test06() throws SQLException { + pstmt.isSimpleIdentifier(null); + } + + /* + * Verify that enquoteLiteral creates a valid literal and converts every + * single quote to two single quotes + */ + @Test(dataProvider = "validEnquotedNCharLiteralValues") + public void test07(String s, String expected) throws SQLException { + assertEquals(pstmt.enquoteNCharLiteral(s), expected); + } + + /* + * Validate a NullPointerException is thrown if the string passed to + * enquoteNCharLiteral is null + */ + @Test(expectedExceptions = NullPointerException.class) + public void test08() throws SQLException { + pstmt.enquoteNCharLiteral(null); + } } diff --git a/test/jdk/java/sql/testng/test/sql/StatementTests.java b/test/jdk/java/sql/testng/test/sql/StatementTests.java index 88697b77f9d25..f2bfe712eb528 100644 --- a/test/jdk/java/sql/testng/test/sql/StatementTests.java +++ b/test/jdk/java/sql/testng/test/sql/StatementTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,38 +23,31 @@ package test.sql; import java.sql.SQLException; +import java.sql.Statement; + import static org.testng.Assert.assertEquals; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import org.testng.annotations.*; import util.BaseTest; -import util.StubStatement; +import util.StubConnection; public class StatementTests extends BaseTest { - protected StubStatement stmt; - protected static String maxIdentifier; + private Statement stmt; @BeforeMethod public void setUpMethod() throws Exception { - stmt = new StubStatement(); + stmt = new StubConnection().createStatement(); } - @BeforeClass - public static void setUpClass() throws Exception { - int maxLen = 128; - StringBuilder s = new StringBuilder(maxLen); - for (int i = 0; i < maxLen; i++) { - s.append('a'); - } - maxIdentifier = s.toString(); + @AfterMethod + public void tearDownMethod() throws Exception { + stmt.close(); } /* * Verify that enquoteLiteral creates a valid literal and converts every * single quote to two single quotes */ - @Test(dataProvider = "validEnquotedLiteralValues") public void test00(String s, String expected) throws SQLException { assertEquals(stmt.enquoteLiteral(s), expected); @@ -67,7 +60,6 @@ public void test00(String s, String expected) throws SQLException { @Test(expectedExceptions = NullPointerException.class) public void test01() throws SQLException { stmt.enquoteLiteral(null); - } /* @@ -76,7 +68,6 @@ public void test01() throws SQLException { @Test(dataProvider = "validIdentifierValues") public void test02(String s, boolean alwaysQuote, String expected) throws SQLException { assertEquals(stmt.enquoteIdentifier(s, alwaysQuote), expected); - } /* @@ -87,7 +78,6 @@ public void test02(String s, boolean alwaysQuote, String expected) throws SQLExc expectedExceptions = SQLException.class) public void test03(String s, boolean alwaysQuote) throws SQLException { stmt.enquoteIdentifier(s, alwaysQuote); - } /* @@ -98,7 +88,6 @@ public void test03(String s, boolean alwaysQuote) throws SQLException { expectedExceptions = NullPointerException.class) public void test04(boolean alwaysQuote) throws SQLException { stmt.enquoteIdentifier(null, alwaysQuote); - } /* @@ -116,7 +105,6 @@ public void test05(String s, boolean expected) throws SQLException { @Test(expectedExceptions = NullPointerException.class) public void test06() throws SQLException { stmt.isSimpleIdentifier(null); - } /* @@ -136,97 +124,4 @@ public void test07(String s, String expected) throws SQLException { public void test08() throws SQLException { stmt.enquoteNCharLiteral(null); } - - /* - * DataProvider used to provide strings that will be used to validate - * that enquoteLiteral converts a string to a literal and every instance of - * a single quote will be converted into two single quotes in the literal. - */ - @DataProvider(name = "validEnquotedLiteralValues") - protected Object[][] validEnquotedLiteralValues() { - return new Object[][]{ - {"Hello", "'Hello'"}, - {"G'Day", "'G''Day'"}, - {"'G''Day'", "'''G''''Day'''"}, - {"I'''M", "'I''''''M'"}, - {"The Dark Knight", "'The Dark Knight'"} - - }; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that enqouteIdentifier returns a simple SQL Identifier or a double - * quoted identifier - */ - @DataProvider(name = "validIdentifierValues") - protected Object[][] validEnquotedIdentifierValues() { - return new Object[][]{ - {"b", false, "b"}, - {"b", true, "\"b\""}, - {maxIdentifier, false, maxIdentifier}, - {maxIdentifier, true, "\"" + maxIdentifier + "\""}, - {"Hello", false, "Hello"}, - {"Hello", true, "\"Hello\""}, - {"G'Day", false, "\"G'Day\""}, - {"G'Day", true, "\"G'Day\""}, - {"Bruce Wayne", false, "\"Bruce Wayne\""}, - {"Bruce Wayne", true, "\"Bruce Wayne\""}, - {"GoodDay$", false, "\"GoodDay$\""}, - {"GoodDay$", true, "\"GoodDay$\""},}; - } - - /* - * DataProvider used to provide strings are invalid for enquoteIdentifier - * resulting in a SQLException being thrown - */ - @DataProvider(name = "invalidIdentifierValues") - protected Object[][] invalidEnquotedIdentifierValues() { - return new Object[][]{ - {"Hel\"lo", false}, - {"\"Hel\"lo\"", true}, - {"Hello" + '\0', false}, - {"", false}, - {maxIdentifier + 'a', false},}; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that isSimpleIdentifier returns the correct value based on the - * identifier specified. - */ - @DataProvider(name = "simpleIdentifierValues") - protected Object[][] simpleIdentifierValues() { - return new Object[][]{ - {"b", true}, - {"Hello", true}, - {"\"Gotham\"", false}, - {"G'Day", false}, - {"Bruce Wayne", false}, - {"GoodDay$", false}, - {"Dick_Grayson", true}, - {"Batmobile1966", true}, - {maxIdentifier, true}, - {maxIdentifier + 'a', false}, - {"", false},}; - } - - /* - * DataProvider used to provide strings that will be used to validate - * that enquoteNCharLiteral converts a string to a National Character - * literal and every instance of - * a single quote will be converted into two single quotes in the literal. - */ - @DataProvider(name = "validEnquotedNCharLiteralValues") - protected Object[][] validEnquotedNCharLiteralValues() { - return new Object[][]{ - {"Hello", "N'Hello'"}, - {"G'Day", "N'G''Day'"}, - {"'G''Day'", "N'''G''''Day'''"}, - {"I'''M", "N'I''''''M'"}, - {"N'Hello'", "N'N''Hello'''"}, - {"The Dark Knight", "N'The Dark Knight'"} - - }; - } } diff --git a/test/jdk/java/sql/testng/test/sql/TimestampTests.java b/test/jdk/java/sql/testng/test/sql/TimestampTests.java index fefe3276d47a1..6baea9fa26f4b 100644 --- a/test/jdk/java/sql/testng/test/sql/TimestampTests.java +++ b/test/jdk/java/sql/testng/test/sql/TimestampTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -667,6 +667,44 @@ public void test53() { expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MIN)); } + /* + * Validate that two Timestamp hashCode values are equal when + * the Timestamp values match, including the nanos. + */ + @Test + public void test54() { + long t = System.currentTimeMillis(); + Timestamp ts1 = new Timestamp(t); + Timestamp ts2 = new Timestamp(t); + ts1.setNanos(123456789); + ts2.setNanos(123456789); + assertTrue(ts1.equals(ts1)); + assertTrue(ts2.equals(ts2)); + assertTrue(ts1.equals(ts2)); + // As the Timestamp values, including the nanos are the same, the hashCode's + // should be equal + assertEquals(ts1.hashCode(), ts2.hashCode()); + } + + /* + * Validate that two Timestamp hashCode values are not equal when only + * the nanos value for the Timestamp differ. + */ + @Test + public void test55() { + long t = System.currentTimeMillis(); + Timestamp ts1 = new Timestamp(t); + Timestamp ts2 = new Timestamp(t); + // Modify the nanos so that the Timestamp values differ + ts1.setNanos(123456789); + ts2.setNanos(987654321); + assertTrue(ts1.equals(ts1)); + assertTrue(ts2.equals(ts2)); + assertFalse(ts1.equals(ts2)); + // As the nanos differ, the hashCode values should differ + assertNotEquals(ts1.hashCode(), ts2.hashCode()); + } + /* * DataProvider used to provide Timestamps which are not valid and are used * to validate that an IllegalArgumentException will be thrown from the diff --git a/test/jdk/java/sql/testng/util/BaseTest.java b/test/jdk/java/sql/testng/util/BaseTest.java index 6821940b7cea2..8751183726dd9 100644 --- a/test/jdk/java/sql/testng/util/BaseTest.java +++ b/test/jdk/java/sql/testng/util/BaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,9 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.security.Policy; import java.sql.JDBCType; import java.sql.SQLException; -import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; + import org.testng.annotations.DataProvider; public class BaseTest { @@ -47,22 +43,7 @@ public class BaseTest { protected final int errorCode = 21; protected final String[] msgs = {"Exception 1", "cause 1", "Exception 2", "Exception 3", "cause 2"}; - - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - - @BeforeMethod - public void setUpMethod() throws Exception { - } - - @AfterMethod - public void tearDownMethod() throws Exception { - } + private static final String MAX_LENGTH_IDENTIFIER = "a".repeat(128); /* * Take some form of SQLException, serialize and deserialize it @@ -92,13 +73,6 @@ protected T serializeDeserializeObject(T o) return o1; } - /* - * Utility Method used to set the current Policy - */ - protected static void setPolicy(Policy p) { - Policy.setPolicy(p); - } - /* * DataProvider used to specify the value to set and check for * methods using boolean values @@ -123,4 +97,99 @@ protected Object[][] jdbcTypes() { } return o; } + + /* + * DataProvider used to provide strings that will be used to validate + * that enquoteLiteral converts a string to a literal and every instance of + * a single quote will be converted into two single quotes in the literal. + */ + @DataProvider(name = "validEnquotedLiteralValues") + protected Object[][] validEnquotedLiteralValues() { + return new Object[][]{ + {"Hello", "'Hello'"}, + {"G'Day", "'G''Day'"}, + {"'G''Day'", "'''G''''Day'''"}, + {"I'''M", "'I''''''M'"}, + {"The Dark Knight", "'The Dark Knight'"}, + }; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that enqouteIdentifier returns a simple SQL Identifier or a + * quoted identifier + */ + @DataProvider(name = "validIdentifierValues") + protected Object[][] validEnquotedIdentifierValues() { + return new Object[][]{ + {"b", false, "b"}, + {"b", true, "\"b\""}, + {MAX_LENGTH_IDENTIFIER, false, MAX_LENGTH_IDENTIFIER}, + {MAX_LENGTH_IDENTIFIER, true, "\"" + MAX_LENGTH_IDENTIFIER + "\""}, + {"Hello", false, "Hello"}, + {"Hello", true, "\"Hello\""}, + {"G'Day", false, "\"G'Day\""}, + {"G'Day", true, "\"G'Day\""}, + {"Bruce Wayne", false, "\"Bruce Wayne\""}, + {"Bruce Wayne", true, "\"Bruce Wayne\""}, + {"select", false, "\"select\""}, + {"table", true, "\"table\""}, + {"GoodDay$", false, "\"GoodDay$\""}, + {"GoodDay$", true, "\"GoodDay$\""},}; + } + + /* + * DataProvider used to provide strings are invalid for enquoteIdentifier + * resulting in a SQLException being thrown + */ + @DataProvider(name = "invalidIdentifierValues") + protected Object[][] invalidEnquotedIdentifierValues() { + return new Object[][]{ + {"Hel\"lo", false}, + {"\"Hel\"lo\"", true}, + {"Hello" + '\0', false}, + {"", false}, + {MAX_LENGTH_IDENTIFIER + 'a', false},}; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that isSimpleIdentifier returns the correct value based on the + * identifier specified. + */ + @DataProvider(name = "simpleIdentifierValues") + protected Object[][] simpleIdentifierValues() { + return new Object[][]{ + {"b", true}, + {"Hello", true}, + {"\"Gotham\"", false}, + {"G'Day", false}, + {"Bruce Wayne", false}, + {"GoodDay$", false}, + {"Dick_Grayson", true}, + {"Batmobile1966", true}, + {MAX_LENGTH_IDENTIFIER, true}, + {MAX_LENGTH_IDENTIFIER + 'a', false}, + {"", false}, + {"select", false} + }; + } + + /* + * DataProvider used to provide strings that will be used to validate + * that enquoteNCharLiteral converts a string to a National Character + * literal and every instance of + * a single quote will be converted into two single quotes in the literal. + */ + @DataProvider(name = "validEnquotedNCharLiteralValues") + protected Object[][] validEnquotedNCharLiteralValues() { + return new Object[][]{ + {"Hello", "N'Hello'"}, + {"G'Day", "N'G''Day'"}, + {"'G''Day'", "N'''G''''Day'''"}, + {"I'''M", "N'I''''''M'"}, + {"N'Hello'", "N'N''Hello'''"}, + {"The Dark Knight", "N'The Dark Knight'"} + }; + } } diff --git a/test/jdk/java/sql/testng/util/StubCallableStatement.java b/test/jdk/java/sql/testng/util/StubCallableStatement.java index 1833a44d56d63..4a7c27314bbfc 100644 --- a/test/jdk/java/sql/testng/util/StubCallableStatement.java +++ b/test/jdk/java/sql/testng/util/StubCallableStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,24 +26,17 @@ import java.io.Reader; import java.math.BigDecimal; import java.net.URL; -import java.sql.Array; -import java.sql.Blob; -import java.sql.CallableStatement; -import java.sql.Clob; -import java.sql.Date; -import java.sql.NClob; -import java.sql.Ref; -import java.sql.RowId; -import java.sql.SQLException; -import java.sql.SQLXML; -import java.sql.Time; -import java.sql.Timestamp; +import java.sql.*; import java.util.Calendar; import java.util.Map; public class StubCallableStatement extends StubPreparedStatement implements CallableStatement{ + public StubCallableStatement(StubConnection con) { + super(con); + } + @Override public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -608,5 +601,4 @@ public T getObject(int parameterIndex, Class type) throws SQLException { public T getObject(String parameterName, Class type) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - } diff --git a/test/jdk/java/sql/testng/util/StubConnection.java b/test/jdk/java/sql/testng/util/StubConnection.java index b9ab97062d353..cd013572adc5e 100644 --- a/test/jdk/java/sql/testng/util/StubConnection.java +++ b/test/jdk/java/sql/testng/util/StubConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,20 +44,25 @@ public class StubConnection implements Connection { private boolean autoCommit = false; + private boolean isclosed; + + public StubConnection() { + isclosed = false; + } @Override public Statement createStatement() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubStatement(this); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubPreparedStatement(this); } @Override public CallableStatement prepareCall(String sql) throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubCallableStatement(this); } @Override @@ -89,17 +94,17 @@ public void rollback() throws SQLException { @Override public void close() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + isclosed = true; } @Override public boolean isClosed() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return isclosed; } @Override public DatabaseMetaData getMetaData() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return new StubDatabaseMetaData(); } @Override diff --git a/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java b/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java new file mode 100644 index 0000000000000..3bf70afaa8f69 --- /dev/null +++ b/test/jdk/java/sql/testng/util/StubDatabaseMetaData.java @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package util; + +import java.sql.*; + +public class StubDatabaseMetaData implements DatabaseMetaData { + @Override + public boolean allProceduresAreCallable() throws SQLException { + return false; + } + + @Override + public boolean allTablesAreSelectable() throws SQLException { + return false; + } + + @Override + public String getURL() throws SQLException { + return ""; + } + + @Override + public String getUserName() throws SQLException { + return ""; + } + + @Override + public boolean isReadOnly() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedLow() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + @Override + public boolean nullsAreSortedAtEnd() throws SQLException { + return false; + } + + @Override + public String getDatabaseProductName() throws SQLException { + return ""; + } + + @Override + public String getDatabaseProductVersion() throws SQLException { + return ""; + } + + @Override + public String getDriverName() throws SQLException { + return ""; + } + + @Override + public String getDriverVersion() throws SQLException { + return ""; + } + + @Override + public int getDriverMajorVersion() { + return 0; + } + + @Override + public int getDriverMinorVersion() { + return 0; + } + + @Override + public boolean usesLocalFiles() throws SQLException { + return false; + } + + @Override + public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + @Override + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesUpperCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesLowerCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesMixedCaseIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + @Override + public String getIdentifierQuoteString() throws SQLException { + return "\""; + } + + @Override + public String getSQLKeywords() throws SQLException { + return ""; + } + + @Override + public String getNumericFunctions() throws SQLException { + return ""; + } + + @Override + public String getStringFunctions() throws SQLException { + return ""; + } + + @Override + public String getSystemFunctions() throws SQLException { + return ""; + } + + @Override + public String getTimeDateFunctions() throws SQLException { + return ""; + } + + @Override + public String getSearchStringEscape() throws SQLException { + return ""; + } + + @Override + public String getExtraNameCharacters() throws SQLException { + return ""; + } + + @Override + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + @Override + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + @Override + public boolean supportsColumnAliasing() throws SQLException { + return false; + } + + @Override + public boolean nullPlusNonNullIsNull() throws SQLException { + return false; + } + + @Override + public boolean supportsConvert() throws SQLException { + return false; + } + + @Override + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + @Override + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + @Override + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + @Override + public boolean supportsExpressionsInOrderBy() throws SQLException { + return false; + } + + @Override + public boolean supportsOrderByUnrelated() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupBy() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupByUnrelated() throws SQLException { + return false; + } + + @Override + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + @Override + public boolean supportsLikeEscapeClause() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsNonNullableColumns() throws SQLException { + return false; + } + + @Override + public boolean supportsMinimumSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + @Override + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } + + @Override + public boolean supportsOuterJoins() throws SQLException { + return false; + } + + @Override + public boolean supportsFullOuterJoins() throws SQLException { + return false; + } + + @Override + public boolean supportsLimitedOuterJoins() throws SQLException { + return false; + } + + @Override + public String getSchemaTerm() throws SQLException { + return ""; + } + + @Override + public String getProcedureTerm() throws SQLException { + return ""; + } + + @Override + public String getCatalogTerm() throws SQLException { + return ""; + } + + @Override + public boolean isCatalogAtStart() throws SQLException { + return false; + } + + @Override + public String getCatalogSeparator() throws SQLException { + return ""; + } + + @Override + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } + + @Override + public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + @Override + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + @Override + public boolean supportsSelectForUpdate() throws SQLException { + return false; + } + + @Override + public boolean supportsStoredProcedures() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInComparisons() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInExists() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInIns() throws SQLException { + return false; + } + + @Override + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return false; + } + + @Override + public boolean supportsCorrelatedSubqueries() throws SQLException { + return false; + } + + @Override + public boolean supportsUnion() throws SQLException { + return false; + } + + @Override + public boolean supportsUnionAll() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } + + @Override + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } + + @Override + public int getMaxBinaryLiteralLength() throws SQLException { + return 0; + } + + @Override + public int getMaxCharLiteralLength() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInGroupBy() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInIndex() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInOrderBy() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInSelect() throws SQLException { + return 0; + } + + @Override + public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + @Override + public int getMaxConnections() throws SQLException { + return 0; + } + + @Override + public int getMaxCursorNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxIndexLength() throws SQLException { + return 0; + } + + @Override + public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxProcedureNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxCatalogNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxRowSize() throws SQLException { + return 0; + } + + @Override + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } + + @Override + public int getMaxStatementLength() throws SQLException { + return 0; + } + + @Override + public int getMaxStatements() throws SQLException { + return 0; + } + + @Override + public int getMaxTableNameLength() throws SQLException { + return 0; + } + + @Override + public int getMaxTablesInSelect() throws SQLException { + return 0; + } + + @Override + public int getMaxUserNameLength() throws SQLException { + return 0; + } + + @Override + public int getDefaultTransactionIsolation() throws SQLException { + return 0; + } + + @Override + public boolean supportsTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + return false; + } + + @Override + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return false; + } + + @Override + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return false; + } + + @Override + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return false; + } + + @Override + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } + + @Override + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { + return null; + } + + @Override + public ResultSet getSchemas() throws SQLException { + return null; + } + + @Override + public ResultSet getCatalogs() throws SQLException { + return null; + } + + @Override + public ResultSet getTableTypes() throws SQLException { + return null; + } + + @Override + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { + return null; + } + + @Override + public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { + return null; + } + + @Override + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + return null; + } + + @Override + public ResultSet getTypeInfo() throws SQLException { + return null; + } + + @Override + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { + return null; + } + + @Override + public boolean supportsResultSetType(int type) throws SQLException { + return false; + } + + @Override + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + return false; + } + + @Override + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + @Override + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + @Override + public boolean supportsBatchUpdates() throws SQLException { + return false; + } + + @Override + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { + return null; + } + + @Override + public Connection getConnection() throws SQLException { + return null; + } + + @Override + public boolean supportsSavepoints() throws SQLException { + return false; + } + + @Override + public boolean supportsNamedParameters() throws SQLException { + return false; + } + + @Override + public boolean supportsMultipleOpenResults() throws SQLException { + return false; + } + + @Override + public boolean supportsGetGeneratedKeys() throws SQLException { + return false; + } + + @Override + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { + return null; + } + + @Override + public boolean supportsResultSetHoldability(int holdability) throws SQLException { + return false; + } + + @Override + public int getResultSetHoldability() throws SQLException { + return 0; + } + + @Override + public int getDatabaseMajorVersion() throws SQLException { + return 0; + } + + @Override + public int getDatabaseMinorVersion() throws SQLException { + return 0; + } + + @Override + public int getJDBCMajorVersion() throws SQLException { + return 0; + } + + @Override + public int getJDBCMinorVersion() throws SQLException { + return 0; + } + + @Override + public int getSQLStateType() throws SQLException { + return 0; + } + + @Override + public boolean locatorsUpdateCopy() throws SQLException { + return false; + } + + @Override + public boolean supportsStatementPooling() throws SQLException { + return false; + } + + @Override + public RowIdLifetime getRowIdLifetime() throws SQLException { + return null; + } + + @Override + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + return null; + } + + @Override + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + return false; + } + + @Override + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } + + @Override + public ResultSet getClientInfoProperties() throws SQLException { + return null; + } + + @Override + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + return null; + } + + @Override + public boolean generatedKeyAlwaysReturned() throws SQLException { + return false; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } +} diff --git a/test/jdk/java/sql/testng/util/StubPreparedStatement.java b/test/jdk/java/sql/testng/util/StubPreparedStatement.java index 4e272bcee2d59..a3b95a65f4ea1 100644 --- a/test/jdk/java/sql/testng/util/StubPreparedStatement.java +++ b/test/jdk/java/sql/testng/util/StubPreparedStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,25 +26,15 @@ import java.io.Reader; import java.math.BigDecimal; import java.net.URL; -import java.sql.Array; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Date; -import java.sql.NClob; -import java.sql.ParameterMetaData; -import java.sql.PreparedStatement; -import java.sql.Ref; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.RowId; -import java.sql.SQLException; -import java.sql.SQLXML; -import java.sql.Time; -import java.sql.Timestamp; +import java.sql.*; import java.util.Calendar; public class StubPreparedStatement extends StubStatement implements PreparedStatement{ + public StubPreparedStatement(StubConnection con) { + super(con); + } + @Override public ResultSet executeQuery() throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -319,5 +309,4 @@ public void setBlob(int parameterIndex, InputStream inputStream) throws SQLExcep public void setNClob(int parameterIndex, Reader reader) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - } diff --git a/test/jdk/java/sql/testng/util/StubStatement.java b/test/jdk/java/sql/testng/util/StubStatement.java index df792e2e4fe03..c8f6a3ac07167 100644 --- a/test/jdk/java/sql/testng/util/StubStatement.java +++ b/test/jdk/java/sql/testng/util/StubStatement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,15 @@ import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; -import java.util.regex.Pattern; -import static java.util.stream.Collectors.joining; public class StubStatement implements Statement { + protected final Connection con; + + public StubStatement(StubConnection con) { + this.con = con; + } + @Override public ResultSet executeQuery(String sql) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); @@ -44,7 +48,7 @@ public int executeUpdate(String sql) throws SQLException { @Override public void close() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + con.close(); } @Override @@ -169,7 +173,7 @@ public int[] executeBatch() throws SQLException { @Override public Connection getConnection() throws SQLException { - throw new UnsupportedOperationException("Not supported yet."); + return con; } @Override @@ -251,7 +255,4 @@ public T unwrap(Class iface) throws SQLException { public boolean isWrapperFor(Class iface) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); } - - - } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java index 95cc508828a08..5bd10ed8848f0 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SQLInputImplTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,6 @@ public class SQLInputImplTests extends BaseTest { private final String sqlType = "SUPERHERO"; @BeforeMethod - @Override public void setUpMethod() throws Exception { map = new HashMap<>(); impl = new TestSQLDataImpl("TestSQLData"); @@ -120,7 +119,6 @@ public void test05() throws Exception { SQLInputImpl sqli = new SQLInputImpl(values, map); Object o = sqli.readObject(); assertTrue(hero.equals(o)); - } /* @@ -204,8 +202,6 @@ public void test11() throws Exception { Object[] values = {struct}; SQLInputImpl sqli = new SQLInputImpl(values, map); Object o = sqli.readObject(); - assertTrue(hero.equals(o)); - } } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java index 00f62df6f7966..1f90c9981a7eb 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SQLOutputImplTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,6 @@ public class SQLOutputImplTests extends BaseTest { private SQLOutputImpl outImpl; @BeforeMethod - @Override public void setUpMethod() throws Exception { results = new Vector(); impl = new TestSQLDataImpl("TestSQLData");