N1QL from the SDK
Edit this article in GitHub
Version 2.2

N1QL from the SDK

This page describes how to issue N1QL queries using the C SDK. N1QL queries are performed using a row-based API which invokes a callback repeatedly, once for each query row. The C SDK uses a special JSON parser to invoke row callbacks as they are read from the network - avoiding waiting for the entire response to be received.

N1QL queries are performed using a row-based API. This API is similar in spirit to the view API (see MapReduce Views using the C (libcouchbase) SDK with Couchbase Server). 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 placeholders

Issuing a N1QL query with a placeholder
lcb_N1QLPARAMS *params = lcb_n1p_new();
lcb_CMDN1QL cmd = { 0 };

// Need to make this properly formatted JSON
std::string city_str;
city_str += '"';
city_str += city;
city_str += '"';

rc = lcb_n1p_setstmtz(params,
    "SELECT airportname FROM `travel-sample` "
    "WHERE city=$1 AND type=\"airport\"");
rc = lcb_n1p_posparam(params, city_str.c_str(), city_str.size());

cmd.callback = query_callback;

rc = lcb_n1p_mkcmd(params, &cmd);
rc = lcb_n1ql_query(instance, cookie, &cmd);
lcb_n1p_free(params);
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);
// ...
Note: 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;