Update of /cvsroot/monetdb/pathfinder/compiler/sql
In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv22998/compiler/sql

Modified Files:
        lalg2sql.brg 
Log Message:


Simple recursion support for the SQL generator for

   with $x seeded by expr recurse expr

SQL allows to express simple recursive statements using the
WITH RECURSIVE clause. In the core to algebra translation we
now have two recursion-strategies (for MIL and SQL) with different
behaviours.
The SQL variant, for example, cannot cope with non-DELTA evaluation
due to its inherent restrictions.




Index: lalg2sql.brg
===================================================================
RCS file: /cvsroot/monetdb/pathfinder/compiler/sql/lalg2sql.brg,v
retrieving revision 1.125
retrieving revision 1.126
diff -u -d -r1.125 -r1.126
--- lalg2sql.brg        17 Mar 2008 17:41:29 -0000      1.125
+++ lalg2sql.brg        19 Mar 2008 10:58:52 -0000      1.126
@@ -289,17 +289,27 @@
 Map:    trace_map (Rel, Map)                         = 102 (10);
 Map:    nil                                          = 103 (10);
 
-Rel:    rec_fix (Rec, Rel)                           = 105 (10);
-Rel:    rec_base                                     = 106 (10);
-Rec:    rec_param (Arg, Rec)                         = 107 (10);
-Rec:    nil                                          = 108 (10);
-Arg:    rec_arg (Rel, Rel)                           = 109 (10);
+Rel:    rec_base                                     = 105 (10);
+Rec:    nil                                          = 106 (10);
+Arg:    rec_arg (Rel, Rel)                           = 107 (10);
+Arg:    rec_arg (Rel, distinct (Rel))                = 108 (10); 
 
-Rel:    dummy (Rel)                                  = 110 (10);
-Rel:    proxy (Rel)                                  = 111 (10);
-Rel:    proxy_base (Rel)                             = 112 (10);
-Rel:    eqjoin_unq (Rel, Rel)                        = 113 (10);
-Rel:    cross_mvd (Rel, Rel)                         = 114 (10);
+Rel:    rec_fix (
+           rec_param (
+              rec_arg (Rel, Rel), 
+              rec_param(
+                  Arg,
+                  nil)), Rel)                        = 109 (10);
+Rel:    rec_fix (
+           rec_param (
+              Arg, 
+              nil), Rel)                             = 110 (10);
+
+Rel:    dummy (Rel)                                  = 115 (10);
+Rel:    proxy (Rel)                                  = 116 (10);
+Rel:    proxy_base (Rel)                             = 117 (10);
+Rel:    eqjoin_unq (Rel, Rel)                        = 118 (10);
+Rel:    cross_mvd (Rel, Rel)                         = 119 (10);
 
 %%
 
@@ -317,6 +327,11 @@
 static PFsql_t *sql_stmts = NULL;
 
 /**
+ * true if we are in a recursion branch
+ */
+static bool rec_branch = false;
+
+/**
  * Generate DB2 SELECTIVITY hints;
  */
 bool selectivity;
@@ -1619,6 +1634,143 @@
     return NULL; /* satisfy picky compilers */
 }
 
