Search code examples
cjsonsqlitesqlite-json1

How to set json array index as bound parameter in sqlite3?


I am using the C-API for SQLite3 and the json1 extension. Within the database, a list of integers is stored as a json_array. I want to create a C integer array from the json_array using the json_extract function. I am looping over each value in the json array by incrementing the index in the SQL statement. As an example, consider:

CREATE TABLE mytable ( label INTEGER PRIMARY KEY, list TEXT);
INSERT INTO mytable VALUES ( 1, json(json_array(1,2,3)) ); 

SELECT json_extract( list, '$[index]' ) FROM mytable WHERE label == 1;
---Example: the result for index=0 is the integer: 1

In the C program, I am currently creating a character string to represent the single-quoted portion of the command, '$[index]', as a bound parameter, as shown in the snippet below.

Can or should I avoid using sprintf to set the index? Or, is this an acceptable solution?

char *sql = "select json_extract(list, ?) from mytable where label == 1";
char *index_param = (char *)malloc(80);

// OTHER STUFF: prepare sql stmt, etc, etc...

for (int i=0; i<n; i++) {  /* n is the number of values in the json list */

    /* Is sprintf the best thing to do here? */
    index_length = sprintf(index_param, "$[%d]", i);

    sqlite3_bind_text(stmt, 1, index_param, index_length+1, SQLITE_STATIC);
    result = sqlite3_step(stmt);
    values[i] = sqlite3_column_int(stmt, 0);
    sqlite3_reset(stmt);
}

Solution

  • You could construct the path in SQL so that you have only an integer parameter:

    SELECT json_extract(list, '$[' || ? || ']') FROM ...
    

    But it would be a better idea to read the array values directly with the json_each() function:

    const char *sql = "SELECT value FROM MyTable, json_each(MyTable.list) WHERE ...";
    // prepare ...
    for (;;) {
        rc = sqlite3_step(stmt);
        if (rc != SQLITE_ROW)
            break;
        values[i++] = sqlite3_column_int(stmt, 0);
    }