From 115fe1507dcabe7d94fb60af7c8297f69fbb9911 Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Fri, 29 Sep 2023 09:59:47 -0700 Subject: [PATCH] more doc updates about returning keys --- doc/all-the-options.md | 3 ++- doc/friendly-sql-functions.md | 8 +++++++- doc/prepared-statements.md | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/all-the-options.md b/doc/all-the-options.md index f664dca..e1bea43 100644 --- a/doc/all-the-options.md +++ b/doc/all-the-options.md @@ -91,6 +91,7 @@ Any function that creates a `PreparedStatement` will additionally accept the fol * `:return-keys` -- a truthy value asks that the JDBC driver to return any generated keys created by the operation; it can be `true` or it can be a vector of keywords identifying column names that should be returned. Not all databases or drivers support all of these options, or all values for any given option. If `:return-keys` is a vector of column names and that is not supported, `next.jdbc` will attempt a generic "return generated keys" option instead. If that is not supported, `next.jdbc` will fall back to a regular SQL operation. If other options are not supported, you may get a `SQLException`. +You may need to use `RETURNING *` on `INSERT` statements instead of using `:return-keys` with some database drivers. > Note: If `plan`, `execute!`, or `execute-one!` are passed a `DataSource`, a "db spec" hash map, or a JDBC URL string, they will call `prepare` to create a `PreparedStatement`, so they will accept the above options in those cases. @@ -98,7 +99,7 @@ In addition to the above, `next.jdbc/execute-batch!` (which may create a `Prepar * `:batch-size` -- an integer that determines how to partition the parameter groups for submitting to the database in batches, * `:large` -- a Boolean flag that indicates whether the batch will produce large update counts (`long` rather than `int` values), -* `:return-generated-keys` -- a Boolean flag that indicates whether `.getGeneratedKeys` should be called on the `PreparedStatement` after each batch is executed (if `true`, `execute-batch!` will return a vector of hash maps containing generated keys). +* `:return-generated-keys` -- a Boolean flag that indicates whether `.getGeneratedKeys` should be called on the `PreparedStatement` after each batch is executed (if `true`, `execute-batch!` will return a vector of hash maps containing generated keys). Some databases do not support this and you need to use `RETURNING *` on `INSERT` statements instead. ## Transactions diff --git a/doc/friendly-sql-functions.md b/doc/friendly-sql-functions.md index 00fdcb1..2d69757 100644 --- a/doc/friendly-sql-functions.md +++ b/doc/friendly-sql-functions.md @@ -34,6 +34,12 @@ Given a table name (as a keyword) and a hash map of column names and values, thi ;; equivalent to (jdbc/execute-one! ds ["INSERT INTO address (name,email) VALUES (?,?)" "A.Person" "albert@person.org"] {:return-keys true}) +;; some databases may require this instead +(jdbc/execute-one! ds ["INSERT INTO address (name,email) VALUES (?,?) RETURNING *" + "A.Person" "albert@person.org"]) +;; which you can achieve with the :suffix option +(sql/insert! ds :address {:name "A. Person" :email "albert@person.org"} + {:suffix "RETURNING *"}) ``` ## `insert-multi!` @@ -109,7 +115,7 @@ will use `execute-batch!` under the hood, instead of `execute!`, as follows: {:return-keys true :return-generated-keys true}) ``` -See [**Batched Parameters**](https://cljdoc.org/d/com.github.seancorfield/next.jdbc/CURRENT/doc/getting-started/prepared-statements#caveats) for caveats and possible database-specific behaviors. +> Note: not all databases or drivers support returning generated keys like this -- see [**Batched Parameters**](https://cljdoc.org/d/com.github.seancorfield/next.jdbc/CURRENT/doc/getting-started/prepared-statements#caveats) for caveats and possible database-specific behaviors. You may need `RETURNING *` in your SQL instead. ## `query` diff --git a/doc/prepared-statements.md b/doc/prepared-statements.md index da86b56..f42a141 100644 --- a/doc/prepared-statements.md +++ b/doc/prepared-statements.md @@ -133,7 +133,7 @@ If you want to get the generated keys from an `insert` done via `execute-batch!` This calls `rs/datafiable-result-set` behind the scenes so you can also pass a `:builder-fn` option to `execute-batch!` if you want something other than qualified as-is hash maps. -> Note: not all databases support calling `.getGeneratedKeys` here (everything I test against seems to, except MS SQL Server). Some databases will only return one generated key per batch, rather than a generated key for every row inserted. +> Note: not all databases support calling `.getGeneratedKeys` here (everything I test against seems to, except MS SQL Server and SQLite). Some databases will only return one generated key per batch, rather than a generated key for every row inserted. You may need to add `RETURNING *` to your `INSERT` statements instead. ### Caveats @@ -141,4 +141,4 @@ There are several caveats around using batched parameters. Some JDBC drivers nee In addition, if the batch operation fails for a group of parameters, it is database-specific whether the remaining groups of parameters are used, i.e., whether the operation is performed for any further groups of parameters after the one that failed. The result of calling `execute-batch!` is a vector of integers. Each element of the vector is the number of rows affected by the operation for each group of parameters. `execute-batch!` may throw a `BatchUpdateException` and calling `.getUpdateCounts` (or `.getLargeUpdateCounts`) on the exception may return an array containing a mix of update counts and error values (a Java `int[]` or `long[]`). Some databases don't always return an update count but instead a value indicating the number of rows is not known (but sometimes you can still get the update counts). -Finally, some database drivers don't do batched operations at all -- they accept `.executeBatch` but they run the operation as separate commands for the database rather than a single batched command. +Finally, some database drivers don't do batched operations at all -- they accept `.executeBatch` but they run the operation as separate commands for the database rather than a single batched command. Some database drivers do not support `.getGeneratedKeys` (e.g., MS SQL Server and SQLite) so you cannot use `:return-generated-keys` and you need to use `RETURNING *` in your `INSERT` statements instead.