[#1157] Add extended SQL / JDBC tracing capabilities in addition to logging - draft API and implementation

This commit is contained in:
Lukas Eder 2012-02-21 21:17:43 +00:00
parent 332f556d01
commit 753b645389
33 changed files with 1362 additions and 544 deletions

View File

@ -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<A, B, S, B2S, BS, L, X, DATE, D, T, U, I, IPK, T658, T725, T639
Boolean bool3 = (derby ? bool1 : null);
Factory create = create(new Settings()
.withExecution(new Execution()
.withStatementType(StatementType.STATIC_STATEMENT)));
.withStatementType(StatementType.STATIC_STATEMENT));
Object[] array1 = create.select(vals(s1, s2, s3, s4)).fetchOneArray();
Object[] array2 = create.select(vals(b1, b2, sh1, sh2, i1, i2, l1, l2, bi1, bi2, bd1, bd2, db1, db2, f1, f2)).fetchOneArray();
@ -347,8 +345,7 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, D, T, U, I, IPK, T658, T725, T639
Timestamp ts1 = Timestamp.valueOf("1981-07-10 12:01:15");
Factory create = create(new Settings()
.withExecution(new Execution()
.withStatementType(StatementType.STATIC_STATEMENT)));
.withStatementType(StatementType.STATIC_STATEMENT));
DATE date = create.newRecord(TDates());
date.setValue(TDates_ID(), 1);

View File

@ -56,7 +56,6 @@ import org.jooq.UpdatableRecord;
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.Factory;
import org.jooq.test.BaseTest;
@ -120,13 +119,12 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, D, T, U, I, IPK, T658, T725, T639
@Test
public void testTableMapping() throws Exception {
Settings settings = new Settings()
.withRendering(new Rendering()
.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput(TAuthor().getSchema().getName())
.withTables(
new MappedTable().withInput(TAuthor().getName()).withOutput(VAuthor().getName()),
new MappedTable().withInput(TBook().getName()).withOutput(VBook().getName())))));
new MappedTable().withInput(TBook().getName()).withOutput(VBook().getName()))));
Select<Record> q =
create(settings).select(TBook_TITLE())
@ -160,14 +158,13 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, D, T, U, I, IPK, T658, T725, T639
// Map to self. This will work even for single-schema RDBMS
// ---------------------------------------------------------------------
Settings settings = new Settings()
.withRendering(new Rendering()
.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput(TAuthor().getSchema().getName())
.withOutput(TAuthor().getSchema().getName())
.withTables(
new MappedTable().withInput(TAuthor().getName()).withOutput(TAuthor().getName()),
new MappedTable().withInput(TBook().getName()).withOutput(TBook().getName())))));
new MappedTable().withInput(TBook().getName()).withOutput(TBook().getName()))));
Select<Record> query =
create(settings).select(TBook_TITLE())
@ -218,11 +215,10 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, D, T, U, I, IPK, T658, T725, T639
// Map to a second schema
// ---------------------------------------------------------------------
settings = new Settings()
.withRendering(new Rendering()
.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput(TAuthor().getSchema().getName())
.withOutput(TAuthor().getSchema().getName() + "2"))));
.withOutput(TAuthor().getSchema().getName() + "2")));
Select<Record> q =
create(settings).select(TBook_TITLE())
@ -264,14 +260,13 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, D, T, U, I, IPK, T658, T725, T639
// Map both schema AND tables
// --------------------------
settings = new Settings()
.withRendering(new Rendering()
.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput(TAuthor().getSchema().getName())
.withOutput(TAuthor().getSchema().getName() + "2")
.withTables(
new MappedTable().withInput(TAuthor().getName()).withOutput(VAuthor().getName()),
new MappedTable().withInput(TBook().getName()).withOutput(VBook().getName())))));
new MappedTable().withInput(TBook().getName()).withOutput(VBook().getName()))));
q =
create(settings).select(TBook_TITLE())

View File

@ -66,7 +66,6 @@ import org.jooq.UDTRecord;
import org.jooq.UpdatableTable;
import org.jooq.conf.MappedSchema;
import org.jooq.conf.RenderMapping;
import org.jooq.conf.Rendering;
import org.jooq.conf.Settings;
import org.jooq.impl.Factory;
import org.jooq.test.hsqldb.generatedclasses.Public;
@ -117,11 +116,10 @@ public class jOOQHSQLDBTest2 extends jOOQAbstractTest<
@Override
protected Factory create(Settings settings) {
settings = (settings != null) ? settings : new Settings();
settings.withRendering(new Rendering()
.withRenderMapping(new RenderMapping()
settings.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput(TAuthor().getSchema().getName())
.withOutput(Public.PUBLIC.getName()))));
.withOutput(Public.PUBLIC.getName())));
return new PublicFactory(getConnection(), settings);
}

