SQLite User Forum

Tcl Interface: allow a function to return NULL?
Login

Tcl Interface: allow a function to return NULL?

(1.2) By chwchw on 2023-04-05 05:26:07 edited from 1.1 [source]

Is it feasible to enhance the Tcl Interface for allowing a Tcl coded SQL function to report an SQL NULL value, e.g. by interpreting the result TCL_BREAK of the Tcl code performing a return -code break to call sqlite_result_null() instead of one of the other sqlite_result_*() functions which yield a typed non NULL result?

Proposed change:

--- tclsqlite3.c.orig
+++ tclsqlite3.c
@@ -1026,7 +1026,9 @@
     Tcl_DecrRefCount(pCmd);
   }
 
-  if( rc && rc!=TCL_RETURN ){
+  if( rc==TCL_BREAK ){
+    sqlite3_result_null(context);
+  }else if( rc && rc!=TCL_RETURN ){
     sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
   }else{
     Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);

(2.1) By Warren Young (wyoung) on 2023-04-05 06:23:55 edited from 2.0 in reply to 1.2 [link] [source]

Deleted

(3) By Donal Fellows (dkfellows) on 2023-04-05 08:32:46 in reply to 1.2 [link] [source]

Logically, that would be reasonable; Tcl doesn't have a native NULL equivalent (it's not a value at all in Tcl's value logic; the closest you get is an absence of a value, which is a variable or dictionary entry that doesn't exist).

(4) By chwchw on 2023-04-05 08:56:26 in reply to 3 [link] [source]

The reason I'm asking and proposing this is that I've came up with a similar solution in my Tcl binding for http://www.open62541.org which uses the special break return code in order to signal errors or exceptions in method calls back to the caller but still can deal with normal runtime errors in the method's implementation locally using for example the background error mechanism.

(5) By Stephan Beal (stephan) on 2025-05-05 16:50:14 in reply to 1.2 [link] [source]

Is it feasible to enhance the Tcl Interface for allowing a Tcl coded SQL function to report an SQL NULL value, e.g. by interpreting the result TCL_BREAK of the Tcl code performing a return -code break ...

With my apologies for the extreme delay on this: that is now checked into a branch and is due to be merged to trunk after the pending 3.50 release.

Your unrelated suggestion in /forumpost/dce85c5ab9f0bc10 is also targeted for 3.51 but is not yet implemented (re-implemented - we have to reimplement it for licensing reasons but will use yours as a blueprint for the feature).

(6) By anonymous on 2025-10-15 22:18:49 in reply to 1.2 [link] [source]

I agree that allowing Tcl-coded SQL functions to return NULL values would be a useful feature, as it would provide more flexibility in handling missing data.

(7) By Stephan Beal (stephan) on 2025-10-15 22:30:46 in reply to 6 [link] [source]

I agree that allowing Tcl-coded SQL functions to return NULL values would be a useful feature

There is no uniform representation of NULL in Tcl. What you can do, as of 3.51, is "return -code break" in place of returning NULL. The end result is still not a NULL, though - it's a string value configured to stand in for Tcl's non-existing NULL.

As relevant snippet from test/tclsqlite.test:

proc breakAsNullUdf args {
  if {"1" eq [lindex $args 0]} {return -code break}
}
do_test tcl-9.4 {
  db function banu breakAsNullUdf
  execsql {SELECT typeof(banu()), typeof(banu(1))}
} {text null}
do_test tcl-9.5 {
  db nullvalue banunull
  db eval {SELECT banu(), banu(1)}
} {{} banunull}

(8) By Donal Fellows (dkfellows) on 2025-10-17 15:44:24 in reply to 7 [link] [source]

There is no uniform representation of NULL in Tcl.

There is; it's the absent key or unset variable. It's the thing that doesn't exist. TDBC strongly recommends mapping NULL that way.

(9) By Stephan Beal (stephan) on 2025-10-18 00:23:20 in reply to 8 [link] [source]

There is; it's the absent key or unset variable. It's the thing that doesn't exist.

Fair enough. The -withoutnulls option already exists for the array/dict cases, leaving the affected keys unset. UDFs, however, don't set anything - they return a value or (as of recently) may communicate a NULL by "break"ing.

A relevant snippet from one of the test scripts:

# 2017-06-26: The -withoutnulls flag to "db eval".
#
# In the "db eval -withoutnulls SQL TARGET" form, NULL results cause the
# corresponding target entry to be unset.  The default behavior (without
# the -withoutnulls flags) is for the corresponding target value to get
# the [db nullvalue] string.