A newer version of this documentation is available.

View Latest

Working with N1QL queries

You can perform Couchbase Query Language (N1QL) queries via the C client library.

N1QL queries are performed using a row-based API. This API is similar in spirit to the view API (see Working with view queries). The N1QL API is available when the libcouchbase/n1ql.h file is included.

To execute a N1QL query, first declare your handler. The handler is called once for each JSON-encoded row, and then one last time with the LCB_RESP_F_FINAL bit set in the rflags response member, where any result metadata (including errors) is returned. To actually make sense of the row’s content, use a JSON decoder on the row and nrow buffer/length fields.

N1QL Row Handler
static void rowCallback(lcb_t instance, int cbtype, const lcb_RESPN1QL *resp) {
    if (! (resp->rflags & LCB_RESP_F_FINAL)) {
        printf("Row: %.*s\n", (int)resp->nrow, resp->row);
    } else {
        printf("Got metadata: %.*s\n", (int)resp->nrow, resp->row);
    }
}

To issue the actual query, populate an lcb_CMDN1QL structure with appropriate parameters. Some of the internals of this structure may be populated using the lcb_N1QLPARAMS object. The lcb_N1QLPARAMS object is provided as a higher-level means by which to construct N1QL queries and supports N1QL features such as query placeholders and prepared statements. For example, to issue a query with a placeholder:

  1. Create the params object (lcb_n1p_new()).

  2. Set the query string (lcb_n1p_setstmtz(params, "statement_string")).

  3. Set the placeholders (lcb_n1p_namedparamz(params, "$param1", "value1"); lcb_n1p_namedparamz(params, "$param2", "value2")).

  4. Populate the lcb_CMDN1QL structure with the encoded query (lcb_n1p_mkcmd(params, &cmd)).

  5. Issue the query (lcb_n1ql_query).

  6. (Optional): You can dump the encoded form of the query using the return value from lcb_n1p_encode(). This returns a null-terminated string.

  7. Free or clear the params object (lcb_n1p_free or lcb_n1p_reset).

Here’s a code example that uses named parameters:

Issuing a N1QL query with a placeholder
// Error checking omitted for brevity

// The command structure
lcb_CMDN1QL cmd = { 0 };
// Allocate the parameter object
lcb_N1QLPARAMS *nparams = lcb_n1p_new();

lcb_n1p_setstmtz(nparams,
   "SELECT fname || \" \" || lname, age FROM default WHERE age > $age LIMIT 5");
// Set the value for '$age'
lcb_n1p_namedparamz(nparams, "$age", "27");
// Now, fill the command structure
lcb_n1p_mkcmd(nparams, &cmd);
#if DEBUG
// Dump the encoded query
printf("Encoded query is: %s\n", lcb_n1p_encode(nparams));
#endif
cmd.callback = rowCallback;

lcb_error_t rc = lcb_n1ql_query(instance, NULL, &cmd);
if (rc != LCB_SUCCESS) {
    // OOPS!
}
// We can release the params object now..
lcb_n1p_free(nparams);
lcb_wait(instance);

You can also utilize the encoded query directly (without using lcb_N1QLPARAMS). This involves using a pre-encoded query per the N1QL REST API. This example issues the same query as above, bypassing the parameters object, and encoding the query manually.

User-encoded query
const char *querystr =
    "{"
        /* read as SELECT fname || " " || lname FROM default WHERE age > $age LIMIT 5 */
        "\"statement\":"SELECT fname || \" \" || lname, age FROM default WHERE age > $age LIMIT 5\","
        "\"$age\": 27"
    "}"
lcb_CMDN1QL cmd = { 0 };
cmd.query = querystr;
cmd.nquery = strlen(querystr);
cmd.callback = rowCallback;
lcb_error_t rc = lcb_n1ql_query(instance, NULL, &cmd);
// ...
Versions prior to 2.5.3 require the content_type field to be set to application/json. Since version 2.5.3, all queries must be in JSON, and the content_type field is ignored.

Prepared Statements

Since version 2.5.3, applications may optimize frequently issued statements by having the client internally prepare them. To use prepared statements, simply set the LCB_CMDN1QL_F_PREPCACHE bit in the cmdflags field

lcb_CMDN1QL cmd = { 0 };
// initialize other sections
cmd.cmdflags |= LCB_CMDN1QL_F_PREPCACHE;