View File

@ -38,7 +38,6 @@ package org.jooq.test;
import org.jooq.conf.MappedSchema;
import org.jooq.conf.RenderMapping;
import org.jooq.conf.Rendering;
import org.jooq.conf.Settings;
import org.jooq.test.mysql.generatedclasses.TestFactory;
@ -63,11 +62,10 @@ public class jOOQMySQLTestSchemaMapping extends jOOQMySQLTest {
@Override
protected TestFactory create(Settings settings) {
settings = (settings != null) ? settings : new Settings();
settings.withRendering(new Rendering()
.withRenderMapping(new RenderMapping()
settings.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput(TAuthor().getSchema().getName())
.withOutput(TAuthor().getSchema().getName() + getSchemaSuffix()))));
.withOutput(TAuthor().getSchema().getName() + getSchemaSuffix())));
return new TestFactory(getConnection(), settings);
}
}

View File

@ -36,7 +36,6 @@
package org.jooq.test;
import org.jooq.conf.Execution;
import org.jooq.conf.Settings;
import org.jooq.conf.StatementType;
import org.jooq.test.oracle.generatedclasses.test.TestFactory;
@ -50,8 +49,7 @@ public class jOOQOracleTestInline extends jOOQOracleTest {
@Override
protected TestFactory create(Settings settings) {
settings = (settings != null) ? settings : new Settings();
settings.withExecution(new Execution()
.withStatementType(StatementType.STATIC_STATEMENT));
settings.withStatementType(StatementType.STATIC_STATEMENT);
return new TestFactory(getConnection(), settings);
}
}

View File

@ -36,7 +36,6 @@
package org.jooq.test;
import org.jooq.conf.Execution;
import org.jooq.conf.Settings;
import org.jooq.conf.StatementType;
import org.jooq.test.sqlserver.generatedclasses.DboFactory;
@ -50,8 +49,7 @@ public class jOOQSQLServerTestInline extends jOOQSQLServerTest {
@Override
protected DboFactory create(Settings settings) {
settings = (settings != null) ? settings : new Settings();
settings.withExecution(new Execution()
.withStatementType(StatementType.STATIC_STATEMENT));
settings.withStatementType(StatementType.STATIC_STATEMENT);
return new DboFactory(getConnection(), settings);
}
}

View File

@ -76,13 +76,13 @@ public interface Configuration extends Serializable {
* <p>
* 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.
* <p>
* See {@link EventListener} for more details.
* See {@link ExecuteListener} for more details.
*
* @return The custom data. This is never <code>null</code>
* @see EventListener
* @see ExecuteListener
*/
Map<String, Object> getData();
@ -91,15 +91,15 @@ public interface Configuration extends Serializable {
* <p>
* 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.
* <p>
* 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 <code>null</code> if no such data is contained
* in this <code>Configuration</code>
* @see EventListener
* @see ExecuteListener
*/
Object getData(String key);
@ -108,21 +108,21 @@ public interface Configuration extends Serializable {
* <p>
* 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.
* <p>
* Be sure that your custom data implements {@link Serializable} if you want
* to serialise this <code>Configuration</code> or objects referencing this
* <code>Configuration</code>, e.g. your {@link Record} types.
* <p>
* 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 <code>null</code> to unset the custom
* data
* @return The previously set custom data or <code>null</code> if no data
* was previously set for the given key
* @see EventListener
* @see ExecuteListener
*/
Object setData(String key, Object value);

View File

@ -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;
* <p>
* This functionality is experimental. It may change again in the future. Use it
* at your own risk.
*
*
* @author Lukas Eder
* @see <a
* href="http://groups.google.com/group/jooq-user/browse_thread/thread/d33e9a902707d111">http://groups.google.com/group/jooq-user/browse_thread/thread/d33e9a902707d111</a>
* @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 {
* <code>null</code> 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);
}

View File

@ -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.
* <p>
* Expect most of this context's objects to be <code>nullable</code>!
*
* @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}
* <p>
* Use this to wrap the <code>PreparedStatement</code> 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();
}

