From 753b6453892523cbc2e7aa96b0d724828446ec5b Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Tue, 21 Feb 2012 21:17:43 +0000 Subject: [PATCH] [#1157] Add extended SQL / JDBC tracing capabilities in addition to logging - draft API and implementation --- .../test/_/testcases/RenderAndBindTests.java | 7 +- .../_/testcases/SchemaAndMappingTests.java | 13 +- .../src/org/jooq/test/jOOQHSQLDBTest2.java | 6 +- .../jooq/test/jOOQMySQLTestSchemaMapping.java | 6 +- .../org/jooq/test/jOOQOracleTestInline.java | 4 +- .../jooq/test/jOOQSQLServerTestInline.java | 4 +- .../src/main/java/org/jooq/Configuration.java | 18 +- .../java/org/jooq/ConfigurationRegistry.java | 8 +- ...EventListener.java => ExecuteContext.java} | 49 +- .../main/java/org/jooq/ExecuteListener.java | 88 ++++ .../src/main/java/org/jooq/SchemaMapping.java | 23 +- .../main/java/org/jooq/conf/MappedSchema.java | 2 +- .../main/java/org/jooq/conf/MappedTable.java | 2 +- .../java/org/jooq/conf/RenderMapping.java | 2 +- .../src/main/java/org/jooq/conf/Settings.java | 115 ++++- .../java/org/jooq/conf/SettingsTools.java | 10 +- .../java/org/jooq/conf/StatementType.java | 2 +- .../main/java/org/jooq/conf/package-info.java | 2 +- .../org/jooq/impl/AbstractConfiguration.java | 99 ++++ .../java/org/jooq/impl/AbstractContext.java | 50 +- .../java/org/jooq/impl/AbstractQuery.java | 74 ++- .../org/jooq/impl/AbstractResultQuery.java | 39 +- .../java/org/jooq/impl/AbstractRoutine.java | 58 +-- .../main/java/org/jooq/impl/CursorImpl.java | 456 +++++++++--------- .../org/jooq/impl/DefaultExecuteContext.java | 138 ++++++ .../java/org/jooq/impl/ExecuteListeners.java | 161 +++++++ jOOQ/src/main/java/org/jooq/impl/Factory.java | 16 +- .../java/org/jooq/impl/FieldTypeHelper.java | 64 +-- .../java/org/jooq/impl/InsertQueryImpl.java | 61 ++- jOOQ/src/main/java/org/jooq/impl/Util.java | 36 +- .../java/org/jooq/tools/LoggerListener.java | 128 +++++ .../org/jooq/tools/StopWatchListener.java | 125 +++++ .../main/resources/xsd/jooq-runtime-2.0.5.xsd | 40 +- 33 files changed, 1362 insertions(+), 544 deletions(-) rename jOOQ/src/main/java/org/jooq/{EventListener.java => ExecuteContext.java} (61%) create mode 100644 jOOQ/src/main/java/org/jooq/ExecuteListener.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/AbstractConfiguration.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/ExecuteListeners.java create mode 100644 jOOQ/src/main/java/org/jooq/tools/LoggerListener.java create mode 100644 jOOQ/src/main/java/org/jooq/tools/StopWatchListener.java diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/RenderAndBindTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/RenderAndBindTests.java index c945cf157e..9470d74fd0 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/RenderAndBindTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/RenderAndBindTests.java @@ -59,7 +59,6 @@ import org.jooq.Result; import org.jooq.Select; import org.jooq.TableRecord; import org.jooq.UpdatableRecord; -import org.jooq.conf.Execution; import org.jooq.conf.Settings; import org.jooq.conf.StatementType; import org.jooq.impl.Factory; @@ -315,8 +314,7 @@ extends BaseTest q = create(settings).select(TBook_TITLE()) @@ -160,14 +158,13 @@ extends BaseTest query = create(settings).select(TBook_TITLE()) @@ -218,11 +215,10 @@ extends BaseTest q = create(settings).select(TBook_TITLE()) @@ -264,14 +260,13 @@ extends BaseTest * This is custom data that was previously set to the configuration using * {@link #setData(String, Object)}. Use custom data if you want to pass - * data to your custom {@link QueryPart} or {@link EventListener} objects to + * data to your custom {@link QueryPart} or {@link ExecuteListener} objects to * be made available at render, bind, execution, fetch time. *

- * See {@link EventListener} for more details. + * See {@link ExecuteListener} for more details. * * @return The custom data. This is never null - * @see EventListener + * @see ExecuteListener */ Map getData(); @@ -91,15 +91,15 @@ public interface Configuration extends Serializable { *

* This is custom data that was previously set to the configuration using * {@link #setData(String, Object)}. Use custom data if you want to pass - * data to your custom {@link QueryPart} or {@link EventListener} objects to + * data to your custom {@link QueryPart} or {@link ExecuteListener} objects to * be made available at render, bind, execution, fetch time. *

- * See {@link EventListener} for more details. + * See {@link ExecuteListener} for more details. * * @param key A key to identify the custom data * @return The custom data or null if no such data is contained * in this Configuration - * @see EventListener + * @see ExecuteListener */ Object getData(String key); @@ -108,21 +108,21 @@ public interface Configuration extends Serializable { *

* This is custom data that was previously set to the configuration using * {@link #setData(String, Object)}. Use custom data if you want to pass - * data to your custom {@link QueryPart} or {@link EventListener} objects to + * data to your custom {@link QueryPart} or {@link ExecuteListener} objects to * be made available at render, bind, execution, fetch time. *

* Be sure that your custom data implements {@link Serializable} if you want * to serialise this Configuration or objects referencing this * Configuration, e.g. your {@link Record} types. *

- * See {@link EventListener} for more details. + * See {@link ExecuteListener} for more details. * * @param key A key to identify the custom data * @param value The custom data or null to unset the custom * data * @return The previously set custom data or null if no data * was previously set for the given key - * @see EventListener + * @see ExecuteListener */ Object setData(String key, Object value); diff --git a/jOOQ/src/main/java/org/jooq/ConfigurationRegistry.java b/jOOQ/src/main/java/org/jooq/ConfigurationRegistry.java index f6805f7960..f34fe5fe78 100644 --- a/jOOQ/src/main/java/org/jooq/ConfigurationRegistry.java +++ b/jOOQ/src/main/java/org/jooq/ConfigurationRegistry.java @@ -37,7 +37,6 @@ package org.jooq; import org.jooq.tools.JooqLogger; - /** * A public static registry that can provide factories ({@link Configuration}'s) * to {@link Attachable}'s upon deserialisation. The registry acts as an @@ -47,11 +46,14 @@ import org.jooq.tools.JooqLogger; *

* This functionality is experimental. It may change again in the future. Use it * at your own risk. - * + * * @author Lukas Eder * @see http://groups.google.com/group/jooq-user/browse_thread/thread/d33e9a902707d111 + * @deprecated - 2.0.5 - Use {@link ExecuteListener#init(ExecuteContext)} + * instead */ +@Deprecated public final class ConfigurationRegistry { private static JooqLogger log = JooqLogger.getLogger(ConfigurationRegistry.class); @@ -95,6 +97,8 @@ public final class ConfigurationRegistry { * null to reset the provider. */ public static void setProvider(ConfigurationProvider provider) { + log.warn("Deprecation", "org.jooq.ConfigurationRegistry is deprecated. Use org.jooq.ExecuteListener instead"); + if (provider != null) { log.info("Registering provider", provider); } diff --git a/jOOQ/src/main/java/org/jooq/EventListener.java b/jOOQ/src/main/java/org/jooq/ExecuteContext.java similarity index 61% rename from jOOQ/src/main/java/org/jooq/EventListener.java rename to jOOQ/src/main/java/org/jooq/ExecuteContext.java index 06d78a09ef..b23692b942 100644 --- a/jOOQ/src/main/java/org/jooq/EventListener.java +++ b/jOOQ/src/main/java/org/jooq/ExecuteContext.java @@ -35,6 +35,53 @@ */ package org.jooq; -public interface EventListener { +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +/** + * A context object for {@link Query} execution passed to registered + * {@link ExecuteListener}'s. + *

+ * Expect most of this context's objects to be nullable! + * + * @author Lukas Eder + */ +public interface ExecuteContext extends Configuration { + + Configuration configuration(); + + // TODO Routines? + // Nullable! + Query query(); + + // Nullable! + void sql(String sql); + + String sql(); + + /** + * Override the context's {@link PreparedStatement} + *

+ * Use this to wrap the PreparedStatement executed by jOOQ with + * your custom wrapper statement, logging bind variables and query + * execution. Beware + */ + void statement(PreparedStatement statement); + + PreparedStatement statement(); + + // Nullable! + void resultSet(ResultSet resultSet); + + ResultSet resultSet(); + + // Nullable + void record(Record record); + + Record record(); + + void result(Result result); + + Result result(); } diff --git a/jOOQ/src/main/java/org/jooq/ExecuteListener.java b/jOOQ/src/main/java/org/jooq/ExecuteListener.java new file mode 100644 index 0000000000..3f318e1393 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/ExecuteListener.java @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import org.jooq.conf.Settings; +import org.jooq.impl.Factory; +import org.jooq.tools.JooqLogger; + +/** + * An event listener for {@link Query} render, prepare, bind, execute, fetch + * steps. + *

+ * EventListener is a base type for loggers, debuggers, profilers, + * data collectors that can be hooked into a jOOQ {@link Factory} using the + * {@link Settings#getEventListeners()} property, passing Settings + * to {@link Factory#Factory(java.sql.Connection, SQLDialect, Settings)} + *

+ * Advanced EventListeners can also provide custom implementations + * of {@link Connection}, {@link PreparedStatement} and {@link ResultSet} to + * jOOQ in apropriate methods. + *

+ * If nothing is specified, the default is to use {@link JooqLogger} as the only + * event listener. + * + * @author Lukas Eder + */ +public interface ExecuteListener { + + void init(ExecuteContext ctx); + + void renderStart(ExecuteContext ctx); + void renderEnd(ExecuteContext ctx); + + void prepareStart(ExecuteContext ctx); + void prepareEnd(ExecuteContext ctx); + + void bindStart(ExecuteContext ctx); + void bindEnd(ExecuteContext ctx); + + void executeStart(ExecuteContext ctx); + void executeEnd(ExecuteContext ctx); + + void recordStart(ExecuteContext ctx); + void recordEnd(ExecuteContext ctx); + + void resultStart(ExecuteContext ctx); + void resultEnd(ExecuteContext ctx); + + void fetchStart(ExecuteContext ctx); + void fetchEnd(ExecuteContext ctx); +} diff --git a/jOOQ/src/main/java/org/jooq/SchemaMapping.java b/jOOQ/src/main/java/org/jooq/SchemaMapping.java index c8df90c3c6..8749204a2e 100644 --- a/jOOQ/src/main/java/org/jooq/SchemaMapping.java +++ b/jOOQ/src/main/java/org/jooq/SchemaMapping.java @@ -43,7 +43,6 @@ import java.util.Map.Entry; import org.jooq.conf.MappedSchema; import org.jooq.conf.MappedTable; import org.jooq.conf.RenderMapping; -import org.jooq.conf.Rendering; import org.jooq.conf.Settings; import org.jooq.impl.SchemaImpl; import org.jooq.impl.TableImpl; @@ -319,22 +318,18 @@ public class SchemaMapping implements Serializable { SchemaMapping result = new SchemaMapping(false); if (settings != null) { - Rendering rendering = settings.getRendering(); + RenderMapping r = settings.getRenderMapping(); - if (rendering != null) { - RenderMapping r = rendering.getRenderMapping(); + if (r != null) { + if (!StringUtils.isEmpty(r.getDefaultSchema())) { + result.use(r.getDefaultSchema()); + } - if (r != null) { - if (!StringUtils.isEmpty(r.getDefaultSchema())) { - result.use(r.getDefaultSchema()); - } + for (MappedSchema schema : r.getSchemata()) { + result.add(schema.getInput(), schema.getOutput()); - for (MappedSchema schema : r.getSchemata()) { - result.add(schema.getInput(), schema.getOutput()); - - for (MappedTable table : schema.getTables()) { - log.warn("TODO", "Re-implement table mapping for table " + table); - } + for (MappedTable table : schema.getTables()) { + log.warn("TODO", "Re-implement table mapping for table " + table); } } } diff --git a/jOOQ/src/main/java/org/jooq/conf/MappedSchema.java b/jOOQ/src/main/java/org/jooq/conf/MappedSchema.java index c92d9fed6d..4653fa361a 100644 --- a/jOOQ/src/main/java/org/jooq/conf/MappedSchema.java +++ b/jOOQ/src/main/java/org/jooq/conf/MappedSchema.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2012.02.18 at 01:30:56 PM MEZ +// Generated on: 2012.02.21 at 09:21:19 PM MEZ // diff --git a/jOOQ/src/main/java/org/jooq/conf/MappedTable.java b/jOOQ/src/main/java/org/jooq/conf/MappedTable.java index 68e2fc9c41..b528ec9b97 100644 --- a/jOOQ/src/main/java/org/jooq/conf/MappedTable.java +++ b/jOOQ/src/main/java/org/jooq/conf/MappedTable.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2012.02.18 at 01:30:56 PM MEZ +// Generated on: 2012.02.21 at 09:21:19 PM MEZ // diff --git a/jOOQ/src/main/java/org/jooq/conf/RenderMapping.java b/jOOQ/src/main/java/org/jooq/conf/RenderMapping.java index bdd6610b4b..86fa9dc5bc 100644 --- a/jOOQ/src/main/java/org/jooq/conf/RenderMapping.java +++ b/jOOQ/src/main/java/org/jooq/conf/RenderMapping.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2012.02.18 at 01:30:56 PM MEZ +// Generated on: 2012.02.21 at 09:21:19 PM MEZ // diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index a91f46381a..2a795bdd56 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -2,15 +2,20 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2012.02.18 at 01:30:56 PM MEZ +// Generated on: 2012.02.21 at 09:21:19 PM MEZ // package org.jooq.conf; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlType; @@ -24,8 +29,10 @@ import javax.xml.bind.annotation.XmlType; * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <all> - * <element name="rendering" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}Rendering" minOccurs="0"/> - * <element name="execution" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}Execution" minOccurs="0"/> + * <element name="renderMapping" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}RenderMapping" minOccurs="0"/> + * <element name="statementType" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}StatementType" minOccurs="0"/> + * <element name="executeLogging" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/> + * <element name="executeListeners" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}ExecuteListeners" minOccurs="0"/> * </all> * </restriction> * </complexContent> @@ -43,64 +50,122 @@ public class Settings { private final static long serialVersionUID = 205L; - protected Rendering rendering; - protected Execution execution; + protected RenderMapping renderMapping; + @XmlElement(defaultValue = "PREPARED_STATEMENT") + protected StatementType statementType = StatementType.PREPARED_STATEMENT; + @XmlElement(defaultValue = "true") + protected Boolean executeLogging = true; + @XmlElementWrapper(name = "executeListeners") + @XmlElement(name = "executeListener") + protected List executeListeners; /** - * Gets the value of the rendering property. + * Gets the value of the renderMapping property. * * @return * possible object is - * {@link Rendering } + * {@link RenderMapping } * */ - public Rendering getRendering() { - return rendering; + public RenderMapping getRenderMapping() { + return renderMapping; } /** - * Sets the value of the rendering property. + * Sets the value of the renderMapping property. * * @param value * allowed object is - * {@link Rendering } + * {@link RenderMapping } * */ - public void setRendering(Rendering value) { - this.rendering = value; + public void setRenderMapping(RenderMapping value) { + this.renderMapping = value; } /** - * Gets the value of the execution property. + * Gets the value of the statementType property. * * @return * possible object is - * {@link Execution } + * {@link StatementType } * */ - public Execution getExecution() { - return execution; + public StatementType getStatementType() { + return statementType; } /** - * Sets the value of the execution property. + * Sets the value of the statementType property. * * @param value * allowed object is - * {@link Execution } + * {@link StatementType } * */ - public void setExecution(Execution value) { - this.execution = value; + public void setStatementType(StatementType value) { + this.statementType = value; } - public Settings withRendering(Rendering value) { - setRendering(value); + /** + * Gets the value of the executeLogging property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isExecuteLogging() { + return executeLogging; + } + + /** + * Sets the value of the executeLogging property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setExecuteLogging(Boolean value) { + this.executeLogging = value; + } + + public List getExecuteListeners() { + if (executeListeners == null) { + executeListeners = new ArrayList(); + } + return executeListeners; + } + + public Settings withRenderMapping(RenderMapping value) { + setRenderMapping(value); return this; } - public Settings withExecution(Execution value) { - setExecution(value); + public Settings withStatementType(StatementType value) { + setStatementType(value); + return this; + } + + public Settings withExecuteLogging(Boolean value) { + setExecuteLogging(value); + return this; + } + + public Settings withExecuteListeners(String... values) { + if (values!= null) { + for (String value: values) { + getExecuteListeners().add(value); + } + } + return this; + } + + public Settings withExecuteListeners(Collection values) { + if (values!= null) { + getExecuteListeners().addAll(values); + } return this; } diff --git a/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java b/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java index 74bfdf112c..da14dadc46 100644 --- a/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java +++ b/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java @@ -53,14 +53,10 @@ public final class SettingsTools { */ public static final StatementType getStatementType(Settings settings) { if (settings != null) { - Execution execution = settings.getExecution(); + StatementType result = settings.getStatementType(); - if (execution != null) { - StatementType result = execution.getStatementType(); - - if (result != null) { - return result; - } + if (result != null) { + return result; } } diff --git a/jOOQ/src/main/java/org/jooq/conf/StatementType.java b/jOOQ/src/main/java/org/jooq/conf/StatementType.java index 9533a38237..5abb11e394 100644 --- a/jOOQ/src/main/java/org/jooq/conf/StatementType.java +++ b/jOOQ/src/main/java/org/jooq/conf/StatementType.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2012.02.18 at 01:30:56 PM MEZ +// Generated on: 2012.02.21 at 09:21:19 PM MEZ // diff --git a/jOOQ/src/main/java/org/jooq/conf/package-info.java b/jOOQ/src/main/java/org/jooq/conf/package-info.java index 2b224aae49..8e6822b618 100644 --- a/jOOQ/src/main/java/org/jooq/conf/package-info.java +++ b/jOOQ/src/main/java/org/jooq/conf/package-info.java @@ -2,7 +2,7 @@ // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2012.02.18 at 01:30:56 PM MEZ +// Generated on: 2012.02.21 at 09:21:19 PM MEZ // @javax.xml.bind.annotation.XmlSchema(namespace = "http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd") diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractConfiguration.java b/jOOQ/src/main/java/org/jooq/impl/AbstractConfiguration.java new file mode 100644 index 0000000000..ac2a863007 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractConfiguration.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.impl; + +import java.sql.Connection; +import java.util.Map; + +import org.jooq.Configuration; +import org.jooq.SQLDialect; +import org.jooq.conf.Settings; + +/** + * A base class for all objects implementing {@link Configuration}, wrapping + * another configuration. + * + * @author Lukas Eder + */ +abstract class AbstractConfiguration implements Configuration { + + /** + * Generated UID + */ + private static final long serialVersionUID = -8527430313425232841L; + + final Configuration configuration; + + AbstractConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + @Override + public final SQLDialect getDialect() { + return configuration.getDialect(); + } + + @Override + public final Connection getConnection() { + return configuration.getConnection(); + } + + @Override + @Deprecated + public final org.jooq.SchemaMapping getSchemaMapping() { + return configuration.getSchemaMapping(); + } + + @Override + public final Settings getSettings() { + return configuration.getSettings(); + } + + @Override + public final Map getData() { + return configuration.getData(); + } + + @Override + public final Object getData(String key) { + return configuration.getData(key); + } + + @Override + public final Object setData(String key, Object value) { + return configuration.setData(key, value); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java index 404c313569..be85eba47c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java @@ -35,36 +35,30 @@ */ package org.jooq.impl; -import java.sql.Connection; -import java.util.Map; - import org.jooq.Configuration; import org.jooq.Context; -import org.jooq.SQLDialect; -import org.jooq.conf.Settings; /** * @author Lukas Eder */ -abstract class AbstractContext> implements Context { +abstract class AbstractContext> extends AbstractConfiguration implements Context { /** * Generated UID */ private static final long serialVersionUID = 4796952332163571043L; - final Configuration configuration; boolean declareFields; boolean declareTables; boolean subquery; int index; AbstractContext(Configuration configuration) { - this.configuration = configuration; + super(configuration); } AbstractContext(Configuration configuration, boolean declareFields, boolean declareTables) { - this.configuration = configuration; + this(configuration); this.declareFields = declareFields; this.declareTables = declareTables; } @@ -120,45 +114,9 @@ abstract class AbstractContext> implements Context { } // ------------------------------------------------------------------------ - // XXX Configuration API + // XXX Object API // ------------------------------------------------------------------------ - @Override - public final SQLDialect getDialect() { - return configuration.getDialect(); - } - - @Override - public final Connection getConnection() { - return configuration.getConnection(); - } - - @Override - @Deprecated - public final org.jooq.SchemaMapping getSchemaMapping() { - return configuration.getSchemaMapping(); - } - - @Override - public final Map getData() { - return configuration.getData(); - } - - @Override - public final Object getData(String key) { - return configuration.getData(key); - } - - @Override - public final Object setData(String key, Object value) { - return configuration.setData(key, value); - } - - @Override - public final Settings getSettings() { - return configuration.getSettings(); - } - void toString(StringBuilder sb) { sb.append( "bind index ["); sb.append(index); diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java index 3962b57315..a05f73f10e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractQuery.java @@ -39,16 +39,15 @@ package org.jooq.impl; import static org.jooq.conf.SettingsTools.executePreparedStatements; import java.sql.Connection; -import java.sql.PreparedStatement; import java.sql.SQLException; import org.jooq.Configuration; -import org.jooq.ConfigurationRegistry; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.Param; import org.jooq.Query; import org.jooq.exception.DetachedException; import org.jooq.tools.JooqLogger; -import org.jooq.tools.StopWatch; /** * @author Lukas Eder @@ -102,13 +101,13 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query { return this; } + @SuppressWarnings("deprecation") @Override public final int execute() { if (isExecutable()) { - StopWatch watch = new StopWatch(); // Let listeners provide a configuration to this query - Configuration configuration = ConfigurationRegistry.provideFor(getConfiguration()); + Configuration configuration = org.jooq.ConfigurationRegistry.provideFor(getConfiguration()); if (configuration == null) { configuration = getConfiguration(); } @@ -118,50 +117,39 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query { throw new DetachedException("Cannot execute query. No Connection configured"); } + ExecuteListener listener = new ExecuteListeners(configuration); + ExecuteContext ctx = new DefaultExecuteContext(configuration, this); + // Ensure that all depending Attachables are attached attach(configuration); - watch.splitTrace("Parts attached"); - PreparedStatement statement = null; - String sql = null; int result = 0; try { - sql = getSQL(); - watch.splitTrace("SQL rendered"); + listener.renderStart(ctx); + ctx.sql(getSQL()); + listener.renderEnd(ctx); - // [#1145] Depending on the configuration, a prepared statement - // or an "ad-hoc" statement is used - boolean usePreparedStatement = executePreparedStatements(getConfiguration().getSettings()); - - if (log.isDebugEnabled()) - log.debug("Executing query", getSQL(true)); - if (log.isTraceEnabled() && usePreparedStatement) - log.trace("Preparing statement", sql); - - statement = prepare(configuration, sql); + listener.prepareStart(ctx); + prepare(ctx); + listener.prepareEnd(ctx); // [#1145] Bind variables only for true prepared statements - if (usePreparedStatement) { - watch.splitTrace("Statement prepared"); - - create(configuration).bind(this, statement); - watch.splitTrace("Variables bound"); + if (executePreparedStatements(getConfiguration().getSettings())) { + listener.bindStart(ctx); + create(configuration).bind(this, ctx.statement()); + listener.bindEnd(ctx); } - result = execute(configuration, statement); - watch.splitTrace("Statement executed"); - + result = execute(ctx, listener); return result; } catch (SQLException e) { - throw Util.translate("AbstractQuery.execute", sql, e); + throw Util.translate("AbstractQuery.execute", ctx.sql(), e); } finally { if (!keepStatementOpen()) { - Util.safeClose(statement); + Util.safeClose(ctx); } - - watch.splitDebug("Statement executed"); } } else { @@ -184,25 +172,23 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query { /** * Default implementation for preparing a statement. Subclasses may override * this method. - * - * @param configuration The configuration holding a connection - * @param sql The generated SQL - * @return The prepared statement */ - protected PreparedStatement prepare(Configuration configuration, String sql) throws SQLException { - return configuration.getConnection().prepareStatement(sql); + protected void prepare(ExecuteContext ctx) throws SQLException { + ctx.statement(ctx.getConnection().prepareStatement(ctx.sql())); } /** * Default implementation for query execution using a prepared statement. * Subclasses may override this method. - * - * @param configuration The configuration that is used for this query's - * execution. - * @param statement The statement to be executed. */ - protected int execute(Configuration configuration, PreparedStatement statement) throws SQLException { - return statement.executeUpdate(); + protected int execute(ExecuteContext ctx, ExecuteListener listener) throws SQLException { + int result = 0; + + listener.executeStart(ctx); + result = ctx.statement().executeUpdate(); + listener.executeEnd(ctx); + + return result; } /** diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java index b651b209e9..d542937117 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java @@ -39,7 +39,6 @@ import static java.util.concurrent.Executors.newSingleThreadExecutor; import java.lang.reflect.Array; import java.sql.Connection; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; @@ -54,6 +53,8 @@ import java.util.concurrent.Future; import org.jooq.Configuration; import org.jooq.Cursor; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.Field; import org.jooq.FieldProvider; import org.jooq.FutureResult; @@ -111,27 +112,25 @@ abstract class AbstractResultQuery extends AbstractQuery imple } @Override - protected final PreparedStatement prepare(Configuration configuration, String sql) throws SQLException { - PreparedStatement statement = super.prepare(configuration, sql); + protected final void prepare(ExecuteContext ctx) throws SQLException { + super.prepare(ctx); if (size > 0) { if (log.isDebugEnabled()) log.debug("Setting fetch size", size); - statement.setFetchSize(size); + ctx.statement().setFetchSize(size); } - - return statement; } @Override - protected final int execute(Configuration configuration, PreparedStatement statement) throws SQLException { - Connection connection = configuration.getConnection(); + protected final int execute(ExecuteContext ctx, ExecuteListener listener) throws SQLException { + Connection connection = ctx.getConnection(); boolean autoCommit = false; // [#706] Postgres requires two separate queries running in the same // transaction to be executed when fetching refcursor types - if (configuration.getDialect() == SQLDialect.POSTGRES && isSelectingRefCursor()) { + if (ctx.getDialect() == SQLDialect.POSTGRES && isSelectingRefCursor()) { autoCommit = connection.getAutoCommit(); if (autoCommit) { @@ -143,12 +142,15 @@ abstract class AbstractResultQuery extends AbstractQuery imple } try { - ResultSet rs = statement.executeQuery(); + listener.executeStart(ctx); + ctx.resultSet(ctx.statement().executeQuery()); + listener.executeEnd(ctx); // Fetch a single result set if (!many) { - FieldList fields = new FieldList(getFields(rs.getMetaData())); - cursor = new CursorImpl(configuration, fields, rs, statement, getRecordType()); + listener.fetchStart(ctx); + FieldList fields = new FieldList(getFields(ctx.resultSet().getMetaData())); + cursor = new CursorImpl(ctx, listener, fields, getRecordType()); if (!lazy) { result = cursor.fetch(); @@ -161,20 +163,21 @@ abstract class AbstractResultQuery extends AbstractQuery imple results = new ArrayList>(); for (;;) { - FieldProvider fields = new MetaDataFieldProvider(configuration, rs.getMetaData()); - Cursor c = new CursorImpl(configuration, fields, rs); + listener.fetchStart(ctx); + FieldProvider fields = new MetaDataFieldProvider(ctx, ctx.resultSet().getMetaData()); + Cursor c = new CursorImpl(ctx, listener, fields); results.add(c.fetch()); - if (statement.getMoreResults()) { - rs = statement.getResultSet(); + if (ctx.statement().getMoreResults()) { + ctx.resultSet(ctx.statement().getResultSet()); } else { break; } } - statement.getMoreResults(Statement.CLOSE_ALL_RESULTS); - statement.close(); + ctx.statement().getMoreResults(Statement.CLOSE_ALL_RESULTS); + ctx.statement().close(); } } finally { diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java index 92e54e0cde..8852b84233 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java @@ -54,6 +54,8 @@ import org.jooq.Attachable; import org.jooq.BindContext; import org.jooq.Configuration; import org.jooq.DataType; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.Field; import org.jooq.Package; import org.jooq.Parameter; @@ -65,8 +67,6 @@ import org.jooq.Schema; import org.jooq.UDTField; import org.jooq.UDTRecord; import org.jooq.tools.Convert; -import org.jooq.tools.JooqLogger; -import org.jooq.tools.StopWatch; /** * A common base class for stored procedures @@ -81,7 +81,6 @@ public abstract class AbstractRoutine extends AbstractSchemaProviderQueryPart * Generated UID */ private static final long serialVersionUID = 6330037113167106443L; - private static final JooqLogger log = JooqLogger.getLogger(AbstractRoutine.class); private final Package pkg; private final List> allParameters; @@ -242,30 +241,25 @@ public abstract class AbstractRoutine extends AbstractSchemaProviderQueryPart } private final int executeCallableStatement() { - StopWatch watch = new StopWatch(); - Configuration configuration = attachable.getConfiguration(); - CallableStatement statement = null; - String sql = null; + ExecuteListener listener = new ExecuteListeners(configuration); + ExecuteContext ctx = new DefaultExecuteContext(configuration, null); + try { Connection connection = configuration.getConnection(); - sql = create(configuration).render(this); - watch.splitTrace("SQL rendered"); + listener.renderStart(ctx); + ctx.sql(create(configuration).render(this)); + listener.renderEnd(ctx); - if (log.isDebugEnabled()) - log.debug("Executing routine", create(configuration).renderInlined(this)); - if (log.isTraceEnabled()) - log.trace("Preparing statement", sql); + listener.prepareStart(ctx); + ctx.statement(connection.prepareCall(ctx.sql())); + listener.prepareEnd(ctx); - statement = connection.prepareCall(sql); - watch.splitTrace("Statement prepared"); - - create(configuration).bind(this, statement); - watch.splitTrace("Variables bound"); - - registerOutParameters(configuration, statement); - watch.splitTrace("OUT params registered"); + listener.bindStart(ctx); + create(configuration).bind(this, ctx.statement()); + registerOutParameters(configuration, (CallableStatement) ctx.statement()); + listener.bindEnd(ctx); // Postgres requires two separate queries running in the same // transaction to be executed when fetching refcursor types @@ -274,25 +268,22 @@ public abstract class AbstractRoutine extends AbstractSchemaProviderQueryPart connection.setAutoCommit(false); } - statement.execute(); + listener.executeStart(ctx); + ctx.statement().execute(); + listener.executeEnd(ctx); if (autoCommit && configuration.getDialect() == SQLDialect.POSTGRES) { connection.setAutoCommit(autoCommit); } - watch.splitTrace("Routine called"); - - fetchOutParameters(configuration, statement); - watch.splitTrace("OUT params fetched"); - + fetchOutParameters(ctx); return 0; } - catch (SQLException exc) { - throw translate("AbstractRoutine.executeCallableStatement", sql, exc); + catch (SQLException e) { + throw translate("AbstractRoutine.executeCallableStatement", ctx.sql(), e); } finally { - Util.safeClose(statement); - watch.splitDebug("Routine executed"); + Util.safeClose(ctx); } } @@ -378,15 +369,14 @@ public abstract class AbstractRoutine extends AbstractSchemaProviderQueryPart context.literal(getName()); } - private final void fetchOutParameters(Configuration configuration, CallableStatement statement) throws SQLException { + private final void fetchOutParameters(ExecuteContext ctx) throws SQLException { for (Parameter parameter : getParameters()) { int index = parameterIndexes.get(parameter); if (parameter.equals(getReturnParameter()) || getOutParameters().contains(parameter)) { - results.put(parameter, FieldTypeHelper.getFromStatement( - configuration, statement, parameter.getType(), index)); + results.put(parameter, FieldTypeHelper.getFromStatement(ctx, parameter.getType(), index)); } } } diff --git a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java index 61b3485e32..d509dc2a64 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java @@ -59,44 +59,41 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.jooq.Configuration; import org.jooq.Cursor; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.Field; import org.jooq.FieldProvider; import org.jooq.Record; import org.jooq.RecordHandler; import org.jooq.Result; import org.jooq.Table; -import org.jooq.tools.JooqLogger; /** * @author Lukas Eder */ class CursorImpl implements Cursor { - /** - * Generated UID - */ - private static final JooqLogger log = JooqLogger.getLogger(CursorImpl.class); + private final ExecuteContext ctx; + private final ExecuteListener listener; + private final FieldProvider fields; + private final Class type; + private boolean isClosed; - private final FieldProvider fields; - private final Configuration configuration; - private final Class type; - private boolean isClosed; - - private transient CursorResultSet rs; - private transient Iterator iterator; + private transient CursorResultSet rs; + private transient Iterator iterator; @SuppressWarnings("unchecked") - CursorImpl(Configuration configuration, FieldProvider fields, ResultSet rs) { - this(configuration, fields, rs, null, (Class) RecordImpl.class); + CursorImpl(ExecuteContext ctx, ExecuteListener listener, FieldProvider fields) { + this(ctx, listener, fields, (Class) RecordImpl.class); } - CursorImpl(Configuration configuration, FieldProvider fields, ResultSet rs, Statement stmt, Class type) { - this.configuration = configuration; + CursorImpl(ExecuteContext ctx, ExecuteListener listener, FieldProvider fields, Class type) { + this.ctx = ctx; + this.listener = (listener != null ? listener : new ExecuteListeners(ctx)); this.fields = fields; this.type = type; - this.rs = new CursorResultSet(stmt, rs); + this.rs = new CursorResultSet(); } @Override @@ -150,22 +147,18 @@ class CursorImpl implements Cursor { @Override public final Result fetch(int number) { - ResultImpl result = new ResultImpl(configuration, fields); + ctx.result(null); + listener.resultStart(ctx); + + ResultImpl result = new ResultImpl(ctx.configuration(), fields); R record = null; for (int i = 0; i < number && ((record = fetchOne()) != null); i++) { result.addRecord(record); } - if (log.isDebugEnabled()) { - String comment = "Fetched result"; - - for (String line : result.format(5).split("\n")) { - log.debug(comment, line); - comment = ""; - } - } - + ctx.result(result); + listener.resultEnd(ctx); return result; } @@ -226,962 +219,955 @@ class CursorImpl implements Cursor { */ private final class CursorResultSet implements ResultSet { - private Statement stmt; - private ResultSet delegate; - - CursorResultSet(Statement stmt, ResultSet delegate) { - this.stmt = stmt; - this.delegate = delegate; - } - @Override public final T unwrap(Class iface) throws SQLException { - return delegate.unwrap(iface); + return ctx.resultSet().unwrap(iface); } @Override public final boolean isWrapperFor(Class iface) throws SQLException { - return delegate.isWrapperFor(iface); + return ctx.resultSet().isWrapperFor(iface); } @Override public final boolean next() throws SQLException { - return delegate.next(); + return ctx.resultSet().next(); } @Override public final void close() throws SQLException { - delegate.close(); - stmt.close(); + listener.fetchEnd(ctx); + ctx.resultSet().close(); + ctx.statement().close(); } @Override public final boolean wasNull() throws SQLException { - return delegate.wasNull(); + return ctx.resultSet().wasNull(); } @Override public final String getString(int columnIndex) throws SQLException { - return delegate.getString(columnIndex); + return ctx.resultSet().getString(columnIndex); } @Override public final boolean getBoolean(int columnIndex) throws SQLException { - return delegate.getBoolean(columnIndex); + return ctx.resultSet().getBoolean(columnIndex); } @Override public final byte getByte(int columnIndex) throws SQLException { - return delegate.getByte(columnIndex); + return ctx.resultSet().getByte(columnIndex); } @Override public final short getShort(int columnIndex) throws SQLException { - return delegate.getShort(columnIndex); + return ctx.resultSet().getShort(columnIndex); } @Override public final int getInt(int columnIndex) throws SQLException { - return delegate.getInt(columnIndex); + return ctx.resultSet().getInt(columnIndex); } @Override public final long getLong(int columnIndex) throws SQLException { - return delegate.getLong(columnIndex); + return ctx.resultSet().getLong(columnIndex); } @Override public final float getFloat(int columnIndex) throws SQLException { - return delegate.getFloat(columnIndex); + return ctx.resultSet().getFloat(columnIndex); } @Override public final double getDouble(int columnIndex) throws SQLException { - return delegate.getDouble(columnIndex); + return ctx.resultSet().getDouble(columnIndex); } @Override @Deprecated public final BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { - return delegate.getBigDecimal(columnIndex, scale); + return ctx.resultSet().getBigDecimal(columnIndex, scale); } @Override public final byte[] getBytes(int columnIndex) throws SQLException { - return delegate.getBytes(columnIndex); + return ctx.resultSet().getBytes(columnIndex); } @Override public final Date getDate(int columnIndex) throws SQLException { - return delegate.getDate(columnIndex); + return ctx.resultSet().getDate(columnIndex); } @Override public final Time getTime(int columnIndex) throws SQLException { - return delegate.getTime(columnIndex); + return ctx.resultSet().getTime(columnIndex); } @Override public final Timestamp getTimestamp(int columnIndex) throws SQLException { - return delegate.getTimestamp(columnIndex); + return ctx.resultSet().getTimestamp(columnIndex); } @Override public final InputStream getAsciiStream(int columnIndex) throws SQLException { - return delegate.getAsciiStream(columnIndex); + return ctx.resultSet().getAsciiStream(columnIndex); } @Override @Deprecated public final InputStream getUnicodeStream(int columnIndex) throws SQLException { - return delegate.getUnicodeStream(columnIndex); + return ctx.resultSet().getUnicodeStream(columnIndex); } @Override public final InputStream getBinaryStream(int columnIndex) throws SQLException { - return delegate.getBinaryStream(columnIndex); + return ctx.resultSet().getBinaryStream(columnIndex); } @Override public final String getString(String columnLabel) throws SQLException { - return delegate.getString(columnLabel); + return ctx.resultSet().getString(columnLabel); } @Override public final boolean getBoolean(String columnLabel) throws SQLException { - return delegate.getBoolean(columnLabel); + return ctx.resultSet().getBoolean(columnLabel); } @Override public final byte getByte(String columnLabel) throws SQLException { - return delegate.getByte(columnLabel); + return ctx.resultSet().getByte(columnLabel); } @Override public final short getShort(String columnLabel) throws SQLException { - return delegate.getShort(columnLabel); + return ctx.resultSet().getShort(columnLabel); } @Override public final int getInt(String columnLabel) throws SQLException { - return delegate.getInt(columnLabel); + return ctx.resultSet().getInt(columnLabel); } @Override public final long getLong(String columnLabel) throws SQLException { - return delegate.getLong(columnLabel); + return ctx.resultSet().getLong(columnLabel); } @Override public final float getFloat(String columnLabel) throws SQLException { - return delegate.getFloat(columnLabel); + return ctx.resultSet().getFloat(columnLabel); } @Override public final double getDouble(String columnLabel) throws SQLException { - return delegate.getDouble(columnLabel); + return ctx.resultSet().getDouble(columnLabel); } @Override @Deprecated public final BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { - return delegate.getBigDecimal(columnLabel, scale); + return ctx.resultSet().getBigDecimal(columnLabel, scale); } @Override public final byte[] getBytes(String columnLabel) throws SQLException { - return delegate.getBytes(columnLabel); + return ctx.resultSet().getBytes(columnLabel); } @Override public final Date getDate(String columnLabel) throws SQLException { - return delegate.getDate(columnLabel); + return ctx.resultSet().getDate(columnLabel); } @Override public final Time getTime(String columnLabel) throws SQLException { - return delegate.getTime(columnLabel); + return ctx.resultSet().getTime(columnLabel); } @Override public final Timestamp getTimestamp(String columnLabel) throws SQLException { - return delegate.getTimestamp(columnLabel); + return ctx.resultSet().getTimestamp(columnLabel); } @Override public final InputStream getAsciiStream(String columnLabel) throws SQLException { - return delegate.getAsciiStream(columnLabel); + return ctx.resultSet().getAsciiStream(columnLabel); } @Override @Deprecated public final InputStream getUnicodeStream(String columnLabel) throws SQLException { - return delegate.getUnicodeStream(columnLabel); + return ctx.resultSet().getUnicodeStream(columnLabel); } @Override public final InputStream getBinaryStream(String columnLabel) throws SQLException { - return delegate.getBinaryStream(columnLabel); + return ctx.resultSet().getBinaryStream(columnLabel); } @Override public final SQLWarning getWarnings() throws SQLException { - return delegate.getWarnings(); + return ctx.resultSet().getWarnings(); } @Override public final void clearWarnings() throws SQLException { - delegate.clearWarnings(); + ctx.resultSet().clearWarnings(); } @Override public final String getCursorName() throws SQLException { - return delegate.getCursorName(); + return ctx.resultSet().getCursorName(); } @Override public final ResultSetMetaData getMetaData() throws SQLException { - return delegate.getMetaData(); + return ctx.resultSet().getMetaData(); } @Override public final Object getObject(int columnIndex) throws SQLException { - return delegate.getObject(columnIndex); + return ctx.resultSet().getObject(columnIndex); } @Override public final Object getObject(String columnLabel) throws SQLException { - return delegate.getObject(columnLabel); + return ctx.resultSet().getObject(columnLabel); } @Override public final int findColumn(String columnLabel) throws SQLException { - return delegate.findColumn(columnLabel); + return ctx.resultSet().findColumn(columnLabel); } @Override public final Reader getCharacterStream(int columnIndex) throws SQLException { - return delegate.getCharacterStream(columnIndex); + return ctx.resultSet().getCharacterStream(columnIndex); } @Override public final Reader getCharacterStream(String columnLabel) throws SQLException { - return delegate.getCharacterStream(columnLabel); + return ctx.resultSet().getCharacterStream(columnLabel); } @Override public final BigDecimal getBigDecimal(int columnIndex) throws SQLException { - return delegate.getBigDecimal(columnIndex); + return ctx.resultSet().getBigDecimal(columnIndex); } @Override public final BigDecimal getBigDecimal(String columnLabel) throws SQLException { - return delegate.getBigDecimal(columnLabel); + return ctx.resultSet().getBigDecimal(columnLabel); } @Override public final boolean isBeforeFirst() throws SQLException { - return delegate.isBeforeFirst(); + return ctx.resultSet().isBeforeFirst(); } @Override public final boolean isAfterLast() throws SQLException { - return delegate.isAfterLast(); + return ctx.resultSet().isAfterLast(); } @Override public final boolean isFirst() throws SQLException { - return delegate.isFirst(); + return ctx.resultSet().isFirst(); } @Override public final boolean isLast() throws SQLException { - return delegate.isLast(); + return ctx.resultSet().isLast(); } @Override public final void beforeFirst() throws SQLException { - delegate.beforeFirst(); + ctx.resultSet().beforeFirst(); } @Override public final void afterLast() throws SQLException { - delegate.afterLast(); + ctx.resultSet().afterLast(); } @Override public final boolean first() throws SQLException { - return delegate.first(); + return ctx.resultSet().first(); } @Override public final boolean last() throws SQLException { - return delegate.last(); + return ctx.resultSet().last(); } @Override public final int getRow() throws SQLException { - return delegate.getRow(); + return ctx.resultSet().getRow(); } @Override public final boolean absolute(int row) throws SQLException { - return delegate.absolute(row); + return ctx.resultSet().absolute(row); } @Override public final boolean relative(int rows) throws SQLException { - return delegate.relative(rows); + return ctx.resultSet().relative(rows); } @Override public final boolean previous() throws SQLException { - return delegate.previous(); + return ctx.resultSet().previous(); } @Override public final void setFetchDirection(int direction) throws SQLException { - delegate.setFetchDirection(direction); + ctx.resultSet().setFetchDirection(direction); } @Override public final int getFetchDirection() throws SQLException { - return delegate.getFetchDirection(); + return ctx.resultSet().getFetchDirection(); } @Override public final void setFetchSize(int rows) throws SQLException { - delegate.setFetchSize(rows); + ctx.resultSet().setFetchSize(rows); } @Override public final int getFetchSize() throws SQLException { - return delegate.getFetchSize(); + return ctx.resultSet().getFetchSize(); } @Override public final int getType() throws SQLException { - return delegate.getType(); + return ctx.resultSet().getType(); } @Override public final int getConcurrency() throws SQLException { - return delegate.getConcurrency(); + return ctx.resultSet().getConcurrency(); } @Override public final boolean rowUpdated() throws SQLException { - return delegate.rowUpdated(); + return ctx.resultSet().rowUpdated(); } @Override public final boolean rowInserted() throws SQLException { - return delegate.rowInserted(); + return ctx.resultSet().rowInserted(); } @Override public final boolean rowDeleted() throws SQLException { - return delegate.rowDeleted(); + return ctx.resultSet().rowDeleted(); } @Override public final void updateNull(int columnIndex) throws SQLException { - delegate.updateNull(columnIndex); + ctx.resultSet().updateNull(columnIndex); } @Override public final void updateBoolean(int columnIndex, boolean x) throws SQLException { - delegate.updateBoolean(columnIndex, x); + ctx.resultSet().updateBoolean(columnIndex, x); } @Override public final void updateByte(int columnIndex, byte x) throws SQLException { - delegate.updateByte(columnIndex, x); + ctx.resultSet().updateByte(columnIndex, x); } @Override public final void updateShort(int columnIndex, short x) throws SQLException { - delegate.updateShort(columnIndex, x); + ctx.resultSet().updateShort(columnIndex, x); } @Override public final void updateInt(int columnIndex, int x) throws SQLException { - delegate.updateInt(columnIndex, x); + ctx.resultSet().updateInt(columnIndex, x); } @Override public final void updateLong(int columnIndex, long x) throws SQLException { - delegate.updateLong(columnIndex, x); + ctx.resultSet().updateLong(columnIndex, x); } @Override public final void updateFloat(int columnIndex, float x) throws SQLException { - delegate.updateFloat(columnIndex, x); + ctx.resultSet().updateFloat(columnIndex, x); } @Override public final void updateDouble(int columnIndex, double x) throws SQLException { - delegate.updateDouble(columnIndex, x); + ctx.resultSet().updateDouble(columnIndex, x); } @Override public final void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { - delegate.updateBigDecimal(columnIndex, x); + ctx.resultSet().updateBigDecimal(columnIndex, x); } @Override public final void updateString(int columnIndex, String x) throws SQLException { - delegate.updateString(columnIndex, x); + ctx.resultSet().updateString(columnIndex, x); } @Override public final void updateBytes(int columnIndex, byte[] x) throws SQLException { - delegate.updateBytes(columnIndex, x); + ctx.resultSet().updateBytes(columnIndex, x); } @Override public final void updateDate(int columnIndex, Date x) throws SQLException { - delegate.updateDate(columnIndex, x); + ctx.resultSet().updateDate(columnIndex, x); } @Override public final void updateTime(int columnIndex, Time x) throws SQLException { - delegate.updateTime(columnIndex, x); + ctx.resultSet().updateTime(columnIndex, x); } @Override public final void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { - delegate.updateTimestamp(columnIndex, x); + ctx.resultSet().updateTimestamp(columnIndex, x); } @Override public final void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { - delegate.updateAsciiStream(columnIndex, x, length); + ctx.resultSet().updateAsciiStream(columnIndex, x, length); } @Override public final void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { - delegate.updateBinaryStream(columnIndex, x, length); + ctx.resultSet().updateBinaryStream(columnIndex, x, length); } @Override public final void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { - delegate.updateCharacterStream(columnIndex, x, length); + ctx.resultSet().updateCharacterStream(columnIndex, x, length); } @Override public final void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { - delegate.updateObject(columnIndex, x, scaleOrLength); + ctx.resultSet().updateObject(columnIndex, x, scaleOrLength); } @Override public final void updateObject(int columnIndex, Object x) throws SQLException { - delegate.updateObject(columnIndex, x); + ctx.resultSet().updateObject(columnIndex, x); } @Override public final void updateNull(String columnLabel) throws SQLException { - delegate.updateNull(columnLabel); + ctx.resultSet().updateNull(columnLabel); } @Override public final void updateBoolean(String columnLabel, boolean x) throws SQLException { - delegate.updateBoolean(columnLabel, x); + ctx.resultSet().updateBoolean(columnLabel, x); } @Override public final void updateByte(String columnLabel, byte x) throws SQLException { - delegate.updateByte(columnLabel, x); + ctx.resultSet().updateByte(columnLabel, x); } @Override public final void updateShort(String columnLabel, short x) throws SQLException { - delegate.updateShort(columnLabel, x); + ctx.resultSet().updateShort(columnLabel, x); } @Override public final void updateInt(String columnLabel, int x) throws SQLException { - delegate.updateInt(columnLabel, x); + ctx.resultSet().updateInt(columnLabel, x); } @Override public final void updateLong(String columnLabel, long x) throws SQLException { - delegate.updateLong(columnLabel, x); + ctx.resultSet().updateLong(columnLabel, x); } @Override public final void updateFloat(String columnLabel, float x) throws SQLException { - delegate.updateFloat(columnLabel, x); + ctx.resultSet().updateFloat(columnLabel, x); } @Override public final void updateDouble(String columnLabel, double x) throws SQLException { - delegate.updateDouble(columnLabel, x); + ctx.resultSet().updateDouble(columnLabel, x); } @Override public final void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { - delegate.updateBigDecimal(columnLabel, x); + ctx.resultSet().updateBigDecimal(columnLabel, x); } @Override public final void updateString(String columnLabel, String x) throws SQLException { - delegate.updateString(columnLabel, x); + ctx.resultSet().updateString(columnLabel, x); } @Override public final void updateBytes(String columnLabel, byte[] x) throws SQLException { - delegate.updateBytes(columnLabel, x); + ctx.resultSet().updateBytes(columnLabel, x); } @Override public final void updateDate(String columnLabel, Date x) throws SQLException { - delegate.updateDate(columnLabel, x); + ctx.resultSet().updateDate(columnLabel, x); } @Override public final void updateTime(String columnLabel, Time x) throws SQLException { - delegate.updateTime(columnLabel, x); + ctx.resultSet().updateTime(columnLabel, x); } @Override public final void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { - delegate.updateTimestamp(columnLabel, x); + ctx.resultSet().updateTimestamp(columnLabel, x); } @Override public final void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { - delegate.updateAsciiStream(columnLabel, x, length); + ctx.resultSet().updateAsciiStream(columnLabel, x, length); } @Override public final void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException { - delegate.updateBinaryStream(columnLabel, x, length); + ctx.resultSet().updateBinaryStream(columnLabel, x, length); } @Override public final void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException { - delegate.updateCharacterStream(columnLabel, reader, length); + ctx.resultSet().updateCharacterStream(columnLabel, reader, length); } @Override public final void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { - delegate.updateObject(columnLabel, x, scaleOrLength); + ctx.resultSet().updateObject(columnLabel, x, scaleOrLength); } @Override public final void updateObject(String columnLabel, Object x) throws SQLException { - delegate.updateObject(columnLabel, x); + ctx.resultSet().updateObject(columnLabel, x); } @Override public final void insertRow() throws SQLException { - delegate.insertRow(); + ctx.resultSet().insertRow(); } @Override public final void updateRow() throws SQLException { - delegate.updateRow(); + ctx.resultSet().updateRow(); } @Override public final void deleteRow() throws SQLException { - delegate.deleteRow(); + ctx.resultSet().deleteRow(); } @Override public final void refreshRow() throws SQLException { - delegate.refreshRow(); + ctx.resultSet().refreshRow(); } @Override public final void cancelRowUpdates() throws SQLException { - delegate.cancelRowUpdates(); + ctx.resultSet().cancelRowUpdates(); } @Override public final void moveToInsertRow() throws SQLException { - delegate.moveToInsertRow(); + ctx.resultSet().moveToInsertRow(); } @Override public final void moveToCurrentRow() throws SQLException { - delegate.moveToCurrentRow(); + ctx.resultSet().moveToCurrentRow(); } @Override public final Statement getStatement() throws SQLException { - return delegate.getStatement(); + return ctx.resultSet().getStatement(); } @Override public final Object getObject(int columnIndex, Map> map) throws SQLException { - return delegate.getObject(columnIndex, map); + return ctx.resultSet().getObject(columnIndex, map); } @Override public final Ref getRef(int columnIndex) throws SQLException { - return delegate.getRef(columnIndex); + return ctx.resultSet().getRef(columnIndex); } @Override public final Blob getBlob(int columnIndex) throws SQLException { - return delegate.getBlob(columnIndex); + return ctx.resultSet().getBlob(columnIndex); } @Override public final Clob getClob(int columnIndex) throws SQLException { - return delegate.getClob(columnIndex); + return ctx.resultSet().getClob(columnIndex); } @Override public final Array getArray(int columnIndex) throws SQLException { - return delegate.getArray(columnIndex); + return ctx.resultSet().getArray(columnIndex); } @Override public final Object getObject(String columnLabel, Map> map) throws SQLException { - return delegate.getObject(columnLabel, map); + return ctx.resultSet().getObject(columnLabel, map); } @Override public final Ref getRef(String columnLabel) throws SQLException { - return delegate.getRef(columnLabel); + return ctx.resultSet().getRef(columnLabel); } @Override public final Blob getBlob(String columnLabel) throws SQLException { - return delegate.getBlob(columnLabel); + return ctx.resultSet().getBlob(columnLabel); } @Override public final Clob getClob(String columnLabel) throws SQLException { - return delegate.getClob(columnLabel); + return ctx.resultSet().getClob(columnLabel); } @Override public final Array getArray(String columnLabel) throws SQLException { - return delegate.getArray(columnLabel); + return ctx.resultSet().getArray(columnLabel); } @Override public final Date getDate(int columnIndex, Calendar cal) throws SQLException { - return delegate.getDate(columnIndex, cal); + return ctx.resultSet().getDate(columnIndex, cal); } @Override public final Date getDate(String columnLabel, Calendar cal) throws SQLException { - return delegate.getDate(columnLabel, cal); + return ctx.resultSet().getDate(columnLabel, cal); } @Override public final Time getTime(int columnIndex, Calendar cal) throws SQLException { - return delegate.getTime(columnIndex, cal); + return ctx.resultSet().getTime(columnIndex, cal); } @Override public final Time getTime(String columnLabel, Calendar cal) throws SQLException { - return delegate.getTime(columnLabel, cal); + return ctx.resultSet().getTime(columnLabel, cal); } @Override public final Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { - return delegate.getTimestamp(columnIndex, cal); + return ctx.resultSet().getTimestamp(columnIndex, cal); } @Override public final Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { - return delegate.getTimestamp(columnLabel, cal); + return ctx.resultSet().getTimestamp(columnLabel, cal); } @Override public final URL getURL(int columnIndex) throws SQLException { - return delegate.getURL(columnIndex); + return ctx.resultSet().getURL(columnIndex); } @Override public final URL getURL(String columnLabel) throws SQLException { - return delegate.getURL(columnLabel); + return ctx.resultSet().getURL(columnLabel); } @Override public final void updateRef(int columnIndex, Ref x) throws SQLException { - delegate.updateRef(columnIndex, x); + ctx.resultSet().updateRef(columnIndex, x); } @Override public final void updateRef(String columnLabel, Ref x) throws SQLException { - delegate.updateRef(columnLabel, x); + ctx.resultSet().updateRef(columnLabel, x); } @Override public final void updateBlob(int columnIndex, Blob x) throws SQLException { - delegate.updateBlob(columnIndex, x); + ctx.resultSet().updateBlob(columnIndex, x); } @Override public final void updateBlob(String columnLabel, Blob x) throws SQLException { - delegate.updateBlob(columnLabel, x); + ctx.resultSet().updateBlob(columnLabel, x); } @Override public final void updateClob(int columnIndex, Clob x) throws SQLException { - delegate.updateClob(columnIndex, x); + ctx.resultSet().updateClob(columnIndex, x); } @Override public final void updateClob(String columnLabel, Clob x) throws SQLException { - delegate.updateClob(columnLabel, x); + ctx.resultSet().updateClob(columnLabel, x); } @Override public final void updateArray(int columnIndex, Array x) throws SQLException { - delegate.updateArray(columnIndex, x); + ctx.resultSet().updateArray(columnIndex, x); } @Override public final void updateArray(String columnLabel, Array x) throws SQLException { - delegate.updateArray(columnLabel, x); + ctx.resultSet().updateArray(columnLabel, x); } @Override public final RowId getRowId(int columnIndex) throws SQLException { - return delegate.getRowId(columnIndex); + return ctx.resultSet().getRowId(columnIndex); } @Override public final RowId getRowId(String columnLabel) throws SQLException { - return delegate.getRowId(columnLabel); + return ctx.resultSet().getRowId(columnLabel); } @Override public final void updateRowId(int columnIndex, RowId x) throws SQLException { - delegate.updateRowId(columnIndex, x); + ctx.resultSet().updateRowId(columnIndex, x); } @Override public final void updateRowId(String columnLabel, RowId x) throws SQLException { - delegate.updateRowId(columnLabel, x); + ctx.resultSet().updateRowId(columnLabel, x); } @Override public final int getHoldability() throws SQLException { - return delegate.getHoldability(); + return ctx.resultSet().getHoldability(); } @Override public final boolean isClosed() throws SQLException { - return delegate.isClosed(); + return ctx.resultSet().isClosed(); } @Override public final void updateNString(int columnIndex, String nString) throws SQLException { - delegate.updateNString(columnIndex, nString); + ctx.resultSet().updateNString(columnIndex, nString); } @Override public final void updateNString(String columnLabel, String nString) throws SQLException { - delegate.updateNString(columnLabel, nString); + ctx.resultSet().updateNString(columnLabel, nString); } @Override public final void updateNClob(int columnIndex, NClob nClob) throws SQLException { - delegate.updateNClob(columnIndex, nClob); + ctx.resultSet().updateNClob(columnIndex, nClob); } @Override public final void updateNClob(String columnLabel, NClob nClob) throws SQLException { - delegate.updateNClob(columnLabel, nClob); + ctx.resultSet().updateNClob(columnLabel, nClob); } @Override public final NClob getNClob(int columnIndex) throws SQLException { - return delegate.getNClob(columnIndex); + return ctx.resultSet().getNClob(columnIndex); } @Override public final NClob getNClob(String columnLabel) throws SQLException { - return delegate.getNClob(columnLabel); + return ctx.resultSet().getNClob(columnLabel); } @Override public final SQLXML getSQLXML(int columnIndex) throws SQLException { - return delegate.getSQLXML(columnIndex); + return ctx.resultSet().getSQLXML(columnIndex); } @Override public final SQLXML getSQLXML(String columnLabel) throws SQLException { - return delegate.getSQLXML(columnLabel); + return ctx.resultSet().getSQLXML(columnLabel); } @Override public final void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { - delegate.updateSQLXML(columnIndex, xmlObject); + ctx.resultSet().updateSQLXML(columnIndex, xmlObject); } @Override public final void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { - delegate.updateSQLXML(columnLabel, xmlObject); + ctx.resultSet().updateSQLXML(columnLabel, xmlObject); } @Override public final String getNString(int columnIndex) throws SQLException { - return delegate.getNString(columnIndex); + return ctx.resultSet().getNString(columnIndex); } @Override public final String getNString(String columnLabel) throws SQLException { - return delegate.getNString(columnLabel); + return ctx.resultSet().getNString(columnLabel); } @Override public final Reader getNCharacterStream(int columnIndex) throws SQLException { - return delegate.getNCharacterStream(columnIndex); + return ctx.resultSet().getNCharacterStream(columnIndex); } @Override public final Reader getNCharacterStream(String columnLabel) throws SQLException { - return delegate.getNCharacterStream(columnLabel); + return ctx.resultSet().getNCharacterStream(columnLabel); } @Override public final void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { - delegate.updateNCharacterStream(columnIndex, x, length); + ctx.resultSet().updateNCharacterStream(columnIndex, x, length); } @Override public final void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { - delegate.updateNCharacterStream(columnLabel, reader, length); + ctx.resultSet().updateNCharacterStream(columnLabel, reader, length); } @Override public final void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { - delegate.updateAsciiStream(columnIndex, x, length); + ctx.resultSet().updateAsciiStream(columnIndex, x, length); } @Override public final void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { - delegate.updateBinaryStream(columnIndex, x, length); + ctx.resultSet().updateBinaryStream(columnIndex, x, length); } @Override public final void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { - delegate.updateCharacterStream(columnIndex, x, length); + ctx.resultSet().updateCharacterStream(columnIndex, x, length); } @Override public final void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException { - delegate.updateAsciiStream(columnLabel, x, length); + ctx.resultSet().updateAsciiStream(columnLabel, x, length); } @Override public final void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { - delegate.updateBinaryStream(columnLabel, x, length); + ctx.resultSet().updateBinaryStream(columnLabel, x, length); } @Override public final void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { - delegate.updateCharacterStream(columnLabel, reader, length); + ctx.resultSet().updateCharacterStream(columnLabel, reader, length); } @Override public final void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException { - delegate.updateBlob(columnIndex, inputStream, length); + ctx.resultSet().updateBlob(columnIndex, inputStream, length); } @Override public final void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { - delegate.updateBlob(columnLabel, inputStream, length); + ctx.resultSet().updateBlob(columnLabel, inputStream, length); } @Override public final void updateClob(int columnIndex, Reader reader, long length) throws SQLException { - delegate.updateClob(columnIndex, reader, length); + ctx.resultSet().updateClob(columnIndex, reader, length); } @Override public final void updateClob(String columnLabel, Reader reader, long length) throws SQLException { - delegate.updateClob(columnLabel, reader, length); + ctx.resultSet().updateClob(columnLabel, reader, length); } @Override public final void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { - delegate.updateNClob(columnIndex, reader, length); + ctx.resultSet().updateNClob(columnIndex, reader, length); } @Override public final void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { - delegate.updateNClob(columnLabel, reader, length); + ctx.resultSet().updateNClob(columnLabel, reader, length); } @Override public final void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { - delegate.updateNCharacterStream(columnIndex, x); + ctx.resultSet().updateNCharacterStream(columnIndex, x); } @Override public final void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { - delegate.updateNCharacterStream(columnLabel, reader); + ctx.resultSet().updateNCharacterStream(columnLabel, reader); } @Override public final void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { - delegate.updateAsciiStream(columnIndex, x); + ctx.resultSet().updateAsciiStream(columnIndex, x); } @Override public final void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { - delegate.updateBinaryStream(columnIndex, x); + ctx.resultSet().updateBinaryStream(columnIndex, x); } @Override public final void updateCharacterStream(int columnIndex, Reader x) throws SQLException { - delegate.updateCharacterStream(columnIndex, x); + ctx.resultSet().updateCharacterStream(columnIndex, x); } @Override public final void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { - delegate.updateAsciiStream(columnLabel, x); + ctx.resultSet().updateAsciiStream(columnLabel, x); } @Override public final void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { - delegate.updateBinaryStream(columnLabel, x); + ctx.resultSet().updateBinaryStream(columnLabel, x); } @Override public final void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { - delegate.updateCharacterStream(columnLabel, reader); + ctx.resultSet().updateCharacterStream(columnLabel, reader); } @Override public final void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { - delegate.updateBlob(columnIndex, inputStream); + ctx.resultSet().updateBlob(columnIndex, inputStream); } @Override public final void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { - delegate.updateBlob(columnLabel, inputStream); + ctx.resultSet().updateBlob(columnLabel, inputStream); } @Override public final void updateClob(int columnIndex, Reader reader) throws SQLException { - delegate.updateClob(columnIndex, reader); + ctx.resultSet().updateClob(columnIndex, reader); } @Override public final void updateClob(String columnLabel, Reader reader) throws SQLException { - delegate.updateClob(columnLabel, reader); + ctx.resultSet().updateClob(columnLabel, reader); } @Override public final void updateNClob(int columnIndex, Reader reader) throws SQLException { - delegate.updateNClob(columnIndex, reader); + ctx.resultSet().updateNClob(columnIndex, reader); } @Override public final void updateNClob(String columnLabel, Reader reader) throws SQLException { - delegate.updateNClob(columnLabel, reader); + ctx.resultSet().updateNClob(columnLabel, reader); } } @@ -1232,21 +1218,23 @@ class CursorImpl implements Cursor { try { if (!isClosed && rs.next()) { - record = Util.newRecord(type, fields, configuration); + ctx.record(null); + listener.recordStart(ctx); + + record = Util.newRecord(type, fields, ctx.configuration()); final List> fieldList = fields.getFields(); final int size = fieldList.size(); for (int i = 0; i < size; i++) { - setValue((AbstractRecord) record, fieldList.get(i), i, rs); + setValue((AbstractRecord) record, fieldList.get(i), i); } - if (log.isTraceEnabled()) { - log.trace("Fetching record", record); - } + ctx.record(record); + listener.recordEnd(ctx); } } catch (SQLException e) { - throw Util.translate("Cursor.fetch", null, e); + throw Util.translate("Cursor.fetch", ctx.sql(), e); } // Conveniently close cursors and underlying objects after the last @@ -1261,8 +1249,8 @@ class CursorImpl implements Cursor { /** * Utility method to prevent unnecessary unchecked conversions */ - private final void setValue(AbstractRecord record, Field field, int index, ResultSet rs) throws SQLException { - T value = FieldTypeHelper.getFromResultSet(configuration, rs, field, index + 1); + private final void setValue(AbstractRecord record, Field field, int index) throws SQLException { + T value = FieldTypeHelper.getFromResultSet(ctx, field, index + 1); record.setValue(field, new Value(value)); } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java new file mode 100644 index 0000000000..b7f26d1e5d --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java @@ -0,0 +1,138 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.impl; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import org.jooq.Configuration; +import org.jooq.ExecuteContext; +import org.jooq.Query; +import org.jooq.Record; +import org.jooq.Result; + +/** + * A default iplementation for the {@link ExecuteContext} + * + * @author Lukas Eder + */ +class DefaultExecuteContext extends AbstractConfiguration implements ExecuteContext { + + /** + * Generated UID + */ + private static final long serialVersionUID = -6653474082935089963L; + + // Persistent attributes + private final Query query; + private String sql; + + // Transient attributes + private transient PreparedStatement statement; + private transient ResultSet resultSet; + private transient Record record; + private transient Result result; + + DefaultExecuteContext(Configuration configuration) { + this(configuration, null); + } + + DefaultExecuteContext(Configuration configuration, Query query) { + super(configuration); + + this.query = query; + } + + @Override + public final Query query() { + return query; + } + + @Override + public final void sql(String s) { + this.sql = s; + } + + @Override + public final String sql() { + return sql; + } + + @Override + public final void statement(PreparedStatement s) { + this.statement = s; + } + + @Override + public final PreparedStatement statement() { + return statement; + } + + @Override + public final void resultSet(ResultSet rs) { + this.resultSet = rs; + } + + @Override + public final ResultSet resultSet() { + return resultSet; + } + + @Override + public final Configuration configuration() { + return configuration; + } + + @Override + public final void record(Record r) { + this.record = r; + } + + @Override + public final Record record() { + return record; + } + + @Override + public final void result(Result r) { + this.result = r; + } + + @Override + public final Result result() { + return result; + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/ExecuteListeners.java b/jOOQ/src/main/java/org/jooq/impl/ExecuteListeners.java new file mode 100644 index 0000000000..0ee9379a6c --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/ExecuteListeners.java @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.impl; + +import java.util.List; + +import org.jooq.Configuration; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; +import org.jooq.conf.Settings; + +/** + * A queue implementation for several {@link ExecuteListener} objects as defined + * in {@link Settings#getExecuteListeners()} + * + * @author Lukas Eder + */ +class ExecuteListeners implements ExecuteListener { + + private final List listeners; + + ExecuteListeners(Configuration configuration) { + listeners = Util.getListeners(configuration); + } + + @Override + public final void init(ExecuteContext ctx) { + throw new UnsupportedOperationException(); + } + + @Override + public final void renderStart(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.renderStart(ctx); + } + } + + @Override + public final void renderEnd(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.renderEnd(ctx); + } + } + + @Override + public final void prepareStart(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.prepareStart(ctx); + } + } + + @Override + public final void prepareEnd(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.prepareEnd(ctx); + } + } + + @Override + public final void bindStart(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.bindStart(ctx); + } + } + + @Override + public final void bindEnd(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.bindEnd(ctx); + } + } + + @Override + public final void executeStart(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.executeStart(ctx); + } + } + + @Override + public final void executeEnd(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.executeEnd(ctx); + } + } + + @Override + public final void fetchStart(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.fetchStart(ctx); + } + } + + @Override + public final void fetchEnd(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.fetchEnd(ctx); + } + } + + @Override + public final void recordStart(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.recordStart(ctx); + } + } + + @Override + public final void recordEnd(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.recordEnd(ctx); + } + } + + @Override + public void resultStart(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.resultStart(ctx); + } + } + + @Override + public void resultEnd(ExecuteContext ctx) { + for (ExecuteListener listener : listeners) { + listener.resultEnd(ctx); + } + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/Factory.java b/jOOQ/src/main/java/org/jooq/impl/Factory.java index 8af83d5a71..b8d9ef8aeb 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Factory.java +++ b/jOOQ/src/main/java/org/jooq/impl/Factory.java @@ -82,11 +82,12 @@ import org.jooq.BindContext; import org.jooq.Case; import org.jooq.Condition; import org.jooq.Configuration; -import org.jooq.ConfigurationRegistry; import org.jooq.DataType; import org.jooq.DatePart; import org.jooq.DeleteQuery; import org.jooq.DeleteWhereStep; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.FactoryOperations; import org.jooq.Field; import org.jooq.FieldProvider; @@ -965,12 +966,18 @@ public class Factory implements FactoryOperations { */ @Override public final Result fetch(ResultSet rs) { + ExecuteListener listener = new ExecuteListeners(this); + ExecuteContext ctx = new DefaultExecuteContext(this, null); + try { FieldProvider fields = new MetaDataFieldProvider(this, rs.getMetaData()); - return new CursorImpl(this, fields, rs).fetch(); + + ctx.resultSet(rs); + listener.fetchStart(ctx); + return new CursorImpl(ctx, listener, fields).fetch(); } catch (SQLException e) { - throw Util.translate("Factory.fetch", null, e); + throw Util.translate("Factory.fetch", ctx.sql(), e); } } @@ -4721,6 +4728,7 @@ public class Factory implements FactoryOperations { out.defaultWriteObject(); } + @SuppressWarnings("deprecation") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); @@ -4728,7 +4736,7 @@ public class Factory implements FactoryOperations { log.debug("Deserialising", this); } - Configuration registered = ConfigurationRegistry.provideFor(this); + Configuration registered = org.jooq.ConfigurationRegistry.provideFor(this); if (registered != null) { connection = registered.getConnection(); } diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldTypeHelper.java b/jOOQ/src/main/java/org/jooq/impl/FieldTypeHelper.java index da4d49141a..fe878981ed 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldTypeHelper.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldTypeHelper.java @@ -36,6 +36,8 @@ package org.jooq.impl; +import static org.jooq.impl.Factory.getNewFactory; + import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Array; @@ -58,13 +60,11 @@ import java.util.Map; import org.jooq.ArrayRecord; import org.jooq.Configuration; -import org.jooq.Cursor; import org.jooq.DataType; import org.jooq.EnumType; +import org.jooq.ExecuteContext; import org.jooq.Field; -import org.jooq.FieldProvider; import org.jooq.MasterDataType; -import org.jooq.Record; import org.jooq.Result; import org.jooq.SQLDialect; import org.jooq.UDTRecord; @@ -280,17 +280,19 @@ public final class FieldTypeHelper { } } - public static T getFromResultSet(Configuration configuration, ResultSet rs, Field field, int index) + static T getFromResultSet(ExecuteContext ctx, Field field, int index) throws SQLException { Class type = field.getType(); - return getFromResultSet(configuration, rs, type, index); + return getFromResultSet(ctx, type, index); } @SuppressWarnings("unchecked") - private static T getFromResultSet(Configuration configuration, ResultSet rs, Class type, int index) + private static T getFromResultSet(ExecuteContext ctx, Class type, int index) throws SQLException { + ResultSet rs = ctx.resultSet(); + if (type == Blob.class) { return (T) rs.getBlob(index); } @@ -299,7 +301,7 @@ public final class FieldTypeHelper { } else if (type == BigInteger.class) { // The SQLite JDBC driver doesn't support BigDecimals - if (configuration.getDialect() == SQLDialect.SQLITE) { + if (ctx.getDialect() == SQLDialect.SQLITE) { return Convert.convert(rs.getString(index), (Class) BigInteger.class); } else { @@ -309,7 +311,7 @@ public final class FieldTypeHelper { } else if (type == BigDecimal.class) { // The SQLite JDBC driver doesn't support BigDecimals - if (configuration.getDialect() == SQLDialect.SQLITE) { + if (ctx.getDialect() == SQLDialect.SQLITE) { return Convert.convert(rs.getString(index), (Class) BigDecimal.class); } else { @@ -326,7 +328,7 @@ public final class FieldTypeHelper { return (T) rs.getClob(index); } else if (type == Date.class) { - return (T) getDate(configuration.getDialect(), rs, index); + return (T) getDate(ctx.getDialect(), rs, index); } else if (type == Double.class) { return (T) checkWasNull(rs, Double.valueOf(rs.getDouble(index))); @@ -347,10 +349,10 @@ public final class FieldTypeHelper { return (T) rs.getString(index); } else if (type == Time.class) { - return (T) getTime(configuration.getDialect(), rs, index); + return (T) getTime(ctx.getDialect(), rs, index); } else if (type == Timestamp.class) { - return (T) getTimestamp(configuration.getDialect(), rs, index); + return (T) getTimestamp(ctx.getDialect(), rs, index); } else if (type == UByte.class) { String string = rs.getString(index); @@ -371,19 +373,19 @@ public final class FieldTypeHelper { // The type byte[] is handled earlier. byte[][] can be handled here else if (type.isArray()) { - switch (configuration.getDialect()) { + switch (ctx.getDialect()) { case POSTGRES: { - return pgGetArray(configuration, rs, type, index); + return pgGetArray(ctx, type, index); } 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 - return (T) convertArray(rs.getArray(index), (Class )type); + return (T) convertArray(rs.getArray(index), (Class) type); } } else if (ArrayRecord.class.isAssignableFrom(type)) { - return (T) getArrayRecord(configuration, rs.getArray(index), (Class>) type); + return (T) getArrayRecord(ctx, rs.getArray(index), (Class>) type); } else if (EnumType.class.isAssignableFrom(type)) { return getEnumType(type, rs.getString(index)); @@ -392,7 +394,7 @@ public final class FieldTypeHelper { return (T) getMasterDataType(type, rs.getObject(index)); } else if (UDTRecord.class.isAssignableFrom(type)) { - switch (configuration.getDialect()) { + switch (ctx.getDialect()) { case POSTGRES: return (T) pgNewUDTRecord(type, rs.getObject(index)); } @@ -401,9 +403,7 @@ public final class FieldTypeHelper { } else if (Result.class.isAssignableFrom(type)) { ResultSet nested = (ResultSet) rs.getObject(index); - FieldProvider fields = new MetaDataFieldProvider(configuration, nested.getMetaData()); - Cursor cursor = new CursorImpl(configuration, fields, nested); - return (T) cursor.fetch(); + return (T) getNewFactory(ctx).fetch(nested); } else { return (T) rs.getObject(index); @@ -567,7 +567,9 @@ public final class FieldTypeHelper { } @SuppressWarnings("unchecked") - public static T getFromStatement(Configuration configuration, CallableStatement stmt, Class type, int index) throws SQLException { + public static T getFromStatement(ExecuteContext ctx, Class type, int index) throws SQLException { + CallableStatement stmt = (CallableStatement) ctx.statement(); + if (type == Blob.class) { return (T) stmt.getBlob(index); } @@ -639,7 +641,7 @@ public final class FieldTypeHelper { return (T) convertArray(stmt.getObject(index), (Class)type); } else if (ArrayRecord.class.isAssignableFrom(type)) { - return (T) getArrayRecord(configuration, stmt.getArray(index), (Class>) type); + return (T) getArrayRecord(ctx, stmt.getArray(index), (Class>) type); } else if (EnumType.class.isAssignableFrom(type)) { return getEnumType(type, stmt.getString(index)); @@ -648,7 +650,7 @@ public final class FieldTypeHelper { return (T) getMasterDataType(type, stmt.getString(index)); } else if (UDTRecord.class.isAssignableFrom(type)) { - switch (configuration.getDialect()) { + switch (ctx.getDialect()) { case POSTGRES: return (T) pgNewUDTRecord(type, stmt.getObject(index)); } @@ -657,9 +659,7 @@ public final class FieldTypeHelper { } else if (Result.class.isAssignableFrom(type)) { ResultSet nested = (ResultSet) stmt.getObject(index); - FieldProvider fields = new MetaDataFieldProvider(configuration, nested.getMetaData()); - Cursor cursor = new CursorImpl(configuration, fields, nested); - return (T) cursor.fetch(); + return (T) getNewFactory(ctx).fetch(nested); } else { return (T) stmt.getObject(index); @@ -923,9 +923,11 @@ public final class FieldTypeHelper { * Workarounds for the unimplemented Postgres JDBC driver features */ @SuppressWarnings("unchecked") - private static T pgGetArray(Configuration configuration, ResultSet rs, Class type, int index) + private static T pgGetArray(ExecuteContext ctx, Class type, int index) throws SQLException { + ResultSet rs = ctx.resultSet(); + // Get the JDBC Array and check for null. If null, that's OK Array array = rs.getArray(index); if (array == null) { @@ -943,9 +945,9 @@ public final class FieldTypeHelper { // Try fetching the array as a JDBC ResultSet try { - ResultSet elements = array.getResultSet(); - while (elements.next()) { - result.add(getFromResultSet(configuration, elements, type.getComponentType(), 2)); + ctx.resultSet(array.getResultSet()); + while (ctx.resultSet().next()) { + result.add(getFromResultSet(ctx, type.getComponentType(), 2)); } } @@ -956,6 +958,10 @@ public final class FieldTypeHelper { return null; } + finally { + ctx.resultSet(rs); + } + return (T) convertArray(result.toArray(), (Class) type); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java index 679d8592b7..428301f05b 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java @@ -40,7 +40,6 @@ import static org.jooq.impl.Factory.val; import static org.jooq.util.sqlite.SQLiteFactory.rowid; import java.sql.Connection; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -54,6 +53,8 @@ import org.jooq.Attachable; import org.jooq.BindContext; import org.jooq.Condition; import org.jooq.Configuration; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.Field; import org.jooq.Identity; import org.jooq.InsertQuery; @@ -305,23 +306,25 @@ class InsertQueryImpl extends AbstractStoreQuery implements } @Override - protected final PreparedStatement prepare(Configuration configuration, String sql) throws SQLException { - Connection connection = configuration.getConnection(); + protected final void prepare(ExecuteContext ctx) throws SQLException { + Connection connection = ctx.getConnection(); // Just in case, always set Sybase ASE statement mode to return // Generated keys if client code wants to SELECT @@identity afterwards - if (configuration.getDialect() == SQLDialect.ASE) { - return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + if (ctx.getDialect() == SQLDialect.ASE) { + ctx.statement(connection.prepareStatement(ctx.sql(), Statement.RETURN_GENERATED_KEYS)); + return; } // Normal statement preparing if no values should be returned else if (returning.isEmpty()) { - return super.prepare(configuration, sql); + super.prepare(ctx); + return; } // Values should be returned from the INSERT else { - switch (configuration.getDialect()) { + switch (ctx.getDialect()) { // Postgres uses the RETURNING clause in SQL case POSTGRES: @@ -329,7 +332,8 @@ class InsertQueryImpl extends AbstractStoreQuery implements case SQLITE: // Sybase will select @@identity after the INSERT case SYBASE: - return super.prepare(configuration, sql); + super.prepare(ctx); + return; // Some dialects can only return AUTO_INCREMENT values // Other values have to be fetched in a second step @@ -339,7 +343,8 @@ class InsertQueryImpl extends AbstractStoreQuery implements case INGRES: case MYSQL: case SQLSERVER: - return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + ctx.statement(connection.prepareStatement(ctx.sql(), Statement.RETURN_GENERATED_KEYS)); + return; // The default is to return all requested fields directly default: { @@ -349,28 +354,28 @@ class InsertQueryImpl extends AbstractStoreQuery implements names.add(field.getName()); } - return connection.prepareStatement(sql, names.toArray(new String[names.size()])); + ctx.statement(connection.prepareStatement(ctx.sql(), names.toArray(new String[names.size()]))); + return; } } } } @Override - protected final int execute(Configuration configuration, PreparedStatement statement) throws SQLException { + protected final int execute(ExecuteContext ctx, ExecuteListener listener) throws SQLException { if (returning.isEmpty()) { - return super.execute(configuration, statement); + return super.execute(ctx, listener); } else { int result = 1; ResultSet rs; - - switch (configuration.getDialect()) { + switch (ctx.getDialect()) { // SQLite can select _rowid_ after the insert case SQLITE: { - result = statement.executeUpdate(); + result = ctx.statement().executeUpdate(); - SQLiteFactory create = new SQLiteFactory(configuration.getConnection()); + SQLiteFactory create = new SQLiteFactory(ctx.getConnection()); returned = create.select(returning) .from(getInto()) @@ -385,8 +390,8 @@ class InsertQueryImpl extends AbstractStoreQuery implements // Generated keys don't work with jconn3, but they seem to work // with jTDS (which is used for Sybase ASE integration) case SYBASE: { - result = statement.executeUpdate(); - selectReturning(configuration, create(configuration).lastID()); + result = ctx.statement().executeUpdate(); + selectReturning(ctx.configuration(), create(ctx).lastID()); return result; } @@ -398,8 +403,8 @@ class InsertQueryImpl extends AbstractStoreQuery implements case INGRES: case MYSQL: case SQLSERVER: { - result = statement.executeUpdate(); - rs = statement.getGeneratedKeys(); + result = ctx.statement().executeUpdate(); + rs = ctx.statement().getGeneratedKeys(); try { List list = new ArrayList(); @@ -407,7 +412,7 @@ class InsertQueryImpl extends AbstractStoreQuery implements list.add(rs.getObject(1)); } - selectReturning(configuration, list.toArray()); + selectReturning(ctx, list.toArray()); return result; } finally { @@ -418,7 +423,7 @@ class InsertQueryImpl extends AbstractStoreQuery implements // Postgres can execute the INSERT .. RETURNING clause like // a select clause. JDBC support is not implemented case POSTGRES: { - rs = statement.executeQuery(); + rs = ctx.statement().executeQuery(); break; } @@ -428,15 +433,19 @@ class InsertQueryImpl extends AbstractStoreQuery implements case HSQLDB: case ORACLE: default: { - result = statement.executeUpdate(); - rs = statement.getGeneratedKeys(); + result = ctx.statement().executeUpdate(); + rs = ctx.statement().getGeneratedKeys(); break; } } - CursorImpl cursor = new CursorImpl(configuration, returning, rs, statement, getInto().getRecordType()); - returned = cursor.fetch(); + ExecuteListener listener2 = new ExecuteListeners(ctx.configuration()); + ExecuteContext ctx2 = new DefaultExecuteContext(ctx.configuration(), null); + + ctx2.resultSet(rs); + listener2.fetchStart(ctx2); + returned = new CursorImpl(ctx2, listener2, returning, getInto().getRecordType()).fetch(); return result; } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Util.java b/jOOQ/src/main/java/org/jooq/impl/Util.java index 0bd491f941..d6e6fc91f3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Util.java +++ b/jOOQ/src/main/java/org/jooq/impl/Util.java @@ -35,6 +35,7 @@ */ package org.jooq.impl; +import static java.lang.Boolean.FALSE; import static java.lang.Integer.toOctalString; import static org.jooq.impl.Factory.getDataType; import static org.jooq.tools.StringUtils.leftPad; @@ -60,6 +61,8 @@ import org.jooq.AttachableInternal; import org.jooq.Configuration; import org.jooq.Cursor; import org.jooq.DataType; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.Field; import org.jooq.FieldProvider; import org.jooq.NamedQueryPart; @@ -73,6 +76,8 @@ import org.jooq.Table; import org.jooq.Type; import org.jooq.exception.DataAccessException; import org.jooq.tools.Convert; +import org.jooq.tools.LoggerListener; +import org.jooq.tools.StopWatchListener; import org.jooq.tools.StringUtils; /** @@ -86,7 +91,7 @@ final class Util { * Indicating whether JPA (javax.persistence) is on the * classpath. */ - private static Boolean isJPAAvailable; + private static Boolean isJPAAvailable; /** * Create a new Oracle-style VARRAY {@link ArrayRecord} @@ -451,6 +456,14 @@ final class Util { return new DataAccessException(message, e); } + /** + * Safely close a statement + */ + static final void safeClose(ExecuteContext ctx) { + safeClose(ctx.resultSet()); + safeClose(ctx.statement()); + } + /** * Safely close a statement */ @@ -810,6 +823,27 @@ final class Util { } } + static final List getListeners(Configuration configuration) { + List result = new ArrayList(); + + if (!FALSE.equals(configuration.getSettings().isExecuteLogging())) { + result.add(new StopWatchListener()); + result.add(new LoggerListener()); + } + + for (String listener : configuration.getSettings().getExecuteListeners()) { + try { + // [#1170] TODO: Cache these classes? + result.add((ExecuteListener) Class.forName(listener).newInstance()); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + return result; + } + /** * Wrap a piece of SQL code in parentheses, if not wrapped already */ diff --git a/jOOQ/src/main/java/org/jooq/tools/LoggerListener.java b/jOOQ/src/main/java/org/jooq/tools/LoggerListener.java new file mode 100644 index 0000000000..8fdb28a658 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/tools/LoggerListener.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.tools; + +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; + +/** + * A default {@link ExecuteListener} that just logs events to java.util.logging, + * log4j, or slf4j using the {@link JooqLogger} + * + * @author Lukas Eder + */ +public class LoggerListener implements ExecuteListener { + + private static final JooqLogger log = JooqLogger.getLogger(LoggerListener.class); + + @Override + public void init(ExecuteContext ctx) { + } + + @Override + public void renderStart(ExecuteContext ctx) { + } + + @Override + public void renderEnd(ExecuteContext ctx) { + } + + @Override + public void prepareStart(ExecuteContext ctx) { + } + + @Override + public void prepareEnd(ExecuteContext ctx) { + } + + @Override + public void bindStart(ExecuteContext ctx) { + } + + @Override + public void bindEnd(ExecuteContext ctx) { + } + + @Override + public void executeStart(ExecuteContext ctx) { + if (log.isDebugEnabled()) { + if (ctx.query() != null) { + log.debug("Executing query", ctx.query().getSQL(true)); + } + else if (!StringUtils.isBlank(ctx.sql())) { + log.debug("Executing query", ctx.sql()); + } + } + } + + @Override + public void executeEnd(ExecuteContext ctx) { + } + + @Override + public void fetchStart(ExecuteContext ctx) { + } + + @Override + public void fetchEnd(ExecuteContext ctx) { + } + + @Override + public void recordStart(ExecuteContext ctx) { + } + + @Override + public void recordEnd(ExecuteContext ctx) { + if (log.isTraceEnabled() && ctx.record() != null) + log.trace("Record fetched", ctx.record()); + } + + @Override + public void resultStart(ExecuteContext ctx) { + } + + @Override + public void resultEnd(ExecuteContext ctx) { + if (log.isDebugEnabled() && ctx.result() != null) { + String comment = "Fetched result"; + + for (String line : ctx.result().format(5).split("\n")) { + log.debug(comment, line); + comment = ""; + } + } + } +} diff --git a/jOOQ/src/main/java/org/jooq/tools/StopWatchListener.java b/jOOQ/src/main/java/org/jooq/tools/StopWatchListener.java new file mode 100644 index 0000000000..4511c89d76 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/tools/StopWatchListener.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.tools; + +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; + +/** + * A default {@link ExecuteListener} that just logs events to java.util.logging, + * log4j, or slf4j using the {@link JooqLogger} + * + * @author Lukas Eder + */ +public class StopWatchListener implements ExecuteListener { + + private final StopWatch watch = new StopWatch(); + + @Override + public void init(ExecuteContext ctx) { + watch.splitTrace("Initialising"); + } + + @Override + public void renderStart(ExecuteContext ctx) { + watch.splitTrace("Rendering query"); + } + + @Override + public void renderEnd(ExecuteContext ctx) { + watch.splitTrace("Query rendered"); + } + + @Override + public void prepareStart(ExecuteContext ctx) { + watch.splitTrace("Preparing statement"); + } + + @Override + public void prepareEnd(ExecuteContext ctx) { + watch.splitTrace("Statement prepared"); + } + + @Override + public void bindStart(ExecuteContext ctx) { + watch.splitTrace("Binding variables"); + } + + @Override + public void bindEnd(ExecuteContext ctx) { + watch.splitTrace("Variables bound"); + } + + @Override + public void executeStart(ExecuteContext ctx) { + watch.splitTrace("Executing query"); + } + + @Override + public void executeEnd(ExecuteContext ctx) { + watch.splitDebug("Query executed"); + } + + @Override + public void fetchStart(ExecuteContext ctx) { + watch.splitTrace("Fetching results"); + } + + @Override + public void fetchEnd(ExecuteContext ctx) { + watch.splitDebug("Results fetched"); + } + + @Override + public void recordStart(ExecuteContext ctx) { + watch.splitTrace("Fetching record"); + } + + @Override + public void recordEnd(ExecuteContext ctx) { + watch.splitTrace("Record fetched"); + } + + @Override + public void resultStart(ExecuteContext ctx) { + watch.splitTrace("Fetching result"); + } + + @Override + public void resultEnd(ExecuteContext ctx) { + watch.splitTrace("Result fetched"); + } +} diff --git a/jOOQ/src/main/resources/xsd/jooq-runtime-2.0.5.xsd b/jOOQ/src/main/resources/xsd/jooq-runtime-2.0.5.xsd index 0a0641c947..eb66ec3ec0 100644 --- a/jOOQ/src/main/resources/xsd/jooq-runtime-2.0.5.xsd +++ b/jOOQ/src/main/resources/xsd/jooq-runtime-2.0.5.xsd @@ -18,20 +18,19 @@ - - - - - - - - - - + + + + + + + + + @@ -83,17 +82,24 @@ - - - - - - - + + + + + + + + + + + + \ No newline at end of file