# HG changeset patch # User lancea # Date 1531352183 14400 # Node ID 64304e37e9b133d07e2d090b961eab044d48f79b # Parent 1a36ad36c9e9dff736fd943f28c6a991b09ba03a JDK-8188051-branch javadoc updates and added TransactionCompletion.java diff -r 1a36ad36c9e9 -r 64304e37e9b1 src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Examples.java --- a/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Examples.java Wed Jul 11 19:30:26 2018 -0400 +++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Examples.java Wed Jul 11 19:36:23 2018 -0400 @@ -32,6 +32,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.Flow; +import java.util.concurrent.ForkJoinPool; import java.util.concurrent.Semaphore; import java.util.stream.Collector; import java.util.stream.Collectors; @@ -173,11 +174,11 @@ } } - // TransactionEnd + // TransactionCompletion public void transaction(DataSource ds) { try (Session session = ds.getSession(t -> System.out.println("ERROR: " + t.toString()))) { - TransactionEnd trans = session.transactionEnd(); + TransactionCompletion trans = session.transactionCompletion(); CompletionStage idPromise = session.rowOperation("select empno, ename from emp where ename = :1 for update") .set("1", "CLARK", AdbaType.VARCHAR) .collect(Collectors.collectingAndThen( @@ -336,6 +337,42 @@ // LocalOperation // SessionProperty + public enum ExampleSessionProperty implements SessionProperty { + LANGUAGE; + + private static final String DEFAULT_VALUE = "AMERICAN_AMERICA"; + + @Override + public Class range() { + return String.class; + } + + @Override + public Object defaultValue() { + return DEFAULT_VALUE; + } + + @Override + public boolean isSensitive() { + return false; + } + + @Override + public boolean configureOperation(OperationGroup group, Object value) { + group.operation("ALTER SESSION SET NLS_LANG = " + + group.enquoteIdentifier((String)value, false)) + .submit(); + return true; + } + + } + + public Session getSession(DataSource ds) { + return ds.builder() + .property(ExampleSessionProperty.LANGUAGE, "FRENCH_FRANCE") + .build() + .attach(); + } // Sharding diff -r 1a36ad36c9e9 -r 64304e37e9b1 src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/OperationGroup.java --- 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 endTransactionOperation(TransactionEnd trans); + public Operation 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 commitMaybeRollback(TransactionEnd trans) { + public default CompletionStage commitMaybeRollback(TransactionCompletion trans) { catchErrors(); return this.endTransactionOperation(trans).submit().getCompletionStage(); } @@ -461,7 +462,269 @@ */ public OperationGroup 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. + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
ValueResult
Hello 'Hello'
G'Day 'G''Day'
'G''Day''''G''''Day'''
I'''M 'I''''''M'
+ *
+ * + * @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: + *
    + *
  • Return the original value if {@code alwaysQuote} is {@code false}
  • + *
  • Return a delimited identifier if {@code alwaysQuote} is + * {@code true}
  • + *
+ * + * 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. + *

+ * 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: + *

    + *
  • The string is not enclosed in double quotes
  • + *
  • The first character is an alphabetic character from a through z, or + * from A through Z
  • + *
  • The name only contains alphanumeric characters or the character + * "_"
  • + *
+ * + * The default implementation will throw a {@code SQLException} if: + *
    + *
  • {@code identifier} contains a {@code null} character or double quote + * and is not a simple SQL identifier.
  • + *
  • The length of {@code identifier} is less than 1 or greater than 128 + * characters + *
+ *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
identifieralwaysQuoteResult
HellofalseHello
Hellotrue"Hello"
G'Dayfalse"G'Day"
"Bruce Wayne"false"Bruce Wayne"
"Bruce Wayne"true"Bruce Wayne"
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. 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: + *
    + *
  • The string is not enclosed in double quotes
  • + *
  • The first character is an alphabetic character from a through z, or + * from A through Z
  • + *
  • The string only contains alphanumeric characters or the character + * "_"
  • + *
  • The string is between 1 and 128 characters in length inclusive
  • + *
+ * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Examples of the conversion:
identifierSimple Identifier
Hellotrue
G'Dayfalse
"Bruce Wayne"false
GoodDay$false
Hello"Worldfalse
"Hello"World"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. 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. + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
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'''
+ *
+ * + * @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 timeout(Duration minTime); diff -r 1a36ad36c9e9 -r 64304e37e9b1 src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Session.java --- a/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Session.java Wed Jul 11 19:30:26 2018 -0400 +++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Session.java Wed Jul 11 19:36:23 2018 -0400 @@ -455,32 +455,32 @@ public OperationGroup operationGroup(); /** - * Returns a new {@link TransactionEnd} that can be used as an argument to an + * Returns a new {@link TransactionCompletion} that can be used as an argument to an * endTransaction Operation. * * It is most likely an error to call this within an error handler, or any * handler as it is very likely that when the handler is executed the next * submitted endTransaction {@link Operation} will have been created with a - * different TransactionEnd. + different TransactionCompletion. ISSUE: Should this be moved to OperationGroup? * - * @return a new {@link TransactionEnd}. Not null. + * @return a new {@link TransactionCompletion}. Not null. * @throws IllegalStateException if this Session is not active */ - public TransactionEnd transactionEnd(); + public TransactionCompletion transactionCompletion(); /** * Unconditionally perform a transaction rollback. Create an endTransaction * {@link Operation}, set it to rollback only, and submit it. The endTransaction * is never skipped. Convenience method. To execute a commit call - * {@link OperationGroup#commitMaybeRollback(jdk.incubator.sql2.TransactionEnd)}. + * {@link OperationGroup#commitMaybeRollback(jdk.incubator.sql2.TransactionCompletion)}. * * @return this {@link OperationGroup} - * @see OperationGroup#commitMaybeRollback(jdk.incubator.sql2.TransactionEnd) + * @see OperationGroup#commitMaybeRollback(jdk.incubator.sql2.TransactionCompletion) */ public default CompletionStage rollback() { - TransactionEnd t = transactionEnd(); + TransactionCompletion t = transactionCompletion(); t.setRollbackOnly(); catchErrors(); return this.endTransactionOperation(t).submit().getCompletionStage(); diff -r 1a36ad36c9e9 -r 64304e37e9b1 src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SessionProperty.java --- a/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SessionProperty.java Wed Jul 11 19:30:26 2018 -0400 +++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SessionProperty.java Wed Jul 11 19:36:23 2018 -0400 @@ -81,27 +81,28 @@ public boolean isSensitive(); /** - * Returns an {@link Operation} that will configure the {@link Session} to have the - * specified property value.May return {@code null} if no {@link Operation} needed. The - returned {@link Operation} is a member of group but is not submitted. + * Creates and submits zero or more {@link Operation}s that will configure the + * {@link Session} to have the specified property value. Returns {@code true} + * if any {@link Operation}s were submitted. {@code false} otherwise. * - * Called by {@link Session.Builder#build()} to configure a {@link Session} as specified - * in the {@link Session.Builder#property} method. SessionProperties known to the implementation - * may return {@code null} and rely on the implementation to do the right thing. + * Called by {@link Session.Builder#build()} to configure a {@link Session} as + * specified in the {@link Session.Builder#property} method. SessionProperties + * known to the implementation may return {@code false} and rely on the + * implementation to do the right thing. * - * @param - * @param group an {@link OperationGroup} which will be the container of the returned - * {@link Operation}, if any + * @param group an {@link OperationGroup} which will be the container of the + * submitted {@link Operation}s, if any * @param value the value to which the property is to be set. May be null if * {@link range()} is {@link Void}. - * @return an {@link Operation} or null + * @return true if any {@link Operation}s were submitted, false otherwise * @throws IllegalStateException if it is not possible to configure the * {@link Session} as specified. - * @throws IllegalArgumentException if {@code this.validate(value)} returns {@code false} + * @throws IllegalArgumentException if {@code this.validate(value)} returns + * {@code false} */ - public default Operation configureOperation(OperationGroup group, Object value) { + public default boolean configureOperation(OperationGroup group, Object value) { if (validate(value)) { - return null; + return false; } else { throw new IllegalArgumentException(value.toString() + " is invalid"); diff -r 1a36ad36c9e9 -r 64304e37e9b1 src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/TransactionCompletion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/TransactionCompletion.java Wed Jul 11 19:36:23 2018 -0400 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, 2018, 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 jdk.incubator.sql2; + +/** + * A mutable object that controls whether a transactionCompletion Operation sends + * a database commit or a database rollback to the server. A transactionCompletion + * Operation is created with a TransactionCompletion. By default a transactionCompletion + * Operation requests that the database end the transaction with a commit. + * If {@link TransactionCompletion#setRollbackOnly} is called on the TransactionCompletion used to create + the Operation prior to the Operation being executed, the Operation will + request that the database end the transaction with a rollback. + + Example: + +
+ * {@code
+   TransactionCompletion t = session.transactionCompletion();
+   session.countOperation(updateSql)
+       .resultProcessor( count -> { if (count > 1) t.setRollbackOnly(); } )
+       .submit();
+   session.commitMaybeRollback(t);
+ }
+ + A TransactionCompletion can not be used to create more than one endTransaction + Operation. + + A TransactionCompletion is thread safe. + + ISSUE: The name is terrible. Please suggest a better alternative, TransactionLatch? + */ +public interface TransactionCompletion { + + /** + * Causes an endTransactionOperation created with this TransactionCompletion that is executed + * subsequent to this call to perform a rollback. If this method is not called + * prior to Operation execution the Operation will perform a commit. + * + * @return true if the call succeeded. False if the call did not succeed in + setting the TransactionCompletion rollback only because the endTransaction + Operation had already been executed. + */ + public boolean setRollbackOnly(); + + /** + * Returns {@code true} iff the {@link setRollbackOnly} method has been called + on this TransactionCompletion + * + * @return {@code true} if {@link setRollbackOnly} has been called. + */ + public boolean isRollbackOnly(); + +} diff -r 1a36ad36c9e9 -r 64304e37e9b1 src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/TransactionEnd.java --- a/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/TransactionEnd.java Wed Jul 11 19:30:26 2018 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2017, 2018, 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 jdk.incubator.sql2; - -/** - * A mutable object that controls whether a transactionEnd Operation sends - * a database commit or a database rollback to the server. A transactionEnd - * Operation is created with a TransactionEnd. By default a transactionEnd - * Operation requests that the database end the transaction with a commit. - * If {@link TransactionEnd#setRollbackOnly} is called on the TransactionEnd used to create - * the Operation prior to the Operation being executed, the Operation will - * request that the database end the transaction with a rollback. - * - * Example: - * - *
- * {@code
-   TransactionEnd t = session.transactionEnd();
-   session.countOperation(updateSql)
-       .resultProcessor( count -> { if (count > 1) t.setRollbackOnly(); } )
-       .submit();
-   session.commitMaybeRollback(t);
- }
- - A TransactionEnd can not be used to create more than one endTransaction - Operation. - - A TransactionEnd is thread safe. - * - * ISSUE: The name is terrible. Please suggest a better alternative, TransactionLatch? - */ -public interface TransactionEnd { - - /** - * Causes an endTransactionOperation created with this TransactionEnd that is executed - * subsequent to this call to perform a rollback. If this method is not called - * prior to Operation execution the Operation will perform a commit. - * - * @return true if the call succeeded. False if the call did not succeed in - setting the TransactionEnd rollback only because the endTransaction - Operation had already been executed. - */ - public boolean setRollbackOnly(); - - /** - * Returns {@code true} iff the {@link setRollbackOnly} method has been called - on this TransactionEnd - * - * @return {@code true} if {@link setRollbackOnly} has been called. - */ - public boolean isRollbackOnly(); - -} diff -r 1a36ad36c9e9 -r 64304e37e9b1 src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/package-info.java --- a/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/package-info.java Wed Jul 11 19:30:26 2018 -0400 +++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/package-info.java Wed Jul 11 19:36:23 2018 -0400 @@ -308,24 +308,24 @@ * it might be necessary to rollback the transaction rather than commit it. This * determination depends on the execution of the Operations long after the * endTransaction Operation is submitted. To address this mismatch, the - * endTransaction Operation is conditioned by a {@link TransactionEnd}. By - * default, a {@link TransactionEnd} will cause an endTransaciton + * endTransaction Operation is conditioned by a {@link TransactionCompletion}. By + * default, a {@link TransactionCompletion} will cause an endTransaciton * {@link Operation} to commit the transaction. At any time before the * endTransaction {@link Operation} that references it is executed a - * {@link TransactionEnd} can be set to rollback the transaction .

+ * {@link TransactionCompletion} can be set to rollback the transaction .

* *

* An endTransaction {@link Operation}, like all {@link Operation}s, is * immutable once submitted. But an endTransaction {@link Operation} is created - * with a {@link TransactionEnd} and that {@link TransactionEnd} can be set to - * commit or rollback. A {@link TransactionEnd} controls the endTransaction + * with a {@link TransactionCompletion} and that {@link TransactionCompletion} can be set to + * commit or rollback. A {@link TransactionCompletion} controls the endTransaction * {@link Operation} created with it. Using this mechanism an error handler, * result handler or other code can cause a subsequent endTransaction * {@link Operation} to rollback instead of the default which is to commit.

* *
  * {@code
- *   TransactionEnd t = session.getTransactionEnd();
+ *   TransactionCompletion t = session.getTransactionEnd();
  *   session.countOperation(updateSql)
  *       .resultProcessor( count -> { 
  *           if (count > 1) t.setRollbackOnly(); 
@@ -339,7 +339,7 @@
  *
  * 

* In this example if the update SQL modifies more than one row the result - * processor will set the {@link TransactionEnd} to rollback only. When the + * processor will set the {@link TransactionCompletion} to rollback only. When the * endTransaction {@link Operation} submitted by * {@link OperationGroup#commitMaybeRollback} is executed it will cause the * transaction to rollback.