diff --git a/jOOQ-website/manual-pdf/jOOQ-manual.fo.xml b/jOOQ-website/manual-pdf/jOOQ-manual.fo.xml index e75e49c370..3ae05ba5ed 100644 --- a/jOOQ-website/manual-pdf/jOOQ-manual.fo.xml +++ b/jOOQ-website/manual-pdf/jOOQ-manual.fo.xml @@ -269,6 +269,22 @@ +Bind values + + + + + + + + + +9. + + + + + QueryParts and the global architecture @@ -279,7 +295,7 @@ -9. +10. @@ -295,7 +311,7 @@ -10. +11. @@ -1904,8 +1920,8 @@ d.execute(); The point of the standard MERGE statement is to take a TARGET table, and merge (INSERT, UPDATE) data from a SOURCE table into it. DB2, Oracle, SQL Server and Sybase also allow for DELETING some data and for adding - many additional clauses. Those non-standard extensions are currently - not supported. Here is an example: + many additional clauses. With jOOQ 2.0.1, only Oracle's MERGE extensions are supported. + Here is an example: @@ -1980,84 +1996,237 @@ WHEN NOT MATCHED THEN INSERT (LAST_NAME) sort of result. The ResultQuery provides many convenience methods -public interface ResultQuery<R extends Record> { + These methods allow for fetching a jOOQ Result or parts of it. + + fetch(); - // These methods allow for fetching a jOOQ Result - // or parts of it. - // ---------------------------------------------- +// Fetch a single field from the result + List fetch(Field field); + List fetch(int fieldIndex); + List fetch(int fieldIndex, Class type); + List fetch(String fieldName); + List fetch(String fieldName, Class type); - // Fetch the whole result - Result<R> fetch(); +// Fetch the first Record +R fetchAny(); - // Fetch a single field from the result - <T> List<T> fetch(Field<T> field); - List<?> fetch(int fieldIndex); - List<?> fetch(String fieldName); +// Fetch exactly one Record +R fetchOne(); - // Fetch the first Record - R fetchAny(); +// Fetch a single field of exactly one Record + T fetchOne(Field field); +Object fetchOne(int fieldIndex); + T fetchOne(int fieldIndex, Class type); +Object fetchOne(String fieldName); + T fetchOne(String fieldName, Class type);]]> - // Fetch exactly one Record - R fetchOne(); + These methods transform the result into another form, if org.jooq.Result is not optimal + +> fetchMaps(); + Map fetchOneMap(); - // Fetch a single field of exactly one Record - <T> T fetchOne(Field<T> field); - Object fetchOne(int fieldIndex); - Object fetchOne(String fieldName); +// Fetch the result as a Map + Map fetchMap(Field key); + Map fetchMap(Field key, Field value); - // These methods transform the result into another - // form, if org.jooq.Result is not optimal - // ----------------------------------------------- +// Fetch the resulting records as arrays +Object[][] fetchArrays(); +Object[] fetchOneArray(); - // Fetch the resulting records as Maps - List<Map<String, Object>> fetchMaps(); - Map<String, Object> fetchOneMap(); +// Fetch a single field as an array + T[] fetchArray(Field field); +Object[] fetchArray(int fieldIndex); + T[] fetchArray(int fieldIndex, Class type); +Object[] fetchArray(String fieldName); + T[] fetchArray(String fieldName, Class type);]]> - // Fetch the result as a Map - <K> Map<K, R> fetchMap(Field<K> key); - <K, V> Map<K, V> fetchMap(Field<K> key, Field<V> value); + These methods transform the result into a user-defined form, if org.jooq.Result is not optimal - // Fetch the resulting records as arrays - Object[][] fetchArrays(); - Object[] fetchOneArray(); + List fetchInto(Class type); - // Fetch a single field as an array - <T> T[] fetchArray(Field<T> field); - Object[] fetchArray(int fieldIndex); - Object[] fetchArray(String fieldName); +// Fetch the resulting records into a custom +// record handler, similar to how Spring JdbcTemplate's +// RowMapper or the Ollin Framework works. +> H fetchInto(H handler); - // These methods transform the result into a user- - // defined form, if org.jooq.Result is not optimal - // ----------------------------------------------- +// These change the behaviour of fetching itself, +// especially, when not all data should be +// fetched at once +// ---------------------------------------------- - // Fetch the resulting records into a custom POJO - // type, which may or may not be JPA-annotated - <E> List<E> fetchInto(Class<? extends E> type); +// Fetch a Cursor for lazy iteration +Cursor fetchLazy(); - // Fetch the resulting records into a custom - // record handler, similar to how Spring JdbcTemplate's - // RowMapper or the Ollin Framework works. - <H extends RecordHandler<R>> H fetchInto(H handler); +// Fetch data asynchronously and let client code +// decide, when the data must be available. +// This makes use of the java.util.concurrent API, +// Similar to how Avajé Ebean works. +FutureResult fetchLater(); +FutureResult fetchLater(ExecutorService executor);]]> + + +1.8. Bind values +1.8. Bind values + + Variable binding has a great impact on how you design your SQL queries. + It will influence your SQL queries' security aspect as well as execution speed. + + Bind values + + Bind values are used in SQL / JDBC for various reasons. Among the most + obvious ones are: + + + + + +- + + + + Protection against SQL injection. Instead of inlining values + possibly originating from user input, you bind those values to + your prepared statement and let the JDBC driver / database take + care of handling security aspects. + + + + + +- + + + + Increased speed. Advanced databases such as Oracle can keep + execution plans of similar queries in a dedicated cache to prevent + hard-parsing your query again and again. In many cases, the actual + value of a bind variable does not influence the execution plan, hence + it can be reused. Preparing a statement will thus be faster + + + + + +- + + + + On a JDBC level, you can also reuse the SQL string and prepared statement + object instead of constructing it again, as you can bind new values to + the prepared statement. This is currently not supported by jOOQ, though + + + + + + + Ways to introduce bind values with jOOQ + + Bind values are omni-present in jOOQ. Whenever you create a condition, + you're actually also adding a bind value: + +// In jOOQ, "Poe" will be the bind value bound to the condition +LAST_NAME.equal("Poe"); - // These change the behaviour of fetching itself, - // especially, when not all data should be - // fetched at once - // ---------------------------------------------- + + + The above notation is actually convenient way to explicitly create + a bind value for "Poe". You could also write this, instead: + +// The Factory allows for explicitly creating bind values +LAST_NAME.equal(Factory.val("Poe")); - // Fetch a Cursor for lazy iteration - Cursor<R> fetchLazy(); +// Or, when static importing Factory.val: +LAST_NAME.equal(val("Poe")) + + + Once created, bind values are part of the query's syntax tree (see + the manual's section about jOOQ's architecture + for more information about jOOQ's internals), + and cannot be modified directly anymore. If you wish to reuse a query and + modify bind values between subsequent query executions, you can access them again + through the org.jooq.Query interface: + + + param = query.getParam("1"); - // Fetch data asynchronously and let client code - // decide, when the data must be available. - // This makes use of the java.util.concurrent API, - // Similar to how Avajé Ebean works. - FutureResult<R> fetchLater(); - FutureResult<R> fetchLater(ExecutorService executor); -} +// You could now modify the Query's underlying bind value: +if ("Poe".equal(param.getValue())) { + param.setConverted("Orwell"); +}]]> + + + The org.jooq.Param type can also be named explicitly + using the Factory's param() methods: + + param1 = query.getParam("lastName"); + +// Or, keep a reference to the typed parameter in order not to lose the type information: +Param param2 = param("lastName", "Poe"); +Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param2)); + +// You can now change the bind value directly on the Param reference: +param2.setValue("Orwell"); +]]> + + + The org.jooq.Query interface also allows for + setting new bind values directly, without accessing the Param type: + + +Query query1 = create.select().from(T_AUTHOR).where(LAST_NAME.equal("Poe")); +query1.bind(1, "Orwell"); + +// Or, with named parameters +Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param("lastName", "Poe"))); +query2.bind("lastName", "Orwell"); + + + NOTE: Should you wish to use jOOQ only as a query builder and execute + queries with another tool, such as Spring Data instead, you can also + use the Factory's renderNamedParams() method, to actually render named + parameter names in generated SQL: + + + + + + + + + +-- The named bind variable can be rendered + +SELECT * +FROM T_AUTHOR +WHERE LAST_NAME = :lastName + + + + + +create.renderNamedParams( + create.select() + .from(T_AUTHOR) + .where(LAST_NAME.equal( + param("lastName", "Poe")))); + + + + + -1.8. QueryParts and the global architecture -1.8. QueryParts and the global architecture +1.9. QueryParts and the global architecture +1.9. QueryParts and the global architecture When constructing Query objects in jOOQ, everything is considered a QueryPart. The purpose of this quickly becomes clear when checking out the QueryPart API essentials @@ -2152,8 +2321,8 @@ public final void toSQL(RenderContext context) { For more complex examples, please refer to the codebase, directly -1.9. Serializability of QueryParts and Results -1.9. Serializability of QueryParts and Results +1.10. Serializability of QueryParts and Results +1.10. Serializability of QueryParts and Results Most of the jOOQ API implements the Serializable interface. This helps storing queries and partial queries in files, transferring queries or result data over TCP/IP, etc. @@ -2218,8 +2387,8 @@ ConfigurationRegistry.setProvider(provider); -1.10. Extend jOOQ with custom types -1.10. Extend jOOQ with custom types +1.11. Extend jOOQ with custom types +1.11. Extend jOOQ with custom types Maybe jOOQ is missing functionality that you would like to see, or you can't wait for the next release... In this case, you can extend any of the following open jOOQ implementation classes @@ -2380,6 +2549,7 @@ generator.database.input-schema=[your database schema / owner / name] #All elements that are generated from your schema (several Java regular expressions, separated by comma) #Watch out for case-sensitivity. Depending on your database, this might be important! +#You can create case-insensitive regular expressions using this syntax: (?i:expr) generator.database.includes=.* #All elements that are excluded from your schema (several Java regular expressions, separated by comma). Excludes match before includes diff --git a/jOOQ-website/manual-pdf/jOOQ-manual.pdf b/jOOQ-website/manual-pdf/jOOQ-manual.pdf index ec72f9a53c..b836ccb036 100644 Binary files a/jOOQ-website/manual-pdf/jOOQ-manual.pdf and b/jOOQ-website/manual-pdf/jOOQ-manual.pdf differ diff --git a/jOOQ-website/manual-single-page/index.php b/jOOQ-website/manual-single-page/index.php index b6cf3846df..32cdce2ae3 100644 --- a/jOOQ-website/manual-single-page/index.php +++ b/jOOQ-website/manual-single-page/index.php @@ -111,6 +111,9 @@ function printContent() { ResultQuery and various ways of fetching data
  • +Bind values +
  • +
  • QueryParts and the global architecture
  • @@ -1096,8 +1099,8 @@ d.execute(); The point of the standard MERGE statement is to take a TARGET table, and merge (INSERT, UPDATE) data from a SOURCE table into it. DB2, Oracle, SQL Server and Sybase also allow for DELETING some data and for adding - many additional clauses. Those non-standard extensions are currently - not supported. Here is an example: + many additional clauses. With jOOQ 2.0.1, only Oracle's MERGE extensions are supported. + Here is an example:

    @@ -1151,82 +1154,204 @@ WHEN NOT MATCHED THEN INSERT (LAST_NAME) sort of result.

    The ResultQuery provides many convenience methods

    -
    public interface ResultQuery<R extends Record> {
    +							

    These methods allow for fetching a jOOQ Result or parts of it.

    + +
    // Fetch the whole result
    +Result<R> fetch();
     
    -  // These methods allow for fetching a jOOQ Result
    -  // or parts of it.
    -  // ----------------------------------------------
    +// Fetch a single field from the result
    +<T> List<T> fetch(Field<T> field);
    +    List<?> fetch(int fieldIndex);
    +<T> List<T> fetch(int fieldIndex, Class<? extends T> type);
    +    List<?> fetch(String fieldName);
    +<T> List<T> fetch(String fieldName, Class<? extends T> type);
     
    -  // Fetch the whole result
    -  Result<R> fetch();
    +// Fetch the first Record
    +R fetchAny();
     
    -  // Fetch a single field from the result
    -  <T> List<T> fetch(Field<T> field);
    -      List<?> fetch(int fieldIndex);
    -      List<?> fetch(String fieldName);
    +// Fetch exactly one Record
    +R fetchOne();
     
    -  // Fetch the first Record
    -  R fetchAny();
    +// Fetch a single field of exactly one Record
    +<T> T  fetchOne(Field<T> field);
    +Object fetchOne(int fieldIndex);
    +<T> T  fetchOne(int fieldIndex, Class<? extends T> type);
    +Object fetchOne(String fieldName);
    +<T> T  fetchOne(String fieldName, Class<? extends T> type);
    - // Fetch exactly one Record - R fetchOne(); +

    These methods transform the result into another form, if org.jooq.Result is not optimal

    + +
    // Fetch the resulting records as Maps
    +List<Map<String, Object>> fetchMaps();
    +     Map<String, Object>  fetchOneMap();
     
    -  // Fetch a single field of exactly one Record
    -  <T> T  fetchOne(Field<T> field);
    -  Object fetchOne(int fieldIndex);
    -  Object fetchOne(String fieldName);
    +// Fetch the result as a Map
    +<K>    Map<K, R> fetchMap(Field<K> key);
    +<K, V> Map<K, V> fetchMap(Field<K> key, Field<V> value);
     
    -  // These methods transform the result into another
    -  // form, if org.jooq.Result is not optimal
    -  // -----------------------------------------------
    +// Fetch the resulting records as arrays
    +Object[][] fetchArrays();
    +Object[]   fetchOneArray();
     
    -  // Fetch the resulting records as Maps
    -  List<Map<String, Object>> fetchMaps();
    -  Map<String, Object> fetchOneMap();
    +// Fetch a single field as an array
    +<T>  T[] fetchArray(Field<T> field);
    +Object[] fetchArray(int fieldIndex);
    +<T>  T[] fetchArray(int fieldIndex, Class<? extends T> type);
    +Object[] fetchArray(String fieldName);
    +<T>  T[] fetchArray(String fieldName, Class<? extends T> type);
    - // Fetch the result as a Map - <K> Map<K, R> fetchMap(Field<K> key); - <K, V> Map<K, V> fetchMap(Field<K> key, Field<V> value); +

    These methods transform the result into a user-defined form, if org.jooq.Result is not optimal

    - // Fetch the resulting records as arrays - Object[][] fetchArrays(); - Object[] fetchOneArray(); +
    // Fetch the resulting records into a custom POJO
    +// type, which may or may not be JPA-annotated
    +<E> List<E> fetchInto(Class<? extends E> type);
     
    -  // Fetch a single field as an array
    -  <T> T[] fetchArray(Field<T> field);
    -  Object[] fetchArray(int fieldIndex);
    -  Object[] fetchArray(String fieldName);
    +// Fetch the resulting records into a custom
    +// record handler, similar to how Spring JdbcTemplate's
    +// RowMapper or the Ollin Framework works.
    +<H extends RecordHandler<R>> H fetchInto(H handler);
     
    -  // These methods transform the result into a user-
    -  // defined form, if org.jooq.Result is not optimal
    -  // -----------------------------------------------
    +// These change the behaviour of fetching itself,
    +// especially, when not all data should be
    +// fetched at once
    +// ----------------------------------------------
     
    -  // Fetch the resulting records into a custom POJO
    -  // type, which may or may not be JPA-annotated
    -  <E> List<E> fetchInto(Class<? extends E> type);
    +// Fetch a Cursor for lazy iteration
    +Cursor<R> fetchLazy();
     
    -  // Fetch the resulting records into a custom
    -  // record handler, similar to how Spring JdbcTemplate's
    -  // RowMapper or the Ollin Framework works.
    -  <H extends RecordHandler<R>> H fetchInto(H handler);
    +// Fetch data asynchronously and let client code
    +// decide, when the data must be available.
    +// This makes use of the java.util.concurrent API,
    +// Similar to how Avajé Ebean works.
    +FutureResult<R> fetchLater();
    +FutureResult<R> fetchLater(ExecutorService executor);
    +

    +1.8. Bind values

    + Variable binding has a great impact on how you design your SQL queries. + It will influence your SQL queries' security aspect as well as execution speed. +

    +

    Bind values

    +

    + Bind values are used in SQL / JDBC for various reasons. Among the most + obvious ones are: +

    +
      + +
    • + Protection against SQL injection. Instead of inlining values + possibly originating from user input, you bind those values to + your prepared statement and let the JDBC driver / database take + care of handling security aspects. +
    • + +
    • + Increased speed. Advanced databases such as Oracle can keep + execution plans of similar queries in a dedicated cache to prevent + hard-parsing your query again and again. In many cases, the actual + value of a bind variable does not influence the execution plan, hence + it can be reused. Preparing a statement will thus be faster +
    • + +
    • + On a JDBC level, you can also reuse the SQL string and prepared statement + object instead of constructing it again, as you can bind new values to + the prepared statement. This is currently not supported by jOOQ, though +
    • + +
    + +

    Ways to introduce bind values with jOOQ

    +

    + Bind values are omni-present in jOOQ. Whenever you create a condition, + you're actually also adding a bind value: +

    +
    // In jOOQ, "Poe" will be the bind value bound to the condition
    +LAST_NAME.equal("Poe");
    - // These change the behaviour of fetching itself, - // especially, when not all data should be - // fetched at once - // ---------------------------------------------- + +

    + The above notation is actually convenient way to explicitly create + a bind value for "Poe". You could also write this, instead: +

    +
    // The Factory allows for explicitly creating bind values
    +LAST_NAME.equal(Factory.val("Poe"));
     
    -  // Fetch a Cursor for lazy iteration
    -  Cursor<R> fetchLazy();
    +// Or, when static importing Factory.val:
    +LAST_NAME.equal(val("Poe"))
    + +

    + Once created, bind values are part of the query's syntax tree (see + the manual's section about jOOQ's architecture + for more information about jOOQ's internals), + and cannot be modified directly anymore. If you wish to reuse a query and + modify bind values between subsequent query executions, you can access them again + through the org.jooq.Query interface: +

    + +
    // Access the first bind value from a query. Indexes are counted from 1, just as with JDBC
    +Query query = create.select().from(T_AUTHOR).where(LAST_NAME.equal("Poe"));
    +Param<?> param = query.getParam("1");
     
    -  // Fetch data asynchronously and let client code
    -  // decide, when the data must be available.
    -  // This makes use of the java.util.concurrent API,
    -  // Similar to how Avajé Ebean works.
    -  FutureResult<R> fetchLater();
    -  FutureResult<R> fetchLater(ExecutorService executor);
    +// You could now modify the Query's underlying bind value:
    +if ("Poe".equal(param.getValue())) {
    +    param.setConverted("Orwell");
     }
    + +

    + The org.jooq.Param type can also be named explicitly + using the Factory's param() methods: +

    +
    // Create a query with a named parameter. You can then use that name for accessing the parameter again
    +Query query1 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param("lastName", "Poe")));
    +Param<?> param1 = query.getParam("lastName");
    +
    +// Or, keep a reference to the typed parameter in order not to lose the <T> type information:
    +Param<String> param2 = param("lastName", "Poe");
    +Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param2));
    +
    +// You can now change the bind value directly on the Param reference:
    +param2.setValue("Orwell");
    +
    + +

    + The org.jooq.Query interface also allows for + setting new bind values directly, without accessing the Param type: +

    + +
    Query query1 = create.select().from(T_AUTHOR).where(LAST_NAME.equal("Poe"));
    +query1.bind(1, "Orwell");
    +
    +// Or, with named parameters
    +Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param("lastName", "Poe")));
    +query2.bind("lastName", "Orwell");
    + +

    + NOTE: Should you wish to use jOOQ only as a query builder and execute + queries with another tool, such as Spring Data instead, you can also + use the Factory's renderNamedParams() method, to actually render named + parameter names in generated SQL: +

    + +
    + + + +
    +
    -- The named bind variable can be rendered
    +
    +SELECT *
    +FROM T_AUTHOR
    +WHERE LAST_NAME = :lastName
    +
    +
    +
    create.renderNamedParams(
    +    create.select()
    +          .from(T_AUTHOR)
    +          .where(LAST_NAME.equal(
    +                 param("lastName", "Poe"))));
    +

    -1.8. QueryParts and the global architecture

    When constructing Query objects in jOOQ, everything is +1.9. QueryParts and the global architecture

    When constructing Query objects in jOOQ, everything is considered a QueryPart. The purpose of this quickly becomes clear when checking out the QueryPart API essentials

    Everything is a QueryPart

    @@ -1306,7 +1431,7 @@ public final void toSQL(RenderContext context) {

    For more complex examples, please refer to the codebase, directly

    -1.9. Serializability of QueryParts and Results

    Most of the jOOQ API implements the Serializable interface. +1.10. Serializability of QueryParts and Results

    Most of the jOOQ API implements the Serializable interface. This helps storing queries and partial queries in files, transferring queries or result data over TCP/IP, etc.

    Attaching QueryParts

    @@ -1357,7 +1482,7 @@ ConfigurationRegistry.setProvider(provider);

    -1.10. Extend jOOQ with custom types

    Maybe jOOQ is missing functionality that you would like to see, +1.11. Extend jOOQ with custom types

    Maybe jOOQ is missing functionality that you would like to see, or you can't wait for the next release... In this case, you can extend any of the following open jOOQ implementation classes

    Write your own QueryPart implementations

    @@ -1497,6 +1622,7 @@ generator.database.input-schema=[your database schema / owner / name] #All elements that are generated from your schema (several Java regular expressions, separated by comma) #Watch out for case-sensitivity. Depending on your database, this might be important! +#You can create case-insensitive regular expressions using this syntax: (?i:expr) generator.database.includes=.* #All elements that are excluded from your schema (several Java regular expressions, separated by comma). Excludes match before includes diff --git a/jOOQ-website/manual/JOOQ/BindValues/index.php b/jOOQ-website/manual/JOOQ/BindValues/index.php new file mode 100644 index 0000000000..9fd645f8a6 --- /dev/null +++ b/jOOQ-website/manual/JOOQ/BindValues/index.php @@ -0,0 +1,154 @@ + + + + + + +
    The jOOQ User Manual : jOOQ classes and their usage : Bind valuesprevious : next
    +

    Bind values

    +

    + Bind values are used in SQL / JDBC for various reasons. Among the most + obvious ones are: +

    +
      + +
    • + Protection against SQL injection. Instead of inlining values + possibly originating from user input, you bind those values to + your prepared statement and let the JDBC driver / database take + care of handling security aspects. +
    • + +
    • + Increased speed. Advanced databases such as Oracle can keep + execution plans of similar queries in a dedicated cache to prevent + hard-parsing your query again and again. In many cases, the actual + value of a bind variable does not influence the execution plan, hence + it can be reused. Preparing a statement will thus be faster +
    • + +
    • + On a JDBC level, you can also reuse the SQL string and prepared statement + object instead of constructing it again, as you can bind new values to + the prepared statement. This is currently not supported by jOOQ, though +
    • + +
    + +

    Ways to introduce bind values with jOOQ

    +

    + Bind values are omni-present in jOOQ. Whenever you create a condition, + you're actually also adding a bind value: +

    +
    // In jOOQ, "Poe" will be the bind value bound to the condition
    +LAST_NAME.equal("Poe");
    + + +

    + The above notation is actually convenient way to explicitly create + a bind value for "Poe". You could also write this, instead: +

    +
    // The Factory allows for explicitly creating bind values
    +LAST_NAME.equal(Factory.val("Poe"));
    +
    +// Or, when static importing Factory.val:
    +LAST_NAME.equal(val("Poe"))
    + +

    + Once created, bind values are part of the query's syntax tree (see + the manual's section about jOOQ's architecture + for more information about jOOQ's internals), + and cannot be modified directly anymore. If you wish to reuse a query and + modify bind values between subsequent query executions, you can access them again + through the org.jooq.Query interface: +

    + +
    // Access the first bind value from a query. Indexes are counted from 1, just as with JDBC
    +Query query = create.select().from(T_AUTHOR).where(LAST_NAME.equal("Poe"));
    +Param<?> param = query.getParam("1");
    +
    +// You could now modify the Query's underlying bind value:
    +if ("Poe".equal(param.getValue())) {
    +    param.setConverted("Orwell");
    +}
    + +

    + The org.jooq.Param type can also be named explicitly + using the Factory's param() methods: +

    +
    // Create a query with a named parameter. You can then use that name for accessing the parameter again
    +Query query1 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param("lastName", "Poe")));
    +Param<?> param1 = query.getParam("lastName");
    +
    +// Or, keep a reference to the typed parameter in order not to lose the <T> type information:
    +Param<String> param2 = param("lastName", "Poe");
    +Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param2));
    +
    +// You can now change the bind value directly on the Param reference:
    +param2.setValue("Orwell");
    +
    + +

    + The org.jooq.Query interface also allows for + setting new bind values directly, without accessing the Param type: +

    + +
    Query query1 = create.select().from(T_AUTHOR).where(LAST_NAME.equal("Poe"));
    +query1.bind(1, "Orwell");
    +
    +// Or, with named parameters
    +Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param("lastName", "Poe")));
    +query2.bind("lastName", "Orwell");
    + +

    + NOTE: Should you wish to use jOOQ only as a query builder and execute + queries with another tool, such as Spring Data instead, you can also + use the Factory's renderNamedParams() method, to actually render named + parameter names in generated SQL: +

    + + + + + +
    +
    -- The named bind variable can be rendered
    +
    +SELECT *
    +FROM T_AUTHOR
    +WHERE LAST_NAME = :lastName
    +
    +
    +
    create.renderNamedParams(
    +    create.select()
    +          .from(T_AUTHOR)
    +          .where(LAST_NAME.equal(
    +                 param("lastName", "Poe"))));
    +
    +
    + + + +
    The jOOQ User Manual : jOOQ classes and their usage : Bind valuesprevious : next
    + + diff --git a/jOOQ-website/manual/JOOQ/Query/index.php b/jOOQ-website/manual/JOOQ/Query/index.php index 9cba4bc897..9a312306ad 100644 --- a/jOOQ-website/manual/JOOQ/Query/index.php +++ b/jOOQ-website/manual/JOOQ/Query/index.php @@ -387,8 +387,8 @@ d.execute(); The point of the standard MERGE statement is to take a TARGET table, and merge (INSERT, UPDATE) data from a SOURCE table into it. DB2, Oracle, SQL Server and Sybase also allow for DELETING some data and for adding - many additional clauses. Those non-standard extensions are currently - not supported. Here is an example: + many additional clauses. With jOOQ 2.0.1, only Oracle's MERGE extensions are supported. + Here is an example:

    diff --git a/jOOQ-website/manual/JOOQ/QueryPart/index.php b/jOOQ-website/manual/JOOQ/QueryPart/index.php index e961411dd3..b68ac07745 100644 --- a/jOOQ-website/manual/JOOQ/QueryPart/index.php +++ b/jOOQ-website/manual/JOOQ/QueryPart/index.php @@ -19,7 +19,7 @@ function printContent() { ?>
    - +
    The jOOQ User Manual : jOOQ classes and their usage : QueryParts and the global architectureprevious : nextThe jOOQ User Manual : jOOQ classes and their usage : QueryParts and the global architectureprevious : next

    Everything is a QueryPart

    @@ -100,7 +100,7 @@ public final void toSQL(RenderContext context) {

    For more complex examples, please refer to the codebase, directly


    - +
    The jOOQ User Manual : jOOQ classes and their usage : QueryParts and the global architectureprevious : nextThe jOOQ User Manual : jOOQ classes and their usage : QueryParts and the global architectureprevious : next
    - +
    The jOOQ User Manual : jOOQ classes and their usage : ResultQuery and various ways of fetching dataprevious : nextThe jOOQ User Manual : jOOQ classes and their usage : ResultQuery and various ways of fetching dataprevious : next

    The ResultQuery provides many convenience methods

    -
    public interface ResultQuery<R extends Record> {
    +							

    These methods allow for fetching a jOOQ Result or parts of it.

    + +
    // Fetch the whole result
    +Result<R> fetch();
     
    -  // These methods allow for fetching a jOOQ Result
    -  // or parts of it.
    -  // ----------------------------------------------
    +// Fetch a single field from the result
    +<T> List<T> fetch(Field<T> field);
    +    List<?> fetch(int fieldIndex);
    +<T> List<T> fetch(int fieldIndex, Class<? extends T> type);
    +    List<?> fetch(String fieldName);
    +<T> List<T> fetch(String fieldName, Class<? extends T> type);
     
    -  // Fetch the whole result
    -  Result<R> fetch();
    +// Fetch the first Record
    +R fetchAny();
     
    -  // Fetch a single field from the result
    -  <T> List<T> fetch(Field<T> field);
    -      List<?> fetch(int fieldIndex);
    -      List<?> fetch(String fieldName);
    +// Fetch exactly one Record
    +R fetchOne();
     
    -  // Fetch the first Record
    -  R fetchAny();
    +// Fetch a single field of exactly one Record
    +<T> T  fetchOne(Field<T> field);
    +Object fetchOne(int fieldIndex);
    +<T> T  fetchOne(int fieldIndex, Class<? extends T> type);
    +Object fetchOne(String fieldName);
    +<T> T  fetchOne(String fieldName, Class<? extends T> type);
    - // Fetch exactly one Record - R fetchOne(); +

    These methods transform the result into another form, if org.jooq.Result is not optimal

    + +
    // Fetch the resulting records as Maps
    +List<Map<String, Object>> fetchMaps();
    +     Map<String, Object>  fetchOneMap();
     
    -  // Fetch a single field of exactly one Record
    -  <T> T  fetchOne(Field<T> field);
    -  Object fetchOne(int fieldIndex);
    -  Object fetchOne(String fieldName);
    +// Fetch the result as a Map
    +<K>    Map<K, R> fetchMap(Field<K> key);
    +<K, V> Map<K, V> fetchMap(Field<K> key, Field<V> value);
     
    -  // These methods transform the result into another
    -  // form, if org.jooq.Result is not optimal
    -  // -----------------------------------------------
    +// Fetch the resulting records as arrays
    +Object[][] fetchArrays();
    +Object[]   fetchOneArray();
     
    -  // Fetch the resulting records as Maps
    -  List<Map<String, Object>> fetchMaps();
    -  Map<String, Object> fetchOneMap();
    +// Fetch a single field as an array
    +<T>  T[] fetchArray(Field<T> field);
    +Object[] fetchArray(int fieldIndex);
    +<T>  T[] fetchArray(int fieldIndex, Class<? extends T> type);
    +Object[] fetchArray(String fieldName);
    +<T>  T[] fetchArray(String fieldName, Class<? extends T> type);
    - // Fetch the result as a Map - <K> Map<K, R> fetchMap(Field<K> key); - <K, V> Map<K, V> fetchMap(Field<K> key, Field<V> value); +

    These methods transform the result into a user-defined form, if org.jooq.Result is not optimal

    - // Fetch the resulting records as arrays - Object[][] fetchArrays(); - Object[] fetchOneArray(); +
    // Fetch the resulting records into a custom POJO
    +// type, which may or may not be JPA-annotated
    +<E> List<E> fetchInto(Class<? extends E> type);
     
    -  // Fetch a single field as an array
    -  <T> T[] fetchArray(Field<T> field);
    -  Object[] fetchArray(int fieldIndex);
    -  Object[] fetchArray(String fieldName);
    +// Fetch the resulting records into a custom
    +// record handler, similar to how Spring JdbcTemplate's
    +// RowMapper or the Ollin Framework works.
    +<H extends RecordHandler<R>> H fetchInto(H handler);
     
    -  // These methods transform the result into a user-
    -  // defined form, if org.jooq.Result is not optimal
    -  // -----------------------------------------------
    +// These change the behaviour of fetching itself,
    +// especially, when not all data should be
    +// fetched at once
    +// ----------------------------------------------
     
    -  // Fetch the resulting records into a custom POJO
    -  // type, which may or may not be JPA-annotated
    -  <E> List<E> fetchInto(Class<? extends E> type);
    +// Fetch a Cursor for lazy iteration
    +Cursor<R> fetchLazy();
     
    -  // Fetch the resulting records into a custom
    -  // record handler, similar to how Spring JdbcTemplate's
    -  // RowMapper or the Ollin Framework works.
    -  <H extends RecordHandler<R>> H fetchInto(H handler);
    -
    -  // These change the behaviour of fetching itself,
    -  // especially, when not all data should be
    -  // fetched at once
    -  // ----------------------------------------------
    -
    -  // Fetch a Cursor for lazy iteration
    -  Cursor<R> fetchLazy();
    -
    -  // Fetch data asynchronously and let client code
    -  // decide, when the data must be available.
    -  // This makes use of the java.util.concurrent API,
    -  // Similar to how Avajé Ebean works.
    -  FutureResult<R> fetchLater();
    -  FutureResult<R> fetchLater(ExecutorService executor);
    -}
    +// Fetch data asynchronously and let client code +// decide, when the data must be available. +// This makes use of the java.util.concurrent API, +// Similar to how Avajé Ebean works. +FutureResult<R> fetchLater(); +FutureResult<R> fetchLater(ExecutorService executor);

    - +
    The jOOQ User Manual : jOOQ classes and their usage : ResultQuery and various ways of fetching dataprevious : nextThe jOOQ User Manual : jOOQ classes and their usage : ResultQuery and various ways of fetching dataprevious : next
    /manual/JOOQ/ResultQuery/">ResultQuery and various ways of fetching data
  • +Bind values +
  • +
  • QueryParts and the global architecture
  • diff --git a/jOOQ-website/manual/META/Configuration/index.php b/jOOQ-website/manual/META/Configuration/index.php index bea4c75084..94542faf16 100644 --- a/jOOQ-website/manual/META/Configuration/index.php +++ b/jOOQ-website/manual/META/Configuration/index.php @@ -94,6 +94,7 @@ generator.database.input-schema=[your database schema / owner / name] #All elements that are generated from your schema (several Java regular expressions, separated by comma) #Watch out for case-sensitivity. Depending on your database, this might be important! +#You can create case-insensitive regular expressions using this syntax: (?i:expr) generator.database.includes=.* #All elements that are excluded from your schema (several Java regular expressions, separated by comma). Excludes match before includes diff --git a/jOOQ-website/manual/index.php b/jOOQ-website/manual/index.php index 3c8cd35268..0e7f5aea31 100644 --- a/jOOQ-website/manual/index.php +++ b/jOOQ-website/manual/index.php @@ -117,6 +117,9 @@ function printContent() { ResultQuery and various ways of fetching data
  • +Bind values +
  • +
  • QueryParts and the global architecture
  • diff --git a/jOOQ-website/src/main/resources/manual.xml b/jOOQ-website/src/main/resources/manual.xml index 7651fff59b..f6412bd62f 100644 --- a/jOOQ-website/src/main/resources/manual.xml +++ b/jOOQ-website/src/main/resources/manual.xml @@ -900,8 +900,8 @@ d.execute(); The point of the standard MERGE statement is to take a TARGET table, and merge (INSERT, UPDATE) data from a SOURCE table into it. DB2, Oracle, SQL Server and Sybase also allow for DELETING some data and for adding - many additional clauses. Those non-standard extensions are currently - not supported. Here is an example: + many additional clauses. With jOOQ 2.0.1, only Oracle's MERGE extensions are supported. + Here is an example:

    @@ -951,80 +951,199 @@ WHEN NOT MATCHED THEN INSERT (LAST_NAME)

    The ResultQuery provides many convenience methods

    -public interface ResultQuery<R extends Record> { +

    These methods allow for fetching a jOOQ Result or parts of it.

    + + fetch(); - // These methods allow for fetching a jOOQ Result - // or parts of it. - // ---------------------------------------------- +// Fetch a single field from the result + List fetch(Field field); + List fetch(int fieldIndex); + List fetch(int fieldIndex, Class type); + List fetch(String fieldName); + List fetch(String fieldName, Class type); - // Fetch the whole result - Result<R> fetch(); +// Fetch the first Record +R fetchAny(); - // Fetch a single field from the result - <T> List<T> fetch(Field<T> field); - List<?> fetch(int fieldIndex); - List<?> fetch(String fieldName); +// Fetch exactly one Record +R fetchOne(); - // Fetch the first Record - R fetchAny(); +// Fetch a single field of exactly one Record + T fetchOne(Field field); +Object fetchOne(int fieldIndex); + T fetchOne(int fieldIndex, Class type); +Object fetchOne(String fieldName); + T fetchOne(String fieldName, Class type);]]> - // Fetch exactly one Record - R fetchOne(); +

    These methods transform the result into another form, if org.jooq.Result is not optimal

    + +> fetchMaps(); + Map fetchOneMap(); - // Fetch a single field of exactly one Record - <T> T fetchOne(Field<T> field); - Object fetchOne(int fieldIndex); - Object fetchOne(String fieldName); +// Fetch the result as a Map + Map fetchMap(Field key); + Map fetchMap(Field key, Field value); - // These methods transform the result into another - // form, if org.jooq.Result is not optimal - // ----------------------------------------------- +// Fetch the resulting records as arrays +Object[][] fetchArrays(); +Object[] fetchOneArray(); - // Fetch the resulting records as Maps - List<Map<String, Object>> fetchMaps(); - Map<String, Object> fetchOneMap(); +// Fetch a single field as an array + T[] fetchArray(Field field); +Object[] fetchArray(int fieldIndex); + T[] fetchArray(int fieldIndex, Class type); +Object[] fetchArray(String fieldName); + T[] fetchArray(String fieldName, Class type);]]> - // Fetch the result as a Map - <K> Map<K, R> fetchMap(Field<K> key); - <K, V> Map<K, V> fetchMap(Field<K> key, Field<V> value); +

    These methods transform the result into a user-defined form, if org.jooq.Result is not optimal

    - // Fetch the resulting records as arrays - Object[][] fetchArrays(); - Object[] fetchOneArray(); + List fetchInto(Class type); - // Fetch a single field as an array - <T> T[] fetchArray(Field<T> field); - Object[] fetchArray(int fieldIndex); - Object[] fetchArray(String fieldName); +// Fetch the resulting records into a custom +// record handler, similar to how Spring JdbcTemplate's +// RowMapper or the Ollin Framework works. +> H fetchInto(H handler); - // These methods transform the result into a user- - // defined form, if org.jooq.Result is not optimal - // ----------------------------------------------- +// These change the behaviour of fetching itself, +// especially, when not all data should be +// fetched at once +// ---------------------------------------------- - // Fetch the resulting records into a custom POJO - // type, which may or may not be JPA-annotated - <E> List<E> fetchInto(Class<? extends E> type); +// Fetch a Cursor for lazy iteration +Cursor fetchLazy(); - // Fetch the resulting records into a custom - // record handler, similar to how Spring JdbcTemplate's - // RowMapper or the Ollin Framework works. - <H extends RecordHandler<R>> H fetchInto(H handler); +// Fetch data asynchronously and let client code +// decide, when the data must be available. +// This makes use of the java.util.concurrent API, +// Similar to how Avajé Ebean works. +FutureResult fetchLater(); +FutureResult fetchLater(ExecutorService executor);]]> +
    + + + +
    + Bind values + + Variable binding has a great impact on how you design your SQL queries. + It will influence your SQL queries' security aspect as well as execution speed. + + +

    Bind values

    +

    + Bind values are used in SQL / JDBC for various reasons. Among the most + obvious ones are: +

    +
      +
    • + Protection against SQL injection. Instead of inlining values + possibly originating from user input, you bind those values to + your prepared statement and let the JDBC driver / database take + care of handling security aspects. +
    • +
    • + Increased speed. Advanced databases such as Oracle can keep + execution plans of similar queries in a dedicated cache to prevent + hard-parsing your query again and again. In many cases, the actual + value of a bind variable does not influence the execution plan, hence + it can be reused. Preparing a statement will thus be faster +
    • +
    • + On a JDBC level, you can also reuse the SQL string and prepared statement + object instead of constructing it again, as you can bind new values to + the prepared statement. This is currently not supported by jOOQ, though +
    • +
    + +

    Ways to introduce bind values with jOOQ

    +

    + Bind values are omni-present in jOOQ. Whenever you create a condition, + you're actually also adding a bind value: +

    +// In jOOQ, "Poe" will be the bind value bound to the condition +LAST_NAME.equal("Poe"); - // These change the behaviour of fetching itself, - // especially, when not all data should be - // fetched at once - // ---------------------------------------------- + +

    + The above notation is actually convenient way to explicitly create + a bind value for "Poe". You could also write this, instead: +

    +// The Factory allows for explicitly creating bind values +LAST_NAME.equal(Factory.val("Poe")); - // Fetch a Cursor for lazy iteration - Cursor<R> fetchLazy(); +// Or, when static importing Factory.val: +LAST_NAME.equal(val("Poe")) + +

    + Once created, bind values are part of the query's syntax tree (see + + for more information about jOOQ's internals), + and cannot be modified directly anymore. If you wish to reuse a query and + modify bind values between subsequent query executions, you can access them again + through the interface: +

    + + param = query.getParam("1"); - // Fetch data asynchronously and let client code - // decide, when the data must be available. - // This makes use of the java.util.concurrent API, - // Similar to how Avajé Ebean works. - FutureResult<R> fetchLater(); - FutureResult<R> fetchLater(ExecutorService executor); -} +// You could now modify the Query's underlying bind value: +if ("Poe".equal(param.getValue())) { + param.setConverted("Orwell"); +}]]> + +

    + The type can also be named explicitly + using the Factory's param() methods: +

    + param1 = query.getParam("lastName"); + +// Or, keep a reference to the typed parameter in order not to lose the type information: +Param param2 = param("lastName", "Poe"); +Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param2)); + +// You can now change the bind value directly on the Param reference: +param2.setValue("Orwell"); +]]> + +

    + The interface also allows for + setting new bind values directly, without accessing the Param type: +

    + +Query query1 = create.select().from(T_AUTHOR).where(LAST_NAME.equal("Poe")); +query1.bind(1, "Orwell"); + +// Or, with named parameters +Query query2 = create.select().from(T_AUTHOR).where(LAST_NAME.equal(param("lastName", "Poe"))); +query2.bind("lastName", "Orwell"); + +

    + NOTE: Should you wish to use jOOQ only as a query builder and execute + queries with another tool, such as Spring Data instead, you can also + use the Factory's renderNamedParams() method, to actually render named + parameter names in generated SQL: +

    + + +create.renderNamedParams( + create.select() + .from(T_AUTHOR) + .where(LAST_NAME.equal( + param("lastName", "Poe")))); +-- The named bind variable can be rendered + +SELECT * +FROM T_AUTHOR +WHERE LAST_NAME = :lastName + +