--- a/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/OperationGroup.java Wed Jul 11 19:30:26 2018 -0400
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/OperationGroup.java Wed Jul 11 19:36:23 2018 -0400
@@ -28,6 +28,7 @@
import java.util.concurrent.CompletionStage;
import java.util.function.Consumer;
import java.util.logging.Logger;
+import java.util.regex.Pattern;
import java.util.stream.Collector;
/**
@@ -391,28 +392,28 @@
* The type argument {@link S} of the containing {@link OperationGroup} must
* be a supertype of {@link TransactionOutcome}.
*
- * @param trans the TransactionEnd that determines whether the Operation does a
- * database commit or a database rollback.
+ * @param trans the TransactionCompletion that determines whether the Operation does a
+ database commit or a database rollback.
* @return an {@link Operation} that will end the database transaction.
* @throws IllegalStateException if this {@link OperationGroup} has been
* submitted and is not held or is parallel.
*/
- public Operation<TransactionOutcome> endTransactionOperation(TransactionEnd trans);
+ public Operation<TransactionOutcome> endTransactionOperation(TransactionCompletion trans);
/**
* Convenience method that creates and submits a endTransaction
* {@link Operation} that commits by default but can be set to rollback by
- * calling {@link TransactionEnd#setRollbackOnly}. The endTransaction Operation
+ * calling {@link TransactionCompletion#setRollbackOnly}. The endTransaction Operation
* is never skipped.
*
- * @param trans the TransactionEnd that determines whether the {@link Operation} is a
+ * @param trans the TransactionCompletion that determines whether the {@link Operation} is a
* database commit or a database rollback.
* @return a {@link CompletionStage} that is completed with the outcome of the
* transaction
* @throws IllegalStateException if this {@link OperationGroup} has been
* submitted and is not held or is parallel.
*/
- public default CompletionStage<TransactionOutcome> commitMaybeRollback(TransactionEnd trans) {
+ public default CompletionStage<TransactionOutcome> commitMaybeRollback(TransactionCompletion trans) {
catchErrors();
return this.endTransactionOperation(trans).submit().getCompletionStage();
}
@@ -461,7 +462,269 @@
*/
public OperationGroup<S, T> logger(Logger logger);
- // Covariant overrides
+ /**
+ * Returns a {@code String} enclosed in single quotes. Any occurrence of a
+ * single quote within the string will be replaced by two single quotes.
+ *
+ * <blockquote>
+ * <table class="striped">
+ * <caption>Examples of the conversion:</caption>
+ * <thead>
+ * <tr><th scope="col">Value</th><th scope="col">Result</th></tr>
+ * </thead>
+ * <tbody style="text-align:center">
+ * <tr> <th scope="row">Hello</th> <td>'Hello'</td> </tr>
+ * <tr> <th scope="row">G'Day</th> <td>'G''Day'</td> </tr>
+ * <tr> <th scope="row">'G''Day'</th>
+ * <td>'''G''''Day'''</td> </tr>
+ * <tr> <th scope="row">I'''M</th> <td>'I''''''M'</td>
+ * </tr>
+ *
+ * </tbody>
+ * </table>
+ * </blockquote>
+ *
+ * @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. Not null
+ * @return A string enclosed by single quotes with every single quote
+ * converted to two single quotes. Not null
+ * @throws NullPointerException if {@code val} is {@code null}
+ * @throws IllegalArgumentException if {@code val} cannot be enquoted
+ */
+ default String enquoteLiteral(String val) {
+ return "'" + val.replace("'", "''") + "'";
+ }
+
+ /**
+ * Returns a SQL identifier. If {@code identifier} is a simple SQL identifier:
+ * <ul>
+ * <li>Return the original value if {@code alwaysQuote} is {@code false}</li>
+ * <li>Return a delimited identifier if {@code alwaysQuote} is
+ * {@code true}</li>
+ * </ul>
+ *
+ * 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.
+ * <p>
+ * 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.
+ *
+ * @implSpec The default implementation uses the following criteria to
+ * determine a valid simple SQL identifier:
+ * <ul>
+ * <li>The string is not enclosed in double quotes</li>
+ * <li>The first character is an alphabetic character from a through z, or
+ * from A through Z</li>
+ * <li>The name only contains alphanumeric characters or the character
+ * "_"</li>
+ * </ul>
+ *
+ * The default implementation will throw a {@code SQLException} if:
+ * <ul>
+ * <li>{@code identifier} contains a {@code null} character or double quote
+ * and is not a simple SQL identifier.</li>
+ * <li>The length of {@code identifier} is less than 1 or greater than 128
+ * characters
+ * </ul>
+ * <blockquote>
+ * <table class="striped" >
+ * <caption>Examples of the conversion:</caption>
+ * <thead>
+ * <tr>
+ * <th scope="col">identifier</th>
+ * <th scope="col">alwaysQuote</th>
+ * <th scope="col">Result</th></tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <th scope="row">Hello</th>
+ * <td>false</td>
+ * <td>Hello</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">Hello</th>
+ * <td>true</td>
+ * <td>"Hello"</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">G'Day</th>
+ * <td>false</td>
+ * <td>"G'Day"</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">"Bruce Wayne"</th>
+ * <td>false</td>
+ * <td>"Bruce Wayne"</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">"Bruce Wayne"</th>
+ * <td>true</td>
+ * <td>"Bruce Wayne"</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">GoodDay$</th>
+ * <td>false</td>
+ * <td>"GoodDay$"</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">Hello"World</th>
+ * <td>false</td>
+ * <td>SQLException</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">"Hello"World"</th>
+ * <td>false</td>
+ * <td>SQLException</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * </blockquote>
+ * @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. Not null
+ * @param alwaysQuote indicates if a simple SQL identifier should be returned
+ * as a quoted identifier
+ * @return A simple SQL identifier or a delimited identifier. Not null
+ * @throws NullPointerException if identifier is {@code null}
+ * @throws IllegalArgumentException if {@code identifier} can not be converted
+ * to a valid identifier
+ */
+ default String enquoteIdentifier(String identifier, boolean alwaysQuote) {
+ int len = identifier.length();
+ if (len < 1 || len > 128) {
+ throw new IllegalArgumentException("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 IllegalArgumentException("Invalid name");
+ }
+ }
+
+ /**
+ * Retrieves whether {@code identifier} is a simple SQL identifier.
+ *
+ * @implSpec The default implementation uses the following criteria to
+ * determine a valid simple SQL identifier:
+ * <ul>
+ * <li>The string is not enclosed in double quotes</li>
+ * <li>The first character is an alphabetic character from a through z, or
+ * from A through Z</li>
+ * <li>The string only contains alphanumeric characters or the character
+ * "_"</li>
+ * <li>The string is between 1 and 128 characters in length inclusive</li>
+ * </ul>
+ *
+ * <blockquote>
+ * <table class="striped" >
+ * <caption>Examples of the conversion:</caption>
+ * <thead>
+ * <tr>
+ * <th scope="col">identifier</th>
+ * <th scope="col">Simple Identifier</th>
+ * </thead>
+ *
+ * <tbody>
+ * <tr>
+ * <th scope="row">Hello</th>
+ * <td>true</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">G'Day</th>
+ * <td>false</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">"Bruce Wayne"</th>
+ * <td>false</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">GoodDay$</th>
+ * <td>false</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">Hello"World</th>
+ * <td>false</td>
+ * </tr>
+ * <tr>
+ * <th scope="row">"Hello"World"</th>
+ * <td>false</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * </blockquote>
+ * @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. Not null
+ * @return true if a simple SQL identifier, false otherwise
+ * @throws NullPointerException if identifier is {@code null}
+ */
+ default boolean isSimpleIdentifier(String identifier) {
+ int len = identifier.length();
+ return len >= 1 && len <= 128
+ && Pattern.compile("[\\p{Alpha}][\\p{Alnum}_]*").matcher(identifier).matches();
+ }
+
+ /**
+ * 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.
+ *
+ * <blockquote>
+ * <table class="striped">
+ * <caption>Examples of the conversion:</caption>
+ * <thead>
+ * <tr>
+ * <th scope="col">Value</th>
+ * <th scope="col">Result</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr> <th scope="row">Hello</th> <td>N'Hello'</td> </tr>
+ * <tr> <th scope="row">G'Day</th> <td>N'G''Day'</td> </tr>
+ * <tr> <th scope="row">'G''Day'</th>
+ * <td>N'''G''''Day'''</td> </tr>
+ * <tr> <th scope="row">I'''M</th> <td>N'I''''''M'</td>
+ * <tr> <th scope="row">N'Hello'</th> <td>N'N''Hello'''</td> </tr>
+ *
+ * </tbody>
+ * </table>
+ * </blockquote>
+ *
+ * @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. Not null
+ * @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'. Not null.
+ * @throws NullPointerException if {@code val} is {@code null}
+ * @throws IllegalArgumentException if {@code val} cannot be enquoted
+ */
+ default String enquoteNCharLiteral(String val) {
+ return "N'" + val.replace("'", "''") + "'";
+ }
+
+ // Covariant overrides
@Override
public OperationGroup<S, T> timeout(Duration minTime);