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
00028
00029
00030
00031
00032
00033 namespace eyedb {
00034
00035 #define oqmlIsPureComp(T) \
00036 ((T) == oqmlEQUAL || \
00037 (T) == oqmlDIFF || \
00038 (T) == oqmlINF || \
00039 (T) == oqmlINFEQ || \
00040 (T) == oqmlSUP || \
00041 (T) == oqmlSUPEQ || \
00042 (T) == oqmlREGCMP || \
00043 (T) == oqmlREGICMP || \
00044 (T) == oqmlREGDIFF || \
00045 (T) == oqmlREGIDIFF)
00046
00047 #define oqmlIsComp(T) \
00048 ((T) == oqmlAND || (T) == oqmlLAND || \
00049 (T) == oqmlOR || (T) == oqmlLOR || \
00050 oqmlIsPureComp(T))
00051
00052 static oqmlAtomType selectAtomType(oqmlATOM_SELECT);
00053
00054
00055
00056 #ifdef TRACE
00057 #define SELECT_TRACE(X) printf X
00058 #else
00059 #define SELECT_TRACE(X)
00060 #endif
00061
00062 class SelectLog {
00063
00064 public:
00065 enum Control {
00066 Off = 0,
00067 On,
00068 Detail
00069 };
00070
00071 static Control oql_select_log_ctl;
00072 static oqmlAtom *oql_select_log;
00073 static const char oql_select_log_ctl_var[];
00074 static const char oql_select_log_var[];
00075
00076 static oqmlStatus *error(oqmlNode *node) {
00077 return new oqmlStatus(node, "%s must be a string of "
00078 "one of the values: on, off or detail",
00079 oql_select_log_ctl_var);
00080 }
00081
00082 static oqmlStatus *init(oqmlNode *node, oqmlContext *ctx) {
00083 if (ctx->getHiddenSelectContextCount())
00084 return oqmlSuccess;;
00085
00086 oqmlAtom *x = 0;
00087 if (!ctx->getSymbol(oql_select_log_ctl_var, 0, &x) || !x) {
00088 oql_select_log_ctl = Off;
00089 oql_select_log = 0;
00090 return oqmlSuccess;;
00091 }
00092
00093 if (!OQML_IS_STRING(x))
00094 return error(node);
00095
00096 const char *val = OQML_ATOM_STRVAL(x);
00097 if (!strcasecmp(val, "off"))
00098 oql_select_log_ctl = Off;
00099 else if (!strcasecmp(val, "on"))
00100 oql_select_log_ctl = On;
00101 else if (!strcasecmp(val, "detail"))
00102 oql_select_log_ctl = Detail;
00103 else
00104 return error(node);
00105
00106 if (oql_select_log_ctl != Off) {
00107 oql_select_log = new oqmlAtom_string("");
00108 ctx->setSymbol(oql_select_log_var, &oql_select_log->type, oql_select_log);
00109 }
00110 else
00111 oql_select_log = 0;
00112
00113 return oqmlSuccess;
00114 }
00115
00116 static void append(const std::string &str) {
00117 oql_select_log->as_string()->set((std::string(OQML_ATOM_STRVAL(oql_select_log)) + str).c_str());
00118 }
00119 };
00120
00121 oqmlAtom *SelectLog::oql_select_log;
00122 SelectLog::Control SelectLog::oql_select_log_ctl = SelectLog::Off;
00123 const char SelectLog::oql_select_log_ctl_var[] = "oql$select_log_ctl";
00124 const char SelectLog::oql_select_log_var[] = "oql$select_log";
00125
00126
00127
00128
00129
00130
00131
00132 oqmlAnd::oqmlAnd(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqmlAND)
00133 {
00134 qleft = _qleft;
00135 qright = _qright;
00136 }
00137
00138 oqmlAnd::~oqmlAnd()
00139 {
00140 }
00141
00142 oqmlNode *
00143 oqmlAnd::optimize_realize(Database *db, oqmlContext *ctx, oqmlNode *ql,
00144 int &_xc)
00145 {
00146 if (xc == 4)
00147 {
00148 _xc = 4;
00149 return ql;
00150 }
00151
00152 oqmlNode **xql;
00153
00154 oqmlTYPE t1 = qleft->getType();
00155
00156 if (t1 == oqmlIDENT)
00157 {
00158 oqmlNode *tql = qleft;
00159 qleft = ql;
00160 return tql;
00161 }
00162
00163 oqmlTYPE t2 = qright->getType();
00164
00165 if (oqmlIsPureComp(t1))
00166 xql = &qleft;
00167 else if (oqmlIsPureComp(t2))
00168 xql = &qright;
00169 else
00170 return ql;
00171
00172 if (((oqmlComp *)(*xql))->appearsMoreOftenThan((oqmlComp *)ql))
00173 {
00174 oqmlNode *tql = *xql;
00175 *xql = ql;
00176 return tql;
00177 }
00178
00179 return ql;
00180 }
00181
00182 void
00183 oqmlAnd::optimize(Database *db, oqmlContext *ctx)
00184 {
00185 oqmlAtomType at_left;
00186
00187 qleft->evalType(db, ctx, &at_left);
00188
00189 eval_type.type = oqmlATOM_OID;
00190 eval_type.cls = at_left.cls;
00191 }
00192
00193 oqmlStatus *
00194 oqmlAnd::check(Database *db, oqmlContext *ctx)
00195 {
00196 oqmlAtomType at_left;
00197 oqmlAtomType at_right;
00198
00199 qleft->evalType(db, ctx, &at_left);
00200 qright->evalType(db, ctx, &at_right);
00201
00202 if (!xc) {
00203 if (at_left.type != oqmlATOM_BOOL || at_right.type != oqmlATOM_BOOL)
00204 return new oqmlStatus("and operator cannot deal with non boolean values");
00205 eval_type.type = oqmlATOM_BOOL;
00206 return oqmlSuccess;
00207 }
00208
00209 if (at_left.type != oqmlATOM_OID)
00210 return new oqmlStatus("and operator: left identifier is not a class");
00211
00212 if (at_right.type != oqmlATOM_OID)
00213 return new oqmlStatus("and operator: right identifier is not a class");
00214
00215 if (!at_left.cls || !at_right.cls)
00216 return oqmlSuccess;
00217
00218 Status status;
00219 Bool issuperclassof;
00220
00221 status = at_left.cls->isSuperClassOf(at_right.cls, &issuperclassof);
00222
00223 if (status)
00224 return new oqmlStatus(status);
00225
00226 if (issuperclassof) {
00227 if (qleft->getType() == oqmlIDENT) {
00228
00229 oqmlNode *ql = qleft;
00230 qleft = qright;
00231 qright = ql;
00232 }
00233
00234 optimize(db, ctx);
00235 return oqmlSuccess;
00236 }
00237
00238 status = at_right.cls->isSuperClassOf(at_left.cls, &issuperclassof);
00239
00240 if (status)
00241 return new oqmlStatus(status);
00242
00243 if (issuperclassof)
00244 {
00245 optimize(db, ctx);
00246 return oqmlSuccess;
00247 }
00248
00249 xc = 4;
00250 eval_type.type = oqmlATOM_OID;
00251 eval_type.cls = db->getSchema()->getClass("object");
00252
00253 return oqmlSuccess;
00254 }
00255
00256 oqmlStatus *oqmlAnd::compile(Database *db, oqmlContext *ctx)
00257 {
00258 oqmlStatus *s;
00259 oqmlTYPE t1, t2;
00260
00261 s = qleft->compile(db, ctx);
00262 if (s)
00263 return s;
00264
00265 s = qright->compile(db, ctx);
00266 if (s)
00267 return s;
00268
00269 t1 = qleft->getType();
00270 t2 = qright->getType();
00271
00272 if (t1 == oqmlIDENT && t2 == oqmlIDENT)
00273 xc = 1;
00274 else if (oqmlIsComp(t1) && t2 == oqmlIDENT)
00275 xc = 2;
00276 else if (t1 == oqmlIDENT && oqmlIsComp(t2))
00277 {
00278
00279 oqmlNode *ql = qleft;
00280 qleft = qright;
00281 qright = ql;
00282 xc = 2;
00283 }
00284 else if (oqmlIsComp(t1) && oqmlIsComp(t2))
00285 xc = 3;
00286 else
00287 xc = 0;
00288
00289 return check(db, ctx);
00290 }
00291
00292 oqmlStatus *
00293 oqmlAnd::eval_0(Database *db, oqmlContext *ctx, oqmlAtomList **alist)
00294 {
00295 assert(0);
00296 oqmlStatus *s;
00297 oqmlAtomList *al_left, *al_right;
00298
00299 s = qleft->eval(db, ctx, &al_left);
00300 if (s)
00301 return s;
00302
00303 if (al_left->cnt != 1)
00304 return new oqmlStatus("and operator cannot deal with non atomic values");
00305
00306 if (al_left->first->type.type != oqmlATOM_BOOL)
00307 return new oqmlStatus("and operator cannot deal with non boolean values");
00308
00309 if (!((oqmlAtom_bool *)al_left->first)->b)
00310 {
00311 (*alist)->append(new oqmlAtom_bool(oqml_False));
00312 return oqmlSuccess;
00313 }
00314
00315 s = qright->eval(db, ctx, &al_right);
00316 if (s)
00317 return s;
00318
00319 if (al_right->cnt != 1)
00320 return new oqmlStatus("and operator cannot deal with non atomic values");
00321
00322 if (al_right->first->type.type != oqmlATOM_BOOL)
00323 return new oqmlStatus("and operator cannot deal with non boolean values");
00324
00325 (*alist)->append(new oqmlAtom_bool(((oqmlAtom_bool *)al_right->first)->b));
00326
00327 return oqmlSuccess;
00328 }
00329
00330 oqmlStatus *
00331 oqmlAnd::eval_1(Database *db, oqmlContext *ctx, oqmlAtomList **alist)
00332 {
00333 oqmlStatus *s;
00334 oqmlAtomList *and_ctx = ctx->getAndContext();
00335 unsigned int r_left, r_right;
00336
00337 s = qleft->estimate(db, ctx, r_left);
00338 if (s) return s;
00339
00340 if (r_left > 0)
00341 {
00342 s = qright->estimate(db, ctx, r_right);
00343 if (s) return s;
00344 }
00345 else
00346 r_right = oqml_ESTIM_MAX;
00347
00348 oqmlAtomList *al_left, *al_right;
00349 if (r_left <= r_right)
00350 {
00351 s = qleft->eval(db, ctx, &al_left);
00352 if (s) return s;
00353
00354 ctx->setAndContext(al_left);
00355
00356 s = qright->eval(db, ctx, alist);
00357 if (s) return s;
00358
00359 ctx->setAndContext(and_ctx);
00360 return oqmlSuccess;
00361 }
00362
00363 s = qright->eval(db, ctx, &al_right);
00364 if (s) return s;
00365
00366 ctx->setAndContext(al_right);
00367
00368 s = qleft->eval(db, ctx, alist);
00369 if (s) return s;
00370
00371 ctx->setAndContext(and_ctx);
00372 return oqmlSuccess;
00373 }
00374
00375 oqmlStatus *oqmlAnd::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00376 {
00377 *alist = new oqmlAtomList();
00378
00379 if (xc == 0)
00380 return eval_0(db, ctx, alist);
00381 if (xc == 4)
00382 return oqmlSuccess;
00383
00384 return eval_1(db, ctx, alist);
00385 }
00386
00387 void oqmlAnd::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00388 {
00389 *at = eval_type;
00390 }
00391
00392 oqmlBool oqmlAnd::isConstant() const
00393 {
00394 return oqml_False;
00395 }
00396
00397 std::string
00398 oqmlAnd::toString(void) const
00399 {
00400 return oqml_binop_string(qleft, qright, " and ", is_statement);
00401 }
00402
00403
00404
00405
00406
00407
00408
00409 oqmlOr::oqmlOr(oqmlNode * _qleft, oqmlNode * _qright) : oqmlNode(oqmlOR)
00410 {
00411 qleft = _qleft;
00412 qright = _qright;
00413 }
00414
00415 oqmlOr::~oqmlOr()
00416 {
00417
00418
00419 }
00420
00421 oqmlStatus *oqmlOr::compile(Database *db, oqmlContext *ctx)
00422 {
00423 oqmlStatus *s;
00424
00425
00426 s = qleft->compile(db, ctx);
00427 if (s)
00428 return s;
00429
00430 s = qright->compile(db, ctx);
00431 if (s)
00432 return s;
00433
00434 return oqmlSuccess;
00435 }
00436
00437 oqmlStatus *oqmlOr::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00438 {
00439 oqmlStatus *s;
00440 oqmlAtomList *al_left, *al_right;
00441
00442 oqmlAtomList *rlist = new oqmlAtomList();
00443 *alist = new oqmlAtomList(new oqmlAtom_list(rlist));
00444
00445 s = qleft->eval(db, ctx, &al_left);
00446 if (s)
00447 return s;
00448
00449 if (al_left->cnt == 1 && OQML_IS_COLL(al_left->first))
00450 rlist->append(OQML_ATOM_COLLVAL(al_left->first));
00451
00452 s = qright->eval(db, ctx, &al_right);
00453 if (s)
00454 return s;
00455
00456 if (al_right->cnt == 1 && OQML_IS_COLL(al_right->first))
00457 rlist->append(OQML_ATOM_COLLVAL(al_right->first));
00458
00459 return oqmlSuccess;
00460 }
00461
00462 void oqmlOr::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00463 {
00464 oqmlAtomType at_left, at_right;
00465 oqmlStatus *s;
00466
00467 qleft->evalType(db, ctx, &at_left);
00468
00469 qright->evalType(db, ctx, &at_right);
00470
00471 if (at_left.type == at_right.type)
00472 *at = at_left;
00473 else
00474 {
00475 at->type = oqmlATOM_UNKNOWN_TYPE;
00476 at->cls = 0;
00477 at->comp = oqml_False;
00478 }
00479 }
00480
00481 oqmlBool oqmlOr::isConstant() const
00482 {
00483 return oqml_False;
00484 }
00485
00486 std::string
00487 oqmlOr::toString(void) const
00488 {
00489 return oqml_binop_string(qleft, qright, " or ", is_statement);
00490 }
00491
00492
00493
00494
00495
00496
00497
00498 oqmlDatabase::oqmlDatabase(const char *_dbname, const char *_mode,
00499 oqmlNode * _ql) : oqmlNode(oqmlDATABASE)
00500 {
00501 dbname = strdup(_dbname);
00502 mode = strdup(_mode);
00503 ql = _ql;
00504 cdb = 0;
00505 }
00506
00507 oqmlDatabase::~oqmlDatabase()
00508 {
00509 free(dbname);
00510 free(mode);
00511 }
00512
00513 oqmlStatus *oqmlDatabase::compile(Database *db, oqmlContext *ctx)
00514 {
00515 Database::OpenFlag open_flag;
00516
00517 if (!strcasecmp(mode, "r"))
00518 open_flag = Database::DBRead;
00519 else if (!strcasecmp(mode, "sr"))
00520 open_flag = Database::DBSRead;
00521 else if (!strcasecmp(mode, "rw"))
00522 open_flag = Database::DBRW;
00523 else
00524 return new oqmlStatus(this, "unknown opening mode: %s", mode);
00525
00526 if (!strcmp(dbname, db->getName()) && db->getOpenFlag() == open_flag)
00527 cdb = db;
00528 else
00529 {
00530 if (db->isLocal())
00531 return new oqmlStatus("cannot use multi database feature"
00532 "in local opening mode");
00533
00534 Status status = Database::open(db->getConnection(), dbname,
00535 db->getDBMDB(),
00536 db->getUser(),
00537 db->getPassword(),
00538 open_flag, 0, &cdb);
00539
00540 if (status) return new oqmlStatus(status);
00541 }
00542
00543 oqmlStatus *s;
00544
00545 if (cdb != db) cdb->transactionBegin();
00546 s = ql->compile(cdb, ctx);
00547 if (cdb != db) cdb->transactionCommit();
00548
00549 return s;
00550 }
00551
00552 oqmlStatus *oqmlDatabase::eval(Database *db, oqmlContext *ctx,
00553 oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00554 {
00555 oqmlStatus *s;
00556
00557 if (cdb != db)
00558 cdb->transactionBegin();
00559
00560 s = ql->eval(cdb, ctx, alist);
00561
00562 if (cdb != db)
00563 cdb->transactionCommit();
00564
00565 if (s)
00566 return s;
00567
00568 return oqmlSuccess;
00569 }
00570
00571 void oqmlDatabase::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00572 {
00573 *at = eval_type;
00574 }
00575
00576 oqmlBool oqmlDatabase::isConstant() const
00577 {
00578 return oqml_False;
00579 }
00580
00581 std::string
00582 oqmlDatabase::toString(void) const
00583 {
00584 return std::string("(database ") + dbname + ")";
00585 }
00586
00587
00588
00589
00590
00591
00592
00593 oqmlSelect::oqmlSelect(oqmlNode *_location,
00594 oqmlBool _distinct,
00595 oqmlBool _one,
00596 oqmlNode *_projection,
00597 oqml_IdentList *_ident_from_list,
00598 oqmlNode *_where,
00599 oqmlNode *_group,
00600 oqmlNode *_having,
00601 oqml_SelectOrder *_order) : oqmlNode(oqmlSELECT)
00602 {
00603 location = _location;
00604 distinct = _distinct;
00605 one = _one;
00606 projection = _projection;
00607 ident_from_list = _ident_from_list;
00608 where = _where;
00609 group = _group;
00610 having = _having;
00611 order = _order;
00612 list_order = 0;
00613 idents = 0;
00614 ident_cnt = 0;
00615 calledFromEval = oqml_False;
00616 databaseStatement = oqml_False;
00617 memset(&logged, 0, sizeof(logged));
00618 }
00619
00620 oqmlSelect::~oqmlSelect()
00621 {
00622 delete ident_from_list;
00623 delete [] list_order;
00624 delete [] idents;
00625 }
00626
00627 oqmlStatus *oqmlSelect::check_order_coll(oqmlNode *actual_projection)
00628 {
00629 oqml_List *projlist = ((oqmlColl *)actual_projection)->getList();
00630 if (!projlist)
00631 return new oqmlStatus(this, "order clause: '%s' not found in projection",
00632 order->list->first->ql->toString().c_str());
00633
00634 list_order = new int[order->list->cnt];
00635 oqml_Link *olink, *plink;
00636 int ocnt, pcnt;
00637 for (olink = order->list->first, ocnt = 0; olink; olink = olink->next, ocnt++)
00638 {
00639 oqmlBool ok = oqml_False;
00640 for (plink = projlist->first, pcnt = 0; plink; plink = plink->next, pcnt++)
00641 if (plink->ql->equals(olink->ql))
00642 {
00643 ok = oqml_True;
00644 list_order[ocnt] = pcnt;
00645 break;
00646 }
00647
00648 if (!ok)
00649 return new oqmlStatus(this, "order clause: '%s' not found "
00650 "in projection",
00651 olink->ql->toString().c_str());
00652 }
00653
00654 return oqmlSuccess;
00655 }
00656
00657 oqmlStatus *oqmlSelect::check_order_simple()
00658 {
00659 for (oqml_Link *link = order->list->first; link; link = link->next)
00660 if (!projection->equals((link->ql)))
00661 return new oqmlStatus(this, "order clause: %s not found in projection",
00662 link->ql->toString().c_str());
00663 return oqmlSuccess;
00664 }
00665
00666 oqmlStatus *oqmlSelect::check_order()
00667 {
00668 if (!order)
00669 return oqmlSuccess;
00670
00671 oqmlNode *actual_projection = projection;
00672 if (projection->getType() == oqmlCALL)
00673 actual_projection = ((oqmlCall *)projection)->getBuiltIn();
00674
00675 if (actual_projection &&
00676 actual_projection->getType() == oqmlLISTCOLL ||
00677 actual_projection->getType() == oqmlBAGCOLL ||
00678 actual_projection->getType() == oqmlARRAYCOLL ||
00679 actual_projection->getType() == oqmlSETCOLL)
00680 return check_order_coll(actual_projection);
00681
00682 return check_order_simple();
00683 }
00684
00685 extern oqmlStatus *
00686 oqml_check_sort_type(oqmlNode *, oqmlATOMTYPE);
00687
00688 oqmlStatus *
00689 oqmlSelect::realize_order(oqmlAtomList **alist)
00690 {
00691 if (!order || !*alist || !(*alist)->cnt || !OQML_IS_COLL((*alist)->first))
00692 return oqmlSuccess;
00693
00694 oqmlAtomList *list = OQML_ATOM_COLLVAL((*alist)->first);
00695
00696 if (!list->cnt) {
00697 *alist = new oqmlAtomList(new oqmlAtom_list(new oqmlAtomList()));
00698 return oqmlSuccess;
00699 }
00700
00701 oqmlStatus *s;
00702 if (!list_order)
00703 {
00704 oqmlAtomType &atom_type = list->first->type;
00705 s = oqml_check_sort_type(this, atom_type,
00706 (std::string("cannot order using '") +
00707 order->list->first->ql->toString() + "'").c_str());
00708 if (s) return s;
00709 oqml_sort_simple(list, OQMLBOOL(!order->asc), atom_type.type, &list);
00710 *alist = new oqmlAtomList(new oqmlAtom_list(list));
00711 return oqmlSuccess;
00712 }
00713
00714
00715
00716 oqml_Link *olink = order->list->first;
00717 for (int i = 0; i < order->list->cnt; i++, olink = olink->next)
00718 {
00719 oqmlAtomType &atom_type = OQML_ATOM_COLLVAL(list->first)->getAtom(list_order[i])->type;
00720 s = oqml_check_sort_type(this, atom_type,
00721 (std::string("cannot order using '") +
00722 olink->ql->toString() + "'").c_str());
00723 if (s) return s;
00724 oqml_sort_list(list, OQMLBOOL(!order->asc), list_order[i],
00725 atom_type.type, &list);
00726 }
00727
00728 *alist = new oqmlAtomList(new oqmlAtom_list(list));
00729 return oqmlSuccess;
00730 }
00731
00732 oqmlBool
00733 oqmlSelect::makeIdents()
00734 {
00735 if (!ident_from_list)
00736 return oqml_False;
00737
00738 oqmlBool missingIdent = oqml_False;
00739
00740 delete [] idents;
00741 idents = new oqml_IdentLink*[ident_from_list->cnt];
00742
00743 oqml_IdentLink *l = ident_from_list->first;
00744
00745 for (ident_cnt = 0; l; ident_cnt++)
00746 {
00747 idents[ident_cnt] = l;
00748 if (!l->ident)
00749 missingIdent = oqml_True;
00750 l = l->next;
00751 }
00752
00753 return missingIdent;
00754 }
00755
00756 oqmlStatus *
00757 oqmlSelect::processFromListRequalification(Database *db, oqmlContext *ctx)
00758 {
00759 for (int i = ident_cnt-1; i >= 0; i--)
00760 {
00761 if (!idents[i]->ident)
00762 continue;
00763
00764 const char *left_ident = 0;
00765 if (idents[i]->ql->asIdent())
00766 left_ident = idents[i]->ql->asIdent()->getName();
00767 else if (idents[i]->ql->asDot())
00768 left_ident = idents[i]->ql->asDot()->getLeftIdent();
00769
00770 if (left_ident)
00771 {
00772 for (int j = i-1; j >= 0; j--)
00773 if (idents[j]->ident && !strcmp(left_ident, idents[j]->ident))
00774 {
00775 idents[i]->requalified = oqml_True;
00776 break;
00777 }
00778
00779 if (idents[i]->requalified)
00780 {
00781 oqmlBool done = oqml_False;
00782 oqmlStatus *s = where->requalify(db, ctx, idents[i]->ident,
00783 idents[i]->ql, done);
00784 if (s) return s;
00785 }
00786 }
00787 }
00788
00789 return oqmlSuccess;
00790 }
00791
00792 #define ERRFROM "from clause '%s': "
00793
00794 std::string ident_gen()
00795 {
00796 static int i;
00797 return std::string("oql$x") + str_convert(i++);
00798 }
00799
00800 oqmlStatus *
00801 oqmlSelect::processMissingIdentsRequalification(Database *db, oqmlContext *ctx)
00802 {
00803 for (int i = ident_cnt-1; i >= 0; i--)
00804 {
00805 if (idents[i]->ident)
00806 {
00807 if (idents[i]->ql->asIdent())
00808 idents[i]->cls = db->getSchema()->getClass(idents[i]->ql->asIdent()->getName());
00809 continue;
00810 }
00811
00812 if (!idents[i]->ql->asIdent())
00813 return new oqmlStatus(this, ERRFROM "needs identifier",
00814 idents[i]->ql->toString().c_str());
00815
00816 const char *ident = idents[i]->ql->asIdent()->getName();
00817
00818 for (int j = i-1; j >= 0; j--)
00819 if (idents[j]->ident && !strcmp(ident, idents[j]->ident))
00820 return new oqmlStatus(this, ERRFROM "needs identifier",
00821 idents[i]->ql->toString().c_str());
00822
00823 idents[i]->cls = db->getSchema()->getClass(ident);
00824 if (!idents[i]->cls)
00825 return new oqmlStatus(this, ERRFROM "not a class",
00826 idents[i]->ql->toString().c_str());
00827
00828
00829 idents[i]->ident = strdup(ident);
00830 unsigned int attr_cnt;
00831 const Attribute **attrs = idents[i]->cls->getAttributes(attr_cnt);
00832 oqmlStatus *s;
00833 if (where)
00834 {
00835 s = where->requalify(db, ctx, attrs, attr_cnt, idents[i]->ident);
00836 if (s) return s;
00837 }
00838
00839 if (order)
00840 for (oqml_Link *link = order->list->first; link; link = link->next)
00841 {
00842 if (link->ql->asIdent())
00843 s = requalify_node(db, ctx, link->ql, attrs, attr_cnt,
00844 idents[i]->ident);
00845 else
00846 s = link->ql->requalify(db, ctx, attrs, attr_cnt,
00847 idents[i]->ident);
00848 if (s) return s;
00849 }
00850
00851 if (projection)
00852 {
00853 if (projection->asIdent())
00854 s = requalify_node(db, ctx, projection, attrs, attr_cnt, idents[i]->ident);
00855 else
00856 s = projection->requalify(db, ctx, attrs, attr_cnt, idents[i]->ident);
00857 if (s) return s;
00858 }
00859 }
00860
00861 return oqmlSuccess;
00862 }
00863
00864 static oqmlBool
00865 is_terminal(const Attribute *attr)
00866 {
00867 if (attr->isNative())
00868 return oqml_False;
00869
00870 if (attr->isString())
00871 return oqml_True;
00872
00873 if (attr->getTypeModifier().pdims != 1)
00874 return oqml_False;
00875
00876 if (attr->isIndirect() || attr->getClass()->asBasicClass() ||
00877 attr->getClass()->asEnumClass())
00878 return oqml_True;
00879
00880 return oqml_False;
00881 }
00882
00883 oqmlStatus *
00884 oqmlSelect::processMissingProjRequalification(Database *db, oqmlContext *ctx)
00885 {
00886 oqml_IdentList *struct_list = new oqml_IdentList();
00887
00888 for (int j = 0; j < ident_cnt; j++)
00889 {
00890 if (!idents[j]->cls)
00891 {
00892 delete struct_list;
00893 return new oqmlStatus(this, ERRFROM "not a class",
00894 idents[j]->ql->toString().c_str());
00895 }
00896
00897 unsigned int attr_cnt;
00898 const Attribute **attrs = idents[j]->cls->getAttributes(attr_cnt);
00899 for (int k = 0; k < attr_cnt; k++)
00900 if (is_terminal(attrs[k]))
00901 struct_list->add(new oqmlIdent(attrs[k]->getName()),
00902 new oqmlDot(new oqmlIdent(idents[j]->ident),
00903 new oqmlIdent(attrs[k]->getName()),
00904 oqml_False));
00905 }
00906
00907 projection = new oqmlStruct(struct_list);
00908
00909 if (isLocked()) projection->lock();
00910
00911 return oqmlSuccess;
00912 }
00913
00914 oqmlStatus *
00915 oqmlSelect::processRequalification_1(Database *db, oqmlContext *ctx)
00916 {
00917 oqmlBool missingIdent = makeIdents();
00918
00919 if (missingIdent || !projection)
00920 {
00921 if (missingIdent && where && !where->mayBeRequalified())
00922 return new oqmlStatus(this, "this construct needs explicit "
00923 "identifiers in the from clause");
00924
00925 oqmlStatus *s = processMissingIdentsRequalification(db, ctx);
00926 if (s) return s;
00927 }
00928
00929 if (!projection)
00930 {
00931 oqmlStatus *s = processMissingProjRequalification(db, ctx);
00932 if (s) return s;
00933 }
00934
00935 return oqmlSuccess;
00936 }
00937
00938 oqmlStatus *
00939 oqmlSelect::processRequalification_2(Database *db, oqmlContext *ctx)
00940 {
00941 if (where && where->mayBeRequalified())
00942 return processFromListRequalification(db, ctx);
00943
00944 return oqmlSuccess;
00945 }
00946
00947 oqmlStatus *
00948 oqmlSelect::compile(Database *db, oqmlContext *ctx)
00949 {
00950 oqmlStatus *s;
00951 if (!calledFromEval) {
00952 memset(&logged, 0, sizeof(logged));
00953 s = SelectLog::init(this, ctx);
00954 if (s) return s;
00955 return oqmlSuccess;
00956 }
00957
00958 if (!db->isInTransaction())
00959 return new oqmlStatus(this, "must be done within the scope of "
00960 "a transaction in database '%s'", db->getName());
00961
00962 s = processRequalification_1(db, ctx);
00963 if (s) return s;
00964
00965 if (!ident_from_list) {
00966 if (projection) {
00967 ctx->incrSelectContext(this);
00968 s = projection->compile(db, ctx);
00969 ctx->decrSelectContext();
00970 if (s) return s;
00971 }
00972 s = check_order();
00973 return s;
00974 }
00975
00976 oqml_IdentLink *l;
00977
00978 l = ident_from_list->first;
00979
00980 while(l) {
00981 if (!l->ident)
00982 return new oqmlStatus(this, "identificator is missing in the from "
00983 "clause: '%s'",
00984 l->ql->toString().c_str());
00985 l = l->next;
00986 }
00987
00988 l = ident_from_list->first;
00989 oqmlAtomType unknownType;
00990
00991 s = oqmlSuccess;
00992
00993 if (!s && !where) {
00994 ctx->incrSelectContext(this);
00995 while(l) {
00996 if (!s)
00997 s = l->ql->compile(db, ctx);
00998 ctx->pushSymbol(l->ident, &unknownType, 0, oqml_False);
00999 l = l->next;
01000 }
01001
01002 if (!s) {
01003 int select_ctx_cnt = ctx->setSelectContextCount(0);
01004 s = projection->compile(db, ctx);
01005 ctx->setSelectContextCount(select_ctx_cnt);
01006 }
01007
01008 if (!s)
01009 s = check_order();
01010
01011 l = ident_from_list->first;
01012
01013 while (l) {
01014 ctx->popSymbol(l->ident, oqml_False);
01015 l = l->next;
01016 }
01017
01018 ctx->decrSelectContext();
01019 return s;
01020 }
01021
01022 ctx->incrSelectContext(this);
01023
01024 while (l) {
01025 if (!s) s = l->ql->compile(db, ctx);
01026 ctx->pushSymbol(l->ident, &selectAtomType, 0, oqml_False);
01027 l = l->next;
01028 }
01029
01030 ctx->decrSelectContext();
01031
01032 if (!s && where) {
01033 int select_ctx_cnt = ctx->setSelectContextCount(0);
01034
01035 ctx->incrHiddenSelectContext(this);
01036 s = where->compile(db, ctx);
01037 ctx->decrHiddenSelectContext();
01038 ctx->setSelectContextCount(select_ctx_cnt);
01039 }
01040
01041 if (!s) {
01042 int select_ctx_cnt = ctx->setSelectContextCount(0);
01043 s = projection->compile(db, ctx);
01044 ctx->setSelectContextCount(select_ctx_cnt);
01045 }
01046
01047 if (!s)
01048 s = check_order();
01049
01050 l = ident_from_list->first;
01051
01052 while (l) {
01053 ctx->popSymbol(l->ident, oqml_False);
01054 l = l->next;
01055 }
01056
01057 return s;
01058 }
01059
01060 oqmlStatus *
01061 optimize(Database *db, oqmlContext *ctx, oqmlAtom_select *atom,
01062 int n, oqml_IdentLink *idents[], oqmlAtomList *&list)
01063 {
01064 if (atom->list)
01065 {
01066 oqmlBool toEval = oqml_False;
01067 oqmlNode *node = atom->node;
01068
01069 if (node)
01070 for (int i = 0; i < n; i++)
01071 if (node->hasIdent(idents[i]->ident)) {
01072 SELECT_TRACE(("optimize : node has ident %p\n", idents[i]->ident));
01073 toEval = oqml_True;
01074 break;
01075 }
01076
01077 if (!toEval) {
01078 list = atom->list;
01079 return oqmlSuccess;
01080 }
01081 }
01082
01083 if (!atom->node)
01084 return oqmlSuccess;
01085
01086 oqmlStatus *s = atom->node->eval(db, ctx, &list);
01087 if (s) return s;
01088 atom->list = list;
01089 return oqmlSuccess;
01090 }
01091
01092 oqmlBool
01093 checkIdent(oqml_IdentLink *idents[], int n, int cnt)
01094 {
01095 const char *ident = idents[n]->ident;
01096
01097 for (int i = n+1; i < cnt; i++)
01098 if (idents[i]->ql->hasIdent(ident))
01099 return oqml_True;
01100
01101 return oqml_False;
01102 }
01103
01104 void stop_imm() { }
01105
01106 static oqmlAtomList *
01107 oqml_make_intersect(oqmlAtomList *list1, oqmlAtom *a2)
01108 {
01109 oqmlAtomList *list = new oqmlAtomList();
01110
01111 if (!a2 || !list1)
01112 return list;
01113
01114 if (OQML_IS_COLL(a2))
01115 {
01116 oqmlAtomList *list2 = OQML_ATOM_COLLVAL(a2);
01117 oqmlAtom *a = list1->first;
01118
01119 while (a)
01120 {
01121 oqmlAtom *next = a->next;
01122 if (list2->isIn(a))
01123 list->append(a->copy());
01124 a = next;
01125 }
01126 }
01127 else if (list1->isIn(a2))
01128 list->append(a2);
01129
01130
01131
01132
01133
01134
01135 return list;
01136 }
01137
01138 oqmlAtom **
01139 begin_cpatoms(oqmlAtomList **cplists, int cpcnt)
01140 {
01141 if (!cpcnt)
01142 return 0;
01143
01144 oqmlAtom **ratoms = new oqmlAtom *[cpcnt];
01145 for (int i = 0; i < cpcnt; i++) {
01146 oqmlAtomList *list = cplists[i];
01147 if (list && list->first && list->first->as_coll())
01148 list = OQML_ATOM_COLLVAL(list->first);
01149 ratoms[i] = (list ? list->first : 0);
01150 }
01151
01152 return ratoms;
01153 }
01154
01155 oqmlAtom **
01156 next_cpatoms(oqmlAtom **cpatoms, int cpcnt)
01157 {
01158 if (!cpcnt)
01159 return 0;
01160
01161 oqmlAtom **ratoms = new oqmlAtom *[cpcnt];
01162 for (int i = 0; i < cpcnt; i++)
01163 ratoms[i] = cpatoms[i]->next;
01164
01165 return ratoms;
01166 }
01167
01168 #ifdef TRACE
01169 #define CP1_TRACE() \
01170 SELECT_TRACE(("EvalCartProdRealize(cpcnt %d, reducing #%d)\n", \
01171 cpcnt, ident_cnt - n - 1)); \
01172 for (int i = 0; i < cpcnt; i++) \
01173 SELECT_TRACE(("EvalCartProdRealize(cpatoms[%d]: %s)\n", \
01174 i, (const char *)cpatoms[i]->getString()))
01175
01176 #define CP2_TRACE() \
01177 if (cpcnt_n) { \
01178 SELECT_TRACE(("\tcp count: %d\n", cpcnt_n)); \
01179 for (int i = 0; i < cpcnt_n; i++) \
01180 SELECT_TRACE(("\tcplist[%d]: %s\n", i, (const char *)cplists_n[i]->getString())); \
01181 }
01182 #else
01183 #define CP1_TRACE()
01184 #define CP2_TRACE()
01185 #endif
01186
01187 oqmlStatus *
01188 oqmlSelect::evalCartProdRealize(Database *db, oqmlContext *ctx,
01189 oqmlAtomList *rlist, int n,
01190 const char *preval_ident,
01191 oqmlAtom **cpatoms, int cpcnt)
01192 {
01193 oqmlStatus *s = oqmlSuccess;
01194 oqmlAtomList *list = 0;
01195
01196 oqmlAtomType at;
01197 oqmlAtom *atom = 0;
01198 const char *ident = idents[n]->ident;
01199 oqmlBool where_optim = oqml_False;
01200 int cpcnt_n = 0;
01201 oqmlAtomList **cplists_n = 0;
01202
01203 SELECT_TRACE(("\nEvalCartProdRealize(n=%d, ident_cnt=%d) `%s'\n",
01204 n, ident_cnt, (const char *)toString()));
01205
01206 if (cpcnt) {
01207 CP1_TRACE();
01208 list = new oqmlAtomList(cpatoms[ident_cnt - n - 1]);
01209 where_optim = oqml_True;
01210 }
01211 else if (idents[n]->skipIdent || idents[n]->requalified) {
01212 if (n != ident_cnt - 1) {
01213 SELECT_TRACE(("\tBefore Requalified EvalCartProdRealize `%s'\n",
01214 (const char *)toString()));
01215 oqmlStatus *s = evalCartProdRealize(db, ctx, rlist, n+1, preval_ident);
01216 SELECT_TRACE(("\tAfter Requalified EvalCartProdRealize `%s'\n",
01217 (const char *)toString()));
01218 return s;
01219 }
01220 ctx->incrWhereContext();
01221 if (idents[n]->skipIdent)
01222 {
01223 ident = "oql$dummy";
01224 list = new oqmlAtomList(new oqmlAtom_nil());
01225 }
01226 else if (ctx->getSymbol(ident, &at, &atom) && atom->as_select() &&
01227 atom->as_select()->collatom)
01228 {
01229 oqmlAtomList *al;
01230 s = idents[n]->ql->eval(db, ctx, &al);
01231 if (s) return s;
01232 list = oqml_make_intersect(atom->as_select()->collatom->list,
01233 al ? al->first : 0);
01234 SELECT_TRACE(("\tMaking list from make_intersect `%s'\n",
01235 (const char *)toString()));
01236 }
01237 else
01238 {
01239 SELECT_TRACE(("\tMaking list from idents[n]->ql->eval `%s' %s\n",
01240 (const char *)toString(),
01241 (const char*)idents[n]->ql->toString()));
01242 s = idents[n]->ql->eval(db, ctx, &list);
01243 if (s) return s;
01244 }
01245 }
01246 else {
01247 oqmlBool wasPopulated;
01248
01249 if (ctx->getSymbol(ident, &at, &atom) && at.type == oqmlATOM_SELECT)
01250 wasPopulated = OQMLBOOL(atom->as_select()->list);
01251 else
01252 assert(0);
01253
01254 ctx->incrWhereContext();
01255 if (n != ident_cnt - 1 && !wasPopulated &&
01256 !checkIdent(idents, n, ident_cnt)) {
01257 ctx->incrSelectContext(this);
01258 ctx->incrPrevalContext();
01259 SELECT_TRACE(("\tBefore Prevaling EvalCartProdRealize `%s'\n",
01260 (const char *)toString()));
01261 s = evalCartProdRealize(db, ctx, rlist, n+1, ident);
01262 SELECT_TRACE(("\tAfter Prevaling EvalCartProdRealize `%s'\n",
01263 (const char *)toString()));
01264 ctx->getSymbol(ident, &at, &atom);
01265 ctx->decrSelectContext();
01266 ctx->decrPrevalContext();
01267 if (s) return s;
01268 }
01269
01270 where_optim = atom->as_select()->list ? oqml_True : oqml_False;
01271 cpcnt_n = atom->as_select()->cpcnt;
01272 cplists_n = atom->as_select()->cplists;
01273 CP2_TRACE();
01274
01275 s = optimize(db, ctx, atom->as_select(), n, idents, list);
01276 SELECT_TRACE(("\tMaking list from optimize `%s' [where_optim %s]\n",
01277 (const char *)toString(),
01278 where_optim ? "true" : "false"));
01279
01280 if (s) return s;
01281 }
01282
01283 if (list && list->first && list->first->as_coll()) {
01284 #ifdef SYNC_GARB
01285
01286 #endif
01287 list = OQML_ATOM_COLLVAL(list->first);
01288 #ifdef SYNC_GARB
01289
01290
01291 #endif
01292 }
01293
01294 oqmlAtom *a = (list ? list->first : 0);
01295 oqmlAtom **cpatoms_n;
01296
01297 if (cpcnt) {
01298 cpatoms_n = cpatoms;
01299 cpcnt_n = cpcnt;
01300 }
01301 else
01302 cpatoms_n = begin_cpatoms(cplists_n, cpcnt_n);
01303
01304 oqmlBool cpatom_while = (!cpatoms && cpatoms_n) ? oqml_True : oqml_False;
01305
01306 if (!a && n != ident_cnt - 1)
01307 a = new oqmlAtom_nil();
01308
01309 SELECT_TRACE(("\tLoop start for %d items `%s'\n", list ? list->cnt : 0,
01310 (const char *)toString()));
01311
01312 if (SelectLog::oql_select_log_ctl != SelectLog::Off) {
01313 if (!logged[n] || SelectLog::oql_select_log_ctl == SelectLog::Detail) {
01314 SelectLog::append((std::string("QUERY : ") + toString() + "\nDEPTH : #" +
01315 str_convert((long)n) + "\n").c_str());
01316 logged[n] = 1;
01317 }
01318 if (SelectLog::oql_select_log_ctl == SelectLog::Detail) {
01319 SelectLog::append((std::string("ITEM COUNT : ") +
01320 str_convert((long)(list ? list->cnt : 0)) + "\n").c_str());
01321 }
01322 }
01323
01324 #if 0
01325 printf("LOOP from 0 to %d\n", (list ? list->cnt : 0));
01326 int nn = 0;
01327
01328 oqmlAtom *xxx = a;
01329 while (xxx) {
01330 oqmlAtom *next = xxx->next;
01331 printf("previous #%d -> %s %s\n", nn, a->getString(), (next ? next->getString() : "<NIL>"));
01332 nn++;
01333 xxx = next;
01334 }
01335
01336 nn = 0;
01337 #endif
01338
01339 while (a) {
01340 oqmlAtom *next = a->next;
01341
01342
01343
01344
01345 oqmlAtom **cpatom_next = 0;
01346 if (cpatom_while)
01347 cpatom_next = next_cpatoms(cpatoms_n, cpcnt_n);
01348 OQML_CHECK_INTR();
01349 if (ident) {
01350 ctx->pushSymbol(ident, &a->type, a, oqml_False);
01351
01352 SELECT_TRACE(("\tPushing Symbol %s -> %s\n", ident, a->getString()));
01353
01354 if (n != ident_cnt - 1) {
01355 SELECT_TRACE(("\tBefore Calling EvalCartProdRealize "
01356 "recursively(%s)\n", (const char *)toString()));
01357 s = evalCartProdRealize(db, ctx, rlist, n+1, preval_ident,
01358 cpatoms_n, cpcnt_n);
01359 SELECT_TRACE(("\tAfter Calling EvalCartProdRealize "
01360 "recursively(%s)\n", (const char *)toString()));
01361 }
01362 else {
01363 oqmlAtomList *xlist = 0;
01364 if (where && ctx->isPrevalContext())
01365 {
01366 oqmlBool done;
01367 unsigned int cnt;
01368 SELECT_TRACE(("\tBefore PreEvaluatingSelect Where(%s)\n",
01369 (const char *)where->toString()));
01370 ctx->pushCPAtom(this, a);
01371 s = where->preEvalSelect(db, ctx, preval_ident, done, cnt,
01372 oqml_False);
01373 ctx->popCPAtom(this);
01374 SELECT_TRACE(("\tAfter PreEvaluatingSelect Where(%s)\n",
01375 (const char *)where->toString()));
01376 }
01377 else if (where && !(where_optim && where->asComp())) {
01378
01379 int select_ctx_cnt = ctx->setSelectContextCount(0);
01380 SELECT_TRACE(("\tBefore Evaluating Where(%s)\n",
01381 (const char *)where->toString()));
01382
01383 ctx->incrHiddenSelectContext(this);
01384 s = where->eval(db, ctx, &xlist);
01385 ctx->decrHiddenSelectContext();
01386 SELECT_TRACE(("\tAfter Evaluating Where(%s)\n",
01387 (const char *)where->toString()));
01388
01389 if (xlist && !xlist->first)
01390 SELECT_TRACE(("\tWhere(%s) returning false\n",
01391 (const char *)where->toString()));
01392 if (!s && xlist->first) {
01393 if (!OQML_IS_BOOL(xlist->first)) {
01394 s = new oqmlStatus(this,
01395 "where condition: "
01396 "boolean expected, got %s",
01397 xlist->first->type.getString());
01398 }
01399 else if (OQML_ATOM_BOOLVAL(xlist->first)) {
01400 SELECT_TRACE(("\tWhere(%s) returning true\n",
01401 (const char *)where->toString()));
01402 oqmlAtomList *ylist;
01403 s = projection->eval(db, ctx, &ylist);
01404 if (!s && ylist->first)
01405 {
01406 if (!distinct || !rlist->isIn(ylist->first)) {
01407 SELECT_TRACE(("\tWhere(%s) appending %s\n",
01408 (const char *)where->toString(),
01409 (const char *)ylist->first->getString()));
01410 rlist->append(ylist->first);
01411 #ifdef SYNC_GARB
01412 if (ylist && !ylist->refcnt) {
01413 ylist->first = 0;
01414 delete ylist;
01415 }
01416 #endif
01417 }
01418 }
01419 }
01420 else
01421 SELECT_TRACE(("\tWhere(%s) returning false\n",
01422 (const char *)where->toString()));
01423 }
01424
01425
01426 ctx->setSelectContextCount(select_ctx_cnt);
01427 #ifdef SYNC_GARB
01428 OQL_DELETE(xlist);
01429 #endif
01430 }
01431 else {
01432
01433 oqmlAtomList *ylist;
01434 int select_ctx_cnt = ctx->setSelectContextCount(0);
01435 s = projection->eval(db, ctx, &ylist);
01436 if (!s && ylist->first) {
01437 SELECT_TRACE(("\t%sappending %s\n",
01438 "Unconditionally ",
01439 (const char *)ylist->first->getString()));
01440 rlist->append(ylist->first);
01441 #ifdef SYNC_GARB
01442 if (ylist && !ylist->refcnt) {
01443 ylist->first = 0;
01444 delete ylist;
01445 }
01446 #endif
01447 }
01448
01449 ctx->setSelectContextCount(select_ctx_cnt);
01450 }
01451 }
01452
01453 ctx->popSymbol(ident, oqml_False);
01454
01455 if (s)
01456 break;
01457 }
01458
01459 if (cpatom_while)
01460 delete [] cpatoms_n;
01461
01462 cpatoms_n = cpatom_next;
01463 a = next;
01464 }
01465
01466 if (cpatom_while)
01467 delete [] cpatoms_n;
01468
01469 SELECT_TRACE(("\tLoop end `%s'\n", (const char *)toString()));
01470
01471 ctx->decrWhereContext();
01472 #ifdef SYNC_GARB
01473
01474 #endif
01475 return s;
01476 }
01477
01478 static oqmlContext *context;
01479
01480 int identlink_cmp(const void *xi1, const void *xi2)
01481 {
01482 const oqml_IdentLink *i1 = *(const oqml_IdentLink **)xi1;
01483 const oqml_IdentLink *i2 = *(const oqml_IdentLink **)xi2;
01484 oqmlAtom *a1, *a2;
01485
01486 if (context->getSymbol(i1->ident, 0, &a1) && a1 && a1->as_select() &&
01487 context->getSymbol(i2->ident, 0, &a2) && a2 && a2->as_select())
01488 {
01489 if (a1->as_select()->isPopulated())
01490 {
01491 if (a2->as_select()->isPopulated())
01492 return 0;
01493 return -1;
01494 }
01495 else if (a2->as_select()->isPopulated())
01496 return 1;
01497
01498 if (a1->as_select()->indexed)
01499 {
01500 if (a2->as_select()->indexed)
01501 return 0;
01502 return -1;
01503 }
01504 else if (a2->as_select()->indexed)
01505 return 1;
01506 }
01507
01508 return 0;
01509 }
01510
01511 static void
01512 dump_idents(const char *msg, oqml_IdentLink *idents[], int n)
01513 {
01514 printf("%s: ", msg);
01515 for (int i = 0; i < n; i++)
01516 printf("ident[%d] = %s\n", i, idents[i]->ident);
01517 }
01518
01519 oqmlBool
01520 oqmlSelect::usesFromIdent(oqmlNode *node)
01521 {
01522 if (!ident_from_list)
01523 return oqml_False;
01524
01525 oqml_IdentLink *l = ident_from_list->first;
01526
01527 while (l)
01528 {
01529 if (node->hasIdent(l->ident))
01530 return oqml_True;
01531 l = l->next;
01532 }
01533
01534 return oqml_False;
01535 }
01536
01537 oqmlStatus *
01538 oqmlSelect::evalCartProd(Database *db, oqmlContext *ctx,
01539 oqmlAtomList **alist)
01540 {
01541 oqmlStatus *s = oqmlSuccess;
01542
01543 if (ident_cnt > 1)
01544 {
01545 context = ctx;
01546
01547 qsort(idents, ident_cnt, sizeof(oqml_IdentLink *), identlink_cmp);
01548
01549 }
01550
01551 #define OPT_DEAD_IDENTS
01552
01553 #ifdef OPT_DEAD_IDENTS
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563 for (int i = 0; i < ident_cnt; i++)
01564 if (!projection->hasIdent(idents[i]->ident) &&
01565 (!where || !where->hasIdent(idents[i]->ident)) &&
01566 !checkIdent(idents, i, ident_cnt))
01567 idents[i]->skipIdent = oqml_True;
01568 #endif
01569
01570 oqmlAtomList *rlist = new oqmlAtomList();
01571
01572 SELECT_TRACE(("\nEvalCartProd Start `%s'\n",
01573 (const char *)toString()));
01574
01575 if (!s)
01576 s = evalCartProdRealize(db, ctx, rlist, 0);
01577
01578 SELECT_TRACE(("EvalCartProd End `%s'\n",
01579 (const char *)toString()));
01580
01581 if (s) return s;
01582
01583 if (one)
01584 *alist = new oqmlAtomList(rlist->first);
01585 else
01586 {
01587 oqmlAtom_coll *list;
01588 if (distinct)
01589 list = new oqmlAtom_set(rlist, oqml_False);
01590 else
01591 list = new oqmlAtom_bag(rlist);
01592
01593
01594 *alist = new oqmlAtomList(list);
01595 }
01596
01597
01598 return oqmlSuccess;
01599 }
01600
01601
01602
01603 #ifdef NEW_ONEATOM
01604 static oqmlBool
01605 xalist_make(oqmlBool one, oqmlAtomList *xalist, oqmlAtomList *alist)
01606 #else
01607 static oqmlBool
01608 xalist_make(oqmlContext *ctx, oqmlAtomList *xalist, oqmlAtomList *alist)
01609 #endif
01610 {
01611 if (!alist)
01612 return oqml_True;
01613
01614 oqmlAtom *xa = xalist->first;
01615 oqmlAtom *a = alist->first;
01616
01617 if (xa && OQML_IS_COLL(xa)) {
01618 if (OQML_IS_COLL(a))
01619 OQML_ATOM_COLLVAL(xa)->append(OQML_ATOM_COLLVAL(a));
01620 else
01621 OQML_ATOM_COLLVAL(xa)->append(a);
01622 }
01623 else if (a)
01624 xalist->append(a);
01625
01626 #ifdef NEW_ONEATOM
01627 if (xalist->cnt && one)
01628 return oqml_False;
01629 #else
01630 if (xalist->cnt && ctx->isOneAtom())
01631 return oqml_False;
01632 #endif
01633
01634 return oqml_True;
01635 }
01636
01637 oqmlStatus *oqmlSelect::eval(Database *db, oqmlContext *ctx, oqmlAtomList **xalist, oqmlComp *, oqmlAtom *)
01638 {
01639 if (one && order)
01640 return new oqmlStatus(this,
01641 "cannot use an order by clause within a select one");
01642
01643 oqmlStatus *s;
01644
01645 s = oqml_get_locations(db, ctx, location, dbs, dbs_cnt);
01646 if (s) return s;
01647
01648 int where_ctx = ctx->setWhereContext(0);
01649 int preval_ctx = ctx->setPrevalContext(0);
01650
01651 oqmlBool oldone = ctx->isOneAtom();
01652 #ifdef NEW_ONEATOM
01653 if (oldone) {
01654 printf("warning: a `select' expression should not be imbricated in a `select one' expression");
01655 }
01656 #else
01657 if (oldone)
01658 return new oqmlStatus(this, "a `select' expression cannot be imbricated in a `select one' expression");
01659
01660 if (one && ident_from_list && ident_from_list->cnt > 1)
01661 return new oqmlStatus(this, "a join cannot be performed in a `select one' expression");
01662 #endif
01663
01664 if (one) ctx->setOneAtom();
01665
01666 SELECT_TRACE(("Eval(%s)\n", (const char *)toString()));
01667 *xalist = new oqmlAtomList();
01668
01669 for (int i = 0; i < dbs_cnt; i++) {
01670 oqmlAtomList *alist = 0;
01671 db = dbs[i];
01672 calledFromEval = oqml_True;
01673 s = compile(db, ctx);
01674 calledFromEval = oqml_False;
01675 if (s) return s;
01676
01677
01678 if (!ident_from_list)
01679 {
01680 ctx->incrSelectContext(this);
01681 s = projection->eval(db, ctx, &alist);
01682 ctx->decrSelectContext();
01683
01684 if (s) return s;
01685
01686 if (distinct && alist->cnt && OQML_IS_COLL(alist->first))
01687 {
01688 oqmlAtom_set *list = new oqmlAtom_set
01689 (OQML_ATOM_COLLVAL(alist->first));
01690
01691 }
01692 else if (one)
01693 {
01694 if (alist->cnt && OQML_IS_COLL(alist->first))
01695 alist = new oqmlAtomList(OQML_ATOM_COLLVAL(alist->first)->first);
01696 else
01697 alist = new oqmlAtomList(alist->first);
01698 }
01699
01700 if (s) return s;
01701
01702 #ifdef NEW_ONEATOM
01703 if (!xalist_make(one, *xalist, alist))
01704 break;
01705 #else
01706 if (!xalist_make(ctx, *xalist, alist))
01707 break;
01708 #endif
01709 continue;
01710 }
01711
01712 s = oqmlSuccess;
01713 char *popIdent = 0;
01714
01715 oqml_IdentLink *l = ident_from_list->first;
01716 while (l)
01717 {
01718 ctx->pushSymbol(l->ident, &selectAtomType,
01719 new oqmlAtom_select(l->ql, l->ql), oqml_False);
01720 l = l->next;
01721 }
01722
01723 s = processRequalification_2(db, ctx);
01724
01725
01726
01727
01728
01729
01730
01731
01732 if (!s && where)
01733 {
01734 oqml_IdentLink *l = ident_from_list->first;
01735
01736 while (l)
01737 {
01738 if (l->ql->getType() == oqmlIDENT)
01739 {
01740 oqmlBool done;
01741 ctx->incrSelectContext(this);
01742 ctx->incrPrevalContext();
01743 unsigned int cnt;
01744 SELECT_TRACE(("Before Where PreEvalSelect `%s' %s\n",
01745 (const char *)toString(),
01746 (const char *)where->toString()));
01747 s = where->preEvalSelect(db, ctx, l->ident, done, cnt);
01748 SELECT_TRACE(("After Where PreEvalSelect `%s' %s\n",
01749 (const char *)toString(),
01750 (const char *)where->toString()));
01751 ctx->decrPrevalContext();
01752 popIdent = l->ident;
01753 ctx->decrSelectContext();
01754 if (s)
01755 break;
01756 oqmlAtom *atom_select = 0;
01757 ctx->getSymbol(l->ident, 0, &atom_select);
01758 if (atom_select->as_select()->list)
01759 break;
01760 }
01761 l = l->next;
01762 }
01763 }
01764
01765 if (!s) {
01766 s = evalCartProd(db, ctx, &alist);
01767
01768 }
01769
01770 l = ident_from_list->first;
01771 while (l)
01772 {
01773 ctx->popSymbol(l->ident, oqml_False);
01774 l = l->next;
01775 }
01776
01777 if (s) return s;
01778 #ifdef NEW_ONEATOM
01779 if (!xalist_make(one, *xalist, alist))
01780 break;
01781 #else
01782 if (!xalist_make(ctx, *xalist, alist))
01783 break;
01784 #endif
01785 }
01786
01787 #ifdef NEW_ONEATOM
01788 ctx->setOneAtom(oqml_False);
01789 #else
01790 ctx->setOneAtom(oldone);
01791 #endif
01792 if (distinct) {
01793 oqmlAtom *xa = (*xalist)->first;
01794 if (xa && OQML_IS_COLL(xa))
01795 *xalist = new oqmlAtomList(new oqmlAtom_set(OQML_ATOM_COLLVAL(xa)));
01796 }
01797
01798 s = realize_order(xalist);
01799 (void)ctx->setWhereContext(where_ctx);
01800 (void)ctx->setPrevalContext(preval_ctx);
01801 return s;
01802 }
01803
01804 void oqmlSelect::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01805 {
01806 *at = eval_type;
01807 }
01808
01809 oqmlBool oqmlSelect::isConstant() const
01810 {
01811 return oqml_False;
01812 }
01813
01814 std::string
01815 oqmlSelect::toString(void) const
01816 {
01817 std::string s = (is_statement ? std::string("") : std::string("(")) +
01818 (databaseStatement ? "context" : "select") +
01819 (location ? std::string("<") + location->toString() + "> " :
01820 std::string(" ")) + (one ? "one " : "") + (distinct ? "distinct " : "") +
01821 (projection ? projection->toString() : std::string("*"));
01822
01823 if (ident_from_list)
01824 {
01825 s += " from ";
01826 oqml_IdentLink *l = ident_from_list->first;
01827 for (int n = 0, c = 0; l; n++, l = l->next)
01828
01829 {
01830 if (c) s += ",";
01831 if (l->ql)
01832 s += l->ql->toString();
01833 if (l->ident)
01834 s += std::string(" as ") + l->ident;
01835 c++;
01836 }
01837 }
01838
01839 if (where)
01840 s += std::string(" where ") + where->toString();
01841
01842 if (group)
01843 s += std::string(" group by ") + group->toString();
01844
01845 if (having)
01846 s += std::string(" having ") + having->toString();
01847
01848 if (order)
01849 {
01850 s += std::string(" order by ");
01851 s += order->list->toString();
01852 s += order->asc ? " asc" : " desc";
01853 }
01854
01855 if (is_statement)
01856 return s + "; ";
01857
01858 return s + ")";
01859 }
01860
01861 void
01862 oqmlSelect::lock()
01863 {
01864 oqmlNode::lock();
01865 projection->lock();
01866 if (location) location->lock();
01867 if (where) where->lock();
01868 if (group) group->lock();
01869 if (having) having->lock();
01870 if (order) order->list->lock();
01871 if (!ident_from_list)
01872 return;
01873
01874 oqml_IdentLink *l = ident_from_list->first;
01875 while (l)
01876 {
01877 l->ql->lock();
01878 l = l->next;
01879 }
01880 }
01881
01882 void
01883 oqmlSelect::unlock()
01884 {
01885 oqmlNode::unlock();
01886 projection->unlock();
01887 if (location) location->unlock();
01888 if (where) where->unlock();
01889 if (group) group->unlock();
01890 if (having) having->unlock();
01891 if (order) order->list->unlock();
01892 if (!ident_from_list)
01893 return;
01894
01895 oqml_IdentLink *l = ident_from_list->first;
01896 while (l)
01897 {
01898 l->ql->unlock();
01899 l = l->next;
01900 }
01901 }
01902
01903 void
01904 oqml_capstring(char *str)
01905 {
01906 char c;
01907 while (c = *str)
01908 {
01909 if (c >= 'a' && c <= 'z')
01910 *str = c + 'A' - 'a';
01911 str++;
01912 }
01913 }
01914 }