+#define FRAG_OP(p) (/* fragment related operators */ \
+                    (p)->kind == la_frag_union    || \
+                    (p)->kind == la_empty_frag    || \
+                    (p)->kind == la_fragment      || \
+                    /* and operators that are     */ \
+                    /* referenced by 'roots' and  */ \
+                    /* 'fragment' only            */ \
+                    (p)->kind == la_doc_tbl       || \
+                    (p)->kind == la_twig          || \
+                    (p)->kind == la_merge_adjacent)
+
+/**
+ * This functions tells us during the generation of
+ * the recursion branch if recursion is allowed
+ */
+static bool
+rec_allowed (PFla_op_t *p)
+{
+    /* check if we have to bind this operator */
+    if (bind_multi_ref && REFCTR(p) > 1 && !FRAG_OP(p))
+        return false;
+
+    switch (p->kind) {
+        case la_serialize_seq:
+        case la_serialize_rel:
+            PFoops (OOPS_FATAL, "serializing during recursion is not 
possible");
+        case la_lit_tbl:
+            return (p->sem.lit_tbl.count > 1);
+        case la_empty_tbl:
+        case la_ref_tbl:
+        case la_attach:
+            return true;
+        case la_cross:
+        case la_eqjoin:
+            return true;
+        case la_semijoin:
+            /* FIXME */
+            assert (!"FIXME");
+        case la_thetajoin:
+        case la_project:
+        case la_select:
+            return true;
+        case la_pos_select:
+            return false;
+        case la_disjunion:
+        case la_intersect:
+        case la_difference:
+        case la_distinct:
+            return false;
+        case la_fun_1to1:
+        case la_num_eq:
+        case la_num_gt:
+        case la_bool_and:
+        case la_bool_or:
+        case la_bool_not:
+            return true;
+        case la_to:
+            return false;
+        case la_avg:
+        case la_max:
+        case la_min:
+        case la_sum:
+        case la_count:
+        case la_all:
+            return (!p->sem.aggr.part);
+        case la_rownum:
+        case la_rowrank:
+        case la_rank:
+        case la_rowid:
+            return false;
+        case la_type:
+        case la_type_assert:
+        case la_seqty1:
+            /* FIXME */
+            assert (!"not yet implemented");
+            break;
+        case la_cast:
+            return true;
+        case la_step:
+        case la_step_join:
+        case la_guide_step:
+        case la_guide_step_join:
+            return true; /* PFprop_set (p->prop); */
+        case la_doc_index_join:
+            /* FIXME */
+            assert (!"not yet implemented");
+            break;
+        case la_doc_tbl:
+        case la_doc_access:
+            return true;
+        case la_twig:
+        case la_fcns:
+        case la_docnode:
+        case la_element:
+        case la_attribute:
+        case la_textnode:
+        case la_comment:
+        case la_processi:
+        case la_content:
+        case la_merge_adjacent:
+            return false;
+        case la_roots:
+        case la_fragment:
+        case la_frag_union:
+        case la_empty_frag:
+        case la_error:
+        case la_cond_err:
+            return true;
+        case la_nil:
+            /* FIXME */
+            assert (!"not yet implemented");
+            break;
+        case la_trace:
+        case la_trace_msg:
+        case la_trace_map:
+            /* FIXME */
+            assert (!"not yet implemented");
+            break;
+        case la_string_join:
+        case la_dummy:
+        case la_rec_fix:
+        case la_rec_param:
+        case la_rec_arg:
+            return false;
+        case la_rec_base:
+            return true;
+        case la_proxy:
+        case la_proxy_base:
+        case la_cross_mvd:
+        case la_eqjoin_unq:
+            return false;
+        default:
+            PFoops (OOPS_FATAL, "This operation is unknown");
+    }
+    return false;
+}
+
 /**
  * A cast to boolean is has to provide a boolean expression.
  */
@@ -1707,6 +1859,9 @@
     /* guard against too deep recursion */
     PFrecursion_fence ();
 
+    if (rec_branch && !rec_allowed (p))
+        PFoops (OOPS_FATAL, "SQL cannot cope with this recursion");
+
     if (SEEN(p)) {
         substitute_aliases (p);
         return;
@@ -1740,6 +1895,22 @@
         case 43:
         /* Rel:    cond_err (Rel, Rel) */
         case 99:
+        /* Arg:    rec_arg (Rel, Rel) */
+        case 107:
+        /* Arg;    rec_arg (Rel, distinct (Rel)) */
+        case 108:
+        /* Rel:    rec_fix (
+                       rec_param (
+                          rec_arg (Rel, Rel), 
+                          rec_param(
+                              Arg,
+                              nil)), Rel) */
+        case 109:
+        /* Rel:    rec_fix (
+                       rec_param (
+                          Arg, 
+                          nil), Rel) */
+        case 110:
             /* top-down translation */
             break;
         default:
@@ -3969,7 +4140,7 @@
                 COLMAP(p) = colmap;
 
                 /* dump the relation if a distinct is required */
-                if (!PFprop_set (p->prop)) {
+                if (!PFprop_set (p->prop) && !rec_branch) {
                     distinct = true;
                     bind = true;
                     execute (comment ("binding due to %sstep operator",
@@ -4657,33 +4828,200 @@
         case 102:
         /* Map:    nil */
         case 103:
-        /* Rel:    rec_fix (Rec, Rel) */
-        case 105:
+            /* FIXME: implementation is missing */
+            PFoops (OOPS_FATAL,
+                    "SQLgen: Translation for the logical "
+                    "algebra pattern (%s) is still missing.",
+                    PFlalg2sql_string[rule]);
+            break;
         /* Rel:    rec_base */
-        case 106:
-        /* Rec:    rec_param (Arg, Rec) */
-        case 107:
+        case 105:
+            /* do nothing, the magic happens in rec_arg */
+            break;
         /* Rec:    nil */
-        case 108:
-        /* Arg:    rec_arg (Rel, Rel) */
-        case 109:
+        case 106:
             /* FIXME: implementation is missing */
             PFoops (OOPS_FATAL,
                     "SQLgen: Translation for the logical "
                     "algebra pattern (%s) is still missing.",
                     PFlalg2sql_string[rule]);
             break;
+        /* Arg:    rec_arg (Rel, Rel) */
+        case 107: 
+        /* Arg:    rec_arg (Rel, distinct (Rel)) */
+        case 108: {
+            /** TOPDOWN **/
+            PFla_op_t *base = p->sem.rec_arg.base;
+            PFla_op_t *seed = L(p);
+            PFla_op_t *recursion = (rule == 107)
+                                   ? R(p)
+                                   : RL(p);
+            /* if we are in rule 107, the operator under
+             * distinct must have the set property */
+            assert (!(rule == 108) || (PFprop_set (RL(p)->prop)));
+
+            PFsql_t *columnlist = NULL;
+            PFsql_t *rec_selectlist = NULL;
+
+            PFsql_col_t *colname = NULL;
+            
+            /* generate SQL code for the seed branch */
+            reduce (kids[0], nts[0]);
+
+            /* for the recursion we have to create a new binding */
+            PFsql_tident_t basetable = new_table_name ();
+            /* new correlation name for bounded table */
+            PFsql_aident_t basealias = new_alias ();
+
+            /* clear colmap */
+            PFarray_last (COLMAP(base)) = 0;
+
+            for (unsigned int i = 0; i < base->schema.count; i++) {
+                for (PFalg_simple_type_t t = 1; t; t <<= 1)
+                    if (t & TYPE_MASK (p->schema.items[i].type)) {
+                        colname = new_col (base->schema.items[i].name,
+                                           t);
+
+                        /* prepare the column list */ 
+                        columnlist = column_list (
+                                         columnlist,
+                                         column_name (colname));
+                        
+                        col_env_add (COLMAP(base),
+                                     base->schema.items[i].name,
+                                     t,
+                                     ext_column_name (basealias, colname));    
+                        col_env_add (COLMAP(p),
+                                     base->schema.items[i].name,
+                                     t,
+                                     ext_column_name (basealias, colname));    
+
+                    }
+            }
+
+            /* clear from and where list */
+            PFarray_last (FROMLIST(base)) = 0;
+            PFarray_last (WHERELIST(base)) = 0; 
+            PFarray_last (FROMLIST(p)) = 0;
+            PFarray_last (WHERELIST(p)) = 0;
+            
+            /* add the new binding to the fromlist */
+            from_list_add (FROMLIST (base), 
+                           table_name (basetable),
+                           alias (basealias));
+
+            /* add the new binding to the fromlist */
+            from_list_add (FROMLIST (p), 
+                           table_name (basetable),
+                           alias (basealias));
+
+
+            /* generate SQL code for the recursion branch */ 
+            rec_branch = true;
+            reduce (kids[1], nts[1]);
+            rec_branch = false;
+            
+            for (unsigned int i = 0; i < base->schema.count; i++) {
+                for (PFalg_simple_type_t t = 1; t; t <<= 1)
+                    if (t & TYPE_MASK (p->schema.items[i].type)) {
+                        rec_selectlist = select_list (
+                                             rec_selectlist,
+                                             col_env_lookup (COLMAP(recursion),
+                                                             
p->schema.items[i].name,
+                                                             t)); 
+                    }
+            }
+
+            execute (comment ("============="));
+            execute (comment ("= RECURSION ="));
+            execute (comment ("============="));
+            execute (bind (table_def (
+                            basetable, 
+                            columnlist),
+                     union_ (
+                     PFsql_select (
+                        false,
+                        transform_selectlist (COLMAP(seed)),
+                        transform_frommap (seed),
+                        transform_wheremap (seed),
+                        NULL,
+                        NULL),
+                     PFsql_select (
+                        false,
+                        rec_selectlist,
+                        transform_frommap (recursion),
+                        transform_wheremap (recursion),
+                        NULL,
+                        NULL))));
+
+            copy_cols_from_where (recursion, p);
+        }   break;
+
+        /* Rel:    rec_fix (
+                       rec_param (
+                          rec_arg (Rel, Rel), 
+                          rec_param(
+                              Arg,
+                              nil)), Rel) */
+        case 109: {
+            /*** TOPDOWN ***/
+            PFla_op_t *loop_param = LL(p),
+                      *base  = LL(p)->sem.rec_arg.base;
+
+            PFla_op_t *overall_result = R(p);
+            PFla_op_t *recarg = LRL(p);
 
+            /* if we are sure, that the loop returns
+             * results in any case, and the base is
+             * used only once, we can continue the 
+             * translation, since we are sure the
+             * loop is not needed anywhere */
+            if (!(PFprop_card(loop_param->prop)) ||
+                !(REFCTR(base) == 1))
+                PFoops (OOPS_FATAL, "SQL cannot cope with this "
+                                    "query");
+
+            reduce (kids[2], nts[2]);
+
+            /* manually decrement the reference counter,
+             * of the overall_result since we don't need
+             * this edge */
+            REFCTR(overall_result)--;
+
+            copy_cols_from_where (p, recarg);
+            bind = true; distinct = true;
+            execute (comment ("Binding due to recursion"));
+        } break;
+        /* Rel:    rec_fix (
+                       rec_param (
+                          Arg, 
+                          nil), Rel) */
+        case 110: {
+            /*** TOPDOWN ***/
+            PFla_op_t *overall_result = R(p);
+            PFla_op_t *recarg = LL(p);
+
+            reduce (kids[0], nts[0]);
+
+            /* manually decrement the reference counter,
+             * of the overall_result since we don't need
+             * this edge */
+            REFCTR(overall_result)--;
+
+            copy_cols_from_where (p, recarg);
+            bind = true; distinct = true;
+            execute (comment ("Binding due to recursion"));
+        }   break;
         /* Rel:    dummy (Rel) */
-        case 110:
+        case 115:
         /* Rel:    proxy (Rel) */
-        case 111:
+        case 116:
         /* Rel:    proxy_base (Rel) */
-        case 112:
+        case 117:
         /* Rel:    eqjoin_unq (Rel, Rel) */
-        case 113:
+        case 118:
         /* Rel:    cross_mvd (Rel, Rel) */
-        case 114:
+        case 119:
 
         default:
             PFoops (OOPS_FATAL,
@@ -4758,17 +5096,6 @@
            break;
     }
 
-#define FRAG_OP(p) (/* fragment related operators */ \
-                    (p)->kind == la_frag_union    || \
-                    (p)->kind == la_empty_frag    || \
-                    (p)->kind == la_fragment      || \
-                    /* and operators that are     */ \
-                    /* referenced by 'roots' and  */ \
-                    /* 'fragment' only            */ \
-                    (p)->kind == la_doc_tbl       || \
-                    (p)->kind == la_twig          || \
-                    (p)->kind == la_merge_adjacent)
-
     /* BINDING: execute the statement at the end
        if the node is dirty, and bind it to a new SQL variable.
        The strategy behind this late binding is to merge


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Monetdb-pf-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/monetdb-pf-checkins

Reply via email to