• 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[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