Couchbase C Client  2.10.7
Asynchronous C Client for Couchbase
example/subdoc/subdoc-xattrs.c

Shows how to work with XATTRs using subdocument API.

/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* Copyright 2017 Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <unistd.h>
#include <stdlib.h>
#include <libcouchbase/n1ql.h>
#include <assert.h>
#include <string.h>
static void generic_callback(lcb_t instance, int type, const lcb_RESPBASE *rb)
{
if (rb->rc != LCB_SUCCESS && rb->rc != LCB_SUBDOC_MULTI_FAILURE) {
printf("Failure: 0x%x, %s\n", rb->rc, lcb_strerror(instance, rb->rc));
return;
}
switch (type) {
size_t iter = 0;
size_t index = 0;
const lcb_RESPSUBDOC *resp = (const lcb_RESPSUBDOC *)rb;
while (lcb_sdresult_next(resp, &ent, &iter)) {
if (index == 0 && ent.status != LCB_SUCCESS) {
// attribute does not exist, skip response
return;
}
if (index == 1) {
printf(" * %.*s: %.*s%%\n", (int)resp->nkey, resp->key, (int)ent.nvalue, ent.value);
}
index++;
}
break;
}
case LCB_CALLBACK_SDMUTATE: {
size_t iter = 0;
size_t oix = 0;
const lcb_RESPSUBDOC *resp = (const lcb_RESPSUBDOC *)rb;
while (lcb_sdresult_next(resp, &ent, &iter)) {
size_t index = oix++;
if (type == LCB_CALLBACK_SDMUTATE) {
index = ent.index;
}
printf("[%lu]: 0x%x. %.*s\n", index, ent.status, (int)ent.nvalue, ent.value);
}
break;
}
}
}
static void n1qlrow_callback(lcb_t instance, int type, const lcb_RESPN1QL *resp)
{
if (resp->rc != LCB_SUCCESS) {
printf("Failure: 0x%x, %s\n", resp->rc, lcb_strerror(instance, resp->rc));
printf("HTTP status: %d\n", (int)resp->htresp->htstatus);
{
const char *const *hdr = resp->htresp->headers;
for (; hdr && *hdr; hdr++) {
printf("%s", *hdr);
if (hdr + 1) {
printf(" = %s", *(++hdr));
}
printf("\n");
}
}
printf("%.*s\n", (int)resp->nrow, resp->row);
return;
}
char *start = "{\"docID\":\"";
char *stop = "\"";
char *key = strstr(resp->row, start);
if (key == NULL || key != resp->row) {
return;
}
key += strlen(start);
char *z = strstr(key, stop);
if (z == NULL) {
return;
}
*z = '\0';
lcb_sched_enter(instance);
{
lcb_CMDSUBDOC cmd = {};
lcb_SDSPEC specs[2] = {};
char *path = "discounts.jsmith123";
LCB_CMD_SET_KEY(&cmd, key, strlen(key));
specs[0].sdcmd = LCB_SDCMD_EXISTS;
LCB_SDSPEC_SET_PATH(&specs[0], path, strlen(path));
specs[1].sdcmd = LCB_SDCMD_GET;
LCB_SDSPEC_SET_PATH(&specs[1], path, strlen(path));
cmd.specs = specs;
cmd.nspecs = 2;
rc = lcb_subdoc3(instance, NULL, &cmd);
assert(rc == LCB_SUCCESS);
}
lcb_sched_leave(instance);
}
#define DEFAULT_CONNSTR "couchbase://localhost/travel-sample"
static lcb_t connect_as(char *username, char *password)
{
struct lcb_create_st crst = {.version = 3};
crst.v.v3.connstr = DEFAULT_CONNSTR;
crst.v.v3.username = username;
crst.v.v3.passwd = password;
lcb_t instance;
rc = lcb_create(&instance, &crst);
assert(rc == LCB_SUCCESS);
rc = lcb_connect(instance);
assert(rc == LCB_SUCCESS);
lcb_wait(instance);
rc = lcb_get_bootstrap_status(instance);
assert(rc == LCB_SUCCESS);
lcb_install_callback3(instance, LCB_CALLBACK_DEFAULT, generic_callback);
return instance;
}
int main()
{
lcb_t instance;
instance = connect_as("Administrator", "password");
// Add key-value pairs to hotel_10138, representing traveller-Ids and associated discount percentages
{
lcb_CMDSUBDOC cmd = {};
lcb_SDSPEC specs[4] = {};
char *key = "hotel_10138";
LCB_CMD_SET_KEY(&cmd, key, strlen(key));
{
char *path = "discounts.jsmith123";
char *val = "20";
LCB_SDSPEC_SET_PATH(&specs[0], path, strlen(path));
LCB_CMD_SET_VALUE(&specs[0], val, strlen(val));
}
{
char *path = "discounts.pjones356";
char *val = "30";
LCB_SDSPEC_SET_PATH(&specs[1], path, strlen(path));
LCB_CMD_SET_VALUE(&specs[1], val, strlen(val));
}
// The following lines, "insert" and "remove", simply demonstrate insertion and
// removal of the same path and value
{
char *path = "discounts.jbrown789";
char *val = "25";
LCB_SDSPEC_SET_PATH(&specs[2], path, strlen(path));
LCB_CMD_SET_VALUE(&specs[2], val, strlen(val));
}
{
char *path = "discounts.jbrown789";
specs[3].sdcmd = LCB_SDCMD_REMOVE;
LCB_SDSPEC_SET_PATH(&specs[3], path, strlen(path));
}
cmd.specs = specs;
cmd.nspecs = 4;
rc = lcb_subdoc3(instance, NULL, &cmd);
assert(rc == LCB_SUCCESS);
}
// Add key - value pairs to hotel_10142, again representing traveller - Ids and associated discount percentages
{
lcb_CMDSUBDOC cmd = {};
lcb_SDSPEC specs[2] = {};
char *key = "hotel_10142";
LCB_CMD_SET_KEY(&cmd, key, strlen(key));
{
char *path = "discounts.jsmith123";
char *val = "15";
LCB_SDSPEC_SET_PATH(&specs[0], path, strlen(path));
LCB_CMD_SET_VALUE(&specs[0], val, strlen(val));
}
{
char *path = "discounts.pjones356";
char *val = "10";
LCB_SDSPEC_SET_PATH(&specs[1], path, strlen(path));
LCB_CMD_SET_VALUE(&specs[1], val, strlen(val));
}
cmd.specs = specs;
cmd.nspecs = 2;
rc = lcb_subdoc3(instance, NULL, &cmd);
assert(rc == LCB_SUCCESS);
}
lcb_wait(instance);
// Create a user and assign roles. This user will search for their available discounts.
{
lcb_CMDHTTP cmd = {};
char *path = "/settings/rbac/users/local/jsmith123";
char *payload = "password=jsmith123pwd&name=John+Smith"
"&roles=data_reader[travel-sample],query_select[travel-sample],data_writer[travel-sample]";
cmd.method = LCB_HTTP_METHOD_PUT;
LCB_CMD_SET_KEY(&cmd, path, strlen(path));
cmd.body = payload;
cmd.nbody = strlen(payload);
cmd.content_type = "application/x-www-form-urlencoded";
lcb_http3(instance, NULL, &cmd);
lcb_wait(instance);
}
lcb_destroy(instance);
// reconnect using new user
instance = connect_as("jsmith123", "jsmith123pwd");
// Perform a N1QL Query to return document IDs from the bucket. These IDs will be
// used to reference each document in turn, and check for extended attributes
// corresponding to discounts.
{
lcb_CMDN1QL cmd = {};
char *query = "SELECT id, meta(`travel-sample`).id AS docID FROM `travel-sample`";
lcb_n1p_setstmtz(params, query);
rc = lcb_n1p_mkcmd(params, &cmd);
assert(rc == LCB_SUCCESS);
cmd.callback = n1qlrow_callback;
printf("User \"jsmith123\" has discounts in the hotels below:\n");
lcb_n1ql_query(instance, NULL, &cmd);
lcb_wait(instance);
}
lcb_destroy(instance);
}
LCB_CALLBACK_DEFAULT
@ LCB_CALLBACK_DEFAULT
Default callback invoked as a fallback.
Definition: couchbase.h:696
lcb_SDENTRY::index
lcb_U8 index
Request index which this result pertains to.
Definition: subdoc.h:318
LCB_SDSPEC_F_MKINTERMEDIATES
#define LCB_SDSPEC_F_MKINTERMEDIATES
Create intermediate paths.
Definition: subdoc.h:189
lcb_wait
lcb_error_t lcb_wait(lcb_t instance)
Wait for the execution of all batched requests.
lcb_strerror
const char * lcb_strerror(lcb_t instance, lcb_error_t error)
Get a textual descrtiption for the given error code.
lcb_RESPN1QL::row
const char * row
Current result row.
Definition: n1ql.h:438
lcb_http3
lcb_error_t lcb_http3(lcb_t instance, const void *cookie, const lcb_CMDHTTP *cmd)
LCB_SDCMD_DICT_UPSERT
@ LCB_SDCMD_DICT_UPSERT
Unconditionally set the value at the path.
Definition: subdoc.h:73
lcb_create_st3::passwd
const char * passwd
Password for bucket.
Definition: couchbase.h:293
lcb_SDSPEC::options
lcb_U32 options
Set of option flags for the command.
Definition: subdoc.h:171
lcb_RESPN1QL::htresp
const lcb_RESPHTTP * htresp
Raw HTTP response, if applicable.
Definition: n1ql.h:442
lcb_get_bootstrap_status
lcb_error_t lcb_get_bootstrap_status(lcb_t instance)
Gets the initial bootstrap status.
lcb_RESPHTTP::headers
const char *const * headers
List of key-value headers.
Definition: couchbase.h:2795
lcb_RESPHTTP::htstatus
short htstatus
HTTP status code.
Definition: couchbase.h:2791
lcb_create_st3::connstr
const char * connstr
Connection string.
Definition: couchbase.h:282
lcb_CMDHTTP::type
lcb_http_type_t type
Type of request to issue.
Definition: couchbase.h:2748
lcb_sdresult_next
int lcb_sdresult_next(const lcb_RESPSUBDOC *resp, lcb_SDENTRY *out, size_t *iter)
Iterate over the results for a subdocument response.
lcb_connect
lcb_error_t lcb_connect(lcb_t instance)
Schedule the initial connection This function will schedule the initial connection for the handle.
lcb_create_st3::username
const char * username
Username to use for authentication.
Definition: couchbase.h:288
lcb_RESPN1QL
Response for a N1QL query.
Definition: n1ql.h:426
lcb_n1ql_query
lcb_error_t lcb_n1ql_query(lcb_t instance, const void *cookie, const lcb_CMDN1QL *cmd)
lcb_SDSPEC::sdcmd
lcb_U32 sdcmd
The command code, lcb_SUBDOCOP.
Definition: subdoc.h:165
LCB_CALLBACK_SDLOOKUP
@ LCB_CALLBACK_SDLOOKUP
<for lcb_storedur3()
Definition: couchbase.h:714
lcb_n1p_new
lcb_N1QLPARAMS * lcb_n1p_new(void)
Create a new N1QL Parameters object.
lcb_error_t
lcb_error_t
Error codes returned by the library.
Definition: error.h:476
LCB_SDCMD_EXISTS
@ LCB_SDCMD_EXISTS
Check if the value for a path exists.
Definition: subdoc.h:51
lcb_sched_enter
void lcb_sched_enter(lcb_t instance)
Enter a scheduling context.
lcb_N1QLPARAMS
struct lcb_N1QLPARAMS_st lcb_N1QLPARAMS
Opaque object representing N1QL parameters.
Definition: n1ql.h:109
lcb_SDENTRY::nvalue
size_t nvalue
Length of the value.
Definition: subdoc.h:309
LCB_HTTP_TYPE_MANAGEMENT
@ LCB_HTTP_TYPE_MANAGEMENT
Execute a management API request.
Definition: couchbase.h:2674
lcb_RESPBASE::rc
lcb_error_t rc
Status code.
Definition: couchbase.h:626
lcb_sched_leave
void lcb_sched_leave(lcb_t instance)
Leave the current scheduling context, scheduling the commands within the context to be flushed to the...
LCB_SDSPEC_SET_PATH
#define LCB_SDSPEC_SET_PATH(s, p, n)
Set the path for an lcb_SDSPEC structure.
Definition: subdoc.h:206
lcb_CMDHTTP::method
lcb_http_method_t method
HTTP Method to use.
Definition: couchbase.h:2749
lcb_create_st::lcb_CRST_u::v3
struct lcb_create_st3 v3
Use this field.
Definition: couchbase.h:338
LCB_SUBDOC_MULTI_FAILURE
@ LCB_SUBDOC_MULTI_FAILURE
Could not execute one or more multi lookups or mutations.
Definition: error.h:478
lcb_CMDHTTP::nbody
lcb_SIZE nbody
Length of the body for the request.
Definition: couchbase.h:2756
lcb_create_st
Wrapper structure for lcb_create()
Definition: couchbase.h:328
lcb_n1p_mkcmd
lcb_error_t lcb_n1p_mkcmd(lcb_N1QLPARAMS *params, lcb_CMDN1QL *cmd)
Populates the given low-level lcb_CMDN1QL structure with the relevant fields from the params structur...
LCB_CMD_SET_KEY
#define LCB_CMD_SET_KEY(cmd, keybuf, keylen)
Set the key for the command.
Definition: couchbase.h:556
lcb_t
struct lcb_st * lcb_t
Definition: couchbase.h:41
lcb_subdoc3
lcb_error_t lcb_subdoc3(lcb_t instance, const void *cookie, const lcb_CMDSUBDOC *cmd)
Perform one or more subdocument operations.
lcb_SDENTRY::value
const void * value
Value for the mutation (only applicable for LCB_SDCMD_COUNTER, currently)
Definition: subdoc.h:307
lcb_SDENTRY::status
lcb_error_t status
Status code.
Definition: subdoc.h:311
lcb_create
lcb_error_t lcb_create(lcb_t *instance, const struct lcb_create_st *options)
Create an instance of lcb.
couchbase.h
LCB_SUCCESS
@ LCB_SUCCESS
Success.
Definition: error.h:478
lcb_RESPN1QL::nrow
size_t nrow
Length of the row.
Definition: n1ql.h:440
lcb_RESPBASE
Base response structure for callbacks.
Definition: couchbase.h:625
lcb_destroy
void lcb_destroy(lcb_t instance)
Destroy (and release all allocated resources) an instance of lcb.
lcb_CMDN1QL::callback
lcb_N1QLCALLBACK callback
Callback to be invoked for each row.
Definition: n1ql.h:414
LCB_SDCMD_GET
@ LCB_SDCMD_GET
Retrieve the value for a path.
Definition: subdoc.h:45
lcb_SDENTRY
Structure for a single sub-document mutation or lookup result.
Definition: subdoc.h:305
lcb_CMDHTTP
Structure for performing an HTTP request.
Definition: couchbase.h:2742
lcb_CMDN1QL
Command structure for N1QL queries.
Definition: n1ql.h:385
lcb_RESPSUBDOC
Response structure for multi lookups.
Definition: subdoc.h:294
LCB_CMD_SET_VALUE
#define LCB_CMD_SET_VALUE(scmd, valbuf, vallen)
Set the value buffer for the command. This may be used when the new value is a single contiguous buff...
Definition: couchbase.h:1139
lcb_create_st::version
int version
Indicates which field in the lcb_CRST_u union should be used.
Definition: couchbase.h:330
lcb_CMDHTTP::body
const char * body
If the request requires a body (e.g.
Definition: couchbase.h:2753
lcb_n1p_setstmtz
#define lcb_n1p_setstmtz(params, qstr)
Shortcut to set NUL-terminated string as statement via lcb_n1p_setquery.
Definition: n1ql.h:159
LCB_SDCMD_REMOVE
@ LCB_SDCMD_REMOVE
Remove an existing path in the document.
Definition: subdoc.h:130
LCB_SDSPEC_F_XATTRPATH
#define LCB_SDSPEC_F_XATTRPATH
Access document XATTR path.
Definition: subdoc.h:192
lcb_install_callback3
lcb_RESPCALLBACK lcb_install_callback3(lcb_t instance, int cbtype, lcb_RESPCALLBACK cb)
lcb_CMDHTTP::content_type
const char * content_type
For views, set this to application/json
Definition: couchbase.h:2763
LCB_SDCMD_DICT_ADD
@ LCB_SDCMD_DICT_ADD
Add the value at the given path, if the given path does not exist.
Definition: subdoc.h:66
lcb_SDSPEC
Subdoc command specification.
Definition: subdoc.h:160