00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "oql_p.h"
00026
00027 #define RS(r) (r ? "r" : "")
00028 #define CHECK_TYPE(X) oqml_check_sort_type(node, (X)->type)
00029
00030
00031
00032
00033
00034
00035
00036 namespace eyedb {
00037
00038 oqmlStatus *
00039 oqml_check_sort_type(oqmlNode *node, oqmlAtomType &type, const char *msg)
00040 {
00041 if (type.type != oqmlATOM_INT &&
00042 type.type != oqmlATOM_STRING &&
00043 type.type != oqmlATOM_DOUBLE &&
00044 type.type != oqmlATOM_CHAR &&
00045 type.type != oqmlATOM_NULL)
00046 return new oqmlStatus(node, (msg ? msg :
00047 "a collection of integer, string, "
00048 "double or character is expected, got %s"),
00049 type.getString());
00050
00051 return oqmlSuccess;
00052 }
00053
00054 static void
00055 oqml_sort_realize(oqmlAtom **array, int array_cnt, oqmlBool reverse,
00056 oqmlAtomList **alist)
00057 {
00058 *alist = new oqmlAtomList();
00059
00060 if (reverse)
00061 {
00062 for (int n = array_cnt - 1; n >= 0; n--)
00063 (*alist)->append(array[n]);
00064
00065 free(array);
00066 return;
00067 }
00068
00069 for (int n = 0; n < array_cnt; n++)
00070 (*alist)->append(array[n]);
00071
00072 free(array);
00073 }
00074
00075 #define CHECK_NULL(LEFT, RIGHT) \
00076 if ((LEFT)->as_null() && (RIGHT)->as_null()) \
00077 return 0; \
00078 if ((LEFT)->as_null())\
00079 return -1;\
00080 if ((RIGHT)->as_null())\
00081 return 1
00082
00083 static int
00084 oqml_sort_int(const void *x1, const void *x2)
00085 {
00086 oqmlAtom *aleft = *(oqmlAtom **)x1;
00087 oqmlAtom *aright = *(oqmlAtom **)x2;
00088
00089 CHECK_NULL(aleft, aright);
00090 return (OQML_ATOM_INTVAL(aleft) - OQML_ATOM_INTVAL(aright));
00091 }
00092
00093 static int
00094 oqml_sort_string(const void *x1, const void *x2)
00095 {
00096 oqmlAtom *aleft = *(oqmlAtom **)x1;
00097 oqmlAtom *aright = *(oqmlAtom **)x2;
00098
00099 CHECK_NULL(aleft, aright);
00100 return strcmp(OQML_ATOM_STRVAL(aleft), OQML_ATOM_STRVAL(aright));
00101 }
00102
00103 static int
00104 oqml_sort_double(const void *x1, const void *x2)
00105 {
00106 oqmlAtom *aleft = *(oqmlAtom **)x1;
00107 oqmlAtom *aright = *(oqmlAtom **)x2;
00108
00109 CHECK_NULL(aleft, aright);
00110 return (OQML_ATOM_DBLVAL(aleft) - OQML_ATOM_DBLVAL(aright));
00111 }
00112
00113 static int
00114 oqml_sort_char(const void *x1, const void *x2)
00115 {
00116 oqmlAtom *aleft = *(oqmlAtom **)x1;
00117 oqmlAtom *aright = *(oqmlAtom **)x2;
00118
00119 CHECK_NULL(aleft, aright);
00120 return (OQML_ATOM_CHARVAL(aleft) - OQML_ATOM_CHARVAL(aright));
00121 }
00122
00123 oqmlAtom **
00124 oqml_make_array(oqmlAtomList *list, int &cnt)
00125 {
00126 oqmlAtom **array = idbNewVect(oqmlAtom *, list->cnt);
00127 oqmlAtom *atom = list->first;
00128
00129 for (cnt = 0; atom; cnt++)
00130 {
00131 array[cnt] = atom;
00132 atom = atom->next;
00133 }
00134
00135 return array;
00136 }
00137
00138 static oqmlStatus *
00139 checkTypes(oqmlNode *node, oqmlAtomList *list, oqmlATOMTYPE &atom_type)
00140 {
00141 oqmlAtom *atom = OQML_ATOM_COLLVAL(list->first)->first;
00142
00143 if (!atom)
00144 return oqmlSuccess;
00145
00146 atom_type = (oqmlATOMTYPE)0;
00147
00148 while (atom)
00149 {
00150 CHECK_TYPE(atom);
00151
00152 if (!atom_type)
00153 {
00154 if (atom->type.type != oqmlATOM_NULL)
00155 atom_type = atom->type.type;
00156 }
00157 else if (atom->type.type != oqmlATOM_NULL &&
00158 atom_type != atom->type.type)
00159 return new oqmlStatus(node, "atom types in collection "
00160 "are no homogeneous");
00161 atom = atom->next;
00162 }
00163
00164 if (atom_type)
00165 {
00166 oqmlAtomType at(atom_type);
00167 oqmlStatus *s = oqml_check_sort_type(node, at);
00168 if (s) return s;
00169 }
00170
00171 return oqmlSuccess;
00172 }
00173
00174 void
00175 oqml_sort_simple(oqmlAtomList *ilist, oqmlBool reverse,
00176 oqmlATOMTYPE atom_type, oqmlAtomList **alist)
00177 {
00178 oqmlAtom **array;
00179 int array_cnt, n;
00180
00181 array = oqml_make_array(ilist, array_cnt);
00182
00183 if (atom_type == oqmlATOM_INT)
00184 qsort(array, array_cnt, sizeof(oqmlAtom *), oqml_sort_int);
00185 else if (atom_type == oqmlATOM_STRING)
00186 qsort(array, array_cnt, sizeof(oqmlAtom *), oqml_sort_string);
00187 else if (atom_type == oqmlATOM_DOUBLE)
00188 qsort(array, array_cnt, sizeof(oqmlAtom *), oqml_sort_double);
00189 else if (atom_type == oqmlATOM_CHAR)
00190 qsort(array, array_cnt, sizeof(oqmlAtom *), oqml_sort_char);
00191
00192
00193 oqml_sort_realize(array, array_cnt, reverse, alist);
00194 }
00195
00196
00197
00198
00199
00200
00201
00202 oqmlSort::oqmlSort(oqml_List *_list, oqmlBool _reverse) :
00203 oqmlXSort(oqmlSORT, _list, _reverse)
00204 {
00205 }
00206
00207 oqmlSort::~oqmlSort()
00208 {
00209 }
00210
00211 oqmlStatus *oqmlSort::compile(Database *db, oqmlContext *ctx)
00212 {
00213 if (!xlist || xlist->cnt < 1)
00214 return new oqmlStatus(this, "one argument expected");
00215
00216 tosort = xlist->first->ql;
00217
00218 if (xlist->cnt != 1) return new oqmlStatus(this, "one argument expected");
00219
00220 return tosort->compile(db, ctx);
00221 }
00222
00223 oqmlStatus *oqmlSort::eval(Database *db, oqmlContext *ctx,
00224 oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00225 {
00226 oqmlStatus *s;
00227 oqmlAtomList *list;
00228 int n;
00229
00230 s = tosort->eval(db, ctx, &list);
00231
00232 if (s) return s;
00233
00234 if (list->cnt != 1 || !OQML_IS_COLL(list->first))
00235 return new oqmlStatus(this, "collection expected");
00236
00237 oqmlATOMTYPE atom_type;
00238 s = checkTypes(this, list, atom_type);
00239 if (s) return s;
00240
00241 oqmlAtomList *ylist;
00242 oqml_sort_simple(OQML_ATOM_COLLVAL(list->first), reverse, atom_type, &ylist);
00243 *alist = new oqmlAtomList(new oqmlAtom_list(ylist));
00244 return oqmlSuccess;
00245 }
00246
00247 void oqmlSort::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00248 {
00249 *at = eval_type;
00250 }
00251
00252 oqmlBool oqmlSort::isConstant() const
00253 {
00254 return tosort->isConstant();
00255 }
00256
00257 std::string
00258 oqmlSort::toString(void) const
00259 {
00260 return (reverse ? std::string("rsort(") : std::string("sort(")) +
00261 (tosort ? tosort->toString() : std::string("")) + ")" + oqml_isstat();
00262 }
00263
00264
00265
00266
00267
00268
00269
00270 struct oqmlAtomPair {
00271 oqmlAtom *list;
00272 oqmlAtom *atom;
00273 };
00274
00275 static int
00276 oqml_isort_int(const void *x1, const void *x2)
00277 {
00278 oqmlAtomPair *ap1 = (oqmlAtomPair *)x1;
00279 oqmlAtomPair *ap2 = (oqmlAtomPair *)x2;
00280
00281 CHECK_NULL(ap1->atom, ap2->atom);
00282 return (OQML_ATOM_INTVAL(ap1->atom) - OQML_ATOM_INTVAL(ap2->atom));
00283 }
00284
00285 static int
00286 oqml_isort_string(const void *x1, const void *x2)
00287 {
00288 oqmlAtomPair *ap1 = (oqmlAtomPair *)x1;
00289 oqmlAtomPair *ap2 = (oqmlAtomPair *)x2;
00290
00291 CHECK_NULL(ap1->atom, ap2->atom);
00292 return strcmp(OQML_ATOM_STRVAL(ap1->atom), OQML_ATOM_STRVAL(ap2->atom));
00293 }
00294
00295 static int
00296 oqml_isort_double(const void *x1, const void *x2)
00297 {
00298 oqmlAtomPair *ap1 = (oqmlAtomPair *)x1;
00299 oqmlAtomPair *ap2 = (oqmlAtomPair *)x2;
00300
00301 CHECK_NULL(ap1->atom, ap2->atom);
00302 return (OQML_ATOM_DBLVAL(ap1->atom) - OQML_ATOM_DBLVAL(ap2->atom));
00303 }
00304
00305 static int
00306 oqml_isort_char(const void *x1, const void *x2)
00307 {
00308 oqmlAtomPair *ap1 = (oqmlAtomPair *)x1;
00309 oqmlAtomPair *ap2 = (oqmlAtomPair *)x2;
00310
00311 CHECK_NULL(ap1->atom, ap2->atom);
00312 return (OQML_ATOM_CHARVAL(ap1->atom) - OQML_ATOM_CHARVAL(ap2->atom));
00313 }
00314
00315 static oqmlAtom *
00316 oqml_get_atom(oqmlAtom *atom_list, int idx)
00317 {
00318 oqmlAtomList *list = OQML_ATOM_COLLVAL(atom_list);
00319 oqmlAtom *atom = list->first;
00320
00321 for (int i = 0; atom; i++)
00322 {
00323 if (i == idx)
00324 return atom;
00325 atom = atom->next;
00326 }
00327
00328 return 0;
00329 }
00330
00331 oqmlAtomPair *
00332 oqml_make_array(oqmlAtomList *list, int &cnt, int idx)
00333 {
00334 oqmlAtomPair *array = idbNewVect(oqmlAtomPair, list->cnt);
00335 oqmlAtom *atom = list->first;
00336
00337 for (cnt = 0; atom; cnt++)
00338 {
00339 if (!OQML_IS_COLL(atom))
00340 break;
00341 array[cnt].list = atom;
00342 array[cnt].atom = oqml_get_atom(atom, idx);
00343 atom = atom->next;
00344 }
00345
00346 return array;
00347 }
00348
00349 static void
00350 oqml_sort_realize(oqmlAtomPair *array, int array_cnt, oqmlBool reverse,
00351 oqmlAtomList **alist)
00352 {
00353 *alist = new oqmlAtomList();
00354
00355 if (reverse)
00356 {
00357 for (int n = array_cnt - 1; n >= 0; n--)
00358 (*alist)->append(array[n].list);
00359
00360 free(array);
00361 return;
00362 }
00363
00364 for (int n = 0; n < array_cnt; n++)
00365 (*alist)->append(array[n].list);
00366
00367 free(array);
00368 }
00369
00370 void
00371 oqml_sort_list(oqmlAtomList *ilist, oqmlBool reverse, int idx,
00372 oqmlATOMTYPE atom_type, oqmlAtomList **alist)
00373 {
00374 oqmlAtomPair *array;
00375 int array_cnt, n;
00376
00377 array = oqml_make_array(ilist, array_cnt, idx);
00378
00379 if (atom_type == oqmlATOM_INT)
00380 qsort(array, array_cnt, sizeof(oqmlAtomPair), oqml_isort_int);
00381 else if (atom_type == oqmlATOM_STRING)
00382 qsort(array, array_cnt, sizeof(oqmlAtomPair), oqml_isort_string);
00383 else if (atom_type == oqmlATOM_DOUBLE)
00384 qsort(array, array_cnt, sizeof(oqmlAtomPair), oqml_isort_double);
00385 else if (atom_type == oqmlATOM_CHAR)
00386 qsort(array, array_cnt, sizeof(oqmlAtomPair), oqml_isort_char);
00387 else
00388 abort();
00389
00390 oqml_sort_realize(array, array_cnt, reverse, alist);
00391 }
00392
00393 static oqmlStatus *
00394 checkTypes(oqmlNode *node, oqmlAtomList *list, int idx, oqmlATOMTYPE &atom_type)
00395 {
00396 oqmlAtom *atom = OQML_ATOM_COLLVAL(list->first)->first;
00397
00398 if (!atom)
00399 return oqmlSuccess;
00400
00401 atom_type = (oqmlATOMTYPE)0;
00402
00403 while (atom)
00404 {
00405 if (!OQML_IS_LIST(atom) && !OQML_IS_ARRAY(atom))
00406 return new oqmlStatus(node, "a collection of lists or arrays "
00407 "was expected");
00408
00409 if (OQML_ATOM_COLLVAL(atom)->cnt <= idx)
00410 return new oqmlStatus(node, "index '%d' too large "
00411 "for collection", idx);
00412
00413 oqmlAtom *x = OQML_ATOM_COLLVAL(atom)->first;
00414
00415 for (int i = 0; x; x = x->next, i++)
00416 if (i == idx)
00417 {
00418 CHECK_TYPE(x);
00419 if (!atom_type)
00420 {
00421 atom_type = x->type.type;
00422 break;
00423 }
00424
00425 if (atom_type != x->type.type)
00426 return new oqmlStatus(node, "atom types at index %d "
00427 "in list or array are not homogeneous",
00428 idx);
00429 }
00430
00431 atom = atom->next;
00432 }
00433
00434 if (atom_type)
00435 {
00436 oqmlAtomType at(atom_type);
00437 oqmlStatus *s = oqml_check_sort_type(node, at);
00438 if (s) return s;
00439 }
00440
00441 return oqmlSuccess;
00442 }
00443
00444
00445
00446
00447
00448
00449
00450 oqmlISort::oqmlISort(oqml_List *_list, oqmlBool _reverse) :
00451 oqmlXSort(oqmlISORT, _list, _reverse)
00452 {
00453 idxnode = 0;
00454 }
00455
00456 oqmlISort::~oqmlISort()
00457 {
00458 }
00459
00460 oqmlStatus *oqmlISort::compile(Database *db, oqmlContext *ctx)
00461 {
00462 if (!xlist || xlist->cnt < 1)
00463 return new oqmlStatus(this, "two arguments expected");
00464
00465 tosort = xlist->first->ql;
00466
00467 if (xlist->cnt < 2) return new oqmlStatus(this, "two arguments expected");
00468 idxnode = xlist->first->next->ql;
00469
00470 if (xlist->cnt != 2) return new oqmlStatus(this, "two arguments expected");
00471
00472 oqmlStatus *s = tosort->compile(db, ctx);
00473 if (s) return s;
00474
00475 return idxnode->compile(db, ctx);
00476 }
00477
00478 oqmlStatus *oqmlISort::eval(Database *db, oqmlContext *ctx,
00479 oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00480 {
00481 oqmlStatus *s;
00482 oqmlAtomList *list;
00483
00484 s = tosort->eval(db, ctx, &list);
00485 if (s) return s;
00486
00487 if (list->cnt != 1 || !OQML_IS_COLL(list->first))
00488 return new oqmlStatus(this, "first argument: collection expected");
00489
00490 oqmlAtomList *idxlist;
00491 s = idxnode->eval(db, ctx, &idxlist);
00492 if (s) return s;
00493
00494 if (idxlist->cnt != 1 || !OQML_IS_INT(idxlist->first))
00495 return new oqmlStatus(this, "second argument: integer expected");
00496
00497 int idx = OQML_ATOM_INTVAL(idxlist->first);
00498
00499 if (idx < 0)
00500 return new oqmlStatus(this, "second argument: "
00501 "positive integer expected");
00502
00503 oqmlATOMTYPE atom_type;
00504 s = checkTypes(this, list, idx, atom_type);
00505 if (s) return s;
00506
00507 oqmlAtomList *ylist;
00508 oqml_sort_list(OQML_ATOM_COLLVAL(list->first), reverse, idx,
00509 atom_type, &ylist);
00510 *alist = new oqmlAtomList(new oqmlAtom_list(ylist));
00511 return oqmlSuccess;
00512
00513 return oqmlSuccess;
00514 }
00515
00516 void oqmlISort::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00517 {
00518 *at = eval_type;
00519 }
00520
00521 oqmlBool oqmlISort::isConstant() const
00522 {
00523 return tosort->isConstant();
00524 }
00525
00526 std::string
00527 oqmlISort::toString(void) const
00528 {
00529 return (reverse ? std::string("risort(") : std::string("isort(")) +
00530 (tosort ? tosort->toString() : std::string("")) +
00531 (idxnode ? std::string(",") + idxnode->toString() : std::string(""))
00532 + ")" + oqml_isstat();
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 #if 0
00544 static int
00545 oqml_sort_pred_realize(const void *x1, const void *x2)
00546 {
00547 oqmlAtom *aleft = *(oqmlAtom **)x1;
00548 oqmlAtom *aright = *(oqmlAtom **)x2;
00549 oqmlAtomList *input = new oqmlAtomList();
00550 input->append(aleft);
00551 input->append(aright);
00552 if (oqml_predarg)
00553 input->append(oqml_predarg);
00554
00555 oqmlAtom *r;
00556 oqmlCall::realizeCall(oqml_db, oqml_ctx, oqml_entry, input,
00557 &r);
00558 }
00559
00560 static void
00561 oqml_sort_pred(oqmlAtomList *al, oqmlFunctionEntry *entry,
00562 oqmlAtomList *predarglist,
00563 oqmlBool reverse, oqmlAtomList **alist)
00564 {
00565 oqmlAtom **array;
00566 int nn;
00567
00568 array = oqml_make_array(al, nn);
00569
00570 qsort(array, nn, sizeof(oqmlAtom *), oqml_sort_pred_realize);
00571
00572 *alist = new oqmlAtomList();
00573
00574 if (reverse)
00575 for (int i = nn-1; i >= 0; i--)
00576 (*alist)->append(array[i]);
00577 else
00578 for (int i = 0; i < nn; i++)
00579 (*alist)->append(array[i]);
00580
00581 free(array);
00582 }
00583
00584 oqmlPSort::oqmlPSort(oqml_List *_list, oqmlBool _reverse) :
00585 oqmlXSort(oqmlPSORT, _list, _reverse)
00586 {
00587 }
00588
00589 oqmlPSort::~oqmlPSort()
00590 {
00591 }
00592
00593 oqmlStatus *oqmlPSort::compile(Database *db, oqmlContext *ctx)
00594 {
00595 if (list->cnt < 2)
00596 return usage();
00597
00598 tosort = list->first->ql;
00599 pred = list->first->next->ql;
00600
00601 oqmlStatus *s = tosort->compile(db, ctx);
00602 if (s) return s;
00603
00604 s = pred->compile(db, ctx);
00605 if (s) return s;
00606
00607 predarg = list->first->next ? list->first->next->ql : 0;
00608 if (predarg)
00609 retun predarg->compile(db, ctx);
00610
00611 return oqmlSuccess;
00612 }
00613
00614 oqmlStatus *oqmlPSort::usage()
00615 {
00616 return new oqmlStatus(this, "usage: %spsort(collection of anything, "
00617 "predicat [, predargs])", RS(reverse));
00618 }
00619
00620 oqmlStatus *oqmlPSort::eval(Database *db, oqmlContext *ctx,
00621 oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00622 {
00623 oqmlStatus *s;
00624 oqmlAtomList *al;
00625 int n;
00626
00627 s = tosort->eval(db, ctx, &al);
00628 if (s) return s;
00629
00630 oqmlAtomList *predlist;
00631 s = pred->eval(db, ctx, &predlist);
00632 if (s) return s;
00633 if (predlist->cnt != 1 || !OQML_IS_IDENT(predlist->first))
00634 return usage();
00635
00636 if (!ctx->getFunction(OQML_ATOM_IDENT(predlist->first, &entry)))
00637 return new oqmlStatus(this, "unknown function '%s'",
00638 OQML_ATOM_IDENT(predlist->first));
00639
00640 oqmlAtomList *predarglist = 0;
00641 if (predarg)
00642 {
00643 s = predarg->eval(db, ctx, &predarglist);
00644 if (s) return s;
00645 }
00646
00647 oqmlAtomList *ylist;
00648 oqml_sort_pred(al, entry, predarglist, reverse, &ylist);
00649 *alist = new oqmlAtomList(new oqmlAtom_list(ylist));
00650 return oqmlSuccess;
00651 }
00652
00653 void oqmlPSort::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00654 {
00655 *at = eval_type;
00656 }
00657
00658 oqmlBool oqmlPSort::isConstant() const
00659 {
00660 return tosort->isConstant();
00661 }
00662
00663 std::string
00664 oqmlPSort::toString(void) const
00665 {
00666 return (reverse ? std::string("rpsort(") : std::string("psort(")) +
00667 tosort->toString() + ", " + pred->toString() +
00668 (predarg ? std::string(", ") + predarg->toString() : std::string("")) +
00669 ")" + oqml_isstat();
00670 }
00671 #endif
00672 }