Beispiel #1
0
void joinGeneric(redisClient *c,
                 jb_t        *jb) {
    if (jb->w.nob > 1) {
        addReply(c, shared.join_m_obc);
        return;
    }
    Order_by         = jb->w.nob;
    Order_by_col_val = NULL;

    /* sort queried-columns to queried-indices */
    jqo_t o_csort_order[MAX_COLUMN_PER_TABLE];
    jqo_t csort_order  [MAX_COLUMN_PER_TABLE];
    for (int i = 0; i < jb->qcols; i++) {
        for (int j = 0; j < jb->n_ind; j++) {
            if (jb->j_tbls[i] == Index[server.dbid][jb->j_indxs[j]].table) {
                csort_order[i].t = jb->j_tbls[i];
                csort_order[i].i = j;
                csort_order[i].c = jb->j_cols[i];
                csort_order[i].n = i;
            }
        }
    }
    memcpy(&o_csort_order, &csort_order, sizeof(jqo_t) * jb->qcols);
    qsort(&csort_order, jb->qcols, sizeof(jqo_t), cmp_jqo);

    /* reorder queried-columns to queried-indices, will sort @ output time */
    bool reordered = 0;
    for (int i = 0; i < jb->qcols; i++) {
        if (jb->j_tbls[i] != csort_order[i].t ||
            jb->j_cols[i] != csort_order[i].c) {
                reordered = 1;
                jb->j_tbls[i] = csort_order[i].t;
                jb->j_cols[i] = csort_order[i].c;
        }
    }

    cswc_t *w      = &jb->w; /* makes coding more compact */
    w->tmatch      = w->obt[0]; /* HACK: initOBsort needs w->tmatch */
    list   *ll     = initOBsort(Order_by, w);
    uchar  pk1type = Tbl[server.dbid]
                         [Index[server.dbid][jb->j_indxs[0]].table].col_type[0];
    bt    *jbtr    = createJoinResultSet(pk1type);

    robj  *rset[MAX_JOIN_INDXS];
    for (int i = 1; i < jb->n_ind; i++) {
        rset[i] = createValSetObject();
    }

    int j_ind_len [MAX_JOIN_INDXS];
    int jind_ncols[MAX_JOIN_INDXS];
    join_add_cols_t jc; /* these dont change in the loop below */
    jc.qcols      = jb->qcols;
    jc.j_tbls     = jb->j_tbls;
    jc.j_cols     = jb->j_cols;
    jc.jind_ncols = jind_ncols;
    jc.j_ind_len  = j_ind_len;
    jc.jbtr       = jbtr;
    
    for (int i = 0; i < jb->n_ind; i++) { /* iterate join indices */
        btEntry    *be, *nbe;
        j_ind_len[i] = 0;
        jc.index     = i;
        jc.itable    = Index[server.dbid][jb->j_indxs[i]].table;
        robj *btt    = lookupKeyRead(c->db, Tbl[server.dbid][jc.itable].name);
        jc.btr       = (bt *)btt->ptr;
        jc.virt      = Index[server.dbid][jb->j_indxs[i]].virt;
     
        if (w->low) { /* RANGE QUERY */
            if (jc.virt) { /* PK */
                btSIter *bi = btGetRangeIterator(jc.btr, w->low, w->high);
                while ((be = btRangeNext(bi)) != NULL) {
                    jc.ajk    = be->key;
                    jc.rrow   = be->val;
                    joinAddColsFromInd(&jc, rset, w);
                }
                btReleaseRangeIterator(bi);
            } else {       /* FK */
                robj    *ind  = Index[server.dbid][jb->j_indxs[i]].obj;
                robj    *ibtt = lookupKey(c->db, ind);
                bt      *ibtr = (bt *)ibtt->ptr;
                btSIter *bi   = btGetRangeIterator(ibtr, w->low, w->high);
                while ((be = btRangeNext(bi)) != NULL) {
                    jc.ajk        = be->key;
                    bt      *nbtr = be->val;
                    btSIter *nbi  = btGetFullRangeIterator(nbtr);
                    while ((nbe = btRangeNext(nbi)) != NULL) {
                        jc.rrow = btFindVal(jc.btr, nbe->key);
                        joinAddColsFromInd(&jc, rset, w);
                    }
                    btReleaseRangeIterator(nbi);
                }
                btReleaseRangeIterator(bi);
            }
        } else {      /* IN() QUERY */
            listNode *ln;
            listIter *li  = listGetIterator(w->inl, AL_START_HEAD);
            if (jc.virt) {
                while((ln = listNext(li)) != NULL) {
                    jc.ajk  = ln->value;
                    jc.rrow = btFindVal(jc.btr, jc.ajk);
                    if (jc.rrow) joinAddColsFromInd(&jc, rset, w);
                }
            } else {
                btSIter *nbi;
                robj *ind    = Index[server.dbid][jb->j_indxs[i]].obj;
                robj *ibtt   = lookupKey(c->db, ind);   
                bt   *ibtr   = (bt *)ibtt->ptr;
                while((ln = listNext(li)) != NULL) {
                    jc.ajk   = ln->value;
                    bt *nbtr = btIndFindVal(ibtr, jc.ajk);
                    if (nbtr) {
                        nbi  = btGetFullRangeIterator(nbtr);
                        while ((nbe = btRangeNext(nbi)) != NULL) {
                            jc.rrow = btFindVal(jc.btr, nbe->key);
                            joinAddColsFromInd(&jc, rset, w);
                        }
                        btReleaseRangeIterator(nbi);
                    }
                }
            }
            listReleaseIterator(li);
        }
    }

    /* cant join if one table had ZERO rows */
    bool one_empty = 0;
    if (jbtr->numkeys == 0) one_empty = 1;
    else {
        for (int i = 1; i < jb->n_ind; i++) {
            if (dictSize((dict *)rset[i]->ptr) == 0) {
                one_empty = 1;
                break;
            }
        }
    }

    LEN_OBJ

    bool        err   = 0;
    long        sent  = 0;
    btIterator *bi    = NULL; /* B4 GOTO */
    char       *reply = NULL; /* B4 GOTO */
    if (!one_empty) {
        int reply_size = 0;
        for (int i = 0; i < jb->n_ind; i++) { // get maxlen possbl 4 joined row
            reply_size += j_ind_len[i] + 1;
        }
        reply = malloc(reply_size); /* freed after while() loop */
    
        build_jrow_reply_t bjr; /* none of these change during a join */
        bzero(&bjr, sizeof(build_jrow_reply_t));
        bjr.j.c           = c;
        bjr.j.jind_ncols  = jind_ncols;
        bjr.j.reply       = reply;
        bjr.j.csort_order = csort_order;
        bjr.j.reordered   = reordered;
        bjr.j.qcols       = jb->qcols;
        bjr.n_ind         = jb->n_ind;
        bjr.card          = &card;
        bjr.j.obt         = w->obt[0];
        bjr.j.obc         = w->obc[0];
        bjr.j_indxs       = jb->j_indxs;
        bjr.j.ll          = ll;
        bjr.j.cstar       = jb->cstar;

        joinRowEntry *be;
        bi = btGetJoinFullRangeIterator(jbtr, pk1type);
        while ((be = btJoinRangeNext(bi, pk1type)) != NULL) { /* iter BT */
            listNode *ln;
            bjr.jk        = be->key;
            list     *jll = (list *)be->val;
            listIter *li  = listGetIterator(jll, AL_START_HEAD);
            while((ln = listNext(li)) != NULL) {        /* iter LIST */
                char *first_entry;
                char *item = ln->value;
                if (bjr.j.obt == Index[server.dbid][bjr.j_indxs[0]].table) {
                    obsl_t *ob       = (obsl_t *)item;
                    Order_by_col_val = ob->keys[0];
                    first_entry      = (char *)ob->row;
                } else {
                    first_entry      = item;
                }
                for (int j = 0; j < jind_ncols[0]; j++) {
                    Rcols[0][j]  = (char **)first_entry;
                    first_entry += PTR_SIZE;
                    memcpy(&Rc_lens[0][j], first_entry, UINT_SIZE);
                    first_entry += UINT_SIZE;
                }
    
                if (!buildJRowReply(&bjr, 1, rset)) {
                    err = 1;
                    goto join_end;
                }
            }
            listReleaseIterator(li);
        }

        if (Order_by) {
            sent = sortJoinOrderByAndReply(c, &bjr, w);
            if (sent == -1) err = 1;
            releaseOBsort(ll);
        }
    }

join_end:
    if (bi)    btReleaseJoinRangeIterator(bi);
    if (reply) free(reply);

    /* free joinRowEntry malloc from joinAddColsFromInd() */
    bool  is_ob = (w->obt[0] == Index[server.dbid][jb->j_indxs[0]].table);
    btJoinRelease(jbtr, jind_ncols[0], is_ob, freeListOfIndRow);

    /* free joinRowEntry malloc from joinAddColsFromInd() */
    dictEntry *de;
    for (int i = 1; i < jb->n_ind; i++) {
        dict *set   = rset[i]->ptr;
        bool  is_ob = (w->obt[0] == Index[server.dbid][jb->j_indxs[i]].table);
        dictIterator *di = dictGetIterator(set);
        while((de = dictNext(di)) != NULL) {
            robj *val  = dictGetEntryVal(de);
            dict *iset = val->ptr;
            freeDictOfIndRow(iset, jind_ncols[i], is_ob);
        }
        dictReleaseIterator(di);
    }

    for (int i = 1; i < jb->n_ind; i++) {
        decrRefCount(rset[i]);
    }

    if (err) return;
    if (w->lim != -1 && sent < card) card = sent;
    if (jb->cstar) {
        lenobj->ptr = sdscatprintf(sdsempty(), ":%ld\r\n", card);
    } else {
        lenobj->ptr = sdscatprintf(sdsempty(), "*%ld\r\n", card);
        if (w->ovar) incrOffsetVar(c, w, card);
    }
}
Beispiel #2
0
/* SYNTAX
   1.) SCANSELECT * FROM tbl
   2.) SCANSELECT * FROM tbl ORDER_BY_CLAUSE
   3.) SCANSELECT * FROM tbl WHERE clause [ORDER_BY_CLAUSE]
*/
void tscanCommand(redisClient *c) {
    int  cmatchs[MAX_COLUMN_PER_TABLE];
    bool nowc   =  0; /* NO WHERE CLAUSE */
    bool cstar  =  0;
    int  qcols  =  0;
    int  tmatch = -1;
    bool join   =  0;
    sds  where  = (c->argc > 4) ? c->argv[4]->ptr : NULL;
    sds  wc     = (c->argc > 5) ? c->argv[5]->ptr : NULL;
    if ((where && !*where) || (wc && !*wc)) {
        addReply(c, shared.scanselectsyntax);
        return;
    }
    if (!parseSelectReply(c, 1, &nowc, &tmatch, cmatchs, &qcols, &join,
                          &cstar, c->argv[1]->ptr, c->argv[2]->ptr,
                          c->argv[3]->ptr, where)) return;
    if (join) {
        addReply(c, shared.scan_join);
        return;
    }
    if (!nowc && !wc) {
        addReply(c, shared.scanselectsyntax);
        return;
    }

    cswc_t  w;
    list   *ll  = NULL; /* B4 GOTO */
    init_check_sql_where_clause(&w, tmatch, wc); /* on error: GOTO tscan_end */

    if (nowc && c->argc > 4) { /* ORDER BY or STORE w/o WHERE CLAUSE */
        if (!strncasecmp(where, "ORDER ", 6) ||
            !strncasecmp(where, "STORE ", 6)) {
            if (!parseWCAddtlSQL(c, c->argv[4]->ptr, &w)) goto tscan_end;
            if (w.lvr) {
                w.lvr = sdsnewlen(w.lvr, strlen(w.lvr));
                if (!leftoverParsingReply(c, w.lvr))      goto tscan_end;
            }
            if (w.wtype > SQL_STORE_LOOKUP_MASK) { /* STORE after ORDER BY */
                addReply(c, shared.scan_store);
                goto tscan_end;
            }
        }
    }
    if (nowc && !w.nob && c->argc > 4) { /* argv[4] parse error */
        w.lvr = sdsdup(where);
        leftoverParsingReply(c, w.lvr);
        goto tscan_end;
    }

    if (!nowc && !w.nob) { /* WhereClause exists and no ORDER BY */
        parseWCReply(c, &w, SQL_SCANSELECT, 1);
        if (w.wtype == SQL_ERR_LOOKUP)       goto tscan_end;
        if (!leftoverParsingReply(c, w.lvr)) goto tscan_end;
        if (w.imatch != -1) { /* disallow SCANSELECT on indexed columns */
            addReply(c, shared.scan_on_index);
            goto tscan_end;
        }
        if (w.wtype > SQL_STORE_LOOKUP_MASK) { /* no SCAN STOREs (for now) */
            addReply(c, shared.scan_store);
            goto tscan_end;
        }
    }

    if (cstar && w.nob) { /* SCANSELECT COUNT(*) ORDER BY -> stupid */
        addReply(c, shared.orderby_count);
        goto tscan_end;
    }

    robj *btt  = lookupKeyRead(c->db, Tbl[server.dbid][w.tmatch].name);
    bt   *btr = (bt *)btt->ptr;
    if (cstar && nowc) { /* SCANSELECT COUNT(*) FROM tbl */
        addReplyLongLong(c, (long long)btr->numkeys);
        goto tscan_end;
    }
    // TODO on "fk_lim" iterate on FK (not PK)
    //if (w.nob) w.imatch = find_index(w.tmatch, w.obc);
    fr_t fr;
    qr_t q;
    setQueued(&w, &q);
    ll = initOBsort(q.qed, &w);
    init_filter_row(&fr, c, btr, &w, &q, qcols, cmatchs, nowc,
                    ll, cstar, OBY_FREE_ROBJ);
    //dumpW(&w, w.wtype);
    LEN_OBJ
    btEntry *be;
    long     sent  =  0;
    long     loops = -1;
    btSIter *bi    = q.pk_lo ? btGetFullIteratorXth(btr, w.ofst):
                               btGetFullRangeIterator(btr);
    while ((be = btRangeNext(bi)) != NULL) {
        loops++;
        if (q.pk_lim) {
            if (!q.pk_lo && w.ofst != -1 && loops < w.ofst) continue;
            sent++;
            if (w.lim == card) break; /* ORDRBY PK LIM */
        }
        condSelectReply(&fr, be->key, be->val, &card);
    }
    btReleaseRangeIterator(bi);

    if (q.qed && card) opSelectOnSort(c, ll, &w, fr.ofree, &sent);

    if (w.lim != -1 && sent < card) card = sent;
    if (cstar) lenobj->ptr = sdscatprintf(sdsempty(), ":%ld\r\n", card);
    else       lenobj->ptr = sdscatprintf(sdsempty(), "*%ld\r\n", card);

    if (w.ovar) incrOffsetVar(c, &w, card);

tscan_end:
    releaseOBsort(ll);
    destroy_check_sql_where_clause(&w);
}