SQLite Forum

Tcl limit API
Login

Tcl limit API

(1) By Mark Benningfield (mbenningfield1) on 2021-01-11 11:21:39 [link]

I'm working on updating a SQLite extension and I thought this would be a good time to learn Tcl and convert the (zillion) unit tests to Tcl. Does the Tcl interface for SQLite not contain a command for the `sqlite3_limit()` API?

(2) By Richard Hipp (drh) on 2021-01-11 12:32:36 in reply to 1 [link]

There is not.  We have traditionally used [an TCL extension][1] to access
sqlite3_limit() for testing.

[1]: https://www.sqlite.org/src/artifact/01e2d375fdbd3fa7?ln=6518-6578

(3) By Mark Benningfield (mbenningfield1) on 2021-01-11 13:26:19 in reply to 2 [link]

Okay, thanks. I've just started out with Tcl, and I haven't really gotten around to the TEA aspects yet. Hopefully the books I've ordered will arrive this week and I can spend the weekend in a deep dip.

(4) By Dan Shearer (danshearer) on 2021-01-11 20:25:20 in reply to 3

> Hopefully the books I've ordered will arrive this week and I can spend the weekend in a deep dip.

I'm getting into Tcl too. Quite a few Tcl books are outdated, but I can recommend "The Tcl Programming Language" both Ashok P Nadkarani as being current up to 8.6, and a considerable amount of writing on the author's website about 8.7-related topics.

Dan Shearer

(5) By Mark Benningfield (mbenningfield1) on 2021-01-18 13:45:37 in reply to 2 [link]

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; 
    +  }