Update of /cvsroot/monetdb/pathfinder/compiler/algebra
In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv4996/compiler/algebra

Added Files:
      Tag: M5XQ
        intro_borders.c 
Log Message:
propagated changes of Wednesday May 20 2009
from the development trunk to the M5XQ branch

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2009/05/20 - tsheyar: compiler/algebra/intro_borders.c,1.1
-- Renamed algebra/intro_rec_border.c into algebra/intro_borders.c.
-- Renamed include/intro_rec_border.h into include/intro_borders.h.

-- Extended the physical algebra with a dependent cross product operator
   that only evaluates its right side if the left side produces at least
   one row.

   This change implicitely implements a control structure for some conditionals.
   E.g., the following query conditionally evaluates the independent
   expressions ('doc("xmark-sf0.001.xml")//*' and 'doc("xmark-sf100.xml")//*'):

   if (1 = (1,2,3))
   then doc("xmark-sf0.1.xml")//*
   else doc("xmark-sf100.xml")//*

   With the dependent cross product operator in place this leads to the 
evaluation
   of the (previously independent) then-branch and the avoidance of the 
evaluation
   of the (expensive) else-branch.

-- Adjusted stable output.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


--- NEW FILE: intro_borders.c ---
/**
 * @file
 *
 * Introduce the borders of recursion and branch bodies..
 * (This enables the MIL generation to detect expressions
 *  that are invariant to the recursion or branch body.)
 *
 * Copyright Notice:
 * -----------------
 *
 * The contents of this file are subject to the Pathfinder Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 * http://monetdb.cwi.nl/Legal/PathfinderLicense-1.1.html
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is the Pathfinder system.
 *
 * The Original Code has initially been developed by the Database &
 * Information Systems Group at the University of Konstanz, Germany and
 * the Database Group at the Technische Universitaet Muenchen, Germany.
 * It is now maintained by the Database Systems Group at the Eberhard
 * Karls Universitaet Tuebingen, Germany.  Portions created by the
 * University of Konstanz, the Technische Universitaet Muenchen, and the
 * Universitaet Tuebingen are Copyright (C) 2000-2005 University of
 * Konstanz, (C) 2005-2008 Technische Universitaet Muenchen, and (C)
 * 2008-2009 Eberhard Karls Universitaet Tuebingen, respectively.  All
 * Rights Reserved.
 *
 * $Id: intro_borders.c,v 1.1.2.2 2009/05/20 16:28:09 sjoerd Exp $
 */

/* always include pf_config.h first! */
#include "pf_config.h"
#include "pathfinder.h"

#include "intro_borders.h"
#include "alg_dag.h"

#include <assert.h>

/* Easily access subtree-parts */
#include "child_mnemonic.h"

#define SEEN(n) n->bit_dag
#define pfIN(n) n->bit_in

/**
 * Worker that introduces border operators and 'in' flags.
 * Nodes are marked 'inside' as soon as one child reports
 * that one of its descendants is a base operator belonging
 * to the current recursion.
 */
