From 25c57493ddc34fcbdf74485641516dd669369d41 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Thu, 14 Feb 2013 11:46:52 +0100 Subject: [PATCH] - Fixed references to Factory / Executor - Added more row-value-expression sections --- jOOQ-website/src/main/java/Transform.java | 25 +- .../src/main/resources/manual-3.0.xml | 1424 +++++++++++------ 2 files changed, 925 insertions(+), 524 deletions(-) diff --git a/jOOQ-website/src/main/java/Transform.java b/jOOQ-website/src/main/java/Transform.java index bdd4018607..f7b53f9421 100644 --- a/jOOQ-website/src/main/java/Transform.java +++ b/jOOQ-website/src/main/java/Transform.java @@ -83,10 +83,10 @@ public class Transform { System.out.println("-------------------------------"); singlePage(); - System.out.println(); - System.out.println("Transforming PDF manual"); - System.out.println("-------------------------------"); - pdf(); +// System.out.println(); +// System.out.println("Transforming PDF manual"); +// System.out.println("-------------------------------"); +// pdf(); } private static String file(String name) { @@ -114,7 +114,7 @@ public class Transform { } private static void replaceVariables(Match manual) { - manual.find("content").each(new Each() { + manual.find("content").add(manual.find("title")).each(new Each() { @Override public void each(Context context) { String content = $(context.element()).content(); @@ -133,6 +133,21 @@ public class Transform { changed = true; } + if (content.contains("{codegen-xsd-version}")) { + content = content.replace("{codegen-xsd-version}", "3.0.0"); + changed = true; + } + + if (content.contains("{export-xsd-version}")) { + content = content.replace("{export-xsd-version}", "2.6.0"); + changed = true; + } + + if (content.contains("{runtime-xsd-version}")) { + content = content.replace("{runtime-xsd-version}", "3.0.0"); + changed = true; + } + if (changed) { $(context.element()).content(content); } diff --git a/jOOQ-website/src/main/resources/manual-3.0.xml b/jOOQ-website/src/main/resources/manual-3.0.xml index 1b159ab6be..b3ca7f5d5f 100644 --- a/jOOQ-website/src/main/resources/manual-3.0.xml +++ b/jOOQ-website/src/main/resources/manual-3.0.xml @@ -209,7 +209,7 @@ org.jooq.property=value]]> +create.selectOne()]]>

Code block contents

@@ -233,12 +233,13 @@ exists(); max(); min(); val(); inline(); // correspond to Factory.exists(); Fact // Whenever you see BOOK/Book, AUTHOR/Author and similar entities, assume they were (static) imported from the generated schema BOOK.TITLE, AUTHOR.LAST_NAME // correspond to com.example.generated.Tables.BOOK.TITLE, com.example.generated.Tables.BOOK.TITLE -// Whenever you see "create" being used in Java code, assume that this is an instance of org.jooq.impl.Factory: -Factory create = new Factory(connection, SQLDialect.ORACLE);]]> +// Whenever you see "create" being used in Java code, assume that this is an instance of org.jooq.impl.Executor. +// The reason why it is called "create" is the fact, that a jOOQ QueryPart is being created from an Executor: +Executor create = new Executor(connection, SQLDialect.ORACLE);]]> -

Arity / Degree

+

Term: Degree (arity)

- jOOQ records (and many other API elements) have a degree N between 1 and {max-row-degree}. The variable degree of an API element is denoted as [N], e.g. Row[N] or Record[N] + jOOQ records (and many other API elements) have a degree N between 1 and {max-row-degree}. The variable degree of an API element is denoted as [N], e.g. Row[N] or Record[N]. The term "degree" is preferred over arity, as "degree" is the term used in the SQL standard, whereas "arity" is used more often in mathematics and relational theory.

Settings

@@ -248,7 +249,7 @@ Factory create = new Factory(connection, SQLDialect.ORACLE);]]>

Sample database

- See the manual's section about to learn more about the sample database. + jOOQ query examples run against the sample database. See the manual's section about to learn more about the sample database.

@@ -260,46 +261,42 @@ Factory create = new Factory(connection, SQLDialect.ORACLE);]]> For the examples in this manual, the same database will always be referred to. It essentially consists of these entities created using the Oracle dialect

CREATE TABLE language ( - id NUMBER(7) NOT NULL PRIMARY KEY, - cd CHAR(2) NOT NULL, - description VARCHAR2(50) + id NUMBER(7) NOT NULL PRIMARY KEY, + cd CHAR(2) NOT NULL, + description VARCHAR2(50) ) CREATE TABLE author ( - id NUMBER(7) NOT NULL PRIMARY KEY, - first_name VARCHAR2(50), - last_name VARCHAR2(50) NOT NULL, - date_of_birth DATE, - year_of_birth NUMBER(7) + id NUMBER(7) NOT NULL PRIMARY KEY, + first_name VARCHAR2(50), + last_name VARCHAR2(50) NOT NULL, + date_of_birth DATE, + year_of_birth NUMBER(7) ) CREATE TABLE book ( - id NUMBER(7) NOT NULL PRIMARY KEY, - author_id NUMBER(7) NOT NULL, - title VARCHAR2(400) NOT NULL, - published_in NUMBER(7) NOT NULL, - language_id NUMBER(7) NOT NULL, - FOREIGN KEY (AUTHOR_ID) REFERENCES author(ID), - FOREIGN KEY (LANGUAGE_ID) REFERENCES language(ID) + id NUMBER(7) NOT NULL PRIMARY KEY, + author_id NUMBER(7) NOT NULL, + title VARCHAR2(400) NOT NULL, + published_in NUMBER(7) NOT NULL, + language_id NUMBER(7) NOT NULL, + + CONSTRAINT fk_book_author FOREIGN KEY (author_id) REFERENCES author(id), + CONSTRAINT fk_book_language FOREIGN KEY (language_id) REFERENCES language(id) ) CREATE TABLE book_store ( - name VARCHAR2(400) NOT NULL UNIQUE + name VARCHAR2(400) NOT NULL UNIQUE ) CREATE TABLE book_to_book_store ( - book_store_name VARCHAR2(400) NOT NULL, - book_id INTEGER NOT NULL, - stock INTEGER, - PRIMARY KEY(book_store_name, book_id), - CONSTRAINT b2bs_book_store_id - FOREIGN KEY (book_store_name) - REFERENCES book_store (name) - ON DELETE CASCADE, - CONSTRAINT b2bs_book_id - FOREIGN KEY (book_id) - REFERENCES book (id) - ON DELETE CASCADE + name VARCHAR2(400) NOT NULL, + book_id INTEGER NOT NULL, + stock INTEGER, + + PRIMARY KEY(name, book_id), + CONSTRAINT fk_b2bs_book_store FOREIGN KEY (name) REFERENCES book_store (name) ON DELETE CASCADE, + CONSTRAINT fk_b2bs_book FOREIGN KEY (book_id) REFERENCES book (id) ON DELETE CASCADE )

More entities, types (e.g. UDT's, ARRAY types, ENUM types, etc), stored procedures and packages are introduced for specific examples @@ -404,13 +401,14 @@ String sql = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) Instead of any tool mentioned in the previous chapters, you can also use jOOQ directly to execute your jOOQ-generated SQL statements. This will add a lot of convenience on top of the previously discussed API for typesafe SQL construction, when you can re-use the information from generated classes to fetch records and custom data types. An example is given here:

- result = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) - .from(BOOK) - .join(AUTHOR) - .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) - .where(BOOK.PUBLISHED_IN.equal(1948)) - .fetch();]]> +> result = +create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) + .from(BOOK) + .join(AUTHOR) + .on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) + .where(BOOK.PUBLISHED_IN.equal(1948)) + .fetch();]]>

