1 #include "ejdb2_internal.h"
2
3 static_assert(IW_VNUMBUFSZ <= IWNUMBUF_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[IWNUMBUF_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[IWNUMBUF_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 RCC(rc, finish, consumer(ctx, 0, id, &step, &matched, 0));
71 }
72 } while (step && (step > 0 ? (nv = nv->next) : (nv = nv->prev)));
73
74 finish:
75 return consumer(ctx, 0, 0, 0, 0, rc);
76 }
77
_jbi_consume_scan(struct _JBEXEC * ctx,JQVAL * jqval,JB_SCAN_CONSUMER consumer)78 static iwrc _jbi_consume_scan(struct _JBEXEC *ctx, JQVAL *jqval, JB_SCAN_CONSUMER consumer) {
79 size_t sz;
80 IWKV_cursor cur;
81 char numbuf[IWNUMBUF_SIZE];
82
83 int64_t step = 1;
84 struct _JBMIDX *midx = &ctx->midx;
85 JBIDX idx = midx->idx;
86 jqp_op_t expr1_op = midx->expr1->op->value;
87
88 IWKV_val key;
89 jbi_jqval_fill_ikey(idx, jqval, &key, numbuf);
90
91 iwrc rc = iwkv_cursor_open(idx->idb, &cur, midx->cursor_init, &key);
92 if ((rc == IWKV_ERROR_NOTFOUND) && ((expr1_op == JQP_OP_LT) || (expr1_op == JQP_OP_LTE))) {
93 iwkv_cursor_close(&cur);
94 midx->cursor_init = IWKV_CURSOR_BEFORE_FIRST;
95 midx->cursor_step = IWKV_CURSOR_NEXT;
96 RCC(rc, finish, iwkv_cursor_open(idx->idb, &cur, midx->cursor_init, 0));
97 if (!midx->expr2) { // Fail fast
98 midx->expr2 = midx->expr1;
99 }
100 } else if (rc) {
101 goto finish;
102 }
103
104 IWKV_cursor_op cursor_reverse_step = (midx->cursor_step == IWKV_CURSOR_NEXT)
105 ? IWKV_CURSOR_PREV : IWKV_CURSOR_NEXT;
106
107 if (midx->cursor_init < IWKV_CURSOR_NEXT) { // IWKV_CURSOR_BEFORE_FIRST || IWKV_CURSOR_AFTER_LAST
108 RCC(rc, finish, iwkv_cursor_to(cur, midx->cursor_step));
109 }
110 do {
111 if (step > 0) {
112 --step;
113 } else if (step < 0) {
114 ++step;
115 }
116 if (!step) {
117 int64_t id;
118 bool matched = false;
119 RCC(rc, finish, iwkv_cursor_copy_val(cur, &numbuf, IW_VNUMBUFSZ, &sz));
120 if (sz > IW_VNUMBUFSZ) {
121 rc = IWKV_ERROR_CORRUPTED;
122 iwlog_ecode_error3(rc);
123 break;
124 }
125 IW_READVNUMBUF64_2(numbuf, id);
126 if ( midx->expr2
127 && !midx->expr2->prematched
128 && !jbi_node_expr_matched(ctx->ux->q->aux, midx->idx, cur, midx->expr2, &rc)) {
129 break;
130 }
131 if ( (expr1_op == JQP_OP_PREFIX)
132 && !jbi_node_expr_matched(ctx->ux->q->aux, midx->idx, cur, midx->expr1, &rc)) {
133 break;
134 }
135 RCGO(rc, finish);
136
137 step = 1;
138 RCC(rc, finish, consumer(ctx, 0, id, &step, &matched, 0));
139 if (!midx->expr1->prematched && matched && (expr1_op != JQP_OP_PREFIX)) {
140 // Further scan will always match the main index expression
141 midx->expr1->prematched = true;
142 }
143 }
144 } while (step && !(rc = iwkv_cursor_to(cur, step > 0 ? midx->cursor_step : cursor_reverse_step)));
145
146 finish:
147 if (rc == IWKV_ERROR_NOTFOUND) {
148 rc = 0;
149 }
150 if (cur) {
151 iwkv_cursor_close(&cur);
152 }
153 return consumer(ctx, 0, 0, 0, 0, rc);
154 }
155
_jbi_consume_noxpr_scan(struct _JBEXEC * ctx,JB_SCAN_CONSUMER consumer)156 iwrc _jbi_consume_noxpr_scan(struct _JBEXEC *ctx, JB_SCAN_CONSUMER consumer) {
157 iwrc rc;
158 size_t sz;
159 IWKV_cursor cur;
160 char numbuf[IWNUMBUF_SIZE];
161 int64_t step = 1;
162 struct _JBMIDX *midx = &ctx->midx;
163 IWKV_cursor_op cursor_reverse_step = (midx->cursor_step == IWKV_CURSOR_NEXT)
164 ? IWKV_CURSOR_PREV : IWKV_CURSOR_NEXT;
165
166 RCC(rc, finish, iwkv_cursor_open(midx->idx->idb, &cur, midx->cursor_init, 0));
167 if (midx->cursor_init < IWKV_CURSOR_NEXT) { // IWKV_CURSOR_BEFORE_FIRST || IWKV_CURSOR_AFTER_LAST
168 RCC(rc, finish, iwkv_cursor_to(cur, midx->cursor_step));
169 }
170 do {
171 if (step > 0) {
172 --step;
173 } else if (step < 0) {
174 ++step;
175 }
176 if (!step) {
177 int64_t id;
178 bool matched;
179 RCC(rc, finish, iwkv_cursor_copy_val(cur, &numbuf, IW_VNUMBUFSZ, &sz));
180 if (sz > IW_VNUMBUFSZ) {
181 rc = IWKV_ERROR_CORRUPTED;
182 iwlog_ecode_error3(rc);
183 break;
184 }
185 IW_READVNUMBUF64_2(numbuf, id);
186 RCGO(rc, finish);
187 step = 1;
188 RCC(rc, finish, consumer(ctx, 0, id, &step, &matched, 0));
189 }
190 } while (step && !(rc = iwkv_cursor_to(cur, step > 0 ? midx->cursor_step : cursor_reverse_step)));
191
192 finish:
193 if (rc == IWKV_ERROR_NOTFOUND) {
194 rc = 0;
195 }
196 if (cur) {
197 iwkv_cursor_close(&cur);
198 }
199 return consumer(ctx, 0, 0, 0, 0, rc);
200 }
201
jbi_uniq_scanner(struct _JBEXEC * ctx,JB_SCAN_CONSUMER consumer)202 iwrc jbi_uniq_scanner(struct _JBEXEC *ctx, JB_SCAN_CONSUMER consumer) {
203 iwrc rc;
204 struct _JBMIDX *midx = &ctx->midx;
205 if (!midx->expr1) {
206 return _jbi_consume_noxpr_scan(ctx, consumer);
207 }
208 JQP_QUERY *qp = ctx->ux->q->qp;
209 JQVAL *jqval = jql_unit_to_jqval(qp->aux, midx->expr1->right, &rc);
210 RCRET(rc);
211 switch (midx->expr1->op->value) {
212 case JQP_OP_EQ:
213 return _jbi_consume_eq(ctx, jqval, consumer);
214 case JQP_OP_IN:
215 if (jqval->type == JQVAL_JBLNODE) {
216 return _jbi_consume_in_node(ctx, jqval, consumer);
217 } else {
218 iwlog_ecode_error3(IW_ERROR_ASSERTION);
219 return IW_ERROR_ASSERTION;
220 }
221 break;
222 default:
223 break;
224 }
225 if ((midx->expr1->op->value == JQP_OP_GT) && (jqval->type == JQVAL_I64)) {
226 JQVAL mjqv;
227 memcpy(&mjqv, jqval, sizeof(*jqval));
228 mjqv.vi64 = mjqv.vi64 + 1; // Because for index scan we use `IWKV_CURSOR_GE`
229 return _jbi_consume_scan(ctx, &mjqv, consumer);
230 } else {
231 return _jbi_consume_scan(ctx, jqval, consumer);
232 }
233 }
234