Since I only needed the `limit` command, and since the `test1.c` extension is ~8600 LOC, I just added the code from the `test_limit()` function as a new switch case in the `tclsqlite` extension. Here's a patch file for anyone that wants to use it: --- C:/Differ/old/tclsqlite.c Fri Nov 27 06:59:17 2020 +++ C:/Differ/new/tclsqlite.c Mon Jan 18 06:51:47 2021 @@ -26,0 +27,14 @@ + +/*============================================================================== + * 2021 January 16 + + * Modified to include the code in the test_limit() function from the test1.c + * file in the SQLite source. This adds the "limit" command to a database + * connection object, which invokes the "sqlite3_limit()" API. + * + * Changes are marked with /* EDIT: ... + * + * The author of these changes further disclaims copyright. + * + *============================================================================*/ + @@ -1916 +1930 @@ - static const char *DB_strs[] = { + static const char *DB_strs[] = { /* EDIT: Added "limit" and DB_LIMIT */ @@ -1930 +1944,2 @@ - "version", "wal_hook", 0 + "version", "wal_hook", "limit", + 0 @@ -1946 +1961 @@ - DB_VERSION, DB_WAL_HOOK + DB_VERSION, DB_WAL_HOOK, DB_LIMIT @@ -3636,0 +3652,65 @@ + /* EDIT: Added a case for DB_LIMIT + ** + ** $db limit ID VALUE + ** + ** Set or query the SQLITE_LIMIT_XX value + */ + case DB_LIMIT: { + static const struct { + char *zName; + int id; + } aId[] = { /* EDIT: Permit exclusion of SQLITE_ prefix */ + { "SQLITE_LIMIT_LENGTH", SQLITE_LIMIT_LENGTH }, + { "SQLITE_LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH }, + { "SQLITE_LIMIT_COLUMN", SQLITE_LIMIT_COLUMN }, + { "SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH }, + { "SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT }, + { "SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP }, + { "SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG }, + { "SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED }, + { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, + { "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, + { "SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH }, + { "SQLITE_LIMIT_WORKER_THREADS", SQLITE_LIMIT_WORKER_THREADS }, + { "LIMIT_LENGTH", SQLITE_LIMIT_LENGTH }, + { "LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH }, + { "LIMIT_COLUMN", SQLITE_LIMIT_COLUMN }, + { "LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH }, + { "LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT }, + { "LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP }, + { "LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG }, + { "LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED }, + { "LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, + { "LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, + { "LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH }, + { "LIMIT_WORKER_THREADS", SQLITE_LIMIT_WORKER_THREADS }, + + /* Out of range test cases */ + { "SQLITE_LIMIT_TOOSMALL", -1, }, + { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_WORKER_THREADS + 1 }, + }; + int i, id = 0; + int val; + const char *zId; + + if( objc!=4 ) { /* EDIT: Added mising end-quote and changed db to limit */ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetStringFromObj(objv[0], 0), " limit ID VALUE\"", 0); + return TCL_ERROR; + } + zId = Tcl_GetString(objv[2]); + for(i=0; i<sizeof(aId)/sizeof(aId[0]); i++){ + if( _stricmp(zId, aId[i].zName)==0 ){ /* EDIT: Permit case-insensitive */ + id = aId[i].id; + break; + } + } + if( i>=sizeof(aId)/sizeof(aId[0]) ){ + Tcl_AppendResult(interp, "unknown limit type: ", zId, (char*)0); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR; + rc = sqlite3_limit(pDb->db, id, val); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return TCL_OK; + }