Example #1
0
/* FwdExpr
 *  handle a forwarded symbol in expression
 *  if the symbol is "virtual", check for its override
 *  map actual symbol type to expression handler
 */
static
rc_t VProdResolveFwdExpr ( const VProdResolve *self, VProduction **out,
    VFormatdecl *fd, const SSymExpr *x, bool casting )
{
    /* virtual names that appear in parent table
       expressions may be overridden in children */
    const KSymbol *sym = x -> _sym;
    if ( sym -> type == eVirtual )
    {
        /* most derived table class */
        const STable *stbl = self -> stbl;
        const KSymbol *sym2 = sym;
        
        sym = STableFindOverride ( stbl, ( const VCtxId* ) & sym -> u . fwd );
        if ( sym == NULL )
        {
            PLOGMSG ( klogWarn, ( klogWarn, "virtual reference '$(fwd)' not found in overrides table"
                       , "fwd=%.*s"
                       , ( int ) sym2 -> name . size
                       , sym2 -> name . addr ));
            return 0;
        }
    }

    /* test symbol type */
    switch ( sym -> type )
    {
    case eProduction:
        return VProdResolveProdExpr ( self, out, sym );
    case ePhysMember:
        return VProdResolvePhysExpr ( self, out, sym );
    case eColumn:
        return VProdResolveColExpr ( self, out, fd, x, casting );
    }

    VDB_DEBUG (("%s: unresolved forward reference '%S'",
                 __func__, &sym->name));

    return 0;
}
Example #2
0
/* ResolveColumn
 *  resolves a column using read/write expression
 */
rc_t VProdResolveColumnRoot ( const VProdResolve *self,
    VProduction **out, const SColumn *scol )
{
    rc_t rc;
    WColumn *wcol;
    VTypedesc desc;
    const char *name;
    VCursor *curs = self -> curs;
    VProduction * in;

    * out = NULL;

    /* decide upon behavior */
    if ( curs -> read_only )
    {
        rc = VProdResolveColumnRead ( self, out, scol );
        if ( rc == 0 && * out <= FAILED_PRODUCTION )
            return RC ( rcVDB, rcCursor, rcOpening, rcColumn, rcUndefined );
        return rc;
    }

    /* write-only cursor must have existing column */
    wcol = VCursorCacheGet ( & curs -> col, & scol -> cid );
    if ( wcol == NULL )
        return 0;

    /* not intended to be reentrant */
    assert ( wcol -> val == NULL );

    /* evaluate input expression */
    if ( scol -> validate == NULL )
    {
        /* use normal read expression */
        rc = VProdResolveColumnRead ( self, &in, scol );
    }
    else
    {
        VFormatdecl fd;
        
        /* create fmtdecl from typedecl */
        memset ( & fd, 0, sizeof fd );

        VDB_DEBUG ( ( "resolving column '%N' validate expression.\n", scol -> name ) );

        /* use validation expression */
        rc = VProdResolveExpr ( self, &in, & desc, & fd, scol -> validate, false );
    }

    /* check failures */
    if ( rc != 0 )
    {
        VDB_DEBUG ( ( "failed to resolve column '%N' - %R.\n", scol -> name, rc ) );
        return rc;
    }
    if ( in <= FAILED_PRODUCTION )
    {
        VDB_DEBUG ( ( "failed to resolve column '%N' - NULL or failed production.\n", scol -> name ) );
        return RC ( rcVDB, rcCursor, rcOpening, rcColumn, rcUndefined );
    }

    /* column name */
    name = scol -> name -> name . addr;

    /* pick up production */
    if ( scol -> validate != NULL )
    {
        rc = VSimpleProdMake ( & wcol -> val, self -> owned,
            prodSimpleCast, name, NULL, NULL, NULL, in, chainDecoding );
        if ( rc != 0 )
            return rc;
    }

    /* create implicit comparison function */
    else
    {
        /* need an output production */
        if ( wcol -> out == NULL )
        {
            rc = VColumnProdMake ( & wcol -> out, self -> owned,
                & wcol -> dad, prodColumnOut, name );
            if ( rc != 0 )
                return rc;
        }

        /* create comparison func */
        rc = VFunctionProdMakeBuiltInComp ( & wcol -> val, self -> owned,
            name, self, wcol -> out, in );
        if ( rc != 0 )
            return rc;
    }

    /* install trigger */
    rc = VectorAppend ( & curs -> trig, NULL, wcol -> val );
    if ( rc == 0 )
        * out = wcol -> val;

    return rc;
}
Example #3
0
/* ResolveColumn
 *  resolves a column from read/validate expression
 */