jOOQ doesn't stop here, though! You can execute any SQL with jOOQ. In other words, you can use any other SQL building tool and run the SQL statements with jOOQ. An example is given here: @@ -450,7 +448,7 @@ Result result = create.fetch(rs);]]> for (AuthorRecord author : create.fetch(AUTHOR)) { // Check if the author has written more than 5 books - if (author.fetchBookListByAuthorId().size() > 5) { + if (author.fetchChildren(FK_BOOK_AUTHOR).size() > 5) { // Congratulate the author by email: if (author.getMailSent()) { @@ -485,6 +483,7 @@ for (AuthorRecord author : create.fetch(AUTHOR)) {

  • : jOOQ allows you to hook your custom execute listeners into jOOQ's SQL statement execution lifecycle in order to centrally coordinate any arbitrary operation performed on SQL being executed. Use this for logging, identity generation, SQL tracing, performance measurements, etc.
  • : jOOQ has a standard DEBUG logger built-in, for logging and tracing all your executed SQL statements and fetched result sets
  • : jOOQ supports stored procedures and functions of your favourite database. All routines and user-defined types are generated and can be included in jOOQ's SQL building API as function references.
  • +
  • : Batch execution is important when executing a big load of SQL statements. jOOQ simplifies these operations compared to JDBC
  • and : jOOQ ships with an API to easily export/import data in various formats
  • @@ -575,7 +574,7 @@ CREATE TABLE `posts` (

    - + com.mysql.jdbc.Driver @@ -649,15 +648,15 @@ INFO: dialect : MYSQL Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: schema : guestbook Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info -INFO: target dir : /Users/jOOQ/Documents/workspace/MySQLTest/src +INFO: target dir : C:/workspace/MySQLTest/src Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: target package : test.generated Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: ---------------------------------------------------------- Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info -INFO: Emptying : /Users/jOOQ/workspace/MySQLTest/src/test/generated +INFO: Emptying : C:/workspace/MySQLTest/src/test/generated Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info -INFO: Generating classes in : /Users/jOOQ/workspace/MySQLTest/src/test/generated +INFO: Generating classes in : C:/workspace/MySQLTest/src/test/generated Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: Generating schema : Guestbook.java Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info @@ -667,7 +666,7 @@ INFO: Sequences fetched : 0 (0 included, 0 excluded) Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: Tables fetched : 5 (5 included, 0 excluded) Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info -INFO: Generating tables : /Users/jOOQ/workspace/MySQLTest/src/test/generated/tables +INFO: Generating tables : C:/workspace/MySQLTest/src/test/generated/tables Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: ARRAYs fetched : 0 (0 included, 0 excluded) Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info @@ -679,11 +678,11 @@ INFO: Generating table : Posts.java Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info INFO: Tables generated : Total: 680.464ms, +558.284ms Nov 1, 2011 7:25:07 PM org.jooq.impl.JooqLogger info -INFO: Generating Keys : /Users/jOOQ/workspace/MySQLTest/src/test/generated/tables +INFO: Generating Keys : C:/workspace/MySQLTest/src/test/generated/tables Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: Keys generated : Total: 718.621ms, +38.157ms Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info -INFO: Generating records : /Users/jOOQ/workspace/MySQLTest/src/test/generated/tables/records +INFO: Generating records : C:/workspace/MySQLTest/src/test/generated/tables/records Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info INFO: Generating record : PostsRecord.java Nov 1, 2011 7:25:08 PM org.jooq.impl.JooqLogger info @@ -748,11 +747,11 @@ public class Main { Let's add a simple query:

    - result = create.select().from(POSTS).fetch();]]> + result = Executor.select().from(POSTS).fetch();]]>

    - First get an instance of Factory so we can write a simple SELECT query. We pass an instance of the MySQL connection to Factory. Note that the factory doesn't close the connection. We'll have to do that ourselves. + First get an instance of Executor so we can write a simple SELECT query. We pass an instance of the MySQL connection to Executor. Note that the executor doesn't close the connection. We'll have to do that ourselves.

    We then use jOOQ's DSL to return an instance of Result. We'll be using this result in the next step. @@ -786,16 +785,10 @@ Result result = create.select().from(POSTS).fetch();]]> import static test.generated.Tables.*; import static org.jooq.impl.Factory.*; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.Statement; +import java.sql.*; -import org.jooq.Record; -import org.jooq.Result; - -import test.generated.GuestbookFactory; -import test.generated.tables.Posts; +import org.jooq.*; +import org.jooq.impl.*; public class Main { @@ -813,8 +806,8 @@ public class Main { Class.forName("com.mysql.jdbc.Driver").newInstance(); conn = DriverManager.getConnection(url, userName, password); - Factory create = new Factory(conn, SQLDialect.MYSQL); - Result<Record> result = create.select().from(POSTS).fetch(); + Executor create = new Executor(conn, SQLDialect.MYSQL); + Result result = create.select().from(POSTS).fetch(); for (Record r : result) { Long id = r.getValue(POSTS.ID); @@ -843,8 +836,8 @@ public class Main { Step 7: Explore!

    - jOOQ has grown to be a comprehensive SQL library. For more information, please consider the manual:
    - http://www.jooq.org/manual/ + jOOQ has grown to be a comprehensive SQL library. For more information, please consider the documentation:
    + http://www.jooq.org/learn.php

    ... explore the Javadoc:
    @@ -925,10 +918,10 @@ import org.jooq.scala.Conversions._ // Import i object Test { // def main(args: Array[String]): Unit = { // val c = DriverManager.getConnection("jdbc:h2:~/test", "sa", ""); // Standard JDBC connection - val f = new Factory(c, SQLDialect.H2); // + val e = new Executor(c, SQLDialect.H2); // val x = T_AUTHOR as "x" // SQL-esque table aliasing // - for (r <- f // Iteration over Result. "r" is an org.jooq.Record + for (r <- e // Iteration over Result. "r" is an org.jooq.Record3 select ( // T_BOOK.ID * T_BOOK.AUTHOR_ID, // Using the overloaded "*" operator T_BOOK.ID + T_BOOK.AUTHOR_ID * 3 + 4, // Using the overloaded "+" operator @@ -936,7 +929,7 @@ object Test { // ) // from T_BOOK // No need to use parentheses or "." here leftOuterJoin ( // - f select (x.ID, x.YEAR_OF_BIRTH) // Dereference fields from aliased table + select (x.ID, x.YEAR_OF_BIRTH) // Dereference fields from aliased table from x // limit 1 // asTable x.getName() // @@ -965,14 +958,14 @@ object Test { //

    • are referenced as "optional dependencies". jOOQ tries to find slf4j or log4j on the classpath. If it fails, it will use the
    • -
    • Oracle ojdbc types used for array creation are loaded using reflection.
    • -
    • Small libraries with compatible licenses are incorporated into jOOQ (jOOR, jOOU, OpenCSV, json simple, commons-lang)
    • +
    • Oracle ojdbc types used for array creation are loaded using reflection. The same applies to Postgres PG* types.
    • +
    • Small libraries with compatible licenses are incorporated into jOOQ. These include jOOR, jOOU, OpenCSV, json simple, commons-lang
    • javax.persistence and javax.validation will be needed if you activate the relevant

    Build your own

    - In order to build jOOQ, please download the sources from https://github.com/jOOQ/jOOQ and use Maven to build it, preferably in Eclipse. + In order to build jOOQ, please download the sources from https://github.com/jOOQ/jOOQ and use Maven to build jOOQ, preferably in Eclipse. jOOQ requires Java 6 to compile and run.

    @@ -1019,7 +1012,7 @@ object Test { // SQL is a declarative language that is hard to integrate into procedural, object-oriented, functional or any other type of programming languages. jOOQ's philosophy is to give SQL the credit it deserves and integrate SQL itself as an "internal domain specific language" directly into Java.

    - With this philosophy in mind, SQL building is the main feature of jOOQ. All other features (such as and ) are mere convenience built on top of jOOQ's SQL building capabilities. + With this philosophy in mind, SQL building is the main feature of jOOQ. All other features (such as and ) are mere convenience built on top of jOOQ's SQL building capabilities.

    This section explains all about the various syntax elements involved with jOOQ's SQL building capabilities. For a complete overview of all syntax elements, please refer to the manual's section about @@ -1028,8 +1021,8 @@ object Test { //

    - The Factory class - + The Factory class +

    jOOQ exposes a lot of interfaces and hides most implementation facts from client code. The reasons for this are:

    @@ -1039,45 +1032,78 @@ object Test { //
  • API guarantee. You only depend on the exposed interfaces, not concrete (potentially dialect-specific) implementations.
  • - The class is the main class from where you will create all jOOQ objects. The Factory serves two types of purposes: + The class is the main class from where you will create all jOOQ objects. It serves as a static factory for , (or "fields"), and many other .

    -
      -
    • It serves as a static factory for , (or "fields"), and many other .
    • -
    • It implements , an object that configures jOOQ's behaviour when executing queries (see for more details). Factories allow for creating that are already "configured" and ready for execution.
    • -

    The static Factory API

    With jOOQ 2.0, static factory methods have been introduced in order to make client code look more like SQL. Ideally, when working with jOOQ, you will simply static import all methods from the Factory class:

    - import static org.jooq.impl.Factory.*; + +import static org.jooq.impl.Factory.*; +

    Note, that when working with Eclipse, you could also add the Factory to your favourites. This will allow to access functions even more fluently:

    concat(trim(FIRST_NAME), trim(LAST_NAME)); + // ... which is in fact the same as: Factory.concat(Factory.trim(FIRST_NAME), Factory.trim(LAST_NAME)); - -

    The Factory as a Configuration object

    +
    + + +
    + Factory subclasses + +

    + There are a couple of subclasses for the general Factory. Each SQL dialect has its own dialect-specific Factory. For instance, if you're only using the MySQL dialect, you can choose to reference the MySQLFactory instead of the standard Factory: +

    +

    + The advantage of referencing a dialect-specific Factory lies in the fact that you have access to more proprietary RDMBS functionality. This may include: +

    +
      +
    • MySQL's encryption functions
    • +
    • PL/SQL constructs, pgplsql, or any other dialect's ROUTINE-language (maybe in the future)
    • +
    +
    +
    +
    +
    + +
    + The Executor class +

    - As any Configuration object, a Factory can be supplied with these objects: + Executor implements , an object that configures jOOQ's behaviour when executing queries (see for more details). Unlike Factories, Executors allow for creating that are already "configured" and ready for execution. +

    + +

    The Executor as a Configuration object

    +

    + As any Configuration object, an Executor can be supplied with these objects:

    • : The dialect of your database. This may be any of the currently supported database types (see for more details)
    • -
    • : An optional JDBC Connection that will be re-used for the whole lifecycle of your Factory (see for more details)
    • -
    • : An optional JDBC DataSource that will be re-used for the whole lifecycle of your Factory. If you prefer using DataSources over Connections, jOOQ will internally fetch new Connections from your DataSource, conveniently closing them again after query execution. This is particularly useful in J2EE or Spring contexts (see for more details)
    • : An optional runtime configuration (see for more details)
    • +
    • + Any of these: +
        +
      • : An optional JDBC Connection that will be re-used for the whole lifecycle of your Executor (see for more details). For simplicity, this is the use-case referenced from this manual, most of the time.
      • +
      • : An optional JDBC DataSource that will be re-used for the whole lifecycle of your Executor. If you prefer using DataSources over Connections, jOOQ will internally fetch new Connections from your DataSource, conveniently closing them again after query execution. This is particularly useful in J2EE or Spring contexts (see for more details)
      • +
      • : A custom abstraction that is used by jOOQ to "acquire" and "release" connections. jOOQ will internally "acquire" new Connections from your ConnectionProvider, conveniently "releasing" them again after query execution. (see for more details)
      • +
      +
    +

    - As a Configuration object, a Factory can construct , for later . An example is given here: + As a Configuration object, an Executor can construct , for later . An example is given here:

    - select = create.selectOne(); -// Using the internally referenced Factory, the select statement can now be executed: +// Using the internally referenced Executor, the select statement can now be executed: Result result = select.fetch();]]>
    @@ -1089,7 +1115,7 @@ Result result = select.fetch();]]> While jOOQ tries to represent the SQL standard as much as possible, many features are vendor-specific to a given database and to its "SQL dialect". jOOQ models this using the enum type.

    - The SQL dialect is one of the main attributes of a . Queries created from such factories will assume dialect-specific behaviour when and . + The SQL dialect is one of the main attributes of an . Queries created from such executors will assume dialect-specific behaviour when and .

    Some parts of the jOOQ API are officially supported only by a given subset of the supported SQL dialects. For instance, the , which is supported by the Oracle and CUBRID databases, is annotated with a annotation, as such: @@ -1097,8 +1123,9 @@ Result result = select.fetch();]]> CONNECT BY clause to the query */ -@Support({ CUBRID, ORACLE }) +@Support({ SQLDialect.CUBRID, SQLDialect.ORACLE }) SelectConnectByConditionStep connectBy(Condition condition);]]> +

    jOOQ API methods which are not annotated with the annotation, or which are annotated with the Support annotation, but without any SQL dialects can be safely used in all SQL dialects. An example for this is the factory method:

    @@ -1116,7 +1143,7 @@ SelectSelectStep select(Field... fields);]]>

    - Nevertheless, the IS DISTINCT FROM predicate is supported in all dialects, as its semantics can be expressed with an equivalent . For more details, see the manual's section about the . + Nevertheless, the IS DISTINCT FROM predicate is supported by jOOQ in all dialects, as its semantics can be expressed with an equivalent . For more details, see the manual's section about the .

    jOOQ and the Oracle SQL dialect

    @@ -1141,34 +1168,67 @@ SelectSelectStep select(Field... fields);]]>

    Interact with JDBC Connections

    - While you can use jOOQ for only, you can also run queries against a JDBC . Internally, jOOQ creates or objects from such a Connection, in order to execute statements. The normal operation mode is to provide a with a JDBC Connection, whose lifecycle you will control yourself. This means that jOOQ will not actively close connections, rollback or commit transactions. + While you can use jOOQ for only, you can also run queries against a JDBC . Internally, jOOQ creates or objects from such a Connection, in order to execute statements. The normal operation mode is to provide an with a JDBC Connection, whose lifecycle you will control yourself. This means that jOOQ will not actively close connections, rollback or commit transactions.

    +

    + Note, in this case, jOOQ will internally use a , which you can reference directly if you prefer that. The DefaultConnectionProvider exposes various transaction-control methods, such as commit(), rollback(), etc. +

    +

    Interact with JDBC DataSources

    - If you're in a J2EE or Spring context, however, you may wish to use a instead. Currently, Connections obtained from such a DataSource will be closed after query execution by jOOQ. The semantics of such a close operation should be the returning of the connection into a connection pool, not the actual closing of the underlying physical connection. Typically, this makes sense in an environment using distributed JTA transactions. An example of using DataSources with jOOQ can be seen in the tutorial section about . + If you're in a J2EE or Spring context, however, you may wish to use a instead. Connections obtained from such a DataSource will be closed after query execution by jOOQ. The semantics of such a close operation should be the returning of the connection into a connection pool, not the actual closing of the underlying physical connection. Typically, this makes sense in an environment using distributed JTA transactions. An example of using DataSources with jOOQ can be seen in the tutorial section about . +

    +

    + Note, in this case, jOOQ iwll internally use a , which you can reference directly if you prefer that. +

    + +

    Inject custom behaviour

    +

    + If your specific environment works differently from any of the above approaches, you can inject your own custom implementation of a ConnectionProvider into jOOQ. This is the API contract you have to fulfil: +

    + + + +

    + Note that acquire() should always return the same Connection until this connection is returned via release()

    + +
    + Custom data +
    + +
    + Execute listeners +
    Custom Settings

    - The jOOQ Factory allows for some optional configuration elements to be used by advanced users. The class is a JAXB-annotated type, that can be provided to a Factory in several ways: + The jOOQ Executor allows for some optional configuration elements to be used by advanced users. The class is a JAXB-annotated type, that can be provided to an Executor in several ways:

    Example

    - For example, if you want to indicate to jOOQ, that it should inline all bind variables, and execute static instead of binding its variables to , you can do so by using the following Factory: + For example, if you want to indicate to jOOQ, that it should inline all bind variables, and execute static instead of binding its variables to , you can do so by using the following Executor:

    +Executor create = new Executor(connection, dialect, settings);]]>

    Subsequent sections of the manual contain some more in-depth explanations about these settings:

    @@ -1176,9 +1236,6 @@ Factory create = new Factory(connection, dialect, settings);]]>
  • -
  • - -
  • @@ -1188,7 +1245,7 @@ Factory create = new Factory(connection, dialect, settings);]]>

    Please refer to the jOOQ runtime configuration XSD for more details:
    - http://www.jooq.org/xsd/jooq-runtime-2.5.0.xsd + http://www.jooq.org/xsd/jooq-runtime-{runtime-xsd-version}.xsd

    @@ -1212,7 +1269,7 @@ Factory create = new Factory(connection, dialect, settings);]]>

    Mapping DEV to MY_BOOK_WORLD with jOOQ

    - When a user from My Book World logs in, you want them to access the MY_BOOK_WORLD schema using classes generated from DEV. This can be achieved with the class, that you can equip your Factory's with. Take the following example: + When a user from My Book World logs in, you want them to access the MY_BOOK_WORLD schema using classes generated from DEV. This can be achieved with the class, that you can equip your Executor's with. Take the following example:

    Settings settings = new Settings() @@ -1221,14 +1278,14 @@ Factory create = new Factory(connection, dialect, settings);]]> new MappedSchema().withInput("DEV") .withOutput("MY_BOOK_WORLD"))); -// Add the settings to the factory -Factory create = new Factory(connection, SQLDialect.ORACLE, settings); +// Add the settings to the executor +Executor create = new Executor(connection, SQLDialect.ORACLE, settings); -// Run queries with the "mapped" factory +// Run queries with the "mapped" executor create.selectFrom(AUTHOR).fetch();

    - The query executed with a Factory equipped with the above mapping will in fact produce this SQL statement: + The query executed with an Executor equipped with the above mapping will in fact produce this SQL statement:

    SELECT * FROM MY_BOOK_WORLD.AUTHOR @@ -1241,7 +1298,7 @@ create.selectFrom(AUTHOR).fetch(); Your development database may not be restricted to hold only one DEV schema. You may also have a LOG schema and a MASTER schema. Let's say the MASTER schema is shared among all customers, but each customer has their own LOG schema instance. Then you can enhance your RenderMapping like this (e.g. using an XML configuration file):

    - + @@ -1263,24 +1320,24 @@ create.selectFrom(AUTHOR).fetch(); Settings settings = JAXB.unmarshal(new File("jooq-runtime.xml"), Settings.class);

    - This will map generated classes from DEV to MY_BOOK_WORLD, from LOG to MY_BOOK_WORLD_LOG, but leave the MASTER schema alone. Whenever you want to change your mapping configuration, you will have to create a new Factory + This will map generated classes from DEV to MY_BOOK_WORLD, from LOG to MY_BOOK_WORLD_LOG, but leave the MASTER schema alone. Whenever you want to change your mapping configuration, you will have to create a new Executor.

    Using a default schema

    - Another option to switch schema names is to use a default schema for the Factory's underlying Connection. Many RDBMS support a USE or SET SCHEMA command, which you can call like this: + Another option to switch schema names is to use a default schema for the Executor's underlying Connection. Many RDBMS support a USE or SET SCHEMA command, which you can call like this:

    // Set the default schema Schema MY_BOOK_WORLD = ... create.use(MY_BOOK_WORLD); -// Run queries with factory having a default schema +// Run queries with an executor having a default schema create.selectFrom(AUTHOR).fetch();

    - Queries generated from the above Factory will produce this kind of SQL statement: + Queries generated from the above Executor will produce this kind of SQL statement:

    -- the schema name is omitted from all SQL constructs. @@ -1294,8 +1351,8 @@ SELECT * FROM AUTHOR Settings settings = new Settings() .withRenderSchema(false); -// Add the settings to the factory -Factory create = new Factory(connection, SQLDialect.ORACLE, settings); +// Add the settings to the executor +Executor create = new Executor(connection, SQLDialect.ORACLE, settings); // Run queries that omit rendering schema names create.selectFrom(AUTHOR).fetch(); @@ -1314,14 +1371,14 @@ create.selectFrom(AUTHOR).fetch(); new MappedTable().withInput("AUTHOR") .withOutput("MY_APP__AUTHOR")))); -// Add the settings to the factory -Factory create = new Factory(connection, SQLDialect.ORACLE, settings); +// Add the settings to the executor +Executor create = new Executor(connection, SQLDialect.ORACLE, settings); -// Run queries with the "mapped" factory +// Run queries with the "mapped" executor create.selectFrom(AUTHOR).fetch();

    - The query executed with a Factory equipped with the above mapping will in fact produce this SQL statement: + The query executed with an Executor equipped with the above mapping will in fact produce this SQL statement:

    SELECT * FROM MY_BOOK_WORLD.MY_APP__AUTHOR @@ -1336,22 +1393,6 @@ create.selectFrom(AUTHOR).fetch();

    - -
    - Factory subclasses - -

    - There are a couple of subclasses for the general Factory. Each SQL dialect has its own dialect-specific Factory. For instance, if you're only using the MySQL dialect, you can choose to reference the MySQLFactory instead of the standard Factory: -

    -

    - The advantage of referencing a dialect-specific Factory lies in the fact that you have access to more proprietary RDMBS functionality. This may include: -

    -
      -
    • MySQL's encryption functions
    • -
    • PL/SQL constructs, pgplsql, or any other dialect's ROUTINE-language (maybe in the future)
    • -
    -
    -
    @@ -1359,13 +1400,13 @@ create.selectFrom(AUTHOR).fetch(); SQL Statements

    - jOOQ currently supports 6 types of SQL statements. All of these statements are constructed from a Factory instance with an optional . If supplied with a Connection or DataSource, they can be executed. Depending on the , executed queries can return results. + jOOQ currently supports 6 types of SQL statements. All of these statements are constructed from an Executor instance with an optional . If supplied with a Connection or DataSource, they can be executed. Depending on the , executed queries can return results.

    - jOOQ's DSL and non-DSL API + jOOQ's DSL and model API

    jOOQ ships with its own DSL (or Domain Specific Language) that simulates SQL in Java. This means, that you can write SQL statements almost as if Java natively supported it, just like .NET's C# does with LINQ to SQL. @@ -1395,11 +1436,12 @@ create.select() We'll see how the aliasing works later in the section about

    -

    jOOQ as an internal domain specific language in Java (a.k.a. the DSL-API)

    +

    jOOQ as an internal domain specific language in Java (a.k.a. the DSL API)

    Many other frameworks have similar APIs with similar feature sets. Yet, what makes jOOQ special is its informal modelling a unified SQL dialect suitable for many vendor-specific dialects, and implementing that BNF notation as a hierarchy of interfaces in Java. This concept is extremely powerful, when with syntax completion. Not only can you code much faster, your SQL code will be compile-checked to a certain extent. An example of a DSL query equivalent to the previous one is given here:

    - result = create.select() .from(AUTHOR) .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) @@ -1408,7 +1450,7 @@ Result result = create.select()

    Unlike other, simpler frameworks that use "fluent APIs" or "method chaining", jOOQ's BNF-based interface hierarchy will not allow bad query syntax. The following will not compile, for instance:

    - result = create.select() .join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID)) // ^^^^ "join" is not possible here @@ -1424,14 +1466,29 @@ Result result = create.select() Result result = create.select(rowNumber()) // ^^^^^^^^^ "over()" is missing here .from(AUTHOR) + .fetch(); + +Result result = create.select() + .from(AUTHOR) + .where(AUTHOR.ID.in(select(BOOK.TITLE).from(BOOK))) + // ^^^^^^^^^^^^^^^^^^ + // AUTHOR.ID is of type Field but subselect returns Record1 + .fetch(); + +Result result = create.select() + .from(AUTHOR) + .where(AUTHOR.ID.in(select(BOOK.AUTHOR_ID, BOOK.ID).from(BOOK))) + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // AUTHOR.ID is of degree 1 but subselect returns Record2 .fetch();]]> -

    History of SQL building and incremental query building (a.k.a. the non-DSL API)

    +

    History of SQL building and incremental query building (a.k.a. the model API)

    - Historically, jOOQ started out as an object-oriented SQL builder library like any other. This meant that all queries and their syntactic components were modeled as so-called , which delegate and to child components. This part of the API will be referred to as the non-DSL API, which is still maintained and used internally by jOOQ for incremental query building. An example of incremental query building is given here: + Historically, jOOQ started out as an object-oriented SQL builder library like any other. This meant that all queries and their syntactic components were modeled as so-called , which delegate and to child components. This part of the API will be referred to as the model API (or non-DSL API), which is still maintained and used internally by jOOQ for incremental query building. An example of incremental query building is given here:

    - query = create.selectQuery(); query.addFrom(AUTHOR); // Join books only under certain circumstances @@ -1442,14 +1499,14 @@ if (join) { Result result = query.fetch();]]>

    - This query is equivalent to the one shown before using the DSL syntax. In fact, internally, the DSL API constructs precisely this QueryObject. Note, that you can always access the SelectQuery object to switch between DSL and non-DSL APIs: + This query is equivalent to the one shown before using the DSL syntax. In fact, internally, the DSL API constructs precisely this SelectQuery object. Note, that you can always access the SelectQuery object to switch between DSL and model APIs:

    - select = create.select().from(AUTHOR); // Add the JOIN clause on the internal QueryObject representation -SelectQuery query = select.getQuery(); +SelectQuery query = select.getQuery(); query.addJoin(BOOK, BOOK.AUTHOR_ID.equal(AUTHOR.ID));]]>

    Mutability

    @@ -1468,16 +1525,16 @@ a.or(b) != a.or(b); // or() always creates new objects // Statements (mutable) // -------------------- -SelectFromStep s1 = create.select(); -SelectJoinStep s2 = s1.from(BOOK); -SelectJoinStep s3 = s1.from(AUTHOR); +SelectFromStep s1 = select(); +SelectJoinStep s2 = s1.from(BOOK); +SelectJoinStep s3 = s1.from(AUTHOR); // The following can be said s1 == s2; // The internal object is always the same s2 == s3; // The internal object is always the same]]>

    - Mutability may be removed in a future version of jOOQ. + On the other hand, beware that you can always extract and modify from any QueryPart.

    @@ -1488,6 +1545,8 @@ s2 == s3; // The internal object is always the same]]>

    When you don't just perform (i.e. SELECT * FROM your_table WHERE ID = ?), you're usually generating new record types using custom projections. With jOOQ, this is as intuitive, as if using SQL directly. A more or less complete example of the "standard" SQL syntax, plus some extensions, is provided by a query like this:

    + +

    SELECT from a complex table expression

    - Details about the various clauses of this query will be provided in subsequent sections + Details about the various clauses of this query will be provided in subsequent sections.

    SELECT from single physical tables

    - A very similar, but limited API is available, if you want to select from single physical tables in order to retrieve . The decision, which type of select to create is already made at the very first step, when you create the SELECT statement with the Factory: + A very similar, but limited API is available, if you want to select from single physical tables in order to retrieve . The decision, which type of select to create is already made at the very first step, when you create the SELECT statement with the Factory or Executor:

    SelectWhereStep selectFrom(Table table);]]> @@ -1546,16 +1605,14 @@ create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count()) .fetchAny();]]>

    - The simple SELECT API is limited in the way that it does not support any of these clauses: + The "reduced" SELECT API is limited in the way that it skips DSL access to any of these clauses:

    • -
    • -

    - In most parts of this manual, it is assumed that you do not use the simple SELECT API. For more information about the simple SELECT API, see the manual's section about . + In most parts of this manual, it is assumed that you do not use the "reduced" SELECT API. For more information about the simple SELECT API, see the manual's section about .

    @@ -1606,6 +1663,32 @@ Select select2 = create.selectOne();]]> select1 = create.selectDistinct(BOOK.TITLE);]]>
    + +

    Typesafe projections with degree up to {max-row-degree}

    +

    + Since jOOQ 3.0, and up to degree {max-row-degree} are now generically typesafe. This is reflected by an overloaded SELECT (and SELECT DISTINCT) API in both Factory and Executor. An extract from Factory: +

    + + select(Collection> fields); +public static SelectSelectStep select(Field... fields); + +// Typesafe select methods: +public static SelectSelectStep> select(Field field1); +public static SelectSelectStep> select(Field field1, Field field2); +public static SelectSelectStep> select(Field field1, Field field2, Field field3); +// [...]]]> + +

    + Since the generic R type is bound to some , the associated T type information can be used in various other contexts, e.g. the . Such a SELECT statement can be assigned typesafely: +

    + +> s1 = create.select(BOOK.ID, BOOK.TITLE); +Select> s2 = create.select(BOOK.ID, trim(BOOK.TITLE));]]> + +

    + For more information about typesafe record types with degree up to {max-row-degree}, see the manual's section about . +

    @@ -1654,8 +1737,8 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> - +

    @@ -1685,7 +1768,7 @@ new Factory(SQLDialect.POSTGRES).selectOne().getSQL();]]> All of these JOIN methods can be called on types, or directly after the FROM clause for convenience. The following example joins AUTHOR and BOOK

    - result = create.select() @@ -1727,7 +1810,7 @@ create.select()

    JOIN ON KEY, convenience provided by jOOQ

    - Surprisingly, SQL does not allow to formally JOIN on well-known foreign key relationship information. Naturally, when you join BOOK to AUTHOR, you will want to do that based on the BOOK.AUTHOR_ID foreign key to AUTHOR.ID primary key relation. Not being able to do this in SQL leads to a lot of repetitive code, re-writing the same JOIN predicate again and again - especially, when your foreign keys contain more than one column. With jOOQ, when you use , you can use foreign key constraint information in JOIN expressions as such: + Surprisingly, the SQL standard does not allow to formally JOIN on well-known foreign key relationship information. Naturally, when you join BOOK to AUTHOR, you will want to do that based on the BOOK.AUTHOR_ID foreign key to AUTHOR.ID primary key relation. Not being able to do this in SQL leads to a lot of repetitive code, re-writing the same JOIN predicate again and again - especially, when your foreign keys contain more than one column. With jOOQ, when you use , you can use foreign key constraint information in JOIN expressions as such:

    @@ -1741,6 +1824,9 @@ JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID]]>

    In case of ambiguity, you can also supply field references for your foreign keys, or the generated foreign key reference to the onKey() method.

    +

    + Note that formal support for the Sybase JOIN ON KEY syntax is on the roadmap. +

    The JOIN USING syntax

    @@ -1903,7 +1989,7 @@ ORDER BY 1]]>

    - Note that this syntax is also supported in the CUBRID database. + Note that this syntax is also supported in the CUBRID database and might be simulated in other dialects supporting common table expressions in the future.

    ORDER SIBLINGS

    @@ -1942,15 +2028,18 @@ FROM BOOK GROUP BY AUTHOR_ID]]>
    + .groupBy(BOOK.AUTHOR_ID);]]>

    - As defined in the SQL standard, when grouping, you may no longer project any columns that are not a formal part of the GROUP BY clause, or . The above example counts all books per author + The above example counts all books per author.

    - +

    + Note, as defined in the SQL standard, when grouping, you may no longer project any columns that are not a formal part of the GROUP BY clause, or . +

    +

    MySQL's deviation from the SQL standard

    - MySQL has a peculiar way of not adhering to this standard behaviour. This is documented in the MySQL manual. In short, with MySQL, you can also project any other field that are not part of the GROUP BY clause. The projected values will just be arbitrary values from within the group. You cannot rely on any ordering. For example: + MySQL has a peculiar way of not adhering to this standard behaviour. This is documented in the MySQL manual. In short, with MySQL, you can also project any other field that is not part of the GROUP BY clause. The projected values will just be arbitrary values from within the group. You cannot rely on any ordering. For example:

    @@ -1967,7 +2056,7 @@ GROUP BY AUTHOR_ID]]>

    Empty GROUP BY clauses

    - jOOQ supports empty GROUP BY () clauses as well. This will result in that return only one record. + jOOQ supports empty GROUP BY () clause as well. This will result in that return only one record.

    @@ -2051,12 +2140,12 @@ ORDER BY 1 ASC, 2 DESC]]> .orderBy(one().asc(), inline(2).desc());]]>

    - Note, how one() is used as a convenience short-cut for inline(1) + Note, how one() is used as a convenience short-cut for inline(1)

    Ordering and NULLS

    - A few databases support the SQL standard "null ordering" clause in sort specification lists, to define whether NULL values should come first or last in an ordered result. + A few databases support the SQL standard "null ordering" clause in sort specification lists, to define whether NULL values should come first or last in an ordered result.

    @@ -2250,9 +2339,9 @@ FOR UPDATE OF TITLE]]> Oracle goes a bit further and also allows to specify the actual locking behaviour. It features these additional clauses, which are all supported by jOOQ:

      -
    • FOR UPDATE NOWAIT: This is the default behaviour. If the lock cannot be acquired, the query fails immediately
    • -
    • FOR UPDATE WAIT n: Try to wait for [n] seconds for the lock acquisition. The query will fail only afterwards
    • -
    • FOR UPDATE SKIP LOCKED: This peculiar syntax will skip all locked records. This is particularly useful when implementing queue tables with multiple consumers
    • +
    • FOR UPDATE NOWAIT: This is the default behaviour. If the lock cannot be acquired, the query fails immediately
    • +
    • FOR UPDATE WAIT n: Try to wait for [n] seconds for the lock acquisition. The query will fail only afterwards
    • +
    • FOR UPDATE SKIP LOCKED: This peculiar syntax will skip all locked records. This is particularly useful when implementing queue tables with multiple consumers

    With jOOQ, you can use those Oracle extensions as such: @@ -2310,7 +2399,7 @@ SELECT * FROM author ORDER BY id DESC;]]> UNION, INTERSECTION and EXCEPT

    - SQL allows to perform set operations as understood in standard set theory on result sets. These operations include unions, intersections, subtractions. For two subselects to be combinable by such a set operator, each subselect must return a of the same arity and type. + SQL allows to perform set operations as understood in standard set theory on result sets. These operations include unions, intersections, subtractions. For two subselects to be combinable by such a set operator, each subselect must return a of the same degree and type.

    UNION and UNION ALL

    @@ -2328,7 +2417,7 @@ create.selectFrom(BOOK).where(BOOK.ID.equal(5)));]]>

    INTERSECT [ ALL ] and EXCEPT [ ALL ]

    - INTERSECT is the operation that produces only those s that are returned by both subselects. EXCEPT is the operation that returns only those s that are returned exclusively in the first subselect. Both operators will remove duplicates from their results. The SQL standard allows to specify the ALL keyword for both of these operators as well, but this is hardly supported in any database. jOOQ does not support INTERSECT ALL, EXEPT ALL operations either. + INTERSECT is the operation that produces only those values that are returned by both subselects. EXCEPT is the operation that returns only those values that are returned exclusively in the first subselect. Both operators will remove duplicates from their results. The SQL standard allows to specify the ALL keyword for both of these operators as well, but this is hardly supported in any database. jOOQ does not support INTERSECT ALL, EXEPT ALL operations either.

    jOOQ's set operators and how they're different from standard SQL

    @@ -2348,6 +2437,21 @@ UNION create.selectFrom(AUTHOR) .orderBy(AUTHOR.DATE_OF_BIRTH.desc()).limit(1));]]>
    +

    Projection typesafety for degrees between 1 and {max-row-degree}

    +

    + Two subselects that are combined by a set operator are required to be of the same degree and, in most databases, also of the same type. jOOQ 3.0's introduction of helps compile-checking these constraints: +

    + +> s1 = select(BOOK.ID, BOOK.TITLE).from(BOOK); +Select> s2 = selectOne(); +Select> s3 = select(one(), zero()); +Select> s4 = select(one(), inline("abc")); + +// Let's try to combine them: +s1.union(s2); // Doesn't compile because of a degree mismatch. Expected: Record2<...>, got: Record1<...> +s1.union(s3); // Doesn't compile because of a type mismatch. Expected: , got: +s1.union(s4); // OK. The two Record[N] types match]]> @@ -2383,6 +2487,10 @@ FROM table1 + +
    + Lexical and logical SELECT clause order +
    @@ -2402,6 +2510,14 @@ VALUES (100, 'Hermann', 'Hesse'); AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .values(100, "Hermann", "Hesse"); +

    + Note that for explicit degrees up to {max-row-degree}, the VALUES() constructor provides additional typesafety. The following example illustrates this: +

    + + step = + create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME); + step.values("A", "B", "C"); + // ^^^ Doesn't compile, the expected type is Integer]]>

    INSERT multiple rows with the VALUES() constructor

    The SQL standard specifies that multiple rows can be supplied to the VALUES() constructor in an INSERT statement. Here's an example of a multi-record INSERT @@ -2449,7 +2565,7 @@ SELECT 101, 'Alfred', 'Döblin' FROM DUAL; .set(AUTHOR.LAST_NAME, "Döblin");

    - As you can see, this syntax is a bit more verbose, but also more type-safe, as every field can be matched with its value. Internally, the two syntaxes are strictly equivalent. + As you can see, this syntax is a bit more verbose, but also more readable, as every field can be matched with its value. Internally, the two syntaxes are strictly equivalent.

    MySQL's INSERT .. ON DUPLICATE KEY UPDATE

    @@ -2533,7 +2649,69 @@ create.insertInto(AUTHOR, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .set(AUTHOR.LAST_NAME, "Hesse") .where(AUTHOR.ID.equal(3)); - + +

    + Most databases allow for using scalar subselects in UPDATE statements in one way or another. jOOQ models this through a set(Field<T>, Select<? extends Record1<T>>) method in the UPDATE DSL API: +

    + + +UPDATE AUTHOR + SET FIRST_NAME = ( + SELECT FIRST_NAME + FROM PERSON + WHERE PERSON.ID = AUTHOR.ID + ), + WHERE ID = 3; +create.update(AUTHOR) + .set(AUTHOR.FIRST_NAME, + select(PERSON.FIRST_NAME) + .from(PERSON) + .where(PERSON.ID.equal(AUTHOR.ID)) + ) + .where(AUTHOR.ID.equal(3)); + + + +

    Using row value expressions in an UPDATE statement

    +

    + jOOQ supports formal in various contexts, among which the UPDATE statement. Only one row value expression can be updated at a time. Here's an example: +

    + + +UPDATE AUTHOR + SET (FIRST_NAME, LAST_NAME) = + ('Hermann', 'Hesse') + WHERE ID = 3; +create.update(AUTHOR) + .set(row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME), + row("Herman", "Hesse")) + .where(AUTHOR.ID.equal(3)); + + +

    + This can be particularly useful when using subselects: +

    + + +UPDATE AUTHOR + SET (FIRST_NAME, LAST_NAME) = ( + SELECT PERSON.FIRST_NAME, PERSON.LAST_NAME + FROM PERSON + WHERE PERSON.ID = AUTHOR.ID + ) + WHERE ID = 3; +create.update(AUTHOR) + .set(row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME), + select(PERSON.FIRST_NAME, PERSON.LAST_NAME) + .from(PERSON) + .where(PERSON.ID.equal(AUTHOR.ID)) + ) + .where(AUTHOR.ID.equal(3)); + + +

    + The above row value expressions usages are completely typesafe. +

    @@ -2607,6 +2785,10 @@ VALUES ('John', 'Hitchcock') http://www.h2database.com/html/grammar.html#merge

    +

    Typesafety of VALUES() for degrees up to {max-row-degree}

    +

    + Much like the , the MERGE statement's VALUES() clause provides typesafety for degrees up to {max-row-degree}, in both the standard syntax variant as well as the H2 variant. +

    @@ -2939,12 +3121,12 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> The SQL standard specifies that the is optional in a . However, according to the standard, you may then no longer use some other clauses, such as the . In the real world, there exist three types of databases:

      -
    • The ones that always require a FROM clause
    • -
    • The ones that never require a FROM clause (and still allow a WHERE clause)
    • +
    • The ones that always require a FROM clause
    • +
    • The ones that never require a FROM clause (and still allow a WHERE clause)
    • The ones that correctly implement the SQL standard

    - With jOOQ, you don't have to worry about the above distinction of SQL dialects. jOOQ never requires a FROM clause, but renders the necessary "DUAL" table, if needed. The following program shows how jOOQ renders "DUAL" tables + With jOOQ, you don't have to worry about the above distinction of SQL dialects. jOOQ never requires a FROM clause, but renders the necessary "DUAL" table, if needed. The following program shows how jOOQ renders "DUAL" tables

    @@ -2952,6 +3134,7 @@ FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(null, null, 'ALLSTATS'));]]> SELECT 1 FROM "db_root" SELECT 1 FROM "SYSIBM"."DUAL" SELECT 1 FROM "SYSIBM"."SYSDUMMY1" +SELECT 1 FROM "RDB$DATABASE" SELECT 1 FROM dual SELECT 1 FROM "INFORMATION_SCHEMA"."SYSTEM_USERS" SELECT 1 FROM (select 1 as dual) as dual @@ -2962,23 +3145,24 @@ SELECT 1 SELECT 1 SELECT 1 FROM [SYS].[DUMMY] ]]> - +

    - Note, that some databases (H2, MySQL) can normally do without "dual". However, there exist some corner-cases with complex nested SELECT statements, where this will cause syntax errors (or parser bugs). To stay on the safe side, jOOQ will always render "dual" in those dialects. + Note, that some databases (H2, MySQL) can normally do without "DUAL". However, there exist some corner-cases with complex nested SELECT statements, where this will cause syntax errors (or parser bugs). To stay on the safe side, jOOQ will always render "dual" in those dialects.

    @@ -3036,7 +3220,7 @@ ORDER BY BOOK.TITLE]]>

    - Table columns implement a more specific interface called , which is parameterised with its associated <R extends Record> record type. + Table columns implement a more specific interface called , which is parameterised with its associated <R extends Record> record type.

    See the manual's section about for more information about what is really generated by the @@ -3081,10 +3265,10 @@ System.out.println("Books : " + record.getValue("books")); Cast expressions

    - jOOQ's source code generator tries to find the most accurate type mapping between your vendor-specific data types and a matching Java type. For instance, most VARCHAR, CHAR, CLOB types will map to String. Most BINARY, BYTEA, BLOB types will map to byte[]. NUMERIC types will default to java.math.BigDecimal, but can also be any of java.math.BigInteger, Long, Integer, Short, Byte, Double, Float. + jOOQ's source code generator tries to find the most accurate type mapping between your vendor-specific data types and a matching Java type. For instance, most VARCHAR, CHAR, CLOB types will map to String. Most BINARY, BYTEA, BLOB types will map to byte[]. NUMERIC types will default to , but can also be any of , , , , , , .

    - Sometimes, this automatic mapping might not be what you needed, or jOOQ cannot know the type of a field. In those cases you would write SQL type CASTs like this: + Sometimes, this automatic mapping might not be what you needed, or jOOQ cannot know the type of a field. In those cases you would write SQL type CAST like this:

    -- Let's say, your Postgres column LAST_NAME was VARCHAR(30) @@ -3098,13 +3282,13 @@ SELECT CAST(AUTHOR.LAST_NAME AS TEXT) FROM DUAL create.select(TAuthor.LAST_NAME.cast(PostgresDataType.TEXT));

    - The same thing can be achieved by casting a Field directly to String.class, as TEXT is the default data type in Postgres to map to Java's String + The same thing can be achieved by casting a Field directly to String.class, as TEXT is the default data type in Postgres to map to Java's String

    create.select(TAuthor.LAST_NAME.cast(String.class));

    - The complete CAST API in Field consists of these three methods: + The complete CAST API in consists of these three methods:

    { @@ -3164,11 +3348,11 @@ public class Factory {

    - For more advanced datetime arithmetic, use the Factory's timestampDiff() and dateDiff() functions, as well as jOOQ's built-in SQL standard INTERVAL data type support: + For more advanced datetime arithmetic, use the Factory's timestampDiff() and dateDiff() functions, as well as jOOQ's built-in SQL standard INTERVAL data type support:

      -
    • INTERVAL YEAR TO MONTH:
    • -
    • INTERVAL DAY TO SECOND:
    • +
    • INTERVAL YEAR TO MONTH:
    • +
    • INTERVAL DAY TO SECOND:
    @@ -3202,10 +3386,10 @@ create.select(concat("A", "B", "C")); This is a list of general functions supported by jOOQ's :

      -
    • COALESCE: Get the first non-null value in a list of arguments.
    • -
    • NULLIF: Return NULL if both arguments are equal, or the first argument, otherwise.
    • -
    • NVL: Get the first non-null value among two arguments.
    • -
    • NVL2: Get the second argument if the first is null, or the third argument, otherwise.
    • +
    • COALESCE: Get the first non-null value in a list of arguments.
    • +
    • NULLIF: Return NULL if both arguments are equal, or the first argument, otherwise.
    • +
    • NVL: Get the first non-null value among two arguments.
    • +
    • NVL2: Get the second argument if the first is null, or the third argument, otherwise.

    @@ -3225,34 +3409,34 @@ create.select(concat("A", "B", "C"));

      -
    • ABS: Get the absolute value of a value.
    • -
    • ACOS: Get the arc cosine of a value.
    • -
    • ASIN: Get the arc sine of a value.
    • -
    • ATAN: Get the arc tangent of a value.
    • -
    • ATAN2: Get the atan2 function of two values.
    • -
    • CEIL: Get the smalles integer value larger than a given numeric value.
    • -
    • COS: Get the cosine of a value.
    • -
    • COSH: Get the hyperbolic cosine of a value.
    • -
    • COT: Get the cotangent of a value.
    • -
    • COTH: Get the hyperbolic cotangent of a value.
    • -
    • DEG: Transform radians into degrees.
    • -
    • EXP: Calculate e^value.
    • -
    • FLOOR: Get the largest integer value smaller than a given numeric value.
    • -
    • GREATEST: Finds the greatest among all argument values (can also be used with non-numeric values).
    • -
    • LEAST: Finds the least among all argument values (can also be used with non-numeric values).
    • -
    • LN: Get the natural logarithm of a value.
    • -
    • LOG: Get the logarithm of a value given a base.
    • -
    • POWER: Calculate value^exponent.
    • -
    • RAD: Transform degrees into radians.
    • -
    • RAND: Get a random number.
    • -
    • ROUND: Rounds a value to the nearest integer.
    • -
    • SIGN: Get the sign of a value (-1, 0, 1).
    • -
    • SIN: Get the sine of a value.
    • -
    • SINH: Get the hyperbolic sine of a value.
    • -
    • SQRT: Calculate the square root of a value.
    • -
    • TAN: Get the tangent of a value.
    • -
    • TANH: Get the hyperbolic tangent of a value.
    • -
    • TRUNC: Truncate the decimals off a given value.
    • +
    • ABS: Get the absolute value of a value.
    • +
    • ACOS: Get the arc cosine of a value.
    • +
    • ASIN: Get the arc sine of a value.
    • +
    • ATAN: Get the arc tangent of a value.
    • +
    • ATAN2: Get the atan2 function of two values.
    • +
    • CEIL: Get the smalles integer value larger than a given numeric value.
    • +
    • COS: Get the cosine of a value.
    • +
    • COSH: Get the hyperbolic cosine of a value.
    • +
    • COT: Get the cotangent of a value.
    • +
    • COTH: Get the hyperbolic cotangent of a value.
    • +
    • DEG: Transform radians into degrees.
    • +
    • EXP: Calculate e^value.
    • +
    • FLOOR: Get the largest integer value smaller than a given numeric value.
    • +
    • GREATEST: Finds the greatest among all argument values (can also be used with non-numeric values).
    • +
    • LEAST: Finds the least among all argument values (can also be used with non-numeric values).
    • +
    • LN: Get the natural logarithm of a value.
    • +
    • LOG: Get the logarithm of a value given a base.
    • +
    • POWER: Calculate value^exponent.
    • +
    • RAD: Transform degrees into radians.
    • +
    • RAND: Get a random number.
    • +
    • ROUND: Rounds a value to the nearest integer.
    • +
    • SIGN: Get the sign of a value (-1, 0, 1).
    • +
    • SIN: Get the sine of a value.
    • +
    • SINH: Get the hyperbolic sine of a value.
    • +
    • SQRT: Calculate the square root of a value.
    • +
    • TAN: Get the tangent of a value.
    • +
    • TANH: Get the hyperbolic tangent of a value.
    • +
    • TRUNC: Truncate the decimals off a given value.

    @@ -3268,16 +3452,16 @@ create.select(concat("A", "B", "C")); Interestingly, bitwise functions and bitwise arithmetic is not very popular among SQL databases. Most databases only support a few bitwise operations, while others ship with the full set of operators. jOOQ's API includes most bitwise operations as listed below. In order to avoid ambiguities with , all bitwise functions are prefixed with "bit"

      -
    • BIT_COUNT: Count the number of bits set to 1 in a number
    • -
    • BIT_AND: Set only those bits that are set in two numbers
    • -
    • BIT_OR: Set all bits that are set in at least one number
    • -
    • BIT_NAND: Set only those bits that are set in two numbers, and inverse the result
    • -
    • BIT_NOR: Set all bits that are set in at least one number, and inverse the result
    • -
    • BIT_NOT: Inverse the bits in a number
    • -
    • BIT_XOR: Set all bits that are set in at exactly one number
    • -
    • BIT_XNOR: Set all bits that are set in at exactly one number, and inverse the result
    • -
    • SHL: Shift bits to the left
    • -
    • SHR: Shift bits to the right
    • +
    • BIT_COUNT: Count the number of bits set to 1 in a number
    • +
    • BIT_AND: Set only those bits that are set in two numbers
    • +
    • BIT_OR: Set all bits that are set in at least one number
    • +
    • BIT_NAND: Set only those bits that are set in two numbers, and inverse the result
    • +
    • BIT_NOR: Set all bits that are set in at least one number, and inverse the result
    • +
    • BIT_NOT: Inverse the bits in a number
    • +
    • BIT_XOR: Set all bits that are set in at exactly one number
    • +
    • BIT_XNOR: Set all bits that are set in at exactly one number, and inverse the result
    • +
    • SHL: Shift bits to the left
    • +
    • SHR: Shift bits to the right

    Some background about bitwise operation simulation

    @@ -3300,33 +3484,33 @@ create.select(concat("A", "B", "C"));

      -
    • ASCII: Get the ASCII code of a character.
    • -
    • BIT_LENGTH: Get the length of a string in bits.
    • -
    • CHAR_LENGTH: Get the length of a string in characters.
    • -
    • CONCAT: Concatenate several strings.
    • -
    • ESCAPE: Escape a string for use with the .
    • -
    • LENGTH: Get the length of a string.
    • -
    • LOWER: Get a string in lower case letters.
    • -
    • LPAD: Pad a string on the left side.
    • -
    • LTRIM: Trim a string on the left side.
    • -
    • OCTET_LENGTH: Get the length of a string in octets.
    • -
    • POSITION: Find a string within another string.
    • -
    • REPEAT: Repeat a string a given number of times.
    • -
    • REPLACE: Replace a string within another string.
    • -
    • RPAD: Pad a string on the right side.
    • -
    • RTRIM: Trim a string on the right side.
    • -
    • SUBSTRING: Get a substring of a string.
    • -
    • TRIM: Trim a string on both sides.
    • -
    • UPPER: Get a string in upper case letters.
    • +
    • ASCII: Get the ASCII code of a character.
    • +
    • BIT_LENGTH: Get the length of a string in bits.
    • +
    • CHAR_LENGTH: Get the length of a string in characters.
    • +
    • CONCAT: Concatenate several strings.
    • +
    • ESCAPE: Escape a string for use with the .
    • +
    • LENGTH: Get the length of a string.
    • +
    • LOWER: Get a string in lower case letters.
    • +
    • LPAD: Pad a string on the left side.
    • +
    • LTRIM: Trim a string on the left side.
    • +
    • OCTET_LENGTH: Get the length of a string in octets.
    • +
    • POSITION: Find a string within another string.
    • +
    • REPEAT: Repeat a string a given number of times.
    • +
    • REPLACE: Replace a string within another string.
    • +
    • RPAD: Pad a string on the right side.
    • +
    • RTRIM: Trim a string on the right side.
    • +
    • SUBSTRING: Get a substring of a string.
    • +
    • TRIM: Trim a string on both sides.
    • +
    • UPPER: Get a string in upper case letters.

    Please refer to the for more details.

    -

    Regular expressions, REGEXP, REGEXP_LIKE, etc.

    +

    Regular expressions, REGEXP, REGEXP_LIKE, etc.

    - Various databases have some means of searching through columns using regular expressions if the does not provide sufficient pattern matching power. While there are many different functions and operators in the various databases, jOOQ settled for the SQL:2008 standard REGEX_LIKE operator. Being an operator (and not a function), you should use the corresponding method on : + Various databases have some means of searching through columns using regular expressions if the does not provide sufficient pattern matching power. While there are many different functions and operators in the various databases, jOOQ settled for the SQL:2008 standard REGEX_LIKE operator. Being an operator (and not a function), you should use the corresponding method on :

    @@ -3346,18 +3530,18 @@ create.select(concat("A", "B", "C"));

      -
    • CURRENT_DATE: Get current date as a DATE object.
    • -
    • CURRENT_TIME: Get current time as a TIME object.
    • -
    • CURRENT_TIMESTAMP: Get current date as a TIMESTAMP object.
    • -
    • DATE_ADD: Add a number of days or an interval to a date.
    • -
    • DATE_DIFF: Get the difference in days between two dates.
    • -
    • TIMESTAMP_ADD: Add a number of days or an interval to a timestamp.
    • -
    • TIMESTAMP_DIFF: Get the difference as an INTERVAL DAY TO SECOND between two dates.
    • +
    • CURRENT_DATE: Get current date as a DATE object.
    • +
    • CURRENT_TIME: Get current time as a TIME object.
    • +
    • CURRENT_TIMESTAMP: Get current date as a TIMESTAMP object.
    • +
    • DATE_ADD: Add a number of days or an interval to a date.
    • +
    • DATE_DIFF: Get the difference in days between two dates.
    • +
    • TIMESTAMP_ADD: Add a number of days or an interval to a timestamp.
    • +
    • TIMESTAMP_DIFF: Get the difference as an INTERVAL DAY TO SECOND between two dates.

    Intervals in jOOQ

    - jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. See the manual's section about for more details. + jOOQ fills a gap opened by JDBC, which neglects an important SQL data type as defined by the SQL standards: INTERVAL types. See the manual's section about for more details.

    @@ -3369,7 +3553,7 @@ create.select(concat("A", "B", "C")); This is a list of system functions supported by jOOQ's :

      -
    • CURRENT_USER: Get current user.
    • +
    • CURRENT_USER: Get current user.
    @@ -3439,7 +3623,7 @@ GROUP BY AUTHOR_ID

    Ordered aggregate functions

    - Oracle and some other databases support "ordered aggregate functions". This means you can provide an ORDER BY clause to an aggregate function, which will be taken into consideration when aggregating. The best example for this is Oracle's LISTAGG() (also known as GROUP_CONCAT in other ). The following query groups by authors and concatenates their books' titles + Oracle and some other databases support "ordered aggregate functions". This means you can provide an ORDER BY clause to an aggregate function, which will be taken into consideration when aggregating. The best example for this is Oracle's LISTAGG() (also known as GROUP_CONCAT in other ). The following query groups by authors and concatenates their books' titles

    SELECT LISTAGG(TITLE, ', ') @@ -3465,7 +3649,7 @@ GROUP BY AUTHOR_ID

    FIRST and LAST: Oracle's "ranked" aggregate functions

    - Oracle allows for restricting aggregate functions using the KEEP() clause, which is supported by jOOQ. In Oracle, some aggregate functions (MIN, MAX, SUM, AVG, COUNT, VARIANCE, or STDDEV) can be restricted by this clause, hence also allows for specifying it. Here are a couple of examples using this clause: + Oracle allows for restricting aggregate functions using the KEEP() clause, which is supported by jOOQ. In Oracle, some aggregate functions (MIN, MAX, SUM, AVG, COUNT, VARIANCE, or STDDEV) can be restricted by this clause, hence also allows for specifying it. Here are a couple of examples using this clause:

    @@ -3596,9 +3780,9 @@ FROM BOOK .from(BOOK)
    -

    Window functions created from Oracle's FIRST and LAST aggregate functions

    +

    Window functions created from Oracle's FIRST and LAST aggregate functions

    - In the previous chapter about , we have seen the concept of "FIRST and LAST aggregate functions". These functions have a window function / analytical function variant, as well. For example: + In the previous chapter about , we have seen the concept of "FIRST and LAST aggregate functions". These functions have a window function / analytical function variant, as well. For example:

    @@ -3623,7 +3807,7 @@ FROM BOOK

    ROLLUP() explained in SQL

    - The SQL standard defines special functions that can be used in the : the grouping functions. These functions can be used to generate several groupings in a single clause. This can best be explained in SQL. Let's take ROLLUP() for instance: + The SQL standard defines special functions that can be used in the : the grouping functions. These functions can be used to generate several groupings in a single clause. This can best be explained in SQL. Let's take ROLLUP() for instance:

    @@ -3756,11 +3940,11 @@ ORDER BY 1 NULLS FIRST, 2 NULLS FIRST

    rollup(Field... fields); -Field cube(Field... fields); -Field groupingSets(Field... fields); -Field groupingSets(Field[]... fields); -Field groupingSets(Collection>... fields); +GroupField rollup(Field... fields); +GroupField cube(Field... fields); +GroupField groupingSets(Field... fields); +GroupField groupingSets(Field[]... fields); +GroupField groupingSets(Collection>... fields); // The utility functions generating IDs per GROUPING SET Field grouping(Field); @@ -3820,7 +4004,7 @@ END echo; User-defined aggregate functions

    - Some databases support user-defined aggregate functions, which can then be used along with or as . An example for such a database is Oracle. With Oracle, you can define the following OBJECT type (the example was taken from the Oracle 11g documentation): + Some databases support user-defined aggregate functions, which can then be used along with or as . An example for such a database is Oracle. With Oracle, you can define the following OBJECT type (the example was taken from the Oracle 11g documentation):

    - The above OBJECT type is then available to function declarations as such: + The above OBJECT type is then available to function declarations as such:

    Using the generated aggregate function

    - jOOQ's will detect such aggregate functions and generate them differently from regular . They implement the type, as mentioned in the manual's section about . Here's how you can use the SECOND_MAX() aggregate function with jOOQ: + jOOQ's will detect such aggregate functions and generate them differently from regular . They implement the type, as mentioned in the manual's section about . Here's how you can use the SECOND_MAX() aggregate function with jOOQ:

    @@ -3904,7 +4088,7 @@ create.select(secondMax(BOOK.PUBLISHED_IN)) The CASE expression

    - The CASE expression is part of the standard SQL syntax. While some RDBMS also offer an IF expression, or a DECODE function, you can always rely on the two types of CASE syntax: + The CASE expression is part of the standard SQL syntax. While some RDBMS also offer an IF expression, or a DECODE function, you can always rely on the two types of CASE syntax:

    @@ -3933,11 +4117,11 @@ create.decode().value(AUTHOR.FIRST_NAME)

    - In jOOQ, both syntaxes are supported (The second one is simulated in Derby, which only knows the first one). Unfortunately, both case and else are reserved words in Java. jOOQ chose to use decode() from the Oracle DECODE function, and otherwise(), which means the same as else. + In jOOQ, both syntaxes are supported (The second one is simulated in Derby, which only knows the first one). Unfortunately, both case and else are reserved words in Java. jOOQ chose to use decode() from the Oracle DECODE function, and otherwise(), which means the same as else.

    - A CASE expression can be used anywhere where you can place a . For instance, you can SELECT the above expression, if you're selecting from AUTHOR: + A CASE expression can be used anywhere where you can place a . For instance, you can SELECT the above expression, if you're selecting from AUTHOR:

    SELECT AUTHOR.FIRST_NAME, [... CASE EXPR ...] AS nationality @@ -3945,7 +4129,7 @@ create.decode().value(AUTHOR.FIRST_NAME)

    The Oracle DECODE() function

    - Oracle knows a more succinct, but maybe less readable DECODE() function with a variable number of arguments. This function roughly does the same as the second case expression syntax. jOOQ supports the DECODE() function and simulates it using CASE expressions in all dialects other than Oracle: + Oracle knows a more succinct, but maybe less readable DECODE() function with a variable number of arguments. This function roughly does the same as the second case expression syntax. jOOQ supports the DECODE() function and simulates it using CASE expressions in all dialects other than Oracle:

    @@ -3974,7 +4158,7 @@ create.decode(AUTHOR.FIRST_NAME,

    CASE clauses in an ORDER BY clause

    - Sort indirection is often implemented with a CASE clause of a SELECT's ORDER BY clause. See the manual's section about the for more details. + Sort indirection is often implemented with a CASE clause of a SELECT's ORDER BY clause. See the manual's section about the for more details.

    @@ -4021,23 +4205,33 @@ create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) Tuples or row value expressions

    - According to the SQL standard, row value expressions can have a degree of more than one. This is commonly used in the , where the VALUES row value constructor allows for providing a row value expression as a source for INSERT data. Row value expressions can appear in various other places, though. They are supported by jOOQ as s / rows. jOOQ's allows for the construction of type-safe s up to the degree / arity of 8. Higher-degree s are supported as well, but without any type-safety. types are modelled as follows: + According to the SQL standard, row value expressions can have a degree of more than one. This is commonly used in the , where the VALUES row value constructor allows for providing a row value expression as a source for INSERT data. Row value expressions can appear in various other places, though. They are supported by jOOQ as records / rows. jOOQ's allows for the construction of type-safe records up to the degree of {max-row-degree}. Higher-degree Rows are supported as well, but without any type-safety. Row types are modelled as follows:

    Row1 row(T1 t1) { ... } -public static Row2 row(T1 t1, T2 t2) { ... } -public static Row3 row(T1 t1, T2 t2, T3 t3) { ... } +public static Row1 row(T1 t1) { ... } +public static Row2 row(T1 t1, T2 t2) { ... } +public static Row3 row(T1 t1, T2 t2, T3 t3) { ... } public static Row4 row(T1 t1, T2 t2, T3 t3, T4 t4) { ... } -// [ ... idem for Row5, Row6, Row7, Row8 ... ] +// [ ... idem for Row5, Row6, Row7, ..., Row{max-row-degree} ] -// Degrees of more than 8 are supported without type-safety +// Degrees of more than {max-row-degree} are supported without type-safety public static RowN row(Object... values) { ... }]]>

    Using row value expressions in predicates

    - Row value expressions are incompatible with most other , but they can be used as a basis for constructing various , such as , , or the "degree 2 row value expression only" . See the relevant sections for more details about how to use row value expressions in predicates. + Row value expressions are incompatible with most other , but they can be used as a basis for constructing various , such as: +

    +
      +
    • +
    • +
    • +
    • +
    • (for degree 2 row value expressions only)
    • +
    +

    + See the relevant sections for more details about how to use row value expressions in predicates.

    Using row value expressions in UPDATE statements

    @@ -4057,7 +4251,7 @@ public static RowN row(Object... values) { ... }]]>

    • The
    • -
    • The (or JOIN .. ON clause, to be precise) of a , ,
    • +
    • The (or JOIN .. ON clause, to be precise) of a , ,
    • The of a , ,
    • The of a
    • The of a
    • @@ -4069,21 +4263,21 @@ public static RowN row(Object... values) { ... }]]> Before SQL:1999, boolean types did not really exist in SQL. They were modelled by 0 and 1 numeric/char values. With SQL:1999, true booleans were introduced and are now supported by most databases. In short, these are possible boolean values:

        -
      • 1 or TRUE
      • -
      • 0 or FALSE
      • -
      • NULL or UNKNOWN
      • +
      • 1 or TRUE
      • +
      • 0 or FALSE
      • +
      • NULL or UNKNOWN

      - It is important to know that SQL differs from many other languages in the way it interprets the NULL boolean value. Most importantly, the following facts are to be remembered: + It is important to know that SQL differs from many other languages in the way it interprets the NULL boolean value. Most importantly, the following facts are to be remembered:

        -
      • [ANY] = NULL yields NULL (not FALSE)
      • -
      • [ANY] != NULL yields NULL (not TRUE)
      • -
      • NULL = NULL yields NULL (not TRUE)
      • -
      • NULL != NULL yields NULL (not FALSE)
      • +
      • [ANY] = NULL yields NULL (not FALSE)
      • +
      • [ANY] != NULL yields NULL (not TRUE)
      • +
      • NULL = NULL yields NULL (not TRUE)
      • +
      • NULL != NULL yields NULL (not FALSE)

      - For simplified NULL handling, please refer to the section about the . + For simplified NULL handling, please refer to the section about the .

      Note that jOOQ does not model these values as actual compatible. @@ -4112,7 +4306,7 @@ BOOK.TITLE.notEqual("Animal Farm")]]>

      • , that allow you to phrase your own SQL string
      • The , a standalone predicate that creates a conditional expression
      • -
      • Constant TRUE and FALSE conditional expressions
      • +
      • Constant TRUE and FALSE conditional expressions

      Connect conditions using boolean operators

      @@ -4126,7 +4320,7 @@ BOOK.TITLE.notEqual("Animal Farm")]]> AND, OR, NOT boolean operators

      - In SQL, as in most other languages, can be connected using the AND and OR binary operators, as well as the NOT unary operator, to form new conditional expressions. In jOOQ, this is modelled as such: + In SQL, as in most other languages, can be connected using the AND and OR binary operators, as well as the NOT unary operator, to form new conditional expressions. In jOOQ, this is modelled as such:

      @@ -4199,34 +4393,29 @@ not() // Invert a condition (synonym for Factory.not(Conditi Unfortunately, Java does not support operator overloading, hence these operators are also implemented as methods in jOOQ, like any other SQL syntax elements. The relevant parts of the interface are these:

      -); // = (some column expression) -eq or equal(Select); // = (some scalar SELECT statement) -ne or notEqual(T); // <> (some bind value) -ne or notEqual(Field); // <> (some column expression) -ne or notEqual(Select); // <> (some scalar SELECT statement) -lt or lessThan(T); // < (some bind value) -lt or lessThan(Field); // < (some column expression) -lt or lessThan(Select); // < (some scalar SELECT statement) -le or lessOrEqual(T); // <= (some bind value) -le or lessOrEqual(Field); // <= (some column expression) -le or lessOrEqual(Select); // <= (some scalar SELECT statement) -gt or greaterThan(T); // > (some bind value) -gt or greaterThan(Field); // > (some column expression) -gt or greaterThan(Select); // > (some scalar SELECT statement) -ge or greaterOrEqual(T); // >= (some bind value) -ge or greaterOrEqual(Field); // >= (some column expression) -ge or greaterOrEqual(Select); // >= (some scalar SELECT statement)]]> +); // = (some column expression) +eq or equal(Select>); // = (some scalar SELECT statement) +ne or notEqual(T); // <> (some bind value) +ne or notEqual(Field); // <> (some column expression) +ne or notEqual(Select>); // <> (some scalar SELECT statement) +lt or lessThan(T); // < (some bind value) +lt or lessThan(Field); // < (some column expression) +lt or lessThan(Select>); // < (some scalar SELECT statement) +le or lessOrEqual(T); // <= (some bind value) +le or lessOrEqual(Field); // <= (some column expression) +le or lessOrEqual(Select>); // <= (some scalar SELECT statement) +gt or greaterThan(T); // > (some bind value) +gt or greaterThan(Field); // > (some column expression) +gt or greaterThan(Select>); // > (some scalar SELECT statement) +ge or greaterOrEqual(T); // >= (some bind value) +ge or greaterOrEqual(Field); // >= (some column expression) +ge or greaterOrEqual(Select>); // >= (some scalar SELECT statement)]]>

      - Note that every operator is represented by two methods. A verbose one (such as equal()) and a two-character one (such as eq()). Both methods are the same. You may choose either one, depending on your taste. The manual will always use the more verbose one. + Note that every operator is represented by two methods. A verbose one (such as equal()) and a two-character one (such as eq()). Both methods are the same. You may choose either one, depending on your taste. The manual will always use the more verbose one.

      -

      NULL in jOOQ's comparison predicates

      -

      - jOOQ has a special way of dealing with null bind values, when you pass them to comparison predicates equal() and notEqual(). For convenience, jOOQ will render predicates. -

      -

      jOOQ's convenience methods using comparison operators

      In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using comparison predicates: @@ -4243,18 +4432,99 @@ BOOK.TITLE.notEqualIgnoreCase("animal farm")]]> +

      + Comparison predicate (degree > 1) + +

      + All variants of the that we've seen in the previous chapter also work for . If your database does not support row value expression comparison predicates, jOOQ simulates them the way they are defined in the SQL standard: +

      + + + (X, Y) + +(A, B, C) > (X, Y, Z) + + +-- greater or equal +(A, B) >= (X, Y) + + +(A, B, C) >= (X, Y, Z) + + + +-- Inverse comparisons + +(A, B) <> (X, Y) +(A, B) < (X, Y) +(A, B) <= (X, Y)]]> + X) + OR ((A = X) AND (B > Y)) +(A > X) + OR ((A = X) AND (B > Y)) + OR ((A = X) AND (B = Y) AND (C > Z)) +-- greater or equal +(A > X) + OR ((A = X) AND (B > Y)) + OR ((A = X) AND (B = Y)) +(A > X) + OR ((A = X) AND (B > Y)) + OR ((A = X) AND (B = Y) AND (C > Z)) + OR ((A = X) AND (B = Y) AND (C = Z)) +-- For simplicity, these predicates are shown in terms +-- of their negated counter parts +NOT((A, B) = (X, Y)) +NOT((A, B) >= (X, Y)) +NOT((A, B) > (X, Y))]]> + + +

      + jOOQ supports all of the above row value expression comparison predicates, both with and at the right-hand side: +

      + + + + + +
      +
      +
      Quantified comparison predicate

      - If the right-hand side of a turns out to be a non-scalar table subquery, you can wrap that subquery in a quantifier, such as ALL, ANY, or SOME. Note that the SQL standard defines ANY and SOME to be equivalent. jOOQ settled for the more intuitive ANY and doesn't support SOME. Here are some examples, supported by jOOQ: + If the right-hand side of a turns out to be a non-scalar table subquery, you can wrap that subquery in a quantifier, such as ALL, ANY, or SOME. Note that the SQL standard defines ANY and SOME to be equivalent. jOOQ settled for the more intuitive ANY and doesn't support SOME. Here are some examples, supported by jOOQ:

      ALL(1920, 1940)]]> - +

      @@ -4263,12 +4533,12 @@ BOOK.PUBLISHED_IN.greaterThanAll(1920, 1940);]]>

      ANY and the IN predicate

      - It is interesting to note that the SQL standard defines the in terms of the ANY-quantified predicate. The following two expressions are equivalent: + It is interesting to note that the SQL standard defines the in terms of the ANY-quantified predicate. The following two expressions are equivalent:

      - - + +

      @@ -4276,12 +4546,12 @@ BOOK.PUBLISHED_IN.greaterThanAll(1920, 1940);]]>

      - +
      NULL predicate

      - In SQL, you cannot compare NULL with any value using , as the result would yield NULL again, which is neither TRUE nor FALSE (see also the manual's section about ). In order to test a for NULL, use the NULL predicate as such: + In SQL, you cannot compare NULL with any value using , as the result would yield NULL again, which is neither TRUE nor FALSE (see also the manual's section about ). In order to test a for NULL, use the NULL predicate as such:

      @@ -4294,20 +4564,68 @@ BOOK.TITLE.isNotNull()]]>
      +
      + NULL predicate (degree > 1) + +

      + The SQL NULL predicate also works well for , although it has some subtle, counter-intuitive features when it comes to inversing predicates with the NOT() operator! Here are some examples: +

      + + + + + + +

      + The SQL standard contains a nice truth table for the above rules: +

      + ++-----------------------+-----------+---------------+---------------+-------------------+ +| Expression | R IS NULL | R IS NOT NULL | NOT R IS NULL | NOT R IS NOT NULL | ++-----------------------+-----------+---------------+---------------+-------------------+ +| degree 1: null | true | false | false | true | +| degree 1: not null | false | true | true | false | +| degree > 1: all null | true | false | false | true | +| degree > 1: some null | false | false | true | true | +| degree > 1: none null | false | true | true | false | ++-----------------------+-----------+---------------+---------------+-------------------+ + +

      + In jOOQ, you would simply use the isNull() and isNotNull() methods on row value expressions. Again, as with the , the row value expression NULL predicate is simulated by jOOQ, if your database does not natively support it: +

      + + + +
      +
      +
      DISTINCT predicate

      - Some databases support the DISTINCT predicate, which serves as a convenient, NULL-safe . With the DISTINCT predicate, the following truth table can be assumed: + Some databases support the DISTINCT predicate, which serves as a convenient, NULL-safe . With the DISTINCT predicate, the following truth table can be assumed:

        -
      • [ANY] IS DISTINCT FROM NULL yields TRUE
      • -
      • [ANY] IS NOT DISTINCT FROM NULL yields FALSE
      • -
      • NULL IS DISTINCT FROM NULL yields FALSE
      • -
      • NULL IS NOT DISTINCT FROM NULL yields TRUE
      • +
      • [ANY] IS DISTINCT FROM NULL yields TRUE
      • +
      • [ANY] IS NOT DISTINCT FROM NULL yields FALSE
      • +
      • NULL IS DISTINCT FROM NULL yields FALSE
      • +
      • NULL IS NOT DISTINCT FROM NULL yields TRUE

      - For instance, you can compare two fields for distinctness, ignoring the fact that any of the two could be NULL, which would lead to funny results. This is supported by jOOQ as such: + For instance, you can compare two fields for distinctness, ignoring the fact that any of the two could be NULL, which would lead to funny results. This is supported by jOOQ as such:

      @@ -4318,7 +4636,7 @@ BOOK.TITLE.isNotDistinctFrom(BOOK.SUB_TITLE)]]>

      - If your database does not natively support the DISTINCT predicate, jOOQ simulates it with an equivalent , modelling the above truth table: + If your database does not natively support the DISTINCT predicate, jOOQ simulates it with an equivalent , modelling the above truth table:

      @@ -4346,7 +4664,7 @@ END BETWEEN predicate

      - The BETWEEN predicate can be seen as syntactic sugar for a pair of . According to the SQL standard, the following two predicates are equivalent: + The BETWEEN predicate can be seen as syntactic sugar for a pair of . According to the SQL standard, the following two predicates are equivalent:

      @@ -4355,7 +4673,7 @@ END

      - Note the inclusiveness of range boundaries in the definition of the BETWEEN predicate. Intuitively, this is supported in jOOQ as such: + Note the inclusiveness of range boundaries in the definition of the BETWEEN predicate. Intuitively, this is supported in jOOQ as such:

      @@ -4367,7 +4685,7 @@ BOOK.PUBLISHED_IN.notBetween(1920).and(1940)]]>

      BETWEEN SYMMETRIC

      - The SQL standard defines the SYMMETRIC keyword to be used along with BETWEEN to indicate that you do not care which bound of the range is larger than the other. A database system should simply swap range bounds, in case the first bound is greater than the second one. jOOQ supports this keyword as well, simulating it if necessary. + The SQL standard defines the SYMMETRIC keyword to be used along with BETWEEN to indicate that you do not care which bound of the range is larger than the other. A database system should simply swap range bounds, in case the first bound is greater than the second one. jOOQ supports this keyword as well, simulating it if necessary.

      @@ -4389,18 +4707,45 @@ BOOK.PUBLISHED_IN.notBetweenSymmetric(1940).and(1920)]]>
      +
      + BETWEEN predicate (degree > 1) + +

      + The SQL BETWEEN predicate also works well for . Much like the , it is defined in terms of a pair of regular : +

      + + + += [B] AND [A] <= [C] +([A] >= [B] AND [A] <= [C]) OR ([A] >= [C] AND [A] <= [B])]]> + + +

      + The above can be factored out according to the rules listed in the manual's section about . +

      + +

      + jOOQ supports the BETWEEN [SYMMETRIC] predicate and simulates it in all SQL dialects where necessary. An example is given here: +

      + + + +
      +
      +
      LIKE predicate

      - LIKE predicates are popular for simple wildcard-enabled pattern matching. Supported wildcards in all SQL databases are: + LIKE predicates are popular for simple wildcard-enabled pattern matching. Supported wildcards in all SQL databases are:

      • _: (single-character wildcard)
      • %: (multi-character wildcard)

      - With jOOQ, the LIKE predicate can be created from any as such: + With jOOQ, the LIKE predicate can be created from any as such:

      @@ -4412,7 +4757,7 @@ BOOK.TITLE.notLike("%abc%")]]>

      Escaping operands with the LIKE predicate

      - Often, your pattern may contain any of the wildcard characters "_" and "%", in case of which you may want to escape them. jOOQ does not automatically escape patterns in like() and notLike() methods. Instead, you can explicitly define an escape character as such: + Often, your pattern may contain any of the wildcard characters "_" and "%", in case of which you may want to escape them. jOOQ does not automatically escape patterns in like() and notLike() methods. Instead, you can explicitly define an escape character as such:

      @@ -4423,15 +4768,15 @@ BOOK.TITLE.notLike("%The !%-Sign Book%", '!')]]>

      - In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters "!_" and "!%", as well as to escape the escape character itself: "!!" + In the above predicate expressions, the exclamation mark character is passed as the escape character to escape wildcard characters "!_" and "!%", as well as to escape the escape character itself: "!!"

      - Please refer to your database manual for more details about escaping patterns with the LIKE predicate. + Please refer to your database manual for more details about escaping patterns with the LIKE predicate.

      jOOQ's convenience methods using the LIKE predicate

      - In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using the LIKE predicate. Typical operations are "contains predicates", "starts with predicates", "ends with predicates", etc. Here is the full convenience API wrapping LIKE predicates: + In addition to the above, jOOQ provides a few convenience methods for common operations performed on strings using the LIKE predicate. Typical operations are "contains predicates", "starts with predicates", "ends with predicates", etc. Here is the full convenience API wrapping LIKE predicates:

      @@ -4454,7 +4799,7 @@ BOOK.TITLE.endsWith("abc")]]>

      - Note, that jOOQ escapes % and _ characters in value in some of the above predicate implementations. For simplicity, this has been omitted in this manual. + Note, that jOOQ escapes % and _ characters in value in some of the above predicate implementations. For simplicity, this has been omitted in this manual.

      @@ -4463,20 +4808,20 @@ BOOK.TITLE.endsWith("abc")]]> IN predicate

      - In SQL, apart from comparing a value against several values, the IN predicate can be used to create semi-joins or anti-joins. jOOQ knows the following methods on the interface, to construct such IN predicates: + In SQL, apart from comparing a value against several values, the IN predicate can be used to create semi-joins or anti-joins. jOOQ knows the following methods on the interface, to construct such IN predicates:

      -) // Construct an IN predicate from a collection of bind values -in(T...) // Construct an IN predicate from bind values -in(Field...) // Construct an IN predicate from column expressions -in(Select) // Construct an IN predicate from a subselect -notIn(Collection) // Construct a NOT IN predicate from a collection of bind values -notIn(T...) // Construct a NOT IN predicate from bind values -notIn(Field...) // Construct a NOT IN predicate from column expressions -notIn(Select) // Construct a NOT IN predicate from a subselect]]> +) // Construct an IN predicate from a collection of bind values +in(T...) // Construct an IN predicate from bind values +in(Field...) // Construct an IN predicate from column expressions +in(Select>) // Construct an IN predicate from a subselect +notIn(Collection) // Construct a NOT IN predicate from a collection of bind values +notIn(T...) // Construct a NOT IN predicate from bind values +notIn(Field...) // Construct a NOT IN predicate from column expressions +notIn(Select>) // Construct a NOT IN predicate from a subselect]]>

      - A sample IN predicate might look like this: + A sample IN predicate might look like this:

      @@ -4489,7 +4834,7 @@ BOOK.TITLE.notIn("Animal Farm", "1984")]]>

      NOT IN and NULL values

      - Beware that you should probably not have any NULL values in the right hand side of a NOT IN predicate, as the whole expression would evaluate to NULL, which is rarely desired. This can be shown informally using the following reasoning: + Beware that you should probably not have any NULL values in the right hand side of a NOT IN predicate, as the whole expression would evaluate to NULL, which is rarely desired. This can be shown informally using the following reasoning:

      -- The following conditional expressions are formally or informally equivalent @@ -4504,16 +4849,36 @@ A != B AND NULL -- [ANY] != NULL yields NULL NULL -- [ANY] AND NULL yields NULL

      - A good way to prevent this from happening is to use the for anti-joins, which is NULL-value insensitive. See the manual's section about to see a boolean truth table. + A good way to prevent this from happening is to use the for anti-joins, which is NULL-value insensitive. See the manual's section about to see a boolean truth table.

      +
      + IN predicate (degree > 1) + +

      + The SQL IN predicate also works well for . Much like the , it is defined in terms of a . The two expressions are equivalent: +

      + + + + + + +

      + jOOQ supports the IN predicate. Simulation of the IN predicate where row value expressions aren't well supported is currently only available for IN predicates that do not take a subselect as an IN predicate value. An example is given here: +

      + + +
      +
      +
      EXISTS predicate

      - Slightly less intuitive, yet more powerful than the previously discussed is the EXISTS predicate, that can be used to form semi-joins or anti-joins. With jOOQ, the EXISTS predicate can be formed in various ways: + Slightly less intuitive, yet more powerful than the previously discussed is the EXISTS predicate, that can be used to form semi-joins or anti-joins. With jOOQ, the EXISTS predicate can be formed in various ways:

      • From the , using static methods. This is probably the most used case
      • @@ -4522,7 +4887,7 @@ NULL -- [ANY] AND NULL yields NULL

      - An example of an EXISTS predicate can be seen here: + An example of an EXISTS predicate can be seen here:

      @@ -4537,7 +4902,7 @@ notExists(create.selectOne().from(BOOK)

      - Note that in SQL, the projection of a subselect in an EXISTS predicate is irrelevant. To help you write queries like the above, you can use jOOQ's selectZero() or selectOne() methods + Note that in SQL, the projection of a subselect in an EXISTS predicate is irrelevant. To help you write queries like the above, you can use jOOQ's selectZero() or selectOne() methods

      Performance of IN vs. EXISTS

      @@ -4552,7 +4917,7 @@ notExists(create.selectOne().from(BOOK) OVERLAPS predicate

      - When comparing dates, the SQL standard allows for using a special OVERLAPS predicate, which checks whether two date ranges overlap each other. The following can be said: + When comparing dates, the SQL standard allows for using a special OVERLAPS predicate, which checks whether two date ranges overlap each other. The following can be said:

      The OVERLAPS predicate in jOOQ

      - jOOQ supports the OVERLAPS predicate on . The following methods are contained in : + jOOQ supports the OVERLAPS predicate on . The following methods are contained in :

      jOOQ's extensions to the standard

      - Unlike the standard (or any database implementing the standard), jOOQ also supports the OVERLAPS predicate for comparing arbitrary . For instance, (1, 3) OVERLAPS (2, 4) will yield true in jOOQ. This is simulated as such + Unlike the standard (or any database implementing the standard), jOOQ also supports the OVERLAPS predicate for comparing arbitrary . For instance, (1, 3) OVERLAPS (2, 4) will yield true in jOOQ. This is simulated as such

      fetch(String sql, Object... bindings); Result fetch(String sql, QueryPart... parts);]]>

      - Apart from the general factory methods, plain SQL is also available in various other contexts. For instance, when adding a .where("a = b") clause to a query. Hence, there exist several convenience methods where plain SQL can be inserted usefully. This is an example displaying all various use-cases in one single query: + Apart from the general factory methods, plain SQL is also available in various other contexts. For instance, when adding a .where("a = b") clause to a query. Hence, there exist several convenience methods where plain SQL can be inserted usefully. This is an example displaying all various use-cases in one single query:

      • - By using the and setting the to STATIC_STATEMENT. This will inline all bind values for SQL statements rendered from such a Factory. + By using the and setting the to STATIC_STATEMENT. This will inline all bind values for SQL statements rendered from such an Executor.
      • By using methods. @@ -4903,8 +5268,8 @@ create.select() Settings settings = new Settings() .withStatementType(StatementType.STATIC_STATEMENT); -// Add the settings to the factory -Factory create = new Factory(connection, SQLDialect.ORACLE, settings); +// Add the settings to the executor +Executor create = new Executor(connection, SQLDialect.ORACLE, settings); // Run queries that omit rendering schema names create.select() @@ -5027,7 +5392,7 @@ int peekIndex();]]>

        An example of rendering SQL

        - A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here: + A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here:

        -- [...] @@ -5036,7 +5401,7 @@ JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID -- [...]

        - This is how jOOQ renders such a condition: + This is how jOOQ renders such a condition (simplified example):

        @@ -5086,8 +5429,8 @@ public final void toSQL(RenderContext context) {

        - +

        And then, use the above factory to render pretty-printed SQL: @@ -5152,7 +5495,7 @@ BindContext bindValues(Object... values) throws DataAccessException;]]>

        An example of binding values to SQL

        - A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here: + A simple example can be provided by checking out jOOQ's internal representation of a (simplified) . It is used for any comparing two fields as for example the AUTHOR.ID = BOOK.AUTHOR_ID condition here:

        -- [...] @@ -5245,9 +5588,6 @@ create.select(IDx2).from(BOOK);]]>
      -
      -
      -
      Plain SQL QueryParts @@ -5281,7 +5621,7 @@ create.selectFrom(BOOK).where("BOOK.ID = {0} AND TITLE = {1}", id, title);]]>Serializability

      - The only transient, non-serializable element in any jOOQ object is the underlying . When you want to execute queries after de-serialisation, or when you want to store/refresh/delete , you will have to "re-attach" them to a Factory + The only transient, non-serializable element in any jOOQ object is the underlying . When you want to execute queries after de-serialisation, or when you want to store/refresh/delete , you will have to "re-attach" them to an Executor

      select = (Select) in.readObject(); select.execute(); // In order to execute the above select, attach it first -Factory create = new Factory(connection, SQLDialect.ORACLE); +Executor create = new Executor(connection, SQLDialect.ORACLE); create.attach(select);]]>

      Automatically attaching QueryParts

      @@ -5420,7 +5760,7 @@ trait SNumberField[T <: Number] extends SAnyField[T] { T_BOOK.TITLE || " abc" || " xy") from T_BOOK leftOuterJoin ( - f select (x.ID, x.YEAR_OF_BIRTH) + select (x.ID, x.YEAR_OF_BIRTH) from x limit 1 asTable x.getName() @@ -5653,7 +5993,7 @@ ResultSet fetchResultSet();]]> Record vs. TableRecord

      - jOOQ understands that SQL is much more expressive than Java, when it comes to the declarative typing of . As a declarative language, SQL allows for creating ad-hoc row value expressions (records with indexed columns) and records (records with named columns). In Java, this is not possible to the same extent. Yet, still, sometimes you wish to use strongly typed records, when you know that you're selecting only from a single table + jOOQ understands that SQL is much more expressive than Java, when it comes to the declarative typing of . As a declarative language, SQL allows for creating ad-hoc row value expressions (records with indexed columns, or tuples) and records (records with named columns). In Java, this is not possible to the same extent. Yet, still, sometimes you wish to use strongly typed records, when you know that you're selecting only from a single table

      Fetching strongly or weakly typed records

      @@ -5674,12 +6014,34 @@ System.out.println("Published in: " + book.getPublishedIn());]]>
      • -
      • -
      +
      + Record1 to Record{max-row-degree} + +

      + jOOQ's support has been explained earlier in this manual. It is useful for constructing row value expressions where they can be used in SQL. The same typesafety is also applied to records for degrees up to {max-row-degree}. To express this fact, is extended by to . Apart from the fact that these extensions of the R type can be used throughout the , they also provide a useful API. Here is , for instance: +

      + + extends Record { + + // Access fields and values as row value expressions + Row2 fieldsRow(); + Row2 valuesRow(); + + // Access fields by index + Field field1(); + Field field2(); + + // Access values by index + T1 value1(); + T2 value2(); +}]]> +
      +
      +
      Arrays, Maps and Lists @@ -5943,10 +6305,10 @@ create.executeUpdate(book);]]> If you're using jOOQ's , you can configure it to for you. Those DAOs operate on . An example of using such a DAO is given here:

      - without bind values, or a with (or without) bind values. But you have to decide early, which way to go. And you'll have to prevent SQL injection and syntax errors manually, when inlining your bind variables.

      - With jOOQ, this is easier. As a matter of fact, it is plain simple. With jOOQ, you can just set a flag in your , and all queries produced by that factory will be executed as static statements, with all bind values inlined. An example is given here: + With jOOQ, this is easier. As a matter of fact, it is plain simple. With jOOQ, you can just set a flag in your , and all queries produced by that executor will be executed as static statements, with all bind values inlined. An example is given here:

      @@ -6276,11 +6638,11 @@ for (BookRecord book : create.selectFrom(BOOK).fetch()) { -- These statements are rendered by the two factories: SELECT ? FROM DUAL WHERE ? = ? SELECT 1 FROM DUAL WHERE 1 = 1]]> -Standalone calls to sequences

      - Instead of actually phrasing a select statement, you can also use the convenience methods: + Instead of actually phrasing a select statement, you can also use the convenience methods:

      The above query will result in an XML document looking like the following one:

      - + @@ -6691,7 +7053,7 @@ Document xml = create.selectFrom(BOOK).fetch().intoXML();

      See the XSD schema definition here, for a formal definition of the XML export format:
      - http://www.jooq.org/xsd/jooq-export-1.6.2.xsd + http://www.jooq.org/xsd/jooq-export-{export-xsd-version}.xsd

      @@ -6834,7 +7196,7 @@ String text = create.selectFrom(BOOK).fetch().format(); With jOOQ, you can load this data using various parameters from the loader API. A simple load may look like this:

      -Factory create = new Factory(connection, dialect); +Executor create = new Executor(connection, dialect); // Load data into the AUTHOR table from an input stream // holding the CSV data. @@ -6963,19 +7325,6 @@ DELETE FROM BOOK WHERE ID = 5;]]>

      Normalised databases assume that a primary key is unique "forever", i.e. that a key, once inserted into a table, will never be changed or re-inserted after deletion. In order to use jOOQ's operations correctly, you should design your database accordingly.

      - -

      Main UNIQUE keys

      -

      - In SQL, a primary key is always also a unique key. In fact, unique keys have very similar properties as primary keys. For instance, they can be referenced from other tables' foreign keys in most databases. In the absence of a formal primary key, jOOQ assumes that the first unique key it encounters will serve as a primary key substitute. This is called the "main key" in jOOQ. In other words, a main key is: -

      -
        -
      • The primary key, if available
      • -
      • The first unique key, otherwise
      • -
      - -

      - For simplicity, the term "primary key" will be used in the sense of such a "main unique key" in this manual. -

      @@ -7062,14 +7411,14 @@ book.refresh();]]>

      CRUD and SELECT statements

      - CRUD operations can be combined with regular querying, if you select records from single database tables, as explained in the manual's section about . For this, you will need to use the selectFrom() method from the : + CRUD operations can be combined with regular querying, if you select records from single database tables, as explained in the manual's section about . For this, you will need to use the selectFrom() method from the :

      @@ -7163,7 +7512,7 @@ END my_trigger;]]> Navigation methods

      - When using jOOQ's along with its , generated records can have navigation methods contained in them, if properly . These navigation methods allow for "navigating" inbound or outbound foreign key references by executing an appropriate query. An example is given here: + and contain foreign key navigation methods. These navigation methods allow for "navigating" inbound or outbound foreign key references by executing an appropriate query. An example is given here:

      @@ -7177,39 +7526,14 @@ END my_trigger;]]> books = author.fetchBookList();]]> +List books = author.fetchChildren(FK_BOOK_AUTHOR);]]>

      - These methods are safe for use with several foreign keys referencing the same tables: -

      - - - - books = author.fetchBookListByAuthorId(); -List books = coAuthor.fetchBookListByCoAuthorId();]]> - - -

      - Note that, unlike in Hibernate, jOOQ's generated navigation methods will always lazy-fetch relevant records, without caching any results. In other words, every time you run such a fetch method, a new query will be issued. + Note that, unlike in Hibernate, jOOQ's navigation methods will always lazy-fetch relevant records, without caching any results. In other words, every time you run such a fetch method, a new query will be issued.

      These fetch methods only work on "attached" records. See the manual's section about for some more insight on "attached" objects. @@ -7221,7 +7545,7 @@ List books = coAuthor.fetchBookListByCoAuthorId();]]> Non-updatable records

      - Tables without UNIQUE keys are considered non-updatable by jOOQ, as jOOQ has no way of uniquely identifying such a record within the database. If you're using jOOQ's , such tables will generate classes, instead of classes. When you fetch from such a table, the returned records will not allow for calling any of the methods. + Tables without a PRIMARY KEY are considered non-updatable by jOOQ, as jOOQ has no way of uniquely identifying such a record within the database. If you're using jOOQ's , such tables will generate classes, instead of classes. When you fetch from such a table, the returned records will not allow for calling any of the methods.

      @@ -7247,8 +7571,8 @@ List books = coAuthor.fetchBookListByCoAuthorId();]]> The above changes to jOOQ's behaviour are transparent to the API, the only thing you need to do for it to be activated is to set the Settings flag. Here is an example illustrating optimistic locking:

      - The MODIFIED column will contain a timestamp indicating the last modification timestamp for any book in the BOOK table. If you're using jOOQ and it's , jOOQ will then generate this TIMESTAMP value for you, automatically. However, instead of running an additional statement prior to an UPDATE or DELETE statement, jOOQ adds a WHERE-clause to the UPDATE or DELETE statement, checking for TIMESTAMP's integrity. This can be best illustrated with an example:

      - { Note that you can further subtype those pre-generated DAO classes, to add more useful DAO methods to them. Using such a DAO is simple:

      - ExecuteListeners

      - The let you specify a list of classes. The ExecuteListener is essentially an event listener for Query, Routine, or ResultSet render, prepare, bind, execute, fetch steps. It is a base type for loggers, debuggers, profilers, data collectors, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods. + The lets you specify a list of instances. The ExecuteListener is essentially an event listener for Query, Routine, or ResultSet render, prepare, bind, execute, fetch steps. It is a base type for loggers, debuggers, profilers, data collectors, triggers, etc. Advanced ExecuteListeners can also provide custom implementations of Connection, PreparedStatement and ResultSet to jOOQ in apropriate methods.

      For convenience and better backwards-compatibility, consider extending instead of implementing this interface. @@ -7497,11 +7821,8 @@ public class StatisticsListener extends DefaultExecuteListener { Now, configure jOOQ's runtime to load your listener

      - - - com.example.StatisticsListener - -]]> +

      And log results any time with a snippet like this: @@ -7538,7 +7859,7 @@ for (ExecuteType type : ExecuteType.values()) {

        -
      • It takes some time to construct jOOQ queries. If you can reuse the same queries, you might cache them. Beware of thread-safety issues, though, as jOOQ's is not threadsafe, and queries are "attached" to their creating Factory
      • +
      • It takes some time to construct jOOQ queries. If you can reuse the same queries, you might cache them. Beware of thread-safety issues, though, as jOOQ's is not threadsafe, and queries are "attached" to their creating Executor
      • It takes some time to render SQL strings. Internally, jOOQ reuses the same for the complete query, but some rendering elements may take their time. You could, of course, cache SQL generated by jOOQ and prepare your own objects
      • It takes some time to bind values to prepared statements. jOOQ does not keep any open prepared statements, internally. Use a sophisticated connection pool, that will cache prepared statements and inject them into jOOQ through the standard JDBC API
      • It takes some time to fetch results. By default, jOOQ will always fetch the complete into memory. Use to prevent that, and scroll over an open underlying database cursor
      • @@ -7788,7 +8109,7 @@ Finishing : Total: 4.814ms, +3.375ms

        There are also lots of advanced configuration parameters, which will be treated in the Note, you can find the official XSD file for a formal specification at:
        - http://www.jooq.org/xsd/jooq-codegen-2.5.0.xsd + http://www.jooq.org/xsd/jooq-codegen-{codegen-xsd-version}.xsd

        Run jOOQ code generation

        @@ -8465,8 +8786,8 @@ public class Book implements java.io.Serializable super(BOOK, Book.class); } - public BookDao(Factory factory) { - super(BOOK, Book.class, factory); + public BookDao(Executor executor) { + super(BOOK, Book.class, executor); } // Every column generates at least one fetch method @@ -8734,22 +9055,11 @@ create.selectFrom(AUTHOR)

      - Both modes will require that you set the in the Factory's settings. When using XML settings: + Both modes will require that you set the in the Executor's configuration:

      - - - org.jooq.debug.impl.DebugListener - -]]> - -

      - Or when using programmatic settings: -

      - - +

      In-process mode

      @@ -9182,9 +9492,9 @@ for (Record record : create().select(

      • [N] in Row[N] has been raised from 8 to 22. This means that existing row value expressions with degree >= 9 are now type-safe
      • -
      • Subqueries returned from Factory.select(...) now implement Select<Record[N]>, not Select<Record>
      • -
      • IN predicates and comparison predicates taking subselects changed incompatibly
      • -
      • INSERT and MERGE statements now take typesafe VALUES() clauses
      • +
      • Subqueries returned from Factory.select(...) now implement Select<Record[N]>, not Select<Record>
      • +
      • IN predicates and comparison predicates taking subselects changed incompatibly
      • +
      • INSERT and MERGE statements now take typesafe VALUES() clauses

      @@ -9353,6 +9663,82 @@ Condition condition3 = BOOK.TITLE.isNotDistinctFrom(possiblyNull);]]>

      +