Changeset: 7e636e341f34 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/7e636e341f34
Modified Files:
        clients/Tests/exports.stable.out
        sql/backends/monet5/sql.c
        sql/backends/monet5/sql_execute.c
        sql/backends/monet5/sql_gencode.c
        sql/server/rel_optimizer.c
        sql/server/sql_mvc.c
        sql/server/sql_mvc.h
        sql/server/sql_parser.y
        sql/server/sql_scan.c
Branch: nested
Log Message:

merged with default


diffs (truncated from 591 to 300 lines):

diff --git a/clients/mapiclient/mhelp.c b/clients/mapiclient/mhelp.c
--- a/clients/mapiclient/mhelp.c
+++ b/clients/mapiclient/mhelp.c
@@ -412,12 +412,15 @@ SQLhelp sqlhelp1[] = {
        {"EXPLAIN",
         "Display logical or physical execution plan for the SQL statement.",
         "EXPLAIN [BEFORE|AFTER] [step] [SHOW DETAILS] statement\n"
-        "\twhere step is REL_UNNEST|REL_REWRITE|PHYSICAL",
+        "\twhere step is LOGICAL UNNEST | LOGICAL REWRITE [posint] [posint] | 
PHYSICAL",
         NULL,
         "Plain EXPLAIN defaults to logical plan.\n"
-        "Use REL_UNNEST|REL_REWRITE|PHYSICAL to specify compilation step to 
show.\n"
+        "Use LOGICAL UNNEST|LOGICAL REWRITE|PHYSICAL to specify compilation 
step to show.\n"
         "Use BEFORE|AFTER to specify moment of compilation step to output.\n"
         "The default is AFTER.\n"
+        "Two positive numbers can be passed to LOGICAL REWRITE to stop at 
specific\n"
+        "rewriter index or rewrite loop cycle, respectively.\n"
+        "If only one positive number is passed to LOGICAL REWRITE, rewrite 
stop cycle defaults to 0.\n"
         "SHOW DETAILS displays column properties, rewriter number of changes\n"
         "and time spent.\n"
         "See also 
https://www.monetdb.org/documentation/admin-guide/debugging-features/explain-sql-stmt/"},
diff --git a/common/stream/bs.c b/common/stream/bs.c
--- a/common/stream/bs.c
+++ b/common/stream/bs.c
@@ -30,6 +30,11 @@ bs_create(void)
        if ((ns = malloc(sizeof(*ns))) == NULL)
                return NULL;
        *ns = (bs) {0};
+#if !defined(HAVE_PTHREAD_H) && defined(WIN32)
+       InitializeCriticalSection(&ns->lock);
+#else
+       pthread_mutex_init(&ns->lock, NULL);
+#endif
        return ns;
 }
 
@@ -178,16 +183,28 @@ bs_putoob(stream *ss, char val)
 static int
 bs_getoob(stream *ss)
 {
+       int oobval;
        bs *s = (bs *) ss->stream_data.p;
        if (s == NULL || ss->inner->getoob == NULL)
                return 0;
+#if !defined(HAVE_PTHREAD_H) && defined(WIN32)
+       EnterCriticalSection(&s->lock);
+#else
+       pthread_mutex_lock(&s->lock);
+#endif
        if (s->seenoob) {
                s->seenoob = false;
-               return s->oobval;
-       }
-       if (ss->readonly && s->itotal == 0)
-               return ss->inner->getoob(ss->inner);
-       return 0;
+               oobval = s->oobval;
+       } else if (ss->readonly && s->itotal == 0)
+               oobval = ss->inner->getoob(ss->inner);
+       else
+               oobval = 0;
+#if !defined(HAVE_PTHREAD_H) && defined(WIN32)
+       LeaveCriticalSection(&s->lock);
+#else
+       pthread_mutex_unlock(&s->lock);
+#endif
+       return oobval;
 }
 
 /* Read buffered data and return the number of items read.  At the
@@ -306,6 +323,11 @@ bs_destroy(stream *ss)
        if (s) {
                if (ss->inner)
                        ss->inner->destroy(ss->inner);
+#if !defined(HAVE_PTHREAD_H) && defined(WIN32)
+               DeleteCriticalSection(&s->lock);
+#else
+               pthread_mutex_destroy(&s->lock);
+#endif
                free(s);
        }
        destroy_stream(ss);
diff --git a/common/stream/socket_stream.c b/common/stream/socket_stream.c
--- a/common/stream/socket_stream.c
+++ b/common/stream/socket_stream.c
@@ -92,7 +92,7 @@ socket_getoob(stream *s)
                        }
                }
 #endif
-               char b = 0;
+               unsigned char b = 0;
                switch (recv(fd, &b, 1, MSG_OOB)) {
                case 0:
                        /* unexpectedly didn't receive a byte */
