--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/AdbaDataSourceProperty.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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;
+
+import java.util.function.Function;
+
+/**
+ * Properties that apply to the DataSource as a whole, not to the individual
+ * {@link Session}s that the {@link DataSource} creates.
+ */
+public enum AdbaDataSourceProperty implements DataSourceProperty {
+
+
+ MAX_RESOURCES(Integer.class,
+ v -> v instanceof Integer && (int) v >= 0,
+ Integer.MAX_VALUE,
+ false),
+
+ MAX_IDLE_RESOURCES(Integer.class,
+ v -> v instanceof Integer && (int) v >= 0,
+ Integer.MAX_VALUE,
+ false);
+
+ private final Class<?> range;
+ private final Function<Object, Boolean> validator;
+ private final Object defaultValue;
+ private final boolean isSensitive;
+
+ private AdbaDataSourceProperty(Class<?> range,
+ Function<Object, Boolean> validator,
+ Object value,
+ boolean isSensitive) {
+ this.range = range;
+ this.validator = validator;
+ this.defaultValue = value;
+ this.isSensitive = isSensitive;
+ }
+
+ @Override
+ public Class<?> range() {
+ return range;
+ }
+
+ @Override
+ public Object defaultValue() {
+ return defaultValue;
+ }
+
+ @Override
+ public boolean isSensitive() {
+ return isSensitive;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/AdbaSessionProperty.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,222 @@
+/*
+ * 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;
+
+import java.util.function.Function;
+import java.time.Duration;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ForkJoinPool;
+
+/**
+ * A set of {@link SessionProperty} commonly supported. Implementations are not
+ * required to support all of these properties.
+ */
+public enum AdbaSessionProperty implements SessionProperty {
+
+ /**
+ *
+ */
+ CACHING(Caching.class,
+ v -> v instanceof Caching,
+ Caching.AS_NEW,
+ false),
+
+ /**
+ *
+ */
+ COMMIT_ON_CLOSE(Boolean.class,
+ v -> v instanceof Boolean,
+ Boolean.FALSE,
+ false),
+
+ /**
+ *
+ */
+ EXECUTOR(Executor.class,
+ v -> v instanceof Executor,
+ ForkJoinPool.commonPool(),
+ false),
+
+ /**
+ *
+ */
+ NETWORK_TIMEOUT(Duration.class,
+ v -> v instanceof Duration && ! ((Duration)v).isNegative(),
+ Duration.ofSeconds(Long.MAX_VALUE),
+ false),
+
+ /**
+ *
+ */
+ PASSWORD(String.class,
+ v -> v instanceof String,
+ null,
+ true),
+
+ /**
+ *
+ */
+ READ_ONLY(Boolean.class,
+ v -> v instanceof Boolean,
+ false,
+ false),
+
+ /**
+ *
+ */
+ SHARDING_KEY(ShardingKey.class,
+ v -> v instanceof ShardingKey,
+ null,
+ false),
+
+ /**
+ *
+ */
+ SHARDING_GROUP_KEY(ShardingKey.class,
+ v -> v instanceof ShardingKey,
+ null,
+ false),
+
+ /**
+ *
+ */
+ TRANSACTION_ISOLATION(TransactionIsolation.class,
+ v -> v instanceof TransactionIsolation,
+ TransactionIsolation.READ_COMMITTED,
+ false),
+
+ /**
+ *
+ */
+ URL(String.class,
+ v -> v instanceof String,
+ null,
+ false),
+
+ /**
+ *
+ */
+ USER(String.class,
+ v -> v instanceof String,
+ null,
+ false);
+
+ private final Class<?> range;
+ private final Function<Object, Boolean> validator;
+ private final Object defaultValue;
+ private final boolean isSensitive;
+
+ private AdbaSessionProperty(Class<?> range,
+ Function<Object, Boolean> validator,
+ Object value,
+ boolean isSensitive) {
+ this.range = range;
+ this.validator = validator;
+ this.defaultValue = value;
+ this.isSensitive = isSensitive;
+ }
+
+ @Override
+ public Class<?> range() {
+ return range;
+ }
+
+ @Override
+ public boolean validate(Object value) {
+ return validator.apply(value);
+ }
+
+ @Override
+ public Object defaultValue() {
+ return defaultValue;
+ }
+
+ @Override
+ public boolean isSensitive() {
+ return isSensitive;
+ }
+
+ /**
+ * Specifies how much flexibility the {@link DataSource} has in satisfying a
+ * request for a {@link Session} possibly by using cached data source resources.
+ */
+ public enum Caching {
+ /**
+ * The returned {@link Session} is required to be backed by a completely new
+ * data source resource configured exactly as specified by the other properties. Use this with caution and
+ * only when absolutely necessary. Use {@link AS_NEW} instead if at all possible.
+ * This should be used only to work around some limitation of the database
+ * or the implementation.
+ */
+ NEW,
+ /**
+ * The returned {@link Session} has no state other than that of a {@link Session}
+ * attached to a newly created data source resource modified as specified by
+ * the other properties. May not be strictly new
+ * but has the same behavior as if it were. The {@link Session}
+ * may be {@link NEW}. The default.
+ */
+ AS_NEW,
+ /**
+ * The returned {@link Session} has the state specified by the other properties
+ * but may have additional state that differs from that of a new {@link Session}.
+ * The {@link Session} may be {@link AS_NEW}.
+ */
+ CACHED;
+ }
+
+ /**
+ *
+ */
+ public enum TransactionIsolation {
+
+ /**
+ *
+ */
+ NONE,
+
+ /**
+ *
+ */
+ READ_COMMITTED,
+
+ /**
+ *
+ */
+ READ_UNCOMMITTED,
+
+ /**
+ *
+ */
+ REPEATABLE_READ,
+
+ /**
+ *
+ */
+ SERIALIZABLE;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/AdbaType.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2017, 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;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+
+/**
+ * <P>Defines the constants that are used to identify generic
+ * SQL types, called JDBC types.
+ *
+ * @see SqlType
+ * @since 1.8
+ */
+public enum AdbaType implements SqlType {
+
+ /**
+ * Identifies the generic SQL type {@code BIT}.
+ */
+ BIT(Boolean.class),
+ /**
+ * Identifies the generic SQL type {@code TINYINT}.
+ */
+ TINYINT(Byte.class),
+ /**
+ * Identifies the generic SQL type {@code SMALLINT}.
+ */
+ SMALLINT(Short.class),
+ /**
+ * Identifies the generic SQL type {@code INTEGER}.
+ */
+ INTEGER(Integer.class),
+ /**
+ * Identifies the generic SQL type {@code BIGINT}.
+ */
+ BIGINT(Long.class),
+ /**
+ * Identifies the generic SQL type {@code FLOAT}.
+ */
+ FLOAT(Double.class),
+ /**
+ * Identifies the generic SQL type {@code REAL}.
+ */
+ REAL(Float.class),
+ /**
+ * Identifies the generic SQL type {@code DOUBLE}.
+ */
+ DOUBLE(Double.class),
+ /**
+ * Identifies the generic SQL type {@code NUMERIC}.
+ */
+ NUMERIC(BigDecimal.class),
+ /**
+ * Identifies the generic SQL type {@code DECIMAL}.
+ */
+ DECIMAL(BigDecimal.class),
+ /**
+ * Identifies the generic SQL type {@code CHAR}.
+ */
+ CHAR(String.class),
+ /**
+ * Identifies the generic SQL type {@code VARCHAR}.
+ */
+ VARCHAR(String.class),
+ /**
+ * Identifies the generic SQL type {@code LONG VARCHAR}.
+ */
+ LONG_VARCHAR(String.class),
+ /**
+ * Identifies the generic SQL type {@code DATE}.
+ */
+ DATE(LocalDate.class),
+ /**
+ * Identifies the generic SQL type {@code TIME}.
+ */
+ TIME(LocalTime.class),
+ /**
+ * Identifies the generic SQL type {@code TIMESTAMP}.
+ */
+ TIMESTAMP(LocalDateTime.class),
+ /**
+ * Identifies the generic SQL type {@code BINARY}.
+ */
+ BINARY(byte[].class),
+ /**
+ * Identifies the generic SQL type {@code VARBINARY}.
+ */
+ VARBINARY(byte[].class),
+ /**
+ * Identifies the generic SQL type {@code LONG VARBINARY}.
+ */
+ LONG_VARBINARY(byte[].class),
+ /**
+ * Identifies the generic SQL value {@code NULL}.
+ */
+ NULL(Void.class),
+ /**
+ * Indicates that the SQL type
+ * is database-specific and gets mapped to a Java object that can be
+ * accessed via the methods getObject and setObject.
+ */
+ OTHER(Object.class),
+ /**
+ * Indicates that the SQL type
+ * is database-specific and gets mapped to a Java object that can be
+ * accessed via the methods getObject and setObject.
+ */
+ JAVA_OBJECT(Object.class),
+ /**
+ * Identifies the generic SQL type {@code DISTINCT}.
+ */
+ DISTINCT(Object.class),
+ /**
+ * Identifies the generic SQL type {@code STRUCT}.
+ */
+ STRUCT(SqlStruct.class),
+ /**
+ * Identifies the generic SQL type {@code ARRAY}.
+ */
+ ARRAY(Object[].class), //TODO questionable. really want <?>[]
+ /**
+ * Identifies the generic SQL type {@code BLOB}.
+ */
+ BLOB(SqlBlob.class),
+ /**
+ * Identifies the generic SQL type {@code CLOB}.
+ */
+ CLOB(SqlClob.class),
+ /**
+ * Identifies the generic SQL type {@code REF}.
+ */
+ REF(SqlRef.class),
+ /**
+ * Identifies the generic SQL type {@code DATALINK}.
+ */
+ DATALINK(Void.class), //TODO
+ /**
+ * Identifies the generic SQL type {@code BOOLEAN}.
+ */
+ BOOLEAN(Boolean.class),
+ /**
+ * Identifies the SQL type {@code ROWID}.
+ */
+ ROWID(Void.class), //TODO
+ /**
+ * Identifies the generic SQL type {@code NCHAR}.
+ */
+ NCHAR(String.class),
+ /**
+ * Identifies the generic SQL type {@code NVARCHAR}.
+ */
+ NVARCHAR(String.class),
+ /**
+ * Identifies the generic SQL type {@code LONG NVARCHAR}.
+ */
+ LONG_NVARCHAR(String.class),
+ /**
+ * Identifies the generic SQL type {@code NCLOB}.
+ */
+ NCLOB(SqlClob.class),
+ /**
+ * Identifies the generic SQL type {@code SQLXML}.
+ */
+ SQLXML(Void.class), //TODO
+
+ /**
+ * Identifies the generic SQL type {@code REF CURSOR}.
+ */
+ REF_CURSOR(Void.class), //TODO
+
+ /**
+ * Identifies the generic SQL type {@code TIME WITH TIME ZONE}.
+ */
+ TIME_WITH_TIME_ZONE(OffsetTime.class),
+
+ /**
+ * Identifies the generic SQL type {@code TIMESTAMP WITH TIME ZONE}.
+ */
+ TIMESTAMP_WITH_TIME_ZONE(OffsetDateTime.class);
+
+ private static final String STANDARD_VENDOR = "jdk.incubator.sql2";
+
+ protected final Class javaType;
+
+ AdbaType(Class type) {
+ javaType = type;
+ }
+
+ /**
+ *{@inheritDoc }
+ * @return The name of this {@code SQLType}.
+ */
+ @Override
+ public String getName() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ /**
+ * Returns the name of the vendor that supports this data type.
+ * @return The name of the vendor for this data type which is
+ * the package name containing this type.
+ */
+ @Override
+ public String getVendor() {
+ return STANDARD_VENDOR;
+ }
+
+ /**
+ * Returns the vendor specific type number for the data type.
+ * @return An Integer representing the data type. For {@code ABDAType},
+ * the value will be the same value as in {@code Types} for the data type.
+ */
+ @Override
+ public <T> Class<T> getJavaType() {
+ return javaType;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/ArrayRowCountOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,191 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Consumer;
+import java.util.stream.Collector;
+
+/**
+ * A database operation that returns a count that is executed multiple times
+ * with multiple sets of parameter values in one database operation. The
+ * parameters are submitted to the database in the same order as in the
+ * sequences passed to the set methods. The count results are passed to the
+ * collector in the same order they are produced by the database. The
+ * value of the Operation is the final result produced by the collector.
+ *
+ * @param <T> the type of the result of collecting the counts
+ */
+public interface ArrayRowCountOperation<T> extends Operation<T> {
+
+ /**
+ * Set a sequence of parameter values. The value is captured and should not be
+ * modified before the {@link Operation} is completed.
+ *
+ * The Operation is completed exceptionally with ClassCastException if any of
+ * the values cannot be converted to the specified SQL type.
+ *
+ * @param id the identifier of the parameter marker to be set
+ * @param values the sequence of values the parameter is to be set to
+ * @param type the SQL type of the values to send to the database
+ * @return this Operation
+ * @throws IllegalArgumentException if the length of values is not the same as
+ * the length of the previously set parameter sequences or if the same id was
+ * passed in a previous call.
+ * @throws IllegalStateException if the {@link Operation} has been submitted
+ */
+ public ArrayRowCountOperation<T> set(String id, List<?> values, SqlType type);
+
+ /**
+ * Set a sequence of parameter values. Use a default SQL type determined by
+ * the type of the value argument. The value is captured and should not be
+ * modified before the {@link Operation} is completed.
+ *
+ * The Operation is completed exceptionally with ClassCastException if any of
+ * the values cannot be converted to the specified SQL type.
+ *
+ * @param id the identifier of the parameter marker to be set
+ * @param values the value the parameter is to be set to
+ * @return this {@link Operation}
+ * @throws IllegalArgumentException if the length of value is not the same as
+ * the length of the previously set parameter sequences or if the same id was
+ * passed in a previous call.
+ * @throws IllegalStateException if the {@link Operation} has been submitted
+ */
+ public ArrayRowCountOperation<T> set(String id, List<?> values);
+
+ /**
+ * Set a sequence of parameter values. The first parameter is captured and
+ * should not be modified before the {@link Operation} is completed.
+ *
+ * The Operation is completed exceptionally with ClassCastException if any of
+ * the values cannot be converted to the specified SQL type.
+ *
+ * @param <S> the Java type of the individual parameter values
+ * @param id the identifier of the parameter marker to be set
+ * @param values the value the parameter is to be set to
+ * @param type the SQL type of the value to send to the database
+ * @return this Operation
+ * @throws IllegalArgumentException if the length of value is not the same as
+ * the length of the previously set parameter sequences or if the same id was
+ * passed in a previous call.
+ * @throws IllegalStateException if the {@link Operation} has been submitted
+ */
+ public <S> ArrayRowCountOperation<T> set(String id, S[] values, SqlType type);
+
+ /**
+ * Set a sequence of parameter values. Use a default SQL type determined by
+ * the type of the value argument. The parameter is captured and should not be
+ * modified before the {@link Operation} is completed.
+ *
+ * The Operation is completed exceptionally with ClassCastException if any of
+ * the values cannot be converted to the specified SQL type.
+ *
+ * @param <S> the Java type of the individual parameter values
+ * @param id the identifier of the parameter marker to be set
+ * @param values the value the parameter is to be set to
+ * @return this Operation
+ * @throws IllegalArgumentException if the length of value is not the same as
+ * the length of the previously set parameter sequences or if the same id was
+ * passed in a previous call.
+ * @throws IllegalStateException if the {@link Operation} has been submitted
+ */
+ public <S> ArrayRowCountOperation<T> set(String id, S[] values);
+
+ /**
+ * Provide a source for a sequence of parameter values.
+ *
+ * This Operation is not executed until source is completed normally. If
+ * source completes exceptionally this Operation completes exceptionally with
+ * an IllegealArgumentException with the source's exception as the cause.
+ *
+ * The Operation is completed exceptionally with ClassCastException if any of
+ * the values of the source cannot be converted to the specified SQL type.
+ *
+ * If the length of the value of source is not the same as the length of all
+ * other parameter sequences this Operation is completed exceptionally with
+ * IllegalArgumentException.
+ *
+ * @param id the identifier of the parameter marker to be set
+ * @param source supplies the values the parameter is to be set to
+ * @param type the SQL type of the value to send to the database
+ * @return this Operation
+ * @throws IllegalArgumentException if the same id was passed in a previous
+ * call.
+ * @throws IllegalStateException if the {@link Operation} has been submitted
+ */
+ public ArrayRowCountOperation<T> set(String id, CompletionStage<?> source, SqlType type);
+
+ /**
+ * Provide a source for a sequence of parameter values. Use a default SQL type
+ * determined by the element type of the value of the source.
+ *
+ * This Operation is not executed until source is completed normally. If
+ * source completes exceptionally this Operation completes exceptionally with
+ * an IllegealArgumentException with the source's exception as the cause.
+ *
+ * The Operation is completed exceptionally with ClassCastException if any of
+ * the values of the source cannot be converted to the specified SQL type.
+ *
+ * If the length of the value of source is not the same as the length of all
+ * other parameter sequences this Operation is completed exceptionally with
+ * IllegalArgumentException.
+ *
+ * @param id the identifier of the parameter marker to be set
+ * @param source supplies the values the parameter is to be set to
+ * @return this {@link Operation}
+ * @throws IllegalArgumentException if the same id was passed in a previous
+ * call.
+ * @throws IllegalStateException if the {@link Operation} has been submitted
+ */
+ public ArrayRowCountOperation<T> set(String id, CompletionStage<?> source);
+
+ /**
+ * Provides a {@link Collector} to reduce the sequence of Counts.The result of
+ * the {@link Operation} is the result of calling finisher on the final
+ * accumulated result. If the {@link Collector} is
+ * {@link Collector.Characteristics#UNORDERED} counts may be accumulated out of
+ * order. If the {@link Collector} is
+ * {@link Collector.Characteristics#CONCURRENT} then the sequence of counts may be
+ * split into subsequences that are reduced separately and then combined.
+ *
+ * @param <A> the type of the accumulator
+ * @param <S> the type of the final result
+ * @param c the Collector. Not null.
+ * @return This ArrayRowCountOperation
+ * @throws IllegalStateException if this method had been called previously or
+ * this Operation has been submitted.
+ */
+ public <A, S extends T> ArrayRowCountOperation<T> collect(Collector<? super Result.RowCount, A, S> c);
+
+ @Override
+ public ArrayRowCountOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ public ArrayRowCountOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/DataSource.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,260 @@
+/*
+ * 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;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+/**
+ * Uses the builder pattern to get a {@link Session}. A {@link DataSource#getSession}
+ * method is provided as a convenience.
+ *
+ * Implementations must be thread safe.
+ */
+public interface DataSource
+ extends AutoCloseable {
+
+ /**
+ * Instances of this type are used to build {@link DataSource}s. This type is
+ * immutable once configured. No property can be set more than once. No
+ * property can be set after {@link build} is called.
+ *
+ * ISSUE: Probably need property(DataSourceProperty prop, Object value).
+ */
+ public interface Builder {
+
+ /**
+ * Specify a property and its value for the built {@link DataSource}.
+ *
+ * @param p {@link DataSourceProperty} to set. Not {@code null}.
+ * @param v value for the property
+ * @return this {@link Builder}
+ * @throws IllegalArgumentException if {@code p.validate(v)} does not return
+ * true, if this method has already been called with the property
+ * {@code p}, or the implementation does not support the
+ * {@link DataSourceProperty}.
+ */
+ public Builder property(DataSourceProperty p, Object v);
+
+ /**
+ * A convenience method for setting the {@link AdbaSessionProperty#URL}.
+ *
+ * @param url the value to be set for {@link AdbaSessionProperty#URL}
+ * @return this {@link Builder}
+ * @see sessionProperty
+ */
+ public default Builder url(String url) {
+ return sessionProperty(AdbaSessionProperty.URL, url);
+ }
+
+ /**
+ * A convenience method for setting the {@link AdbaSessionProperty#USER}.
+ *
+ * @param name the value to be set for {@link AdbaSessionProperty#USER}
+ * @return this {@link Builder}
+ * @see sessionProperty
+ */
+ public default Builder username(String name) {
+ return sessionProperty(AdbaSessionProperty.USER, name);
+ }
+
+ /**
+ * A convenience method for setting the {@link AdbaSessionProperty#PASSWORD}.
+ *
+ * @param password the value to be set for {@link AdbaSessionProperty#PASSWORD}
+ * @return this {@link Builder}
+ * @see sessionProperty
+ */
+ public default Builder password(String password) {
+ return sessionProperty(AdbaSessionProperty.PASSWORD, password);
+ }
+
+ /**
+ * Specify the value of a {@link Session} property that will be set by default on
+ * all {@link Session}s produced by this {@link DataSource}. A different value can be set
+ * for a particular {@link Session} via {@link Session.Builder#property}.
+ *
+ * @param property the {@link SessionProperty} to be set. May not be {@code null}.
+ * @param value the value to be set for {@code property}
+ * @return this {@link Builder}
+ * @throws IllegalArgumentException if {@code property.validate(value)} does not
+ * return {@code true}. If it throws an {@link Exception} that {@link Exception} is the cause. Or if
+ * this property has been specified previously to this method or
+ * {@link sessionProperty} or {@link registerSessionProperty}.
+ * @throws IllegalStateException if {@link build} has previously been called.
+ */
+ public Builder defaultSessionProperty(SessionProperty property, Object value);
+
+ /**
+ * Specify the value of a {@link Session} property that will be set on
+ * all {@link Session}s produced by the built {@link DataSource}.
+ * Attempting to set a different value via
+ * {@link Session.Builder#property} will throw
+ * {@link IllegalArgumentException}.
+ *
+ * @param property the {@link SessionProperty} to set. May not be
+ * {@code null}.
+ * @param value the value to set as the default for {@code property}
+ * @return this {@link Builder}
+ * @throws IllegalArgumentException if {@code property.validate(value)} does
+ * not return {@code true}. If it throws an {@link Exception} that
+ * {@link Exception} is the cause. Or if this property has been specified
+ * previously to this method or {@link defaultSessionProperty} or
+ * {@link registerSessionProperty}.
+ * @throws IllegalStateException if {@link build} has previously been
+ * called.
+ */
+ public Builder sessionProperty(SessionProperty property, Object value);
+
+ /**
+ * Make a user defined property known to the implementation. One reason to
+ * do this is so the default value of the property will be used. If the
+ * {@link DataSource} doesn't know about the property then it cannot know to
+ * set the default value. Convenience method.
+ *
+ * @param property the {@link SessionProperty} to make known. May not be
+ * {@code null}.
+ * @return this Builder
+ * @throws IllegalArgumentException if this property has been specified
+ * previously to this method or {@link sessionProperty} or
+ * {@link defaultSessionProperty}.
+ * @throws IllegalStateException if {@link build} has previously been
+ * called.
+ */
+ public default Builder registerSessionProperty(SessionProperty property) {
+ return defaultSessionProperty(property, property.defaultValue());
+ }
+
+ /**
+ * Provide a method that the built {@link DataSource} will call to control the
+ * rate of {@link Session} creations. The built
+ * {@link DataSource} will call {@code request} with a positive argument
+ * when the {@link DataSource} is able to accept more calls to
+ * {@link DataSource#builder}. The difference between
+ * the sum of all arguments passed to {@code request} and the number of
+ * calls to {@link DataSource#builder} is the
+ * <i>demand</i>. The demand must always be non-negative. If a call is made to
+ * {@link DataSource#builder} that would make the demand negative, that call
+ * throws {@link IllegalStateException}. If {@code requestHook} is not called,
+ * the demand is defined to be infinite.
+ *
+ * <p>
+ * Since the user thread is never blocked, a user thread could in theory
+ * create, attach, use, and close {@link Session}s faster than the underlying
+ * implementation can process the submitted work. At some point work would
+ * start timing out or Java would run out of memory to store the queued
+ * {@link Operation}s. This is a poor way address the issue. This method
+ * allows user code to get feedback from the {@link DataSource} as to whether
+ * the {@link DataSource} can accept more work.
+ * </p>
+ *
+ * @param request accepts calls to increase the demand. Not null.
+ * @return this {@link Builder}
+ * @throws IllegalStateException if this method has been called previously
+ */
+ public Builder requestHook(LongConsumer request);
+
+ /**
+ * Return a DataSource configured as specified.
+ *
+ * @return a configured {@link DataSource}. Not {@code null}.
+ * @throws IllegalArgumentException if unable to return a {@link DataSource} due to
+ * problems with the configuration such is missing or conflicting properties.
+ */
+ public DataSource build();
+ }
+
+ /**
+ * Returns a {@link Session} builder. By default that builder will return
+ * {@link Session}s with the {@code SessionProperty}s specified when creating this
+ * DataSource. Default and unspecified {@link SessionProperty}s can be set with
+ * the returned builder.
+ *
+ * @return a new {@link Session} builder. Not {@code null}.
+ * @throws IllegalStateException if this {@link DataSource} is closed
+ */
+ public Session.Builder builder();
+
+ /**
+ * Returns a {@link Session} that has a submitted attach {@link Operation}. Convenience
+ * method for use with try with resources.
+ *
+ * @return a {@link Session}
+ * @throws IllegalStateException if this {@link DataSource} is closed
+ */
+ public default Session getSession() {
+ return builder().build().attach();
+ }
+
+ /**
+ * Returns a {@link Session} that has a submitted attach {@link Operation} with an error
+ * handler. Convenience method for use with try with resources. The error
+ * handle handles errors in the attach {@link Operation}.
+ *
+ * @param handler for errors in the attach {@link Operation}
+ * @return a {@link Session}
+ * @throws IllegalStateException if this {@link DataSource} is closed
+ */
+ public default Session getSession(Consumer<Throwable> handler) {
+ return builder().build().attach(handler);
+ }
+
+ /**
+ * Translates a SQL string from the format specified by the format argument
+ * to a format that can be used to create {@link Operation}s for the {@link Session}s
+ * provided by this {@link DataSource}.
+ *
+ * ISSUE: Just an idea
+ *
+ * @param format not {@code null}
+ * @param source SQL in the format specified by {@code format}. Not {@code null}.
+ * @return SQL in the format supported by this {@link DataSource}. Not {@code null}.
+ * @throws IllegalArgumentException if the {@code format} is not supported or
+ * if the {@link DataSource} cannot translate the SQL
+ * @throws IllegalStateException if this {@link DataSource} is closed
+ */
+ public default String translateSql(String format, String source) throws SqlException {
+ throw new IllegalArgumentException("Unsupported format: \"" + format + "\"");
+ }
+
+ /**
+ * Return a list of the source formats accepted by the {@link translateSql} method.
+ *
+ * ISSUE: Just an idea
+ *
+ * @return an array of Strings each of which identifies a supported format
+ * @throws IllegalStateException if this {@link DataSource} is closed
+ */
+ public default List<String> supportedTranslateSqlFormats() {
+ return new LinkedList<>();
+ }
+
+ @Override
+ public void close();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/DataSourceFactory.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import java.util.ServiceLoader;
+import java.util.ServiceLoader.Provider;
+
+/**
+ * This interface supports injecting a {@link DataSourceFactory}. The SPI
+ * mechanism will find {@link DataSourceFactory} implementations with the
+ * given class name.
+ *
+ * Implementations must be thread safe.
+ *
+ */
+public interface DataSourceFactory {
+
+ /**
+ * Uses SPI to find a {@link DataSourceFactory} with the requested name or
+ * {@code null} if one is not found.
+ *
+ * @param <T>
+ * @param name the name of the class that implements the factory
+ * @return a {@link DataSourceFactory} for {@code name} or {@code null} if one
+ * is not found
+ */
+ public static <T extends DataSourceFactory> T newFactory(String name) {
+ if (name == null) throw new IllegalArgumentException("DataSourceFactory name is null");
+ return (T)ServiceLoader
+ .load(DataSourceFactory.class)
+ .stream()
+ .filter(p -> p.type().getName().equals(name))
+ .findFirst()
+ .map(Provider::get)
+ .orElse(null);
+ }
+
+ /**
+ * Returns a new {@link DataSource} builder.
+ *
+ * @return a {@link DataSource} builder. Not {@code null}.
+ */
+ public DataSource.Builder builder();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/DataSourceProperty.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 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;
+
+/**
+ * An attribute of a {@link DataSource} that can be configured to influence its
+ * behavior. Implementors of this interface define the properties of
+ * {@link DataSource}s. The {@link DataSource.Builder#property} method is used
+ * to set the values of {@link DataSource} properties.
+ *
+ * Implementations must be thread safe.
+ *
+ */
+public interface DataSourceProperty {
+
+ /**
+ * Return the name of this {@link DataSourceProperty}.
+ *
+ * @return the name of this {@link DataSourceProperty}
+ */
+ public String name();
+
+ /**
+ * Return the type of the value of this {@link DataSourceProperty}. Any value
+ * set for this property must be assignable to this type.
+ *
+ * @return the type of the values of this {@link DataSourceProperty}
+ */
+ public Class<?> range();
+
+ /**
+ * Determine whether a value is valid for this {@link DataSourceProperty}.
+ * Returns {@code true} if {@code value} is valid and {@code false} otherwise.
+ *
+ * @param value a value for this {@link DataSourceProperty}
+ * @return {@code true} iff {@code value} is valid for this
+ * {@link DataSourceProperty}
+ */
+ public default boolean validate(Object value) {
+ return (value == null && this.range() == Void.class) || this.range().isInstance(value);
+ }
+
+ /**
+ * Return the value for this property to use if no other value is set. This
+ * has no meaning for user defined properties as the implementation is not
+ * aware of the the existence of the property. Default values are used for
+ * standard and implementation defined properties.
+ *
+ * @return the default value or {@code null} if there is no default value
+ */
+ public Object defaultValue();
+
+ /**
+ * Returns true if this {@link DataSourceProperty} is contains sensitive
+ * information such as a password or encryption key.
+ *
+ * @return true iff this is sensitive
+ */
+ public boolean isSensitive();
+
+ /**
+ * Configure the {@link DataSource as appropriate for the given {@code value}
+ * of this {@link DataSourceProperty}. This is primarily for the use of user
+ * defined properties.
+ *
+ * @param ds the {@link DataSource} to configure
+ * @param value the value of this property
+ */
+ public default void configure(DataSource ds, Object value) {
+ // nothing
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Examples.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2016, 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;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+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;
+
+/**
+ * Simple example code using various aspects of ADBA. These do not necessarily
+ * demonstrate the best way to use each feature, just one way.
+ */
+public class Examples {
+
+ // DataSourceFactory
+
+ public DataSource getDataSource() {
+ return DataSourceFactory.newFactory("oracle.database.adba")
+ .builder()
+ .url("//host.oracle.com:5521/example")
+ .username("scott")
+ .password("tiger")
+ .build();
+ }
+
+ // RowCountOperation
+
+ public void insertItem(DataSource ds, Item item) {
+ try (Session session = ds.getSession()) {
+ session.rowCountOperation("insert into tab values (:id, :name, :answer)")
+ .set("id", item.id(), AdbaType.NUMERIC)
+ .set("name", item.name(), AdbaType.VARCHAR)
+ .set("answer", item.answer(), AdbaType.NUMERIC)
+ .submit();
+ }
+ }
+
+ // RowOperation
+
+ public void idsForAnswer(DataSource ds, List<Integer> result, int correctAnswer) {
+ try (Session session = ds.getSession()) {
+ session.<List<Integer>>rowOperation("select id, name, answer from tab where answer = :target")
+ .set("target", correctAnswer, AdbaType.NUMERIC)
+ .collect(() -> result,
+ (list, row) -> list.add(row.at("id").get(Integer.class)) )
+ .submit();
+ }
+ }
+
+ // RowOperation
+
+ public CompletionStage<List<Item>> itemsForAnswer(DataSource ds, int answer) {
+ try (Session session = ds.getSession()) {
+ return session.<List<Item>>rowOperation("select id, name, answer from tab where answer = :target")
+ .set("target", 42, AdbaType.NUMERIC)
+ .collect(Collectors.mapping(
+ row -> new Item(row.at("id").get(Integer.class),
+ row.at("name").get(String.class),
+ row.at("answer").get(Integer.class) ),
+ Collectors.toList() ))
+ .submit()
+ .getCompletionStage();
+ }
+ }
+
+ // Independent OperationGroup
+
+ public void insertItemsIndependent(DataSource ds, List<Item> list) {
+ String sql = "insert into tab values (:id, :name, :answer)";
+ try (Session session = ds.getSession()) {
+ OperationGroup group = session.operationGroup()
+ .independent();
+ for (Item elem : list) {
+ group.rowCountOperation(sql)
+ .set("id", elem.id)
+ .set("name", elem.name)
+ .set("answer", elem.answer)
+ .submit()
+ .getCompletionStage()
+ .exceptionally( t -> {
+ System.out.println(elem.id);
+ return null;
+ });
+ }
+ group.submit();
+
+ }
+ }
+
+ // Held OperationGroup
+
+ public void insertItemsHold(DataSource ds, List<Item> list) {
+ String sql = "insert into tabone values (:id, :name, :answer)";
+ try (Session session = ds.getSession()) {
+ OperationGroup group = session.operationGroup()
+ .independent();
+ group.submitHoldingForMoreMembers();
+ for (Item elem : list) {
+ group.rowCountOperation(sql)
+ .set("elem_", elem)
+ .submit()
+ .getCompletionStage()
+ .exceptionally( t -> {
+ System.out.println(elem.id);
+ return null;
+ });
+ }
+ group.releaseProhibitingMoreMembers();
+ }
+ }
+
+ // Parallel, Independent OperationGroup
+
+ public void updateListParallel(List<Item> list, DataSource ds) {
+ String query = "select id from tab where answer = :answer";
+ String update = "update tab set name = :name where id = :id";
+ try (Session session = ds.getSession()) {
+ OperationGroup<Object, Object> group = session.operationGroup()
+ .independent()
+ .parallel();
+ group.submitHoldingForMoreMembers();
+ for (Item elem : list) {
+ CompletionStage<Integer> idPromise = group.<List<Integer>>rowOperation(query)
+ .set("answer", elem.answer, AdbaType.NUMERIC)
+ .collect( Collector.of(
+ () -> new ArrayList<>(),
+ (l, row) -> l.add( row.at("id").get(Integer.class) ),
+ (l, r) -> l ))
+ .submit()
+ .getCompletionStage()
+ .thenApply( l -> l.get(0) );
+ group.rowCountOperation(update)
+ .set("id", idPromise)
+ .set("name", "the ultimate question")
+ .submit()
+ .getCompletionStage()
+ .exceptionally( t -> {
+ System.out.println(elem.id);
+ return null;
+ });
+ }
+ group.releaseProhibitingMoreMembers();
+ }
+ }
+
+ // TransactionCompletion
+
+ public void transaction(DataSource ds) {
+ try (Session session = ds.getSession(t -> System.out.println("ERROR: " + t.toString()))) {
+ TransactionCompletion trans = session.transactionCompletion();
+ CompletionStage<Integer> idPromise = session.<Integer>rowOperation("select empno, ename from emp where ename = :1 for update")
+ .set("1", "CLARK", AdbaType.VARCHAR)
+ .collect(Collectors.collectingAndThen(
+ Collectors.mapping(r -> r.at("empno").get(Integer.class),
+ Collectors.toList()),
+ l -> l.get(0)))
+ .onError( t -> trans.setRollbackOnly() )
+ .submit()
+ .getCompletionStage();
+ session.<Long>rowCountOperation("update emp set deptno = :1 where empno = :2")
+ .set("1", 50, AdbaType.INTEGER)
+ .set("2", idPromise, AdbaType.INTEGER)
+ .apply(c -> {
+ if (c.getCount() != 1L) {
+ trans.setRollbackOnly();
+ throw new RuntimeException("updated wrong number of rows");
+ }
+ return c.getCount();
+ })
+ .onError(t -> trans.setRollbackOnly() )
+ .submit();
+ // .getCompletionStage()
+ // .exceptionally( t -> { trans.setRollbackOnly(); return null; } ) // incorrect
+ session.catchErrors();
+ session.commitMaybeRollback(trans);
+ }
+ }
+
+ // RowPublisherOperation
+
+ public CompletionStage<List<String>> rowSubscriber(DataSource ds) {
+
+ String sql = "select empno, ename from emp";
+ CompletableFuture<List<String>> result = new CompletableFuture<>();
+
+ Flow.Subscriber<Result.RowColumn> subscriber = new Flow.Subscriber<>() {
+
+ Flow.Subscription subscription;
+ List<String> names = new ArrayList<>();
+ int demand = 0;
+
+ @Override
+ public void onSubscribe(Flow.Subscription subscription) {
+ this.subscription = subscription;
+ this.subscription.request(10);
+ demand += 10;
+ }
+
+ @Override
+ public void onNext(Result.RowColumn column) {
+ names.add(column.at("ename").get(String.class));
+ if (--demand < 1) {
+ subscription.request(10);
+ demand += 10;
+ }
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ result.completeExceptionally(throwable);
+ }
+
+ @Override
+ public void onComplete() {
+ result.complete(names);
+ }
+
+ };
+
+ try (Session session = ds.getSession()) {
+ return session.<List<String>>rowPublisherOperation(sql)
+ .subscribe(subscriber, result)
+ .submit()
+ .getCompletionStage();
+ }
+ }
+
+ // Control Operation Submission Rate
+
+ public CompletionStage<Long> insertRecords(DataSource ds, DataInputStream in) {
+ String insert = "insert into tab values (@record)";
+ try (Session session = ds.getSession()) {
+ OperationGroup<Long, Long> group = session.<Long, Long>operationGroup()
+ .independent()
+ .collect(Collectors.summingLong(c -> c));
+ group.submitHoldingForMoreMembers();
+ Semaphore demand = new Semaphore(0);
+ session.requestHook( n -> demand.release((int)n) );
+ while (in.available() > 0) {
+ demand.acquire(1); // user thread blocked by Semaphore, not by ADBA
+ group.<Long>rowCountOperation(insert)
+ .set("record", in.readUTF(), AdbaType.VARCHAR)
+ .apply(c -> c.getCount())
+ .submit();
+ }
+ return group.releaseProhibitingMoreMembers()
+ .getCompletionStage();
+ }
+ catch (IOException | InterruptedException ex) {
+ throw new SqlException(ex);
+ }
+ }
+
+ // ArrayRowCountOperation
+
+ public CompletionStage<Long> arrayInsert(DataSource ds,
+ List<Integer> ids,
+ List<String> names,
+ List<Integer> answers) {
+ String sql = "insert into tab values (?, ?, ?)";
+ try (Session session = ds.getSession()) {
+ return session.<Long>arrayRowCountOperation(sql)
+ .collect(Collectors.summingLong( c -> c.getCount() ))
+ .set("1",ids, AdbaType.INTEGER)
+ .set("2", names, AdbaType.VARCHAR)
+ .set("3", answers, AdbaType.INTEGER)
+ .submit()
+ .getCompletionStage();
+ }
+ }
+
+ // ArrayRowCountOperation -- transposed
+
+ public CompletionStage<Long> transposedArrayInsert(DataSource ds, List<Item> items) {
+ String sql = "insert into tab values (?, ?, ?)";
+ try (Session session = ds.getSession()) {
+ return session.<Long>arrayRowCountOperation(sql)
+ .collect(Collectors.summingLong( c -> c.getCount() ))
+ .set("1", items.stream().map(Item::id).collect(Collectors.toList()), AdbaType.INTEGER)
+ .set("2", items.stream().map(Item::name).collect(Collectors.toList()), AdbaType.VARCHAR)
+ .set("3", items.stream().map(Item::answer).collect(Collectors.toList()), AdbaType.INTEGER)
+ .submit()
+ .getCompletionStage();
+ }
+ }
+
+ // OutOperation
+
+ public CompletionStage<Item> getItem(DataSource ds, int id) {
+ String sql = "call item_for_id(:id, :name, :answer)";
+ try (Session session = ds.getSession()) {
+ return session.<Item>outOperation(sql)
+ .set("id", id, AdbaType.INTEGER)
+ .outParameter("name", AdbaType.VARCHAR)
+ .outParameter("answer", AdbaType.INTEGER)
+ .apply( out -> new Item(id,
+ out.at("name").get(String.class),
+ out.at("answer").get(Integer.class)) )
+ .submit()
+ .getCompletionStage();
+ }
+ }
+
+ // MultiOperation
+
+ // 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
+
+ // TransactionOutcome
+
+ // Column navigation
+
+ private class Name { Name(String ... args) {} }
+ private class Address { Address(String ... args) {} }
+
+ private Name getName(Result.Column col) {
+ return new Name(
+ col.get(String.class), // title
+ col.next().get(String.class), // given name
+ col.next().get(String.class), // middle initial
+ col.next().get(String.class), // family name
+ col.next().get(String.class)); // suffix
+ }
+
+ private Address getAddress(Result.Column col) {
+ List<String> a = new ArrayList<>();
+ for (Result.Column c : col.slice(6)) {
+ a.add(c.get(String.class));
+ }
+ return new Address(a.toArray(new String[0]));
+ }
+ public void columNavigation(Result.RowColumn column) {
+ Name fullName = getName(column.at("name_title"));
+ Address streetAddress = getAddress(column.at("street_address_line1"));
+ Address mailingAddress = getAddress(column.at("mailing_address_line1"));
+ for (Result.Column c : column.at(-14)) { // dump the last 14 columns
+ System.out.println("trailing column " + c.get(String.class));
+ }
+ }
+
+ // Error handling
+
+
+ static public class Item {
+ public int id;
+ public String name;
+ public int answer;
+
+ public Item(int i, String n, int a) {
+ id =i;
+ name = n;
+ answer = a;
+ }
+
+ public int id() {
+ return id;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public int answer() {
+ return answer;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/LocalOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.concurrent.Callable;
+import java.util.function.Consumer;
+
+/**
+ * An {@link Operation} that executes a user defined action when executed. Does
+ * not perform any database action. The result of a {@link LocalOperation} is
+ * the result of calling the {@link Callable}. This type allows user code to
+ * execute arbitrary code at particular points in the sequence of
+ * {@link Operation}s executed by a {@link Session} without having to execute
+ * a specific database action at the same time.
+ *
+ * @param <T> the type of the result of this {@link Operation}
+ */
+public interface LocalOperation<T> extends Operation<T> {
+
+ /**
+ * Provides an action for this {@link Operation}. The action is called when this
+ * {@link LocalOperation} is executed. The result of this {@link LocalOperation}
+ * is the result of executing the action.
+ *
+ * ISSUE: Should this use Supplier rather than Callable?
+ *
+ * @param action called when this {@link Operation} is executed
+ * @return this {@link LocalOperation}
+ * @throws IllegalStateException if this method has already been called or
+ * this {@link Operation} has been submitted.
+ */
+ public LocalOperation<T> onExecution(Callable<T> action);
+
+ @Override
+ public LocalOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ public LocalOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/MultiOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,175 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.concurrent.CompletionStage;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * A multi-operation is an {@link Operation} that returns one or more results in
+ * addition to the out result defined by the {@link Operation}. Each result is
+ * processed by an Operation. The Operations can be created by calling
+ * rowOperation, rowProcessorOperation, or countOperation if the kind of results
+ * is known. These results are processed in the order the Operations are
+ * submitted. Any results not processed by an explicit Operation is processed by
+ * calling the appropriate handler specified by onRows or onCount. If any result
+ * is an error that error is processed by calling the handler specified by
+ * onError. If the appropriate handler is not specified that result is ignored,
+ * including errors.
+ *
+ * ISSUE: Should this have a collector?
+ *
+ * @param <T> The type of the result of this {@link Operation}
+ */
+public interface MultiOperation<T> extends OutOperation<T> {
+
+ /**
+ * Returns a {@link RowOperation} to process a row sequence result. The
+ * {@link Operation}s are executed in the order they are submitted. If a
+ * result is of the wrong type for the next submitted {@link Operation} the
+ * {@link MultiOperation} is completed with {@link IllegalStateException}.
+ *
+ * @return a {@link RowOperation} that is part of this {@link MultiOperation}
+ */
+ public RowOperation<T> rowOperation();
+
+ /**
+ * Returns a {@link RowPublisherOperation} to process a row sequence result.
+ * The {@link Operation}s are executed in the order they are submitted. If a
+ * result is of the wrong type for the next submitted {@link Operation} the
+ * {@link MultiOperation} is completed with {@link IllegalStateException}.
+ *
+ * @return a {@link RowPublisherOperation} that is part of this
+ * {@link MultiOperation}
+ */
+ public RowPublisherOperation<T> rowProcessorOperation();
+
+ /**
+ * Returns a {@link RowCountOperation} to process a count result. The
+ * {@link Operation}s are executed in the order they are submitted. If a
+ * result is of the wrong type for the next submitted Operation the
+ * {@link MultiOperation} is completed with {@link IllegalStateException}.
+ *
+ * @return a {@link RowCountOperation} that is part of this
+ * {@link MultiOperation}
+ */
+ public RowCountOperation<T> rowCountOperation();
+
+ /**
+ * Provides a handler for trailing count results. The provided handler is
+ * called for each count result not processed by RowCountOperation. When
+ * called the first argument is the number of results that preceeded the
+ * current result. The second argument is a {@link RowCountOperation} that
+ * will process the current result. This {@link RowCountOperation} has not
+ * been configured in any way nor has it been submitted. The handler
+ * configures the {@link RowCountOperation} and submits it. The count result
+ * is processed when the {@link RowCountOperation} is submitted. If the
+ * {@link RowCountOperation} is not submitted when the handler returns the
+ * count result is ignored.
+ *
+ * If this method is not called any trailing count results are ignored.
+ *
+ * @param handler not null
+ * @return this MultiOperation
+ * @throws IllegalStateException if this method was called previously
+ */
+ public MultiOperation<T> onCount(BiConsumer<Integer, RowCountOperation<T>> handler);
+
+ /**
+ * Provides a handler for trailing row sequence results. The provided handler
+ * is called for each row sequence result not processed by a RowOperation.
+ * When called the first argument is the number of results that preceeded the
+ * current result. The second argument is a {@link RowOperation} that will
+ * process the current result. This {@link RowOperation} has not been
+ * configured in any way nor has it been submitted. The handler configures the
+ * {@link RowOperation} and submits it. The row sequence result is processed
+ * when the {@link RowOperation} is submitted. If the {@link RowOperation} is
+ * not submitted when the handler returns, the row sequence result is ignored.
+ *
+ * If this method is not called any trailing row sequence results are ignored.
+ *
+ * ISSUE: Should there be a version of this method that provides
+ * RowProcessorOperations? If so only one of that method or this one can be
+ * called.
+ *
+ * @param handler
+ * @return This MultiOperation
+ * @throws IllegalStateException if this method was called previously
+ */
+ public MultiOperation<T> onRows(BiConsumer<Integer, RowOperation<T>> handler);
+
+ /**
+ * Provides an error handler for this {@link Operation}. The provided handler
+ * is called for each error that occurs. When called the first argument is the
+ * number of results, including errors, that preceeded the current error. The
+ * second argument is a {@link Throwable} corresponding to the error. When the
+ * handler returns processing of the MultiOperation results continues. Only
+ * one onError method may be called.
+ *
+ * @param handler a BiConsumer that handles an error
+ * @return this MultiOperation
+ * @throws IllegalStateException if this method or
+ * {@link MultiOperation#onError(java.util.function.Consumer)} was called
+ * previously
+ */
+ public MultiOperation<T> onError(BiConsumer<Integer, Throwable> handler);
+ // Covariant overrides
+
+ /**
+ * This handler is called if the execution fails completely. If the execution
+ * returns any individual results, even if any or all of those results are
+ * errors, this handler is not called.
+ *
+ * @param handler
+ * @return
+ */
+ @Override
+ public MultiOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ public MultiOperation<T> apply(Function<Result.OutColumn, ? extends T> processor);
+
+ @Override
+ public MultiOperation<T> outParameter(String id, SqlType type);
+
+ @Override
+ public MultiOperation<T> set(String id, Object value, SqlType type);
+
+ @Override
+ public MultiOperation<T> set(String id, Object value);
+
+ @Override
+ public MultiOperation<T> set(String id, CompletionStage<?> source, SqlType type);
+
+ @Override
+ public MultiOperation<T> set(String id, CompletionStage<?> source);
+
+ @Override
+ public MultiOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Operation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.function.Consumer;
+
+/**
+ * A description of some work to be done by the database and how to process the
+ * database output. An {@link Operation} is created by an
+ * {@link OperationGroup}, configured and submitted. If not submitted it is not
+ * executed. If submitted it is possibly executed according to the attributes of
+ * the {@link OperationGroup} that created it.
+ *
+ * <p>
+ * If execution of the work results in an error, the Operation is completed
+ * exceptionally. The {@link Throwable} that completes the Operation is
+ * implementation dependent. It is recommended that an implementation use
+ * SqlException in the event of database problems. Other {@link Throwable}s such
+ * as {@link java.io.IOException}, {@link NullPointerException}, etc can be used
+ * as appropriate. An implementation should not wrap a useful exception in a
+ * {@link SqlException} unless that provides valuable additional information. An
+ * implementation should use whatever {@link Throwable} best facilitates
+ * appropriate error handling.</p>
+ *
+ * <p>
+ * An Operation is not required to be thread safe. In general a single user
+ * thread will configure and submit an Operation. Once an Operation is submitted
+ * it is immutable. {@link OperationGroup} is an exception and is thread safe.</p>
+ *
+ * @param <T> the type of the result of the {@link Operation}
+ */
+public interface Operation<T> extends PrimitiveOperation<T> {
+
+ /**
+ * Provides an error handler for this {@link Operation}. If execution of this
+ * {@link Operation} results in an error, before the Operation is completed,
+ * the handler is called with the {@link Throwable} as the argument. The type
+ * of the {@link Throwable} is implementation dependent.
+ *
+ * @param handler
+ * @return this {@link Operation}
+ * @throws IllegalStateException if this method is called more than once on
+ * this operation
+ */
+ public Operation<T> onError(Consumer<Throwable> handler);
+
+ /**
+ * The minimum time before this {@link Operation} might be canceled
+ * automatically. The default value is forever. The time is
+ * counted from the beginning of Operation execution. The Operation will not
+ * be canceled before {@code minTime} after the beginning of execution.
+ * Some time at least {@code minTime} after the beginning of execution,
+ * an attempt will be made to cancel the {@link Operation} if it has not yet
+ * completed. Implementations are encouraged to attempt to cancel within a
+ * reasonable time, though what is reasonable is implementation dependent.
+ *
+ * @param minTime minimum time to wait before attempting to cancel
+ * @return this Operation
+ * @throws IllegalArgumentException if minTime <= {@link java.time.Duration#ZERO}
+ * @throws IllegalStateException if this method is called more than once on
+ * this operation
+ */
+ public Operation<T> timeout(Duration minTime);
+
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/OperationGroup.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,734 @@
+/*
+ * 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;
+
+import java.time.Duration;
+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;
+
+/**
+ * <p>
+ * A set of {@link Operation}s that share certain properties, are managed as a
+ * unit, and are executed as a unit. The {@link Operation}s created by an
+ * {@link OperationGroup} and submitted are the member {@link Operation}s of
+ * that {@link OperationGroup}. An {@link OperationGroup} is not a transaction
+ * and is not related to a transaction in any way.</p>
+ *
+ * <p>
+ * An {@link OperationGroup} conceptually has a collection of member
+ * {@link Operation}s. When an {@link OperationGroup} is submitted it is placed
+ * in the collection of the {@link OperationGroup} of which it is a member. The
+ * member {@link OperationGroup} is executed according to the attributes of the
+ * {@link OperationGroup} of which it is a member. The member {@link Operation}s
+ * of an {@link OperationGroup} are executed according to the attributes of that
+ * {@link OperationGroup}.</p>
+ *
+ * <p>
+ * How an {@link OperationGroup} is executed depends on its attributes.</p>
+ *
+ * <p>
+ * If an {@link OperationGroup} has a condition and the value of that condition
+ * is {@link Boolean#TRUE} then execute the member {@link Operation}s as below.
+ * If it is {@link Boolean#FALSE} then the {@link OperationGroup} is completed
+ * with the value null. If the condition completed exceptionally then the
+ * {@link OperationGroup} is completed exceptionally with a
+ * {@link SqlSkippedException} that has that exception as its cause.</p>
+ *
+ * <p>
+ * If the {@link OperationGroup} is sequential the member {@link Operation}s are
+ * executed in the order they were submitted. If it is parallel, they may be
+ * executed in any order including simultaneously.</p>
+ *
+ * <p>
+ * If an {@link OperationGroup} is dependent and a member {@link Operation}
+ * completes exceptionally the remaining member {@link Operation}s in the
+ * collection are completed exceptionally with a {@link SqlSkippedException}
+ * that has the initial {@link Exception} as its cause and the {@link OperationGroup}
+ * is completed exceptionally with the initial {@link Exception}. A member
+ * {@link Operation} in-flight may either complete normally or be completed
+ * exceptionally but must complete one way or the other. [NOTE: Too strong?]</p>
+ *
+ * <p>
+ * After a call to {@link OperationGroup#submitHoldingForMoreMembers} the
+ * {@link OperationGroup} is submitted and held. After a call to
+ * {@link OperationGroup#releaseProhibitingMoreMembers} the {@link OperationGroup}
+ * is no longer held and is still submitted. Holding permits member {@link Operation}s
+ * to be executed at the same time additional member {@link Operation}s are
+ * submitted. Collecting the member {@link Operation}s' results does not begin
+ * until the {@link OperationGroup} is no longer held.</p>
+ *
+ * <p>
+ * If an {@link OperationGroup} is held additional member {@link Operation}s may
+ * be submitted. If an {@link OperationGroup} is not held, no additional member
+ * {@link Operation}s may be submitted after the {@link OperationGroup} is
+ * submitted. If an {@link OperationGroup} is held it will be completed only after
+ * it is released or if conditional and the condition is not {@link Boolean#TRUE}.
+ * If a {@link OperationGroup} is dependent, held, one of its member
+ * {@link Operation}s completed exceptionally, and its queue is empty then the
+ * {@link OperationGroup} is released.</p>
+ *
+ * <p>
+ * The result of this {@link OperationGroup} is the result of collecting the
+ * results of its member {@link Operation}s. If the {@link OperationGroup} is
+ * dependent and one of its member {@link Operation}s completes exceptionally,
+ * the {@link OperationGroup} is completed exceptionally.</p>
+ *
+ * <p>
+ * An implementation of this class must be thread safe as result and error
+ * handlers running asynchronously may be accessing an {@link OperationGroup} in
+ * parallel with each other and with a user thread.</p>
+
+* <p>
+ * ISSUE: Currently no way to create a nested {@link OperationGroup}. That is an
+ * intentional limitation but may be a simplification we can live with. Or not.</p>
+ *
+ * @param <S> The type of the result of the member {@link Operation}s
+ * @param <T> The type of the collected results the member {@link Operation}s
+ */
+public interface OperationGroup<S, T> extends Operation<T> {
+
+ /**
+ * Mark this {@link OperationGroup} as parallel. If this method is not called
+ * the {@link OperationGroup} is sequential. If an {@link OperationGroup} is
+ * parallel, member {@link Operation}s may be executed in any order including
+ * in parallel. If an {@link OperationGroup} is sequential, the default,
+ * member {@link Operation}s are executed strictly in the order they are
+ * submitted.
+ *
+ * Note: There is no covariant override of this method in {@link Session}
+ * as there is only a small likelihood of needing it.
+ *
+ * @return this {@link OperationGroup}
+ * @throws IllegalStateException if this {@link OperationGroup} has been
+ * submitted, any member {@link Operation}s have been created, or this method
+ * has been called previously
+ */
+ public OperationGroup<S, T> parallel();
+
+ /**
+ * Mark this {@link OperationGroup} as independent. If this method is not
+ * called the {@link OperationGroup} is dependent, the default. If an
+ * {@link OperationGroup} is independent then failure of one member
+ * {@link Operation} does not affect the execution of other member
+ * {@link Operation}s. If an {@link OperationGroup} is dependent then failure
+ * of one member {@link Operation} will cause all member {@link Operation}s
+ * remaining in the queue to be completed exceptionally with a
+ * {@link SqlSkippedException} with the cause set to the original exception.
+ *
+ * The result of this {@link OperationGroup}'s execution is the result of collecting the
+ * results of the member {@link Operation}s that complete normally.
+ *
+ * Note: There is no covariant override of this method in {@link Session}
+ * as there is only a small likelihood of needing it.
+ *
+ * @return this {@link OperationGroup}
+ * @throws IllegalStateException if this {@link OperationGroup} has been
+ * submitted, any member {@link Operation}s have been created, or this method
+ * has been called previously
+ */
+ public OperationGroup<S, T> independent();
+
+ /**
+ * Define a condition that determines whether the member {@link Operation}s of
+ * this {@link OperationGroup} are executed or not. If and when this
+ * {@link OperationGroup} is executed then if the condition argument is
+ * completed with {@link Boolean#TRUE} the member {@link Operation}s are
+ * executed. If {@link Boolean#FALSE} or if it is completed exceptionally the
+ * member {@link Operation}s are not executed but are removed from the queue.
+ * After all member {@link Operation}s have been removed from the queue this
+ * {@link OperationGroup} is completed with {@code null}.
+ *
+ * Note: There is no covariant override of this method in Session as there
+ * is only a small likelihood of needing it.
+ *
+ * ISSUE: Should the member Operations be skipped or otherwise completed
+ * exceptionally?
+ *
+ * @param condition a {@link CompletionStage} the value of which determines
+ * whether this {@link OperationGroup} is executed or not
+ * @return this OperationGroup
+ * @throws IllegalStateException if this {@link OperationGroup} has been
+ * submitted, any member {@link Operation}s have been created, or this method
+ * has been called previously
+ */
+ public OperationGroup<S, T> conditional(CompletionStage<Boolean> condition);
+
+ /**
+ * Mark this {@link OperationGroup} as submitted and held. It can be executed but cannot be
+ * completed. A {@link OperationGroup} that is held remains in the queue even
+ * if all of its current member {@link Operation}s have completed. So long as
+ * the {@link OperationGroup} is held new member {@link Operation}s can be
+ * submitted. A {@link OperationGroup} that is held must be released before it
+ * can be completed and removed from the queue.
+ *
+ * If the {@link OperationGroup} is dependent and one of its member {@link Operation}s
+ * completes exceptionally and its queue is empty the {@link OperationGroup}
+ * is completed.
+ *
+ * Note: There is no covariant override of this method in Session as there
+ * is only a small likelihood of needing it.
+ *
+ * ISSUE: Need a better name.
+ *
+ * @return a Submission for this OperationGroup
+ * @throws IllegalStateException if this {@link OperationGroup} has been
+ * submitted
+ */
+ public Submission<T> submitHoldingForMoreMembers();
+
+ /**
+ * Allow this {@link OperationGroup} to be completed and removed from the
+ * queue once all of its member {@link Operation}s have been completed. After
+ * this method is called no additional member {@link Operation}s can be
+ * submitted. Once all member {@link Operation}s have been removed from the
+ * queue this {@link OperationGroup} will be completed and removed from the
+ * queue.
+ *
+ * Note: There is no covariant override of this method in Session as there
+ * is only a small likelihood of needing it.
+ *
+ * ISSUE: Need a better name.
+ *
+ * @return the same Submission that was returned by {@link OperationGroup#submitHoldingForMoreMembers}
+ * @throws IllegalStateException if this {@link OperationGroup} has been
+ * completed or is not held.
+ */
+ public Submission<T> releaseProhibitingMoreMembers();
+
+ /**
+ * Provides a {@link Collector} to reduce the results of the member
+ * {@link Operation}s. The result of this {@link OperationGroup} is the result
+ * of calling finisher on the final accumulated result.If the
+ * {@link Collector} is {@link Collector.Characteristics#UNORDERED} the member
+ * {@link Operation} results may be accumulated out of order.If the
+ * {@link Collector} is {@link Collector.Characteristics#CONCURRENT} then the
+ * member {@link Operation} results may be split into subsets that are reduced
+ * separately and then combined. If this {@link OperationGroup} is sequential,
+ * the characteristics of the {@link Collector} only affect how the results of
+ * the member {@link Operation}s are collected; the member {@link Operation}s
+ * are executed sequentially regardless. If this {@link OperationGroup} is
+ * parallel the characteristics of the {@link Collector} may influence the
+ * execution order of the member {@link Operation}s.
+ *
+ * The default value is
+ * {@code Collector.of(()->null, (a,t)->{}, (l,r)->null, a->null)}.
+ *
+ * @param c the Collector. Not null.
+ * @return This OperationGroup
+ * @throws IllegalStateException if called more than once or if this
+ * {@link OperationGroup} has been submitted
+ */
+ public OperationGroup<S, T> collect(Collector<S, ?, T> c);
+
+ /**
+ * Return a new member {@link PrimitiveOperation} that is never skipped.
+ * Skipping of member {@link Operation}s stops with a catchOperation and the
+ * subsequent {@link Operation} is executed normally. The value of a
+ * catchOperation is always null. Since a catchOperation is never completed
+ * exceptionally, it has no error handler or timeout.
+ *
+ * @return an {@link PrimitiveOperation} that is never skipped;
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held or if the {@link OperationGroup} is parallel or
+ * independent.
+ */
+ public PrimitiveOperation<S> catchOperation();
+
+ /**
+ * Creates and submits a catch Operation. Convenience method.
+ *
+ * @return this OperationGroup
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held or if the {@link OperationGroup} is parallel or
+ * independent.
+ */
+ public default OperationGroup<S, T> catchErrors() {
+ catchOperation().submit();
+ return this;
+ }
+
+ /**
+ * Return a new {@link ArrayRowCountOperation}.
+ * <p>
+ * Usage Note: Frequently use of this method will require a type witness to
+ * enable correct type inferencing.
+ * <pre><code>
+ * session.<b><List<Integer>></b>arrayCountOperation(sql)
+ * .set ...
+ * .collect ...
+ * .submit ...
+ * </code></pre>
+ *
+ * @param <R> the result type of the returned {@link ArrayRowCountOperation}
+ * @param sql SQL to be executed. Must return an update count.
+ * @return a new {@link ArrayRowCountOperation} that is a member of this
+ * {@link OperationGroup}
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held
+ */
+ public <R extends S> ArrayRowCountOperation<R> arrayRowCountOperation(String sql);
+
+ /**
+ * Return a new {@link ParameterizedRowCountOperation}.
+ *
+ * @param <R> the result type of the returned {@link CountOperation}
+ * @param sql SQL to be executed. Must return an update count.
+ * @return an new {@link ParameterizedRowCountOperation} that is a member of this
+ * {@link OperationGroup}
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held
+ */
+ public <R extends S> ParameterizedRowCountOperation<R> rowCountOperation(String sql);
+
+ /**
+ * Return a new {@link Operation} for a SQL that doesn't return any result,
+ * for example DDL. The result of this Operation is always null.
+ *
+ * The result of the returned Operation must be Void but specifying that here
+ * causes problems.
+ *
+ * @param sql SQL for the {@link Operation}.
+ * @return a new {@link Operation} that is a member of this
+ * {@link OperationGroup}
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held
+ */
+ public Operation<S> operation(String sql);
+
+ /**
+ * Return a new {@link OutOperation} that is a member {@link Operation} of this
+ * {@link OperationGroup}. The SQL must return a set of zero or more out
+ * parameters or function results.
+ *
+ * @param <R> the result type of the returned {@link OutOperation}
+ * @param sql SQL for the {@link Operation}. Must return zero or more out
+ * parameters or function results.
+ * @return a new {@link OutOperation} that is a member of this
+ * {@link OperationGroup}
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held
+ */
+ public <R extends S> OutOperation<R> outOperation(String sql);
+
+ /**
+ * Return a new {@link ParameterizedRowOperation} that is a member
+ * {@link Operation} of this {@link OperationGroup}.
+ *
+ * @param <R> the type of the result of the returned
+ * {@link ParameterizedRowOperation}
+ * @param sql SQL for the {@link Operation}. Must return a row sequence.
+ * @return a new {@link ParameterizedRowOperation} that is a member of this
+ * {@link OperationGroup}
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held
+ */
+ public <R extends S> ParameterizedRowOperation<R> rowOperation(String sql);
+
+ /**
+ * Return a new {@link ParameterizedRowPublisherOperation} that is a member
+ * {@link Operation} of this {@link OperationGroup}.
+ *
+ * @param <R> the type of the result of the returned
+ * {@link ParameterizedRowPublisherOperation}
+ * @param sql SQL for the {@link Operation}. Must return a row sequence.
+ * @return a new {@link ParameterizedRowPublisherOperation} that is a member
+ * of this {@link OperationGroup}
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held
+ */
+ public <R extends S> ParameterizedRowPublisherOperation<R> rowPublisherOperation(String sql);
+
+ /**
+ * Return a new {@link MultiOperation} that is a member
+ * {@link Operation} of this {@link OperationGroup}.
+ *
+ * @param <R> the type of the result of the returned
+ * {@link MultiOperation}
+ * @param sql SQL for the {@link Operation}
+ * @return a new {@link MultiOperation} that is a member of this
+ * {@link OperationGroup}
+ * @throws IllegalStateException if the {@link OperationGroup} has been
+ * submitted and is not held
+ */
+ public <R extends S> MultiOperation<R> multiOperation(String sql);
+
+ /**
+ * Return a new {@link Operation} that ends the database transaction. This
+ * {@link Operation} is a member of the {@link OperationGroup}. The
+ * transaction is ended with a commit unless the {@link Transaction} has been
+ * {@link Transaction#setRollbackOnly} in which case the transaction is ended
+ * with a rollback.
+ *
+ * <p>
+ * An endTransaction Operation may be skipped. To insure that it will not be
+ * skipped it should immediately follow a catch Operation. All end transaction
+ * convenience methods do so.</p>
+ *
+ * The type argument {@link S} of the containing {@link OperationGroup} must
+ * be a supertype of {@link TransactionOutcome}.
+ *
+ * @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(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 TransactionCompletion#setRollbackOnly}. The endTransaction Operation
+ * is never skipped.
+ *
+ * @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(TransactionCompletion trans) {
+ catchErrors();
+ return this.endTransactionOperation(trans).submit().getCompletionStage();
+ }
+
+ /**
+ * Return a new {@link LocalOperation} that is a member {@link Operation} of
+ * this {@link OperationGroup}.
+ *
+ * @param <R> value type of the returned local {@link Operation}
+ * @return a LocalOperation
+ * @throws IllegalStateException if this {@link OperationGroup} has been submitted and
+ * is not held
+ */
+ public <R extends S> LocalOperation<R> localOperation();
+
+ /**
+ * Supply a {@link Logger} for the implementation of this
+ * {@link OperationGroup} to use to log significant events. Exactly what
+ * events are logged, at what Level the events are logged and with what
+ * parameters is implementation dependent. All member {@link Operation}s of
+ * this {@link OperationGroup} will use the same {@link Logger} except a
+ * member {@link OperationGroup} that is supplied with a different
+ * {@link Logger} uses that {@link Logger}.
+ *
+ * Supplying a {@link Logger} configured with a
+ * {@link java.util.logging.MemoryHandler} with the
+ * {@link java.util.logging.MemoryHandler#pushLevel} set to
+ * {@link java.util.logging.Level#WARNING} will result in no log output in
+ * normal operation. In the event of an error the actions leading up to the
+ * error will be logged.
+ *
+ * Implementation Note: Implementations are encouraged to log the creation of
+ * this {@link OperationGroup} set to {@link java.util.logging.Level#INFO},
+ * the creation of member {@link Operation}s at the
+ * {@link java.util.logging.Level#CONFIG} level, and execution of member
+ * {@link Operation}s at the {@link java.util.logging.Level#FINE} level.
+ * Detailed information about the execution of member {@link Operation}s may
+ * be logged at the {@link java.util.logging.Level#FINER} and
+ * {@link java.util.logging.Level#FINEST} levels. Errors in the execution of
+ * user code should be logged at the {@link java.util.logging.Level#WARNING}
+ * Level. Errors in the implementation code should be logged at the
+ * {@link java.util.logging.Level#SEVERE} Level.
+ *
+ * @param logger used by the implementation to log significant events
+ * @return this {@link OperationGroup}
+ */
+ public OperationGroup<S, T> logger(Logger logger);
+
+ /**
+ * 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);
+
+ @Override
+ public OperationGroup<S, T> onError(Consumer<Throwable> handler);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/OutOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * An {@link ParameterizedOperation} for which the result is a set of out parameter
+ * values and/or function results. As the SQL is vendor specific, how parameters
+ * are represented in the SQL is itself vendor specific.
+ *
+ * @param <T> the type of the result of this {@link Operation}
+ */
+public interface OutOperation<T> extends ParameterizedOperation<T> {
+
+ /**
+ * Register an out parameter identified by the given id.
+ *
+ * @param id the parameter identifier
+ * @param type the SQL type of the value of the parameter
+ * @return this {@link OutOperation}
+ * @throws IllegalArgumentException if id is not a parameter marker in the SQL
+ * @throws IllegalStateException if this method has been called previously on
+ * this {@link Operation} with the same id or this {@link OutOperation} has been submitted
+ */
+ public OutOperation<T> outParameter(String id, SqlType type);
+
+ /**
+ * Provide a processor that will handle the result of executing the SQL.
+ *
+ * @param processor the {@link Function} that will be called to process the result of
+ * this {@link OutOperation}
+ * @return this {@link OutOperation}
+ * @throws IllegalStateException if this method has been called previously on
+ * this {@link Operation} or this {@link Operation} has been submitted.
+ */
+ public OutOperation<T> apply(Function<Result.OutColumn, ? extends T> processor);
+
+ // Covariant overrides
+
+ @Override
+ public OutOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ public OutOperation<T> set(String id, Object value);
+
+ @Override
+ public OutOperation<T> set(String id, Object value, SqlType type);
+
+ @Override
+ public OutOperation<T> set(String id, CompletionStage<?> source);
+
+ @Override
+ public OutOperation<T> set(String id, CompletionStage<?> source, SqlType type);
+
+ @Override
+ public OutOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/ParameterizedOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,108 @@
+/*
+ * 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;
+
+import java.util.concurrent.CompletionStage;
+
+/**
+ * An Operation that has in parameters.
+ *
+ * As the SQL is vendor specific, how parameters are represented in the SQL is
+ * itself vendor specific.
+ *
+ * For positional parameters, those where all parameters are indicated by the
+ * same character sequence, for example '?', it is recommended that the
+ * parameter id be the decimal integer representation of the parameter number.
+ *
+ * A SQL structured type passed as an argument to a set method must be created
+ * by the same {@link Session} that the created the
+ * {@link ParameterizedOperation}. If not {@link IllegalArgumentException} is
+ * thrown. A SQL structured type is one of
+ * {@link SqlArray}, {@link SqlBlob}, {@link SqlClob}, {@link SqlRef} or
+ * {@link SqlStruct}. This limitation holds recursively for all components of
+ * a SQL structured type. An implementation may relax this constraint.
+ *
+ * @param <T> the type of the result of this {@link Operation}
+ */
+public interface ParameterizedOperation<T> extends Operation<T> {
+
+ /**
+ * Set a parameter value. The value is captured and should not be modified
+ * before the {@link Operation} is completed.
+ *
+ * @param id the identifier of the parameter marker to be set
+ * @param value the value the parameter is to be set to
+ * @param type the SQL type of the value to send to the database
+ * @return this Operation
+ */
+ public ParameterizedOperation<T> set(String id, Object value, SqlType type);
+
+ /**
+ * Set a parameter value. Use a default SQL type determined by the type of the
+ * value argument. The value is captured and should not be modified before the
+ * {@link Operation} is completed.
+ *
+ * @param id the identifier of the parameter marker to be set
+ * @param value the value the parameter is to be set to
+ * @return this {@link Operation}
+ */
+ public ParameterizedOperation<T> set(String id, Object value);
+
+ /**
+ * Set a parameter value to be the value of a
+ * {@link java.util.concurrent.CompletionStage}. The {@link Operation} will
+ * not be executed until the {@link java.util.concurrent.CompletionStage} is
+ * completed. This method allows submitting {@link Operation}s that depend on
+ * the result of previous {@link Operation}s rather than requiring that the
+ * dependent {@link Operation} be submitted only when the previous
+ * {@link Operation} completes.
+ *
+ * @param id the identifier of the parameter marker to be set
+ * @param source the {@link java.util.concurrent.CompletionStage} that provides
+ * the value the parameter is to be set to
+ * @param type the SQL type of the value to send to the database
+ * @return this {@link Operation}
+ */
+ public ParameterizedOperation<T> set(String id, CompletionStage<?> source, SqlType type);
+
+ /**
+ * Set a parameter value to be the future value of a
+ * {@link java.util.concurrent.CompletionStage}. The {@link Operation} will
+ * not be executed until the {@link java.util.concurrent.CompletionStage} is
+ * completed. This method allows submitting {@link Operation}s that depend on
+ * the result of previous {@link Operation}s rather than requiring that the
+ * dependent {@link Operation} be submitted only when the previous
+ * {@link Operation} completes. Use a default SQL type determined by the type
+ * of the value of the {@link java.util.concurrent.CompletionStage}
+ * argument.
+ *
+ * @param id the identifier of the parameter marker to be set
+ * @param source the {@link java.util.concurrent.CompletionStage} that
+ * provides the value the parameter is to be set to
+ * @return this {@link Operation}
+ */
+ public ParameterizedOperation<T> set(String id, CompletionStage<?> source);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/ParameterizedRowCountOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * A {@link ParameterizedRowCountOperation} is a {@link ParameterizedOperation} that returns a count.
+ *
+ * @param <T> the type of the result of this {@link Operation}
+ */
+public interface ParameterizedRowCountOperation<T> extends ParameterizedOperation<T>, RowCountOperation<T> {
+
+ /**
+ * Returns a {@link RowOperation} to process the auto-generated keys, if any, returned
+ * by this {@link Operation}. If no keys are named the columns of the returned
+ * rows are implementation dependent. If keys are specified the columns of the
+ * returned rows are the keys. The {@link RowOperation} must be submitted before this
+ * {@link Operation} is submitted. If it has not submitting this {@link Operation} will
+ * result throw {@link IllegalStateException}.
+ *
+ * ISSUE: Should this be in {@link RowCountOperation}?
+ *
+ * @param keys the names of the returned columns or null.
+ * @return A RowOperation that will process the auto-generated keys
+ * @throws IllegalStateException if this method has already been called on this
+ * {@link Operation} or if this {@link Operation} has already been submitted.
+ */
+ public RowOperation<T> returning(String ... keys);
+
+ // Covariant overrides
+
+ @Override
+ public ParameterizedRowCountOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ ParameterizedRowCountOperation<T> apply(Function<Result.RowCount, ? extends T> processor);
+
+ @Override
+ public ParameterizedRowCountOperation<T> set(String id, Object value);
+
+ @Override
+ public ParameterizedRowCountOperation<T> set(String id, Object value, SqlType type);
+
+ @Override
+ public ParameterizedRowCountOperation<T> set(String id, CompletionStage<?> source);
+
+ @Override
+ public ParameterizedRowCountOperation<T> set(String id, CompletionStage<?> source, SqlType type);
+
+ @Override
+ public ParameterizedRowCountOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/ParameterizedRowOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Consumer;
+import java.util.stream.Collector;
+
+/**
+ * An Operation that accepts parameters and processes a sequence of rows.
+ *
+ * @param <T> the type of the result of this {@link Operation}
+ */
+public interface ParameterizedRowOperation<T> extends ParameterizedOperation<T>, RowOperation<T> {
+
+ // Covariant overrides
+
+ @Override
+ public ParameterizedRowOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ public ParameterizedRowOperation<T> fetchSize(long rows) throws IllegalArgumentException;
+
+ @Override
+ public <A, S extends T> ParameterizedRowOperation<T> collect(Collector<? super Result.RowColumn, A, S> c);
+
+ @Override
+ public ParameterizedRowOperation<T> set(String id, Object value, SqlType type);
+
+ @Override
+ public ParameterizedRowOperation<T> set(String id, CompletionStage<?> source, SqlType type);
+
+ @Override
+ public ParameterizedRowOperation<T> set(String id, CompletionStage<?> source);
+
+ @Override
+ public ParameterizedRowOperation<T> set(String id, Object value);
+
+ @Override
+ public ParameterizedRowOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/ParameterizedRowPublisherOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 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;
+
+import java.time.Duration;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.Flow;
+import java.util.function.Consumer;
+
+/**
+ * An Operation that accepts parameters, subscribes to a sequence of rows, and
+ * returns a result.
+ *
+ * @param <T> the type of the result of this {@link Operation}
+ */
+public interface ParameterizedRowPublisherOperation<T>
+ extends RowPublisherOperation<T>, ParameterizedOperation<T> {
+
+ // Covariant overrides
+
+ @Override
+ public ParameterizedRowPublisherOperation<T> subscribe(Flow.Subscriber<? super Result.RowColumn> subscriber,
+ CompletionStage<? extends T> result);
+
+ @Override
+ public ParameterizedRowPublisherOperation<T> set(String id, Object value, SqlType type);
+
+ @Override
+ public ParameterizedRowPublisherOperation<T> set(String id, CompletionStage<?> source, SqlType type);
+
+ @Override
+ public ParameterizedRowPublisherOperation<T> set(String id, CompletionStage<?> source);
+
+ @Override
+ public ParameterizedRowPublisherOperation<T> set(String id, Object value);
+
+ @Override
+ public ParameterizedRowPublisherOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ public ParameterizedRowPublisherOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/PrimitiveOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,57 @@
+/*
+ * 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 PrimitiveOperation can be submitted, nothing more. Used only by
+ * {@link OperationGroup#catchOperation} and as a supertype to {@link Operation}.
+ *
+ * References in JavaDoc to the "collection of Operations" and "member
+ * Operations" should be understood to include PrimitiveOperations. The
+ * distinction between {@link Operation} and {@link PrimitiveOperation} in the
+ * API is strictly followed as it enables the compiler to catch a significant
+ * class of errors. The two types are not distinguished in the JavaDoc as making
+ * such a distinction would not add clarity.
+ *
+ * @see Operation
+ * @see OperationGroup#catchOperation
+ */
+public interface PrimitiveOperation<T> {
+
+ /**
+ * Add this {@link PrimitiveOperation} to the tail of the {@link Operation}
+ * collection of the {@link Session} that created this
+ * {@link PrimitiveOperation}. A {@link PrimitiveOperation} can be submitted
+ * only once. Once a {@link PrimitiveOperation} is submitted it is immutable.
+ * Any attempt to modify a submitted {@link PrimitiveOperation} will throw
+ * {@link IllegalStateException}.
+ *
+ * @return a {@link Submission} for this {@link PrimitiveOperation}
+ * @throws IllegalStateException if this method is called more than once on
+ * this {@link PrimitiveOperation}
+ */
+ Submission<T> submit();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Result.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 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;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+
+/**
+ *
+ */
+public interface Result {
+
+ /**
+ * A {@link Result} that is just a number of rows modified, a {@link Long}.
+ *
+ * Note: It is certainly true that this is not needed; {@link Long} could be
+ * used instead. Seems like there might be a documentational advantage to
+ * having this type. If you don't like it, just mentally replace it with
+ * {@link Long} everywhere it appears.
+ */
+ public static interface RowCount extends Result {
+
+ /**
+ *
+ * @return
+ */
+ public long getCount();
+ }
+
+ /**
+ * A mutable handle to one value of an ordered sequence of columns of a row or
+ * of out parameters. Columns have a 1-based index and optionally an
+ * identifier. Identifiers are not guaranteed to be unique. Only {@code clone}
+ * and {@code slice} create new instances. All other methods return this
+ * instance (modifying it if necessary) including {@code forEach},
+ * {@code next}, and {@code iterator}.
+ */
+ public interface Column extends Result, Iterable<Column>, Iterator<Column>, Cloneable {
+
+ /**
+ * Return the value of this column as an instance of the given type.
+ *
+ * @param <T>
+ * @param type
+ * @return the value of this {@link Column}
+ */
+ public <T> T get(Class<T> type);
+
+ /**
+ * Return the value of this {@link Column} as an instance of the default
+ * Java type for this column.
+ *
+ * @param <T>
+ * @return the value of this {@link Column}
+ */
+ public default <T> T get() {
+ return get(javaType());
+ }
+
+ /**
+ * Return the identifier of this {@link Column}. May be null.
+ *
+ * @return the identifier of this {@link Column}. May be null
+ */
+ public String identifier();
+
+ /**
+ * Return the 1-based index of this {@link Column}. The returned value is
+ * relative to the slice if this {@link Column} is the result of a call to
+ * {@code slice()}. {@code
+ * col.slice(n).index() == 1}.
+ *
+ * @return the index of this {@link Column}
+ */
+ public int index();
+
+ /**
+ * Return the 1-based index of this {@link Column} relative to the original
+ * sequence of values.
+ * {@code col.absoluteIndex() == col.slice(n).absoluteIndex()}.
+ *
+ * @return the absolute 1-based index of this {@link Column}
+ */
+ public int absoluteIndex();
+
+ /**
+ * Return the SQL type of the value of this {@link Column}.
+ *
+ * @return the SQL type of this value
+ */
+ public SqlType sqlType();
+
+ /**
+ * Return the Java type that best represents the value of this
+ * {@link Column}.
+ *
+ * @param <T>
+ * @return a {@link Class} that best represents the value of this
+ * {@link Column}
+ */
+ public <T>Class<T> javaType();
+
+ /**
+ * The length of the current value if defined.
+ *
+ * @return
+ * @throws UnsupportedOperationException if the length of the current value
+ * is undefined
+ */
+ public long length();
+
+ /**
+ * Return the number of remaining values accessible by this {@link Column}
+ * excluding the current value. This is the number of times {@code next()}
+ * can be called before {@code hasNext()} returns false.
+ *
+ * @return the number of values remaining
+ */
+ public int numberOfValuesRemaining();
+
+ /**
+ * Modify this {@link Column} to point to a value identified by id.
+ *
+ * @apiNote The value specified for {@code id} represents the name of a
+ * column or parameter marker for the underlying data source and is
+ * implementation specific. This may be a simple SQL identifier, a quoted
+ * identifier, or any other type of identifier supported by the data source.
+ * <p>
+ * Consult your implementation's documentation for additional
+ * information.
+ *
+ * @param id an identifier. Not null
+ * @return this {@link Column}
+ * @throws NoSuchElementException if id does not identify exactly one value
+ */
+ public Column at(String id);
+
+ /**
+ * Modify this {@link Column} to point to the value at {@code index}. The
+ * first value is at index 1. Negative numbers count back from the last
+ * value. The last value is at index -1.
+ *
+ * @param index a new index
+ * @return this {@link Column}
+ * @throws NoSuchElementException if {@code index > length} or
+ * {@code index < -length}
+ */
+ public Column at(int index);
+
+ /**
+ * Modify this {@link Column} to point to the value at the current index +
+ * {@code offset}. If {@code offset} is 0 this is a noop. If {@code offset}
+ * is negative the new index is less than the current index. If the new
+ * index would be less than 1 or greater than length this {@link Column} is
+ * not modified and {@link IllegalArgumentException} is thrown.
+ *
+ * @param offset an increment to the current index
+ * @return this {@link Column}
+ * @throws NoSuchElementException if the new index would be less than 1 or
+ * greater than {@code length}
+ */
+ public default Column next(int offset) {
+ int newIndex = index() + offset;
+ if (offset > numberOfValuesRemaining() || newIndex < 1) {
+ throw new NoSuchElementException();
+ }
+ return at(newIndex);
+ }
+
+ /**
+ * Return a new {@link Column} that is a handle to a subsequence of the
+ * sequence of values referenced by this {@link Column}. The subsequence
+ * consists of {@code numValues} number of values. If {@code numValues} is
+ * positive the values are the value of this column and its successors. If
+ * {@code numValues} is negative the values are the predecessors of this
+ * column not including this {@link Column}. The order of the values of the
+ * new {@link Column} is the same as the order of the values of this
+ * {@link Column}. The returned {@link Column} points to the first value of
+ * the slice. This {@link Column} is not modified.
+ *
+ * @param numValues the number of columns to include in the slice
+ * @return a new {@link Column}.
+ * @throws NoSuchElementException if the current index plus
+ * {@code numValues} is greater than the number of values of this
+ * {@link Column} or less than 1
+ */
+ public Column slice(int numValues);
+
+ /**
+ * Return a new {@link Column} that is a duplicate of this {@link Column}.
+ * This {@link Column} is not modified.
+ *
+ * @return a new {@link Column}
+ */
+ public Column clone();
+
+ /**
+ * Modify this {@link Column} to point to the next value in the sequence.
+ *
+ * @return this {@link Column}
+ * @throws NoSuchElementException if the new index would be greater than
+ * {@code length}
+ */
+ @Override
+ public default Column next() {
+ return next(1);
+ }
+
+ @Override
+ public default boolean hasNext() {
+ return numberOfValuesRemaining() > 0;
+ }
+
+ @Override
+ public default void forEach(Consumer<? super Column> action) {
+ do {
+ action.accept(this);
+ if (!hasNext()) break;
+ next();
+ } while (true);
+ }
+
+ @Override
+ public default Column iterator() {
+ return this.clone();
+ }
+
+ /**
+ * TODO This almost certainly works correctly but it doesn't integrate well
+ * with the other access patterns. A better approach would be a Spliterator
+ * that overrides trySplit and creates new slices for each batch.
+ *
+ * There is a fundamental problem with mixing Spliterator with the other
+ * access patterns. The other patterns assume navigation from one column to
+ * an arbitrary other column. Spliterator.trySplit can divide the column
+ * sequence in arbitrary places invalidating the assumption about column
+ * navigation.
+ *
+ * @return a {@link java.util.Spliterator}
+ */
+ @Override
+ public default Spliterator<Column> spliterator() {
+ List list = new ArrayList<>(numberOfValuesRemaining());
+ this.clone().forEach(c -> list.add(c.slice(1)));
+ return java.util.Spliterators.spliterator(list.toArray(), numberOfValuesRemaining());
+ }
+ }
+
+ /**
+ * Used by {@link OutOperation} to expose the out parameters of a stored
+ * procedure call.
+ *
+ * This exists to allow for future additions.
+ */
+ public interface OutColumn extends Column {
+
+ }
+
+ /**
+ * Used by {@link RowOperation} to expose each row of a row sequence.
+ */
+ public static interface RowColumn extends Column {
+
+ /**
+ * The count of rows in the row sequence preceeding this {@link RowColumn}.
+ * For the first row in the row sequence the {@code rowNumber} is 0.
+ *
+ * @return the count of rows in the row sequence preceeding this
+ * {@link RowColumn}
+ * @throws IllegalStateException if the call that was passed this
+ * {@link Result} has ended
+ */
+ public long rowNumber();
+
+ /**
+ * Terminate processing of the rows in this {@link RowOperation}. No further
+ * rows in the row sequence will be processed. All subsequent rows, if any,
+ * will be ignored. Any rows already fetched will not be processed. Any rows
+ * not yet fetched may or may not be fetched. If fetched they will not be
+ * processed. The RowOperation will be completed normally, as though the
+ * current row were the last row of the row sequence.
+ *
+ * @throws IllegalStateException if the call that was passed this
+ * {@link RowColumn} has ended
+ */
+ public void cancel();
+
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/RowCountOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * An {@link Operation} that returns a count.
+ *
+ * @param <T> the type of the result of the {@link Operation}
+ * @see ParameterizedCountOperation
+ */
+public interface RowCountOperation<T> extends Operation<T> {
+
+ /**
+ * Sets the result processor for this {@link Operation}.
+ *
+ * @param function processes the count produced by executing this
+ * {@link Operation} and returns the result
+ * @return this {@link RowCountOperation}
+ * @throws IllegalStateException if this method has been called previously
+ */
+ public RowCountOperation<T> apply(Function<Result.RowCount, ? extends T> function);
+
+ @Override
+ public RowCountOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ public RowCountOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/RowOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Collector;
+
+/**
+ * A {@link RowOperation} is a database operation that returns a row sequence.
+ *
+ * @param <T> the type of the result of this {@link Operation}
+ */
+public interface RowOperation<T> extends Operation<T> {
+
+ /**
+ * A hint to the implementation of how many rows to fetch in each database
+ * access. Implementations are free to ignore it.
+ *
+ * @param rows suggested number of rows to fetch per access
+ * @return this {@link RowOperation}
+ * @throws IllegalArgumentException if row < 1
+ * @throws IllegalStateException if this method had been called previously or
+ * this Operation has been submitted.
+ */
+ public RowOperation<T> fetchSize(long rows) throws IllegalArgumentException;
+
+ /**
+ * Provides a {@link Collector} to reduce the sequence of rows.The result of
+ * the {@link Operation} is the result of calling finisher on the final
+ * accumulated result. If the {@link Collector} is
+ * {@link Collector.Characteristics#UNORDERED} rows may be accumulated out of
+ * order. If the {@link Collector} is
+ * {@link Collector.Characteristics#CONCURRENT} then the sequence of rows may be
+ * split into subsequences that are reduced separately and then combined.
+ *
+ * @param <A> the type of the accumulator
+ * @param <S> the type of the final result
+ * @param c the Collector. Not null.
+ * @return This RowOperation
+ * @throws IllegalStateException if this method had been called previously or
+ * this Operation has been submitted.
+ */
+ public <A, S extends T> RowOperation<T> collect(Collector<? super Result.RowColumn, A, S> c);
+
+ /**
+ * Convenience method to collect the rows when the accumulated result is the
+ * final result.
+ *
+ * @param <S> the type of the accumulated result
+ * @param supplier supplies the accumulated result
+ * @param accumulator accumulates each RowColumn into the accumulated result
+ * @return this RowOperation
+ */
+ public default <S extends T> RowOperation<T> collect(Supplier<S> supplier,
+ BiConsumer<S, Result.RowColumn> accumulator) {
+ return collect(Collector.of(supplier, accumulator, (l, r) -> l));
+ }
+
+ @Override
+ public RowOperation<T> onError(Consumer<Throwable> handler);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/RowPublisherOperation.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,33 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package jdk.incubator.sql2;
+
+import java.time.Duration;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.Flow;
+import java.util.function.Consumer;
+
+public interface RowPublisherOperation<T> extends Operation<T> {
+
+ /**
+ * * DRAFT Subscribe to the stream of Rows returned by this Operation. The
+ * result of this Operation is the value of the {@code result} parameter.
+ *
+ * @param subscriber Not null.
+ * @param result Not null.
+ * @return this RowPublisherOperation
+ */
+ public RowPublisherOperation<T> subscribe(Flow.Subscriber<? super Result.RowColumn> subscriber,
+ CompletionStage<? extends T> result);
+ // Covariant overrides
+
+ @Override
+ public RowPublisherOperation<T> onError(Consumer<Throwable> handler);
+
+ @Override
+ public RowPublisherOperation<T> timeout(Duration minTime);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Session.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,618 @@
+/*
+ * 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;
+
+import java.time.Duration;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+/**
+ * A {@link Session} is an abstraction of a SQL database and
+ * a group of {@link Operation}s to be executed by that SQL database. No method
+ * on {@link Session} or any of its dependent objects ({@link RowOperation}
+ * etc) blocks. Any method that might block must execute any potentially blocking
+ * action in a thread other than the calling thread.
+ *
+ * <p>
+ * A {@link Session} is independent of any particular data source. Any data
+ * source that meets the specifications set by the {@link Session.Builder} can
+ * be used to execute the {@link Operation}s submitted to the {@link Session].
+ * An application is expected to create, use, and close {@link Session}s as
+ * needed. An application should hold a {@link Session} only when required by
+ * data source semantics. An implementation should cache and reused data source
+ * resources as appropriate. {@link Session}s should not be cached.
+ *
+ * <p>
+ * An implementation of this type must be thread safe as result and error
+ * handlers running asynchronously may be accessing a {@link Session} in
+ * parallel with each other and with a user thread. {@link Session}s are not
+ * required to support multiplexed use; a single {@link Session} should be
+ * used for only one unit of work at a time. Executing independent units of work
+ * on a single {@link Session} in parallel will most likely lead to
+ * unpredictable outcomes. As a rule of thumb only one user thread should access
+ * a {@link Session} at a time. Such a user thread should execute a complete
+ * unit of work before another user thread accesses the {@link Session}. An
+ * implementation may support parallel multiplexed use, but it is not required.</p>
+ *
+ * <p>
+ * All methods inherited from OperationGroup throw IllegalStateException if the
+ * the {@link Session} is not active.</p>
+ */
+public interface Session extends AutoCloseable, OperationGroup<Object, Object> {
+
+ /**
+ * Identifies the operational state of a {@link Session}.
+ */
+ public enum Lifecycle {
+ /**
+ * unattached. When a attach {@link Operation} is completed successfully
+ * -> {@link OPEN}. If {@link deactivate} is called ->
+ * {@link NEW_INACTIVE}. If {@link abort} is called -> {@link ABORTING}.
+ * No {@link Operation}s other than attach and close will be performed. A
+ Session in this state is both 'open' and 'active'.
+ */
+ NEW,
+ /**
+ * Unattached and inactive. Any queued attach or close {@link Operation}
+ * is performed. No work can be submitted. If the {@link activate} method is
+ * called -> {@link NEW}. If a attach {@link Operation} completes ->
+ * {@link INACTIVE}. If a close {@link Operation} is executed ->
+ * {@link CLOSING}. If {@link abort} is called -> {@link ABORTING}. A
+ Session in this state is 'open'.
+ */
+ NEW_INACTIVE,
+ /**
+ * fully operational. Work is queued and performed. If {@link deactivate} is
+ * called -> {@link INACTIVE}. If a close {@link Operation} is executed
+ * -> {@link CLOSING}. If {@link abort} is called -> {@link ABORTING}.
+ A Session in this state is both 'open' and 'active'.
+ */
+ OPEN,
+ /**
+ * Not available for new work. Queued work is performed. No work can be
+ * submitted. If the {@link activate} method is called -> {@link OPEN}.
+ * If a close {@link Operation} is executed -> {@link CLOSING}. If
+ * {@link abort} is called -> {@link ABORTING}. A {@link Session} in
+ * this state is 'open'.
+ */
+ INACTIVE,
+ /**
+ * Work in progress is completed but no additional work is started or
+ * queued. Attempting to queue work throws {@link IllegalStateException}.
+ * When the currently executing {@link Operation}s are completed ->
+ * {@link CLOSED}. All other queued Operations are completed exceptionally
+ with SqlSkippedException. A Session in this state is 'closed'.
+ */
+ CLOSING,
+ /**
+ * Work is neither queued nor performed. The currently executing
+ * {@link Operation}s, if any, are terminated, exceptionally if necessary.
+ * Any queued {@link Operation}s are terminated exceptionally with
+ * {@link SqlSkippedException}. Attempting to queue work throws
+ * {@link IllegalStateException}. When the queue is empty -<
+ * {@link CLOSED}. A Session in this state is 'closed'.
+ */
+ ABORTING,
+ /**
+ * Work is neither queued nor performed. Attempting to queue work throws
+ * {@link IllegalStateException}. A Session in this state is 'closed'.
+ */
+ CLOSED;
+
+ static {
+ NEW.init(true, true, NEW, NEW_INACTIVE, OPEN, ABORTING, CLOSING, CLOSED);
+ NEW_INACTIVE.init(true, false, NEW, NEW_INACTIVE, INACTIVE, ABORTING, CLOSING, CLOSED);
+ OPEN.init(true, true, OPEN, INACTIVE, OPEN, ABORTING, CLOSING, CLOSED);
+ INACTIVE.init(true, false, OPEN, INACTIVE, INACTIVE, ABORTING, INACTIVE, INACTIVE);
+ CLOSING.init(false, true, CLOSING, CLOSING, CLOSING, ABORTING, CLOSING, CLOSED);
+ ABORTING.init(false, true, ABORTING, ABORTING, ABORTING, ABORTING, ABORTING, CLOSED);
+ CLOSED.init(false, true, CLOSED, CLOSED, CLOSED, CLOSED, CLOSED, CLOSED);
+ }
+
+ private boolean isOpen;
+ private boolean isActive;
+ private Lifecycle onActivate;
+ private Lifecycle onDeactivate;
+ private Lifecycle onAttach;
+ private Lifecycle onAbort;
+ private Lifecycle onClose;
+ private Lifecycle onClosed;
+
+ private void init(boolean io, boolean ia, Lifecycle ac, Lifecycle da, Lifecycle cn, Lifecycle ab, Lifecycle cl, Lifecycle cd) {
+ isOpen = io;
+ isActive = ia;
+ onActivate = ac;
+ onDeactivate = da;
+ onAttach = cn;
+ onAbort = ab;
+ onClose = cl;
+ onClosed = cd;
+ }
+ public boolean isOpen() {
+ return isOpen;
+ }
+
+ public boolean isActive() {
+ return isActive;
+ }
+
+ public Lifecycle activate() {
+ return onActivate;
+ }
+
+ public Lifecycle deactivate() {
+ return onDeactivate;
+ }
+
+ public Lifecycle attach() {
+ return onAttach;
+ }
+
+ public Lifecycle abort() {
+ return onAbort;
+ }
+
+ public Lifecycle close() {
+ return onClose;
+ }
+
+ public Lifecycle closed() {
+ return onClosed;
+ }
+
+ }
+
+ /**
+ * Specifiers for how much effort to put into validating a {@link Session}.
+ * The amount of effort put into checking should be non-decreasing from NONE
+ * (least effort) to COMPLETE (most effort). Exactly what is checked is
+ * implementation dependent. For example, a memory resident database driver
+ * might implement SOCKET and NETWORK to be the same as LOCAL. SERVER might
+ * verify that a database manager thread is running and COMPLETE might trigger
+ * the database manager thread to run a deadlock detection algorithm.
+ */
+ public enum Validation {
+ /**
+ * isValid fails only if the {@link Session} is closed.
+ */
+ NONE,
+ /**
+ * {@link NONE} plus check local resources
+ */
+ LOCAL,
+ /**
+ * {@link LOCAL} plus the server isn't obviously unreachable (dead socket)
+ */
+ SOCKET,
+ /**
+ * {@link SOCKET} plus the network is intact (network PING)
+ */
+ NETWORK,
+ /**
+ * {@link NETWORK} plus significant server processes are running
+ */
+ SERVER,
+ /**
+ * everything that can be checked is working. At least {@link SERVER}.
+ */
+ COMPLETE;
+ }
+
+ /**
+ * A Listener that is notified of changes in a Session's lifecycle.
+ */
+ public interface SessionLifecycleListener extends java.util.EventListener {
+
+ /**
+ * If this {@link java.util.EventListener} is registered with a
+ * {@link Session} this method is called whenever that
+ * {@link Session}'s lifecycle changes. Note that the lifecycle may have
+ * changed again by the time this method is called so the
+ * {@link Session}'s current lifecycle may be different from the value of
+ * {@code current}.
+ *
+ * @param session the {@link Session}
+ * @param previous the previous value of the lifecycle
+ * @param current the new value of the lifecycle
+ */
+ public void lifecycleEvent(Session session, Lifecycle previous, Lifecycle current);
+ }
+
+ /**
+ * A {@link Session} builder. A {@link Session} is initially in the
+ * {@link Session.Lifecycle#NEW} lifecycle state. It transitions to the
+ * {@link Session.Lifecycle#OPEN} lifecycle state when fully initialized or
+ * to {@link Session.Lifecycle#CLOSED} if initialization fails.
+ *
+ */
+ public interface Builder {
+
+ /**
+ * Specify a property and its value for the built {@link Session}.
+ *
+ * @param p {@link SessionProperty} to set. Not {@code null}.
+ * @param v value for the property
+ * @return this {@link Builder}
+ * @throws IllegalArgumentException if {@code p.validate(v)} does not return
+ * true, if this method has already been called with the property
+ * {@code p}, or the implementation does not support the {@link SessionProperty}.
+ */
+ public Builder property(SessionProperty p, Object v);
+
+ /**
+ * Return a {@link Session} with the attributes specified. Note that the
+ * {@link Session} may not be attached to a server. Call one of the
+ * {@link attach} convenience methods to attach the {@link Session} to
+ * a server. The lifecycle of the new {@link Session} is
+ * {@link Lifecycle#NEW}.
+
+ This method cannot block. If the DataSource is unable to support a new
+ Session when this method is called, this method throws SqlException.
+ Note that the implementation does not have to allocate scarce resources to
+ the new {@link Session} when this method is called so limiting the
+ * number of {@link Session}s is not required to limit the use of
+ * scarce resources. It may be appropriate to limit the number of
+ * {@link Session}s for other reasons, but that is implementation dependent.
+ *
+ * @return a {@link Session}
+ * @throws IllegalStateException if this method has already been called or
+ if the implementation cannot create a Session with the specified
+ {@link SessionProperty}s.
+ * @throws IllegalStateException if the {@link DataSource} that created this
+ * {@link Builder} is closed
+ * @throws SqlException if creating a {@link Session} would exceed some
+ * limit
+ */
+ public Session build();
+ }
+
+ /**
+ * Returns an {@link Operation} that attaches this {@link Session} to a
+ * data source. If the Operation completes successfully and the lifecycle is
+ * {@link Lifecycle#NEW} -> {@link Lifecycle#OPEN}. If lifecycle is
+ * {@link Lifecycle#NEW_INACTIVE} -> {@link Lifecycle#INACTIVE}. If the
+ * {@link Operation} completes exceptionally the lifecycle ->
+ * {@link Lifecycle#CLOSED}. The lifecycle must be {@link Lifecycle#NEW} or
+ * {@link Lifecycle#NEW_INACTIVE} when the {@link Operation} is executed.
+ * Otherwise the {@link Operation} will complete exceptionally with
+ * {@link SqlException}.
+ *
+ * Note: It is highly recommended to use the {@link attach()} convenience
+ * method or to use {@link DataSource#getSession} which itself calls
+ * {@link attach()}. Unless there is a specific need, do not call this method
+ * directly.
+ *
+ * @return an {@link Operation} that attaches this {@link Session} to a
+ * server.
+ * @throws IllegalStateException if this {@link Session} is in a lifecycle
+ * state other than {@link Lifecycle#NEW}.
+ */
+ public Operation<Void> attachOperation();
+
+ /**
+ * Convenience method that supports the fluent style of the builder needed by
+ * try with resources.
+ *
+ * Note: A {@link Session} is an {@link OperationGroup} and so has some
+ * advanced features that most users do not need. Management of these features
+ * is encapsulated in this method and the corresponding {@link close()}
+ * convenience method. The vast majority of users should just use these
+ * methods and not worry about the advanced features. The convenience methods
+ * do the right thing for the overwhelming majority of use cases. A tiny
+ * number of users might want to take advantage of the advanced features that
+ * {@link OperationGroup} brings to {@link Session} and so would call
+ * {@link attachOperation} directly.
+ *
+ * @return this Session
+ * @throws IllegalStateException if this {@link Session} is in a lifecycle
+ * state other than {@link Lifecycle#NEW}.
+ */
+ public default Session attach() {
+ this.submitHoldingForMoreMembers();
+ this.attachOperation()
+ .submit();
+ return this;
+ }
+
+ /**
+ * Convenience method that supports the fluent style of the builder needed by
+ * try with resources.
+ *
+ * @param onError an Exception handler that is called if the attach
+ * {@link Operation} completes exceptionally.
+ * @return this {@link Session}
+ * @throws IllegalStateException if this {@link Session} is in a lifecycle
+ * state other than {@link Lifecycle#NEW}.
+ */
+ public default Session attach(Consumer<Throwable> onError) {
+ this.submitHoldingForMoreMembers();
+ this.attachOperation()
+ .submit()
+ .getCompletionStage()
+ .exceptionally(t -> { onError.accept(t); return null; } );
+ return this;
+ }
+
+ /**
+ * Returns an {@link Operation} that verifies that the resources are available
+ * and operational. Successful completion of that {@link Operation} implies
+ * that at some point between the beginning and end of the {@link Operation}
+ the Session was working properly to the extent specified by {@code depth}.
+ * There is no guarantee that the {@link Session} is still working after
+ * completion. If the {@link Session} is not valid the Operation completes
+ * exceptionally.
+ *
+ * @param depth how completely to check that resources are available and
+ * operational. Not {@code null}.
+ * @return an {@link Operation} that will validate this {@link Session}
+ * @throws IllegalStateException if this Session is not active
+ */
+ public Operation<Void> validationOperation(Validation depth);
+
+ /**
+ * Convenience method to validate a {@link Session}.
+ *
+ * @param depth how completely to check that resources are available and
+ * operational. Not {@code null}.
+ * @param minTime how long to wait. If 0, wait forever
+ * @param onError called if validation fails or times out. May be
+ * {@code null}.
+ * @return this {@link Session}
+ * @throws IllegalArgumentException if {@code milliseconds} < 0 or
+ * {@code depth} is {@code null}.
+ * @throws IllegalStateException if this Session is not active
+ */
+ public default Session validate(Validation depth,
+ Duration minTime,
+ Consumer<Throwable> onError) {
+ this.validationOperation(depth)
+ .timeout(minTime)
+ .onError(onError)
+ .submit();
+ return this;
+ }
+
+ /**
+ * Create an {@link Operation} to close this {@link Session}. When the
+ * {@link Operation} is executed, if this {@link Session} is open ->
+ * {@link Lifecycle#CLOSING}. If this {@link Session} is closed executing
+ * the returned {@link Operation} is a no-op. When the queue is empty and all
+ * resources released -> {@link Lifecycle#CLOSED}.
+ *
+ * A close {@link Operation} is never skipped. Even when the
+ * {@link Session} is dependent, the default, and an {@link Operation}
+ * completes exceptionally, a close {@link Operation} is still executed. If
+ * the {@link Session} is parallel, a close {@link Operation} is not
+ * executed so long as there are other {@link Operation}s or the
+ * {@link Session} is held for more {@link Operation}s.
+ *
+ * Note: It is highly recommended to use try with resources or the
+ * {@link close()} convenience method. Unless there is a specific need, do not
+ * call this method directly.
+ *
+ * @return an {@link Operation} that will close this {@link Session}.
+ * @throws IllegalStateException if the Session is not active
+ */
+ public Operation<Void> closeOperation();
+
+ /**
+ * Create and submit an {@link Operation} to close this {@link Session}.
+ * Convenience method.
+ *
+ * Note: A {@link Session} is an {@link OperationGroup} and so has some
+ * advanced features; that most users do not need. Management of these
+ * features is encapsulated in this method and the corresponding
+ * {@link attach()} convenience method. The vast majority of users should
+ * just use these methods and not worry about the advanced features. The
+ * convenience methods do the right thing for the overwhelming majority of use
+ * cases. A tiny number of user might want to take advantage of the advanced
+ * features that {@link OperationGroup} brings to {@link Session} and so
+ * would call {@link closeOperation} directly.
+ *
+ * @throws IllegalStateException if the Session is not active
+ */
+ @Override
+ public default void close() {
+ this.closeOperation()
+ .submit();
+ this.releaseProhibitingMoreMembers();
+ }
+
+ /**
+ * Create a new {@link OperationGroup} for this {@link Session}.
+ *
+ * @param <S> the result type of the member {@link Operation}s of the returned
+ * {@link OperationGroup}
+ * @param <T> the result type of the collected results of the member
+ * {@link Operation}s
+ * @return a new {@link OperationGroup}.
+ * @throws IllegalStateException if this Session is not active
+ */
+ public <S, T> OperationGroup<S, T> operationGroup();
+
+ /**
+ * 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 TransactionCompletion.
+
+ ISSUE: Should this be moved to OperationGroup?
+ *
+ * @return a new {@link TransactionCompletion}. Not null.
+ * @throws IllegalStateException if this Session is not active
+ */
+ 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.TransactionCompletion)}.
+ *
+ * @return this {@link OperationGroup}
+ * @see OperationGroup#commitMaybeRollback(jdk.incubator.sql2.TransactionCompletion)
+ */
+ public default CompletionStage<TransactionOutcome> rollback() {
+ TransactionCompletion t = transactionCompletion();
+ t.setRollbackOnly();
+ catchErrors();
+ return this.endTransactionOperation(t).submit().getCompletionStage();
+ }
+
+ /**
+ * Register a listener that will be called whenever there is a change in the
+ * lifecycle of this {@link Session}.If the listener is already registered
+ this is a no-op. ISSUE: Should lifecycleListener be a SessionProperty so that it is
+ always reestablished on Session.activate?
+ *
+ * @param listener Not {@code null}.
+ * @return this Session
+ * @throws IllegalStateException if this Session is not active
+ */
+ public Session registerLifecycleListener(SessionLifecycleListener listener);
+
+ /**
+ * Removes a listener that was registered by calling
+ * registerLifecycleListener.Sometime after this method is called the listener
+ * will stop receiving lifecycle events. If the listener is not registered,
+ * this is a no-op.
+ *
+ * @param listener Not {@code null}.
+ * @return this Session
+ * @throws IllegalStateException if this Session is not active
+ */
+ public Session deregisterLifecycleListener(SessionLifecycleListener listener);
+
+ /**
+ * Return the current lifecycle of this {@link Session}.
+ *
+ * @return the current lifecycle of this {@link Session}.
+ */
+ public Lifecycle getSessionLifecycle();
+
+ /**
+ * Terminate this {@link Session}. If lifecycle is
+ * {@link Lifecycle#NEW}, {@link Lifecycle#OPEN}, {@link Lifecycle#INACTIVE}
+ * or {@link Lifecycle#CLOSING} -> {@link Lifecycle#ABORTING} If lifecycle
+ * is {@link Lifecycle#ABORTING} or {@link Lifecycle#CLOSED} this is a no-op.
+ * If an {@link Operation} is currently executing, terminate it immediately.
+ * Remove all remaining {@link Operation}s from the queue. {@link Operation}s
+ * are not skipped. They are just removed from the queue.
+ *
+ * @return this {@link Session}
+ */
+ public Session abort();
+
+ /**
+ * Return the set of properties configured on this {@link Session}
+ * excepting any sensitive properties. Neither the key nor the value for
+ * sensitive properties are included in the result. Properties (other than
+ * sensitive properties) that have default values are included even when not
+ * explicitly set. Properties that have no default value and are not set
+ * explicitly are not included.
+ *
+ * @return a {@link Map} of property, value. Not modifiable. May be retained.
+ * Not {@code null}.
+ * @throws IllegalStateException if this Session is not active
+ */
+ public Map<SessionProperty, Object> getProperties();
+
+ /**
+ *
+ * @return a {@link ShardingKey.Builder} for this {@link Session}
+ * @throws IllegalStateException if this Session is not active
+ */
+ public ShardingKey.Builder shardingKeyBuilder();
+
+ /**
+ * Provide a method that this {@link Session} will call to control the rate
+ * of {@link Operation} submission. This {@link Session} will call
+ * {@code request} with a positive argument when the {@link Session} is
+ * able to accept more {@link Operation} submissions. The difference between
+ * the sum of all arguments passed to {@code request} and the number of
+ * {@link Operation}s submitted after this method is called is the
+ * <i>demand</i>. The demand must always be non-negative. If an
+ * {@link Operation} is submitted that would make the demand negative the call
+ * to {@link Operation#submit} throws {@link IllegalStateException}. Prior to
+ * a call to {@code requestHook}, the demand is defined to be infinite.
+ * After a call to {@code requestHook}, the demand is defined to be
+ * zero and is subsequently computed as described previously.
+ * {@link Operation}s submitted prior to the call to {@code requestHook} do
+ * not affect the demand.
+ *
+ * @param request accepts calls to increase the demand. Not null.
+ * @return this {@link Session}
+ * @throws IllegalStateException if this method has been called previously or
+ * this {@link Session} is not active.
+ */
+ public Session requestHook(LongConsumer request);
+
+ /**
+ * Make this {@link Session} ready for use. A newly created
+ * {@link Session} is active. Calling this method on a {@link Session}
+ * that is active is a no-op. If the lifecycle is {@link Lifecycle#INACTIVE}
+ * -> {@link Lifecycle#OPEN}. If the lifecycle is
+ * {@link Lifecycle#NEW_INACTIVE} -> {@link Lifecycle#NEW}.
+ *
+ * @return this {@link Session}
+ * @throws IllegalStateException if this {@link Session} is closed.
+ */
+ public Session activate();
+
+ /**
+ * Makes this {@link Session} inactive. After a call to this method
+ * previously submitted Operations will be executed normally. If the lifecycle
+ * is {@link Lifecycle#NEW} -> {@link Lifecycle#NEW_INACTIVE}. if the
+ * lifecycle is {@link Lifecycle#OPEN} -> {@link Lifecycle#INACTIVE}. If
+ * the lifecycle is {@link Lifecycle#INACTIVE} or
+ * {@link Lifecycle#NEW_INACTIVE} this method is a no-op. After calling this
+ * method or calling any method other than {@link deactivate}, {@link activate},
+ * {@link abort}, or {@link getSessionLifecycle} will throw
+ * {@link IllegalStateException}. Data source state not specified
+ * by {@link Session.Builder} may not be preserved.
+ *
+ * <p>
+ * In general {@link Session}s should not be pooled as the implementation
+ * should cache and reuse the data source resources that back {@link Session}s
+ * as appropriate, not cache the {@link Session}s themselves.
+ * However, any {@link Session} pool is required by default to
+ * call {@code deactivate} when putting a {@link Session} into the pool. The
+ * pool is required by default to call {@code activate} when removing a
+ * {@link Session} from the pool for use. A pool may have an optional mode where
+ * it does not call {@code deactivate}/{@code activate} as required above. The
+ * behavior of the pool and {@link Session}s cached in the pool in such a
+ * mode is entirely implementation dependent.</p>
+ *
+ * @return this {@link Session}
+ * @throws IllegalStateException if this {@link Session} is closed
+ */
+ public Session deactivate();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SessionProperty.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,112 @@
+/*
+ * 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;
+
+/**
+ * An attribute of a {@link Session} that can be configured to influence its
+ * behavior. Implementors of this interface define the properties of
+ * {@link Session}s. The {@link Session.Builder#property} method is used to set the values
+ * of {@link Session} properties.
+ *
+ * Implementations must be thread safe.
+ *
+ */
+public interface SessionProperty {
+
+ /**
+ * Return the name of this {@link SessionProperty}.
+ *
+ * @return the name of this {@link SessionProperty}
+ */
+ public String name();
+
+ /**
+ * Return the type of the value of this {@link SessionProperty}. Any value
+ * set for this property must be assignable to this type.
+ *
+ * @return the type of the values of this {@link SessionProperty}
+ */
+ public Class<?> range();
+
+ /**
+ * Determine whether a value is valid for this {@link SessionProperty}. Returns
+ * {@code true} if {@code value} is valid and {@code false} otherwise.
+ *
+ * @param value a value for this {@link SessionProperty}
+ * @return {@code true} iff {@code value} is valid for this {@link SessionProperty}
+ */
+ public default boolean validate(Object value) {
+ return (value == null && this.range() == Void.class) || this.range().isInstance(value);
+ }
+
+ /**
+ * Return the value for this property to use if no other value is set. For
+ * this to have any meaning for a user defined property the property must be
+ * registered with the {@link DataSource} by calling
+ * {@link DataSource.Builder#registerSessionProperty}.
+ *
+ * @return the default value or {@code null} if there is no default value
+ */
+ public Object defaultValue();
+
+ /**
+ * Returns true if this {@link SessionProperty} is contains sensitive information
+ * such as a password or encryption key.
+ *
+ * @return true iff this is sensitive
+ */
+ public boolean isSensitive();
+
+ /**
+ * 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 false} and rely on the
+ * implementation to do the right thing.
+ *
+ * @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 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}
+ */
+ public default boolean configureOperation(OperationGroup<?, ?> group, Object value) {
+ if (validate(value)) {
+ return false;
+ }
+ else {
+ throw new IllegalArgumentException(value.toString() + " is invalid");
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/ShardingKey.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,116 @@
+/*
+ * 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;
+
+/**
+ * Interface used to indicate that this object represents a Sharding Key. A
+ * {@link ShardingKey} instance is only guaranteed to be compatible with the
+ * data source instance that it was derived from. A {@link ShardingKey} is
+ * created using {@link Builder}.
+ * <p>
+ * The following example illustrates the use of {@link Builder} to create a
+ * {@link ShardingKey}:
+ * <pre>
+ * {@code
+ *
+ * DataSource ds = new MyDataSource();
+ * ShardingKey shardingKey = ds.createShardingKeyBuilder()
+ * .subkey("abc", JDBCType.VARCHAR)
+ * .subkey(94002, JDBCType.INTEGER)
+ * .build();
+ * }
+ * </pre>
+ * <p>
+ *
+ * A {@link ShardingKey} is used for specifying a
+ * {@link AdbaSessionProperty#SHARDING_KEY} or a
+ * {@link AdbaSessionProperty#SHARDING_GROUP_KEY}. Databases that support
+ * composite Sharding may use a * to specify a additional level of partitioning
+ * within to specify a additional level of partitioning within the Shard.
+ * <p>
+ * The following example illustrates the use of {@link Builder} to create a
+ * {@link AdbaSessionProperty#SHARDING_GROUP_KEY} for an eastern region with
+ * a {@link AdbaSessionProperty#SHARDING_KEY} specified for the Pittsburgh
+ * branch office:
+ * <pre>
+ * {@code
+ *
+ * DataSource ds = new MyDataSource();
+ * ShardingKey superShardingKey = ds.shardingKeyBuilder()
+ * .subkey("EASTERN_REGION", JDBCType.VARCHAR)
+ * .build();
+ * ShardingKey shardingKey = ds.shardingKeyBuilder()
+ * .subkey("PITTSBURGH_BRANCH", JDBCType.VARCHAR)
+ * .build();
+ * Session con = ds.builder()
+ * .property(SHARDING_GROUP_KEY, superShardingKey)
+ * .property(SHARDING_KEY, shardingKey)
+ * .build();
+ * }
+ * </pre>
+ */
+public interface ShardingKey {
+
+ /**
+ * A builder created from a {@link DataSource} or object, used to create a
+ * {@link ShardingKey} with sub-keys of supported data types. Implementations
+ * must support JDBCType.VARCHAR and may also support additional data types.
+ * <p>
+ * The following example illustrates the use of {@link Builder} to create a
+ * {@link ShardingKey}:
+ * <pre>
+ * {@code
+ *
+ * DataSource ds = new MyDataSource();
+ * ShardingKey shardingKey = ds.createShardingKeyBuilder()
+ * .subkey("abc", JDBCType.VARCHAR)
+ * .subkey(94002, JDBCType.INTEGER)
+ * .build();
+ * }
+ * </pre>
+ */
+ public interface Builder {
+
+ /**
+ * This method will be called to add a subkey into a Sharding Key object
+ * being built. The order in which subkey method is called is important as
+ * it indicates the order of placement of the subkey within the Sharding
+ * Key.
+ *
+ * @param subkey contains the object that needs to be part of shard sub key
+ * @param subkeyType sub-key data type of type java.sql.SQLType
+ * @return this builder object
+ */
+ public Builder subkey(Object subkey, SqlType subkeyType);
+
+ /**
+ * Returns an instance of the object defined by this builder.
+ *
+ * @return The built object
+ */
+ public ShardingKey build();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlArray.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Identifies a type that represents an ARRAY SQL type.
+ * Any type to which this annotation is applied must either extend or implement
+ * java.util.List. Additionally the type must have at least one of the following:
+ * <ul>
+ * <li>a public zero-arg constructor</li>
+ * <li>a public constructor Constructor(int initialCapacity)</li>
+ * <li>a public constructor Constructor(<? super List<?>>)</li>
+ * <li>a public static factory method of(<? super List<?>>)</li>
+ * </ul>
+ * If more than one of the above is supported it is implementation dependent which
+ * is used.
+ *
+ *
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface SqlArray {
+ public String elementSqlTypeName();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlBlob.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,255 @@
+/*
+ * 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;
+
+import java.nio.channels.AsynchronousByteChannel;
+import java.util.concurrent.CompletionStage;
+
+/**
+ * A reference to a BINARY LARGE OBJECT in the attached database.
+ *
+ */
+public interface SqlBlob extends AutoCloseable {
+
+ /**
+ * Return an {@link Operation} that will release the temporary resources
+ * associated with this {@link SqlBlob}.
+ *
+ * @return an {@link Operation} that will release the temporary resources
+ * associated with this {@link SqlBlob}.
+ */
+ public Operation<Void> closeOperation();
+
+ @Override
+ public default void close() {
+ this.closeOperation().submit();
+ }
+
+ /**
+ * Return a {@link Operation} that fetches the position of this {@link SqlBlob}.
+ * The position is 1-based. Position 0 is immediately before the first byte in
+ * the {@link SqlBlob}. Position 1 is the first byte in the {@link SqlBlob}, etc.
+ * Position {@link length()} is the last byte in the {@link SqlBlob}.
+ *
+ * Position is between 0 and length + 1.
+ *
+ * @return a {@link Operation} that returns the position of this {@link SqlBlob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public Operation<Long> getPositionOperation();
+
+ /**
+ * Get the position of this {@link SqlBlob}. The position is 1-based. Position 0
+ * is immediately before the first byte in the {@link SqlBlob}. Position 1 is the
+ * first byte in the {@link SqlBlob}, etc. Position {@link length()} is the last
+ * byte in the {@link SqlBlob}.
+ *
+ * Position is between 0 and length + 1.
+ *
+ * ISSUE: Should position be 1-based as SQL seems to do or 0-based as Java
+ * does?
+ *
+ * @return a future which value is the 1-based position of this {@link SqlBlob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public default CompletionStage<Long> getPosition() {
+ return getPositionOperation().submit().getCompletionStage();
+ }
+
+ /**
+ * Return a {@link Operation} that fetches the length of this {@link SqlBlob}.
+ *
+ * @return a {@link Operation} that returns the length of this {@link SqlBlob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public Operation<Long> lengthOperation();
+
+ /**
+ * Get the length of this {@link SqlBlob}.
+ *
+ * @return a future which value is the number of bytes in this {@link SqlBlob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public default CompletionStage<Long> length() {
+ return lengthOperation().submit().getCompletionStage();
+ }
+
+ /**
+ * Return a {@link Operation} that sets the position of this {@link SqlBlob}. If
+ * offset exceeds the length of this {@link SqlBlob} set position to the length +
+ * 1 of this {@link SqlBlob}, ie one past the last byte.
+ *
+ * @param offset a non-negative number
+ * @return a {@link Operation} that sets the position of this {@link SqlBlob}
+ * @throws IllegalArgumentException if {@code offset} is less than 0
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public Operation<Long> setPositionOperation(long offset);
+
+ /**
+ * Set the position of this {@link SqlBlob}. If offset exceeds the length of this
+ * {@link SqlBlob} set position to the length + 1 of this {@link SqlBlob}, ie one
+ * past the last byte.
+ *
+ * @param offset the 1-based position to set
+ * @return this {@link SqlBlob}
+ * @throws IllegalArgumentException if offset is less than 0
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public default SqlBlob setPosition(long offset) {
+ setPositionOperation(offset).submit();
+ return this;
+ }
+
+ /**
+ * Return a {@link Operation} to set the position to the beginning of the next
+ * occurrence of the target after the position. If there is no such occurrence
+ * set the position to 0.
+ *
+ * @param target a {@link SqlBlob} created by the same {@link Session}
+ * containing the byte sequence to search for
+ * @return a {@link Operation} that locates {@code target} in this
+ * {@link SqlBlob}
+ * @throws IllegalArgumentException if {@code target} was created by some
+ * other {@link Session}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public Operation<Long> locateOperation(SqlBlob target);
+
+ /**
+ * Set the position to the beginning of the next occurrence of the target
+ * after the position. If there is no such occurrence set the position to 0.
+ *
+ * @param target the byte sequence to search for
+ * @return this {@link SqlBlob}
+ * @throws IllegalArgumentException if {@code target} was created by some
+ * other {@link Session}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed
+ */
+ public default SqlBlob locate(SqlBlob target) {
+ locateOperation(target).submit();
+ return this;
+ }
+
+ /**
+ * Return an {@link Operation} to set the position to the beginning of the
+ * next occurrence of the target after the position. If there is no such
+ * occurrence set the position to 0.
+ *
+ * @param target the byte sequence to search for. Not {@code null}. Captured.
+ * @return a {@link Operation} that locates {@code target} in this
+ * {@link SqlBlob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public Operation<Long> locateOperation(byte[] target);
+
+ /**
+ * Set the position to the beginning of the next occurrence of the target
+ * after the position. If there is no such occurrence set the position to 0.
+ *
+ * @param target the byte sequence to search for
+ * @return this {@link SqlBlob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public default SqlBlob locate(byte[] target) {
+ locateOperation(target).submit();
+ return this;
+ }
+
+ /**
+ * Return a {@link Operation} that truncates this {@link SqlBlob} so that the
+ * current position is the end of the {@link SqlBlob}. If the position is N, then
+ * after {@link trim()} the length is N - 1. The position is still N. This
+ * will fail if position is 0.
+ *
+ * @return a {@link Operation} that trims the length of this {@link SqlBlob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed or position is 0.
+ */
+ public Operation<Long> trimOperation();
+
+ /**
+ * Truncate this {@link SqlBlob} so that the current position is the end of the
+ * {@link SqlBlob}. If the position is N, then after {@link trim()} the length is
+ * N - 1. The position is still N. This will fail if position is 0.
+ *
+ * @return this SqlBlob
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed or position is 0.
+ */
+ public default SqlBlob trim() {
+ trimOperation().submit();
+ return this;
+ }
+
+ /**
+ * Return a {@link java.nio.channels.Channel} that can be used to read bytes from the
+ * {@link SqlBlob} beginning at the position. Reading bytes from the returned
+ * {@link java.nio.channels.Channel} advances the position.
+ *
+ * Each call to a read method that fetches bytes from the server creates and
+ * submits a virtual {@link Operation} to fetch those bytes. This virtual
+ * {@link Operation} is executed in sequence with other {@link Operation}s and
+ * may be skipped if an error occurs.
+ *
+ * @return a read-only byte {@link java.nio.channels.Channel} beginning at the position.
+ * @throws IllegalStateException if the {@link Session} that created this
+ SqlBlob is closed.
+ */
+ public AsynchronousByteChannel getReadChannel();
+
+ /**
+ * Return a {@link java.nio.channels.Channel} that can be used to write bytes
+ * to this {@link SqlBlob} beginning at the position. Bytes written overwrite
+ * bytes already in the {@link SqlBlob}. Writing bytes to the returned
+ * {@link java.nio.channels.Channel} advances the position.
+ *
+ * Each call to a write method that flushes bytes to the server creates and
+ * submits a virtual {@link Operation} to flush those bytes. This virtual
+ * {@link Operation} is executed in sequence with other {@link Operation}s and
+ * may be skipped if an error occurs.
+ *
+ * ISSUE: Can the app read bytes from a write
+ * {@link java.nio.channels.Channel}? If so then maybe remove
+ * {@link getReadChannel} and add a read-only flag to this method, renamed
+ * {@code getChannel}.
+ *
+ * @return a writable byte {@link java.nio.channels.Channel} beginning at the
+ * position.
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlBlob} is closed.
+ */
+ public AsynchronousByteChannel getWriteChannel();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlClob.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,245 @@
+/*
+ * 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;
+
+import java.io.Reader;
+import java.io.Writer;
+import java.util.concurrent.CompletionStage;
+
+/**
+ * A reference to a CHARACTER LARGE OBJECT in the attached database.
+ *
+ */
+public interface SqlClob extends AutoCloseable {
+
+ /**
+ * Return an {@link Operation} that will release the temporary resources
+ * associated with this {@link SqlClob}.
+ *
+ * @return an {@link Operation} that will release the temporary resources
+ * associated with this {@link SqlClob}.
+ */
+ public Operation<Void> closeOperation();
+
+ @Override
+ public default void close() {
+ this.closeOperation().submit();
+ }
+
+ /**
+ * Return a {@link Operation} that fetches the position of this {@link SqlClob}.
+ * Position 0 is immediately before the first char in the {@link SqlClob}.
+ * Position 1 is the first char in the {@link SqlClob}, etc. Position
+ * {@link length()} is the last char in the {@link SqlClob}.
+ *
+ * Position is between 0 and length + 1.
+ *
+ * @return an {@link Operation} that returns the position of this {@link SqlClob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.;
+ */
+ public Operation<Long> getPositionOperation();
+
+ /**
+ * Get the position of this {@link SqlClob}. Position 0 is immediately before the
+ * first char in the {@link SqlClob}. Position 1 is the first char in the
+ * {@link SqlClob}, etc. Position {@link length()} is the last char in the SqlClob.
+
+ Position is between 0 and length + 1.
+
+ ISSUE: Should position be 1-based as SQL seems to do or 0-based as Java
+ does?
+ *
+ * @return a future which value is the position of this {@link SqlClob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.
+ */
+ public default CompletionStage<Long> getPosition() {
+ return getPositionOperation().submit().getCompletionStage();
+ }
+
+ /**
+ * Return a {@link Operation} that fetches the length of this {@link SqlClob}.
+ *
+ * @return a {@link Operation} that returns the length of this {@link SqlClob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.
+ */
+ public Operation<Long> lengthOperation();
+
+ /**
+ * Get the length of this {@link SqlClob}.
+ *
+ * @return a {@link java.util.concurrent.Future} which value is the number of
+ * chars in this {@link SqlClob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.
+ */
+ public default CompletionStage<Long> length() {
+ return lengthOperation().submit().getCompletionStage();
+ }
+
+ /**
+ * Return an {@link Operation} that sets the position of this {@link SqlClob}. If
+ * {@code offset} exceeds the length of this {@link SqlClob} set position to the
+ * length + 1 of this {@link SqlClob}, ie one past the last char.
+ *
+ * @param offset a non-negative number
+ * @return a {@link Operation} that sets the position of this {@link SqlClob}
+ * @throws IllegalArgumentException if {@code offset} is less than 0
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.
+ */
+ public Operation<Long> setPositionOperation(long offset);
+
+ /**
+ * Set the position of this {@link SqlClob}. If {@code offset} exceeds the length
+ * of this {@link SqlClob} set position to the length + 1 of this {@link SqlClob},
+ * ie one past the last char.
+ *
+ * @param offset the 1-based position to set
+ * @return this {@link SqlClob}
+ * @throws IllegalArgumentException if {@code offset} is less than 0
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.
+ */
+ public default SqlClob setPosition(long offset) {
+ setPositionOperation(offset).submit();
+ return this;
+ }
+
+ /**
+ * Return an {@link Operation} to set the position to the beginning of the
+ * next occurrence of the target after the position. If there is no such
+ * occurrence set the position to 0.
+ *
+ * @param target a {@link SqlClob} created by the same {@link Session}
+ * containing the char sequence to search for
+ * @return an {@link Operation} that locates {@code target} in this
+ * {@link SqlClob}
+ * @throws IllegalArgumentException if {@code target} was created by some
+ * other {@link Session}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.
+ */
+ public Operation<Long> locateOperation(SqlClob target);
+
+ /**
+ * Set the position to the beginning of the next occurrence of the target
+ * after the position. If there is no such occurrence set the position to 0.
+ *
+ * @param target the char sequence to search for
+ * @return this {@link SqlClob}
+ * @throws IllegalArgumentException if {@code target} was created by some
+ * other {@link Session}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed
+ */
+ public default SqlClob locate(SqlClob target) {
+ locateOperation(target).submit();
+ return this;
+ }
+
+ /**
+ * Return an {@link Operation} to set the position to the beginning of the
+ * next occurrence of the target after the position. If there is no such
+ * occurrence set the position to 0.
+ *
+ * @param target the char sequence to search for. Not {@code null}. Captured.
+ * @return an {@link Operation} that locates {@code target} in this
+ * {@link SqlClob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.
+ */
+ public Operation<Long> locateOperation(CharSequence target);
+
+ /**
+ * Set the position to the beginning of the next occurrence of the target
+ * after the position. If there is no such occurrence set the position to 0.
+ *
+ * @param target the char sequence to search for
+ * @return this {@link SqlClob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed.
+ */
+ public default SqlClob locate(CharSequence target) {
+ locateOperation(target).submit();
+ return this;
+ }
+
+ /**
+ * Return an {@link Operation} that truncates this {@link SqlClob} so that the
+ * current position is the end of the {@link SqlClob}. If the position is N, then
+ * after trim() the length is N - 1. The position is still N. This will fail
+ * if position is 0.
+ *
+ * @return an {@link Operation} that trims the length of this {@link SqlClob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed or position is 0.
+ */
+ public Operation<Long> trimOperation();
+
+ /**
+ * Truncate this {@link SqlClob} so that the current position is the end of the
+ * {@link SqlClob}. If the position is N, then after {@link trim()} the length is
+ * N - 1. The position is still N. This will fail if position is 0.
+ *
+ * @return this {@link SqlClob}
+ * @throws IllegalStateException if the {@link Session} that created this
+ * {@link SqlClob} is closed or position is 0.
+ */
+ public default SqlClob trim() {
+ trimOperation().submit();
+ return this;
+ }
+
+ /**
+ * Returns a {@link Reader} for the characters in this {@link SqlClob}.
+ * Characters are read starting at the current position. Each character read
+ * advances the position by one.
+ *
+ * ISSUE: There is no character analog to
+ * {@link java.nio.channels.AsynchronousByteChannel}. It is trivial to
+ * construct a {@link java.io.Reader} from an
+ * {@link java.nio.channels.AsynchronousByteChannel} however.
+ *
+ * @return a Reader for the characters in this SqlClob
+ */
+ public Reader getReader();
+
+ /**
+ * Returns a Writer for this {@link SqlClob}. Characters are written starting at
+ * the current position. Each character written advances the position by one.
+ *
+ * ISSUE: There is no character analog to
+ * {@link java.nio.channels.AsynchronousByteChannel}. It is trivial to
+ * construct a {@link java.io.Writer} from an
+ * {@link java.nio.channels.AsynchronousByteChannel} however.
+ *
+ * @return a Writer for the characters of this SqlClob
+ */
+ public Writer getWriter();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlColumns.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+
+/**
+ * Identifies a constructor or static factory method that can be used to construct
+ * an instance of the containing type when the type is passed to {@link Result.ResultMap#get}.
+ * The method or constructor must be public.
+ *
+ * An instance of this type will be constructed by calling the factory method or
+ * constructor. Each element in the value of this annotation is used as a column
+ * identifier. The value of that column is passed to the corresponding parameter
+ * of the annotated method or constructor. The id argument to {@link Result.ResultMap#get} is
+ * prefixed to the column identifiers.
+ *
+ * The following pseudo-code describes how an instance is constructed.
+ *
+ * {@code
+ * <pre> int i = 0;
+ * String[] columns = methodOrConstructor.getAnnotation(SqlColumns.class).value();
+ * Object[] args = new Object[columns.length];
+ * for (String columnName : columns)
+ * args[i] = resultMap.get(prefix + columnName, parameterTypes[i++];
+ * instance = methodOrConstructor.invoke(null, args);</pre>}
+ *
+ */
+@Retention(RUNTIME)
+@Target({CONSTRUCTOR, METHOD})
+public @interface SqlColumns {
+
+ /**
+ * The column names corresponding to the parameters of the factory method or
+ * constructor to construct an instance of this type. There must be exactly one
+ * column name for each parameter of the annotated method or constructor.
+ *
+ * @return the column names in the order returned by the database
+ */
+ public String[] value();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlException.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,140 @@
+/*
+ * 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;
+
+/**
+ * <P>
+ * An exception that provides information on a database access error or other
+ * errors.
+ *
+ * <P>
+ * Each <code>SqlException</code> provides several kinds of information:
+ * <UL>
+ * <LI> a string describing the error. This is used as the Java Exception
+ * message, available via the method <code>getMesasge</code>.
+ * <LI> a "SQLstate" string, which follows either the XOPEN SQLstate conventions
+ * or the SQL:2003 conventions. The values of the SQLState string are described
+ * in the appropriate spec. The <code>DatabaseMetaData</code> method
+ * <code>getSQLStateType</code> can be used to discover whether the driver
+ * returns the XOPEN type or the SQL:2003 type.
+ * <LI> an integer error code that is specific to each vendor. Normally this
+ * will be the actual error code returned by the underlying database.
+ * <LI> the causal relationship, if any for this <code>SqlException</code>.
+ * <LI> the SQL string that was executing when the error occurred.
+ * <LI> the position in the SQL string where the error was detected.
+ * </UL>
+ */
+public class SqlException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ // Fields
+
+ /**
+ */
+ private final String sqlState;
+
+ /**
+ */
+ private final int vendorCode;
+
+ /**
+ * The SQL string that was sent to the database.
+ */
+ private final String sqlString;
+
+ /**
+ * The index of the first character in SQL where an error is detected. Zero
+ * based.
+ */
+ private final int position;
+
+ // Constructors
+
+ public SqlException(Throwable ex) {
+ super(ex);
+ this.sqlState = null;
+ this.vendorCode = -1;
+ this.sqlString = null;
+ this.position = -1;
+ }
+
+ /**
+ *
+ * @param message
+ * @param cause
+ * @param sqlState
+ * @param vendorCode
+ * @param sql
+ * @param position
+ */
+ public SqlException(String message, Throwable cause, String sqlState, int vendorCode, String sql, int position) {
+ super(message, cause);
+ this.sqlState = sqlState;
+ this.vendorCode = vendorCode;
+ this.sqlString = sql;
+ this.position = position;
+ }
+
+ // Methods
+
+ /**
+ * Retrieves the SqlState for this <code>SqlException</code> object.
+ *
+ * @return the SQLState value
+ */
+ public String getSqlState() {
+ return (sqlState);
+ }
+
+ /**
+ * Retrieves the vendor-specific exception code for this
+ * <code>SqlException</code> object.
+ *
+ * @return the vendor's error code
+ */
+ public int getVendorCode() {
+ return (vendorCode);
+ }
+
+ /**
+ * Get the position.
+ *
+ * @return the index of the first character in sql where an error is detected.
+ * Zero based.
+ */
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * Get the sql.
+ *
+ * @return the SQL string sent to the database
+ */
+ public String getSqlString() {
+ return sqlString;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlParameter.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+
+/**
+ * Identifies a method the result of which will be bound to a parameter in a SQL
+ * statement when an instance of the containing type is passed to
+ * {@link ParameterizedOperation#set}.
+ *
+ * The following pseudo-code describes how an instance is used to set parameter
+ * values:
+ *
+ * {@code
+ * <pre> for (Method getter : annotatedMethods) {
+ * Annotation parameter = getter.getAnnotation(SqlParameter.class);
+ * op.set(prefix + parameter.marker(), method.invoke(instance), parameter.sqlType());
+ * }</pre>}
+ *
+ */
+@Retention(RUNTIME)
+@Target({METHOD})
+public @interface SqlParameter {
+
+ /**
+ * The marker for SQL parameter that the result of this method will be bound to.
+ *
+ * @return the name that identifies the parameter in the SQL
+ */
+ public String marker();
+
+ /**
+ * The SQL type of the value bound to the parameter.
+ * Must be either the name of an enum in {@link SqlType} or the fully
+ * qualified name of a constant {@link SqlType},
+ * for example an enum that implements that interface.
+ *
+ * @return the name of the SQL type of the value bound to the parameter
+ */
+ public String sqlType() default "<default>";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlRef.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import java.util.concurrent.CompletionStage;
+
+/**
+ *
+ * @param <T>
+ */
+public interface SqlRef<T> {
+
+ /**
+ * Return the name of SQL type of the referent of this SQL REF.
+ *
+ * ISSUE: Oracle Database JDBC driver may do a round trip for this. Is this
+ * that heavy in other databases?
+ *
+ * @return
+ */
+ public String getReferentTypeName();
+
+ /**
+ * Create and return an Operation that will fetch the value of the REF from
+ * the database. The value of the Operation is the value of the REF.
+ *
+ * @return an Operation that will fetch the referent of this SqlRef
+ */
+ public Operation<T> fetchOperation();
+
+ /**
+ * Submit an Operation that will fetch the value of the REF in the database.
+ *
+ * @return a Future that will complete when the submitted Operation completes.
+ * The value of the Future is the value of the REF.
+ */
+ public default CompletionStage<T> fetch() {
+ return fetchOperation().submit().getCompletionStage();
+ }
+
+ /**
+ * Create and return an Operation that will set the value of the REF in the
+ * database.
+ *
+ * @param value
+ * @return an Operation that will store the new referent into the REF
+ */
+ public Operation<Void> storeOperation(T value);
+
+ /**
+ * Submit an Operation that will store the new value of the referent into
+ * the REF in the database.
+ *
+ * @param value
+ * @return a Future that will complete when the submitted Operation completes.
+ */
+ public default CompletionStage<Void> store(T value) {
+ return storeOperation(value).submit().getCompletionStage();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlSkippedException.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,69 @@
+/*
+ * 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 {@link SqlException} that is used to complete an {@link Operation} when that {@link Operation} is
+ * skipped. If an {@link Operation} is skipped the {@link Operation} is removed from the head of
+ * the queue, no work is sent to the database and the {@link java.util.concurrent.CompletionStage} of that
+ * {@link Operation} is completed exceptionally with a {@link SqlSkippedException}. The cause of
+ * the {@link SqlSkippedException} is the {@link Throwable} that caused the {@link Operation} to be
+ * skipped, if any.
+ *
+ */
+public class SqlSkippedException extends SqlException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ * @param message
+ * @param cause
+ * @param sqlState
+ * @param vendorCode
+ * @param sql
+ * @param position
+ */
+ public SqlSkippedException(String message, Throwable cause, String sqlState, int vendorCode, String sql, int position) {
+ super(message, cause, sqlState, vendorCode, sql, position);
+ }
+
+ /**
+ *
+ * @param cause
+ */
+ public SqlSkippedException(SqlException cause) {
+ super(cause.getMessage(), cause, cause.getSqlState(), cause.getVendorCode(), cause.getSqlString(), cause.getPosition());
+ }
+
+ /**
+ *
+ * @param cause
+ */
+ public SqlSkippedException(Throwable cause) {
+ super(cause.getMessage(), cause, null, -1, null, -1);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlStruct.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Identifies a type that represents a STRUCT SQL type.
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface SqlStruct {
+
+ /**
+ * The SQL name of the SQL STRUCT type.
+ *
+ * @return the SQL identifier
+ */
+ public String sqlTypeName();
+
+ /**
+ * The fields of the SQL STRUCT type.
+ *
+ * @return the fields
+ */
+ public Field[] fields();
+
+ /**
+ * Describes a field of a SQL STRUCT type.
+ */
+ public @interface Field {
+
+ /**
+ * The name of the field in the SQL STRUCT.
+ *
+ * @return the name of the field
+ */
+ public String sqlFieldName();
+
+ /**
+ * The name of the SQL type of the field
+ *
+ * @return the SQL type name of the field
+ */
+ public String sqlTypeName();
+
+ /**
+ * The Java identifier corresponding to the SQL field. This identifier is
+ * used to determine the corresponding getter and setter for getting and
+ * setting the value of this field in the annotated Java type.
+ *
+ * Implementations may choose to directly access a field named with the same
+ * identifier or a constructor or static factory method where all of the
+ * formal parameters are named by @Field annotations in the applied
+ * @SqlStruct.
+ *
+ * @return a Java identifier
+ */
+ public String javaFieldName();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/SqlType.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+/**
+ * Identifies a SQL type. Can be a type defined by standard SQL or a vendor
+ * specific type.
+ *
+ * @see AdbaType
+ */
+public interface SqlType {
+
+ /**
+ *
+ * @return
+ */
+ public String getName();
+
+ /**
+ *
+ * @return
+ */
+ public String getVendor();
+
+ /**
+ *
+ * @return a Java type that best represents values of this SQL type
+ */
+ public <T> Class<T> getJavaType();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/Submission.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import java.util.concurrent.CompletionStage;
+
+/**
+ * The result of submitting an {@link Operation}. The {@link cancel} method of a
+ * {@link CompletionStage} does not cancel the {@link Operation}. This is part
+ * of the contract of {@link CompletionStage}. This type provides a method to
+ * cancel the {@link Operation}. Canceling an {@link Operation} only makes sense
+ * after the {@link Operation} is submitted so this type is the result of
+ * submitting an {@link Operation}.
+ *
+ * ISSUE: Should Operation.submit return a CompletionStage with the requirement
+ * that cancel attempts to cancel the database action? Conceptually this is fine.
+ * The concern is that it requires the implementor to implement their own
+ * CompletionStage or at the least subclass CompletableFuture to override
+ * cancel. Neither of these is trivial.
+ *
+ * @param <T> The type of the result of the {@link Operation} that created this
+ * {@link Submission}
+ */
+public interface Submission<T> {
+
+ /**
+ * Request that the {@link Operation} not be executed or that its execution be
+ * aborted if already begun. This is a best effort action and may not succeed
+ * in preventing or aborting the execution. This method does not block.
+ *
+ * If execution is prevented the Operation is completed exceptionally with
+ * SkippedSqlException. If the Operation is aborted it is completed
+ * exceptionally with SqlException.
+ *
+ * @return a {@link java.util.concurrent.CompletionStage} that has the value
+ * true if the {@link Operation} is canceled.
+ */
+ public CompletionStage<Boolean> cancel();
+
+ /**
+ * Returns a {@link CompletionStage} which value is the result of the
+ * {@link Operation}. Any actions on the returned {@link CompletionStage},
+ * eg {@code completeExceptionally} or {@code cancel}, have no impact on this
+ * {@link Operation}. If this {@link Operation} is already completed the
+ * returned {@link CompletionStage} will be completed.
+ *
+ * The returned {@link CompletionStage} is completed after the Operation
+ * is completed. It may be completed by the same thread that completed the
+ * Operation or a different one. The Operation following the one that created
+ * this Submission begins execution when the Operation that created this
+ * Submission is completed. It is not required to wait for the returned
+ * CompletionStage to complete. [Note: this is necessary because the app can
+ * call this method after the Operation completes.]
+ *
+ * Each call of this method for a given {@link Operation} returns the same
+ * {@link CompletionStage}.
+ *
+ * @return the {@link java.util.concurrent.CompletionStage} for the result of this
+ * {@link Operation}. Retained.
+ */
+ public CompletionStage<T> getCompletionStage();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/TransactionCompletion.java Thu Jul 12 15:21:13 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:
+
+ <pre>
+ * {@code
+ TransactionCompletion t = session.transactionCompletion();
+ session.countOperation(updateSql)
+ .resultProcessor( count -> { if (count > 1) t.setRollbackOnly(); } )
+ .submit();
+ session.commitMaybeRollback(t);
+ }</pre>
+
+ 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();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/TransactionOutcome.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+/**
+ * Possible outcomes for a database transaction.
+ */
+public enum TransactionOutcome {
+ /**
+ * The outcome of the transaction is unknown.
+ */
+ UNKNOWN,
+
+ /**
+ * The outcome of the transaction is in doubt.
+ */
+ IN_DOUBT,
+
+ /**
+ * The transaction committed successfully.
+ */
+ COMMIT,
+
+ /**
+ * The transaction rolled back successfully.
+ */
+ ROLLBACK;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/jdk/incubator/sql2/package-info.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * <p>
+ * An API for accessing and processing data stored in a data source (usually a
+ * relational database) using the Java™ programming language. This API
+ * includes a framework whereby different drivers can be installed dynamically
+ * to access different data sources. This API is specifically geared for passing
+ * SQL statements to a database though it may be used for reading and writing
+ * data from/to any data source that has a tabular format.</p>
+ *
+ * <p>
+ * This API differs from the API in {@code java.sql} in several ways.</p>
+ * <ul>
+ * <li>Is asynchronous
+ * <li>Is geared toward high-throughput programs
+ * <li>Does not attempt to support every database feature
+ * <li>Does not attempt to abstract the database
+ * <li>Uses the builder pattern
+ * <li>Supports the fluent programming style
+ * </ul>
+ *
+ * <p>
+ * It is worth emphasizing that this API is an alternate to the {@code java.sql}
+ * API, not a replacement. There are many programs that can much more readily be
+ * written using the {@code java.sql} API as it has many features that are not
+ * available in this API. For example this API provides almost no mechanism for
+ * getting metadata.</p>
+ *
+ * <p>
+ * This API is not an extension to the {@code java.sql} API. It an independent
+ * API and is used on its own without reference to java.sql. </p>
+ *
+ *
+ * <h3>Overview</h3>
+ *
+ * <p>
+ * The core feature of this API is that it is asynchronous. No method call will
+ * wait for a network operation. </p>
+ *
+ * <p>
+ * Possibly blocking actions are represented as {@link Operation}s. An
+ * application using the API creates and submits one or more {@link Operation}s.
+ * The implementation executes these {@link Operation}s asynchronously, reporting
+ * their results via {@link java.util.concurrent.CompletionStage}s. An application
+ * can respond to the results via the
+ * {@link java.util.concurrent.CompletionStage}s or via callbacks that can be
+ * configured on many of the {@link Operation}s or both. Creating and submitting
+ * {@link Operation}s is strictly non-blocking. Handling the results of possibly
+ * blocking {@link Operation}s is done asynchronously. No application thread
+ * will ever block on a call to a method in this API.</p>
+ *
+ * <p>
+ * All {@link Operation}s provide a
+ * {@link java.util.concurrent.CompletionStage}. The value of that
+ * {@link java.util.concurrent.CompletionStage} is the value of the
+ * {@link Operation}, set when the {@link Operation} completes. Some
+ * {@link Operation}s provide callbacks for processing the result of the
+ * {@link Operation} independent of the
+ * {@link java.util.concurrent.CompletionStage}. Those {@link Operation}s can
+ * be used for executing SQL that returns results of a specific type. For
+ * example SQL that returns a row sequence would be executed with a
+ * {@link RowOperation}. A {@link RowOperation} provides callbacks for
+ * processing each row and for collecting the results of processing the rows.
+ * Other {@link Operation}s are specialized for SQL that returns a count or that
+ * returns out parameters. The choice of {@link Operation} is dependent on the
+ * result to be processed and is independent of the particular kind of SQL
+ * statement.</p>
+ *
+ * <p>
+ * An {@link OperationGroup} encapsulates a group of {@link Operation}s and
+ * executes them using common attributes. An {@link OperationGroup} can be
+ * unconditional or conditional, sequential or parallel, dependent or
+ * independent, or any combination of these. Dependent/independent controls
+ * error handling. If one member of a dependent {@link OperationGroup} fails the
+ * remaining not-yet-executed members are completed exceptionally. If the
+ * {@link OperationGroup} is independent, the member {@link Operation}s are
+ * executed regardless of whether one or more fails.</p>
+ *
+ * <p>
+ * A single context in a data source is represented by a {@link Session}. A
+ * {@link Session} is somewhat analogous to a logical {@link java.sql.Connection}.
+ * A physical {@link java.sql.Connection} has no representation in this API; if
+ * such an entity exists at all it is strictly internal to an implementation.
+ * Within this spec this entity is referred to as a "data source resource".
+ * </p>
+ *
+ * <p>
+ * A {@link Session} is itself an {@link OperationGroup} and so can be
+ * conditional, parallel, or independent, but by default is unconditional,
+ * sequential, dependent. While a {@link Session} may be created with values
+ * other than the defaults, using the defaults is by far the most common case.
+ * The API provides convenience methods that support this case. Using these
+ * convenience methods is recommended in all but the most unusual circumstances.
+ * In particular making the {@link Session} parallel introduces some
+ * challenges that would require a full understanding of the details of the API.
+ * It would almost certainly be better to create a parallel
+ * {@link OperationGroup} within the {@link Session}.</p>
+ *
+ * <p>
+ * <i>
+ * ISSUE: Should we disallow {@code Session.parallel()}?</i></p>
+ *
+ * <p>
+ * The {@code java.sql} API frequently provides many ways to do the same thing.
+ * This API makes no attempt to do this. For those capabilities this API
+ * supports, it frequently defines exactly one way to do something. Doing things
+ * another way, for example calling methods in a non-standard order, frequently
+ * results in an IllegalStateException. This approach is intended to make things
+ * simpler for both the user and the implementor. Rather than having to
+ * understand complicated interactions of many different components and methods
+ * executed in any order, the intent is that there is only one way to do things
+ * so only one path must be understood or implemented. Anything off that path is
+ * an error. While this requires a programmer to write code in one specific way
+ * it makes things easier on future maintainers of the code as the code will
+ * conform to the standard pattern. Similarly the implementation is simplified
+ * as only the standard use pattern is supported.</p>
+ *
+ * <p>
+ * One way this API simplifies things in to define types as single use. Many
+ * types are created, configured, used once, and are then no longer usable. Most
+ * configuration methods can be called only once on a given instance. Once an
+ * instance is configured it cannot be reconfigured. Once an instance is used it
+ * cannot be reused. This simplifies things by eliminating the need to
+ * understand and implement arbitrary sequences of method calls that reconfigure
+ * and reuse instances. Since objects are single use there is no expectation
+ * that an application cache or share {@link Operation}s.</p>
+ *
+ * <p>
+ * While the user visible types are single use, it is expected that an
+ * implementation will cache and reuse data and {@link Object}s that are worth
+ * the effort. Rather than attempt to guess what an implementation should reuse
+ * and capture that in the API, this API leaves it entirely up to the
+ * implementation. Since the API specifies very little reuse, an implementation
+ * is free to reuse whatever is appropriate. Since the pattern of use is
+ * strictly enforced figuring out how to reuse objects is greatly
+ * simplified.</p>
+ *
+ * <p>
+ * The {@code java.sql} API provides many tools for abstracting the database,
+ * for enabling the user to write database independent code. This API does not.
+ * It is not a goal of this API to enable users to write database independent
+ * code. That is not to say it is not possible, just that this API does not
+ * provide tools to support such. Abstraction features typically impose
+ * performance penalties on some implementations. As this API is geared for
+ * high-throughput programs it avoids such abstractions rather than reduce
+ * performance.</p>
+ *
+ * <p>
+ * One such abstraction feature is the JDBC escape sequences. Implementing these
+ * features requires parsing the SQL so as to identify the escape sequences and
+ * then generating a new String with the vendor specific SQL corresponding to
+ * the escape sequence. This is an expensive operation. Further each SQL must be
+ * parsed whether it contains an escape sequence or not imposing the cost on all
+ * JDBC users, not just the ones who use escape sequences. The same is true of
+ * JDBC parameter markers. The SQL accepted by this API is entirely vendor
+ * specific, including parameter markers. There is no need for pre-processing
+ * prior to SQL execution substantially reducing the amount of work the
+ * implementation must do.</p>
+ *
+ * <p>
+ * Note: It would be a reasonable future project to develop a SQL builder API
+ * that creates vendor specific SQL from some more abstract representation.</p>
+ *
+ * <p>
+ * This API is targeted at high-throughput apps. If a particular feature of this
+ * API would have a surprising performance impact for a particular implementation
+ * it is recommended that the implementation not implement that feature. It is
+ * better that a feature be unsupported as opposed to users investing substantial
+ * effort in an app using that feature only to discover in production that the
+ * performance is unacceptable. For example, if an implementation can only support
+ * {@link Operation#timeout} through active polling it would be better for that
+ * implementation to throw {@link UnsupportedOperationException} if
+ * {@link Operation#timeout} is called. To this end every type and method is
+ * optional except returning a {@link DataSourceFactory} in response to a call to
+ * {@link DataSourceFactory#newFactory} with the appropriate name.</p>
+ *
+ * <h3>Execution Model</h3>
+ *
+ * <p>
+ * <i>This section describes the function of a conforming implementation. It is
+ * not necessary for an implementation to be implemented as described only that
+ * the behavior be the same.</i></p>
+ *
+ * <p>
+ * An {@link Operation} has an action and a
+ * {@link java.util.concurrent.CompletionStage}. Some {@link Operation}s have
+ * some form of result processor.</p>
+ *
+ * <p>
+ * An {@link Operation} is executed by causing the action to be performed,
+ * processing the result of the action if there is a result processor, and
+ * completing the {@link java.util.concurrent.CompletionStage} with the result
+ * of the result processor if there is one. If the action or the result processing
+ * causes an unhandled error the {@link java.util.concurrent.CompletionStage} is
+ * completed exceptionally. The {@link java.util.concurrent.CompletionStage} is
+ * completed asynchronously, as though it were created by calling an
+ * <i>async</i> method on {@link java.util.concurrent.CompletionStage}.
+ * </p>
+ *
+ * <p>
+ * Performing the action may require one or more interactions with the database.
+ * These interactions may be carried out in parallel with processing the result.
+ * If the database result is ordered, that result is processed in the order
+ * specified by the database.</p>
+ *
+ * <p>
+ * An {@link OperationGroup} has a collection of member {@link Operation}s and
+ * optionally a condition. For a sequential {@link OperationGroup}
+ * {@link Operation}s are selected from the collection in the order they were
+ * submitted. For a parallel {@link OperationGroup} {@link Operation}s are
+ * selected from the collection in any order.</p>
+ *
+ * <p>
+ * The action of an {@link OperationGroup} is performed as follows:
+ * <ul>
+ * <li>
+ * If the {@link OperationGroup} has a condition, the value of the condition is
+ * retrieved. If the value is {@link Boolean#FALSE} the action is complete and
+ * the {@link java.util.concurrent.CompletionStage} is completed with null. If
+ * the condition value completes exceptionally the action is complete and the
+ * {@link java.util.concurrent.CompletionStage} is completed exceptionally
+ * with the same exception. If the condition value is {@link Boolean#TRUE} or
+ * there is no condition the {@link Operation}s in the collection are executed
+ * and their results processed. The action is complete when the
+ * {@link OperationGroup} is not held and all the {@link Operation}s have been
+ * executed.</li>
+ * <li>
+ * If the {@link OperationGroup} is parallel more than one member
+ * {@link Operation} may be executed at a time.</li>
+ * <li>
+ * If the {@link OperationGroup} is dependent and a member {@link Operation} completes
+ * exceptionally all member {@link Operation}s that are yet to begin
+ * execution are completed exceptionally with a {@link SqlSkippedException}. The
+ * cause of that exception is the {@link Throwable} that caused the
+ * {@link Operation} to be completed exceptionally. If an {@link Operation} is
+ * in flight when another {@link Operation} completes exceptionally the in
+ * flight {@link Operation} may either be allowed to complete uninterrupted or
+ * it may be completed exceptionally. The {@link OperationGroup} is dependent it
+ * is completed exceptionally with the {@link Throwable} that caused the
+ * {@link Operation} to complete exceptionally.
+ *
+ * <p>
+ * Note: the {@link Operation}s returned by {@link Session#closeOperation}
+ * and {@link OperationGroup#catchOperation} are never skipped, i.e. never
+ * completed exceptionally with {@link SqlSkippedException}. The {@link Operation}
+ * returned by {@link OperationGroup#catchOperation} never completes
+ * exceptionally so the following {@link Operation} is always executed normally.
+ * No {@link Operation} can be submitted after the {@link Operation} returned by
+ * {@link Session#closeOperation} has been submitted.</p> </li>
+ * <li>
+ * If the {@link OperationGroup} is independent and an {@link Operation}
+ * completes exceptionally all other {@link Operation}s are executed regardless.
+ * There is no result to be processed for an {@link Operation} that completed
+ * exceptionally. The {@link OperationGroup} is not completed exceptionally as
+ * the result of one or more {@link Operation}s completing exceptionally.</li>
+ * </ul>
+ *
+ * <p>
+ * A {@link Session} is a distinguished {@link OperationGroup}. A
+ * {@link Session} is executed upon being submitted.</p>
+ *
+ * <h3>Transactions</h3>
+ *
+ * <p>
+ * <i>This section describes the function of a conforming implementation. It is
+ * not necessary for an implementation to be implemented as described only that
+ * the behavior be the same.</i></p>
+ *
+ * <p>
+ * An implementation has only limited control over transactions. SQL statements
+ * can start, commit, and rollback transactions without the implementation
+ * having any influence or even being aware. This specification only describes
+ * the behavior of those transaction actions that are visible to and controlled
+ * by the implementation, i.e. the endTransaction {@link Operation}.
+ * Transaction actions caused by SQL may interact with actions controlled by the
+ * implementation in unexpected ways.</p>
+ *
+ * <p>
+ * The creation of Operations and the subsequent execution of those Operations
+ * are separated in time. It is quite reasonable to determine that a transaction
+ * should commit after the Operation that ends the transaction is submitted. But
+ * if the execution of the transaction does not result in the expected results
+ * 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 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 TransactionCompletion} can be set to rollback the transaction .</p>
+ *
+ * <p>
+ * An endTransaction {@link Operation}, like all {@link Operation}s, is
+ * immutable once submitted. But an endTransaction {@link Operation} is created
+ * 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.</p>
+ *
+ * <pre>
+ * {@code
+ * TransactionCompletion t = session.getTransactionEnd();
+ * session.countOperation(updateSql)
+ * .resultProcessor( count -> {
+ * if (count > 1) t.setRollbackOnly();
+ * return null;
+ * } )
+ * .submit();
+ * session.catchErrors();
+ * session.commitMaybeRollback(t);
+ * }
+ * </pre>
+ *
+ * <p>
+ * In this example if the update SQL modifies more than one row the result
+ * 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.</p>
+ *
+ *
+ * <h3>Implementation Note</h3>
+ *
+ * <p>
+ * If an implementation exposes any implementation specific types and methods, the
+ * implementation is expected to provide covariant overrides for all methods that
+ * return the standard super-type of the implementation specific type.</p>
+ *
+ * <p>
+ * Consider an implementation that adds a method foo() to RowCountOperation. To do
+ * that it would have to expose a type FooRowCountOperation extends RowCountOperation.
+ * So that an application can transparently access foo, the implementation would
+ * also have to expose FooDataSource, FooOperationGroup and FooSession. Further
+ * each of these types would have to declare covariant overrides for every method
+ * that returns a direct super-type of one of these types.</p>
+ * <ul>
+ * <li>FooDataSourceFactory must override builder to return FooDataSource.Builder</li>
+ * <li>FooDataSource.Builder must override url, password, etc to return a
+ * FooDataSource.Builder. build must return a FooDataSource.</li>
+ * <li>FooDataSource must override builder to return FooSession.Builder</li>
+ * <li>FooSession.Builder must override url, password, etc to return a
+ * FooSession.Builder. build must return a FooSession</li>
+ * <li>FooDataSource must override getSession to return FooSession</li>
+ * <li>FooSession must extend FooOperationGroup</li>
+ * <li>FooOperationGroup> must override rowCountOperation to return FooRowCountOperation</li>
+ * <li>FooRowCountOperation must override apply and onError to return FooRowCountOperation</li>
+ * </ul>
+ * <p>
+ * The intent is to transparently expose the vendor extension without use of casts.
+ * Example: </p>
+ *
+ * <pre>
+ * {@code
+ * FooDataSourceFactory factory = DataSourceFatory.newFactory("com.foo.FooDataSourceFatory");
+ * FooDataSource dataSource = factory.builder()
+ * .url("scott/tiger@host:port")
+ * .build();
+ * FooSession session = dataSource.getSession();
+ * CompletionStage<Long> count = session.rowOperation(sql)
+ * .set("param", value, AdbaType.VARCHAR)
+ * .foo()
+ * .submit()
+ * .getCompletionStage();
+ * }
+ * </pre>
+ *
+ * <p>
+ * Notice that there are no casts, yet both standard methods an the vendor extension
+ * method foo can be referenced. This is possible only if the implementation exposes
+ * all the necessary types and provides covariant overrides for every method that
+ * returns one of those types. Implementations are expected (required?) to do this.
+ * </p>
+ *
+ * <p>
+ * If an implementation does not expose any implementation specific methods or
+ * types, that implementation is not required to provide covariant overrides that
+ * return implementation specific types.</p>
+ *
+ *
+ */
+ package jdk.incubator.sql2;
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.incubator.adba/share/classes/module-info.java Thu Jul 12 15:21:13 2018 -0400
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+module jdk.incubator.adba {
+ requires static transitive java.logging;
+ exports jdk.incubator.sql2;
+ uses jdk.incubator.sql2.DataSourceFactory;
+}