static bool
introduce_rec_borders_worker (PFpa_op_t *n, PFarray_t *bases)
{
    unsigned int i;
    bool base_path = false;

    /* short-cut in case n is already determined as 'inside' */
    if (pfIN(n))
        return true;

    switch (n->kind)
    {
        /* ignore nested recursions and only collect the path */
        case pa_rec_fix:
            base_path = introduce_rec_borders_worker (L(n), bases);
            break;
        case pa_side_effects:
            base_path = introduce_rec_borders_worker (R(n), bases);
            break;
        case pa_rec_param:
            base_path = introduce_rec_borders_worker (L(n), bases);
            base_path = introduce_rec_borders_worker (R(n), bases)
                        || base_path;
            break;
        case pa_nil:
            break;
        case pa_rec_arg:
            base_path = introduce_rec_borders_worker (L(n), bases);
            break;

        /* if the base operator belongs to the currently searched
           recursion mark the node as inside the recursion */
        case pa_rec_base:
            for (i = 0; i < PFarray_last (bases); i++)
                if (n == *(PFpa_op_t **) PFarray_at (bases, i)) {
                    base_path = true;
                    break;
                }
            break;

        case pa_fun_call:
             base_path = introduce_rec_borders_worker (L(n), bases) ||
                         introduce_rec_borders_worker (R(n), bases);

             /* the complete function call resides in the recursion */
             if (base_path) {
                 /* If one argument of the function call resides in the
                    recursion the loop relation certainly does as well. */

                 /* Introduce a recursion border for all arguments
                    that reside outside the recursion. */
                 PFpa_op_t *param = R(n);
                 while (param->kind != pa_nil) {
                     if (param->kind == pa_fun_param && !pfIN(L(param))) {
                         L(param) = PFpa_rec_border (L(param));
                         L(param)->prop = L(L(param))->prop;
                     }
                     param = R(param);
                 }
             }
             break;

        case pa_fun_param:
             /* only collect the base paths */
             base_path = introduce_rec_borders_worker (L(n), bases) ||
                         introduce_rec_borders_worker (R(n), bases);
             break;

        case pa_fcns:
            /* this also skips the introduction of a rec_border
               operator for the content of an empty elements:
               elem (fcns (nil, nil)). */
            if (R(n)->kind == pa_nil)
                break;
            /* else fall through */
        default:
            /* follow the children until a base or a leaf is reached */
            for (unsigned int i = 0; i < PFPA_OP_MAXCHILD && n->child[i]; i++)
                base_path = introduce_rec_borders_worker (n->child[i], bases)
                            || base_path;

            /* Introduce border if the current node is 'inside'
               the recursion while its left child is not.
               Make sure that no borders are introduced along the
               fragment information edge. */
            if (base_path && L(n) && !pfIN(L(n))) {
                L(n) = PFpa_rec_border (L(n));
                L(n)->prop = L(L(n))->prop;
            }
            /* Introduce border if the current node is 'inside'
               the recursion while its right child is not. */
            if (base_path && R(n) && !pfIN(R(n)) &&
                R(n)->kind != pa_fcns) {
                R(n) = PFpa_rec_border (R(n));
                R(n)->prop = L(R(n))->prop;
            }
            break;
    }
    if (base_path)
        pfIN(n) = true;

    return base_path;
}

/**
 * reset the 'in' bits.
 * (We know that these 'in' bits are set for the seed
 *  and all lie on a path starting from the seed.)
 */
static void
in_reset (PFpa_op_t *n)
{
    unsigned int i;

    if (!pfIN(n))
        return;
    else
        pfIN(n) = false;

    for (i = 0; i < PFPA_OP_MAXCHILD && n->child[i]; i++)
        in_reset (n->child[i]);
}

/**
 * Introduce boundary operators for every recursion
 * such that the MIL generation detects expressions
 * that are invariant to the recursion body.
 *
 * Walk down the DAG and for each recursion operator
 * introduce border operators.
 *
 * We mark all operators that lie on the path from the
 * result (or the recursion arguments) to the base
 * operators of the recursion as inside the recursion body.
 *
 * A border is introduced between nodes (a) and (b) where
 * (a) is the parent of (b), (a) lies in the set of nodes marked
 * as inside, and (b) lies in the set of nodes marked as outside
 * of the recursion body.
 */
static void
introduce_rec_borders (PFpa_op_t *n)
{
    if (SEEN(n))
        return;
    else
        SEEN(n) = true;

    switch (n->kind)
    {
        case pa_rec_fix:
        {
            PFarray_t *bases = PFarray (sizeof (PFpa_op_t *), 3);
            PFpa_op_t *cur;

            /* collect base operators */
            assert (L(n)->kind == pa_side_effects);
            cur = LR(n);
            while (cur->kind != pa_nil) {
                assert (cur->kind == pa_rec_param &&
                        L(cur)->kind == pa_rec_arg);
                *(PFpa_op_t **) PFarray_add (bases) = L(cur)->sem.rec_arg.base;
                cur = R(cur);
            }

            /* call the path traversal worker, that introduces
               the border operator and marks all 'inside' nodes,
               for all recursion arguments as well as the result */
            cur = LL(n);
            while (cur->kind != pa_nil) {
                introduce_rec_borders_worker (R(cur), bases);
                cur = L(cur);
            }
            cur = LR(n);
            while (cur->kind != pa_nil) {
                introduce_rec_borders_worker (LR(cur), bases);
                cur = R(cur);
            }
            introduce_rec_borders_worker (R(n), bases);

            /* Remove the 'in' flag for all nodes */
            cur = LL(n);
            while (cur->kind != pa_nil) {
                in_reset (R(cur));
                cur = L(cur);
            }
            cur = LR(n);
            while (cur->kind != pa_nil) {
                in_reset (LR(cur));
                cur = R(cur);
            }
            in_reset (R(n));
        } break;

        default:
            for (unsigned int i = 0; i < PFPA_OP_MAXCHILD && n->child[i]; i++)
                introduce_rec_borders (n->child[i]);
            break;
    }
}

