On Ignition 7.8 with SQL Server 2014 and Java 8u65, system.db.runPrepUpdate(qry, [v], getKey=1) inserts the row but never returns the identity value. The script then dies with SQLServerException: A result set was generated for update. The failure is in the JDBC key-retrieval path on the gateway, not in the SQL. The fix that holds is to have SQL Server return the key as an ordinary result set, through a stored procedure or an OUTPUT INSERTED clause. Once you do that, Ignition no longer depends on the driver's generated-keys handling.
Where does the getKey request stop between the button and SQL Server?
Follow the exception chain from the outside in. Each wrapper names the hop that passed the failure along.
| Hop | Component | Evidence in the trace | Outcome |
|---|---|---|---|
| 1 | Vision client, button actionPerformed script |
File "event:actionPerformed", line 3 |
Call dispatched to the gateway |
| 2 | Gateway database service | GatewayException: SQL error for "INSERT INTO TEMP (name) Values (?)" |
Statement handed to the JDBC driver with getKey = true
|
| 3 | SQL Server JDBC driver running in the gateway JVM | SQLServerException: A result set was generated for update. |
Request stops here |
| 4 | SQL Server 2014 | Row present in temp
|
INSERT committed |
The call signature in the trace, (INSERT INTO TEMP (name) Values (?), [I was here], , true, false), reads as query, arguments, database (blank, so the project default connection), getKey, and skipAudit. The client JRE plays no part. The statement runs on the gateway, so the gateway's JRE and driver jar decide the outcome.
Why does the driver report "A result set was generated for update"?
With getKey set, Ignition prepares the statement with the JDBC generated-keys flag, calls executeUpdate(), and then asks the driver for getGeneratedKeys(). SQL Server has no native generated-keys protocol. The driver handles it by appending an identity select, , to the batch and then walking the result stream. It expects an update count first and the key row after that.
executeUpdate() requires the first result to be an update count. If a result set arrives first, the driver throws this exception. The INSERT has already executed on the server by then, which is why the row appears while the key is lost. The usual things that push a result set ahead of the update count are:
- An INSERT trigger on the table that runs a
SELECTwithoutSET NOCOUNT ON. - A driver whose generated-keys handling does not match what the server returns.
- A driver jar or JRE state on the gateway that differs from the one that worked earlier.
Here the table has no trigger, and the fault came and went with the Java runtime state. A Java update had partially deleted files in the 8.0.65 folder. Letting that update finish cleared the error, and then the error came back after a gateway restart with no further Java update. That intermittent pattern points to the driver/JVM layer, not to the schema.
What should you check on the gateway and in the database first?
| Check | Where to read it | What it decides |
|---|---|---|
| Triggers on the target table | Whether a trigger result set explains the error. Also whether OUTPUT needs an INTO target. |
|
| JRE the gateway actually runs | Gateway web page, Status section; gateway startup log | Whether the gateway picked up a different or half-updated Java install |
| Java auto-updater activity | Java install folder timestamps; OS update/task history | Whether an updater changed files under the running gateway |
| JDBC driver and connection | Gateway Configure → Databases → Drivers and Connections | Which driver jar and connect properties serve this datasource |
| Gateway log at the failure time | Gateway Console / wrapper log | The full SQLServerException stack, confirming the throw site |
If a trigger returns rows, add SET NOCOUNT ON and remove the stray SELECT. If no trigger exists, as in this case, stop working the schema and move key retrieval out of the driver.
Which key-retrieval approach holds up: driver keys, string query, or SQL-side return?
| Approach | Uses driver generated-keys path | Schema change | Field result | Risk |
|---|---|---|---|---|
Repair or finish the gateway Java update, keep runPrepUpdate(getKey=1)
|
Yes | None | Cleared the fault temporarily, then it returned | Recurs with any JVM/driver drift |
system.db.runUpdateQuery with getKey, query built as a string |
Yes | None | Suggested, not tested | Same key path; string-built SQL opens injection and quoting problems |
| Stored procedure that inserts and returns the key | No | One procedure | Working replacement | Low |
INSERT ... OUTPUT INSERTED.id via runPrepQuery
|
No | None | Same mechanism as the procedure | Needs OUTPUT INTO if the table has enabled triggers |
Return the key as a result set. Use the stored procedure where you own the database. Use the OUTPUT clause where you cannot add objects. Both go through executeQuery(), where a result set is the expected answer, so the exception cannot occur.
How do you move key retrieval into a stored procedure or OUTPUT clause?
- Create the procedure.
SET NOCOUNT ONsuppresses the INSERT's row-count message, so the key row is the first result the driver sees: - Grant
EXECUTEondbo.InsertTempto the login used by the Ignition database connection. - Replace the button script. Call the procedure with a query function, not an update function:
v = 'I was here' ds = system.db.runPrepQuery('EXEC dbo.InsertTemp ?', [v]) newId = ds[0][0] print newId - Alternatively, skip the procedure and use the
OUTPUTclause directly:qry = 'INSERT INTO dbo.temp (name) OUTPUT INSERTED.id VALUES (?)' ds = system.db.runPrepQuery(qry, ['I was here']) newId = ds[0][0] - If
sys.triggersshows an enabled trigger on the table, SQL Server rejectsOUTPUTwithoutINTO. In that case use the procedure form with , or output into a table variable and select from it.
Two pitfalls come up repeatedly with this pattern:
- A batch like sent through
runPrepQuerywithoutSET NOCOUNT ONreturns the update count first. The driver then reports that the statement did not return a result set, which is the mirror image of the original error. -
@@IDENTITYpicks up identities generated by triggers in other tables. Use orOUTPUT.
How do you prove the key path survives restarts and Java updates?
- Run the new call from the Designer Script Console and confirm
newIdprints an integer. - In SQL Server Management Studio, run
SELECT TOP 1 id, name FROM dbo.temp ORDER BY id DESCand confirm the id matches the printed value and that exactly one row was added. - Fire the button several times in a row from a Vision client. Confirm the returned ids increment with no gaps caused by failed calls, and that the gateway log shows no
SQLServerException. - Disable the Java auto-updater on the gateway host so the runtime cannot change under a running gateway. Schedule JRE changes as maintenance with a gateway restart afterward.
- Restart the gateway, repeat steps 1-3, and confirm the returned id still matches the newest row in
dbo.temp.
FAQ
How do I get the identity value from an insert in Ignition without getKey?
Call system.db.runPrepQuery with INSERT ... OUTPUT INSERTED.id VALUES (?), or with EXEC on a stored procedure that ends in , and read ds[0][0]. This returns the key as a normal result set and bypasses the JDBC generated-keys path.
Why does the insert succeed even though runPrepUpdate throws an exception?
SQL Server executes and commits the INSERT before the driver parses the results. The exception is raised afterward, when executeUpdate() finds a result set where it expected an update count. You end up with a committed row and no key.
How do I tell if a trigger is causing 'A result set was generated for update'?
Query sys.triggers for the table's . If an enabled trigger contains a SELECT without SET NOCOUNT ON, its row set reaches the driver first and triggers the error. With no triggers present, look at the gateway JRE and JDBC driver instead.
How do I stop Java updates from breaking the Ignition gateway database calls?
Disable the Java auto-updater on the gateway host and apply JRE changes only during a maintenance window, followed by a gateway restart. A partially completed update that deletes files in the active JRE folder can change driver behavior while the gateway is running.