View File

@ -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.
* <p>
* <code>EventListener</code> 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 <code>Settings</code>
* to {@link Factory#Factory(java.sql.Connection, SQLDialect, Settings)}
* <p>
* Advanced <code>EventListeners</code> can also provide custom implementations
* of {@link Connection}, {@link PreparedStatement} and {@link ResultSet} to
* jOOQ in apropriate methods.
* <p>
* 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);
}

View File

@ -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);
}
}
}

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// 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
//

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// 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
//

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// 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
//

View File

@ -2,15 +2,20 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// 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;
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;all>
* &lt;element name="rendering" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}Rendering" minOccurs="0"/>
* &lt;element name="execution" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}Execution" minOccurs="0"/>
* &lt;element name="renderMapping" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}RenderMapping" minOccurs="0"/>
* &lt;element name="statementType" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}StatementType" minOccurs="0"/>
* &lt;element name="executeLogging" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
* &lt;element name="executeListeners" type="{http://www.jooq.org/xsd/jooq-runtime-2.0.5.xsd}ExecuteListeners" minOccurs="0"/>
* &lt;/all>
* &lt;/restriction>
* &lt;/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<String> 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<String> getExecuteListeners() {
if (executeListeners == null) {
executeListeners = new ArrayList<String>();
}
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<String> values) {
if (values!= null) {
getExecuteListeners().addAll(values);
}
return this;
}

View File

@ -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;
}
}

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// 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
//

View File

@ -2,7 +2,7 @@
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.5-b02-fcs
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// 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")

View File

@ -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<String, Object> 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);
}
}

View File

@ -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<C extends Context<C>> implements Context<C> {
abstract class AbstractContext<C extends Context<C>> extends AbstractConfiguration implements Context<C> {
/**
* 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<C extends Context<C>> implements Context<C> {
}
// ------------------------------------------------------------------------
// 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<String, Object> 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);

View File

@ -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;
}
/**

View File

@ -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<R extends Record> 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<R extends Record> 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<R>(configuration, fields, rs, statement, getRecordType());
listener.fetchStart(ctx);
FieldList fields = new FieldList(getFields(ctx.resultSet().getMetaData()));
cursor = new CursorImpl<R>(ctx, listener, fields, getRecordType());
if (!lazy) {
result = cursor.fetch();
@ -161,20 +163,21 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
results = new ArrayList<Result<Record>>();
for (;;) {
FieldProvider fields = new MetaDataFieldProvider(configuration, rs.getMetaData());
Cursor<Record> c = new CursorImpl<Record>(configuration, fields, rs);
listener.fetchStart(ctx);
FieldProvider fields = new MetaDataFieldProvider(ctx, ctx.resultSet().getMetaData());
Cursor<Record> c = new CursorImpl<Record>(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 {

View File

@ -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<T> 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<Parameter<?>> allParameters;
@ -242,30 +241,25 @@ public abstract class AbstractRoutine<T> 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<T> 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<T> 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));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}

View File

@ -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<ExecuteListener> 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);
}
}
}

View File

@ -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<Record> 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<Record>(this, fields, rs).fetch();
ctx.resultSet(rs);
listener.fetchStart(ctx);
return new CursorImpl<Record>(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();
}

View File

@ -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> T getFromResultSet(Configuration configuration, ResultSet rs, Field<T> field, int index)
static <T> T getFromResultSet(ExecuteContext ctx, Field<T> field, int index)
throws SQLException {
Class<? extends T> type = field.getType();
return getFromResultSet(configuration, rs, type, index);
return getFromResultSet(ctx, type, index);
}
@SuppressWarnings("unchecked")
private static <T> T getFromResultSet(Configuration configuration, ResultSet rs, Class<? extends T> type, int index)
private static <T> T getFromResultSet(ExecuteContext ctx, Class<? extends T> 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<? extends T>) 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<? extends T>) 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<? extends Object[]> )type);
return (T) convertArray(rs.getArray(index), (Class<? extends Object[]>) type);
}
}
else if (ArrayRecord.class.isAssignableFrom(type)) {
return (T) getArrayRecord(configuration, rs.getArray(index), (Class<? extends ArrayRecord<?>>) type);
return (T) getArrayRecord(ctx, rs.getArray(index), (Class<? extends ArrayRecord<?>>) 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<Record> cursor = new CursorImpl<Record>(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> T getFromStatement(Configuration configuration, CallableStatement stmt, Class<? extends T> type, int index) throws SQLException {
public static <T> T getFromStatement(ExecuteContext ctx, Class<? extends T> 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<? extends Object[]>)type);
}
else if (ArrayRecord.class.isAssignableFrom(type)) {
return (T) getArrayRecord(configuration, stmt.getArray(index), (Class<? extends ArrayRecord<?>>) type);
return (T) getArrayRecord(ctx, stmt.getArray(index), (Class<? extends ArrayRecord<?>>) 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<Record> cursor = new CursorImpl<Record>(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> T pgGetArray(Configuration configuration, ResultSet rs, Class<? extends T> type, int index)
private static <T> T pgGetArray(ExecuteContext ctx, Class<? extends T> 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<? extends Object[]>) type);
}
}

View File

@ -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<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> implements
case INGRES:
case MYSQL:
case SQLSERVER: {
result = statement.executeUpdate();
rs = statement.getGeneratedKeys();
result = ctx.statement().executeUpdate();
rs = ctx.statement().getGeneratedKeys();
try {
List<Object> list = new ArrayList<Object>();
@ -407,7 +412,7 @@ class InsertQueryImpl<R extends Record> extends AbstractStoreQuery<R> implements
list.add(rs.getObject(1));
}
selectReturning(configuration, list.toArray());
selectReturning(ctx, list.toArray());
return result;
}
finally {
@ -418,7 +423,7 @@ class InsertQueryImpl<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> implements
case HSQLDB:
case ORACLE:
default: {
result = statement.executeUpdate();
rs = statement.getGeneratedKeys();
result = ctx.statement().executeUpdate();
rs = ctx.statement().getGeneratedKeys();
break;
}
}
CursorImpl<R> cursor = new CursorImpl<R>(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<R>(ctx2, listener2, returning, getInto().getRecordType()).fetch();
return result;
}
}

View File

@ -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 (<code>javax.persistence</code>) 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<ExecuteListener> getListeners(Configuration configuration) {
List<ExecuteListener> result = new ArrayList<ExecuteListener>();
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
*/

View File

@ -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 = "";
}
}
}
}

