From 1481f3e8d92e6ae9abf55ed5543243a84c63c6e1 Mon Sep 17 00:00:00 2001 From: Ryan Culpepper Date: Fri, 26 Apr 2019 13:33:35 +0200 Subject: [PATCH] sqlite3: fix reporting of insert-id --- .../db/private/sqlite3/connection.rkt | 23 +++++++++++++------ .../collects/db/private/sqlite3/dbsystem.rkt | 4 +++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/racket/collects/db/private/sqlite3/connection.rkt b/racket/collects/db/private/sqlite3/connection.rkt index 3caca40f19..a2a44965bb 100644 --- a/racket/collects/db/private/sqlite3/connection.rkt +++ b/racket/collects/db/private/sqlite3/connection.rkt @@ -117,17 +117,26 @@ (cursor-result info pst (box #f))] [else (simple-result - (let ([last-insert-rowid (A (sqlite3_last_insert_rowid db))] - [total-changes (A (sqlite3_total_changes db))]) + (let ([last-insert-rowid (A (sqlite3_last_insert_rowid db))]) ;; Not all statements clear last_insert_rowid, changes; so ;; extra guards to make sure results are relevant. + (define changes? (> (A (sqlite3_total_changes db)) saved-total-changes)) `((insert-id - . ,(and (not (= last-insert-rowid saved-last-insert-rowid)) + ;; We want to report insert-id if statement was a *successful* INSERT, + ;; but we can't check that directly. Instead, check if either + ;; - last_insert_rowid changed (but this check might fail, if the inserted + ;; row happens to have the same rowid was the last INSERT; for example, + ;; because the last INSERT was to a different table); or + ;; - the statement looked like an INSERT and the db reports changes + ;; (but this check misses WITH...INSERT statements). + ;; Note that we can't use the errno approach of setting last_insert_rowid + ;; to a known unused value, because there are no unused values (if an + ;; INTEGER PRIMARY KEY field exists, that is the rowid) and because the + ;; last_insert_rowid is visible to SQL statements. + . ,(and (or (not (= last-insert-rowid saved-last-insert-rowid)) + (and changes? (eq? (send pst get-stmt-type) 'insert))) last-insert-rowid)) - (affected-rows - . ,(if (> total-changes saved-total-changes) - (A (sqlite3_changes db)) - 0)))))]))))) + (affected-rows . ,(if changes? (A (sqlite3_changes db)) 0)))))]))))) (define/public (fetch/cursor fsym cursor fetch-size) (let ([pst (cursor-result-pst cursor)] diff --git a/racket/collects/db/private/sqlite3/dbsystem.rkt b/racket/collects/db/private/sqlite3/dbsystem.rkt index 1b7833999a..6d099a6074 100644 --- a/racket/collects/db/private/sqlite3/dbsystem.rkt +++ b/racket/collects/db/private/sqlite3/dbsystem.rkt @@ -42,7 +42,9 @@ ;; ======================================== ;; SQL "parsing" -;; We just care about detecting commands that affect transaction status. +;; We mainly care about detecting commands that affect transaction status. +;; We also want to detect INSERT statements to report 'insert-id (see query1 +;; in connection%). ;; classify-sl-sql : string [nat] -> symbol/#f (define classify-sl-sql