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