rc_t VProdResolveColumnRead ( const VProdResolve *self,
    VProduction **out, const SColumn *scol )
{
    rc_t rc;
    VFormatdecl fd;
    const char *name;
    VCursor *curs;
    VColumn *vcol;

    VDB_DEBUG ( ( "resolving column '%N' read expression.\n", scol -> name ) );

    /* potential error if self is NULL */
    curs = self -> curs;
    if ( out == NULL )
    {
        rc =  RC(rcVDB, rcProduction, rcResolving, rcParam, rcNull);
        VDB_DEBUG ( ( "result NULL for column '%N'; no output can be produced by '%s' rc %R\n",
                      scol -> name, __func__, rc ) );
        return rc;
    }
    
    /* fetch the column */
    vcol = VCursorCacheGet ( & curs -> col, & scol -> cid );
    if ( vcol == NULL )
    {
        VDB_DEBUG ( ( "failed to fetch NULL for column '%N'; no output was produced by '%s'\n",
                      scol -> name, __func__ ) );
        return 0;
    }

    /* if the read production is in place, return it */
    if ( vcol -> in != NULL )
    {
        if ( vcol -> in != FAILED_PRODUCTION )
            * out = vcol -> in;
        return 0;
    }

    /* pre-fail */
    vcol -> in = FAILED_PRODUCTION;

    /* production resolution works with fmtdecl */
    fd . td = scol -> td;
    fd . fmt = 0;

    /* resolve the expression */
    rc = VProdResolveExpr ( self, out, & vcol -> desc, & fd, scol -> read, false );
    assert (rc != -1);

    if ( rc != 0 || *out == NULL )
        return rc;

    /* repair incomplete column declarations */
    if ( scol -> td . type_id == 0 )
    {
        if ( fd . td . type_id == 0 )
        {
            rc = RC ( rcVDB, rcColumn, rcResolving, rcType, rcUndefined );
            VDB_DEBUG (("failed to repair incomplete declaration for column '%N' rc %R\n",
                        scol -> name, rc));
            return rc;
        }
        ( ( SColumn* ) scol ) -> td = fd . td;
    }

    /* create a simple prod to manage fd and desc */
    name = scol -> name -> name . addr;
    assert ( name [ scol -> name -> name . size ] == 0 );
    rc = VSimpleProdMake ( out, self -> owned, self->curs, prodSimpleCast,
        name, & fd, & vcol -> desc, NULL, * out, self -> chain );

    assert (rc != -1);
    if ( rc != 0 )
    {
        VDB_DEBUG (("failed to create a simple prod to manage fd and desc for column '%N', rc %R\n",
                    scol -> name, rc));
        return rc;
    }

    /* return column input - this is input to the column
       that is intended to be read from the cursor */
    vcol -> in = * out;
    return rc;
}
Example #4
0
rc_t VProdResolveExpr ( const VProdResolve *self,
    VProduction **out, VTypedesc *desc, VFormatdecl *fd,
    const SExpression *expr, bool casting )
{
    rc_t rc;
    VProduction *prod;

    if ( expr == NULL )
    {
        /* report NULL expression, but don't die */
        PLOGMSG ( klogWarn, ( klogWarn, "NULL expression in '$(tbl)' table schema"
                   , "tbl=%.*s"
                   , ( int ) self -> stbl -> name -> name . size
                   , self -> stbl -> name -> name . addr ));
        return 0;
    }

    prod = NULL;
    *out = NULL;

#if _DEBUGGING
    ++ indent_level;
    VDB_DEBUG (( "%*cresolving expression '%s'\n", indent_level, ' ',
                 VProdResolvePrintExpr ( self, expr ) ));
#endif

    switch ( expr -> var )
    {
    case eParamExpr:
        /* a script function is making reference to a parameter */
        rc = VProdResolveParamExpr ( self, & prod, ( ( const SSymExpr* ) expr ) -> _sym );
    assert (rc != -1);
        break;

    case eProdExpr:
        /* return a simple production */
        rc = VProdResolveProdExpr ( self, & prod, ( ( const SSymExpr* ) expr ) -> _sym );
    assert (rc != -1);
        break;

    case eFwdExpr:
        /* handle an implicit or overridden reference */
        rc = VProdResolveFwdExpr ( self, & prod, fd, ( const SSymExpr* ) expr, casting );
    assert (rc != -1);
        break;

    case eColExpr:
        /* return a column production */
        rc = VProdResolveColExpr ( self, & prod, fd, ( const SSymExpr* ) expr, casting );
    assert (rc != -1);
        break;

    case ePhysExpr:
        /* return a physical production */
        rc = VProdResolvePhysExpr ( self, & prod, ( ( const SSymExpr* ) expr ) -> _sym );
    assert (rc != -1);
        break;

    case eScriptExpr:
        /* create a script function */
        rc = VProdResolveScriptExpr ( self, & prod, fd, ( const SFuncExpr* ) expr );
    assert (rc != -1);
        break;

    case eFuncExpr:
        /* create an external function */
        rc = VProdResolveFuncExpr ( self, & prod, fd, ( const SFuncExpr* ) expr );
    assert (rc != -1);
        break;

    case eCastExpr:
        /* perform an explicit cast */
        rc = VProdResolveCastExpr ( self, & prod, ( const SBinExpr* ) expr );
    assert (rc != -1);
        break;
        
    case eCondExpr:
        /* run left and right expressions in order until exit condition */
        rc = VProdResolveExpr ( self, out, desc, fd, ( ( const SBinExpr* ) expr ) -> left, casting );
    assert (rc != -1);
        if ( ( rc == 0 && * out == NULL ) || self -> discover_writable_columns )
        {
            rc = VProdResolveExpr ( self, out, desc, fd, ( ( const SBinExpr* ) expr ) -> right, casting );
    assert (rc != -1);
        }
#if _DEBUGGING
        -- indent_level;
#endif
        return rc;

    default:
        /* report bad expression, but don't die */
        PLOGMSG ( klogWarn, ( klogWarn, "unrecognized expression in '$(tbl)' table schema"
                   , "tbl=%.*s"
                   , ( int ) self -> stbl -> name -> name . size
                   , self -> stbl -> name -> name . addr ));
#if _DEBUGGING
        -- indent_level;
#endif
        return 0;
    }

    /* guard against returns of NULL or FAILED_PRODUCTION */
    if ( rc == 0 && prod > FAILED_PRODUCTION )
    {
        VDB_DEBUG ( ("%*cresolved expression  '%s'\n", indent_level, ' ', VProdResolvePrintExpr ( self, expr ) ) );

        /* returned production must be on requested chain */
        if ( ( prod -> chain & self -> chain ) == 0 )
        {
            rc = RC ( rcVDB, rcProduction, rcResolving, rcSchema, rcInconsistent );
            VDB_DEBUG ( ( "%*cPRODUCTION RESOLVED ON WRONG FORK: %R\n", indent_level, ' ', rc ) );
        }
        else
        {
            /* fix uncommitted production chain */
            if ( prod -> chain == chainUncommitted )
                prod -> chain = self -> chain;

            /* test for type compatibility - modifies "fd" */
            if ( casting ?
                 VFormatdeclCommonAncestor ( & prod -> fd, self -> schema, fd, fd, NULL ) :
                 VFormatdeclToFormatdecl ( & prod -> fd, self -> schema, fd, fd, NULL ) )
            {
                /* if no type description is requested, we're done */
                if ( desc == NULL )
                    * out = prod;
                else
                {
                    /* otherwise, create a type description */
                    rc = VSchemaDescribeTypedecl ( self -> schema, desc, & fd -> td );
    assert (rc != -1);
                    if ( rc != 0 )
                        VDB_DEBUG ( ( "%*cREQUESTED TYPE CANNOT BE DESCRIBED: %R\n", indent_level, ' ', rc ) );
                    else
                        * out = prod;
                }
            }
            else
            {
#if _DEBUGGING
                char from [ 128 ] = "", to [ 128 ] = "";
                VTypedeclToText ( & prod -> fd . td, self -> schema, from, sizeof from );
                VTypedeclToText ( & fd -> td, self -> schema, to, sizeof to );
                VDB_DEBUG ( ( "%*cexpression '%s' cannot be %s from '%s' to '%s'\n"
                              , indent_level, ' '
                              , VProdResolvePrintExpr ( self, expr )
                              , casting ? "cast" : "typed"
                              , from
                              , to
                             )
                    );
#endif
            }
        }
    }
    else if ( rc != 0 )
    {
        VDB_DEBUG ( ( "failed to resolve expression '%s' prod %p %R\n", VProdResolvePrintExpr ( self, expr ), prod, rc ) );
    }
    else if ( prod == NULL )
    {
        VDB_DEBUG ( ( "expression '%s' was not resolved\n", VProdResolvePrintExpr ( self, expr ) ) );
    }
    else
    {
        VDB_DEBUG ( ( "expression '%s' returned FAILED_PRODUCTION\n", VProdResolvePrintExpr ( self, expr ) ) );
    }

#if _DEBUGGING
    -- indent_level;
#endif

    return rc;
}