View File

@ -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");
}
}

View File

@ -18,20 +18,19 @@
<element name="settings" type="jooq-runtime:Settings"/>
<complexType name="Settings">
<all>
<!-- Configure query rendering properties -->
<element name="rendering" type="jooq-runtime:Rendering" minOccurs="0" maxOccurs="1"/>
<!-- Configure query execution properties -->
<element name="execution" type="jooq-runtime:Execution" minOccurs="0" maxOccurs="1"/>
</all>
</complexType>
<complexType name="Rendering">
<all>
<!-- Configure render mapping for runtime schema / table rewriting in
generated SQL -->
<element name="renderMapping" type="jooq-runtime:RenderMapping" minOccurs="0" maxOccurs="1"/>
<!-- The type of statement that is to be executed -->
<element name="statementType" type="jooq-runtime:StatementType" minOccurs="0" maxOccurs="1" default="PREPARED_STATEMENT"/>
<!-- When set to true, this will add jOOQ's default logging ExecuteListeners -->
<element name="executeLogging" type="boolean" minOccurs="0" maxOccurs="1" default="true"/>
<!-- The event listeners to be notified upon execution events -->
<element name="executeListeners" type="jooq-runtime:ExecuteListeners" minOccurs="0" maxOccurs="1"/>
</all>
</complexType>
@ -83,17 +82,24 @@
</all>
</complexType>
<complexType name="Execution">
<all>
<!-- The type of statement that is to be executed -->
<element name="statementType" type="jooq-runtime:StatementType" minOccurs="0" maxOccurs="1" default="PREPARED_STATEMENT"/>
</all>
</complexType>
<simpleType name="StatementType">
<restriction base="string">
<!-- Execute statements with inlined bind values, avoiding JDBC's
PreparedStatements -->
<enumeration value="STATIC_STATEMENT"/>
<!-- Execute statements with bind values, using JDBC's
PreparedStatements -->
<enumeration value="PREPARED_STATEMENT"/>
</restriction>
</simpleType>
<complexType name="ExecuteListeners">
<sequence>
<!-- An event listener implementing org.jooq.ExecuteListener -->
<element name="executeListener" type="string" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
</schema>