• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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