1 /* Copyright(C) 2006-2007 Brazil
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License as published by the Free Software Foundation; either
6 version 2.1 of the License, or (at your option) any later version.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Lesser General Public License for more details.
13 You should have received a copy of the GNU Lesser General Public
14 License along with this library; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 static sen_obj *nf_records(sen_ctx *ctx, sen_obj *args, sen_ql_co *co);
26 static sen_obj *nf_object(sen_ctx *ctx, sen_obj *args, sen_ql_co *co);
27 static sen_obj *nf_void(sen_ctx *ctx, sen_obj *args, sen_ql_co *co);
28 static sen_obj *nf_snip(sen_ctx *ctx, sen_obj *args, sen_ql_co *co);
30 #define SYM_DO(sym,key,block) do {\
31 if (sym->flags & SEN_INDEX_NORMALIZE) {\
33 if (!(nstr = sen_nstr_open(key, strlen(key), sym->encoding, 0))) {\
34 QLERR("nstr open failed");\
37 char *key = nstr->norm;\
40 sen_nstr_close(nstr);\
46 #define PVALUE(obj,type) ((type *)((obj)->u.p.value))
47 #define RVALUE(obj) PVALUE(obj, sen_records)
50 rec_obj_bind(sen_obj *obj, sen_records *rec, sen_id cls)
52 obj->type = sen_ql_records;
53 obj->flags = SEN_OBJ_NATIVE|SEN_OBJ_ALLOCATED;
56 obj->u.p.func = nf_records;
60 snip_obj_bind(sen_obj *obj, sen_snip *snip)
62 obj->type = sen_ql_snip;
63 obj->flags = SEN_OBJ_NATIVE|SEN_OBJ_ALLOCATED;
64 obj->u.p.value = snip;
65 obj->u.p.func = nf_snip;
69 obj_obj_bind(sen_obj *obj, sen_id cls, sen_id self)
71 obj->type = sen_ql_object;
72 obj->flags = SEN_OBJ_NATIVE;
75 obj->u.o.func = nf_object;
79 sen_ql_mk_obj(sen_ctx *ctx, sen_id cls, sen_id self)
83 obj_obj_bind(o, cls, self);
87 inline static sen_obj *
88 slot_value_obj(sen_ctx *ctx, sen_db_store *slot, sen_id id, const sen_obj *args, sen_obj *res)
91 ip = (VOIDP(args) || (PAIRP(args) && VOIDP(CAR(args))))
92 ? sen_ra_at(slot->u.o.ra, id)
93 : sen_ra_get(slot->u.o.ra, id);
94 if (!ip) { return F; }
100 if (car->class != slot->u.o.class) { return F; }
105 char *name = car->u.b.value;
106 sen_db_store *cls = sen_db_store_by_id(slot->db, slot->u.o.class);
107 if (!cls) { return F; }
108 SYM_DO(cls->u.c.keys, name, { *ip = sen_sym_get(cls->u.c.keys, name); });
112 if (*ip && VOIDP(car)) {
114 if (!(cls = sen_db_store_by_id(slot->db, slot->u.o.class))) { return F; }
115 /* todo : use sen_sym_del_with_sis if cls->u.c.keys->flags & SEN_SYM_WITH_SIS */
116 /* disable cascade delete */
117 // sen_sym_del(cls->u.c.keys, _sen_sym_key(cls->u.c.keys, *ip));
125 if (!*ip) { return F; }
126 if (!res) { SEN_OBJ_NEW(ctx, res); }
127 obj_obj_bind(res, slot->u.o.class, *ip);
131 #define STR2DBL(str,len,val) do {\
132 char *end, buf0[128], *buf = (len) < 128 ? buf0 : SEN_MALLOC((len) + 1);\
135 memcpy(buf, (str), (len));\
138 d = strtod(buf, &end);\
139 if (!((len) < 128)) { SEN_FREE(buf); }\
140 if (!errno && buf + (len) == end) {\
142 } else { QLERR("cast failed"); }\
143 } else { QLERR("buf alloc failed"); }\
146 inline static sen_obj *
147 slot_value_ra(sen_ctx *ctx, sen_db_store *slot, sen_id id, const sen_obj *args, sen_obj *res)
150 vp = (VOIDP(args) || (PAIRP(args) && VOIDP(CAR(args))))
151 ? sen_ra_at(slot->u.f.ra, id)
152 : sen_ra_get(slot->u.f.ra, id);
153 if (!vp) { return F; }
159 switch (slot->u.f.class) {
162 int64_t iv = sen_atoll(STRVALUE(car), STRVALUE(car) + car->u.b.size, NULL);
163 *(int32_t *)vp = (int32_t) iv;
166 case 2 : /* <uint> */
168 int64_t iv = sen_atoll(STRVALUE(car), STRVALUE(car) + car->u.b.size, NULL);
169 *(uint32_t *)vp = (uint32_t) iv;
172 case 3 : /* <int64> */
174 int64_t iv = sen_atoll(STRVALUE(car), STRVALUE(car) + car->u.b.size, NULL);
178 case 4 : /* <float> */
179 { /* todo : support #i notation */
180 char *str = STRVALUE(car);
181 int len = car->u.b.size;
182 STR2DBL(str, len, *(double *)vp);
185 case 8 : /* <time> */
188 if (!sen_str2timeval(STRVALUE(car), car->u.b.size, &tv)) {
189 memcpy(vp, &tv, sizeof(sen_timeval));
192 char *str = STRVALUE(car);
193 int len = car->u.b.size;
194 STR2DBL(str, len, dval);
195 tv.tv_sec = (int32_t) dval;
196 tv.tv_usec = (int32_t) ((dval - tv.tv_sec) * 1000000);
197 memcpy(vp, &tv, sizeof(sen_timeval));
202 if (car->u.b.size != slot->u.f.ra->header->element_size) { return F; }
203 memcpy(vp, car->u.b.value, car->u.b.size);
207 switch (slot->u.f.class) {
209 *(int32_t *)vp = (int32_t) IVALUE(car);
211 case 2 : /* <uint> */
212 *(uint32_t *)vp = (uint32_t) IVALUE(car);
214 case 3 : /* <int64> */
215 *(int64_t *)vp = IVALUE(car);
217 case 4 : /* <float> */
218 *(double *)vp = (double) IVALUE(car);
220 case 8 : /* <time> */
223 tv.tv_sec = (int32_t) IVALUE(car);
225 memcpy(vp, &tv, sizeof(sen_timeval));
229 if (slot->u.f.ra->header->element_size > sizeof(int64_t)) { return F; }
230 memcpy(vp, &IVALUE(car), slot->u.f.ra->header->element_size);
235 switch (slot->u.f.class) {
237 *(int32_t *)vp = (int32_t) FVALUE(car);
239 case 2 : /* <uint> */
240 *(uint32_t *)vp = (uint32_t) FVALUE(car);
242 case 3 : /* <int64> */
243 *(int64_t *)vp = (int64_t) FVALUE(car);
245 case 4 : /* <float> */
246 *(double *)vp = FVALUE(car);
248 case 8 : /* <time> */
251 tv.tv_sec = (int32_t) FVALUE(car);
252 tv.tv_usec = (int32_t) ((FVALUE(car) - tv.tv_sec) * 1000000);
253 memcpy(vp, &tv, sizeof(sen_timeval));
261 switch (slot->u.f.class) {
263 *(int32_t *)vp = (int32_t) car->u.tv.tv_usec;
265 case 2 : /* <uint> */
266 *(uint32_t *)vp = (uint32_t) car->u.tv.tv_usec;
268 case 3 : /* <int64> */
269 *(int64_t *)vp = (int64_t) car->u.tv.tv_usec;
271 case 4 : /* <float> */
272 *(double *)vp = ((double) car->u.tv.tv_usec) / 1000000 + car->u.tv.tv_sec;
274 case 8 : /* <time> */
275 memcpy(vp, &car->u.tv, sizeof(sen_timeval));
283 memset(vp, 0, slot->u.f.ra->header->element_size);
289 if (!res) { SEN_OBJ_NEW(ctx, res); }
290 switch (slot->u.f.class) {
292 SETINT(res, *(int32_t *)vp);
294 case 2 : /* <uint> */
295 SETINT(res, *(uint32_t *)vp);
297 case 3 : /* <int64> */
298 SETINT(res, *(int64_t *)vp);
300 case 4 : /* <float> */
301 SETFLOAT(res, *(double *)vp);
303 case 8 : /* <time> */
307 res->type = sen_ql_bulk;
308 res->u.b.size = slot->u.f.ra->header->element_size;
314 inline static sen_obj *
315 slot_value_ja(sen_ctx *ctx, sen_db_store *slot, sen_id id, const sen_obj *args, sen_obj *res)
319 vp = (void *)sen_ja_ref(slot->u.v.ja, id, &vs);
322 if (!vp) { return F; }
323 if (!res) { SEN_OBJ_NEW(ctx, res); }
324 res->flags = SEN_OBJ_ALLOCATED|SEN_OBJ_FROMJA;
325 res->type = sen_ql_bulk;
335 // todo : support append and so on..
337 unsigned int max_element_size;
339 nvp = car->u.b.value;
340 if (sen_ja_info(slot->u.v.ja, &max_element_size) ||
341 nvs > max_element_size) {
342 QLERR("too long value(%d) > max_element_size(%d)", nvs, max_element_size);
344 } else if (VOIDP(car)) {
348 if (vp) { sen_ja_unref(slot->u.v.ja, id, vp, vs); }
351 if (vs == nvs && (!vs || (vp && nvp && !memcmp(vp, nvp, vs)))) {
352 if (vp) { sen_ja_unref(slot->u.v.ja, id, vp, vs); }
355 for (t = slot->triggers; t; t = t->next) {
356 if (t->type == sen_db_before_update_trigger) {
357 sen_db_store *index = sen_db_store_by_id(slot->db, t->target);
358 const char *key = _sen_sym_key(index->u.i.index->keys, id);
359 if (key && sen_index_upd(index->u.i.index, key, vp, vs, nvp, nvs)) {
360 SEN_LOG(sen_log_error, "sen_index_upd failed. id=%d key=(%s) id'=%d", id, _sen_sym_key(index->u.i.index->keys, id), sen_sym_at(index->u.i.index->keys, _sen_sym_key(index->u.i.index->keys, id)));
364 if (vp) { sen_ja_unref(slot->u.v.ja, id, vp, vs); }
365 return sen_ja_put(slot->u.v.ja, id, nvp, nvs, 0) ? F : car;
369 inline static sen_obj *
370 slot_value(sen_ctx *ctx, sen_db_store *slot, sen_id obj, sen_obj *args, sen_obj *res)
372 switch (slot->type) {
373 case sen_db_obj_slot :
374 return slot_value_obj(ctx, slot, obj, args, res);
376 case sen_db_ra_slot :
377 return slot_value_ra(ctx, slot, obj, args, res);
379 case sen_db_ja_slot :
380 return slot_value_ja(ctx, slot, obj, args, res);
382 case sen_db_idx_slot :
385 const char *key = _sen_sym_key(slot->u.i.index->lexicon, obj);
386 if (!key) { return F; }
387 if (!(rec = sen_index_sel(slot->u.i.index, key, strlen(key)))) {
390 if (!res) { SEN_OBJ_NEW(ctx, res); }
391 rec_obj_bind(res, rec, slot->u.i.class);
401 inline static sen_obj *
402 int2strobj(sen_ctx *ctx, int64_t i)
405 if (sen_str_lltoa(i, buf, buf + 32, &rest)) { return NULL; }
406 return sen_ql_mk_string(ctx, buf, rest - buf);
410 str_value(sen_ctx *ctx, sen_obj *o)
412 if (o->flags & SEN_OBJ_SYMBOL) {
413 char *r = SEN_SET_STRKEY_BY_VAL(o);
414 return *r == ':' ? r + 1 : r;
415 } else if (o->type == sen_ql_bulk) {
417 } else if (o->type == sen_ql_int) {
418 sen_obj *p = int2strobj(ctx, IVALUE(o));
419 return p ? p->u.b.value : NULL;
424 inline static sen_obj *
425 obj2oid(sen_ctx *ctx, sen_obj *obj, sen_obj *res)
428 sen_rbuf bogus_buf = { /*.head = */buf, /*.curr = */buf, /*.tail = */buf + 32 };
429 if (obj->type != sen_ql_object) { return F; }
430 sen_obj_inspect(ctx, obj, &bogus_buf, SEN_OBJ_INSPECT_ESC);
432 uint32_t size = SEN_RBUF_VSIZE(&bogus_buf);
433 char *value = SEN_MALLOC(size + 1);
434 if (!value) { return F; }
435 sen_obj_clear(ctx, res);
436 res->flags = SEN_OBJ_ALLOCATED;
437 res->type = sen_ql_bulk;
438 res->u.b.size = size;
439 res->u.b.value = value;
440 memcpy(res->u.b.value, buf, res->u.b.size + 1);
442 if (!(res = sen_ql_mk_string(ctx, buf, SEN_RBUF_VSIZE(&bogus_buf)))) { return F; }
447 #define SET_KEY_VALUE(ctx,v_,o_) do {\
450 sen_db_store *cls = sen_db_store_by_id(ctx->db, o_->class);\
451 if (!cls) { QLERR("Invalid Object"); }\
452 switch (cls->type) {\
454 if (!(key = _sen_sym_key(cls->u.c.keys, o_->u.o.self))) { QLERR("Invalid Object"); }\
456 v_->type = sen_ql_bulk;\
457 v_->u.b.value = (char *)key;\
458 v_->u.b.size = strlen(key);\
461 v_->u.i.i = o_->u.o.self;\
462 v_->type = sen_ql_int;\
468 if (!(key = _sen_sym_key(ctx->db->keys, o_->u.o.self))) { QLERR("Invalid Object"); }\
470 v_->type = sen_ql_bulk;\
471 v_->u.b.value = (char *)key;\
472 v_->u.b.size = strlen(key);\
495 nf_object(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
499 sen_obj *obj, *car, *res;
500 if (!(obj = res = ctx->code)) { QLERR("invalid receiver"); }
502 if (!(msg = str_value(ctx, car))) { QLERR("invalid message"); }
507 res = obj2oid(ctx, obj, NULL);
509 case 'k' : /* :key */
511 SEN_OBJ_NEW(ctx, res);
512 SET_KEY_VALUE(ctx, res, obj);
514 case 'S' : /* :score */
517 SEN_OBJ_NEW(ctx, res);
518 (res)->type = sen_ql_int;
519 (res)->u.i.i = ((recinfo *)(ctx->currec))->score;
524 case 'N' : /* :nsubrecs */
527 SEN_OBJ_NEW(ctx, res);
528 (res)->type = sen_ql_int;
529 (res)->u.i.i = ((recinfo *)(ctx->currec))->n_subrecs;
536 if (!(slot = sen_db_class_slot(ctx->db, obj->class, msg))) {
537 QLERR("Invalid slot %s", msg);
540 res = slot_value(ctx, slot, obj->u.o.self, args, NULL);
542 if (sen_db_lock(ctx->db, -1)) {
543 SEN_LOG(sen_log_crit, "clear_all_slot_values: lock failed");
545 res = slot_value(ctx, slot, obj->u.o.self, args, NULL);
546 sen_db_unlock(ctx->db);
554 sen_ql_class_at(sen_ctx *ctx, sen_db_store *cls, const void *key, int flags, sen_obj *res)
557 SYM_DO(cls->u.c.keys, key, {
558 id = flags ? sen_sym_get(cls->u.c.keys, key) : sen_sym_at(cls->u.c.keys, key);
561 if (!res) { SEN_OBJ_NEW(ctx, res); }
562 obj_obj_bind(res, cls->id, id);
570 nf_void(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
572 if (!ctx->code) { return F; }
576 #define DEF_COMPAR_FUNC(funcname,expr) \
577 static int funcname(sen_records *ra, const sen_recordh *a, sen_records *rb, const sen_recordh *b, void *arg)\
581 sen_ra *raa = (sen_ra *)ra->userdata, *rab = (sen_ra *)rb->userdata;\
582 sen_set_element_info(ra->records, a, (void **)&pa, NULL);\
583 sen_set_element_info(rb->records, b, (void **)&pb, NULL);\
584 va = sen_ra_at(raa, *pa);\
585 vb = sen_ra_at(rab, *pb);\
597 DEF_COMPAR_FUNC(compar_ra, (memcmp(va, vb, raa->header->element_size)));
598 DEF_COMPAR_FUNC(compar_int, (*((int32_t *)va) - *((int32_t *)vb)));
599 DEF_COMPAR_FUNC(compar_uint, (*((uint32_t *)va) - *((uint32_t *)vb)));
600 DEF_COMPAR_FUNC(compar_int64, (*((int64_t *)va) - *((int64_t *)vb)));
601 DEF_COMPAR_FUNC(compar_float,
602 (isgreater(*((double *)va), *((double *)vb)) ? 1 :
603 (isless(*((double *)va), *((double *)vb)) ? -1 : 0)));
604 DEF_COMPAR_FUNC(compar_time,
605 ((((sen_timeval *)va)->tv_sec != ((sen_timeval *)vb)->tv_sec) ?
606 (((sen_timeval *)va)->tv_sec - ((sen_timeval *)vb)->tv_sec) :
607 (((sen_timeval *)va)->tv_usec - ((sen_timeval *)vb)->tv_usec)));
610 compar_ja(sen_records *ra, const sen_recordh *a, sen_records *rb, const sen_recordh *b, void *arg)
616 sen_ja *jaa = (sen_ja *)ra->userdata, *jab = (sen_ja *)rb->userdata;
617 sen_set_element_info(ra->records, a, (void **)&pa, NULL);
618 sen_set_element_info(rb->records, b, (void **)&pb, NULL);
619 va = sen_ja_ref(jaa, *pa, &la);
620 vb = sen_ja_ref(jab, *pb, &lb);
624 if (!(r = memcmp(va, vb, lb))) { r = 1; }
626 if (!(r = memcmp(va, vb, la))) { r = la == lb ? 0 : -1; }
628 sen_ja_unref(jab, *pb, vb, lb);
632 sen_ja_unref(jaa, *pa, va, la);
635 sen_ja_unref(jab, *pb, vb, lb);
645 compar_key(sen_records *ra, const sen_recordh *a, sen_records *rb, const sen_recordh *b, void *arg)
649 sen_sym *ka = ra->userdata, *kb = rb->userdata;
650 sen_set_element_info(ra->records, a, (void **)&pa, NULL);
651 sen_set_element_info(rb->records, b, (void **)&pb, NULL);
652 va = _sen_sym_key(ka, *pa);
653 vb = _sen_sym_key(kb, *pb);
654 // todo : if (key_size)..
656 return vb ? strcmp(va, vb) : 1;
662 static sen_obj sen_db_pslot_key = {
663 sen_db_pslot, SEN_OBJ_NATIVE, 0, 0, { { SEN_DB_PSLOT_FLAG, NULL } }
666 static sen_obj sen_db_pslot_id = {
667 sen_db_pslot, SEN_OBJ_NATIVE, 0, 0, { { SEN_DB_PSLOT_FLAG|SEN_DB_PSLOT_ID, NULL } }
669 static sen_obj sen_db_pslot_score = {
670 sen_db_pslot, SEN_OBJ_NATIVE, 0, 0, { { SEN_DB_PSLOT_FLAG|SEN_DB_PSLOT_SCORE, NULL } }
672 static sen_obj sen_db_pslot_nsubrecs = {
673 sen_db_pslot, SEN_OBJ_NATIVE, 0, 0, { { SEN_DB_PSLOT_FLAG|SEN_DB_PSLOT_NSUBRECS, NULL } }
676 inline static sen_obj *
677 class_slot(sen_ctx *ctx, sen_id base, char *msg, sen_records *records, int *recpslotp)
684 return &sen_db_pslot_id;
685 case 'K' : /* :key */
687 return &sen_db_pslot_key;
688 case 'S' : /* :score */
692 return &sen_db_pslot_score;
695 case 'N' : /* :nsubrecs */
699 return &sen_db_pslot_nsubrecs;
707 char buf[SEN_SYM_MAX_KEY_SIZE];
708 if (sen_db_class_slotpath(ctx->db, base, msg, buf)) {
709 QLERR("Invalid slot %s", msg);
711 if (!(slot = sen_db_store_open(ctx->db, buf))) {
712 QLERR("store open failed %s", buf);
719 slotexp_prepare(sen_ctx *ctx, sen_id base, sen_obj *e, sen_records *records)
726 for (r = NIL; PAIRP(CAR(e)); e = CAR(e)) {
727 if (PAIRP(CDR(e))) { r = CONS(CDR(e), r); }
732 if (CDR(e) != NIL) { QLERR("invalid slot expression"); }
735 r = CONS(CONS(T, NIL), r);
738 if (!(str = str_value(ctx, CAR(e)))) {
739 QLERR("invalid slotname");
743 QLERR(" ':' assigned without records");
745 base = records->subrec_id;
746 if (!(key = _sen_sym_key(ctx->db->keys, base))) { QLERR("invalid base class"); }
748 if (!CLASSP(slot)) { QLERR("invalid class"); }
749 r = CONS(CONS(slot, CDR(e)), r);
751 if ((slot = class_slot(ctx, base, str, records, &recpslotp)) == F) {
752 QLERR("invalid slot");
754 if (recpslotp) { r = slot; goto exit; }
755 r = CONS(CONS(slot, CDR(e)), r);
758 for (e = CDR(r); PAIRP(e); e = CDR(e)) {
759 if (!(str = str_value(ctx, CAAR(e))) ||
760 (slot = class_slot(ctx, base, str, records, &recpslotp)) == F) {
761 QLERR("invalid slot");
763 if (recpslotp) { r = slot; goto exit; }
764 e->u.l.car = CONS(slot, CDAR(e));
768 if (!(str = str_value(ctx, e))) {
769 QLERR("invalid expr");
771 r = class_slot(ctx, base, str, records, &recpslotp);
777 /* SET_SLOT_VALUE doesn't update slot value */
778 #define SET_SLOT_VALUE(ctx,slot,value,args,ri) do {\
779 sen_id id = (slot)->u.o.self;\
780 if (id & SEN_DB_PSLOT_FLAG) {\
781 uint8_t pslot_type = id & SEN_DB_PSLOT_MASK;\
782 switch (pslot_type) {\
783 case 0 : /* SEN_DB_PSLOT_KEY */\
784 SET_KEY_VALUE((ctx), (value), (value));\
786 case SEN_DB_PSLOT_ID :\
787 obj2oid((ctx), (value), (value));\
789 case SEN_DB_PSLOT_SCORE :\
790 (value)->type = sen_ql_int;\
791 (value)->u.i.i = (ri)->score;\
793 case SEN_DB_PSLOT_NSUBRECS :\
794 (value)->type = sen_ql_int;\
795 (value)->u.i.i = (ri)->n_subrecs;\
799 sen_db_store *dbs = sen_db_store_by_id((ctx)->db, id);\
800 value = slot_value((ctx), dbs, (value)->u.o.self, /*(args)*/ NIL, (value));\
805 slotexp_exec(sen_ctx *ctx, sen_obj *expr, sen_obj *value, recinfo *ri)
813 if (INTP(CADR(t))) { i = CADR(t)->u.i.i; }
814 obj_obj_bind(value, car->u.o.self, ri->subrecs[i].subid);
816 SET_SLOT_VALUE(ctx, car, value, CDR(t), ri);
818 } else if (SLOTP(expr)) {
819 SET_SLOT_VALUE(ctx, expr, value, NIL, ri);
821 while (value != NIL && PAIRP(expr)) {
823 if (!PAIRP(t)) { break; }
825 SET_SLOT_VALUE(ctx, car, value, CDR(t), ri);
831 ses_check(sen_obj *e, int *ns, int *ne)
839 ses_check(x, ns, ne);
843 ses_check(x, ns, ne);
846 if (SYMBOLP(e) && !KEYWORDP(e)) { (*ne)++; }
851 ses_copy(sen_ctx *ctx, sen_obj *e)
856 r = CONS(x == NIL ? &ctx->curobj : ses_copy(ctx, x), NIL);
860 *d = CONS(ses_copy(ctx, x), NIL);
870 ses_prepare(sen_ctx *ctx, sen_id base, sen_obj *e, sen_records *records)
873 ses_check(e, &ns, &ne);
875 obj_obj_bind(&ctx->curobj, base, 0);
876 return CONS(T, ns ? ses_copy(ctx, e) : e);
879 return CONS(NIL, slotexp_prepare(ctx, base, e, records));
887 ses_exec(sen_ctx *ctx, sen_obj *e, recinfo *ri, sen_obj *objs)
892 return sen_ql_eval(ctx, CDR(e), objs);
896 return slotexp_exec(ctx, CDR(e), &ctx->curobj, ri);
901 ses_clear(sen_ctx *ctx)
903 sen_obj_clear(ctx, &ctx->curobj);
909 } compar_expr_userdata;
912 compar_expr(sen_records *ra, const sen_recordh *a, sen_records *rb, const sen_recordh *b, void *arg)
915 sen_obj oa, ob, *va, *vb;
918 sen_ctx *ctx = (sen_ctx *) arg;
919 compar_expr_userdata *ceuda = (compar_expr_userdata *)ra->userdata;
920 compar_expr_userdata *ceudb = (compar_expr_userdata *)rb->userdata;
921 sen_obj *exa = ceuda->se, *exb = ceudb->se;
922 sen_set_element_info(ra->records, a, (void **)&pa, (void **)&ria);
923 sen_set_element_info(rb->records, b, (void **)&pb, (void **)&rib);
927 va = slotexp_exec(ctx, exa, &oa, ria);
928 vb = slotexp_exec(ctx, exb, &ob, rib);
930 obj_obj_bind(&ctx->curobj, ceuda->base, *pa);
931 va = ses_exec(ctx, exa, ria, exa);
932 if (va != NIL) { memcpy(&oa, va, sizeof(sen_obj)); va = &oa; }
933 obj_obj_bind(&ctx->curobj, ceudb->base, *pb);
934 vb = ses_exec(ctx, exa, rib, exb);
935 if (vb != NIL) { memcpy(&ob, vb, sizeof(sen_obj)); vb = &ob; }
938 r = (vb == NIL) ? 0 : -1;
939 } else if (vb == NIL) {
942 if (va->type != vb->type) {
943 SEN_LOG(sen_log_error, "obj type unmatch in compar_expr");
949 sen_db_store *ca, *cb;
950 if (!(ca = sen_db_store_by_id(ctx->db, va->class)) ||
951 (cb = sen_db_store_by_id(ctx->db, vb->class))) {
952 SEN_LOG(sen_log_error, "clas open failed in compar_expr");
955 const char *ka = _sen_sym_key(ca->u.c.keys, va->u.o.self);
956 const char *kb = _sen_sym_key(cb->u.c.keys, vb->u.o.self);
957 r = (ka && kb) ? strcmp(ka, kb) : 0;
963 uint32_t la = va->u.b.size, lb = vb->u.b.size;
965 if (!(r = memcmp(va->u.b.value, vb->u.b.value, lb))) { r = 1; }
967 if (!(r = memcmp(va->u.b.value, vb->u.b.value, la))) { r = la == lb ? 0 : -1; }
972 r = IVALUE(va) - IVALUE(vb);
975 if (isgreater(FVALUE(va), FVALUE(vb))) {
978 r = (isless(FVALUE(va), FVALUE(vb))) ? -1 : 0;
982 if (va->u.tv.tv_sec != vb->u.tv.tv_sec) {
983 r = va->u.tv.tv_sec - vb->u.tv.tv_sec;
985 r = va->u.tv.tv_usec - vb->u.tv.tv_usec;
989 SEN_LOG(sen_log_error, "invalid value in compar_expr");
995 sen_obj_clear(ctx, va);
996 sen_obj_clear(ctx, vb);
1001 compar_obj(sen_records *ra, const sen_recordh *a, sen_records *rb, const sen_recordh *b, void *arg)
1003 const char *va, *vb;
1004 sen_id *pa, *pb, *oa, *ob;
1005 sen_sym *key = (sen_sym *)arg;
1006 // todo : target class may not be identical
1007 sen_ra *raa = (sen_ra *)ra->userdata, *rab = (sen_ra *)rb->userdata;
1008 sen_set_element_info(ra->records, a, (void **)&pa, NULL);
1009 sen_set_element_info(rb->records, b, (void **)&pb, NULL);
1010 va = (oa = sen_ra_at(raa, *pa)) ? _sen_sym_key(key, *oa) : NULL;
1011 vb = (ob = sen_ra_at(rab, *pb)) ? _sen_sym_key(key, *ob) : NULL;
1012 // todo : if (key_size)..
1014 return vb ? strcmp(va, vb) : 1;
1021 group_obj(sen_records *ra, const sen_recordh *a, void *gkey, void *arg)
1024 sen_ra *raa = (sen_ra *)ra->userdata;
1025 sen_set_element_info(ra->records, a, (void **)&pa, NULL);
1026 if (!(oa = sen_ra_at(raa, *pa))) { return 1; }
1027 memcpy(gkey, oa, sizeof(sen_id));
1031 inline static sen_obj *
1032 rec_obj_new(sen_ctx *ctx, sen_db_store *cls, sen_rec_unit record_unit,
1033 sen_rec_unit subrec_unit, unsigned int max_n_subrecs)
1037 if (!(r = sen_records_open(record_unit, subrec_unit, max_n_subrecs))) {
1038 QLERR("sen_records_open failed");
1041 r->keys = cls->u.c.keys;
1042 SEN_OBJ_NEW(ctx, res);
1043 rec_obj_bind(res, r, cls->id);
1045 r->keys = ctx->db->keys;
1046 SEN_OBJ_NEW(ctx, res);
1047 rec_obj_bind(res, r, 0);
1053 sen_ql_native_func *func;
1056 sen_sel_operator op;
1061 slotexpp(sen_obj *expr)
1063 while (PAIRP(expr)) { expr = CAR(expr); }
1067 inline static sen_obj*
1068 match_prepare(sen_ctx *ctx, match_spec *spec, sen_id base, sen_obj *args)
1071 sen_obj *car, *expr, **ap = &spec->args, **ep = &spec->exprs;
1073 ses_check(expr, &ns, &ne);
1074 if (ne == 1 && PAIRP(expr) && NATIVE_FUNCP(CAR(expr))) {
1076 spec->func = car->u.o.func;
1077 for (*ap = NIL, *ep = NIL; POP(car, expr) != NIL; ap = &CDR(*ap)) {
1079 if (slotexpp(car)) {
1080 v = slotexp_prepare(ctx, base, car, NULL);
1081 if (ERRP(ctx, SEN_WARN)) { return F; }
1083 if (ERRP(ctx, SEN_WARN)) { return F; }
1085 v = sen_obj_new(ctx);
1087 if (ERRP(ctx, SEN_WARN)) { return F; }
1093 if (ERRP(ctx, SEN_WARN)) { return F; }
1097 spec->exprs = ses_prepare(ctx, base, expr, NULL);
1100 if (RECORDSP(expr)) {
1102 if (expr->class != base) { QLERR("class unmatch"); }
1104 spec->op = sen_sel_and;
1105 if ((ops = str_value(ctx, car))) {
1107 case '+': spec->op = sen_sel_or; break;
1108 case '-': spec->op = sen_sel_but; break;
1109 case '*': spec->op = sen_sel_and; break;
1110 case '>': spec->op = sen_sel_adjust; break;
1114 sen_db_store *cls = sen_db_store_by_id(ctx->db, base);
1115 expr = rec_obj_new(ctx, cls, sen_rec_document, sen_rec_none, 0);
1116 if (ERRP(ctx, SEN_WARN)) { return F; }
1117 spec->op = sen_sel_or;
1119 spec->objs = CONS(expr, spec->exprs);
1124 match_exec(sen_ctx *ctx, match_spec *spec, sen_id base, sen_id id)
1126 sen_obj *value, *expr, *exprs = spec->exprs, *res;
1128 while (POP(expr, exprs) != NIL) {
1130 obj_obj_bind(value, base, id);
1131 /* todo : slotexp_exec may return F */
1132 slotexp_exec(ctx, expr, value, NULL);
1134 res = spec->func(ctx, spec->args, &ctx->co);
1136 obj_obj_bind(&ctx->curobj, base, id);
1137 res = ses_exec(ctx, exprs, NULL, spec->objs);
1144 nf_records(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
1148 if (!(res = ctx->code)) { QLERR("invalid receiver"); }
1150 if (!(msg = str_value(ctx, car))) { QLERR("invalid message"); }
1152 case '\0' : /* get instance by key */
1157 if (!(name = str_value(ctx, car))) { return F; }
1158 if (ctx->code->class) {
1159 if (!(cls = sen_db_store_by_id(ctx->db, ctx->code->class))) {
1160 QLERR("class open failed");
1162 res = sen_ql_class_at(ctx, cls, name, 0, NULL);
1164 !sen_set_at(RVALUE(ctx->code)->records, &res->u.o.self, NULL)) {
1168 res = sen_ql_at(ctx, name);
1169 if (!res || !(res->flags & SEN_OBJ_NATIVE) ||
1170 !sen_set_at(RVALUE(ctx->code)->records, &res->u.o.self, NULL)) {
1178 case 'd' : /* :difference */
1181 sen_records *r = RVALUE(ctx->code);
1184 if (RECORDSP(car)) {
1185 sen_records_difference(r, RVALUE(car));
1190 case 'g' : /* :group */
1195 sen_db_store *cls, *slot;
1196 sen_group_optarg arg;
1197 sen_obj *rec = ctx->code;
1199 if (!(str = str_value(ctx, car))) { break; }
1200 if (!(slot = sen_db_class_slot(ctx->db, rec->class, str))) { break; }
1201 if (!(cls = sen_db_store_by_id(ctx->db, slot->u.o.class))) { break; }
1202 if (slot->type != sen_db_obj_slot) { break; } // todo : support others
1203 RVALUE(rec)->userdata = slot->u.o.ra;
1204 arg.mode = sen_sort_descending;
1205 arg.func = group_obj;
1206 arg.func_arg = NULL;
1207 arg.key_size = sizeof(sen_id);
1209 if (!sen_obj2int(ctx, car)) { limit = car->u.i.i; }
1211 if ((str = str_value(ctx, car)) && (*str == 'a')) {
1212 arg.mode = sen_sort_ascending;
1214 if (!sen_records_group(RVALUE(rec), limit, &arg)) {
1215 RVALUE(rec)->subrec_id = rec->class;
1216 rec->class = slot->u.o.class;
1217 RVALUE(rec)->keys = cls->u.c.keys;
1222 case 'i' : /* :intersect */
1225 sen_records *r = RVALUE(ctx->code);
1226 while (PAIRP(args)) {
1228 if (!RECORDSP(car)) { continue; }
1229 sen_records_intersect(r, RVALUE(car));
1230 car->type = sen_ql_void;
1231 car->u.o.func = nf_void;
1232 car->flags &= ~SEN_OBJ_ALLOCATED;
1236 case 'n' : /* :nrecs */
1238 SEN_OBJ_NEW(ctx, res);
1239 res->type = sen_ql_int;
1240 res->u.i.i = sen_records_nhits(RVALUE(ctx->code));
1246 case 'c' : /* :scan-select */
1250 sen_id *rid, base = ctx->code->class;
1252 res = match_prepare(ctx, &spec, base, args);
1253 if (ERRP(ctx, SEN_WARN)) { return F; }
1256 SEN_SET_EACH(RVALUE(ctx->code)->records, eh, &rid, NULL, {
1257 if (match_exec(ctx, &spec, base, *rid)) {
1258 sen_set_get(RVALUE(res)->records, rid, (void **)&ri);
1263 SEN_SET_EACH(RVALUE(res)->records, eh, &rid, &ri, {
1264 if (!sen_set_at(RVALUE(ctx->code)->records, rid, NULL) ||
1265 !match_exec(ctx, &spec, base, *rid)) {
1266 sen_set_del(RVALUE(res)->records, eh);
1271 SEN_SET_EACH(RVALUE(res)->records, eh, &rid, &ri, {
1272 if (sen_set_at(RVALUE(ctx->code)->records, rid, NULL) &&
1273 match_exec(ctx, &spec, base, *rid)) {
1274 sen_set_del(RVALUE(res)->records, eh);
1278 case sen_sel_adjust :
1279 /* todo : support it */
1284 case 'o' : /* :sort */
1289 sen_sort_optarg arg;
1290 sen_obj *rec = ctx->code;
1291 compar_expr_userdata ceud;
1293 arg.compar_arg = (void *)(intptr_t)RVALUE(rec)->record_size;
1294 arg.mode = sen_sort_descending;
1295 if ((str = str_value(ctx, CAR(args)))) {
1298 case 's' : /* :score */
1300 case 'k' : /* :key */
1302 sen_db_store *cls = sen_db_store_by_id(ctx->db, rec->class);
1304 RVALUE(rec)->userdata = cls->u.c.keys;
1305 arg.compar = compar_key;
1308 RVALUE(rec)->userdata = ctx->db->keys;
1309 arg.compar = compar_key;
1314 (void *)(intptr_t)(RVALUE(rec)->record_size + sizeof(int));
1318 sen_db_store *slot = sen_db_class_slot(ctx->db, rec->class, str);
1320 switch (slot->type) {
1321 case sen_db_ra_slot :
1322 RVALUE(rec)->userdata = slot->u.f.ra;
1323 switch (slot->u.f.class) {
1324 case 1 : /* <int> */
1325 arg.compar = compar_int;
1327 case 2 : /* <uint> */
1328 arg.compar = compar_uint;
1330 case 3 : /* <int64> */
1331 arg.compar = compar_int64;
1333 case 4 : /* <float> */
1334 arg.compar = compar_float;
1336 case 8 : /* <time> */
1337 arg.compar = compar_time;
1340 arg.compar = compar_ra;
1344 case sen_db_ja_slot :
1345 RVALUE(rec)->userdata = slot->u.v.ja;
1346 arg.compar = compar_ja;
1348 case sen_db_obj_slot :
1350 sen_db_store *cls = sen_db_store_by_id(ctx->db, slot->u.o.class);
1352 RVALUE(rec)->userdata = slot->u.o.ra;
1353 arg.compar = compar_obj;
1354 arg.compar_arg = cls->u.c.keys;
1365 se = ses_prepare(ctx, rec->class, CAR(args), RVALUE(rec));
1366 /* se = slotexp_prepare(ctx, rec->class, CAR(args), RVALUE(rec)); */
1367 if (ERRP(ctx, SEN_WARN)) { return F; }
1368 ceud.base = rec->class;
1370 RVALUE(rec)->userdata = &ceud;
1371 arg.compar = compar_expr;
1372 arg.compar_arg = ctx;
1376 if (!sen_obj2int(ctx, car)) { limit = car->u.i.i; }
1377 if (limit <= 0) { limit = RVALUE(rec)->records->n_entries; }
1379 if ((str = str_value(ctx, car)) && *str == 'a') {
1380 arg.mode = sen_sort_ascending;
1382 if (!sen_records_sort(RVALUE(rec), limit, &arg)) { res = rec; }
1385 case 'u' : /* :subtract */
1388 sen_records *r = RVALUE(ctx->code);
1389 while (PAIRP(args)) {
1391 if (!RECORDSP(car)) { continue; }
1392 sen_records_subtract(r, RVALUE(car));
1393 car->type = sen_ql_void;
1394 car->u.o.func = nf_void;
1395 car->flags &= ~SEN_OBJ_ALLOCATED;
1401 /* ambiguous message. todo : return error */
1407 case 'u' : /* :union */
1410 sen_records *r = RVALUE(ctx->code);
1411 while (PAIRP(args)) {
1413 if (!RECORDSP(car)) { continue; }
1414 sen_records_union(r, RVALUE(car));
1415 car->type = sen_ql_void;
1416 car->u.o.func = nf_void;
1417 car->flags &= ~SEN_OBJ_ALLOCATED;
1421 case '+' : /* :+ (iterator next) */
1424 sen_records *r = RVALUE(ctx->code);
1425 if (ctx->code->class) {
1427 if (res->type == sen_ql_object &&
1428 res->class == ctx->code->class &&
1429 sen_records_next(r, NULL, 0, NULL)) {
1430 sen_set_element_info(r->records, r->curr_rec, (void **)&rid, NULL);
1431 res->u.o.self = *rid;
1436 if (sen_records_next(r, NULL, 0, NULL)) {
1438 sen_set_element_info(r->records, r->curr_rec, (void **)&rid, NULL);
1439 if (!(key = _sen_sym_key(ctx->db->keys, *rid))) { QLERR("invalid key"); }
1447 case '\0' : /* : (iterator begin) */
1450 sen_records *r = RVALUE(ctx->code);
1451 sen_records_rewind(r);
1452 if (sen_records_next(r, NULL, 0, NULL)) {
1453 sen_set_element_info(r->records, r->curr_rec, (void **)&rid, NULL);
1454 if (ctx->code->class) {
1455 SEN_OBJ_NEW(ctx, res);
1456 obj_obj_bind(res, ctx->code->class, *rid);
1459 if (!(key = _sen_sym_key(ctx->db->keys, *rid))) { QLERR("invalid key"); }
1469 default : /* invalid message */
1483 clear_all_slot_values(sen_ctx *ctx, sen_id base, sen_id self)
1487 char buf[SEN_SYM_MAX_KEY_SIZE];
1488 if (sen_db_class_slotpath(ctx->db, base, "", buf)) { return; }
1489 slots = sen_sym_prefix_search(ctx->db->keys, buf);
1493 sen_obj o = { sen_ql_list, SEN_OBJ_REFERER };
1496 if (sen_db_lock(ctx->db, -1)) {
1497 SEN_LOG(sen_log_crit, "clear_all_slot_values: lock failed");
1499 SEN_SET_EACH(slots, eh, &sid, NULL, {
1500 sen_db_store *slot = sen_db_store_by_id(ctx->db, *sid);
1501 /* todo : if (!slot) error handling */
1502 if (slot && (slot->type != sen_db_idx_slot /* || virtualslot */)) {
1504 slot_value(ctx, slot, self, &o, &dummy);
1507 sen_db_unlock(ctx->db);
1509 sen_set_close(slots);
1514 #define MAXSLOTS 0x100
1517 nf_class(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
1525 if (!(res = ctx->code)) { QLERR("invalid receiver"); }
1526 base = ctx->code->u.o.self;
1527 if (!(cls = sen_db_store_by_id(ctx->db, base))) { QLERR("invalid class"); }
1528 sym = cls->u.c.keys;
1529 SEN_QL_CO_BEGIN(co);
1531 if (!(msg = str_value(ctx, car))) { QLERR("invalid message"); }
1533 case '\0' : /* get instance by key */
1537 if (!(name = str_value(ctx, car))) { return F; }
1538 res = sen_ql_class_at(ctx, cls, name, 0, NULL);
1546 case 'l' : /* :clearlock */
1549 res = *sym->lock ? T : F;
1550 sen_sym_clear_lock(sym);
1553 case 'o' : /* :common-prefix-search */
1559 if (!(name = str_value(ctx, car))) { return F; }
1560 SYM_DO(sym, name, { id = sen_sym_common_prefix_search(sym, name); });
1562 SEN_OBJ_NEW(ctx, res);
1563 obj_obj_bind(res, base, id);
1577 case 'f' : /* :def */
1583 sen_db_store_spec spec;
1585 if (!(name = str_value(ctx, car))) { return F; }
1586 if (sen_db_class_slot(ctx->db, base, name)) { return T; /* already exists */ }
1588 spec.u.s.class = car->u.o.self;
1590 spec.u.s.collection_type = 0;
1591 switch (car->type) {
1592 case sen_db_raw_class :
1594 sen_db_store *tc = sen_db_store_by_id(ctx->db, spec.u.s.class);
1595 if (!tc) { return F; }
1596 /* todo : use tc->id instead of element_size */
1597 spec.type = (tc->u.bc.element_size > 8) ? sen_db_ja_slot : sen_db_ra_slot;
1598 spec.u.s.size = tc->u.bc.element_size;
1603 spec.type = sen_db_obj_slot;
1605 case sen_db_obj_slot :
1606 case sen_db_ra_slot :
1607 case sen_db_ja_slot :
1608 spec.type = sen_db_idx_slot;
1611 /* keyword might be assigned */
1616 while (PAIRP(args)) {
1618 if (PAIRP(car)) { /* view definition */
1619 char *opt = str_value(ctx, CADR(car));
1620 if (opt && !strcmp(opt, ":match")) { /* fulltext index */
1621 spec.type = sen_db_idx_slot;
1626 if (CAR(car)->type != sen_db_class &&
1627 CAR(car)->type != sen_db_rel1) {
1628 QLERR("class must be assigned as index target");
1630 spec.u.s.class = CAR(car)->u.o.self;
1631 if (!(slotname = str_value(ctx, CADR(car))) ||
1632 !(ts = sen_db_class_slot(ctx->db, spec.u.s.class, slotname))) {
1637 sen_db_store *tc = sen_db_slot_class_by_id(ctx->db, car->u.o.self);
1638 if (!tc) { return F; }
1639 spec.u.s.class = tc->id;
1640 target = car->u.o.self;
1646 char buf[SEN_SYM_MAX_KEY_SIZE];
1647 if (sen_db_class_slotpath(ctx->db, base, name, buf)) { return F; }
1648 if (!(slot = sen_db_store_create(ctx->db, buf, &spec))) { return F; }
1649 if (spec.type == sen_db_idx_slot && target) {
1650 sen_db_store_rel_spec rs;
1651 rs.type = sen_db_index_target;
1653 sen_db_store_add_trigger(slot, &rs);
1654 sen_db_idx_slot_build(ctx->db, slot);
1656 if ((res = INTERN(buf)) != F) {
1657 sen_ql_bind_symbol(slot, res);
1662 case 'l' : /* :delete */
1668 if (!(name = str_value(ctx, car))) { return F; }
1669 SYM_DO(sym, name, { id = sen_sym_at(sym, name); });
1670 if (!id) { return F; }
1671 clear_all_slot_values(ctx, base, id);
1672 /* todo : use sen_sym_del_with_sis if sym->flags & SEN_SYM_WITH_SIS */
1673 /* todo : check foreign key constraint */
1674 SYM_DO(sym, name, { sen_sym_del(sym, name); });
1685 case 'l' : /* :load */
1693 case 'e' : /* :new */
1698 if (!(name = str_value(ctx, car))) { return F; }
1699 if (sen_db_lock(ctx->db, -1)) {
1700 SEN_LOG(sen_log_crit, "nf_class::new: lock failed");
1702 res = sen_ql_class_at(ctx, cls, name, 1, NULL);
1704 sen_obj cons, dummy;
1706 cons.type = sen_ql_list;
1707 cons.flags = SEN_OBJ_REFERER;
1709 while (PAIRP(args)) {
1711 if (!(msg = str_value(ctx, car))) { break; }
1713 if (VOIDP(car)) { break; }
1714 if (!(slot = sen_db_class_slot(ctx->db, base, msg))) { break; }
1716 slot_value(ctx, slot, res->u.o.self, &cons, &dummy);
1719 sen_db_unlock(ctx->db);
1723 case 'r' : /* :nrecs */
1726 SEN_OBJ_NEW(ctx, res);
1727 res->type = sen_ql_int;
1728 res->u.i.i = sen_sym_size(sym);
1733 /* ambiguous message. todo : return error */
1739 case 'p' : /* :prefix-search */
1744 if (!(name = str_value(ctx, car))) { return F; }
1745 res = rec_obj_new(ctx, cls, sen_rec_document, sen_rec_none, 0);
1746 if (ERRP(ctx, SEN_WARN)) { return F; }
1748 sen_sym_prefix_search_with_set(sym, name, RVALUE(res)->records);
1758 case 'a' : /* :scan-select */
1764 res = match_prepare(ctx, &spec, base, args);
1765 if (ERRP(ctx, SEN_WARN)) { return F; }
1769 sen_id id = SEN_SYM_NIL; /* maxid = sen_sym_curr_id(sym); */
1770 posinfo *pi = (posinfo *) &id;
1771 while ((id = sen_sym_next(sym, id))) {
1772 if (match_exec(ctx, &spec, base, id)) {
1773 sen_set_get(RVALUE(res)->records, pi, (void **)&ri);
1779 SEN_SET_EACH(RVALUE(res)->records, eh, &rid, &ri, {
1780 if (!match_exec(ctx, &spec, base, *rid)) {
1781 sen_set_del(RVALUE(res)->records, eh);
1786 SEN_SET_EACH(RVALUE(res)->records, eh, &rid, &ri, {
1787 if (match_exec(ctx, &spec, base, *rid)) {
1788 sen_set_del(RVALUE(res)->records, eh);
1792 case sen_sel_adjust :
1793 /* todo : support it */
1798 case 'h' : /* :schema */
1801 if (sym->flags & SEN_SYM_WITH_SIS) { res = CONS(INTERN(":sis"), res); }
1802 if (sym->flags & SEN_INDEX_NORMALIZE) { res = CONS(INTERN(":normalize"), res); }
1803 if (sym->flags & SEN_INDEX_NGRAM) { res = CONS(INTERN(":ngram"), res); }
1804 if (sym->flags & SEN_INDEX_DELIMITED) { res = CONS(INTERN(":delimited"), res); }
1806 char encstr[32] = ":";
1807 strcpy(encstr + 1, sen_enctostr(sym->encoding));
1808 res = CONS(INTERN(encstr), res);
1810 res = CONS(INTERN("ptable"),
1811 CONS(CONS(INTERN("quote"),
1812 CONS(INTERN(_sen_sym_key(ctx->db->keys, base)), NIL)), res));
1816 case 'u' : /* :suffix-search */
1821 if (!(name = str_value(ctx, car))) { return F; }
1822 res = rec_obj_new(ctx, cls, sen_rec_document, sen_rec_none, 0);
1823 if (ERRP(ctx, SEN_WARN)) { return F; }
1825 sen_sym_suffix_search_with_set(sym, name, RVALUE(res)->records);
1829 case 'l' : /* :slots */
1833 char buf[SEN_SYM_MAX_KEY_SIZE];
1835 if (!(name = str_value(ctx, car))) { name = ""; }
1836 if (sen_db_class_slotpath(ctx->db, base, name, buf)) { return F; }
1839 if (!(r = sen_records_open(sen_rec_document, sen_rec_none, 0))) {
1842 r->keys = ctx->db->keys;
1843 SEN_OBJ_NEW(ctx, res);
1844 rec_obj_bind(res, r, 0);
1846 sen_sym_prefix_search_with_set(ctx->db->keys, buf, RVALUE(res)->records);
1851 case 'u' : /* :undef */
1856 if (!(name = str_value(ctx, car))) { return F; }
1857 res = sen_db_class_del_slot(ctx->db, base, name) ? F : T;
1860 case '+' : /* :+ (iterator next) */
1864 if (res->type == sen_ql_object &&
1865 res->class == cls->id &&
1866 (id = sen_sym_next(sym, res->u.o.self))) {
1873 case '\0' : /* : (iterator begin) */
1876 id = sen_sym_next(sym, SEN_SYM_NIL);
1877 if (id == SEN_SYM_NIL) {
1880 SEN_OBJ_NEW(ctx, res);
1881 obj_obj_bind(res, cls->id, id);
1887 default : /* :slotname */
1890 res = class_slot(ctx, base, msg, NULL, &recpslotp);
1897 struct _ins_stat *stat;
1898 for (s = args, i = 0; PAIRP(s); s = CDR(s), i++) {
1900 if (!(msg = str_value(ctx, car))) { return F; }
1901 if ((s->u.l.car = class_slot(ctx, base, msg, NULL, &recpslotp)) == F) { return F; }
1903 if (!(s = sen_obj_alloc(ctx, sizeof(struct _ins_stat)))) { return F; }
1904 stat = (struct _ins_stat *)s->u.b.value; // todo : not GC safe
1906 stat->nslots = i + 1;
1909 SEN_QL_CO_WAIT(co, stat);
1910 if (BULKP(args) && args->u.b.size) {
1911 char *tokbuf[MAXSLOTS];
1913 sen_obj val, obj, cons, dummy;
1914 cons.type = sen_ql_list;
1915 cons.flags = SEN_OBJ_REFERER;
1916 cons.u.l.car = &val;
1918 val.type = sen_ql_bulk;
1919 if (sen_str_tok(args->u.b.value, args->u.b.size, '\t', tokbuf, MAXSLOTS, NULL) == stat->nslots) {
1922 if (sen_db_lock(ctx->db, -1)) {
1923 SEN_LOG(sen_log_crit, "nf_class::load lock failed");
1925 o = sen_ql_class_at(ctx, cls, args->u.b.value, 1, &obj);
1927 for (s = stat->slots, i = 1; i < stat->nslots; s = CDR(s), i++) {
1928 val.u.b.value = tokbuf[i - 1] + 1;
1929 val.u.b.size = tokbuf[i] - val.u.b.value;
1930 if (!(slot = sen_db_store_by_id(ctx->db, CAR(s)->u.o.self))) { /* todo */ }
1931 slot_value(ctx, slot, obj.u.o.self, &cons, &dummy); // todo : refine cons
1935 sen_db_unlock(ctx->db);
1939 co->mode |= SEN_CTX_TAIL;
1941 } while (!(co->mode & (SEN_CTX_HEAD|SEN_CTX_TAIL)));
1942 if ((res = sen_obj_new(ctx))) {
1943 res->type = sen_ql_int;
1944 res->u.i.i = stat->nrecs;
1953 #define REL1_GET_INSTANCE_BY_KEY(rel,key,id) do {\
1955 if (rel->u.f.class) {\
1956 sen_db_store *tcls = sen_db_store_by_id(ctx->db, rel->u.f.class);\
1957 if (!tcls || !(name = str_value(ctx, key))) {\
1960 SYM_DO(tcls->u.c.keys, name, {\
1961 id = sen_sym_at(tcls->u.c.keys, name);\
1965 switch (key->type) {\
1967 name = key->u.b.value;\
1968 id = sen_atoi(name, name + key->u.b.size, NULL);\
1980 nf_rel1(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
1985 sen_obj *args0 = args, *car, *res;
1986 if (!(res = ctx->code)) { QLERR("invalid receiver"); }
1987 base = ctx->code->u.o.self;
1988 if (!(cls = sen_db_store_by_id(ctx->db, base))) { QLERR("invalid class"); }
1990 if (!(msg = str_value(ctx, car))) { QLERR("invalid message"); }
1992 case '\0' : /* get instance by key */
1997 REL1_GET_INSTANCE_BY_KEY(cls, car, id);
1998 if (!id || !(v = (uint8_t *)sen_ra_at(cls->u.f.ra, id)) || !(*v & 1)) {
2001 res = sen_ql_mk_obj(ctx, base, id);
2010 case 'l' : /* :clearlock */
2022 case 'l' : /* :delete */
2028 REL1_GET_INSTANCE_BY_KEY(cls, car, id);
2029 if (!id || !(v = (uint8_t *)sen_ra_at(cls->u.f.ra, id)) || !(*v & 1)) {
2032 clear_all_slot_values(ctx, base, id);
2033 cls->u.f.ra->header->nrecords -= 1;
2045 case 'e' : /* :new */
2050 if (sen_db_lock(ctx->db, -1)) {
2051 SEN_LOG(sen_log_crit, "nf_rel1::new lock failed");
2053 if (cls->u.f.class) {
2055 sen_db_store *tcls = sen_db_store_by_id(ctx->db, cls->u.f.class);
2059 if ((name = str_value(ctx, car))) {
2060 res = sen_ql_class_at(ctx, tcls, name, 0, NULL);
2063 if ((v = (uint8_t *)sen_ra_get(cls->u.f.ra, id))) {
2065 cls->u.f.ra->header->nrecords += 1;
2073 id = cls->u.f.ra->header->curr_max + 1;
2074 if ((v = (uint8_t *)sen_ra_get(cls->u.f.ra, id))) {
2075 cls->u.f.ra->header->nrecords += 1;
2077 res = sen_ql_mk_obj(ctx, base, id);
2083 sen_obj cons, dummy;
2085 cons.type = sen_ql_list;
2086 cons.flags = SEN_OBJ_REFERER;
2088 while (PAIRP(args)) {
2090 if (!(msg = str_value(ctx, car))) { continue; }
2092 if (VOIDP(car)) { continue; }
2093 if (!(slot = sen_db_class_slot(ctx->db, base, msg))) { break; }
2095 slot_value(ctx, slot, res->u.o.self, &cons, &dummy);
2098 sen_db_unlock(ctx->db);
2103 case 'r' : /* :nrecs */
2106 SEN_OBJ_NEW(ctx, res);
2107 res->type = sen_ql_int;
2108 res->u.i.i = cls->u.f.ra->header->nrecords;
2114 /* ambiguous message. todo : return error */
2123 case 'c' : /* :scan-select */
2129 res = match_prepare(ctx, &spec, base, args);
2130 if (ERRP(ctx, SEN_WARN)) { return F; }
2134 sen_id id = SEN_SYM_NIL, maxid = cls->u.f.ra->header->curr_max;
2135 posinfo *pi = (posinfo *) &id;
2136 while (++id <= maxid) {
2137 if (match_exec(ctx, &spec, base, id)) {
2138 sen_set_get(RVALUE(res)->records, pi, (void **)&ri);
2144 SEN_SET_EACH(RVALUE(res)->records, eh, &rid, &ri, {
2145 if (!match_exec(ctx, &spec, base, *rid)) {
2146 sen_set_del(RVALUE(res)->records, eh);
2151 SEN_SET_EACH(RVALUE(res)->records, eh, &rid, &ri, {
2152 if (match_exec(ctx, &spec, base, *rid)) {
2153 sen_set_del(RVALUE(res)->records, eh);
2157 case sen_sel_adjust :
2158 /* todo : support it */
2164 case 'u' : /* :suffix-search is not available*/
2172 case '+' : /* :+ (iterator next) */
2175 if (res->type == sen_ql_object && res->class == cls->id) {
2177 sen_id id = res->u.o.self, maxid = cls->u.f.ra->header->curr_max;
2182 if ((v = (uint8_t *)sen_ra_at(cls->u.f.ra, id)) && (*v & 1)) { break; }
2186 } else { return F; /* cause error ? */ }
2189 case '\0' : /* : (iterator begin) */
2192 sen_id id = SEN_SYM_NIL + 1, maxid;
2193 maxid = cls->u.f.ra->header->curr_max;
2194 while (!(v = (uint8_t *)sen_ra_at(cls->u.f.ra, id)) || !(*v & 1)) {
2195 if (++id > maxid) { return F; }
2197 res = sen_ql_mk_obj(ctx, base, id);
2204 return nf_class(ctx, args0, co);
2207 inline static sen_obj *
2208 sen_obj_query(sen_ctx *ctx, const char *str, unsigned int str_len,
2209 sen_sel_operator default_op, int max_exprs, sen_encoding encoding)
2212 sen_obj *res = sen_obj_new(ctx);
2213 if (!res || !(q = sen_query_open(str, str_len, default_op, max_exprs, encoding))) {
2216 res->type = sen_ql_query;
2217 res->flags = SEN_OBJ_ALLOCATED;
2223 nf_toquery(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
2225 sen_obj *o = NULL, *s;
2228 /* TODO: operator, exprs, encoding */
2229 if (!(o = sen_obj_query(ctx, s->u.b.value, s->u.b.size, sen_sel_and, 32, ctx->encoding))) {
2230 QLERR("query_obj_new failed");
2237 nf_slot(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
2243 if (!(res = ctx->code)) { QLERR("invalid receiver"); }
2244 base = ctx->code->u.o.self;
2245 if (!(slot = sen_db_store_by_id(ctx->db, base))) { QLERR("sen_db_store_by_id failed"); }
2247 if (!(msg = str_value(ctx, car))) { QLERR("invalid message"); }
2251 if (IDX_SLOTP(ctx->code)) {
2253 sen_sel_operator op;
2256 if (!BULKP(q)) { return F; }
2257 if (!(q = sen_obj_query(ctx, q->u.b.value, q->u.b.size, sen_sel_and, 32, ctx->encoding))) {
2258 QLERR("query_obj_new failed");
2261 /* TODO: specify record unit */
2262 /* (idxslot query ((slot1 weight1) (slot2 weight2) ...) records operator+ */
2264 /* TODO: handle weights */
2266 if (RECORDSP(res)) {
2270 if ((ops = str_value(ctx, car))) {
2272 case '+': op = sen_sel_or; break;
2273 case '-': op = sen_sel_but; break;
2274 case '*': op = sen_sel_and; break;
2275 case '>': op = sen_sel_adjust; break;
2280 if (!(cls = sen_db_store_by_id(ctx->db, slot->u.i.class))) { return F; }
2281 res = rec_obj_new(ctx, cls, sen_rec_document, sen_rec_none, 0);
2282 if (ERRP(ctx, SEN_WARN)) { return F; }
2285 sen_query_exec(slot->u.i.index, PVALUE(q, sen_query), RVALUE(res), op);
2290 if (!(name = str_value(ctx, car))) { return F; }
2291 if (!(cls = sen_db_slot_class_by_id(ctx->db, base))) { return F; }
2292 res = sen_ql_class_at(ctx, cls, name, 0, NULL);
2295 slot_value(ctx, slot, res->u.o.self, args, res);
2297 if (sen_db_lock(ctx->db, -1)) {
2298 SEN_LOG(sen_log_crit, "nf_slot: lock failed");
2300 slot_value(ctx, slot, res->u.o.self, args, res);
2301 sen_db_unlock(ctx->db);
2310 case 'd' : /* :defrag */
2312 if (JA_SLOTP(ctx->code)) {
2313 int threshold = 1, nsegs;
2315 if (!sen_obj2int(ctx, car)) { threshold = car->u.i.i; }
2316 nsegs = sen_ja_defrag(slot->u.v.ja, threshold);
2317 SEN_OBJ_NEW(ctx, res);
2318 res->type = sen_ql_int;
2321 QLERR("invalid message");
2324 case 's' : /* :schema */
2328 switch (slot->type) {
2329 case sen_db_obj_slot :
2330 if (!(key = _sen_sym_key(ctx->db->keys, slot->u.o.class))) {
2331 QLERR("invalid target as obj_slot");
2333 res = CONS(INTERN(key), NIL);
2335 case sen_db_ra_slot :
2336 if (!(key = _sen_sym_key(ctx->db->keys, slot->u.f.class))) {
2337 QLERR("invalid target as ra_slot");
2339 res = CONS(INTERN(key), NIL);
2341 case sen_db_ja_slot :
2342 if (!(key = _sen_sym_key(ctx->db->keys, slot->u.v.class))) {
2343 QLERR("invalid target as ja_slot");
2345 res = CONS(INTERN(key), NIL);
2347 case sen_db_idx_slot :
2350 res = CONS(INTERN("::match"), CONS(NIL, NIL));
2351 for (t = slot->triggers; t; t = t->next) {
2352 if (t->type == sen_db_index_target) {
2353 if (!(key = _sen_sym_key(ctx->db->keys, t->target))) {
2354 QLERR("invalid target as idx_slot");
2356 res = CONS(INTERN(key), res);
2359 // todo : support multi column
2360 res = CONS(INTERN(":as"), CONS(CONS(INTERN("quote"), CONS(res, NIL)), NIL));
2364 QLERR("not supported yet");
2367 QLERR("not supported yet");
2370 QLERR("invalid slot type");
2374 char *p, buf[SEN_SYM_MAX_KEY_SIZE];
2375 strcpy(buf, _sen_sym_key(ctx->db->keys, base));
2376 if (!(p = strchr(buf, '.'))) { QLERR("invalid slotname %s", buf); }
2378 res = CONS(INTERN("::def"), CONS(INTERN(p), res));
2380 res = CONS(INTERN(buf), res);
2391 sen_ql_bind_symbol(sen_db_store *dbs, sen_obj *symbol)
2393 symbol->type = dbs->type;
2394 symbol->flags |= SEN_OBJ_NATIVE;
2395 symbol->u.o.self = dbs->id;
2396 switch (symbol->type) {
2398 symbol->u.o.func = nf_class;
2401 case sen_db_obj_slot :
2402 symbol->u.o.func = nf_slot;
2403 symbol->class = dbs->u.o.class;
2405 case sen_db_ra_slot :
2406 symbol->u.o.func = nf_slot;
2407 symbol->class = dbs->u.f.class;
2409 case sen_db_ja_slot :
2410 symbol->u.o.func = nf_slot;
2411 symbol->class = dbs->u.v.class;
2413 case sen_db_idx_slot :
2414 symbol->u.o.func = nf_slot;
2415 symbol->class = dbs->u.i.class;
2418 symbol->u.o.func = nf_rel1;
2422 symbol->u.o.func = nf_void;
2429 nf_snippet(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
2431 /* args: (width@int max_results@int cond1@list cond2@list ...) */
2432 /* cond: (keyword@bulk [opentag@bulk closetag@bulk]) */
2434 /* args: (width@int max_results@int query@query cond1@list cond2@list ...) */
2435 /* cond: (opentag@bulk closetag@bulk) */
2439 unsigned int width, max_results;
2441 if (sen_obj2int(ctx, cur)) { QLERR("snippet failed (width expected)"); }
2442 width = IVALUE(cur);
2444 if (sen_obj2int(ctx, cur)) { QLERR("snipped failed (max_result expected)"); }
2445 max_results = IVALUE(cur);
2446 if (!PAIRP(args)) { QLERR("cond expected"); }
2447 if (PAIRP(CAR(args)) || BULKP(CAR(args))) {
2448 /* FIXME: mapping */
2449 if (!(s = sen_snip_open(ctx->encoding, SEN_SNIP_NORMALIZE, width, max_results,
2450 NULL, 0, NULL, 0, (sen_snip_mapping *)-1))) {
2451 QLERR("sen_snip_open failed");
2453 SEN_OBJ_NEW(ctx, res);
2454 snip_obj_bind(res, s);
2455 while (PAIRP(args)) {
2456 char *ot = NULL, *ct = NULL;
2457 uint32_t ot_l = 0, ct_l = 0;
2462 if (PAIRP(CDR(cur)) && BULKP(CADR(cur))) {
2463 ot = sen_obj_copy_bulk_value(ctx, CADR(cur));
2464 ot_l = CADR(cur)->u.b.size;
2465 if (PAIRP(CDDR(cur)) && BULKP(CADDR(cur))) {
2466 ct = sen_obj_copy_bulk_value(ctx, CADDR(cur));
2467 ct_l = CADDR(cur)->u.b.size;
2473 if (!BULKP(kw)) { QLERR("snippet failed (invalid kw)"); }
2474 if ((sen_snip_add_cond(s, kw->u.b.value, kw->u.b.size, ot, ot_l, ct, ct_l))) {
2475 QLERR("sen_snip_add_cond failed");
2478 s->flags |= SEN_SNIP_COPY_TAG;
2479 } else if (QUERYP(CAR(args))) {
2482 unsigned int n_tags = 0;
2483 const char **opentags, **closetags;
2484 unsigned int *opentag_lens, *closetag_lens;
2485 SEN_OBJ_NEW(ctx, res);
2488 for (x = args; PAIRP(x); x = CDR(x)) { n_tags++; }
2489 if (!n_tags) { n_tags++; }
2490 if (!(opentags = SEN_MALLOC((sizeof(char *) + sizeof(unsigned int)) * 2 * n_tags))) {
2491 QLERR("malloc failed");
2493 closetags = &opentags[n_tags];
2494 opentag_lens = (unsigned int *)&closetags[n_tags];
2495 closetag_lens = &opentag_lens[n_tags];
2497 for (x = args; PAIRP(x); x = CDR(x)) {
2500 if (BULKP(CAR(cur))) {
2501 opentags[n_tags] = STRVALUE(CAR(cur));
2502 opentag_lens[n_tags] = CAR(cur)->u.b.size;
2503 if (PAIRP(CDR(cur)) && BULKP(CADR(cur))) {
2504 closetags[n_tags] = STRVALUE(CADR(cur));
2505 closetag_lens[n_tags] = CADR(cur)->u.b.size;
2514 closetags[0] = NULL;
2515 opentag_lens[0] = 0;
2516 closetag_lens[0] = 0;
2518 s = sen_query_snip(q, SEN_SNIP_NORMALIZE|SEN_SNIP_COPY_TAG, width, max_results, n_tags,
2519 opentags, opentag_lens, closetags, closetag_lens,
2520 (sen_snip_mapping *)-1);
2522 snip_obj_bind(res, s);
2524 QLERR("snippet failed. cond or query expected");
2530 nf_snip(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
2532 /* args: (str@bulk) */
2533 if (!PAIRP(args) || !BULKP(CAR(args))) { QLERR("invalid argument"); }
2536 unsigned int i, len, max_len, nresults;
2537 sen_snip *s = PVALUE(ctx->code, sen_snip);
2538 sen_obj *v, *str = CAR(args), *spc = PAIRP(CDR(args)) ? CADR(args) : NIL;
2539 if ((sen_snip_exec(s, str->u.b.value, str->u.b.size, &nresults, &max_len))) {
2540 QLERR("sen_snip_exec failed");
2542 if (sen_rbuf_init(&buf, max_len)) { QLERR("sen_rbuf_init failed"); }
2544 for (i = 0; i < nresults; i++) {
2545 if (i && spc != NIL) { sen_obj_inspect(ctx, spc, &buf, 0); }
2546 if (sen_rbuf_reserve(&buf, max_len)) {
2548 QLERR("sen_rbuf_space failed");
2550 if ((sen_snip_get_result(s, i, buf.curr, &len))) {
2552 QLERR("sen_snip_get_result failed");
2557 char *ss = str->u.b.value, *se = str->u.b.value + str->u.b.size;
2558 if (sen_substring(&ss, &se, 0, s->width, ctx->encoding)) {
2559 QLERR("sen_substring failed");
2561 sen_rbuf_write(&buf, ss, se - ss);
2563 SEN_RBUF2OBJ(ctx, &buf, v);
2569 nf_db(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
2573 sen_obj *car, *res = ctx->code;
2575 if (!(msg = str_value(ctx, car))) { return res; }
2578 case 'c' : /* :clearlock */
2582 sen_db_store *store;
2583 for (id = sen_sym_curr_id(ctx->db->keys); id; id--) {
2584 if (strchr(_sen_sym_key(ctx->db->keys, id), '.')) { continue; }
2585 if ((store = sen_db_store_by_id(ctx->db, id))) {
2586 if (store->type == sen_db_class) {
2587 sen_sym_clear_lock(store->u.c.keys);
2591 res = *ctx->db->keys->lock ? T : F;
2592 sen_db_clear_lock(ctx->db);
2595 case 'd' : /* :drop */
2598 const char *name, *slotname;
2600 char buf[SEN_SYM_MAX_KEY_SIZE];
2602 if (!(name = str_value(ctx, car))) { QLERR("Invalid argument"); }
2603 if (!(cls = sen_db_store_open(ctx->db, name)) || cls->type != sen_db_class) {
2604 QLERR("Invalid class %s", name);
2606 if (sen_db_class_slotpath(ctx->db, cls->id, "", buf)) {
2607 QLERR("class open failed %s", name);
2609 if ((slots = sen_sym_prefix_search(ctx->db->keys, buf))) {
2611 SEN_SET_EACH(slots, eh, &sid, NULL, {
2612 if ((slotname = _sen_sym_key(ctx->db->keys, *sid))) {
2613 sen_db_store_remove(ctx->db, slotname);
2616 sen_set_close(slots);
2618 sen_db_store_remove(ctx->db, name);
2621 case 'p' : /* :prefix-search */
2626 if (!(name = str_value(ctx, car))) { return F; }
2629 if (!(r = sen_records_open(sen_rec_document, sen_rec_none, 0))) {
2632 r->keys = ctx->db->keys;
2633 SEN_OBJ_NEW(ctx, res);
2634 rec_obj_bind(res, r, 0);
2636 sen_sym_prefix_search_with_set(ctx->db->keys, name, RVALUE(res)->records);
2639 SEN_SET_EACH(RVALUE(res)->records, eh, &rid, NULL, {
2640 const char *key = _sen_sym_key(ctx->db->keys, *rid);
2641 if (key && strchr(key, '.')) { sen_set_del(RVALUE(res)->records, eh); }
2646 case 't' : /* :typedef */
2651 sen_db_store_spec spec;
2652 spec.type = sen_db_class;
2654 spec.u.c.flags = SEN_INDEX_NORMALIZE|SEN_INDEX_SHARED_LEXICON;
2655 spec.u.c.encoding = ctx->encoding;
2656 spec.type = sen_db_raw_class;
2658 if (!(name = str_value(ctx, car))) { return F; }
2659 if (sen_db_store_open(ctx->db, name)) { return T; /* already exists */ }
2660 for (cdr = args; PAIRP(cdr); cdr = CDR(cdr)) {
2661 if (!sen_obj2int(ctx, CAR(cdr))) { spec.u.c.size = CAR(cdr)->u.i.i; }
2663 if (!spec.u.c.size) { return F; } /* size must be assigned */
2664 if (!(cls = sen_db_store_create(ctx->db, name, &spec))) { return F; }
2665 if ((res = INTERN(name)) != F) {
2666 sen_ql_bind_symbol(cls, res);
2670 case '+' : /* :+ (iterator next) */
2673 if (res->type == sen_db_raw_class ||
2674 res->type == sen_db_class ||
2675 res->type == sen_db_obj_slot ||
2676 res->type == sen_db_ra_slot ||
2677 res->type == sen_db_ja_slot ||
2678 res->type == sen_db_idx_slot ||
2679 res->type == sen_db_vslot ||
2680 res->type == sen_db_pslot ||
2681 res->type == sen_db_rel1 ||
2682 res->type == sen_db_rel2) {
2684 sen_id id = res->u.o.self;
2685 while ((id = sen_sym_next(ctx->db->keys, id))) {
2686 key = _sen_sym_key(ctx->db->keys, id);
2689 if (id == SEN_SYM_NIL) {
2699 case '\0' : /* : (iterator begin) */
2702 sen_id id = SEN_SYM_NIL;
2703 while ((id = sen_sym_next(ctx->db->keys, id))) {
2704 key = _sen_sym_key(ctx->db->keys, id);
2707 if (id == SEN_SYM_NIL) {
2720 nf_table(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
2724 sen_obj *car, *res = F;
2725 sen_db_store_spec spec;
2726 spec.type = sen_db_class;
2728 spec.u.c.flags = SEN_INDEX_SHARED_LEXICON;
2729 spec.u.c.encoding = ctx->encoding;
2730 while (PAIRP(args)) {
2732 switch (car->type) {
2733 case sen_db_raw_class :
2734 if (!(cls = sen_db_store_by_id(ctx->db, car->u.o.self))) { return F; }
2735 if ((spec.u.c.size = cls->u.bc.element_size) == SEN_SYM_MAX_KEY_SIZE) {
2738 if (spec.u.c.size > SEN_SYM_MAX_KEY_SIZE) { return F; }
2741 if (!(cls = sen_db_store_by_id(ctx->db, car->u.o.self))) { return F; }
2742 /* todo : support subrecs */
2743 res = rec_obj_new(ctx, cls, sen_rec_document, sen_rec_none, 0);
2744 if (ERRP(ctx, SEN_WARN)) { return F; }
2747 if ((opt = str_value(ctx, car))) {
2749 case 'd' : /* delimited */
2751 spec.u.c.flags |= SEN_INDEX_DELIMITED;
2753 case 'e' : /* euc-jp */
2755 spec.u.c.encoding = sen_enc_euc_jp;
2757 case 'k' : /* koi8r */
2759 spec.u.c.encoding = sen_enc_koi8r;
2761 case 'l' : /* latin1 */
2763 spec.u.c.encoding = sen_enc_latin1;
2768 case 'g' : /* ngram */
2770 spec.u.c.flags |= SEN_INDEX_NGRAM;
2772 case 'o' : /* normalize */
2774 spec.u.c.flags |= SEN_INDEX_NORMALIZE;
2777 QLERR("ambiguous option %s", opt);
2783 case 'j' : /* shift-jis */
2785 spec.u.c.encoding = sen_enc_sjis;
2787 case 'i' : /* with-sis */
2789 spec.u.c.flags |= SEN_SYM_WITH_SIS;
2791 case 'u' : /* surrogate-key */
2793 spec.type = sen_db_rel1;
2798 QLERR("ambiguous option %s", opt);
2801 case 'u' : /* utf8 */
2803 spec.u.c.encoding = sen_enc_utf8;
2805 case 'v' : /* view */
2809 default : /* numeric */
2810 if (sen_obj2int(ctx, car)) {
2811 /* todo : illegal option */
2813 spec.u.c.size = car->u.i.i;
2818 /* todo : invalid arg */
2822 /* todo : support anonymous class */
2827 nf_ptable(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
2831 sen_db_store_spec spec;
2832 spec.type = sen_db_class;
2834 spec.u.c.flags = SEN_INDEX_SHARED_LEXICON;
2835 spec.u.c.encoding = ctx->encoding;
2837 if (!(name = str_value(ctx, car))) { return F; }
2838 if (sen_db_store_open(ctx->db, name)) { return T; }
2839 while (PAIRP(args)) {
2841 switch (car->type) {
2842 case sen_db_raw_class :
2844 sen_db_store *cls = sen_db_store_by_id(ctx->db, car->u.o.self);
2845 if (!cls) { return F; }
2846 if ((spec.u.c.size = cls->u.bc.element_size) == SEN_SYM_MAX_KEY_SIZE) {
2849 if (spec.u.c.size > SEN_SYM_MAX_KEY_SIZE) { return F; }
2853 spec.type = sen_db_rel1;
2854 spec.u.s.class = car->u.o.self;
2858 if ((opt = str_value(ctx, car))) {
2860 case 'd' : /* delimited */
2862 spec.u.c.flags |= SEN_INDEX_DELIMITED;
2864 case 'e' : /* euc-jp */
2866 spec.u.c.encoding = sen_enc_euc_jp;
2868 case 'k' : /* koi8r */
2870 spec.u.c.encoding = sen_enc_koi8r;
2872 case 'l' : /* latin1 */
2874 spec.u.c.encoding = sen_enc_latin1;
2879 case 'g' : /* ngram */
2881 spec.u.c.flags |= SEN_INDEX_NGRAM;
2883 case 'o' : /* normalize */
2885 spec.u.c.flags |= SEN_INDEX_NORMALIZE;
2888 QLERR("ambiguous option %s", opt);
2894 case 'j' : /* shift-jis */
2896 spec.u.c.encoding = sen_enc_sjis;
2898 case 'i' : /* with-sis */
2900 spec.u.c.flags |= SEN_SYM_WITH_SIS;
2902 case 'u' : /* surrogate-key */
2904 spec.type = sen_db_rel1;
2909 QLERR("ambiguous option %s", opt);
2912 case 'u' : /* utf8 */
2914 spec.u.c.encoding = sen_enc_utf8;
2916 case 'v' : /* view */
2920 default : /* numeric */
2921 if (sen_obj2int(ctx, car)) {
2922 QLERR("illegal option");
2924 spec.u.c.size = car->u.i.i;
2929 QLERR("invalid arg");
2936 if (!(cls = sen_db_store_create(ctx->db, name, &spec))) { return F; }
2937 if ((res = INTERN(name)) != F) {
2938 sen_ql_bind_symbol(cls, res);
2945 _sen_obj_key(sen_ctx *ctx, sen_obj *obj)
2948 switch (obj->type) {
2949 case sen_ql_object :
2951 if (!(cls = sen_db_store_by_id(ctx->db, obj->class))) { return NULL; }
2952 switch (cls->type) {
2954 return _sen_sym_key(cls->u.c.keys, obj->u.o.self);
2957 /* todo : return key value when cls->u.f.class exists */
2958 sen_obj *p = int2strobj(ctx, obj->u.o.self);
2959 return p ? p->u.b.value : NULL;
2965 return _sen_sym_key(ctx->db->keys, obj->u.o.self);
2967 case sen_db_raw_class :
2969 case sen_db_obj_slot :
2970 case sen_db_ra_slot :
2971 case sen_db_ja_slot :
2972 case sen_db_idx_slot :
2973 return _sen_sym_key(ctx->db->keys, obj->u.o.self);
2979 #define flags(p) ((p)->flags)
2980 #define issymbol(p) (flags(p) & SEN_OBJ_SYMBOL)
2981 #define ismacro(p) (flags(p) & SEN_OBJ_MACRO)
2983 static void disp_j(sen_ctx *ctx, sen_obj *obj, sen_rbuf *buf);
2986 disp_j_with_format(sen_ctx *ctx, sen_obj *args, sen_rbuf *buf)
2990 switch (car->type) {
2991 case sen_ql_records :
2995 sen_obj *slots, *s, **d, *se, *v;
2996 const sen_recordh *rh;
2997 int i, o, hashp = 0, offset = 0, limit = 10;
2998 sen_records *r = RVALUE(car);
3001 if (!PAIRP(slots)) {
3002 disp_j(ctx, car, buf);
3003 if (ERRP(ctx, SEN_WARN)) { return; }
3006 if (CAR(slots) == INTERN("@")) {
3010 for (s = slots, d = &slots, o = 0; PAIRP(s); s = CDR(s), d = &CDR(*d), o = 1 - o) {
3014 se = ses_prepare(ctx, base, CAR(s), r);
3015 /* se = slotexp_prepare(ctx, base, CAR(s), r); */
3016 if (ERRP(ctx, SEN_WARN)) { return; }
3021 if (!sen_obj2int(ctx, car)) { offset = car->u.i.i; }
3023 if (!sen_obj2int(ctx, car)) { limit = car->u.i.i; }
3024 if (limit <= 0) { limit = r->records->n_entries; }
3025 sen_records_rewind(r);
3026 for (i = 0; i < offset; i++) {
3027 if (!sen_records_next(r, NULL, 0, NULL)) { break; }
3029 SEN_RBUF_PUTC(buf, '[');
3030 for (i = 0; i < limit; i++) {
3031 if (!sen_records_next(r, NULL, 0, NULL) ||
3032 !(rh = sen_records_curr_rec(r)) ||
3033 sen_set_element_info(r->records, rh, (void **)&rp, (void **)&ri)) {
3036 if (i) { SEN_RBUF_PUTS(buf, ", "); }
3037 SEN_RBUF_PUTC(buf, hashp ? '{' : '[');
3038 for (s = slots, o = 0;; o = 1 - o) {
3042 disp_j(ctx, v, buf);
3044 obj_obj_bind(&ctx->curobj, base, *rp);
3045 v = ses_exec(ctx, se, ri, slots);
3046 /* v = slotexp_exec(ctx, se, &obj, ri); */
3047 disp_j(ctx, v, buf);
3050 if (ERRP(ctx, SEN_WARN)) { return; }
3051 if (!PAIRP(s)) { break; }
3052 SEN_RBUF_PUTS(buf, (hashp && !o) ? ": " : ", ");
3054 SEN_RBUF_PUTC(buf, hashp ? '}' : ']');
3056 SEN_RBUF_PUTC(buf, ']');
3059 case sen_ql_object :
3061 sen_id id = car->u.o.self, base = car->class;
3065 if (!PAIRP(slots)) {
3066 disp_j(ctx, car, buf);
3069 if (CAR(slots) == INTERN("@")) {
3072 if (!PAIRP(slots)) {
3073 disp_j(ctx, car, buf);
3077 SEN_RBUF_PUTC(buf, hashp ? '{' : '[');
3078 for (o = 0; ; o = 1 - o) {
3081 disp_j(ctx, v, buf);
3084 se = ses_prepare(ctx, base, CAR(slots), NULL);
3085 /* se = slotexp_prepare(ctx, base, CAR(slots), NULL); */
3086 if (ERRP(ctx, SEN_WARN)) { return; }
3087 obj_obj_bind(&ctx->curobj, base, id);
3088 v = ses_exec(ctx, se, NULL, se);
3089 /* v = slotexp_exec(ctx, se, &obj, NULL); */
3090 disp_j(ctx, v, buf);
3093 if (ERRP(ctx, SEN_WARN)) { return; }
3095 if (!PAIRP(slots)) { break; }
3096 SEN_RBUF_PUTS(buf, (hashp && !o) ? ": " : ", ");
3098 SEN_RBUF_PUTC(buf, hashp ? '}' : ']');
3102 disp_j(ctx, car, buf);
3103 if (ERRP(ctx, SEN_WARN)) { return; }
3109 disp_j(sen_ctx *ctx, sen_obj *obj, sen_rbuf *buf)
3111 if (!obj || obj == NIL) {
3112 SEN_RBUF_PUTS(buf, "[]");
3113 } else if (obj == T) {
3114 SEN_RBUF_PUTS(buf, "true");
3115 } else if (obj == F) {
3116 SEN_RBUF_PUTS(buf, "false");
3118 switch (obj->type) {
3120 if (issymbol(obj) && obj != INTERN("null")) {
3121 const char *r = SEN_SET_STRKEY_BY_VAL(obj);
3122 sen_rbuf_str_esc(buf, (*r == ':') ? r + 1 : r, -1, ctx->encoding);
3124 SEN_RBUF_PUTS(buf, "null");
3127 case sen_ql_records :
3133 const sen_recordh *rh;
3134 sen_records *r = RVALUE(obj);
3135 sen_records_rewind(r);
3136 obj_obj_bind(&o, obj->class, 0);
3137 SEN_RBUF_PUTC(buf, '[');
3139 if (!sen_records_next(r, NULL, 0, NULL) ||
3140 !(rh = sen_records_curr_rec(r)) ||
3141 sen_set_element_info(r->records, rh, (void **)&rp, (void **)&ri)) {
3144 if (i) { SEN_RBUF_PUTS(buf, ", "); }
3146 disp_j(ctx, &o, buf);
3147 if (ERRP(ctx, SEN_WARN)) { return; }
3149 SEN_RBUF_PUTC(buf, ']');
3153 if (obj->u.l.car == INTERN(":")) {
3154 disp_j_with_format(ctx, obj->u.l.cdr, buf);
3155 if (ERRP(ctx, SEN_WARN)) { return; }
3156 } else if (obj->u.l.car == INTERN("@")) {
3158 SEN_RBUF_PUTC(buf, '{');
3159 for (obj = obj->u.l.cdr, o = 0;; o = 1 - o) {
3161 disp_j(ctx, obj->u.l.car, buf);
3162 if (ERRP(ctx, SEN_WARN)) { return; }
3164 if ((obj = obj->u.l.cdr) && (obj != NIL)) {
3166 SEN_RBUF_PUTS(buf, o ? ", " : ": ");
3168 SEN_RBUF_PUTS(buf, " . ");
3169 disp_j(ctx, obj, buf);
3170 if (ERRP(ctx, SEN_WARN)) { return; }
3171 SEN_RBUF_PUTC(buf, '}');
3175 SEN_RBUF_PUTC(buf, '}');
3180 SEN_RBUF_PUTC(buf, '[');
3182 disp_j(ctx, obj->u.l.car, buf);
3183 if (ERRP(ctx, SEN_WARN)) { return; }
3184 if ((obj = obj->u.l.cdr) && (obj != NIL)) {
3186 SEN_RBUF_PUTS(buf, ", ");
3188 SEN_RBUF_PUTS(buf, " . ");
3189 disp_j(ctx, obj, buf);
3190 if (ERRP(ctx, SEN_WARN)) { return; }
3191 SEN_RBUF_PUTC(buf, ']');
3195 SEN_RBUF_PUTC(buf, ']');
3201 case sen_ql_object :
3203 const char *key = _sen_obj_key(ctx, obj);
3205 sen_rbuf_str_esc(buf, key, -1, ctx->encoding);
3207 SEN_RBUF_PUTS(buf, "<LOSTKEY>");
3212 sen_obj_inspect(ctx, obj, buf, SEN_OBJ_INSPECT_ESC|SEN_OBJ_INSPECT_SYM_AS_STR);
3218 static void disp_t(sen_ctx *ctx, sen_obj *obj, sen_rbuf *buf, int *f);
3221 disp_t_with_format(sen_ctx *ctx, sen_obj *args, sen_rbuf *buf, int *f)
3225 switch (car->type) {
3226 case sen_ql_records :
3230 sen_obj *slots, *s, **d, *se, *v;
3231 const sen_recordh *rh;
3232 int i, o, hashp = 0, offset = 0, limit = 10;
3233 sen_records *r = RVALUE(car);
3236 if (!PAIRP(slots)) {
3237 disp_t(ctx, car, buf, f);
3240 if (CAR(slots) == INTERN("@")) {
3244 for (s = slots, d = &slots, o = 0; PAIRP(s); s = CDR(s), o = 1 - o) {
3246 if (s != slots) { SEN_RBUF_PUTC(buf, '\t'); *f = 1; }
3247 disp_t(ctx, CAR(s), buf, f);
3249 se = ses_prepare(ctx, base, CAR(s), r);
3250 /* se = slotexp_prepare(ctx, base, CAR(s), r); */
3251 if (ERRP(ctx, SEN_WARN)) { return ; }
3257 if (!sen_obj2int(ctx, car)) { offset = car->u.i.i; }
3259 if (!sen_obj2int(ctx, car)) { limit = car->u.i.i; }
3260 if (limit <= 0) { limit = r->records->n_entries; }
3261 sen_records_rewind(r);
3262 for (i = 0; i < offset; i++) {
3263 if (!sen_records_next(r, NULL, 0, NULL)) { break; }
3265 for (i = 0; i < limit; i++) {
3266 if (!sen_records_next(r, NULL, 0, NULL) ||
3267 !(rh = sen_records_curr_rec(r)) ||
3268 sen_set_element_info(r->records, rh, (void **)&rp, (void **)&ri)) {
3271 if (*f) { ctx->output(ctx, SEN_CTX_MORE, ctx->data.ptr); *f = 0; }
3274 obj_obj_bind(&ctx->curobj, base, *rp);
3275 v = ses_exec(ctx, se, ri, slots);
3276 /* v = slotexp_exec(ctx, t, &obj, ri); */
3277 disp_t(ctx, v, buf, f);
3279 if (!PAIRP(s)) { break; }
3280 SEN_RBUF_PUTC(buf, '\t'); *f = 1;
3285 case sen_ql_object :
3287 sen_id id = car->u.o.self, base = car->class;
3289 sen_obj *slots, *val, *v;
3291 if (!PAIRP(slots)) {
3292 disp_t(ctx, car, buf, f);
3295 if (CAR(slots) == INTERN("@")) {
3298 if (!PAIRP(slots)) {
3299 disp_t(ctx, car, buf, f);
3302 if (*f) { ctx->output(ctx, SEN_CTX_MORE, ctx->data.ptr); *f = 0; }
3303 for (o = 0, val = slots; ; o = 1 - o) {
3305 if (val != slots) { SEN_RBUF_PUTC(buf, '\t'); *f = 1; }
3306 disp_t(ctx, CAR(val), buf, f);
3309 if (!PAIRP(val)) { break; }
3312 for (o = 0, val = slots; ; o = 1 - o) {
3315 if (!PAIRP(val)) { break; }
3318 se = ses_prepare(ctx, base, CAR(val), NULL);
3319 /* se = slotexp_prepare(ctx, base, CAR(val), NULL); */
3320 if (ERRP(ctx, SEN_WARN)) { return; }
3321 obj_obj_bind(&ctx->curobj, base, id);
3322 v = ses_exec(ctx, se, NULL, se);
3323 /* v = slotexp_exec(ctx, se, &obj, NULL); */
3324 disp_t(ctx, v, buf, f);
3327 if (!PAIRP(val)) { break; }
3328 if (val != slots) { SEN_RBUF_PUTC(buf, '\t'); *f = 1; }
3334 disp_t(ctx, car, buf, f);
3340 disp_t(sen_ctx *ctx, sen_obj *obj, sen_rbuf *buf, int *f)
3342 if (!obj || obj == NIL) {
3343 SEN_RBUF_PUTS(buf, "()"); *f = 1;
3344 } else if (obj == T) {
3345 SEN_RBUF_PUTS(buf, "#t"); *f = 1;
3346 } else if (obj == F) {
3347 SEN_RBUF_PUTS(buf, "#f"); *f = 1;
3349 switch (obj->type) {
3350 case sen_ql_records :
3356 const sen_recordh *rh;
3357 sen_records *r = RVALUE(obj);
3358 sen_records_rewind(r);
3359 obj_obj_bind(&o, obj->class, 0);
3361 if (!sen_records_next(r, NULL, 0, NULL) ||
3362 !(rh = sen_records_curr_rec(r)) ||
3363 sen_set_element_info(r->records, rh, (void **)&rp, (void **)&ri)) {
3367 if (*f) { ctx->output(ctx, SEN_CTX_MORE, ctx->data.ptr); *f = 0; }
3368 disp_t(ctx, &o, buf, f);
3373 if (obj->u.l.car == INTERN(":")) {
3374 disp_t_with_format(ctx, obj->u.l.cdr, buf, f);
3375 } else if (obj->u.l.car == INTERN("@")) {
3377 sen_obj *val = obj->u.l.cdr;
3378 for (o0 = 0; o0 <= 1; o0++) {
3379 if (*f) { ctx->output(ctx, SEN_CTX_MORE, ctx->data.ptr); *f = 0; }
3380 for (obj = val, o = o0;; o = 1 - o) {
3381 if (!o) { disp_t(ctx, obj->u.l.car, buf, f); }
3382 if ((obj = obj->u.l.cdr) && (obj != NIL)) {
3384 if (!o && PAIRP(CDR(obj))) { SEN_RBUF_PUTC(buf, '\t'); *f = 1; }
3387 SEN_RBUF_PUTC(buf, '\t'); *f = 1; /* dot pair */
3388 disp_t(ctx, obj, buf, f);
3399 disp_t(ctx, obj->u.l.car, buf, f);
3400 if ((obj = obj->u.l.cdr) && (obj != NIL)) {
3402 SEN_RBUF_PUTC(buf, '\t'); *f = 1;
3404 SEN_RBUF_PUTC(buf, '\t'); *f = 1; /* dot pair */
3405 disp_t(ctx, obj, buf, f);
3415 sen_obj_inspect(ctx, obj, buf, 0); *f = 1;
3422 nf_disp(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
3429 if ((str = str_value(ctx, fmt))) {
3431 case 'j' : /* json */
3433 disp_j(ctx, val, &ctx->outbuf);
3435 if (ERRP(ctx, SEN_WARN)) { return F; }
3437 case 's' : /* sexp */
3440 case 't' : /* tsv */
3442 disp_t(ctx, val, &ctx->outbuf, &f);
3443 if (ERRP(ctx, SEN_WARN)) { return F; }
3445 case 'x' : /* xml */
3450 QLERR("Few arguments");
3453 ctx->output(ctx, SEN_CTX_MORE, ctx->data.ptr);
3454 if (ERRP(ctx, SEN_WARN)) { return F; }
3460 sen_encoding encoding;
3465 inline static sen_obj *
3466 mk_atom(sen_ctx *ctx, char *str, unsigned int len)
3468 const char *cur, *str_end = str + len;
3469 int64_t ivalue = sen_atoll(str, str_end, &cur);
3470 if (cur == str_end) {
3472 SEN_OBJ_NEW(ctx, x);
3478 if (len == 4 && !memcmp(str, "true", 4)) { return T; }
3481 if (len == 5 && !memcmp(str, "false", 5)) { return F; }
3485 if (len == 4 && !memcmp(str, "null", 4)) { return NIL; }
3489 if (0 < len && len < SEN_SYM_MAX_KEY_SIZE - 1) {
3490 char buf[SEN_SYM_MAX_KEY_SIZE];
3491 memcpy(buf, str, len);
3500 json_readstr(sen_ctx *ctx, jctx *jc)
3503 for (start = end = jc->cur;;) {
3505 /* null check and length check */
3506 if (!(len = sen_str_charlen_nonnull(end, jc->str_end, jc->encoding))) {
3507 jc->cur = jc->str_end;
3510 if (sen_isspace(end, jc->encoding)
3511 || *end == ':' || *end == ','
3512 || *end == '[' || *end == '{'
3513 || *end == ']' || *end == '}') {
3519 if (start < end || jc->cur < jc->str_end) {
3520 return mk_atom(ctx, start, end - start);
3527 json_readstrexp(sen_ctx *ctx, jctx *jc)
3530 char *start, *src, *dest;
3531 for (start = src = dest = jc->cur;;) {
3533 /* null check and length check */
3534 if (!(len = sen_str_charlen_nonnull(src, jc->str_end, jc->encoding))) {
3535 jc->cur = jc->str_end;
3537 res = sen_ql_mk_string(ctx, start, dest - start);
3538 return res ? res : F;
3542 if (src[0] == '"' && len == 1) {
3544 res = sen_ql_mk_string(ctx, start, dest - start);
3545 return res ? res : F;
3546 } else if (src[0] == '\\' && src + 1 < jc->str_end && len == 1) {
3550 while (len--) { *dest++ = *src++; }
3556 json_read(sen_ctx *ctx, jctx *jc)
3560 if (jc->cur >= jc->str_end) { return NULL; }
3565 sen_obj *o, *r = NIL, **p = &r;
3566 while ((o = json_read(ctx, jc)) && o != F) {
3568 if (ERRP(ctx, SEN_WARN)) { return F; }
3576 sen_obj *o, *r = CONS(INTERN("@"), NIL), **p = &(CDR(r));
3577 while ((o = json_read(ctx, jc)) && o != F) {
3579 if (ERRP(ctx, SEN_WARN)) { return F; }
3596 return json_readstrexp(ctx, jc);
3598 return json_readstr(ctx, jc);
3604 nf_json_read(sen_ctx *ctx, sen_obj *args, sen_ql_co *co)
3607 POP(car, args); // todo : delete when called with (())
3611 jc.encoding = ctx->encoding;
3612 jc.cur = car->u.b.value;
3613 jc.str_end = car->u.b.value + car->u.b.size;
3614 if ((r = json_read(ctx, &jc))) { return r; }
3620 sen_ql_def_db_funcs(sen_ctx *ctx)
3622 sen_ql_def_native_func(ctx, "<db>", nf_db);
3623 sen_ql_def_native_func(ctx, "table", nf_table);
3624 sen_ql_def_native_func(ctx, "ptable", nf_ptable);
3625 sen_ql_def_native_func(ctx, "snippet", nf_snippet);
3626 sen_ql_def_native_func(ctx, "disp", nf_disp);
3627 sen_ql_def_native_func(ctx, "json-read", nf_json_read);
3628 sen_ql_def_native_func(ctx, "x->query", nf_toquery);