/**
 * Traverse the complete plan and annotate all operators
 * except for the operators we want to evaluate in dependence.
 */
static void
mark_plan (PFpa_op_t *n, PFpa_op_t *dep_op)
{
    if (pfIN(n))
        return;
    else
        pfIN(n) = true;

    if (n == dep_op) {
        assert (n->kind == pa_dep_cross);

        mark_plan (L(n), dep_op);

        /* don't mark the right side */
    }
    else
        for (unsigned int i = 0; i < PFPA_OP_MAXCHILD && n->child[i]; i++)
            mark_plan (n->child[i], dep_op);
}

/**
 * Worker for introduce_dep_borders.
 */ 
static void
introduce_dep_borders_worker (PFpa_op_t *n)
{
    /* We mark only the independent operators as SEEN as we stop
       as soon as we reach a boundary to an dependent operator. */
    if (SEEN(n))
        return;
    else
        SEEN(n) = true;

    for (unsigned int i = 0; i < PFPA_OP_MAXCHILD && n->child[i]; i++)
        if (!pfIN(n) && pfIN(n->child[i]) &&
            n->child[i]->kind != pa_nil)
            /* Introduce a border if a boundary is reached
               and stop the traversal. */
            n->child[i] = PFpa_dep_border (n->child[i]);
        else
            /* Recursively traverse the plan otherwise. */
            introduce_dep_borders_worker (n->child[i]);

    /* Rewrite dependent cross products that are nested in
       the right side of another dependent cross into normal
       cross products again. */
    if (n->kind == pa_dep_cross)
        /* we can replace the kind as the two cross
           product operators behave exactly the same */
        n->kind = pa_cross;
}

/**
 * Traverse the query plan and find operators that
 * introduce dependencies.
 */
static void
introduce_dep_borders (PFpa_op_t *n, PFpa_op_t *root)
{
    if (SEEN(n))
        return;
    else
        SEEN(n) = true;

    /* Detect borders for this operator. */
    if (n->kind == pa_dep_cross) {
        /* Traverse the query plan for the left argument */
        introduce_dep_borders (L(n), root);

        /* Mark all operators that are reachable from the
           root (except for the right side of n) to detect
           which operators are referenced from both in-/outside. */
        mark_plan (root, n);

        /* Dependent cross products that have no operators
           that can be evaluated in dependence are rewritten
           into normal cross products again. */
        if (pfIN(R(n)))
            /* we can replace the kind as the two cross
               product operators behave exactly the same */
            n->kind = pa_cross;
        else
            /* Introduce the borders for this operator. */
            introduce_dep_borders_worker (R(n));
        in_reset (root);
    }
    else
        for (unsigned int i = 0; i < PFPA_OP_MAXCHILD && n->child[i]; i++)
            introduce_dep_borders (n->child[i], root);
}

/**
 * Introduce boundary operators.
 */
PFpa_op_t *
PFpa_intro_borders (PFpa_op_t *n)
{
    /* Introduce border operators
       for recursions. */
    introduce_rec_borders (n);
    PFpa_dag_reset (n);

    /* Introduce border operators
       for dependency generating operators */
    introduce_dep_borders (n, n);
    PFpa_dag_reset (n);

    return n;
}


------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables 
unlimited royalty-free distribution of the report engine 
for externally facing server and web deployment. 
http://p.sf.net/sfu/businessobjects
_______________________________________________
Monetdb-pf-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/monetdb-pf-checkins

Reply via email to