1 #include "ejdb2_internal.h"
2
_jbi_consume_eq(struct _JBEXEC * ctx,JQVAL * jqval,JB_SCAN_CONSUMER consumer)3 static iwrc _jbi_consume_eq(struct _JBEXEC *ctx, JQVAL *jqval, JB_SCAN_CONSUMER consumer) {
4 iwrc rc;
5 bool matched;
6 IWKV_cursor cur;
7 char numbuf[IWNUMBUF_SIZE];
8
9 int64_t step = 1;
10 struct _JBMIDX *midx = &ctx->midx;
11 JBIDX idx = midx->idx;
12 IWKV_cursor_op cursor_reverse_step = IWKV_CURSOR_NEXT;
13 midx->cursor_step = IWKV_CURSOR_PREV;
14
15 IWKV_val key;
16 jbi_jqval_fill_ikey(idx, jqval, &key, numbuf);
17 key.compound = INT64_MIN;
18 if (!key.size) {
19 return consumer(ctx, 0, 0, 0, 0, 0);
20 }
21 rc = iwkv_cursor_open(idx->idb, &cur, IWKV_CURSOR_GE, &key);
22 if (rc == IWKV_ERROR_NOTFOUND) {
23 return consumer(ctx, 0, 0, 0, 0, 0);
24 } else {
25 RCRET(rc);
26 }
27
28 do {
29 if (step > 0) {
30 --step;
31 } else if (step < 0) {
32 ++step;
33 }
34 if (!step) {
35 int64_t id;
36 RCC(rc, finish, iwkv_cursor_is_matched_key(cur, &key, &matched, &id));
37 if (!matched) {
38 break;
39 }
40 step = 1;
41 RCC(rc, finish, consumer(ctx, 0, id, &step, &matched, 0));
42 }
43 } while (step && !(rc = iwkv_cursor_to(cur, step > 0 ? midx->cursor_step : cursor_reverse_step)));
44
45 finish:
46 if (rc == IWKV_ERROR_NOTFOUND) {
47 rc = 0;
48 }
49 if (cur) {
50 iwkv_cursor_close(&cur);
51 }
52 return consumer(ctx, 0, 0, 0, 0, rc);
53 }
54
_jbi_cmp_jqval(const void * v1,const void * v2)55 static int _jbi_cmp_jqval(const void *v1, const void *v2) {
56 iwrc rc;
57 const JQVAL *jqv1 = v1;
58 const JQVAL *jqv2 = v2;
59 return jql_cmp_jqval_pair(jqv1, jqv2, &rc);
60 }
61
_jbi_consume_in_node(struct _JBEXEC * ctx,JQVAL * jqval,JB_SCAN_CONSUMER consumer)62 static iwrc _jbi_consume_in_node(struct _JBEXEC *ctx, JQVAL *jqval, JB_SCAN_CONSUMER consumer) {
63 int i;
64 int64_t id;
65 bool matched;
66 char jqvarrbuf[512];
67 char numbuf[IWNUMBUF_SIZE];
68
69 iwrc rc = 0;
70 int64_t step = 1;
71 IWKV_cursor cur = 0;
72 struct _JBMIDX *midx = &ctx->midx;
73 JBIDX idx = midx->idx;
74 IWKV_val key = { .compound = INT64_MIN };
75 JBL_NODE nv = jqval->vnode->child;
76
77 for (i = 0; nv; nv = nv->next) {
78 if ((nv->type >= JBV_BOOL) && (nv->type <= JBV_STR)) {
79 ++i;
80 }
81 }
82 if (i == 0) {
83 return consumer(ctx, 0, 0, 0, 0, 0);
84 }
85
86 JQVAL *jqvarr = (i * sizeof(*jqvarr)) <= sizeof(jqvarrbuf)
87 ? jqvarrbuf : malloc(i * sizeof(*jqvarr));
88 if (!jqvarr) {
89 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
90 }
91 for (i = 0, nv = jqval->vnode->child; nv; nv = nv->next) {
92 if ((nv->type >= JBV_BOOL) && (nv->type <= JBV_STR)) {
93 JQVAL jqv;
94 jql_node_to_jqval(nv, &jqv);
95 memcpy(&jqvarr[i++], &jqv, sizeof(jqv));
96 }
97 }
98 // Sort jqvarr according to index order, lowest first (asc)
99 qsort(jqvarr, i, sizeof(jqvarr[0]), _jbi_cmp_jqval);
100
101 for (int c = 0; c < i && !rc; ++c) {
102 JQVAL *jqv = &jqvarr[c];
103 jbi_jqval_fill_ikey(idx, jqv, &key, numbuf);
104 if (cur) {
105 iwkv_cursor_close(&cur);
106 }
107 RCC(rc, finish, iwkv_cursor_open(idx->idb, &cur, IWKV_CURSOR_GE, &key));
108 do {
109 if (step > 0) {
110 --step;
111 } else if (step < 0) {
112 ++step;
113 }
114 if (!step) {
115 RCC(rc, finish, iwkv_cursor_is_matched_key(cur, &key, &matched, &id));
116 if (!matched) {
117 break;
118 }
119 step = 1;
120 RCC(rc, finish, consumer(ctx, 0, id, &step, &matched, 0));
121 }
122 } while (step && !(rc = iwkv_cursor_to(cur, IWKV_CURSOR_PREV))); // !!! only one direction
123 }
124
125 finish:
126 if (rc == IWKV_ERROR_NOTFOUND) {
127 rc = 0;
128 }
129 if (cur) {
130 iwkv_cursor_close(&cur);
131 }
132 if ((char*) jqvarr != jqvarrbuf) {
133 free(jqvarr);
134 }
135 return consumer(ctx, 0, 0, 0, 0, rc);
136 }
137
_jbi_consume_scan(struct _JBEXEC * ctx,JQVAL * jqval,JB_SCAN_CONSUMER consumer)138 static iwrc _jbi_consume_scan(struct _JBEXEC *ctx, JQVAL *jqval, JB_SCAN_CONSUMER consumer) {
139 size_t sz;
140 IWKV_cursor cur;
141 char numbuf[IWNUMBUF_SIZE];
142
143 int64_t step = 1, prev_id = 0;
144 struct _JBMIDX *midx = &ctx->midx;
145 JBIDX idx = midx->idx;
146 jqp_op_t expr1_op = midx->expr1->op->value;
147
148 IWKV_val key;
149 jbi_jqval_fill_ikey(idx, jqval, &key, numbuf);
150 if (!key.size) {
151 return consumer(ctx, 0, 0, 0, 0, 0);
152 }
153 key.compound = (midx->cursor_step == IWKV_CURSOR_PREV) ? INT64_MIN : INT64_MAX;
154
155 iwrc rc = iwkv_cursor_open(idx->idb, &cur, midx->cursor_init, &key);
156 if ((rc == IWKV_ERROR_NOTFOUND) && ((expr1_op == JQP_OP_LT) || (expr1_op == JQP_OP_LTE))) {
157 iwkv_cursor_close(&cur);
158 key.compound = INT64_MAX;
159 midx->cursor_init = IWKV_CURSOR_BEFORE_FIRST;
160 midx->cursor_step = IWKV_CURSOR_NEXT;
161 RCC(rc, finish, iwkv_cursor_open(idx->idb, &cur, midx->cursor_init, 0));
162 if (!midx->expr2) { // Fail fast
163 midx->expr2 = midx->expr1;
164 }
165 } else if (rc) {
166 goto finish;
167 }
168
169 if (midx->cursor_init < IWKV_CURSOR_NEXT) { // IWKV_CURSOR_BEFORE_FIRST || IWKV_CURSOR_AFTER_LAST
170 RCC(rc, finish, iwkv_cursor_to(cur, midx->cursor_step));
171 }
172
173 IWKV_cursor_op cursor_reverse_step = (midx->cursor_step == IWKV_CURSOR_PREV)
174 ? IWKV_CURSOR_NEXT : IWKV_CURSOR_PREV;
175 do {
176 if (step > 0) {
177 --step;
178 } else if (step < 0) {
179 ++step;
180 }
181 if (!step) {
182 int64_t id;
183 bool matched = false;
184 RCC(rc, finish, iwkv_cursor_copy_key(cur, 0, 0, &sz, &id));
185 if ( midx->expr2
186 && !midx->expr2->prematched
187 && !jbi_node_expr_matched(ctx->ux->q->aux, midx->idx, cur, midx->expr2, &rc)) {
188 break;
189 }
190 if ( (expr1_op == JQP_OP_PREFIX)
191 && !jbi_node_expr_matched(ctx->ux->q->aux, midx->idx, cur, midx->expr1, &rc)) {
192 break;
193 }
194 RCGO(rc, finish);
195 step = 1;
196 if (id != prev_id) {
197 RCC(rc, finish, consumer(ctx, 0, id, &step, &matched, 0));
198 if (!midx->expr1->prematched && matched && (expr1_op != JQP_OP_PREFIX)) {
199 // Further scan will always match main index expression
200 midx->expr1->prematched = true;
201 }
202 prev_id = step < 1 ? 0 : id;
203 }
204 }
205 } while (step && !(rc = iwkv_cursor_to(cur, step > 0 ? midx->cursor_step : cursor_reverse_step)));
206
207 finish:
208 if (rc == IWKV_ERROR_NOTFOUND) {
209 rc = 0;
210 }
211 if (cur) {
212 iwkv_cursor_close(&cur);
213 }
214 return consumer(ctx, 0, 0, 0, 0, rc);
215 }
216
_jbi_consume_noxpr_scan(struct _JBEXEC * ctx,JB_SCAN_CONSUMER consumer)217 static iwrc _jbi_consume_noxpr_scan(struct _JBEXEC *ctx, JB_SCAN_CONSUMER consumer) {
218 iwrc rc;
219 size_t sz;
220 IWKV_cursor cur;
221 int64_t step = 1, prev_id = 0;
222 struct _JBMIDX *midx = &ctx->midx;
223 IWKV_cursor_op cursor_reverse_step = (midx->cursor_step == IWKV_CURSOR_PREV)
224 ? IWKV_CURSOR_NEXT : IWKV_CURSOR_PREV;
225
226 RCC(rc, finish, iwkv_cursor_open(midx->idx->idb, &cur, midx->cursor_init, 0));
227 if (midx->cursor_init < IWKV_CURSOR_NEXT) { // IWKV_CURSOR_BEFORE_FIRST || IWKV_CURSOR_AFTER_LAST
228 RCC(rc, finish, iwkv_cursor_to(cur, midx->cursor_step));
229 }
230 do {
231 if (step > 0) {
232 --step;
233 } else if (step < 0) {
234 ++step;
235 }
236 if (!step) {
237 int64_t id;
238 bool matched;
239 RCC(rc, finish, iwkv_cursor_copy_key(cur, 0, 0, &sz, &id));
240 step = 1;
241 if (id != prev_id) {
242 RCC(rc, finish, consumer(ctx, 0, id, &step, &matched, 0));
243 prev_id = step < 1 ? 0 : id;
244 }
245 }
246 } while (step && !(rc = iwkv_cursor_to(cur, step > 0 ? midx->cursor_step : cursor_reverse_step)));
247
248 finish:
249 if (rc == IWKV_ERROR_NOTFOUND) {
250 rc = 0;
251 }
252 if (cur) {
253 iwkv_cursor_close(&cur);
254 }
255 return consumer(ctx, 0, 0, 0, 0, rc);
256 }
257
jbi_dup_scanner(struct _JBEXEC * ctx,JB_SCAN_CONSUMER consumer)258 iwrc jbi_dup_scanner(struct _JBEXEC *ctx, JB_SCAN_CONSUMER consumer) {
259 iwrc rc;
260 struct _JBMIDX *midx = &ctx->midx;
261 if (!midx->expr1) {
262 return _jbi_consume_noxpr_scan(ctx, consumer);
263 }
264 JQP_QUERY *qp = ctx->ux->q->qp;
265 JQVAL *jqval = jql_unit_to_jqval(qp->aux, midx->expr1->right, &rc);
266 RCRET(rc);
267 switch (midx->expr1->op->value) {
268 case JQP_OP_EQ:
269 return _jbi_consume_eq(ctx, jqval, consumer);
270 case JQP_OP_IN:
271 if (jqval->type == JQVAL_JBLNODE) {
272 return _jbi_consume_in_node(ctx, jqval, consumer);
273 } else {
274 iwlog_ecode_error3(IW_ERROR_ASSERTION);
275 return IW_ERROR_ASSERTION;
276 }
277 break;
278 default:
279 break;
280 }
281
282 if ((midx->expr1->op->value == JQP_OP_GT) && (jqval->type == JQVAL_I64)) {
283 JQVAL mjqv;
284 memcpy(&mjqv, jqval, sizeof(*jqval));
285 mjqv.vi64 = mjqv.vi64 + 1; // Because for index scan we use `IWKV_CURSOR_GE`
286 return _jbi_consume_scan(ctx, &mjqv, consumer);
287 } else {
288 return _jbi_consume_scan(ctx, jqval, consumer);
289 }
290 }
291