1 /**
2  *     Copyright 2016-2017 Couchbase, Inc.
3  *
4  *   Licensed under the Apache License, Version 2.0 (the "License");
5  *   you may not use this file except in compliance with the License.
6  *   You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *   See the License for the specific language governing permissions and
14  *   limitations under the License.
15  */
16 
17 #include "couchbase.h"
18 
19 #define LOGARGS(instance, lvl) LCB_LOG_##lvl, instance, "pcbc/n1ix_list", __FILE__, __LINE__
20 
21 typedef struct {
22     opcookie_res header;
23     PCBC_ZVAL *specs;
24     int nspecs;
25 } opcookie_n1ix_list_res;
26 
n1ix_list_callback(lcb_t instance,int cbtype,const lcb_RESPN1XMGMT * resp)27 static void n1ix_list_callback(lcb_t instance, int cbtype, const lcb_RESPN1XMGMT *resp)
28 {
29     opcookie_n1ix_list_res *result = ecalloc(1, sizeof(opcookie_n1ix_list_res));
30     int i;
31     TSRMLS_FETCH();
32 
33     result->header.err = resp->rc;
34     if (result->header.err != LCB_SUCCESS) {
35         pcbc_log(LOGARGS(instance, ERROR), "Failed to list indexes. %d: %.*s", (int)resp->inner->htresp->htstatus,
36                  (int)resp->inner->nrow, (char *)resp->inner->row);
37     }
38     result->nspecs = resp->nspecs;
39     result->specs = ecalloc(result->nspecs, sizeof(PCBC_ZVAL));
40     for (i = 0; i < result->nspecs; ++i) {
41         const lcb_N1XSPEC *spec = resp->specs[i];
42         int last_error;
43         PCBC_ZVAL value, json;
44 
45         PCBC_ZVAL_ALLOC(value);
46         PCBC_ZVAL_ALLOC(json);
47         PCBC_JSON_COPY_DECODE(PCBC_P(json), spec->rawjson, spec->nrawjson, PHP_JSON_OBJECT_AS_ARRAY, last_error);
48         if (last_error != 0) {
49             pcbc_log(LOGARGS(instance, WARN), "Failed to decode value as JSON: json_last_error=%d", last_error);
50             ZVAL_NULL(PCBC_P(value));
51         } else {
52             pcbc_n1ix_init(PCBC_P(value), PCBC_P(json) TSRMLS_CC);
53         }
54 
55         zval_ptr_dtor(&json);
56         result->specs[i] = value;
57     }
58 
59     opcookie_push((opcookie *)resp->cookie, &result->header);
60 }
61 
proc_n1ix_list_results(zval * return_value,opcookie * cookie TSRMLS_DC)62 static lcb_error_t proc_n1ix_list_results(zval *return_value, opcookie *cookie TSRMLS_DC)
63 {
64     opcookie_n1ix_list_res *result = (opcookie_n1ix_list_res *)opcookie_next_res(cookie, NULL);
65     lcb_error_t err = opcookie_get_first_error(cookie);
66     int i;
67 
68     if (result) {
69         if (err == LCB_SUCCESS) {
70             array_init(return_value);
71             for (i = 0; i < result->nspecs; ++i) {
72                 add_index_zval(return_value, i, PCBC_P(result->specs[i]));
73             }
74         }
75         efree(result->specs);
76     }
77 
78     return err;
79 }
80 
pcbc_n1ix_list(pcbc_bucket_manager_t * manager,zval * return_value TSRMLS_DC)81 int pcbc_n1ix_list(pcbc_bucket_manager_t *manager, zval *return_value TSRMLS_DC)
82 {
83     lcb_CMDN1XMGMT cmd = {0};
84     opcookie *cookie;
85     lcb_error_t err;
86 
87     cmd.callback = n1ix_list_callback;
88     cookie = opcookie_init();
89 
90     cmd.spec.nkeyspace = strlen(manager->conn->bucketname);
91     cmd.spec.keyspace = manager->conn->bucketname;
92     err = lcb_n1x_list(manager->conn->lcb, cookie, &cmd);
93 
94     if (err == LCB_SUCCESS) {
95         lcb_wait(manager->conn->lcb);
96         err = proc_n1ix_list_results(return_value, cookie TSRMLS_CC);
97     }
98 
99     opcookie_destroy(cookie);
100 
101     if (err != LCB_SUCCESS) {
102         throw_lcb_exception(err);
103         return FAILURE;
104     }
105     return SUCCESS;
106 }
107