From 14419422008cc1ba42dea5ef90e6fb2762633064 Mon Sep 17 00:00:00 2001 From: Christopher Baines Date: Wed, 4 Sep 2019 12:52:12 +0200 Subject: Hack better NULL support on to (squee) PQgetvalue used by squee returns null values as empty strings, which are ambiguous for string fields. Therefore, use PQgetisnull to implement a serialiser for squee which checks empty strings to see if they're actually a NULL value, then returns '() in this case. exec-query-with-null-handling can be used to access this behaviour. --- guix-data-service/database.scm | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/guix-data-service/database.scm b/guix-data-service/database.scm index 140ea44..0d6d61b 100644 --- a/guix-data-service/database.scm +++ b/guix-data-service/database.scm @@ -16,12 +16,15 @@ ;;; . (define-module (guix-data-service database) + #:use-module (system foreign) #:use-module (squee) #:export (with-postgresql-connection with-postgresql-transaction with-advisory-session-lock - obtain-advisory-transaction-lock)) + obtain-advisory-transaction-lock + + exec-query-with-null-handling)) ;; TODO This isn't exported for some reason (define pg-conn-finish @@ -80,3 +83,36 @@ (exec-query conn "SELECT pg_advisory_xact_lock($1)" (list lock-number)))) + +(define squee/libpq + (@@ (squee) libpq)) + +(define squee/unwrap-result-ptr + (@@ (squee) unwrap-result-ptr)) + +(define %PQgetisnull + (pointer->procedure int + (dynamic-func "PQgetisnull" squee/libpq) + (list '* int int))) + +(define (result-serializer-simple-list-with-null-handling result-ptr) + "Get a simple list of lists representing the result of the query" + (let ((rows-range (iota (result-num-rows result-ptr))) + (cols-range (iota (result-num-cols result-ptr)))) + (map + (lambda (row-i) + (map + (lambda (col-i) + (let ((val (result-get-value result-ptr row-i col-i))) + (if (string-null? val) + (if (eq? 1 (%PQgetisnull + (squee/unwrap-result-ptr result-ptr) row-i col-i)) + '() + val) + val))) + cols-range)) + rows-range))) + +(define* (exec-query-with-null-handling pg-conn command #:optional (params '())) + (exec-query pg-conn command params + #:serializer result-serializer-simple-list-with-null-handling)) -- cgit v1.2.3