diff --git a/jOOQ-examples/jOOQ-spring-boot-example/.gitignore b/jOOQ-examples/jOOQ-spring-boot-example/.gitignore
index 26ae8c908e..4440e58198 100644
--- a/jOOQ-examples/jOOQ-spring-boot-example/.gitignore
+++ b/jOOQ-examples/jOOQ-spring-boot-example/.gitignore
@@ -3,3 +3,4 @@
.settings
/target
/*.iml
+/bin/
diff --git a/jOOQ/src/main/java/org/jooq/Binding.java b/jOOQ/src/main/java/org/jooq/Binding.java
new file mode 100644
index 0000000000..092d1efeeb
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/Binding.java
@@ -0,0 +1,184 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+import java.io.Serializable;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLInput;
+import java.sql.SQLOutput;
+import java.sql.Timestamp;
+
+import org.jooq.exception.DataAccessException;
+import org.jooq.impl.DefaultBinding;
+
+/**
+ * An SPI (Service Provider Interface) that exposes all low-level interactions
+ * with JDBC bind variables.
+ *
+ * This SPI is used by jOOQ users to implement support for custom data types
+ * that would otherwise not be supported by jOOQ and/or JDBC. All of jOOQ's
+ * internal support for bind variable types is implemented in
+ * {@link DefaultBinding}.
+ *
+ * @author Lukas Eder
+ */
+public interface Binding extends Serializable {
+
+ /**
+ * Generate SQL code for the bind variable.
+ *
+ * Implementations should generate SQL code onto
+ * {@link BindingSQLContext#render()}, given the context's bind variable
+ * located at {@link BindingSQLContext#value()}. Examples of such SQL code
+ * are:
+ *
+ * "?": Default implementations can simply generate a
+ * question mark.
+ *
+ *
+ * "123": Implementations may choose to inline bind
+ * variables to influence execution plan generation.
+ *
+ * {@link RenderContext#paramType()} contains information whether inlined
+ * bind variables are expected in the current context.
+ *
+ *
+ * "CAST(? AS DATE)": Cast a database to a more specific
+ * type. This can be useful in databases like Oracle, which map both
+ * DATE and TIMESTAMP SQL types to
+ * {@link Timestamp}.
+ *
+ * {@link RenderContext#castMode()} may contain some hints about whether
+ * casting is suggested in the current context.
+ *
+ *
+ * "?::json": Vendor-specific bind variables can be
+ * supported, e.g. {@link SQLDialect#POSTGRES}'s JSON data type.
+ *
+ *
+ * Implementations must provide consistent behaviour between
+ * {@link #sql(BindingSQLContext)} and
+ * {@link #set(BindingSetStatementContext)}, i.e. when bind variables are
+ * inlined, then they must not be bound to the {@link PreparedStatement} in
+ * {@link #set(BindingSetStatementContext)}
+ *
+ * @param ctx The context object containing all argument objects.
+ * @throws SQLException Implementations are allowed to pass on all
+ * {@link SQLException}s to the caller to be wrapped in
+ * {@link DataAccessException}s.
+ */
+ void sql(BindingSQLContext ctx) throws SQLException;
+
+ /**
+ * Register a {@link CallableStatement}'s OUT parameter.
+ *
+ * @param ctx The context object containing all argument objects.
+ * @throws SQLException Implementations are allowed to pass on all
+ * {@link SQLException}s to the caller to be wrapped in
+ * {@link DataAccessException}s.
+ */
+ void register(BindingRegisterContext ctx) throws SQLException;
+
+ /**
+ * Set a {@link PreparedStatement}'s IN parameter.
+ *
+ * @param ctx The context object containing all argument objects.
+ * @throws SQLException Implementations are allowed to pass on all
+ * {@link SQLException}s to the caller to be wrapped in
+ * {@link DataAccessException}s.
+ */
+ void set(BindingSetStatementContext ctx) throws SQLException;
+
+ /**
+ * Set a {@link SQLOutput}'s IN parameter.
+ *
+ * @param ctx The context object containing all argument objects.
+ * @throws SQLException Implementations are allowed to pass on all
+ * {@link SQLException}s to the caller to be wrapped in
+ * {@link DataAccessException}s.
+ */
+ void set(BindingSetSQLOutputContext ctx) throws SQLException;
+
+ /**
+ * Get a {@link ResultSet}'s OUT value.
+ *
+ * Implementations are expected to produce a value by calling
+ * {@link BindingGetResultSetContext#value(Object)}, passing the resulting
+ * value to the method.
+ *
+ * @param ctx The context object containing all argument objects.
+ * @throws SQLException Implementations are allowed to pass on all
+ * {@link SQLException}s to the caller to be wrapped in
+ * {@link DataAccessException}s.
+ */
+ void get(BindingGetResultSetContext ctx) throws SQLException;
+
+ /**
+ * Get a {@link CallableStatement}'s OUT value.
+ *
+ * Implementations are expected to produce a value by calling
+ * {@link BindingGetStatementContext#value(Object)}, passing the resulting
+ * value to the method.
+ *
+ * @param ctx The context object containing all argument objects.
+ * @throws SQLException Implementations are allowed to pass on all
+ * {@link SQLException}s to the caller to be wrapped in
+ * {@link DataAccessException}s.
+ */
+ void get(BindingGetStatementContext ctx) throws SQLException;
+
+ /**
+ * Get a {@link SQLInput}'s OUT value.
+ *
+ * Implementations are expected to produce a value by calling
+ * {@link BindingGetSQLInputContext#value(Object)}, passing the resulting
+ * value to the method.
+ *
+ * @param ctx The context object containing all argument objects.
+ * @throws SQLException Implementations are allowed to pass on all
+ * {@link SQLException}s to the caller to be wrapped in
+ * {@link DataAccessException}s.
+ */
+ void get(BindingGetSQLInputContext ctx) throws SQLException;
+}
diff --git a/jOOQ/src/main/java/org/jooq/BindingContext.java b/jOOQ/src/main/java/org/jooq/BindingContext.java
new file mode 100644
index 0000000000..80a2fc41a9
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/BindingContext.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+public interface BindingContext {
+ Configuration configuration();
+
+ SQLDialect dialect();
+
+ SQLDialect family();
+}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/BindingGetResultSetContext.java b/jOOQ/src/main/java/org/jooq/BindingGetResultSetContext.java
new file mode 100644
index 0000000000..c2d88e10c9
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/BindingGetResultSetContext.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+import java.sql.ResultSet;
+
+/**
+ * A container type for {@link Binding#get(BindingGetResultSetContext)}
+ * arguments.
+ *
+ * @author Lukas Eder
+ */
+public interface BindingGetResultSetContext extends Scope {
+
+ /**
+ * The {@link ResultSet} from which a value is retrieved.
+ */
+ ResultSet resultSet();
+
+ /**
+ * The column index at which the value is retrieved.
+ */
+ int index();
+
+ /**
+ * A callback to which the resulting value is registered.
+ */
+ void value(T value);
+}
diff --git a/jOOQ/src/main/java/org/jooq/BindingGetSQLInputContext.java b/jOOQ/src/main/java/org/jooq/BindingGetSQLInputContext.java
new file mode 100644
index 0000000000..dbcf79d5d3
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/BindingGetSQLInputContext.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+import java.sql.SQLInput;
+
+/**
+ * A container type for {@link Binding#get(BindingGetSQLInputContext)}
+ * arguments.
+ *
+ * @author Lukas Eder
+ */
+public interface BindingGetSQLInputContext extends Scope {
+
+ /**
+ * The {@link SQLInput} from which a value is retrieved.
+ */
+ SQLInput input();
+
+ /**
+ * A callback to which the resulting value is registered.
+ */
+ void value(T value);
+}
diff --git a/jOOQ/src/main/java/org/jooq/BindingGetStatementContext.java b/jOOQ/src/main/java/org/jooq/BindingGetStatementContext.java
new file mode 100644
index 0000000000..e29b5d4b24
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/BindingGetStatementContext.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+import java.sql.CallableStatement;
+
+/**
+ * A container type for {@link Binding#get(BindingGetStatementContext)}
+ * arguments.
+ *
+ * @author Lukas Eder
+ */
+public interface BindingGetStatementContext extends Scope {
+
+ /**
+ * The {@link CallableStatement} from which a value is retrieved.
+ */
+ CallableStatement statement();
+
+ /**
+ * The column index at which the value is retrieved.
+ */
+ int index();
+
+ /**
+ * A callback to which the resulting value is registered.
+ */
+ void value(T value);
+}
diff --git a/jOOQ/src/main/java/org/jooq/BindingRegisterContext.java b/jOOQ/src/main/java/org/jooq/BindingRegisterContext.java
new file mode 100644
index 0000000000..2e9666e3d1
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/BindingRegisterContext.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+import java.sql.CallableStatement;
+
+/**
+ * A container type for {@link Binding#register(BindingRegisterContext)}
+ * arguments.
+ *
+ * @author Lukas Eder
+ */
+public interface BindingRegisterContext extends Scope {
+
+ /**
+ * The {@link CallableStatement} on which a bind variable should be
+ * registered.
+ */
+ CallableStatement statement();
+
+ /**
+ * The bind variable index at which a bind variable should be registered.
+ */
+ int index();
+}
diff --git a/jOOQ/src/main/java/org/jooq/BindingSQLContext.java b/jOOQ/src/main/java/org/jooq/BindingSQLContext.java
new file mode 100644
index 0000000000..94bec36ca2
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/BindingSQLContext.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+/**
+ * A container type for {@link Binding#sql(BindingSQLContext)} arguments.
+ *
+ * @author Lukas Eder
+ */
+public interface BindingSQLContext extends Scope {
+
+ /**
+ * The {@link RenderContext} that contains the generated SQL and the current
+ * SQL generation state.
+ */
+ RenderContext render();
+
+ /**
+ * The bind value that is being rendered.
+ */
+ T value();
+}
diff --git a/jOOQ/src/main/java/org/jooq/BindingSetSQLOutputContext.java b/jOOQ/src/main/java/org/jooq/BindingSetSQLOutputContext.java
new file mode 100644
index 0000000000..789261d9c2
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/BindingSetSQLOutputContext.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+import java.sql.SQLOutput;
+
+/**
+ * A container type for {@link Binding#set(BindingSetSQLOutputContext)}
+ * arguments.
+ *
+ * @author Lukas Eder
+ */
+public interface BindingSetSQLOutputContext extends Scope {
+
+ /**
+ * The {@link SQLOutput} to which a bind variable should be bound.
+ */
+ SQLOutput output();
+
+ /**
+ * The bind value that is being bound.
+ */
+ T value();
+}
diff --git a/jOOQ/src/main/java/org/jooq/BindingSetStatementContext.java b/jOOQ/src/main/java/org/jooq/BindingSetStatementContext.java
new file mode 100644
index 0000000000..58dd8d2c76
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/BindingSetStatementContext.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+import java.sql.PreparedStatement;
+
+/**
+ * A container type for {@link Binding#set(BindingSetStatementContext)}
+ * arguments.
+ *
+ * @author Lukas Eder
+ */
+public interface BindingSetStatementContext extends Scope {
+
+ /**
+ * The {@link PreparedStatement} to which a bind variable should be bound.
+ */
+ PreparedStatement statement();
+
+ /**
+ * The bind variable index at which a bind variable should be bound.
+ */
+ int index();
+
+ /**
+ * The bind value that is being bound.
+ */
+ T value();
+}
diff --git a/jOOQ/src/main/java/org/jooq/Context.java b/jOOQ/src/main/java/org/jooq/Context.java
index 4e758cf4e3..8ecf7111aa 100644
--- a/jOOQ/src/main/java/org/jooq/Context.java
+++ b/jOOQ/src/main/java/org/jooq/Context.java
@@ -41,7 +41,6 @@
package org.jooq;
import java.sql.PreparedStatement;
-import java.util.Map;
import org.jooq.RenderContext.CastMode;
import org.jooq.conf.ParamType;
@@ -56,93 +55,12 @@ import org.jooq.exception.DataAccessException;
* @see BindContext
* @see RenderContext
*/
-public interface Context> {
+public interface Context> extends Scope {
// ------------------------------------------------------------------------
// General methods
// ------------------------------------------------------------------------
- /**
- * The configuration wrapped by this context.
- */
- Configuration configuration();
-
- /**
- * The settings wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().settings().
- */
- Settings settings();
-
- /**
- * The {@link SQLDialect} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().
- */
- SQLDialect dialect();
-
- /**
- * The {@link SQLDialect#family()} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().family().
- */
- SQLDialect family();
-
- /**
- * Get all custom data from this Context.
- *
- * This is custom data that was previously set to the context using
- * {@link #data(Object, Object)}. Use custom data if you want to pass data
- * to {@link QueryPart} objects for a given {@link RenderContext} or
- * {@link BindContext}.
- *
- * Unlike {@link Configuration#data()}, these data's lifecycle only
- * matches that of a render or bind context.
- *
- * @return The custom data. This is never null
- */
- Map data();
-
- /**
- * Get some custom data from this Context.
- *
- * This is custom data that was previously set to the context using
- * {@link #data(Object, Object)}. Use custom data if you want to pass data
- * to {@link QueryPart} objects for a given {@link RenderContext} or
- * {@link BindContext}.
- *
- * Unlike {@link Configuration#data()}, these data's lifecycle only
- * matches that of a render or bind context.
- *
- * @param key A key to identify the custom data
- * @return The custom data or null if no such data is contained
- * in this ExecuteContext
- * @see ExecuteListener
- */
- Object data(Object key);
-
- /**
- * Set some custom data to this Context.
- *
- * This is custom data that was previously set to the context using
- * {@link #data(Object, Object)}. Use custom data if you want to pass data
- * to {@link QueryPart} objects for a given {@link RenderContext} or
- * {@link BindContext}.
- *
- * Unlike {@link Configuration#data()}, these data's lifecycle only
- * matches that of a render or bind context.
- *
- * @param key A key to identify the custom data
- * @param value The custom data
- * @return The previously set custom data or null if no data
- * was previously set for the given key
- * @see ExecuteListener
- */
- Object data(Object key, Object value);
-
/**
* Visit a QueryPart in the current Context.
*
diff --git a/jOOQ/src/main/java/org/jooq/DSLContext.java b/jOOQ/src/main/java/org/jooq/DSLContext.java
index 86a5ac8835..bb06977955 100644
--- a/jOOQ/src/main/java/org/jooq/DSLContext.java
+++ b/jOOQ/src/main/java/org/jooq/DSLContext.java
@@ -113,42 +113,12 @@ import org.jooq.impl.DSL;
* @see Configuration
* @author Lukas Eder
*/
-public interface DSLContext {
+public interface DSLContext extends Scope {
// -------------------------------------------------------------------------
// XXX Configuration API
// -------------------------------------------------------------------------
- /**
- * The Configuration referenced from this
- * DSLContext.
- */
- Configuration configuration();
-
- /**
- * The settings wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().settings().
- */
- Settings settings();
-
- /**
- * The {@link SQLDialect} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().
- */
- SQLDialect dialect();
-
- /**
- * The {@link SQLDialect#family()} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().family().
- */
- SQLDialect family();
-
/**
* Map a schema to another one.
*
diff --git a/jOOQ/src/main/java/org/jooq/ExecuteContext.java b/jOOQ/src/main/java/org/jooq/ExecuteContext.java
index efce65db5a..b72eea388a 100644
--- a/jOOQ/src/main/java/org/jooq/ExecuteContext.java
+++ b/jOOQ/src/main/java/org/jooq/ExecuteContext.java
@@ -58,7 +58,7 @@ import org.jooq.exception.DataAccessException;
* @author Lukas Eder
* @see ExecuteListener
*/
-public interface ExecuteContext {
+public interface ExecuteContext extends Scope {
/**
* Get all custom data from this ExecuteContext.
@@ -110,35 +110,6 @@ public interface ExecuteContext {
*/
Object data(Object key, Object value);
- /**
- * The configuration wrapped by this context.
- */
- Configuration configuration();
-
- /**
- * The settings wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().settings().
- */
- Settings settings();
-
- /**
- * The {@link SQLDialect} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().
- */
- SQLDialect dialect();
-
- /**
- * The {@link SQLDialect#family()} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().family().
- */
- SQLDialect family();
-
/**
* The connection to be used in this execute context.
*
diff --git a/jOOQ/src/main/java/org/jooq/Field.java b/jOOQ/src/main/java/org/jooq/Field.java
index 5d17f56ba1..58c9037d0f 100644
--- a/jOOQ/src/main/java/org/jooq/Field.java
+++ b/jOOQ/src/main/java/org/jooq/Field.java
@@ -116,6 +116,11 @@ public interface Field extends GroupField {
*/
Converter, T> getConverter();
+ /**
+ * The field's underlying {@link Binding}.
+ */
+ Binding getBinding();
+
/**
* The Java type of the field.
*/
diff --git a/jOOQ/src/main/java/org/jooq/Parameter.java b/jOOQ/src/main/java/org/jooq/Parameter.java
index 0810292b4b..126301224c 100644
--- a/jOOQ/src/main/java/org/jooq/Parameter.java
+++ b/jOOQ/src/main/java/org/jooq/Parameter.java
@@ -69,6 +69,11 @@ public interface Parameter extends QueryPart {
*/
Converter, T> getConverter();
+ /**
+ * The parameter's underlying {@link Binding}.
+ */
+ Binding getBinding();
+
/**
* The type of this parameter (might not be dialect-specific)
*/
diff --git a/jOOQ/src/main/java/org/jooq/RecordContext.java b/jOOQ/src/main/java/org/jooq/RecordContext.java
index 433610bd74..6be8b27054 100644
--- a/jOOQ/src/main/java/org/jooq/RecordContext.java
+++ b/jOOQ/src/main/java/org/jooq/RecordContext.java
@@ -42,15 +42,13 @@ package org.jooq;
import java.util.Map;
-import org.jooq.conf.Settings;
-
/**
* A context object for {@link Record} manipulation passed to registered
* {@link RecordListener}'s.
*
* @author Lukas Eder
*/
-public interface RecordContext {
+public interface RecordContext extends Scope {
/**
* Get all custom data from this RecordContext.
@@ -102,35 +100,6 @@ public interface RecordContext {
*/
Object data(Object key, Object value);
- /**
- * The configuration wrapped by this context.
- */
- Configuration configuration();
-
- /**
- * The settings wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().settings().
- */
- Settings settings();
-
- /**
- * The {@link SQLDialect} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().
- */
- SQLDialect dialect();
-
- /**
- * The {@link SQLDialect#family()} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().family().
- */
- SQLDialect family();
-
/**
* The type of database interaction that is being executed.
*
diff --git a/jOOQ/src/main/java/org/jooq/Scope.java b/jOOQ/src/main/java/org/jooq/Scope.java
new file mode 100644
index 0000000000..43eae0ae17
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/Scope.java
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq;
+
+import java.util.Map;
+
+import org.jooq.conf.Settings;
+
+/**
+ * Scope implementations provide access to a variety of objects that are
+ * available from a given scope.
+ *
+ * The scope of the various objects contained in this type (e.g.
+ * {@link #configuration()}, {@link #settings()}, etc.) are implementation
+ * dependent and will be specified by the concrete subtype of Scope.
+ *
+ * @author Lukas Eder
+ */
+public interface Scope {
+
+ /**
+ * The configuration of the current scope.
+ */
+ Configuration configuration();
+
+ /**
+ * The settings wrapped by this context.
+ *
+ * This method is a convenient way of accessing
+ * configuration().settings().
+ */
+ Settings settings();
+
+ /**
+ * The {@link SQLDialect} wrapped by this context.
+ *
+ * This method is a convenient way of accessing
+ * configuration().dialect().
+ */
+ SQLDialect dialect();
+
+ /**
+ * The {@link SQLDialect#family()} wrapped by this context.
+ *
+ * This method is a convenient way of accessing
+ * configuration().dialect().family().
+ */
+ SQLDialect family();
+
+ /**
+ * Get all custom data from this Scope.
+ *
+ * This is custom data that was previously set to the context using
+ * {@link #data(Object, Object)}. Use custom data if you want to pass data
+ * to {@link QueryPart} objects for a given {@link Scope}.
+ *
+ * @return The custom data. This is never null
+ */
+ Map data();
+
+ /**
+ * Get some custom data from this Scope.
+ *
+ * This is custom data that was previously set to the context using
+ * {@link #data(Object, Object)}. Use custom data if you want to pass data
+ * to {@link QueryPart} objects for a given {@link Scope}
+ *
+ * @param key A key to identify the custom data
+ * @return The custom data or null if no such data is contained
+ * in this Scope
+ */
+ Object data(Object key);
+
+ /**
+ * Set some custom data to this Scope.
+ *
+ * This is custom data that was previously set to the context using
+ * {@link #data(Object, Object)}. Use custom data if you want to pass data
+ * to {@link QueryPart} objects for a given {@link Scope}.
+ *
+ * @param key A key to identify the custom data
+ * @param value The custom data
+ * @return The previously set custom data or null if no data
+ * was previously set for the given key
+ */
+ Object data(Object key, Object value);
+}
diff --git a/jOOQ/src/main/java/org/jooq/TransactionContext.java b/jOOQ/src/main/java/org/jooq/TransactionContext.java
index 1e15cb2a09..4a0b67e8c6 100644
--- a/jOOQ/src/main/java/org/jooq/TransactionContext.java
+++ b/jOOQ/src/main/java/org/jooq/TransactionContext.java
@@ -40,7 +40,6 @@
*/
package org.jooq;
-import org.jooq.conf.Settings;
/**
* A context object that is used to pass arguments to the various methods of
@@ -48,36 +47,7 @@ import org.jooq.conf.Settings;
*
* @author Lukas Eder
*/
-public interface TransactionContext {
-
- /**
- * The configuration scoped to this transaction and its nested transactions.
- */
- Configuration configuration();
-
- /**
- * The settings wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().settings().
- */
- Settings settings();
-
- /**
- * The {@link SQLDialect} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().
- */
- SQLDialect dialect();
-
- /**
- * The {@link SQLDialect#family()} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().family().
- */
- SQLDialect family();
+public interface TransactionContext extends Scope {
/**
* A user-defined transaction object, possibly obtained from
diff --git a/jOOQ/src/main/java/org/jooq/VisitContext.java b/jOOQ/src/main/java/org/jooq/VisitContext.java
index 02690367c1..4c4f312375 100644
--- a/jOOQ/src/main/java/org/jooq/VisitContext.java
+++ b/jOOQ/src/main/java/org/jooq/VisitContext.java
@@ -42,8 +42,6 @@ package org.jooq;
import java.util.Map;
-import org.jooq.conf.Settings;
-
/**
* A context object for {@link QueryPart} traversal passed to registered
* {@link VisitListener}'s.
@@ -51,7 +49,7 @@ import org.jooq.conf.Settings;
* @author Lukas Eder
* @see VisitListener
*/
-public interface VisitContext {
+public interface VisitContext extends Scope {
/**
* Get all custom data from this VisitContext.
@@ -91,35 +89,6 @@ public interface VisitContext {
*/
Object data(Object key, Object value);
- /**
- * The configuration wrapped by this context.
- */
- Configuration configuration();
-
- /**
- * The settings wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().settings().
- */
- Settings settings();
-
- /**
- * The {@link SQLDialect} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().
- */
- SQLDialect dialect();
-
- /**
- * The {@link SQLDialect#family()} wrapped by this context.
- *
- * This method is a convenient way of accessing
- * configuration().dialect().family().
- */
- SQLDialect family();
-
/**
* The most recent clause that was encountered through
* {@link Context#start(Clause)}.
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractBindingContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractBindingContext.java
new file mode 100644
index 0000000000..ee520b43e4
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractBindingContext.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import org.jooq.BindingContext;
+import org.jooq.Configuration;
+import org.jooq.SQLDialect;
+
+/**
+ * @author Lukas Eder
+ */
+abstract class AbstractBindingContext implements BindingContext {
+
+ private final Configuration configuration;
+
+ AbstractBindingContext(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public final Configuration configuration() {
+ return configuration;
+ }
+
+ @Override
+ public final SQLDialect dialect() {
+ return configuration.dialect();
+ }
+
+ @Override
+ public final SQLDialect family() {
+ return configuration.dialect().family();
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java
index 622c4c1ee1..68b91ba0a3 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java
@@ -46,7 +46,6 @@ import static org.jooq.impl.Utils.DATA_OMIT_CLAUSE_EVENT_EMISSION;
import java.sql.PreparedStatement;
import java.util.ArrayDeque;
import java.util.Deque;
-import java.util.HashMap;
import java.util.Map;
import org.jooq.BindContext;
@@ -69,11 +68,9 @@ import org.jooq.conf.Settings;
* @author Lukas Eder
*/
@SuppressWarnings("unchecked")
-abstract class AbstractContext> implements Context {
+abstract class AbstractContext> extends AbstractScope implements Context {
- final Configuration configuration;
final PreparedStatement stmt;
- final Map data;
boolean declareFields;
boolean declareTables;
@@ -94,9 +91,9 @@ abstract class AbstractContext> implements Context {
CastMode castMode = CastMode.DEFAULT;
AbstractContext(Configuration configuration, PreparedStatement stmt) {
- this.configuration = configuration;
+ super(configuration);
+
this.stmt = stmt;
- this.data = new HashMap();
this.visitClauses = new ArrayDeque();
VisitListenerProvider[] providers = configuration.visitListenerProviders();
@@ -316,41 +313,6 @@ abstract class AbstractContext> implements Context {
// XXX Context API
// ------------------------------------------------------------------------
- @Override
- public final Configuration configuration() {
- return configuration;
- }
-
- @Override
- public final Settings settings() {
- return Utils.settings(configuration());
- }
-
- @Override
- public final SQLDialect dialect() {
- return Utils.configuration(configuration()).dialect();
- }
-
- @Override
- public final SQLDialect family() {
- return dialect().family();
- }
-
- @Override
- public final Map data() {
- return data;
- }
-
- @Override
- public final Object data(Object key) {
- return data.get(key);
- }
-
- @Override
- public final Object data(Object key, Object value) {
- return data.put(key, value);
- }
-
private final C visit0(QueryPart part) {
if (part != null) {
QueryPartInternal internal = (QueryPartInternal) part;
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
index 24982d79fb..055cf5d8f9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
@@ -77,6 +77,7 @@ import java.util.Map;
import java.util.Map.Entry;
import org.jooq.BetweenAndStep;
+import org.jooq.Binding;
import org.jooq.CaseValueStep;
import org.jooq.CaseWhenStep;
import org.jooq.Clause;
@@ -113,6 +114,7 @@ abstract class AbstractField extends AbstractQueryPart implements Field {
private final String comment;
private final DataType dataType;
private final Converter, T> converter;
+ private final Binding binding;
AbstractField(String name, DataType type) {
this(name, type, null, null);
@@ -131,6 +133,8 @@ abstract class AbstractField extends AbstractQueryPart implements Field {
: type instanceof ConvertedDataType
? ((ConvertedDataType, T>) type).converter()
: new IdentityConverter(type.getType());
+
+ this.binding = new DefaultBinding(this.converter, type.isLob());
}
// ------------------------------------------------------------------------
@@ -174,6 +178,11 @@ abstract class AbstractField extends AbstractQueryPart implements Field {
return converter;
}
+ @Override
+ public final Binding getBinding() {
+ return binding;
+ }
+
@Override
public final DataType getDataType() {
return dataType;
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
index bed7a39b89..115ed06247 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
@@ -57,7 +57,6 @@ import static org.jooq.impl.Utils.settings;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
-import java.sql.Types;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -67,7 +66,6 @@ import java.util.Map;
import java.util.Set;
import org.jooq.AggregateFunction;
-// ...
import org.jooq.AttachableInternal;
import org.jooq.BindContext;
import org.jooq.Clause;
@@ -86,7 +84,6 @@ import org.jooq.Result;
import org.jooq.Routine;
import org.jooq.Schema;
import org.jooq.UDTField;
-import org.jooq.UDTRecord;
import org.jooq.exception.ControlFlowSignal;
import org.jooq.tools.Convert;
@@ -559,13 +556,22 @@ public abstract class AbstractRoutine extends AbstractQueryPart implements Ro
if (parameter.equals(getReturnParameter()) ||
getOutParameters().contains(parameter)) {
- int index = parameterIndexes.get(parameter);
- results.put(parameter, Utils.getFromStatement(ctx, parameter, index));
+ fetchOutParameter(ctx, parameter);
}
}
}
- @SuppressWarnings("unchecked")
+ private final void fetchOutParameter(ExecuteContext ctx, Parameter parameter) throws SQLException {
+ DefaultBindingGetStatementContext out = new DefaultBindingGetStatementContext(
+ ctx.configuration(),
+ (CallableStatement) ctx.statement(),
+ parameterIndexes.get(parameter)
+ );
+
+ parameter.getBinding().get(out);
+ results.put(parameter, out.value());
+ }
+
private final void registerOutParameters(Configuration c, CallableStatement statement) throws SQLException {
// Register all out / inout parameters according to their position
@@ -574,47 +580,15 @@ public abstract class AbstractRoutine extends AbstractQueryPart implements Ro
if (parameter.equals(getReturnParameter()) ||
getOutParameters().contains(parameter)) {
- int index = parameterIndexes.get(parameter);
- int sqlType = parameter.getDataType().getDataType(c).getSQLType();
-
- switch (c.dialect().family()) {
- /* [pro] xx
-
- xx xxx xxxx xxxx xxxxxxx xxxxx xxxxxx xxxxx xx xxxx
- xx xxxx xxx xxxx xxxx
- xxxx xxxxxxx x
- xx xxxxxxxx xx xxxxxxxxxxxxx x
- xxxxxxxxxxxx xxxxxx x xxxxx
- xxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxx
- x
-
- xxxx xx xxxxxxxx xx xxxxxxxxxxxx x
- xxxxxxxxxxxxxx xxxxxx x xxxxxxxxxxxxxxxxxxxxx
- xxxxxxxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
- x
-
- xx xxx xxxxxxx xxxxxxxxx xx xxx xx xxxxxxxx x xxxx
- xx xxxxxxx
- xxxx x
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx
- x
-
- xxxxxx
- x
-
- xx [/pro] */
- default: {
- statement.registerOutParameter(index, sqlType);
- break;
- }
- }
+ registerOutParameter(c, statement, parameter);
}
}
}
+ private final void registerOutParameter(Configuration c, CallableStatement statement, Parameter parameter) throws SQLException {
+ parameter.getBinding().register(new DefaultBindingRegisterContext(c, statement, parameterIndexes.get(parameter)));
+ }
+
// ------------------------------------------------------------------------
// Fetch routine results
// ------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractScope.java b/jOOQ/src/main/java/org/jooq/impl/AbstractScope.java
new file mode 100644
index 0000000000..3ecbdb6f28
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractScope.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jooq.Configuration;
+import org.jooq.SQLDialect;
+import org.jooq.Scope;
+import org.jooq.conf.Settings;
+
+/**
+ * @author Lukas Eder
+ */
+abstract class AbstractScope implements Scope {
+
+ private final Configuration configuration;
+ private final Map data;
+
+ AbstractScope(Configuration configuration) {
+ this.data = new HashMap();
+
+ // The Configuration can be null when unattached objects are
+ // executed or when unattached Records are stored...
+ if (configuration == null) {
+ configuration = new DefaultConfiguration();
+ }
+
+ this.configuration = configuration;
+ }
+
+ // ------------------------------------------------------------------------
+ // XXX Scope API
+ // ------------------------------------------------------------------------
+
+ @Override
+ public final Configuration configuration() {
+ return configuration;
+ }
+
+ @Override
+ public final Settings settings() {
+ return Utils.settings(configuration());
+ }
+
+ @Override
+ public final SQLDialect dialect() {
+ return Utils.configuration(configuration()).dialect();
+ }
+
+ @Override
+ public final SQLDialect family() {
+ return dialect().family();
+ }
+
+ @Override
+ public final Map data() {
+ return data;
+ }
+
+ @Override
+ public final Object data(Object key) {
+ return data.get(key);
+ }
+
+ @Override
+ public final Object data(Object key, Object value) {
+ return data.put(key, value);
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/ArrayRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/ArrayRecordImpl.java
index ee904d0ad7..3fbd9d18b8 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ArrayRecordImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ArrayRecordImpl.java
@@ -183,7 +183,7 @@ xxxxxx xxxxx xxxxxxxxxxxxxxxxxx xxxxxxx xxxxxxxxxxxxx xxxxxxxxxx xxxxxxxxxxxxxx
xxxxxxxxx
xxxxxxxxxxx
xxxxxx xxxxx xxxx xxxxxxxxxxxxxxxxxx xxxxxx xxxxxx xxxxxxxxxxxx x
- xxxxxxxxxxxxxxx xxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxx xxxxxxx
x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java
index 8851136434..97567bf2a1 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java
@@ -1471,7 +1471,9 @@ class CursorImpl implements Cursor {
* Utility method to prevent unnecessary unchecked conversions
*/
private final void setValue(AbstractRecord record, Field field, int index) throws SQLException {
- T value = Utils.getFromResultSet(ctx, field, index + 1);
+ DefaultBindingGetResultSetContext out = new DefaultBindingGetResultSetContext(ctx.configuration(), ctx.resultSet(), index + 1);
+ field.getBinding().get(out);
+ T value = out.value();
record.values[index] = value;
record.originals[index] = value;
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultArray.java b/jOOQ/src/main/java/org/jooq/impl/DefaultArray.java
new file mode 100644
index 0000000000..57a57ab505
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultArray.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import java.sql.Array;
+import java.sql.ResultSet;
+import java.util.Map;
+
+import org.jooq.SQLDialect;
+import org.jooq.exception.SQLDialectNotSupportedException;
+
+class DefaultArray implements Array {
+
+ private final SQLDialect dialect;
+ private final Object[] array;
+ private final Class> type;
+
+ public DefaultArray(SQLDialect dialect, Object[] array, Class> type) {
+ this.dialect = dialect;
+ this.array = array;
+ this.type = type;
+ }
+
+ @Override
+ public String getBaseTypeName() {
+ return DefaultDataType.getDataType(dialect, type.getComponentType()).getTypeName();
+ }
+
+ @Override
+ public int getBaseType() {
+ throw new SQLDialectNotSupportedException("Array.getBaseType()");
+ }
+
+ @Override
+ public Object getArray() {
+ return array;
+ }
+
+ @Override
+ public Object getArray(Map> map) {
+ return array;
+ }
+
+ @Override
+ public Object getArray(long index, int count) {
+ throw new SQLDialectNotSupportedException("Array.getArray(long, int)");
+ }
+
+ @Override
+ public Object getArray(long index, int count, Map> map) {
+ throw new SQLDialectNotSupportedException("Array.getArray(long, int, Map)");
+ }
+
+ @Override
+ public ResultSet getResultSet() {
+ throw new SQLDialectNotSupportedException("Array.getResultSet()");
+ }
+
+ @Override
+ public ResultSet getResultSet(Map> map) {
+ throw new SQLDialectNotSupportedException("Array.getResultSet(Map)");
+ }
+
+ @Override
+ public ResultSet getResultSet(long index, int count) {
+ throw new SQLDialectNotSupportedException("Array.getResultSet(long, int)");
+ }
+
+ @Override
+ public ResultSet getResultSet(long index, int count, Map> map) {
+ throw new SQLDialectNotSupportedException("Array.getResultSet(long, int, Map)");
+ }
+
+ @Override
+ public void free() {
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindContext.java
index de080e3058..e899666ab9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultBindContext.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindContext.java
@@ -40,364 +40,28 @@
*/
package org.jooq.impl;
-import static java.util.Arrays.asList;
-// ...
-// ...
-// ...
-import static org.jooq.SQLDialect.POSTGRES;
-import static org.jooq.SQLDialect.SQLITE;
-// ...
-// ...
-import static org.jooq.impl.DefaultExecuteContext.localTargetConnection;
-import static org.jooq.tools.reflect.Reflect.on;
-import static org.jooq.util.postgres.PostgresUtils.toPGArrayString;
-import static org.jooq.util.postgres.PostgresUtils.toPGInterval;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.sql.Array;
-import java.sql.Blob;
-import java.sql.Clob;
-import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.sql.Types;
-import java.util.Arrays;
-import java.util.UUID;
-// ...
import org.jooq.BindContext;
import org.jooq.Configuration;
-import org.jooq.Converter;
-import org.jooq.EnumType;
import org.jooq.Field;
-import org.jooq.SQLDialect;
-import org.jooq.UDTRecord;
-import org.jooq.exception.SQLDialectNotSupportedException;
-import org.jooq.tools.Convert;
-import org.jooq.tools.JooqLogger;
-import org.jooq.tools.jdbc.MockArray;
-import org.jooq.types.DayToSecond;
-import org.jooq.types.UByte;
-import org.jooq.types.UInteger;
-import org.jooq.types.ULong;
-import org.jooq.types.UShort;
-import org.jooq.types.YearToMonth;
/**
* @author Lukas Eder
*/
class DefaultBindContext extends AbstractBindContext {
- private static final JooqLogger log = JooqLogger.getLogger(DefaultBindContext.class);
-
DefaultBindContext(Configuration configuration, PreparedStatement stmt) {
super(configuration, stmt);
}
@Override
- @SuppressWarnings({ "unchecked", "rawtypes" })
+ @SuppressWarnings({ "unchecked" })
protected final BindContext bindValue0(Object value, Field> field) throws SQLException {
- SQLDialect dialect = configuration.dialect();
-
- // [#650] [#3108] Use the Field's Converter before actually binding any value
- Converter, ?> converter = field.getConverter();
- Class> type = converter.fromType();
- value = ((Converter) converter).to(value);
-
- if (log.isTraceEnabled()) {
- if (value != null && value.getClass().isArray() && value.getClass() != byte[].class) {
- log.trace("Binding variable " + peekIndex(), Arrays.asList((Object[]) value) + " (" + type + ")");
- }
- else {
- log.trace("Binding variable " + peekIndex(), value + " (" + type + ")");
- }
- }
-
- // Setting null onto a prepared statement is subtly different for every
- // SQL dialect. See the following section for details
- if (value == null) {
- int sqlType = DefaultDataType.getDataType(dialect, type).getSQLType();
-
- /* [pro] xx
- xx xxxxxxxxxxxx xxxxx xxxxx xxxx xx xx xxxxx xxxx xxxxx xxxx xxxx
- xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
- xxxxxx xxxxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxxxxx
- x
-
- xxxx
- xx [/pro] */
- // [#1126] Oracle's UDTs need to be bound with their type name
- if (UDTRecord.class.isAssignableFrom(type)) {
- String typeName = Utils.newRecord(false, (Class>) type)
- .operate(null)
- .getUDT()
- .getName();
- stmt.setNull(nextIndex(), sqlType, typeName);
- }
-
- // [#1225] [#1227] TODO Put this logic into DataType
- // Some dialects have trouble binding binary data as BLOB
- else if (asList(POSTGRES).contains(configuration.dialect()) && sqlType == Types.BLOB) {
- stmt.setNull(nextIndex(), Types.BINARY);
- }
-
- /* [pro] xx
- xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxx x
-
- xx xxxx xxxxxxxxxx xxxx xx xxxx xxxxxx xxxx xxx xxx xxxxxxxxx xxxxxx
- xx xxxxxxxxxxx xxxxx xxxxxxx xxx xxxxxxx
- xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- xxxxxx xxxxxxxxx x
- xxxx xxxxxxxxxxxxx
- xxxx xxxxxxxxxxxxxxxx
- xxxx xxxxxxxxxxxxxxxxxxxx
- xxxx xxxxxxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
- xxxxxx
-
- xxxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx
- xxxxxx
- x
- x
-
- xx xxxxxxx xxxxxxx xxx xxx xxxxxx xxxxxx xxxx xxx xxxx xxxxxxxx xxx xxx xxxx xxxxxx
- xx xxxxxx xxx xxx xxxxxxx xxxxx
- xxxx xx xxxxxxxx xx xxxxxxxxxxxxx xx xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
- xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx
- x
-
- xx [/pro] */
- // All other types can be set to null if the JDBC type is known
- else if (sqlType != Types.OTHER) {
- stmt.setNull(nextIndex(), sqlType);
- }
-
- /* [pro] xx
- xx xxxxxx xxx xxx xxxxxxx xxxxxxx xxxxx xxxxxx xx xxx xx xxxx
- xx xxxxxxxxxxx xxx
- xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxxxxx x
- xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx
- x
-
- xx xxxxxx xxx xxxxxxx xxxxxxx xxxxx xxx xx xxx xx xxxx xxxxx xxxxxxx
- xxxx xx xxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxx x
- xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
- x
-
- xx [/pro] */
- // [#729] In the absence of the correct JDBC type, try setObject
- else {
- stmt.setObject(nextIndex(), null);
- }
- }
- else {
-
- // Try to infer the bind value type from the actual bind value if possible.
- if (type == Object.class) {
- type = value.getClass();
- }
-
- if (type == Blob.class) {
- stmt.setBlob(nextIndex(), (Blob) value);
- }
- else if (type == Boolean.class) {
- /* [pro] xx
- xx xx xxxxxx xxxxxx xxxxxx xx xxxxx xxxxx xxxxx xx xxxxxxxxx xx xxxxxxxxxx xx xxxxxxx xxxxxxx
- xx xxxxxxxxxxxxxxxxx xx xxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx xxxxx x x x xxx
- xxxx
- xx [/pro] */
- stmt.setBoolean(nextIndex(), (Boolean) value);
- }
- else if (type == BigDecimal.class) {
- if (asList(SQLITE).contains(dialect.family())) {
- stmt.setString(nextIndex(), value.toString());
- }
- else {
- stmt.setBigDecimal(nextIndex(), (BigDecimal) value);
- }
- }
- else if (type == BigInteger.class) {
- if (asList(SQLITE).contains(dialect.family())) {
- stmt.setString(nextIndex(), value.toString());
- }
- else {
- stmt.setBigDecimal(nextIndex(), new BigDecimal((BigInteger) value));
- }
- }
- else if (type == Byte.class) {
- stmt.setByte(nextIndex(), (Byte) value);
- }
- else if (type == byte[].class) {
- stmt.setBytes(nextIndex(), (byte[]) value);
- }
- else if (type == Clob.class) {
- stmt.setClob(nextIndex(), (Clob) value);
- }
- else if (type == Double.class) {
- stmt.setDouble(nextIndex(), (Double) value);
- }
- else if (type == Float.class) {
- stmt.setFloat(nextIndex(), (Float) value);
- }
- else if (type == Integer.class) {
- stmt.setInt(nextIndex(), (Integer) value);
- }
- else if (type == Long.class) {
- /* [pro] xx
- xx xxxxxxxxxxxxxxxxx xx xxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
- xxxx
- xx [/pro] */
- stmt.setLong(nextIndex(), (Long) value);
- }
- else if (type == Short.class) {
- stmt.setShort(nextIndex(), (Short) value);
- }
- else if (type == String.class) {
- stmt.setString(nextIndex(), (String) value);
- }
-
- // There is potential for trouble when binding date time as such
- // -------------------------------------------------------------
- else if (type == Date.class) {
- if (dialect == SQLITE) {
- stmt.setString(nextIndex(), ((Date) value).toString());
- }
- else {
- stmt.setDate(nextIndex(), (Date) value);
- }
- }
- else if (type == Time.class) {
- if (dialect == SQLITE) {
- stmt.setString(nextIndex(), ((Time) value).toString());
- }
- else {
- stmt.setTime(nextIndex(), (Time) value);
- }
- }
- else if (type == Timestamp.class) {
- if (dialect == SQLITE) {
- stmt.setString(nextIndex(), ((Timestamp) value).toString());
- }
- else {
- stmt.setTimestamp(nextIndex(), (Timestamp) value);
- }
- }
-
- // [#566] Interval data types are best bound as Strings
- else if (type == YearToMonth.class) {
- if (dialect == POSTGRES) {
- stmt.setObject(nextIndex(), toPGInterval((YearToMonth) value));
- }
- else {
- stmt.setString(nextIndex(), value.toString());
- }
- }
- else if (type == DayToSecond.class) {
- if (dialect == POSTGRES) {
- stmt.setObject(nextIndex(), toPGInterval((DayToSecond) value));
- }
- else {
- stmt.setString(nextIndex(), value.toString());
- }
- }
- else if (type == UByte.class) {
- stmt.setShort(nextIndex(), ((UByte) value).shortValue());
- }
- else if (type == UShort.class) {
- stmt.setInt(nextIndex(), ((UShort) value).intValue());
- }
- else if (type == UInteger.class) {
- /* [pro] xx
- xx xxxxxxxxxxxxxxxxx xx xxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
- xxxx
- xx [/pro] */
- stmt.setLong(nextIndex(), ((UInteger) value).longValue());
- }
- else if (type == ULong.class) {
- /* [pro] xx
- xx xxxxxxxxxxxxxxxxx xx xxxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
- xxxx
- xx [/pro] */
- stmt.setBigDecimal(nextIndex(), new BigDecimal(value.toString()));
- }
- else if (type == UUID.class) {
- switch (dialect.family()) {
-
- // [#1624] Some JDBC drivers natively support the
- // java.util.UUID data type
- case H2:
- case POSTGRES: {
- stmt.setObject(nextIndex(), value);
- break;
- }
-
- /* [pro] xx
- xx xxxxx xxx xxxxxxxx xxxx xxxx xxxxx xx xx xxxx xxxx xxxxxxxx
- xx xxxx xx xxxx xxxxxxxxxx xxxxxxx xxxx xxxxxxxxxxxxxxxxxx
- xxxx xxxxxxxxxx
- xxxx xxxxxxx
-
- xx [/pro] */
- // Most databases don't have such a type. In this case, jOOQ
- // simulates the type
- default: {
- stmt.setString(nextIndex(), value.toString());
- break;
- }
- }
- }
-
- // The type byte[] is handled earlier. byte[][] can be handled here
- else if (type.isArray()) {
- switch (dialect) {
- case POSTGRES: {
- stmt.setString(nextIndex(), toPGArrayString((Object[]) value));
- break;
- }
- case HSQLDB: {
- Object[] a = (Object[]) value;
- Class> t = type;
-
- // [#2325] Some array types are not natively supported by HSQLDB
- // More integration tests are probably needed...
- if (type == UUID[].class) {
- a = Convert.convertArray(a, String[].class);
- t = String[].class;
- }
-
- stmt.setArray(nextIndex(), new MockArray(dialect, a, t));
- break;
- }
- case H2: {
- stmt.setObject(nextIndex(), value);
- break;
- }
- default:
- throw new SQLDialectNotSupportedException("Cannot bind ARRAY types in dialect " + dialect);
- }
- }
- /* [pro] xx
- xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
- xxxxxxxxxxxxxx xxxxxxxxxxx x xxxxxxxxxxxxxxxx xxxxxx
- xxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- x
- xx [/pro] */
- else if (EnumType.class.isAssignableFrom(type)) {
- stmt.setString(nextIndex(), ((EnumType) value).getLiteral());
- }
- else {
- stmt.setObject(nextIndex(), value);
- }
- }
+ ((Field) field).getBinding().set(
+ new DefaultBindingSetStatementContext(configuration(), stmt, nextIndex(), value)
+ );
return this;
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
new file mode 100644
index 0000000000..814f8d3798
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
@@ -0,0 +1,2080 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import static java.lang.Boolean.TRUE;
+import static java.lang.Integer.toOctalString;
+import static java.util.Arrays.asList;
+// ...
+// ...
+import static org.jooq.SQLDialect.CUBRID;
+// ...
+import static org.jooq.SQLDialect.DERBY;
+import static org.jooq.SQLDialect.FIREBIRD;
+import static org.jooq.SQLDialect.H2;
+import static org.jooq.SQLDialect.HSQLDB;
+// ...
+// ...
+import static org.jooq.SQLDialect.MARIADB;
+import static org.jooq.SQLDialect.MYSQL;
+// ...
+import static org.jooq.SQLDialect.POSTGRES;
+import static org.jooq.SQLDialect.SQLITE;
+// ...
+// ...
+import static org.jooq.conf.ParamType.INLINED;
+import static org.jooq.conf.ParamType.NAMED;
+import static org.jooq.conf.ParamType.NAMED_OR_INLINED;
+import static org.jooq.impl.DSL.name;
+import static org.jooq.impl.DSL.using;
+import static org.jooq.impl.DefaultExecuteContext.localTargetConnection;
+import static org.jooq.impl.Utils.needsBackslashEscaping;
+import static org.jooq.tools.StringUtils.leftPad;
+import static org.jooq.tools.jdbc.JDBCUtils.safeFree;
+import static org.jooq.tools.jdbc.JDBCUtils.wasNull;
+import static org.jooq.tools.reflect.Reflect.on;
+import static org.jooq.util.postgres.PostgresUtils.toPGArrayString;
+import static org.jooq.util.postgres.PostgresUtils.toPGInterval;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.List;
+import java.util.UUID;
+
+// ...
+import org.jooq.Binding;
+import org.jooq.BindingGetResultSetContext;
+import org.jooq.BindingGetSQLInputContext;
+import org.jooq.BindingGetStatementContext;
+import org.jooq.BindingRegisterContext;
+import org.jooq.BindingSQLContext;
+import org.jooq.BindingSetSQLOutputContext;
+import org.jooq.BindingSetStatementContext;
+import org.jooq.Configuration;
+import org.jooq.Context;
+import org.jooq.Converter;
+import org.jooq.DataType;
+import org.jooq.EnumType;
+import org.jooq.Field;
+import org.jooq.RenderContext;
+import org.jooq.Result;
+import org.jooq.Row;
+import org.jooq.SQLDialect;
+import org.jooq.Schema;
+import org.jooq.Scope;
+import org.jooq.UDTRecord;
+import org.jooq.exception.SQLDialectNotSupportedException;
+import org.jooq.tools.Convert;
+import org.jooq.tools.JooqLogger;
+import org.jooq.tools.StringUtils;
+import org.jooq.tools.jdbc.JDBCUtils;
+import org.jooq.tools.jdbc.MockArray;
+import org.jooq.types.DayToSecond;
+import org.jooq.types.Interval;
+import org.jooq.types.UByte;
+import org.jooq.types.UInteger;
+import org.jooq.types.ULong;
+import org.jooq.types.UNumber;
+import org.jooq.types.UShort;
+import org.jooq.types.YearToMonth;
+import org.jooq.util.postgres.PostgresUtils;
+
+/**
+ * @author Lukas Eder
+ */
+public class DefaultBinding implements Binding {
+
+ static final JooqLogger log = JooqLogger.getLogger(DefaultBinding.class);
+ private static final char[] HEX = "0123456789abcdef".toCharArray();
+
+ /**
+ * Generated UID
+ */
+ private static final long serialVersionUID = -198499389344950496L;
+
+ final Class type;
+ final Converter converter;
+
+ @Deprecated
+ // TODO: This type boolean should not be passed standalone to the
+ // constructor. Find a better design
+ final boolean isLob;
+ @Deprecated
+ final String paramName;
+
+ public DefaultBinding(Converter converter) {
+ this(converter, false, null);
+ }
+
+ DefaultBinding(Converter converter, boolean isLob) {
+ this(converter, isLob, null);
+ }
+
+ DefaultBinding(Converter converter, boolean isLob, String paramName) {
+ this.type = converter.fromType();
+ this.converter = converter;
+ this.isLob = isLob;
+ this.paramName = paramName;
+ }
+
+ @Override
+ public void sql(BindingSQLContext ctx) {
+ T converted = converter.to(ctx.value());
+
+ // Casting can be enforced or prevented
+ switch (ctx.render().castMode()) {
+ case NEVER:
+ toSQL(ctx, converted);
+ return;
+
+ case ALWAYS:
+ toSQLCast(ctx, converted);
+ return;
+ }
+
+ // See if we "should" cast, to stay on the safe side
+ if (shouldCast(ctx, converted)) {
+ toSQLCast(ctx, converted);
+ }
+
+ // Most RDBMS can infer types for bind values
+ else {
+ toSQL(ctx, converted);
+ }
+ }
+
+ private final boolean shouldCast(BindingSQLContext ctx, T converted) {
+
+ // In default mode, casting is only done when parameters are NOT inlined
+ if (ctx.render().paramType() != INLINED) {
+
+ // Generated enums should not be cast...
+ if (!(converted instanceof EnumType)) {
+ switch (ctx.family()) {
+
+ // These dialects can hardly detect the type of a bound constant.
+ /* [pro] xx
+ xxxx xxxx
+ xxxx xxxxxxxxx
+ xx [/pro] */
+ case DERBY:
+ case FIREBIRD:
+
+ // These dialects have some trouble, when they mostly get it right.
+ case H2:
+ case HSQLDB:
+
+ // [#1261] There are only a few corner-cases, where this is
+ // really needed. Check back on related CUBRID bugs
+ case CUBRID:
+
+ // [#1029] Postgres and [#632] Sybase need explicit casting
+ // in very rare cases.
+ /* [pro] xx
+ xxxx xxxxxxx
+ xx [/pro] */
+ case POSTGRES: {
+ return true;
+ }
+ }
+ }
+ }
+
+ // [#566] JDBC doesn't explicitly support interval data types. To be on
+ // the safe side, always cast these types in those dialects that support
+ // them
+ if (Interval.class.isAssignableFrom(type)) {
+ switch (ctx.family()) {
+ /* [pro] xx
+ xxxx xxxxxxx
+ xx [/pro] */
+ case POSTGRES:
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Render the bind variable including a cast, if necessary
+ */
+ private final void toSQLCast(BindingSQLContext ctx, T converted) {
+ DataType dataType = DefaultDataType.getDataType(ctx.dialect(), type);
+ DataType sqlDataType = dataType.getSQLDataType();
+ SQLDialect family = ctx.family();
+
+ // [#822] Some RDBMS need precision / scale information on BigDecimals
+ if (converted != null && type == BigDecimal.class && asList(CUBRID, DERBY, FIREBIRD, HSQLDB).contains(family)) {
+
+ // Add precision / scale on BigDecimals
+ int scale = ((BigDecimal) converted).scale();
+ int precision = scale + ((BigDecimal) converted).precision();
+
+ // Firebird's max precision is 18
+ if (family == FIREBIRD) {
+ precision = Math.min(precision, 18);
+ }
+
+ toSQLCast(ctx, converted, dataType, 0, precision, scale);
+ }
+
+ // [#1028] Most databases don't know an OTHER type (except H2, HSQLDB).
+ else if (SQLDataType.OTHER == sqlDataType) {
+
+ // If the bind value is set, it can be used to derive the cast type
+ if (converted != null) {
+ toSQLCast(ctx, converted, DefaultDataType.getDataType(family, converted.getClass()), 0, 0, 0);
+ }
+
+ // [#632] [#722] Current integration tests show that Ingres and
+ // Sybase can do without casting in most cases.
+ else if (asList().contains(family)) {
+ ctx.render().sql(getBindVariable(ctx.render()));
+ }
+
+ // Derby and DB2 must have a type associated with NULL. Use VARCHAR
+ // as a workaround. That's probably not correct in all cases, though
+ else {
+ toSQLCast(ctx, converted, DefaultDataType.getDataType(family, String.class), 0, 0, 0);
+ }
+ }
+
+ // [#1029] Postgres generally doesn't need the casting. Only in the
+ // above case where the type is OTHER
+ // [#1125] Also with temporal data types, casting is needed some times
+ // [#1130] TODO type can be null for ARRAY types, etc.
+ else if (family == POSTGRES && (sqlDataType == null || !sqlDataType.isTemporal())) {
+ toSQL(ctx, converted);
+ }
+
+ // [#1727] VARCHAR types should be cast to their actual lengths in some
+ // dialects
+ else if ((sqlDataType == SQLDataType.VARCHAR || sqlDataType == SQLDataType.CHAR) && asList(FIREBIRD).contains(family)) {
+ toSQLCast(ctx, converted, dataType, getValueLength(converted), 0, 0);
+ }
+
+ /* [pro] xx
+ xx xxxxxxx xxxx xxxx xxxxx xxxxxx xxx xx xxxx xx xxx xxxxxx xx xxxx xxxxxxxx
+ xxxx xx xxxxxxxxxxxx xx xxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxxxx xxxxxxxxxx xxxxxxxxx xx xx xxx
+ x
+ xx [/pro] */
+
+ // In all other cases, the bind variable can be cast normally
+ else {
+ toSQLCast(ctx, converted, dataType, dataType.length(), dataType.precision(), dataType.scale());
+ }
+ }
+
+ private final int getValueLength(T value) {
+ String string = (String) value;
+ if (string == null) {
+ return 1;
+ }
+
+ else {
+ int length = string.length();
+
+ // If non 7-bit ASCII characters are present, multiply the length by
+ // 4 to be sure that even UTF-32 collations will fit. But don't use
+ // larger numbers than Derby's upper limit 32672
+ for (int i = 0; i < length; i++) {
+ if (string.charAt(i) > 127) {
+ return Math.min(32672, 4 * length);
+ }
+ }
+
+ return Math.min(32672, length);
+ }
+ }
+
+ private final void toSQLCast(BindingSQLContext ctx, T converted, DataType> dataType, int length, int precision, int scale) {
+ ctx.render().keyword("cast").sql("(");
+ toSQL(ctx, converted);
+ ctx.render().sql(" ").keyword("as").sql(" ")
+ .sql(dataType.length(length).precision(precision, scale).getCastTypeName(ctx.configuration()))
+ .sql(")");
+ }
+
+ /**
+ * Get a bind variable, depending on value of
+ * {@link RenderContext#namedParams()}
+ */
+ private final String getBindVariable(RenderContext context) {
+ if (context.paramType() == NAMED || context.paramType() == NAMED_OR_INLINED) {
+ int index = context.nextIndex();
+
+ if (StringUtils.isBlank(paramName)) {
+ return ":" + index;
+ }
+ else {
+ return ":" + paramName;
+ }
+ }
+ else {
+ return "?";
+ }
+ }
+
+ /**
+ * Inlining abstraction
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private final void toSQL(BindingSQLContext ctx, Object val) {
+ SQLDialect family = ctx.family();
+ RenderContext render = ctx.render();
+
+ if (render.paramType() == INLINED) {
+ // [#2223] Some type-casts in this section may seem unnecessary, e.g.
+ // ((Boolean) val).toString(). They have been put in place to avoid
+ // accidental type confusions where type != val.getClass(), and thus
+ // SQL injection may occur
+
+ if (val == null) {
+ render.keyword("null");
+ }
+ else if (type == Boolean.class) {
+
+ // [#1153] Some dialects don't support boolean literals TRUE and FALSE
+ if (asList(FIREBIRD, SQLITE).contains(family)) {
+ render.sql(((Boolean) val) ? "1" : "0");
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxx xx xxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxx xxxx x xxxxx x xxxxxxx
+ x
+ xx [/pro] */
+ else {
+ render.keyword(((Boolean) val).toString());
+ }
+ }
+
+ // [#1154] Binary data cannot always be inlined
+ else if (type == byte[].class) {
+ byte[] binary = (byte[]) val;
+
+ if (asList().contains(family)) {
+ render.sql("0x")
+ .sql(convertBytesToHex(binary));
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxx xx xxxx x
+ xxxxxxxxxxxxxxxxxxxxxx
+ xxxxxxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ xxxxxxxxxxx
+ x
+ xx [/pro] */
+ else if (asList(DERBY, H2, HSQLDB, MARIADB, MYSQL, SQLITE).contains(family)) {
+ render.sql("X'")
+ .sql(convertBytesToHex(binary))
+ .sql("'");
+ }
+ else if (asList().contains(family)) {
+ render.keyword("hextoraw('")
+ .sql(convertBytesToHex(binary))
+ .sql("')");
+ }
+ else if (family == POSTGRES) {
+ render.sql("E'")
+ .sql(convertBytesToPostgresOctal(binary))
+ .keyword("'::bytea");
+ }
+
+ // This default behaviour is used in debug logging for dialects
+ // that do not support inlining binary data
+ else {
+ render.sql("X'")
+ .sql(convertBytesToHex(binary))
+ .sql("'");
+ }
+ }
+
+ // Interval extends Number, so let Interval come first!
+ else if (Interval.class.isAssignableFrom(type)) {
+ render.sql("'")
+ .sql(escape(val, render))
+ .sql("'");
+ }
+
+ else if (Number.class.isAssignableFrom(type)) {
+ render.sql(((Number) val).toString());
+ }
+
+ // [#1156] Date/Time data types should be inlined using JDBC
+ // escape syntax
+ else if (type == Date.class) {
+
+ // The SQLite JDBC driver does not implement the escape syntax
+ // [#1253] SQL Server and Sybase do not implement date literals
+ if (asList(SQLITE).contains(family)) {
+ render.sql("'").sql(escape(val, render)).sql("'");
+ }
+
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
+ x
+
+ xxxx xx xxxxxxx xx xxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxx
+ x
+ xx [/pro] */
+
+ // [#1253] Derby doesn't support the standard literal
+ else if (family == DERBY) {
+ render.keyword("date('").sql(escape(val, render)).sql("')");
+ }
+
+ // [#3648] Circumvent a MySQL bug related to date literals
+ else if (family == MYSQL) {
+ render.keyword("{d '").sql(escape(val, render)).sql("'}");
+ }
+
+ // Most dialects implement SQL standard date literals
+ else {
+ render.keyword("date '").sql(escape(val, render)).sql("'");
+ }
+ }
+ else if (type == Timestamp.class) {
+
+ // The SQLite JDBC driver does not implement the escape syntax
+ // [#1253] SQL Server and Sybase do not implement timestamp literals
+ if (asList(SQLITE).contains(family)) {
+ render.sql("'").sql(escape(val, render)).sql("'");
+ }
+
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
+ x
+
+ xxxx xx xxxxxxx xx xxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxxxxxxx
+ x
+ xx [/pro] */
+
+ // [#1253] Derby doesn't support the standard literal
+ else if (family == DERBY) {
+ render.keyword("timestamp('").sql(escape(val, render)).sql("')");
+ }
+
+ // CUBRID timestamps have no fractional seconds
+ else if (family == CUBRID) {
+ render.keyword("datetime '").sql(escape(val, render)).sql("'");
+ }
+
+ // [#3648] Circumvent a MySQL bug related to date literals
+ else if (family == MYSQL) {
+ render.keyword("{ts '").sql(escape(val, render)).sql("'}");
+ }
+
+ // Most dialects implement SQL standard timestamp literals
+ else {
+ render.keyword("timestamp '").sql(escape(val, render)).sql("'");
+ }
+ }
+ else if (type == Time.class) {
+
+ // The SQLite JDBC driver does not implement the escape syntax
+ // [#1253] SQL Server and Sybase do not implement time literals
+ if (asList(SQLITE).contains(family)) {
+ render.sql("'").sql(new SimpleDateFormat("HH:mm:ss").format((Time) val)).sql("'");
+ }
+
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx
+ x
+
+ xxxx xx xxxxxxx xx xxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xx xxxxxxxxx
+ x
+ xx [/pro] */
+
+ // [#1253] Derby doesn't support the standard literal
+ else if (family == DERBY) {
+ render.keyword("time").sql("('").sql(escape(val, render)).sql("')");
+ }
+
+ // [#3648] Circumvent a MySQL bug related to date literals
+ else if (family == MYSQL) {
+ render.keyword("{t '").sql(escape(val, render)).sql("'}");
+ }
+ /* [pro] xx
+ xx xxxxxxx xxxxxx xxxxxxx xxxx xxxx xxxxxxxx
+ xxxx xx xxxxxxx xx xxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx xxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
+ x
+
+ xx [/pro] */
+ // Most dialects implement SQL standard time literals
+ else {
+ render.keyword("time").sql(" '").sql(escape(val, render)).sql("'");
+ }
+ }
+ else if (type.isArray()) {
+ String separator = "";
+
+ // H2 renders arrays as rows
+ if (family == H2) {
+ render.sql("(");
+
+ for (Object o : ((Object[]) val)) {
+ render.sql(separator);
+ new DefaultBinding(new IdentityConverter(type.getComponentType()), isLob).sql(new DefaultBindingSQLContext(ctx.configuration(), ctx.render(), o));
+ separator = ", ";
+ }
+
+ render.sql(")");
+ }
+
+ // By default, render HSQLDB / POSTGRES syntax
+ else {
+ render.keyword("ARRAY");
+ render.sql("[");
+
+ for (Object o : ((Object[]) val)) {
+ render.sql(separator);
+ new DefaultBinding(new IdentityConverter(type.getComponentType()), isLob).sql(new DefaultBindingSQLContext(ctx.configuration(), ctx.render(), o));
+ separator = ", ";
+ }
+
+ render.sql("]");
+
+ // [#3214] Some PostgreSQL array type literals need explicit casting
+ if (family == POSTGRES && EnumType.class.isAssignableFrom(type.getComponentType())) {
+ render.sql("::")
+ .keyword(DefaultDataType.getDataType(family, type).getCastTypeName(render.configuration()));
+ }
+ }
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxx
+ x
+ xx [/pro] */
+ else if (EnumType.class.isAssignableFrom(type)) {
+ String literal = ((EnumType) val).getLiteral();
+
+ if (literal == null) {
+ new DefaultBinding(new IdentityConverter(String.class), isLob).sql(new DefaultBindingSQLContext(ctx.configuration(), ctx.render(), literal));
+ }
+ else {
+ new DefaultBinding(new IdentityConverter(String.class), isLob).sql(new DefaultBindingSQLContext(ctx.configuration(), ctx.render(), literal));
+ }
+ }
+ else if (UDTRecord.class.isAssignableFrom(type)) {
+ render.sql("[UDT]");
+ }
+
+ // Known fall-through types:
+ // - Blob, Clob (both not supported by jOOQ)
+ // - String
+ // - UUID
+ else {
+ render.sql("'")
+ .sql(escape(val, render), true)
+ .sql("'");
+ }
+ }
+
+ // In Postgres, some additional casting must be done in some cases...
+ else if (family == SQLDialect.POSTGRES) {
+
+ // Postgres needs explicit casting for array types
+ if (type.isArray() && byte[].class != type) {
+ render.sql(getBindVariable(render));
+ render.sql("::");
+ render.keyword(DefaultDataType.getDataType(family, type).getCastTypeName(render.configuration()));
+ }
+
+ // ... and also for enum types
+ else if (EnumType.class.isAssignableFrom(type)) {
+ render.sql(getBindVariable(render));
+
+ // [#968] Don't cast "synthetic" enum types (note, val can be null!)
+ EnumType e = (EnumType) type.getEnumConstants()[0];
+ Schema schema = e.getSchema();
+
+ if (schema != null) {
+ render.sql("::");
+
+ schema = using(render.configuration()).map(schema);
+ if (schema != null && TRUE.equals(render.configuration().settings().isRenderSchema())) {
+ render.visit(schema);
+ render.sql(".");
+ }
+
+ render.visit(name(e.getName()));
+ }
+ }
+
+ else {
+ render.sql(getBindVariable(render));
+ }
+ }
+
+ else {
+ render.sql(getBindVariable(render));
+ }
+ }
+
+ /**
+ * Escape a string literal by replacing ' by '', and possibly also backslashes.
+ */
+ private final String escape(Object val, Context> context) {
+ String result = val.toString();
+
+ if (needsBackslashEscaping(context.configuration()))
+ result = result.replace("\\", "\\\\");
+
+ return result.replace("'", "''");
+ }
+
+ /**
+ * Convert a byte array to a hex encoded string.
+ *
+ * @param value the byte array
+ * @return the hex encoded string
+ */
+ private static final String convertBytesToHex(byte[] value) {
+ return convertBytesToHex(value, value.length);
+ }
+
+ /**
+ * Convert a byte array to a hex encoded string.
+ *
+ * @param value the byte array
+ * @param len the number of bytes to encode
+ * @return the hex encoded string
+ */
+ private static final String convertBytesToHex(byte[] value, int len) {
+ char[] buff = new char[len + len];
+ char[] hex = HEX;
+ for (int i = 0; i < len; i++) {
+ int c = value[i] & 0xff;
+ buff[i + i] = hex[c >> 4];
+ buff[i + i + 1] = hex[c & 0xf];
+ }
+ return new String(buff);
+ }
+
+ /**
+ * Postgres uses octals instead of hex encoding
+ */
+ private static final String convertBytesToPostgresOctal(byte[] binary) {
+ StringBuilder sb = new StringBuilder();
+
+ for (byte b : binary) {
+ sb.append("\\\\");
+ sb.append(leftPad(toOctalString(b), 3, '0'));
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public void register(BindingRegisterContext ctx) throws SQLException {
+ Configuration configuration = ctx.configuration();
+ int sqlType = DefaultDataType.getDataType(ctx.dialect(), type).getSQLType();
+
+ switch (configuration.dialect().family()) {
+ /* [pro] xx
+
+ xx xxx xxxx xxxx xxxxxxx xxxxx xxxxxx xxxxx xx xxxx
+ xx xxxx xxx xxxx xxxx
+ xxxx xxxxxxx x
+ xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxx xxxxxx x xxxxx
+ xxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxx xxxxxxxxxxxxxx xxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxx
+ x
+
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxxxx xxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
+ x
+
+ xx xxx xxxxxxx xxxxxxxxx xx xxx xx xxxxxxxx x xxxx
+ xx xxxxxxx
+ xxxx x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx
+ x
+
+ xxxxxx
+ x
+
+ xx [/pro] */
+ default: {
+ ctx.statement().registerOutParameter(ctx.index(), sqlType);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void set(BindingSetStatementContext ctx) throws SQLException {
+ Configuration configuration = ctx.configuration();
+ SQLDialect dialect = ctx.dialect();
+ T value = converter.to(ctx.value());
+
+ if (log.isTraceEnabled()) {
+ if (value != null && value.getClass().isArray() && value.getClass() != byte[].class) {
+ log.trace("Binding variable " + ctx.index(), Arrays.asList((Object[]) value) + " (" + type + ")");
+ }
+ else {
+ log.trace("Binding variable " + ctx.index(), value + " (" + type + ")");
+ }
+ }
+
+ // Setting null onto a prepared statement is subtly different for every
+ // SQL dialect. See the following section for details
+ if (value == null) {
+ int sqlType = DefaultDataType.getDataType(dialect, type).getSQLType();
+
+ /* [pro] xx
+ xx xxxxxxxxxxxx xxxxx xxxxx xxxx xx xx xxxxx xxxx xxxxx xxxx xxxx
+ xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxx xxxxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxxxxx
+ x
+
+ xxxx
+ xx [/pro] */
+ // [#1126] Oracle's UDTs need to be bound with their type name
+ if (UDTRecord.class.isAssignableFrom(type)) {
+ String typeName = Utils.newRecord(false, (Class>) type)
+ .operate(null)
+ .getUDT()
+ .getName();
+ ctx.statement().setNull(ctx.index(), sqlType, typeName);
+ }
+
+ // [#1225] [#1227] TODO Put this logic into DataType
+ // Some dialects have trouble binding binary data as BLOB
+ else if (asList(POSTGRES).contains(configuration.dialect()) && sqlType == Types.BLOB) {
+ ctx.statement().setNull(ctx.index(), Types.BINARY);
+ }
+
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxx x
+
+ xx xxxx xxxxxxxxxx xxxx xx xxxx xxxxxx xxxx xxx xxx xxxxxxxxx xxxxxx
+ xx xxxxxxxxxxx xxxxx xxxxxxx xxx xxxxxxx
+ xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ xxxxxx xxxxxxxxx x
+ xxxx xxxxxxxxxxxxx
+ xxxx xxxxxxxxxxxxxxxx
+ xxxx xxxxxxxxxxxxxxxxxxxx
+ xxxx xxxxxxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
+ xxxxxx
+
+ xxxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx
+ xxxxxx
+ x
+ x
+
+ xx xxxxxxx xxxxxxx xxx xxx xxxxxx xxxxxx xxxx xxx xxxx xxxxxxxx xxx xxx xxxx xxxxxx
+ xx xxxxxx xxx xxx xxxxxxx xxxxx
+ xxxx xx xxxxxxxx xx xxxxxxxxxxxxx xx xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx
+ x
+
+ xx [/pro] */
+ // All other types can be set to null if the JDBC type is known
+ else if (sqlType != Types.OTHER) {
+ ctx.statement().setNull(ctx.index(), sqlType);
+ }
+
+ /* [pro] xx
+ xx xxxxxx xxx xxx xxxxxxx xxxxxxx xxxxx xxxxxx xx xxx xx xxxx
+ xx xxxxxxxxxxx xxx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx
+ x
+
+ xx xxxxxx xxx xxxxxxx xxxxxxx xxxxx xxx xx xxx xx xxxx xxxxx xxxxxxx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxx x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
+ x
+
+ xx [/pro] */
+ // [#729] In the absence of the correct JDBC type, try setObject
+ else {
+ ctx.statement().setObject(ctx.index(), null);
+ }
+ }
+ else {
+ Class> actualType = type;
+
+ // Try to infer the bind value type from the actual bind value if possible.
+ if (actualType == Object.class) {
+ actualType = value.getClass();
+ }
+
+ if (actualType == Blob.class) {
+ ctx.statement().setBlob(ctx.index(), (Blob) value);
+ }
+ else if (actualType == Boolean.class) {
+ /* [pro] xx
+ xx xx xxxxxx xxxxxx xxxxxx xx xxxxx xxxxx xxxxx xx xxxxxxxxx xx xxxxxxxxxx xx xxxxxxx xxxxxxx
+ xx xxxxxxxxxxxxxxxxx xx xxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx xxxxx x x x xxx
+ xxxx
+ xx [/pro] */
+ ctx.statement().setBoolean(ctx.index(), (Boolean) value);
+ }
+ else if (actualType == BigDecimal.class) {
+ if (asList(SQLITE).contains(dialect.family())) {
+ ctx.statement().setString(ctx.index(), value.toString());
+ }
+ else {
+ ctx.statement().setBigDecimal(ctx.index(), (BigDecimal) value);
+ }
+ }
+ else if (actualType == BigInteger.class) {
+ if (asList(SQLITE).contains(dialect.family())) {
+ ctx.statement().setString(ctx.index(), value.toString());
+ }
+ else {
+ ctx.statement().setBigDecimal(ctx.index(), new BigDecimal((BigInteger) value));
+ }
+ }
+ else if (actualType == Byte.class) {
+ ctx.statement().setByte(ctx.index(), (Byte) value);
+ }
+ else if (actualType == byte[].class) {
+ ctx.statement().setBytes(ctx.index(), (byte[]) value);
+ }
+ else if (actualType == Clob.class) {
+ ctx.statement().setClob(ctx.index(), (Clob) value);
+ }
+ else if (actualType == Double.class) {
+ ctx.statement().setDouble(ctx.index(), (Double) value);
+ }
+ else if (actualType == Float.class) {
+ ctx.statement().setFloat(ctx.index(), (Float) value);
+ }
+ else if (actualType == Integer.class) {
+ ctx.statement().setInt(ctx.index(), (Integer) value);
+ }
+ else if (actualType == Long.class) {
+ /* [pro] xx
+ xx xxxxxxxxxxxxxxxxx xx xxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
+ xxxx
+ xx [/pro] */
+ ctx.statement().setLong(ctx.index(), (Long) value);
+ }
+ else if (actualType == Short.class) {
+ ctx.statement().setShort(ctx.index(), (Short) value);
+ }
+ else if (actualType == String.class) {
+ ctx.statement().setString(ctx.index(), (String) value);
+ }
+
+ // There is potential for trouble when binding date time as such
+ // -------------------------------------------------------------
+ else if (actualType == Date.class) {
+ if (dialect == SQLITE) {
+ ctx.statement().setString(ctx.index(), ((Date) value).toString());
+ }
+ else {
+ ctx.statement().setDate(ctx.index(), (Date) value);
+ }
+ }
+ else if (actualType == Time.class) {
+ if (dialect == SQLITE) {
+ ctx.statement().setString(ctx.index(), ((Time) value).toString());
+ }
+ else {
+ ctx.statement().setTime(ctx.index(), (Time) value);
+ }
+ }
+ else if (actualType == Timestamp.class) {
+ if (dialect == SQLITE) {
+ ctx.statement().setString(ctx.index(), ((Timestamp) value).toString());
+ }
+ else {
+ ctx.statement().setTimestamp(ctx.index(), (Timestamp) value);
+ }
+ }
+
+ // [#566] Interval data types are best bound as Strings
+ else if (actualType == YearToMonth.class) {
+ if (dialect == POSTGRES) {
+ ctx.statement().setObject(ctx.index(), toPGInterval((YearToMonth) value));
+ }
+ else {
+ ctx.statement().setString(ctx.index(), value.toString());
+ }
+ }
+ else if (actualType == DayToSecond.class) {
+ if (dialect == POSTGRES) {
+ ctx.statement().setObject(ctx.index(), toPGInterval((DayToSecond) value));
+ }
+ else {
+ ctx.statement().setString(ctx.index(), value.toString());
+ }
+ }
+ else if (actualType == UByte.class) {
+ ctx.statement().setShort(ctx.index(), ((UByte) value).shortValue());
+ }
+ else if (actualType == UShort.class) {
+ ctx.statement().setInt(ctx.index(), ((UShort) value).intValue());
+ }
+ else if (actualType == UInteger.class) {
+ /* [pro] xx
+ xx xxxxxxxxxxxxxxxxx xx xxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
+ xxxx
+ xx [/pro] */
+ ctx.statement().setLong(ctx.index(), ((UInteger) value).longValue());
+ }
+ else if (actualType == ULong.class) {
+ /* [pro] xx
+ xx xxxxxxxxxxxxxxxxx xx xxxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
+ xxxx
+ xx [/pro] */
+ ctx.statement().setBigDecimal(ctx.index(), new BigDecimal(value.toString()));
+ }
+ else if (actualType == UUID.class) {
+ switch (dialect.family()) {
+
+ // [#1624] Some JDBC drivers natively support the
+ // java.util.UUID data type
+ case H2:
+ case POSTGRES: {
+ ctx.statement().setObject(ctx.index(), value);
+ break;
+ }
+
+ /* [pro] xx
+ xx xxxxx xxx xxxxxxxx xxxx xxxx xxxxx xx xx xxxx xxxx xxxxxxxx
+ xx xxxx xx xxxx xxxxxxxxxx xxxxxxx xxxx xxxxxxxxxxxxxxxxxx
+ xxxx xxxxxxxxxx
+ xxxx xxxxxxx
+
+ xx [/pro] */
+ // Most databases don't have such a type. In this case, jOOQ
+ // simulates the type
+ default: {
+ ctx.statement().setString(ctx.index(), value.toString());
+ break;
+ }
+ }
+ }
+
+ // The type byte[] is handled earlier. byte[][] can be handled here
+ else if (actualType.isArray()) {
+ switch (dialect) {
+ case POSTGRES: {
+ ctx.statement().setString(ctx.index(), toPGArrayString((Object[]) value));
+ break;
+ }
+ case HSQLDB: {
+ Object[] a = (Object[]) value;
+ Class> t = actualType;
+
+ // [#2325] Some array types are not natively supported by HSQLDB
+ // More integration tests are probably needed...
+ if (actualType == UUID[].class) {
+ a = Convert.convertArray(a, String[].class);
+ t = String[].class;
+ }
+
+ ctx.statement().setArray(ctx.index(), new MockArray(dialect, a, t));
+ break;
+ }
+ case H2: {
+ ctx.statement().setObject(ctx.index(), value);
+ break;
+ }
+ default:
+ throw new SQLDialectNotSupportedException("Cannot bind ARRAY types in dialect " + dialect);
+ }
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxxxxxxxxxx xxxxxxxxxxx x xxxxxxxxxxxxxxxx xxxxxx
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ x
+ xx [/pro] */
+ else if (EnumType.class.isAssignableFrom(actualType)) {
+ ctx.statement().setString(ctx.index(), ((EnumType) value).getLiteral());
+ }
+ else {
+ ctx.statement().setObject(ctx.index(), value);
+ }
+ }
+ }
+
+ @Override
+ public void set(BindingSetSQLOutputContext ctx) throws SQLException {
+ T value = converter.to(ctx.value());
+ if (value == null) {
+ ctx.output().writeObject(null);
+ }
+ else if (type == Blob.class) {
+ ctx.output().writeBlob((Blob) value);
+ }
+ else if (type == Boolean.class) {
+ ctx.output().writeBoolean((Boolean) value);
+ }
+ else if (type == BigInteger.class) {
+ ctx.output().writeBigDecimal(new BigDecimal((BigInteger) value));
+ }
+ else if (type == BigDecimal.class) {
+ ctx.output().writeBigDecimal((BigDecimal) value);
+ }
+ else if (type == Byte.class) {
+ ctx.output().writeByte((Byte) value);
+ }
+ else if (type == byte[].class) {
+
+ // [#1327] Oracle cannot serialise BLOBs as byte[] to SQLOutput
+ // Use reflection to avoid dependency on OJDBC
+ if (isLob) {
+ Blob blob = null;
+
+ try {
+ blob = on("oracle.sql.BLOB").call("createTemporary",
+ on(ctx.output()).call("getSTRUCT")
+ .call("getJavaSqlConnection").get(),
+ false,
+ on("oracle.sql.BLOB").get("DURATION_SESSION")).get();
+
+ blob.setBytes(1, (byte[]) value);
+ ctx.output().writeBlob(blob);
+ }
+ finally {
+ DefaultExecuteContext.register(blob);
+ }
+ }
+ else {
+ ctx.output().writeBytes((byte[]) value);
+ }
+ }
+ else if (type == Clob.class) {
+ ctx.output().writeClob((Clob) value);
+ }
+ else if (type == Date.class) {
+ ctx.output().writeDate((Date) value);
+ }
+ else if (type == Double.class) {
+ ctx.output().writeDouble((Double) value);
+ }
+ else if (type == Float.class) {
+ ctx.output().writeFloat((Float) value);
+ }
+ else if (type == Integer.class) {
+ ctx.output().writeInt((Integer) value);
+ }
+ else if (type == Long.class) {
+ ctx.output().writeLong((Long) value);
+ }
+ else if (type == Short.class) {
+ ctx.output().writeShort((Short) value);
+ }
+ else if (type == String.class) {
+
+ // [#1327] Oracle cannot serialise CLOBs as String to SQLOutput
+ // Use reflection to avoid dependency on OJDBC
+ if (isLob) {
+ Clob clob = null;
+
+ try {
+ clob = on("oracle.sql.CLOB").call("createTemporary",
+ on(ctx.output()).call("getSTRUCT")
+ .call("getJavaSqlConnection").get(),
+ false,
+ on("oracle.sql.CLOB").get("DURATION_SESSION")).get();
+
+ clob.setString(1, (String) value);
+ ctx.output().writeClob(clob);
+ }
+ finally {
+ DefaultExecuteContext.register(clob);
+ }
+ }
+ else {
+ ctx.output().writeString((String) value);
+ }
+ }
+ else if (type == Time.class) {
+ ctx.output().writeTime((Time) value);
+ }
+ else if (type == Timestamp.class) {
+ ctx.output().writeTimestamp((Timestamp) value);
+ }
+ else if (type == YearToMonth.class) {
+ ctx.output().writeString(value.toString());
+ }
+ else if (type == DayToSecond.class) {
+ ctx.output().writeString(value.toString());
+ }
+// else if (type.isArray()) {
+// stream.writeArray(value);
+// }
+ else if (UNumber.class.isAssignableFrom(type)) {
+ ctx.output().writeString(value.toString());
+ }
+ else if (type == UUID.class) {
+ ctx.output().writeString(value.toString());
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+
+ xx xxxxxxx xx xxx xxxxxx xxxxxx xxxx xxxxxxxxxxxxxxxxxx xxx xxxx
+ xx xxx xx xxxxxxxxxxxxxxxxxxx xxxxx xx xxxxxxxxxxx xxxxxx xx xxxxxx
+ xxxxxxxxxxxxxx xxxxxxxxxxx x xxxxxxxxxxxxxxxx xxxxxx
+ xxxxxxxx xxxxx x xxxxxxxxxxxxxxxxxx
+
+ xx xxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxx xxxxxxxxxxxxxxxxxx x
+ xxxxxxxx xxxxxxxxx x xxx xxxxxxxxxxxxxxxxxxxxx
+
+ xxx xxxx x x xx x x xxxxxxxxxxxxxxxxx xxxx
+ xxxxxxxxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
+ xxxxx x xxxxxxxxxx
+ x
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxx
+ x
+ xx [/pro] */
+ else if (EnumType.class.isAssignableFrom(type)) {
+ ctx.output().writeString(((EnumType) value).getLiteral());
+ }
+ else if (UDTRecord.class.isAssignableFrom(type)) {
+ ctx.output().writeObject((UDTRecord>) value);
+ }
+ else {
+ throw new UnsupportedOperationException("Type " + type + " is not supported");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void get(BindingGetResultSetContext ctx) throws SQLException {
+ T result = null;
+
+ if (type == Blob.class) {
+ result = (T) ctx.resultSet().getBlob(ctx.index());
+ }
+ else if (type == Boolean.class) {
+ result = (T) wasNull(ctx.resultSet(), Boolean.valueOf(ctx.resultSet().getBoolean(ctx.index())));
+ }
+ else if (type == BigInteger.class) {
+ // The SQLite JDBC driver doesn't support BigDecimals
+ if (ctx.configuration().dialect() == SQLDialect.SQLITE) {
+ result = Convert.convert(ctx.resultSet().getString(ctx.index()), (Class) BigInteger.class);
+ }
+ else {
+ BigDecimal b = ctx.resultSet().getBigDecimal(ctx.index());
+ result = (T) (b == null ? null : b.toBigInteger());
+ }
+ }
+ else if (type == BigDecimal.class) {
+ // The SQLite JDBC driver doesn't support BigDecimals
+ if (ctx.configuration().dialect() == SQLDialect.SQLITE) {
+ result = Convert.convert(ctx.resultSet().getString(ctx.index()), (Class) BigDecimal.class);
+ }
+ else {
+ result = (T) ctx.resultSet().getBigDecimal(ctx.index());
+ }
+ }
+ else if (type == Byte.class) {
+ result = (T) wasNull(ctx.resultSet(), Byte.valueOf(ctx.resultSet().getByte(ctx.index())));
+ }
+ else if (type == byte[].class) {
+ result = (T) ctx.resultSet().getBytes(ctx.index());
+ }
+ else if (type == Clob.class) {
+ result = (T) ctx.resultSet().getClob(ctx.index());
+ }
+ else if (type == Date.class) {
+ result = (T) getDate(ctx.configuration().dialect(), ctx.resultSet(), ctx.index());
+ }
+ else if (type == Double.class) {
+ result = (T) wasNull(ctx.resultSet(), Double.valueOf(ctx.resultSet().getDouble(ctx.index())));
+ }
+ else if (type == Float.class) {
+ result = (T) wasNull(ctx.resultSet(), Float.valueOf(ctx.resultSet().getFloat(ctx.index())));
+ }
+ else if (type == Integer.class) {
+ result = (T) wasNull(ctx.resultSet(), Integer.valueOf(ctx.resultSet().getInt(ctx.index())));
+ }
+ else if (type == Long.class) {
+ result = (T) wasNull(ctx.resultSet(), Long.valueOf(ctx.resultSet().getLong(ctx.index())));
+ }
+ else if (type == Short.class) {
+ result = (T) wasNull(ctx.resultSet(), Short.valueOf(ctx.resultSet().getShort(ctx.index())));
+ }
+ else if (type == String.class) {
+ result = (T) ctx.resultSet().getString(ctx.index());
+ }
+ else if (type == Time.class) {
+ result = (T) getTime(ctx.configuration().dialect(), ctx.resultSet(), ctx.index());
+ }
+ else if (type == Timestamp.class) {
+ result = (T) getTimestamp(ctx.configuration().dialect(), ctx.resultSet(), ctx.index());
+ }
+ else if (type == YearToMonth.class) {
+ if (ctx.configuration().dialect() == POSTGRES) {
+ Object object = ctx.resultSet().getObject(ctx.index());
+ result = (T) (object == null ? null : PostgresUtils.toYearToMonth(object));
+ }
+ else {
+ String string = ctx.resultSet().getString(ctx.index());
+ result = (T) (string == null ? null : YearToMonth.valueOf(string));
+ }
+ }
+ else if (type == DayToSecond.class) {
+ if (ctx.configuration().dialect() == POSTGRES) {
+ Object object = ctx.resultSet().getObject(ctx.index());
+ result = (T) (object == null ? null : PostgresUtils.toDayToSecond(object));
+ }
+ else {
+ String string = ctx.resultSet().getString(ctx.index());
+ result = (T) (string == null ? null : DayToSecond.valueOf(string));
+ }
+ }
+ else if (type == UByte.class) {
+ result = (T) Convert.convert(ctx.resultSet().getString(ctx.index()), UByte.class);
+ }
+ else if (type == UShort.class) {
+ result = (T) Convert.convert(ctx.resultSet().getString(ctx.index()), UShort.class);
+ }
+ else if (type == UInteger.class) {
+ result = (T) Convert.convert(ctx.resultSet().getString(ctx.index()), UInteger.class);
+ }
+ else if (type == ULong.class) {
+ result = (T) Convert.convert(ctx.resultSet().getString(ctx.index()), ULong.class);
+ }
+ else if (type == UUID.class) {
+ switch (ctx.configuration().dialect().family()) {
+
+ // [#1624] Some JDBC drivers natively support the
+ // java.util.UUID data type
+ case H2:
+ case POSTGRES: {
+ result = (T) ctx.resultSet().getObject(ctx.index());
+ break;
+ }
+
+ /* [pro] xx
+ xx xxxxx xxx xxxxxxxx xxxx xxxx xxxxx xx xx xxxx xxxx xxxxxxxx
+ xx xxxx xx xxxx xxxxxxxxxx xxxxxxx xxxx xxxxxxxxxxxxxxxxxx
+ xxxx xxxxxxxxxx
+ xxxx xxxxxxx
+
+ xx [/pro] */
+ // Most databases don't have such a type. In this case, jOOQ
+ // simulates the type
+ default: {
+ result = (T) Convert.convert(ctx.resultSet().getString(ctx.index()), UUID.class);
+ break;
+ }
+ }
+ }
+
+ // The type byte[] is handled earlier. byte[][] can be handled here
+ else if (type.isArray()) {
+ switch (ctx.configuration().dialect()) {
+ case POSTGRES: {
+ result = pgGetArray(ctx, ctx.resultSet(), type, ctx.index());
+ break;
+ }
+
+ default:
+ // Note: due to a HSQLDB bug, it is not recommended to call rs.getObject() here:
+ // See https://sourceforge.net/tracker/?func=detail&aid=3181365&group_id=23316&atid=378131
+ result = (T) convertArray(ctx.resultSet().getArray(ctx.index()), (Class extends Object[]>) type);
+ break;
+ }
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxx x xxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxx
+ x
+ xx [/pro] */
+ else if (EnumType.class.isAssignableFrom(type)) {
+ result = getEnumType(type, ctx.resultSet().getString(ctx.index()));
+ }
+ else if (UDTRecord.class.isAssignableFrom(type)) {
+ switch (ctx.configuration().dialect()) {
+ case POSTGRES:
+ result = (T) pgNewUDTRecord(type, ctx.resultSet().getObject(ctx.index()));
+ break;
+
+ default:
+ result = (T) ctx.resultSet().getObject(ctx.index(), DataTypes.udtRecords());
+ break;
+ }
+
+ }
+ else if (Result.class.isAssignableFrom(type)) {
+ ResultSet nested = (ResultSet) ctx.resultSet().getObject(ctx.index());
+ result = (T) DSL.using(ctx.configuration()).fetch(nested);
+ }
+ else {
+ result = (T) unlob(ctx.resultSet().getObject(ctx.index()));
+ }
+
+ ctx.value(converter.from(result));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void get(BindingGetStatementContext ctx) throws SQLException {
+ T result = null;
+
+ if (type == Blob.class) {
+ result = (T) ctx.statement().getBlob(ctx.index());
+ }
+ else if (type == Boolean.class) {
+ result = (T) wasNull(ctx.statement(), Boolean.valueOf(ctx.statement().getBoolean(ctx.index())));
+ }
+ else if (type == BigInteger.class) {
+ BigDecimal d = ctx.statement().getBigDecimal(ctx.index());
+ result = (T) (d == null ? null : d.toBigInteger());
+ }
+ else if (type == BigDecimal.class) {
+ result = (T) ctx.statement().getBigDecimal(ctx.index());
+ }
+ else if (type == Byte.class) {
+ result = (T) wasNull(ctx.statement(), Byte.valueOf(ctx.statement().getByte(ctx.index())));
+ }
+ else if (type == byte[].class) {
+ result = (T) ctx.statement().getBytes(ctx.index());
+ }
+ else if (type == Clob.class) {
+ result = (T) ctx.statement().getClob(ctx.index());
+ }
+ else if (type == Date.class) {
+ result = (T) ctx.statement().getDate(ctx.index());
+ }
+ else if (type == Double.class) {
+ result = (T) wasNull(ctx.statement(), Double.valueOf(ctx.statement().getDouble(ctx.index())));
+ }
+ else if (type == Float.class) {
+ result = (T) wasNull(ctx.statement(), Float.valueOf(ctx.statement().getFloat(ctx.index())));
+ }
+ else if (type == Integer.class) {
+ result = (T) wasNull(ctx.statement(), Integer.valueOf(ctx.statement().getInt(ctx.index())));
+ }
+ else if (type == Long.class) {
+ result = (T) wasNull(ctx.statement(), Long.valueOf(ctx.statement().getLong(ctx.index())));
+ }
+ else if (type == Short.class) {
+ result = (T) wasNull(ctx.statement(), Short.valueOf(ctx.statement().getShort(ctx.index())));
+ }
+ else if (type == String.class) {
+ result = (T) ctx.statement().getString(ctx.index());
+ }
+ else if (type == Time.class) {
+ result = (T) ctx.statement().getTime(ctx.index());
+ }
+ else if (type == Timestamp.class) {
+ result = (T) ctx.statement().getTimestamp(ctx.index());
+ }
+ else if (type == YearToMonth.class) {
+ if (ctx.configuration().dialect() == POSTGRES) {
+ Object object = ctx.statement().getObject(ctx.index());
+ result = (T) (object == null ? null : PostgresUtils.toYearToMonth(object));
+ }
+ else {
+ String string = ctx.statement().getString(ctx.index());
+ result = (T) (string == null ? null : YearToMonth.valueOf(string));
+ }
+ }
+ else if (type == DayToSecond.class) {
+ if (ctx.configuration().dialect() == POSTGRES) {
+ Object object = ctx.statement().getObject(ctx.index());
+ result = (T) (object == null ? null : PostgresUtils.toDayToSecond(object));
+ }
+ else {
+ String string = ctx.statement().getString(ctx.index());
+ result = (T) (string == null ? null : DayToSecond.valueOf(string));
+ }
+ }
+ else if (type == UByte.class) {
+ String string = ctx.statement().getString(ctx.index());
+ result = (T) (string == null ? null : UByte.valueOf(string));
+ }
+ else if (type == UShort.class) {
+ String string = ctx.statement().getString(ctx.index());
+ result = (T) (string == null ? null : UShort.valueOf(string));
+ }
+ else if (type == UInteger.class) {
+ String string = ctx.statement().getString(ctx.index());
+ result = (T) (string == null ? null : UInteger.valueOf(string));
+ }
+ else if (type == ULong.class) {
+ String string = ctx.statement().getString(ctx.index());
+ result = (T) (string == null ? null : ULong.valueOf(string));
+ }
+ else if (type == UUID.class) {
+ switch (ctx.configuration().dialect().family()) {
+
+ // [#1624] Some JDBC drivers natively support the
+ // java.util.UUID data type
+ case H2:
+ case POSTGRES: {
+ result = (T) ctx.statement().getObject(ctx.index());
+ break;
+ }
+
+ /* [pro] xx
+ xx xxxxx xxx xxxxxxxx xxxx xxxx xxxxx xx xx xxxx xxxx xxxxxxxx
+ xx xxxx xx xxxx xxxxxxxxxx xxxxxxx xxxx xxxxxxxxxxxxxxxxxx
+ xxxx xxxxxxxxxx
+ xxxx xxxxxxx
+
+ xx [/pro] */
+ // Most databases don't have such a type. In this case, jOOQ
+ // simulates the type
+ default: {
+ result = (T) Convert.convert(ctx.statement().getString(ctx.index()), UUID.class);
+ break;
+ }
+ }
+ }
+
+ // The type byte[] is handled earlier. byte[][] can be handled here
+ else if (type.isArray()) {
+ result = (T) convertArray(ctx.statement().getObject(ctx.index()), (Class extends Object[]>)type);
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxx x xxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxx
+ x
+ xx [/pro] */
+ else if (EnumType.class.isAssignableFrom(type)) {
+ result = getEnumType(type, ctx.statement().getString(ctx.index()));
+ }
+ else if (UDTRecord.class.isAssignableFrom(type)) {
+ switch (ctx.configuration().dialect()) {
+ case POSTGRES:
+ result = (T) pgNewUDTRecord(type, ctx.statement().getObject(ctx.index()));
+ break;
+
+ default:
+ result = (T) ctx.statement().getObject(ctx.index(), DataTypes.udtRecords());
+ break;
+ }
+ }
+ else if (Result.class.isAssignableFrom(type)) {
+ ResultSet nested = (ResultSet) ctx.statement().getObject(ctx.index());
+ result = (T) DSL.using(ctx.configuration()).fetch(nested);
+ }
+ else {
+ result = (T) ctx.statement().getObject(ctx.index());
+ }
+
+ ctx.value(converter.from(result));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void get(BindingGetSQLInputContext ctx) throws SQLException {
+ T result = null;
+
+ if (type == Blob.class) {
+ result = (T) ctx.input().readBlob();
+ }
+ else if (type == Boolean.class) {
+ result = (T) wasNull(ctx.input(), Boolean.valueOf(ctx.input().readBoolean()));
+ }
+ else if (type == BigInteger.class) {
+ BigDecimal d = ctx.input().readBigDecimal();
+ result = (T) (d == null ? null : d.toBigInteger());
+ }
+ else if (type == BigDecimal.class) {
+ result = (T) ctx.input().readBigDecimal();
+ }
+ else if (type == Byte.class) {
+ result = (T) wasNull(ctx.input(), Byte.valueOf(ctx.input().readByte()));
+ }
+ else if (type == byte[].class) {
+
+ // [#1327] Oracle cannot deserialise BLOBs as byte[] from SQLInput
+ if (isLob) {
+ Blob blob = null;
+ try {
+ blob = ctx.input().readBlob();
+ result = (T) (blob == null ? null : blob.getBytes(1, (int) blob.length()));
+ }
+ finally {
+ safeFree(blob);
+ }
+ }
+ else {
+ result = (T) ctx.input().readBytes();
+ }
+ }
+ else if (type == Clob.class) {
+ result = (T) ctx.input().readClob();
+ }
+ else if (type == Date.class) {
+ result = (T) ctx.input().readDate();
+ }
+ else if (type == Double.class) {
+ result = (T) wasNull(ctx.input(), Double.valueOf(ctx.input().readDouble()));
+ }
+ else if (type == Float.class) {
+ result = (T) wasNull(ctx.input(), Float.valueOf(ctx.input().readFloat()));
+ }
+ else if (type == Integer.class) {
+ result = (T) wasNull(ctx.input(), Integer.valueOf(ctx.input().readInt()));
+ }
+ else if (type == Long.class) {
+ result = (T) wasNull(ctx.input(), Long.valueOf(ctx.input().readLong()));
+ }
+ else if (type == Short.class) {
+ result = (T) wasNull(ctx.input(), Short.valueOf(ctx.input().readShort()));
+ }
+ else if (type == String.class) {
+ result = (T) ctx.input().readString();
+ }
+ else if (type == Time.class) {
+ result = (T) ctx.input().readTime();
+ }
+ else if (type == Timestamp.class) {
+ result = (T) ctx.input().readTimestamp();
+ }
+ else if (type == YearToMonth.class) {
+ String string = ctx.input().readString();
+ result = (T) (string == null ? null : YearToMonth.valueOf(string));
+ }
+ else if (type == DayToSecond.class) {
+ String string = ctx.input().readString();
+ result = (T) (string == null ? null : DayToSecond.valueOf(string));
+ }
+ else if (type == UByte.class) {
+ String string = ctx.input().readString();
+ result = (T) (string == null ? null : UByte.valueOf(string));
+ }
+ else if (type == UShort.class) {
+ String string = ctx.input().readString();
+ result = (T) (string == null ? null : UShort.valueOf(string));
+ }
+ else if (type == UInteger.class) {
+ String string = ctx.input().readString();
+ result = (T) (string == null ? null : UInteger.valueOf(string));
+ }
+ else if (type == ULong.class) {
+ String string = ctx.input().readString();
+ result = (T) (string == null ? null : ULong.valueOf(string));
+ }
+ else if (type == UUID.class) {
+ result = (T) Convert.convert(ctx.input().readString(), UUID.class);
+ }
+
+ // The type byte[] is handled earlier. byte[][] can be handled here
+ else if (type.isArray()) {
+ Array array = ctx.input().readArray();
+ result = (T) (array == null ? null : array.getArray());
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xxxxxx x xxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxx xxxxxxxxxxxxxxxx xxxxxx
+ x
+ xx [/pro] */
+ else if (EnumType.class.isAssignableFrom(type)) {
+ result = getEnumType(type, ctx.input().readString());
+ }
+ else if (UDTRecord.class.isAssignableFrom(type)) {
+ result = (T) ctx.input().readObject();
+ }
+ else {
+ result = (T) unlob(ctx.input().readObject());
+ }
+
+ ctx.value(converter.from(result));
+ }
+
+
+
+
+ /* [pro] xx
+ xxxxxxx xxxxxx xxxxx xxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxx xxxxx xxxxxx xxxxxxx xxxxxxx xxxxxxxxxxxxxxx xxxxx xxxxxx xxxxxxxxxxxx x
+ xx xxxxxx xx xxxxx x
+ xxxxxx xxxxx
+ x
+ xxxx x
+ xx xxxxx xxxxxx xxx xxxxx xxxxxx xxxx xxxx xxxxxxx
+ xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxx
+ x
+ x
+
+ xxxxxx xxxxx xxx xxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx xxxxxxx xxxxx xxxxxxx xxxxxx xxxxxxxxxxxx x
+ xx xxxxxxx xx xxxxx x
+ xxxxxxxxxxxxxxxx xxxxxx
+ x
+ xxxx x
+ xx xxxxxx xxxxx xxxxxx xxxx xx xxxxxx xx xxxx xxxxx xx xxxxxx
+ xx xxxxxx xxxxx xxxx xxxx xx xxxx xx xxxxxxx xxxx xx xxxxxx xx
+ xx xxxxxxxxx xxxxxxx xxx xxxxxx xxxxxxx
+ xxxxxxxx xxxxx x xxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ xxx xxxxxxxxx x xxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxx
+
+ xxx xxxx x x xx x x xxxxxxxxxxxxx xxxx
+ xxxxxxxxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
+ xxxxxxxxxxxxxxxxxxxxxx
+ xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ x
+
+ xxxxxx xxxxxxx
+ x
+
+ xx [/pro] */
+ /**
+ * [#2534] Extract byte[] or String data from a
+ * LOB, if the argument is a lob.
+ */
+ private static Object unlob(Object object) throws SQLException {
+ if (object instanceof Blob) {
+ Blob blob = (Blob) object;
+
+ try {
+ return blob.getBytes(1, (int) blob.length());
+ }
+ finally {
+ JDBCUtils.safeFree(blob);
+ }
+ }
+ else if (object instanceof Clob) {
+ Clob clob = (Clob) object;
+
+ try {
+ return clob.getSubString(1, (int) clob.length());
+ }
+ finally {
+ JDBCUtils.safeFree(clob);
+ }
+ }
+
+ return object;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static final T getEnumType(Class type, String literal) throws SQLException {
+ try {
+ Object[] list = (Object[]) type.getMethod("values").invoke(type);
+
+ for (Object e : list) {
+ String l = ((EnumType) e).getLiteral();
+
+ if (l.equals(literal)) {
+ return (T) e;
+ }
+ }
+ }
+ catch (Exception e) {
+ throw new SQLException("Unknown enum literal found : " + literal);
+ }
+
+ return null;
+ }
+
+ private static final Object[] convertArray(Object array, Class extends Object[]> type) throws SQLException {
+ if (array instanceof Object[]) {
+ return Convert.convert(array, type);
+ }
+ else if (array instanceof Array) {
+ return convertArray((Array) array, type);
+ }
+
+ return null;
+ }
+
+ private static final Object[] convertArray(Array array, Class extends Object[]> type) throws SQLException {
+ if (array != null) {
+ return Convert.convert(array.getArray(), type);
+ }
+
+ return null;
+ }
+
+ private static final Date getDate(SQLDialect dialect, ResultSet rs, int index) throws SQLException {
+
+ // SQLite's type affinity needs special care...
+ if (dialect == SQLDialect.SQLITE) {
+ String date = rs.getString(index);
+
+ if (date != null) {
+ return new Date(parse("yyyy-MM-dd", date));
+ }
+
+ return null;
+ }
+
+ // Cubrid SQL dates are incorrectly fetched. Reset milliseconds...
+ // See http://jira.cubrid.org/browse/APIS-159
+ // See https://sourceforge.net/apps/trac/cubridinterface/ticket/140
+ else if (dialect == CUBRID) {
+ Date date = rs.getDate(index);
+
+ if (date != null) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(date.getTime());
+ cal.set(Calendar.MILLISECOND, 0);
+ date = new Date(cal.getTimeInMillis());
+ }
+
+ return date;
+ }
+
+ else {
+ return rs.getDate(index);
+ }
+ }
+
+ private static final Time getTime(SQLDialect dialect, ResultSet rs, int index) throws SQLException {
+
+ // SQLite's type affinity needs special care...
+ if (dialect == SQLDialect.SQLITE) {
+ String time = rs.getString(index);
+
+ if (time != null) {
+ return new Time(parse("HH:mm:ss", time));
+ }
+
+ return null;
+ }
+
+ // Cubrid SQL dates are incorrectly fetched. Reset milliseconds...
+ // See http://jira.cubrid.org/browse/APIS-159
+ // See https://sourceforge.net/apps/trac/cubridinterface/ticket/140
+ else if (dialect == CUBRID) {
+ Time time = rs.getTime(index);
+
+ if (time != null) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(time.getTime());
+ cal.set(Calendar.MILLISECOND, 0);
+ time = new Time(cal.getTimeInMillis());
+ }
+
+ return time;
+ }
+
+ else {
+ return rs.getTime(index);
+ }
+ }
+
+ private static final Timestamp getTimestamp(SQLDialect dialect, ResultSet rs, int index) throws SQLException {
+
+ // SQLite's type affinity needs special care...
+ if (dialect == SQLDialect.SQLITE) {
+ String timestamp = rs.getString(index);
+
+ if (timestamp != null) {
+ return new Timestamp(parse("yyyy-MM-dd HH:mm:ss", timestamp));
+ }
+
+ return null;
+ } else {
+ return rs.getTimestamp(index);
+ }
+ }
+
+ private static final long parse(String pattern, String date) throws SQLException {
+ try {
+
+ // Try reading a plain number first
+ try {
+ return Long.valueOf(date);
+ }
+
+ // If that fails, try reading a formatted date
+ catch (NumberFormatException e) {
+ return new SimpleDateFormat(pattern).parse(date).getTime();
+ }
+ }
+ catch (ParseException e) {
+ throw new SQLException("Could not parse date " + date, e);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // XXX: The following section has been added for Postgres UDT support. The
+ // official Postgres JDBC driver does not implement SQLData and similar
+ // interfaces. Instead, a string representation of a UDT has to be parsed
+ // -------------------------------------------------------------------------
+
+ @SuppressWarnings("unchecked")
+ private static final T pgFromString(Class type, String string) throws SQLException {
+ if (string == null) {
+ return null;
+ }
+ else if (type == Blob.class) {
+ // Not supported
+ }
+ else if (type == Boolean.class) {
+ return (T) Boolean.valueOf(string);
+ }
+ else if (type == BigInteger.class) {
+ return (T) new BigInteger(string);
+ }
+ else if (type == BigDecimal.class) {
+ return (T) new BigDecimal(string);
+ }
+ else if (type == Byte.class) {
+ return (T) Byte.valueOf(string);
+ }
+ else if (type == byte[].class) {
+ return (T) PostgresUtils.toBytes(string);
+ }
+ else if (type == Clob.class) {
+ // Not supported
+ }
+ else if (type == Date.class) {
+ SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
+ return (T) new Date(pgParseDate(string, f).getTime());
+ }
+ else if (type == Double.class) {
+ return (T) Double.valueOf(string);
+ }
+ else if (type == Float.class) {
+ return (T) Float.valueOf(string);
+ }
+ else if (type == Integer.class) {
+ return (T) Integer.valueOf(string);
+ }
+ else if (type == Long.class) {
+ return (T) Long.valueOf(string);
+ }
+ else if (type == Short.class) {
+ return (T) Short.valueOf(string);
+ }
+ else if (type == String.class) {
+ return (T) string;
+ }
+ else if (type == Time.class) {
+ SimpleDateFormat f = new SimpleDateFormat("HH:mm:ss");
+ return (T) new Time(pgParseDate(string, f).getTime());
+ }
+ else if (type == Timestamp.class) {
+ SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ return (T) new Timestamp(pgParseDate(string, f).getTime());
+ }
+ else if (type == UByte.class) {
+ return (T) UByte.valueOf(string);
+ }
+ else if (type == UShort.class) {
+ return (T) UShort.valueOf(string);
+ }
+ else if (type == UInteger.class) {
+ return (T) UInteger.valueOf(string);
+ }
+ else if (type == ULong.class) {
+ return (T) ULong.valueOf(string);
+ }
+ else if (type == UUID.class) {
+ return (T) UUID.fromString(string);
+ }
+ else if (type.isArray()) {
+ return (T) pgNewArray(type, string);
+ }
+ /* [pro] xx
+ xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
+ xx xxx xxxxxxxxx
+ x
+ xx [/pro] */
+ else if (EnumType.class.isAssignableFrom(type)) {
+ return getEnumType(type, string);
+ }
+ else if (UDTRecord.class.isAssignableFrom(type)) {
+ return (T) pgNewUDTRecord(type, string);
+ }
+
+ throw new UnsupportedOperationException("Class " + type + " is not supported");
+ }
+
+ private static final java.util.Date pgParseDate(String string, SimpleDateFormat f) throws SQLException {
+ try {
+ return f.parse(string);
+ }
+ catch (ParseException e) {
+ throw new SQLException(e);
+ }
+ }
+
+ /**
+ * Create a UDT record from a PGobject
+ *
+ * Unfortunately, this feature is very poorly documented and true UDT
+ * support by the PostGreSQL JDBC driver has been postponed for a long time.
+ *
+ * @param object An object of type PGobject. The actual argument type cannot
+ * be expressed in the method signature, as no explicit
+ * dependency to postgres logic is desired
+ * @return The converted {@link UDTRecord}
+ */
+ @SuppressWarnings("unchecked")
+ private static final UDTRecord> pgNewUDTRecord(Class> type, final Object object) throws SQLException {
+ if (object == null) {
+ return null;
+ }
+
+ return Utils.newRecord(true, (Class>) type)
+ .operate(new RecordOperation, SQLException>() {
+
+ @Override
+ public UDTRecord> operate(UDTRecord> record) throws SQLException {
+ List values = PostgresUtils.toPGObject(object.toString());
+
+ Row row = record.fieldsRow();
+ for (int i = 0; i < row.size(); i++) {
+ pgSetValue(record, row.field(i), values.get(i));
+ }
+
+ return record;
+ }
+ });
+ }
+
+ /**
+ * Workarounds for the unimplemented Postgres JDBC driver features
+ */
+ @SuppressWarnings("unchecked")
+ private static final T pgGetArray(Scope ctx, ResultSet rs, Class type, int index) throws SQLException {
+
+ // Get the JDBC Array and check for null. If null, that's OK
+ Array array = rs.getArray(index);
+ if (array == null) {
+ return null;
+ }
+
+ // Try fetching a Java Object[]. That's gonna work for non-UDT types
+ try {
+ return (T) convertArray(rs.getArray(index), (Class extends Object[]>) type);
+ }
+
+ // This might be a UDT (not implemented exception...)
+ catch (Exception e) {
+ List result = new ArrayList();
+
+ // Try fetching the array as a JDBC ResultSet
+ try {
+ while (rs.next()) {
+ DefaultBindingGetResultSetContext out = new DefaultBindingGetResultSetContext(ctx.configuration(), rs, 2);
+ new DefaultBinding(new IdentityConverter((Class) type.getComponentType()), false).get(out);
+ result.add(out.value());
+ }
+ }
+
+ // That might fail too, then we don't know any further...
+ catch (Exception fatal) {
+ log.error("Cannot parse Postgres array: " + rs.getString(index));
+ log.error(fatal);
+ return null;
+ }
+
+ return (T) convertArray(result.toArray(), (Class extends Object[]>) type);
+ }
+ }
+
+ /**
+ * Create an array from a String
+ *
+ * Unfortunately, this feature is very poorly documented and true UDT
+ * support by the PostGreSQL JDBC driver has been postponed for a long time.
+ *
+ * @param string A String representation of an array
+ * @return The converted array
+ */
+ private static final Object[] pgNewArray(Class> type, String string) throws SQLException {
+ if (string == null) {
+ return null;
+ }
+
+ try {
+ Class> component = type.getComponentType();
+ String values = string.replaceAll("^\\{(.*)\\}$", "$1");
+
+ if ("".equals(values)) {
+ return (Object[]) java.lang.reflect.Array.newInstance(component, 0);
+ }
+ else {
+ String[] split = values.split(",");
+ Object[] result = (Object[]) java.lang.reflect.Array.newInstance(component, split.length);
+
+ for (int i = 0; i < split.length; i++) {
+ result[i] = pgFromString(type.getComponentType(), split[i]);
+ }
+
+ return result;
+ }
+ }
+ catch (Exception e) {
+ throw new SQLException(e);
+ }
+ }
+
+ private static final void pgSetValue(UDTRecord> record, Field field, String value) throws SQLException {
+ record.setValue(field, pgFromString(field.getType(), value));
+ }
+}
+
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindingContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingContext.java
new file mode 100644
index 0000000000..8bc00f0437
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingContext.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import org.jooq.Configuration;
+
+/**
+ * @author Lukas Eder
+ */
+@Deprecated
+class DefaultBindingContext extends AbstractBindingContext {
+ DefaultBindingContext(Configuration configuration) {
+ super(configuration);
+ }
+}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetResultSetContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetResultSetContext.java
new file mode 100644
index 0000000000..5bfeffa9e8
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetResultSetContext.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import java.sql.ResultSet;
+
+import org.jooq.BindingGetResultSetContext;
+import org.jooq.Configuration;
+
+/**
+ * @author Lukas Eder
+ */
+class DefaultBindingGetResultSetContext extends AbstractScope implements BindingGetResultSetContext {
+
+ private final ResultSet resultSet;
+ private final int index;
+ private T value;
+
+ DefaultBindingGetResultSetContext(Configuration configuration, ResultSet resultSet, int index) {
+ super(configuration);
+
+ this.resultSet = resultSet;
+ this.index = index;
+ }
+
+ @Override
+ public final ResultSet resultSet() {
+ return resultSet;
+ }
+
+ @Override
+ public final int index() {
+ return index;
+ }
+
+ @Override
+ public final void value(T v) {
+ this.value = v;
+ }
+
+ final T value() {
+ return value;
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetSQLInputContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetSQLInputContext.java
new file mode 100644
index 0000000000..e9aeceda17
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetSQLInputContext.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import java.sql.SQLInput;
+
+import org.jooq.BindingGetSQLInputContext;
+import org.jooq.Configuration;
+
+/**
+ * @author Lukas Eder
+ */
+class DefaultBindingGetSQLInputContext extends AbstractScope implements BindingGetSQLInputContext {
+
+ private final SQLInput input;
+ private T value;
+
+ DefaultBindingGetSQLInputContext(Configuration configuration, SQLInput input) {
+ super(configuration);
+
+ this.input = input;
+ }
+
+ @Override
+ public final SQLInput input() {
+ return input;
+ }
+
+ @Override
+ public final void value(T v) {
+ this.value = v;
+ }
+
+ final T value() {
+ return value;
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetStatementContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetStatementContext.java
new file mode 100644
index 0000000000..9b0cf404a6
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingGetStatementContext.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import java.sql.CallableStatement;
+
+import org.jooq.BindingGetStatementContext;
+import org.jooq.Configuration;
+
+/**
+ * @author Lukas Eder
+ */
+class DefaultBindingGetStatementContext extends AbstractScope implements BindingGetStatementContext {
+
+ private final CallableStatement statement;
+ private final int index;
+ private T value;
+
+ DefaultBindingGetStatementContext(Configuration configuration, CallableStatement statement, int index) {
+ super(configuration);
+
+ this.statement = statement;
+ this.index = index;
+ }
+
+ @Override
+ public final CallableStatement statement() {
+ return statement;
+ }
+
+ @Override
+ public final int index() {
+ return index;
+ }
+
+ @Override
+ public final void value(T v) {
+ this.value = v;
+ }
+
+ final T value() {
+ return value;
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindingRegisterContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingRegisterContext.java
new file mode 100644
index 0000000000..4d4bc6fa8d
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingRegisterContext.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import java.sql.CallableStatement;
+
+import org.jooq.BindingRegisterContext;
+import org.jooq.Configuration;
+
+/**
+ * @author Lukas Eder
+ */
+class DefaultBindingRegisterContext extends AbstractScope implements BindingRegisterContext {
+
+ private final CallableStatement statement;
+ private final int index;
+
+ DefaultBindingRegisterContext(Configuration configuration, CallableStatement statement, int index) {
+ super(configuration);
+
+ this.statement = statement;
+ this.index = index;
+ }
+
+ @Override
+ public final CallableStatement statement() {
+ return statement;
+ }
+
+ @Override
+ public final int index() {
+ return index;
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSQLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSQLContext.java
new file mode 100644
index 0000000000..85e796c80e
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSQLContext.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import org.jooq.BindingSQLContext;
+import org.jooq.Configuration;
+import org.jooq.RenderContext;
+
+/**
+ * @author Lukas Eder
+ */
+class DefaultBindingSQLContext extends AbstractScope implements BindingSQLContext {
+
+ private final RenderContext render;
+ private final T value;
+
+ DefaultBindingSQLContext(Configuration configuration, RenderContext render, T value) {
+ super(configuration);
+
+ this.render = render;
+ this.value = value;
+ }
+
+ @Override
+ public final RenderContext render() {
+ return render;
+ }
+
+ @Override
+ public final T value() {
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSetSQLOutputContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSetSQLOutputContext.java
new file mode 100644
index 0000000000..231133dcb8
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSetSQLOutputContext.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import java.sql.SQLOutput;
+
+import org.jooq.BindingSetSQLOutputContext;
+import org.jooq.Configuration;
+
+/**
+ * @author Lukas Eder
+ */
+class DefaultBindingSetSQLOutputContext extends AbstractScope implements BindingSetSQLOutputContext {
+
+ private final SQLOutput output;
+ private final T value;
+
+ DefaultBindingSetSQLOutputContext(Configuration configuration, SQLOutput output, T value) {
+ super(configuration);
+
+ this.output = output;
+ this.value = value;
+ }
+
+ @Override
+ public final SQLOutput output() {
+ return output;
+ }
+
+ @Override
+ public final T value() {
+ return value;
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSetStatementContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSetStatementContext.java
new file mode 100644
index 0000000000..b1b88d8aae
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBindingSetStatementContext.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * This work is dual-licensed
+ * - under the Apache Software License 2.0 (the "ASL")
+ * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
+ * =============================================================================
+ * You may choose which license applies to you:
+ *
+ * - If you're using this work with Open Source databases, you may choose
+ * either ASL or jOOQ License.
+ * - If you're using this work with at least one commercial database, you must
+ * choose jOOQ License
+ *
+ * For more information, please visit http://www.jooq.org/licenses
+ *
+ * Apache Software License 2.0:
+ * -----------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * jOOQ License and Maintenance Agreement:
+ * -----------------------------------------------------------------------------
+ * Data Geekery grants the Customer the non-exclusive, timely limited and
+ * non-transferable license to install and use the Software under the terms of
+ * the jOOQ License and Maintenance Agreement.
+ *
+ * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
+ * and Maintenance Agreement for more details: http://www.jooq.org/licensing
+ */
+package org.jooq.impl;
+
+import java.sql.PreparedStatement;
+
+import org.jooq.BindingSetStatementContext;
+import org.jooq.Configuration;
+
+/**
+ * @author Lukas Eder
+ */
+class DefaultBindingSetStatementContext extends AbstractScope implements BindingSetStatementContext {
+
+ private final PreparedStatement statement;
+ private final int index;
+ private final T value;
+
+ DefaultBindingSetStatementContext(Configuration configuration, PreparedStatement statement, int index, T value) {
+ super(configuration);
+
+ this.statement = statement;
+ this.index = index;
+ this.value = value;
+ }
+
+ @Override
+ public final PreparedStatement statement() {
+ return statement;
+ }
+
+ @Override
+ public final int index() {
+ return index;
+ }
+
+ @Override
+ public final T value() {
+ return value;
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
index ff565c9c25..45e2e904ee 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
@@ -220,7 +220,7 @@ import org.jooq.tools.reflect.ReflectException;
* @author Lukas Eder
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
-public class DefaultDSLContext implements DSLContext, Serializable {
+public class DefaultDSLContext extends AbstractScope implements DSLContext, Serializable {
/**
* Generated UID
@@ -228,8 +228,6 @@ public class DefaultDSLContext implements DSLContext, Serializable {
private static final long serialVersionUID = 2681360188806309513L;
private static final JooqLogger log = JooqLogger.getLogger(DefaultDSLContext.class);
- private final Configuration configuration;
-
// -------------------------------------------------------------------------
// XXX Constructors
// -------------------------------------------------------------------------
@@ -267,48 +265,21 @@ public class DefaultDSLContext implements DSLContext, Serializable {
}
public DefaultDSLContext(Configuration configuration) {
-
- // The Configuration can be null when unattached Query objects are
- // executed or when unattached Records are stored...
- if (configuration == null) {
- configuration = new DefaultConfiguration();
- }
-
- this.configuration = configuration;
+ super(configuration);
}
// -------------------------------------------------------------------------
// XXX Configuration API
// -------------------------------------------------------------------------
- @Override
- public Configuration configuration() {
- return configuration;
- }
-
- @Override
- public Settings settings() {
- return Utils.settings(configuration());
- }
-
- @Override
- public SQLDialect dialect() {
- return Utils.configuration(configuration()).dialect();
- }
-
- @Override
- public SQLDialect family() {
- return dialect().family();
- }
-
@Override
public Schema map(Schema schema) {
- return Utils.getMappedSchema(configuration, schema);
+ return Utils.getMappedSchema(configuration(), schema);
}
@Override
public Table map(Table table) {
- return Utils.getMappedTable(configuration, table);
+ return Utils.getMappedTable(configuration(), table);
}
// -------------------------------------------------------------------------
@@ -317,7 +288,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public Meta meta() {
- return new MetaImpl(configuration);
+ return new MetaImpl(configuration());
}
// -------------------------------------------------------------------------
@@ -328,7 +299,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
public T transactionResult(TransactionalCallable transactional) {
T result = null;
- DefaultTransactionContext ctx = new DefaultTransactionContext(configuration.derive());
+ DefaultTransactionContext ctx = new DefaultTransactionContext(configuration().derive());
TransactionProvider provider = ctx.configuration().transactionProvider();
try {
@@ -379,7 +350,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public RenderContext renderContext() {
- return new DefaultRenderContext(configuration);
+ return new DefaultRenderContext(configuration());
}
@Override
@@ -419,7 +390,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
}
final Map> extractParams0(QueryPart part, boolean includeInlinedParams) {
- ParamCollector collector = new ParamCollector(configuration, includeInlinedParams);
+ ParamCollector collector = new ParamCollector(configuration(), includeInlinedParams);
collector.visit(part);
return Collections.unmodifiableMap(collector.result);
}
@@ -431,7 +402,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public BindContext bindContext(PreparedStatement stmt) {
- return new DefaultBindContext(configuration, stmt);
+ return new DefaultBindContext(configuration(), stmt);
}
@Override
@@ -452,7 +423,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public void attach(Collection extends Attachable> attachables) {
for (Attachable attachable : attachables) {
- attachable.attach(configuration);
+ attachable.attach(configuration());
}
}
@@ -462,7 +433,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public > LoaderOptionsStep loadInto(Table table) {
- return new LoaderImpl(configuration, table);
+ return new LoaderImpl(configuration(), table);
}
// -------------------------------------------------------------------------
@@ -486,7 +457,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@SuppressWarnings("deprecation")
Query query(org.jooq.Template template, Object... parameters) {
- return new SQLQuery(configuration, queryPart(template, parameters));
+ return new SQLQuery(configuration(), queryPart(template, parameters));
}
@Override
@@ -636,7 +607,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@SuppressWarnings("deprecation")
ResultQuery resultQuery(org.jooq.Template template, Object... parameters) {
- return new SQLResultQuery(configuration, queryPart(template, parameters));
+ return new SQLResultQuery(configuration(), queryPart(template, parameters));
}
// -------------------------------------------------------------------------
@@ -726,7 +697,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public Cursor fetchLazy(ResultSet rs) {
try {
- return fetchLazy(rs, new MetaDataFieldProvider(configuration, rs.getMetaData()).getFields());
+ return fetchLazy(rs, new MetaDataFieldProvider(configuration(), rs.getMetaData()).getFields());
}
catch (SQLException e) {
throw new DataAccessException("Error while accessing ResultSet meta data", e);
@@ -735,7 +706,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public Cursor fetchLazy(ResultSet rs, Field>... fields) {
- ExecuteContext ctx = new DefaultExecuteContext(configuration);
+ ExecuteContext ctx = new DefaultExecuteContext(configuration());
ExecuteListener listener = new ExecuteListeners(ctx);
ctx.resultSet(rs);
@@ -835,7 +806,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public Result fetchFromStringData(List data) {
if (data.size() == 0) {
- return new ResultImpl(configuration);
+ return new ResultImpl(configuration());
}
else {
List> fields = new ArrayList>();
@@ -844,7 +815,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
fields.add(fieldByName(String.class, name));
}
- Result result = new ResultImpl(configuration, fields);
+ Result result = new ResultImpl(configuration(), fields);
if (data.size() > 1) {
for (String[] values : data.subList(1, data.size())) {
@@ -869,52 +840,52 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public WithAsStep with(String alias) {
- return new WithImpl(configuration, false).with(alias);
+ return new WithImpl(configuration(), false).with(alias);
}
@Override
public WithAsStep with(String alias, String... fieldAliases) {
- return new WithImpl(configuration, false).with(alias, fieldAliases);
+ return new WithImpl(configuration(), false).with(alias, fieldAliases);
}
@Override
public WithStep with(CommonTableExpression>... tables) {
- return new WithImpl(configuration, false).with(tables);
+ return new WithImpl(configuration(), false).with(tables);
}
@Override
public WithAsStep withRecursive(String alias) {
- return new WithImpl(configuration, true).with(alias);
+ return new WithImpl(configuration(), true).with(alias);
}
@Override
public WithAsStep withRecursive(String alias, String... fieldAliases) {
- return new WithImpl(configuration, true).with(alias, fieldAliases);
+ return new WithImpl(configuration(), true).with(alias, fieldAliases);
}
@Override
public WithStep withRecursive(CommonTableExpression>... tables) {
- return new WithImpl(configuration, true).with(tables);
+ return new WithImpl(configuration(), true).with(tables);
}
@Override
public SelectWhereStep selectFrom(Table table) {
SelectWhereStep result = DSL.selectFrom(table);
- result.attach(configuration);
+ result.attach(configuration());
return result;
}
@Override
public SelectSelectStep select(Collection extends Field>> fields) {
SelectSelectStep result = DSL.select(fields);
- result.attach(configuration);
+ result.attach(configuration());
return result;
}
@Override
public SelectSelectStep select(Field>... fields) {
SelectSelectStep result = DSL.select(fields);
- result.attach(configuration);
+ result.attach(configuration());
return result;
}
@@ -1057,14 +1028,14 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public SelectSelectStep selectDistinct(Collection extends Field>> fields) {
SelectSelectStep result = DSL.selectDistinct(fields);
- result.attach(configuration);
+ result.attach(configuration());
return result;
}
@Override
public SelectSelectStep selectDistinct(Field>... fields) {
SelectSelectStep result = DSL.selectDistinct(fields);
- result.attach(configuration);
+ result.attach(configuration());
return result;
}
@@ -1207,42 +1178,42 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Override
public SelectSelectStep> selectZero() {
SelectSelectStep> result = DSL.selectZero();
- result.attach(configuration);
+ result.attach(configuration());
return result;
}
@Override
public SelectSelectStep> selectOne() {
SelectSelectStep> result = DSL.selectOne();
- result.attach(configuration);
+ result.attach(configuration());
return result;
}
@Override
public SelectSelectStep> selectCount() {
SelectSelectStep> result = DSL.selectCount();
- result.attach(configuration);
+ result.attach(configuration());
return result;
}
@Override
public SelectQuery selectQuery() {
- return new SelectQueryImpl(null, configuration);
+ return new SelectQueryImpl(null, configuration());
}
@Override
public SelectQuery selectQuery(TableLike table) {
- return new SelectQueryImpl(null, configuration, table);
+ return new SelectQueryImpl(null, configuration(), table);
}
@Override
public InsertQuery insertQuery(Table into) {
- return new InsertQueryImpl(configuration, into);
+ return new InsertQueryImpl(configuration(), into);
}
@Override
public InsertSetStep insertInto(Table into) {
- return new InsertImpl(configuration, into, Collections.>emptyList());
+ return new InsertImpl(configuration(), into, Collections.>emptyList());
}
// [jooq-tools] START [insert]
@@ -1250,160 +1221,160 @@ public class DefaultDSLContext implements DSLContext, Serializable {
@Generated("This method was generated using jOOQ-tools")
@Override
public InsertValuesStep1 insertInto(Table into, Field field1) {
- return new InsertImpl(configuration, into, Arrays.asList(new Field[] { field1 }));
+ return new InsertImpl(configuration(), into, Arrays.asList(new Field[] { field1 }));
}
@Generated("This method was generated using jOOQ-tools")
@Override
public InsertValuesStep2 insertInto(Table into, Field field1, Field field2) {
- return new InsertImpl(configuration, into, Arrays.asList(new Field[] { field1, field2 }));
+ return new InsertImpl(configuration(), into, Arrays.asList(new Field[] { field1, field2 }));
}
@Generated("This method was generated using jOOQ-tools")
@Override
public InsertValuesStep3 insertInto(Table into, Field field1, Field field2, Field field3) {
- return new InsertImpl(configuration, into, Arrays.asList(new Field[] { field1, field2, field3 }));
+ return new InsertImpl(configuration(), into, Arrays.asList(new Field[] { field1, field2, field3 }));
}
@Generated("This method was generated using jOOQ-tools")
@Override
public InsertValuesStep4 insertInto(Table into, Field field1, Field field2, Field field3, Field field4) {
- return new InsertImpl(configuration, into, Arrays.asList(new Field[] { field1, field2, field3, field4 }));
+ return new InsertImpl(configuration(), into, Arrays.asList(new Field[] { field1, field2, field3, field4 }));
}
@Generated("This method was generated using jOOQ-tools")
@Override
public InsertValuesStep5 insertInto(Table into, Field field1, Field field2, Field field3, Field field4, Field field5) {
- return new InsertImpl(configuration, into, Arrays.asList(new Field[] { field1, field2, field3, field4, field5 }));
+ return new InsertImpl(configuration(), into, Arrays.asList(new Field[] { field1, field2, field3, field4, field5 }));
}
@Generated("This method was generated using jOOQ-tools")
@Override
public InsertValuesStep6 insertInto(Table into, Field field1, Field field2, Field field3, Field field4, Field field5, Field field6) {
- return new InsertImpl(configuration, into, Arrays.asList(new Field[] { field1, field2, field3, field4, field5, field6 }));
+ return new InsertImpl(configuration(), into, Arrays.asList(new Field[] { field1, field2, field3, field4, field5, field6 }));
}
@Generated("This method was generated using jOOQ-tools")
@Override
public InsertValuesStep7 insertInto(Table into, Field field1, Field field2, Field field3, Field field4, Field field5, Field