1 #include "ejdb2_internal.h"
2
3 static_assert(IW_VNUMBUFSZ <= JBNUMBUF_SIZE, "IW_VNUMBUFSZ <= JBNUMBUF_SIZE");
4
_jbi_consume_eq(struct _JBEXEC * ctx,JQVAL * jqval,JB_SCAN_CONSUMER consumer)5 static iwrc _jbi_consume_eq(struct _JBEXEC *ctx, JQVAL *jqval, JB_SCAN_CONSUMER consumer) {
6 size_t sz;
7 uint64_t id;
8 int64_t step;
9 bool matched;
10 struct _JBMIDX *midx = &ctx->midx;
11 char numbuf[JBNUMBUF_SIZE];
12 IWKV_val key;
13
14 jbi_jqval_fill_ikey(midx->idx, jqval, &key, numbuf);
15 if (!key.size) {
16 return consumer(ctx, 0, 0, 0, 0, 0);
17 }
18 iwrc rc = iwkv_get_copy(midx->idx->idb, &key, numbuf, sizeof(numbuf), &sz);
19 if (rc) {
20 if (rc == IWKV_ERROR_NOTFOUND) {
21 return consumer(ctx, 0, 0, 0, 0, 0);
22 } else {
23 return rc;
24 }
25 }
26 IW_READVNUMBUF64_2(numbuf, id);
27 rc = consumer(ctx, 0, id, &step, &matched, 0);
28 return consumer(ctx, 0, 0, 0, 0, rc);
29 }
30
_jbi_consume_in_node(struct _JBEXEC * ctx,JQVAL * jqval,JB_SCAN_CONSUMER consumer)31 static iwrc _jbi_consume_in_node(struct _JBEXEC *ctx, JQVAL *jqval, JB_SCAN_CONSUMER consumer) {
32 JQVAL jqv;
33 size_t sz;
34 uint64_t id;
35 bool matched;
36 char numbuf[JBNUMBUF_SIZE];
37
38 iwrc rc = 0;
39 int64_t step = 1;
40 IWKV_val key;
41 struct _JBMIDX *midx = &ctx->midx;
42 JBL_NODE nv = jqval->vnode->child;
43
44 if (!nv) {
45 return consumer(ctx, 0, 0, 0, 0, 0);
46 }
47 do {
48 jql_node_to_jqval(nv, &jqv);
49 jbi_jqval_fill_ikey(midx->idx, &jqv, &key, numbuf);
50 if (!key.size) {
51 continue;
52 }
53 rc = iwkv_get_copy(midx->idx->idb, &key, numbuf, sizeof(numbuf), &sz);
54 if (rc) {
55 if (rc == IWKV_ERROR_NOTFOUND) {
56 rc = 0;
57 continue;
58 } else {
59 goto finish;
60 }
61 }
62 if (step > 0) {
63 --step;
64 } else if (step < 0) {
65 ++step;
66 }
67 if (!step) {
68 IW_READVNUMBUF64_2(numbuf, id);
69 step = 1;
70 rc = consumer(ctx, 0, id, &step, &matched, 0);
71 RCGO(rc, finish);
72 }
73 } while (step && (step > 0 ? (nv = nv->next) : (nv = nv->prev)));
74
75 finish:
76 return consumer(ctx, 0, 0, 0, 0, rc);
77 }
78
_jbi_consume_scan(struct _JBEXEC * ctx,JQVAL * jqval,JB_SCAN_CONSUMER consumer)79 static iwrc _jbi_consume_scan(struct _JBEXEC *ctx, JQVAL *jqval, JB_SCAN_CONSUMER consumer) {
80 size_t sz;
81 IWKV_cursor cur;
82 char numbuf[JBNUMBUF_SIZE];
83
84 int64_t step = 1;
85 struct _JBMIDX *midx = &ctx->midx;
86 JBIDX idx = midx->idx;
87 jqp_op_t expr1_op = midx->expr1->op->value;
88
89 IWKV_val key;
90 jbi_jqval_fill_ikey(idx, jqval, &key, numbuf);
91
92 iwrc rc = iwkv_cursor_open(idx->idb, &cur, midx->cursor_init, &key);
93 if ((rc == IWKV_ERROR_NOTFOUND) && ((expr1_op == JQP_OP_LT) || (expr1_op == JQP_OP_LTE))) {
94 iwkv_cursor_close(&cur);
95 midx->cursor_init = IWKV_CURSOR_BEFORE_FIRST;
96 midx->cursor_step = IWKV_CURSOR_NEXT;
97 rc = iwkv_cursor_open(idx->idb, &cur, midx->cursor_init, 0);
98 RCGO(rc, finish);
99 if (!midx->expr2) { // Fail fast
100 midx->expr2 = midx->expr1;
101 }
102 } else if (rc) {
103 goto finish;
104 }
105
106 IWKV_cursor_op cursor_reverse_step = (midx->cursor_step == IWKV_CURSOR_NEXT)
107 ? IWKV_CURSOR_PREV : IWKV_CURSOR_NEXT;
108
109 if (midx->cursor_init < IWKV_CURSOR_NEXT) { // IWKV_CURSOR_BEFORE_FIRST || IWKV_CURSOR_AFTER_LAST
110 rc = iwkv_cursor_to(cur, midx->cursor_step);
111 RCGO(rc, finish);
112 }
113 do {
114 if (step > 0) {
115 --step;
116 } else if (step < 0) {
117 ++step;
118 }
119 if (!step) {
120 int64_t id;
121 bool matched = false;
122 rc = iwkv_cursor_copy_val(cur, &numbuf, IW_VNUMBUFSZ, &sz);
123 RCGO(rc, finish);
124 if (sz > IW_VNUMBUFSZ) {
125 rc = IWKV_ERROR_CORRUPTED;
126 iwlog_ecode_error3(rc);
127 break;
128 }
129 IW_READVNUMBUF64_2(numbuf, id);
130 if ( midx->expr2
131 && !midx->expr2->prematched
132 && !jbi_node_expr_matched(ctx->ux->q->aux, midx->idx, cur, midx->expr2, &rc)) {
133 break;
134 }
135 if ( (expr1_op == JQP_OP_PREFIX)
136 && !jbi_node_expr_matched(ctx->ux->q->aux, midx->idx, cur, midx->expr1, &rc)) {
137 break;
138 }
139 RCGO(rc, finish);
140
141 step = 1;
142 rc = consumer(ctx, 0, id, &step, &matched, 0);
143 RCGO(rc, finish);
144 if (!midx->expr1->prematched && matched && (expr1_op != JQP_OP_PREFIX)) {
145 // Further scan will always match the main index expression
146 midx->expr1->prematched = true;
147 }
148 }
149 } while (step && !(rc = iwkv_cursor_to(cur, step > 0 ? midx->cursor_step : cursor_reverse_step)));
150
151 finish:
152 if (rc == IWKV_ERROR_NOTFOUND) {
153 rc = 0;
154 }
155 if (cur) {
156 iwkv_cursor_close(&cur);
157 }
158 return consumer(ctx, 0, 0, 0, 0, rc);
159 }
160
_jbi_consume_noxpr_scan(struct _JBEXEC * ctx,JB_SCAN_CONSUMER consumer)161 iwrc _jbi_consume_noxpr_scan(struct _JBEXEC *ctx, JB_SCAN_CONSUMER consumer) {
162 size_t sz;
163 IWKV_cursor cur;
164 char numbuf[JBNUMBUF_SIZE];
165 int64_t step = 1;
166 struct _JBMIDX *midx = &ctx->midx;
167 IWKV_cursor_op cursor_reverse_step = (midx->cursor_step == IWKV_CURSOR_NEXT)
168 ? IWKV_CURSOR_PREV : IWKV_CURSOR_NEXT;
169
170 iwrc rc = iwkv_cursor_open(midx->idx->idb, &cur, midx->cursor_init, 0);
171 RCGO(rc, finish);
172 if (midx->cursor_init < IWKV_CURSOR_NEXT) { // IWKV_CURSOR_BEFORE_FIRST || IWKV_CURSOR_AFTER_LAST
173 rc = iwkv_cursor_to(cur, midx->cursor_step);
174 RCGO(rc, finish);
175 }
176 do {
177 if (step > 0) {
178 --step;
179 } else if (step < 0) {
180 ++step;
181 }
182 if (!step) {
183 int64_t id;
184 bool matched;
185 rc = iwkv_cursor_copy_val(cur, &numbuf, IW_VNUMBUFSZ, &sz);
186 RCGO(rc, finish);
187 if (sz > IW_VNUMBUFSZ) {
188 rc = IWKV_ERROR_CORRUPTED;
189 iwlog_ecode_error3(rc);
190 break;
191 }
192 IW_READVNUMBUF64_2(numbuf, id);
193 RCGO(rc, finish);
194 step = 1;
195 rc = consumer(ctx, 0, id, &step, &matched, 0);
196 RCGO(rc, finish);
197 }
198 } while (step && !(rc = iwkv_cursor_to(cur, step > 0 ? midx->cursor_step : cursor_reverse_step)));
199
200 finish:
201 if (rc == IWKV_ERROR_NOTFOUND) {
202 rc = 0;
203 }
204 if (cur) {
205 iwkv_cursor_close(&cur);
206 }
207 return consumer(ctx, 0, 0, 0, 0, rc);
208 }
209
jbi_uniq_scanner(struct _JBEXEC * ctx,JB_SCAN_CONSUMER consumer)210 iwrc jbi_uniq_scanner(struct _JBEXEC *ctx, JB_SCAN_CONSUMER consumer) {
211 iwrc rc;
212 struct _JBMIDX *midx = &ctx->midx;
213 if (!midx->expr1) {
214 return _jbi_consume_noxpr_scan(ctx, consumer);
215 }
216 JQP_QUERY *qp = ctx->ux->q->qp;
217 JQVAL *jqval = jql_unit_to_jqval(qp->aux, midx->expr1->right, &rc);
218 RCRET(rc);
219 switch (midx->expr1->op->value) {
220 case JQP_OP_EQ:
221 return _jbi_consume_eq(ctx, jqval, consumer);
222 case JQP_OP_IN:
223 if (jqval->type == JQVAL_JBLNODE) {
224 return _jbi_consume_in_node(ctx, jqval, consumer);
225 } else {
226 iwlog_ecode_error3(IW_ERROR_ASSERTION);
227 return IW_ERROR_ASSERTION;
228 }
229 break;
230 default:
231 break;
232 }
233 if ((midx->expr1->op->value == JQP_OP_GT) && (jqval->type == JQVAL_I64)) {
234 JQVAL mjqv;
235 memcpy(&mjqv, jqval, sizeof(*jqval));
236 mjqv.vi64 = mjqv.vi64 + 1; // Because for index scan we use `IWKV_CURSOR_GE`
237 return _jbi_consume_scan(ctx, &mjqv, consumer);
238 } else {
239 return _jbi_consume_scan(ctx, jqval, consumer);
240 }
241 }
242