@@ -163,7 +163,7 @@ socket_getoob_unix(stream *s)
                        if (nr == 2 && buf[0] == OOBMSG0 && buf[1] == OOBMSG1) {
                                nr = recv(fd, buf, 3, 0);
                                if (nr == 3)
-                                       return buf[2];
+                                       return (unsigned char) buf[2];
                        }
                }
        return 0;
diff --git a/common/stream/stream_internal.h b/common/stream/stream_internal.h
--- a/common/stream/stream_internal.h
+++ b/common/stream/stream_internal.h
@@ -62,6 +62,9 @@
 #include <lz4.h>
 #include <lz4frame.h>
 #endif
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
 
 #ifndef SHUT_RD
 #define SHUT_RD                0
@@ -259,11 +262,16 @@ stream *open_lz4wastream(const char *res
  * bs2.c should be dropped.*/
 typedef struct bs bs;
 struct bs {
+#if !defined(HAVE_PTHREAD_H) && defined(WIN32)
+       CRITICAL_SECTION lock;
+#else
+       pthread_mutex_t lock;
+#endif
        uint16_t nr;            /* how far we got in buf */
        uint16_t itotal;        /* amount available in current read block */
        bool seenflush;
        bool seenoob;
-       char oobval;
+       unsigned char oobval;
        int64_t blks;           /* read/written blocks (possibly partial) */
        int64_t bytes;          /* read/written bytes */
        char buf[BLOCK];        /* the buffered data (minus the size of
diff --git a/sql/ChangeLog.Dec2025 b/sql/ChangeLog.Dec2025
--- a/sql/ChangeLog.Dec2025
+++ b/sql/ChangeLog.Dec2025
@@ -34,12 +34,13 @@
   guaranteed.
 
 * Fri Oct  3 2025 Lucas Pereira <[email protected]>
-- EXPLAIN now supports a BEFORE/AFTER REL_UNNEST/REL_REWRITE/PHYSICAL
+- EXPLAIN now supports a BEFORE/AFTER LOGICAL UNNEST/LOGICAL REWRITE/PHYSICAL
   clause to indicate which phase of query compilation to show.  A plain
-  EXPLAIN is equivalent to EXPLAIN BEFORE PHYSICAL, which is what PLAN
-  used to do. The old EXPLAIN is now EXPLAIN PHYSICAL. SHOW DETAILS
-  includes more information about properties, rewriters number of
-  changes and time spent.
+  EXPLAIN is equivalent to EXPLAIN AFTER REWRITE, which is what PLAN
+  used to do. The old EXPLAIN is now EXPLAIN PHYSICAL. LOGICAL REWRITE also
+  supports specifying two positive values, rewriter index number and
+  optimizer loop cycle stop counter. SHOW DETAILS includes more information
+  about properties, rewriters number of changes and time spent.
 - The PLAN keyword has been removed.
 
 * Tue Sep 16 2025 Sjoerd Mullender <[email protected]>
diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -139,7 +139,7 @@ sql_symbol2relation(backend *be, symbol 
        sql_rel *rel;
        sql_query *query = query_create(be->mvc);
        int value_based_opt = be->mvc->emode != m_prepare, storage_based_opt;
-       int profile = be->mvc->emode == m_plan;
+       int profile = be->mvc->emode == m_explain;
 
        rel = rel_semantic(query, sym);
 
@@ -5818,8 +5818,6 @@ SQLread_dump_rel(Client cntxt, MalBlkPtr
        if (refs == NULL)
                goto bailout;
 
-       m->step = S_REL_REWRITE;
-       m->temporal = T_AFTER;
        m->show_details = true;
 
        rel_print_refs(m, s, rel, 0, refs, 0);
diff --git a/sql/backends/monet5/sql_execute.c 
b/sql/backends/monet5/sql_execute.c
--- a/sql/backends/monet5/sql_execute.c
+++ b/sql/backends/monet5/sql_execute.c
@@ -61,7 +61,7 @@ SQLrun(Client c, backend *be)
        TRC_INFO(SQL_EXECUTION, "Executing: %s", c->query);
        MT_thread_setworking(c->query);
 
-       if (m->emod == mod_explain) {
+       if (m->emod == mod_explain_phys) {
                if (c->curprg->def)
                        printFunction(c->fdout, mb, 0, LIST_MAL_NAME | 
LIST_MAL_VALUE  | LIST_MAL_TYPE |  LIST_MAL_MAPI);
        } else {
diff --git a/sql/backends/monet5/sql_gencode.c 
b/sql/backends/monet5/sql_gencode.c
--- a/sql/backends/monet5/sql_gencode.c
+++ b/sql/backends/monet5/sql_gencode.c
@@ -988,7 +988,7 @@ sql_relation2stmt(backend *be, sql_rel *
                sql_error(c, 003, SQLSTATE(42000) "Missing relation to convert 
into statements");
                return NULL;
        } else {
-               if (c->emode == m_plan) {
+               if (c->emode == m_explain) {
                        rel_print(c, r, 0);
                } else {
                        s = output_rel_bin(be, r, top);
diff --git a/sql/backends/monet5/sql_scenario.c 
b/sql/backends/monet5/sql_scenario.c
--- a/sql/backends/monet5/sql_scenario.c
+++ b/sql/backends/monet5/sql_scenario.c
@@ -1423,6 +1423,8 @@ SQLparser_body(Client c, backend *be)
        m->temporal = T_NONE;
        m->step = S_NONE;
        m->show_details = false;
+       m->rewriter_stop_idx = -1;
+       m->rewriter_stop_cycle = -1;
        m->trace = false;
        c->query = NULL;
        c->qryctx.starttime = GDKusec();
@@ -1552,7 +1554,9 @@ SQLparser_body(Client c, backend *be)
                                opt = ((m->emod == mod_exec) == 0); /* no need 
to optimize prepare - execute */
                        }
 
-                       if (be->mvc->emod == mod_explain && be->mvc->step == 
S_PHYSICAL && be->mvc->temporal == T_BEFORE)
+                       if (be->mvc->emod == mod_explain_phys &&
+                               be->mvc->step == S_PHYSICAL &&
+                               be->mvc->temporal == T_BEFORE)
                                opt = 0;
 
                        if (err)
diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c
--- a/sql/server/rel_optimizer.c
+++ b/sql/server/rel_optimizer.c
@@ -621,9 +621,21 @@ run_optimizer_set(visitor *v, sql_optimi
                                run->name = set[i].name;
                                int changes = v->changes;
                                lng clk = GDKusec();
+
+                               if (BEFORE_LOGICAL_REWRITE(v->sql) &&
+                                       v->sql->rewriter_stop_idx >= 0 &&
+                                       set[i].index == 
v->sql->rewriter_stop_idx)
+                                       return rel;
+
                                rel = opt(v, gp, rel);
                                run->time += (GDKusec() - clk);
                                run->nchanges += (v->changes - changes);
+
+                               if (AFTER_LOGICAL_REWRITE(v->sql) &&
+                                       v->sql->rewriter_stop_idx >= 0 &&
+                                       set[i].index == 
v->sql->rewriter_stop_idx)
+                                       return rel;
+
                        } else {
                                rel = opt(v, gp, rel);
                        }
@@ -637,38 +649,64 @@ run_optimizer_set(visitor *v, sql_optimi
 static sql_rel *
 rel_optimizer_one(mvc *sql, sql_rel *rel, int profile, int instantiate, int 
value_based_opt, int storage_based_opt)
 {
-       global_props gp = {.cnt = {0}, .instantiate = (uint8_t)instantiate, 
.opt_cycle = 0 };
-       visitor v = { .sql = sql, .value_based_opt = value_based_opt, 
.storage_based_opt = storage_based_opt, .changes = 1, .data = &gp };
+       global_props gp = {
+               .cnt = {0},
+               .instantiate = (uint8_t)instantiate,
+               .opt_cycle = 0
+       };
+
+       visitor v = {
+               .sql = sql,
+               .value_based_opt = value_based_opt,
+               .storage_based_opt = storage_based_opt,
+               .changes = 1,
+               .data = &gp
+       };
 
-       sql->runs = !(ATOMIC_GET(&GDKdebug) & TESTINGMASK) && profile ? 
ma_zalloc(sql->sa, NSQLREWRITERS * sizeof(sql_optimizer_run)) : NULL;
-       for ( ;rel && gp.opt_cycle < 20 && v.changes; gp.opt_cycle++) {
+       sql->runs = !(ATOMIC_GET(&GDKdebug) & TESTINGMASK) && profile ?
+               ma_zalloc(sql->sa, NSQLREWRITERS * sizeof(sql_optimizer_run)) :
+               NULL;
+
+       for ( ; rel && gp.opt_cycle < 20 && v.changes; gp.opt_cycle++) {
                v.changes = 0;
-               gp = (global_props) {.cnt = {0}, .instantiate = 
(uint8_t)instantiate, .opt_cycle = gp.opt_cycle};
-               rel = rel_visitor_topdown(&v, rel, &rel_properties); /* collect 
relational tree properties */
+               gp = (global_props) {
+                       .cnt = {0},
+                       .instantiate = (uint8_t)instantiate,
+                       .opt_cycle = gp.opt_cycle
+               };
+               /* collect relational tree properties */
+               rel = rel_visitor_topdown(&v, rel, &rel_properties);
                gp.opt_level = calculate_opt_level(sql, rel);
                if (gp.opt_level == 0 && !gp.needs_mergetable_rewrite)
                        break;
                sql->recursive = gp.recursive;
                rel = run_optimizer_set(&v, sql->runs, rel, &gp, 
pre_sql_optimizers);
+
+               if (sql->step == S_LOGICAL_REWRITE &&
+                       sql->rewriter_stop_cycle >= 0 &&
+                       gp.opt_cycle == sql->rewriter_stop_cycle)
+                       return rel;
        }
+
 #ifndef NDEBUG
        assert(gp.opt_cycle < 20);
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to