Changeset: a62315e6e373 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/a62315e6e373
Modified Files:
        gdk/gdk.h
        gdk/gdk_join.c
        monetdb5/modules/kernel/algebra.c
Branch: groupjoin
Log Message:

Implemented BATmarkjoin.


diffs (truncated from 1907 to 300 lines):

diff --git a/gdk/gdk.h b/gdk/gdk.h
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -2307,6 +2307,8 @@ gdk_export gdk_return BAToutercross(BAT 
 
 gdk_export gdk_return BATleftjoin(BAT **r1p, BAT **r2p, BAT *l, BAT *r, BAT 
*sl, BAT *sr, bool nil_matches, BUN estimate)
        __attribute__((__warn_unused_result__));
+gdk_export gdk_return BATmarkjoin(BAT **r1p, BAT **r2p, BAT **r3p, BAT *l, BAT 
*r, BAT *sl, BAT *sr, BUN estimate)
+       __attribute__((__warn_unused_result__));
 gdk_export gdk_return BATouterjoin(BAT **r1p, BAT **r2p, BAT *l, BAT *r, BAT 
*sl, BAT *sr, bool nil_matches, bool match_one, BUN estimate)
        __attribute__((__warn_unused_result__));
 gdk_export gdk_return BATthetajoin(BAT **r1p, BAT **r2p, BAT *l, BAT *r, BAT 
*sl, BAT *sr, int op, bool nil_matches, BUN estimate)
diff --git a/gdk/gdk_join.c b/gdk/gdk_join.c
--- a/gdk/gdk_join.c
+++ b/gdk/gdk_join.c
@@ -44,6 +44,13 @@
  *     equi-join, but the left output is sorted, and if there are
  *     multiple matches, only one is returned (i.e., the left output
  *     is also key, making it a candidate list)
+ * BATmarkjoin
+ *     equi-join, but the left output is sorted, if there is no
+ *     match for a value in the left input, there is still an output
+ *     with NIL in the right output, and there is a third output column
+ *     containing a flag that indicates the "certainty" of the match: 1
+ *     there is a match, 0, there is no match and there are no NIL
+ *     values, NIL, there is no match but there are NIL values
  * BATthetajoin
  *     theta-join: an extra operator must be provided encoded as an
  *     integer (macros JOIN_EQ, JOIN_NE, JOIN_LT, JOIN_LE, JOIN_GT,
@@ -99,11 +106,11 @@ joinparamcheck(BAT *l, BAT *r1, BAT *r2,
 /* Create the result bats for a join, returns the absolute maximum
  * number of outputs that could possibly be generated. */
 static BUN
-joininitresults(BAT **r1p, BAT **r2p, BUN lcnt, BUN rcnt, bool lkey, bool rkey,
-               bool semi, bool nil_on_miss, bool only_misses, bool min_one,
-               BUN estimate)
+joininitresults(BAT **r1p, BAT **r2p, BAT **r3p, BUN lcnt, BUN rcnt,
+               bool lkey, bool rkey, bool semi, bool nil_on_miss,
+               bool only_misses, bool min_one, BUN estimate)
 {
-       BAT *r1, *r2;
+       BAT *r1, *r2, *r3;
        BUN maxsize, size;
 
        /* if nil_on_miss is set, we really need a right output */
@@ -115,6 +122,8 @@ joininitresults(BAT **r1p, BAT **r2p, BU
        *r1p = NULL;
        if (r2p)
                *r2p = NULL;
+       if (r3p)
+               *r3p = NULL;
        if (lcnt == 0) {
                /* there is nothing to match */
                maxsize = 0;
@@ -173,6 +182,17 @@ joininitresults(BAT **r1p, BAT **r2p, BU
                        }
                        *r2p = r2;
                }
+               if (r3p) {
+                       r3 = COLnew(0, TYPE_bit, 0, TRANSIENT);
+                       if (r3 == NULL) {
+                               BBPreclaim(r1);
+                               BBPreclaim(r2);
+                               if (r2p)
+                                       *r2p = NULL;
+                               return BUN_NONE;
+                       }
+                       *r3p = r3;
+               }
                *r1p = r1;
                return 0;
        }
@@ -204,6 +224,22 @@ joininitresults(BAT **r1p, BAT **r2p, BU
                r2->theap->dirty = true;
                *r2p = r2;
        }
+       if (r3p) {
+               BAT *r3 = COLnew(0, TYPE_bit, size, TRANSIENT);
+               if (r3 == NULL) {
+                       BBPreclaim(r1);
+                       BBPreclaim(r2);
+                       return BUN_NONE;
+               }
+               r3->tnil = false;
+               r3->tnonil = true;
+               r3->tkey = false;
+               r3->tsorted = false;
+               r3->trevsorted = false;
+               r3->tseqbase = oid_nil;
+               r3->theap->dirty = true;
+               *r3p = r3;
+       }
        return maxsize;
 }
 
@@ -216,7 +252,7 @@ joininitresults(BAT **r1p, BAT **r2p, BU
 #define APPEND(b, o)           (((oid *) b->theap->base)[b->batCount++] = (o))
 
 static inline gdk_return
-maybeextend(BAT *restrict r1, BAT *restrict r2,
+maybeextend(BAT *restrict r1, BAT *restrict r2, BAT *restrict r3,
            BUN cnt, BUN lcur, BUN lcnt, BUN maxsize)
 {
        if (BATcount(r1) + cnt > BATcapacity(r1)) {
@@ -243,11 +279,17 @@ maybeextend(BAT *restrict r1, BAT *restr
                                return GDK_FAIL;
                        assert(BATcapacity(r1) == BATcapacity(r2));
                }
+               if (r3) {
+                       BATsetcount(r3, BATcount(r3));
+                       if (BATextend(r3, newcap) != GDK_SUCCEED)
+                               return GDK_FAIL;
+                       assert(BATcapacity(r1) == BATcapacity(r3));
+               }
        }
        return GDK_SUCCEED;
 }
 
-/* Return BATs through r1p and r2p for the case that there is no
+/* Return BATs through r1p, r2p, and r3p for the case that there is no
  * match between l and r, taking all flags into consideration.
  *
  * This means, if nil_on_miss is set or only_misses is set, *r1p is a
@@ -255,10 +297,11 @@ maybeextend(BAT *restrict r1, BAT *restr
  * values of l, and *r2p (if r2p is not NULL) is all nil.  If neither
  * of those flags is set, the result is two empty BATs. */
 static gdk_return
-nomatch(BAT **r1p, BAT **r2p, BAT *l, BAT *r, struct canditer *restrict lci,
+nomatch(BAT **r1p, BAT **r2p, BAT **r3p, BAT *l, BAT *r,
+       struct canditer *restrict lci, bit defmark,
        bool nil_on_miss, bool only_misses, const char *func, lng t0)
 {
-       BAT *r1, *r2 = NULL;
+       BAT *r1, *r2 = NULL, *r3 = NULL;
 
        MT_thread_setalgorithm(__func__);
        if (lci->ncand == 0 || !(nil_on_miss | only_misses)) {
@@ -272,6 +315,14 @@ nomatch(BAT **r1p, BAT **r2p, BAT *l, BA
                        }
                        *r2p = r2;
                }
+               if (r3p) {
+                       if ((r3 = COLnew(0, TYPE_bit, 0, TRANSIENT)) == NULL) {
+                               BBPreclaim(r1);
+                               BBPreclaim(r2);
+                               return GDK_FAIL;
+                       }
+                       *r3p = r3;
+               }
        } else {
                r1 = canditer_slice(lci, 0, lci->ncand);
                if (r2p) {
@@ -281,16 +332,24 @@ nomatch(BAT **r1p, BAT **r2p, BAT *l, BA
                        }
                        *r2p = r2;
                }
+               if (r3p) {
+                       if ((r3 = BATconstant(0, TYPE_bit, &defmark, 
lci->ncand, TRANSIENT)) == NULL) {
+                               BBPreclaim(r1);
+                               BBPreclaim(r2);
+                               return GDK_FAIL;
+                       }
+                       *r3p = r3;
+               }
        }
        *r1p = r1;
        TRC_DEBUG(ALGO, "l=" ALGOBATFMT ",r=" ALGOBATFMT ",sl=" ALGOOPTBATFMT
                  ",nil_on_miss=%s,only_misses=%s"
-                 " - > " ALGOBATFMT "," ALGOOPTBATFMT
+                 " - > " ALGOBATFMT "," ALGOOPTBATFMT "," ALGOOPTBATFMT
                  " (%s -- " LLFMT "usec)\n",
                  ALGOBATPAR(l), ALGOBATPAR(r), ALGOOPTBATPAR(lci->s),
                  nil_on_miss ? "true" : "false",
                  only_misses ? "true" : "false",
-                 ALGOBATPAR(r1), ALGOOPTBATPAR(r2),
+                 ALGOBATPAR(r1), ALGOOPTBATPAR(r2), ALGOOPTBATPAR(r3),
                  func, GDKusec() - t0);
        return GDK_SUCCEED;
 }
@@ -299,7 +358,7 @@ nomatch(BAT **r1p, BAT **r2p, BAT *l, BA
  * repeated multiple times) on the left.  This means we can use a
  * point select to find matches in the right column. */
 static gdk_return
-selectjoin(BAT **r1p, BAT **r2p, BAT *l, BAT *r,
+selectjoin(BAT **r1p, BAT **r2p, BAT **r3p, BAT *l, BAT *r,
           struct canditer *lci, struct canditer *rci,
           bool nil_matches, bool nil_on_miss, bool semi, bool max_one, bool 
min_one,
           lng t0, bool swapped, const char *reason)
@@ -327,8 +386,9 @@ selectjoin(BAT **r1p, BAT **r2p, BAT *l,
            (*ATOMcompare(li.type))(v, ATOMnilptr(li.type)) == 0) {
                /* NIL doesn't match anything */
                bat_iterator_end(&li);
-               return nomatch(r1p, r2p, l, r, lci, nil_on_miss, false,
-                              reason, t0);
+               gdk_return rc = nomatch(r1p, r2p, r3p, l, r, lci, bit_nil, 
nil_on_miss,
+                                       false, reason, t0);
+               return rc;
        }
 
        bn = BATselect(r, rci->s, v, NULL, true, true, false);
@@ -343,9 +403,11 @@ selectjoin(BAT **r1p, BAT **r2p, BAT *l,
                        GDKerror("not enough matches");
                        return GDK_FAIL;
                }
-               if (!nil_on_miss)
-                       return nomatch(r1p, r2p, l, r, lci, nil_on_miss, false,
-                                      reason, t0);
+               if (!nil_on_miss) {
+                       assert(r3p == NULL);
+                       return nomatch(r1p, r2p, r3p, l, r, lci, 0, nil_on_miss,
+                                      false, reason, t0);
+               }
                /* special case: return nil on RHS */
                bncount = 1;
                bn = NULL;
@@ -447,16 +509,39 @@ selectjoin(BAT **r1p, BAT **r2p, BAT *l,
                BATsetcount(r2, lci->ncand * bncount);
                *r2p = r2;
        }
+       BAT *r3 = NULL;
+       if (r3p) {
+               bit mark;
+               if (bn) {
+                       /* there is a match */
+                       mark = 1;
+               } else if (r->tnonil) {
+                       /* no match, no NIL in r */
+                       mark = 0;
+               } else {
+                       /* no match, search for NIL in r */
+                       BAT *n = BATselect(r, rci->s, ATOMnilptr(r->ttype), 
NULL, true, true, false);
+                       if (n == NULL)
+                               goto bailout;
+                       mark = BATcount(n) == 0 ? 0 : bit_nil;
+                       BBPreclaim(n);
+               }
+               r3 = BATconstant(0, TYPE_bit, &mark, lci->ncand, TRANSIENT);
+               if (r3 == NULL)
+                       goto bailout;
+               *r3p = r3;
+       }
        BBPreclaim(bn);
        TRC_DEBUG(ALGO, "l=" ALGOBATFMT ","
                  "r=" ALGOBATFMT ",sl=" ALGOOPTBATFMT ","
                  "sr=" ALGOOPTBATFMT ",nil_matches=%s;%s %s "
-                 "-> " ALGOBATFMT "," ALGOOPTBATFMT " (" LLFMT "usec)\n",
+                 "-> " ALGOBATFMT "," ALGOOPTBATFMT "," ALGOOPTBATFMT
+                 " (" LLFMT "usec)\n",
                  ALGOBATPAR(l), ALGOBATPAR(r),
                  ALGOOPTBATPAR(lci->s), ALGOOPTBATPAR(rci->s),
                  nil_matches ? "true" : "false",
                  swapped ? " swapped" : "", reason,
-                 ALGOBATPAR(r1), ALGOOPTBATPAR(r2),
+                 ALGOBATPAR(r1), ALGOOPTBATPAR(r2), ALGOOPTBATPAR(r3),
                  GDKusec() - t0);
 
        return GDK_SUCCEED;
@@ -475,13 +560,14 @@ selectjoin(BAT **r1p, BAT **r2p, BAT *l,
 #endif
 
 /* Implementation of join where the right-hand side is dense, and if
- * there is a right candidate list, it too is dense.  In case
- * nil_on_miss is not set, we use a range select (BATselect) to find
- * the matching values in the left column and then calculate the
- * corresponding matches from the right.  If nil_on_miss is set, we
- * need to do some more work. */
+ * there is a right candidate list, it too is dense.  This means there
+ * are no NIL values in r.  In case nil_on_miss is not set, we use a
+ * range select (BATselect) to find the matching values in the left
+ * column and then calculate the corresponding matches from the right.
+ * If nil_on_miss is set, we need to do some more work. The latter is
+ * also the only case in which r3p van be set. */
 static gdk_return
-mergejoin_void(BAT **r1p, BAT **r2p, BAT *l, BAT *r,
+mergejoin_void(BAT **r1p, BAT **r2p, BAT **r3p, BAT *l, BAT *r,
               struct canditer *restrict lci, struct canditer *restrict rci,
               bool nil_on_miss, bool only_misses, lng t0, bool swapped,
               const char *reason)
@@ -489,7 +575,8 @@ mergejoin_void(BAT **r1p, BAT **r2p, BAT
        oid lo, hi;
        BUN i;
        oid o, *o1p = NULL, *o2p = NULL;
-       BAT *r1 = NULL, *r2 = NULL;
+       bit *m3p = NULL;
+       BAT *r1 = NULL, *r2 = NULL, *r3 = NULL;
        bool ltsorted = false, ltrevsorted = false, ltkey = false;
 
        /* r is dense, and if there is a candidate list, it too is
@@ -520,6 +607,7 @@ mergejoin_void(BAT **r1p, BAT **r2p, BAT
 
        /* at this point, the matchable values in r are [lo..hi) */
        if (!nil_on_miss) {
+               assert(r3p == NULL);
                r1 = BATselect(l, lci->s, &lo, &hi, true, false, only_misses);
                if (r1 == NULL)
                        return GDK_FAIL;
@@ -602,8 +690,9 @@ mergejoin_void(BAT **r1p, BAT **r2p, BAT
                *r2p = r2;
                goto doreturn2;
        }
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to