Exemplo n.º 1
0
/* CastExpr
 *  inserts an explicit cast operation
 *
 *  in "C" style languages ( okay, ALGOL style ), a cast expression is
 *  used as a means of coercing the rh expression type to a fixed type,
 *  which is then assigned to the lh side with normal typecasting rules.
 *  specifically, performs an intermediate assignment allowing truncation
 *  to reshape and potentially reformat the rh value ( e.g. float to char ).
 *
 *  in "C++" there were new cast operators introduced to indicate more nuance:
 *    static_cast      - permits up and down-casts with compiler check
 *    const_cast       - modifies cv qualifiers [ not applicable to VDB ]
 *    dynamic_cast     - permits up and down-casts with runtime check
 *    reinterpret_cast - permits casts between unrelated classes with
 *                       compatible binary forms ( a la "C" style ).
 *
 *  in "VDB", the compiler preserves lh and rh type information until
 *  productions are resolved. assignments always involve implicit casts
 *  that permit casting from sub to super-type. our explicit cast expression
 *  performs something analogous to the C++ "static_cast" in that it allows
 *  direct up and down casts, as well as sibling and cousin casts.
 *
 *  specifically, LH = ( T ) RH when T is a sub-type of LH and:
 *    a) RH is a sub-type of T [ implicit rule ]
 *    b) T is a sub-type of RH [ downcast ]
 *    c) T and RH share a common ancestor
 *  in all cases, LH, T and RH must all have identical element sizes
 *
 *  implicit typecasting rules allow LH or RH to be a typeset. the types
 *  are initially refined to the intersection between LH and RH
 *    a) TYPE    x TYPE
 *    b) TYPESET x TYPE
 *    c) TYPE    x TYPESET
 *    d) TYPESET x TYPESET
 *  in the latter case, the intersection may produce more than one possible
 *  result, which would incur an error when evaluating the expression. a
 *  cast operator will remove the ambiguity.
 *
 *  the rh expression may involve a column name, with type overloading. this
 *  creates the same effect as a TYPESET. a cast operator can clarify an ambigous
 *  assignment, and in the case of downcasts, make it possible.
 *
 * NB
 *  to perform a C++ style reinterpret_cast, use the "cast" function
 */
static
rc_t VProdResolveCastExpr ( const VProdResolve *self, VProduction **out, const SBinExpr *expr )
{
    /* extract cast type */
    VFormatdecl cast;
    rc_t rc = STypeExprResolveAsFormatdecl
        ( ( const STypeExpr* ) expr -> left, self -> schema, & cast );
    if ( rc == 0 )
    {
        /* resolve rh expression */
        VTypedesc desc;
        VFormatdecl fd = cast;
        rc = VProdResolveExpr ( self, out, & desc,
            & fd, expr -> right, true );
        if ( rc != 0 || * out == NULL )
            return rc;

        /* casting mode allowed returned production to be:
           a) identical type
           b) sub-type
           c) super-type
           d) have common parent

           in all cases, the sizeof rh production element
           matches "cast" size */
        rc = VSimpleProdMake ( out, self -> owned, self -> curs, prodSimpleCast,
            "cast", & cast, & desc, NULL, * out, self -> chain );
    }

    return rc;
}
Exemplo n.º 2
0
/* ProdExpr
 *  resolve a simple production by name
 *  create/return a VSimpleProd object
 */
rc_t VProdResolveSProduction ( const VProdResolve *self, VProduction **out, const SProduction *sprod )
{
    rc_t rc;
    VFormatdecl fd;

    /* check cache */
    VProduction *vprod = VCursorCacheGet ( self -> cache, & sprod -> cid );
    if ( vprod != NULL )
    {
        /* return valid or failed production */
        * out = vprod;
        return 0;
    }

    /* pre-fail */
    rc = VCursorCacheSet ( self -> cache, & sprod -> cid, FAILED_PRODUCTION );
    if ( rc == 0 )
    {
        /* resolve production type */
        if ( sprod -> trigger )
            memset ( & fd, 0, sizeof fd );
        else
        {
            rc = STypeExprResolveAsFormatdecl
                ( ( const STypeExpr* ) sprod -> fd, self -> schema, & fd );
        }
    }
    if ( rc == 0 )
    {
        /* resolve assignment expression */
        VTypedesc desc;
        rc = VProdResolveExpr ( self, out, & desc,
            & fd, sprod -> expr, false );
        if ( rc == 0 && * out != NULL )
        {
            const char *name = sprod -> name -> name . addr;
            assert ( name [ sprod -> name -> name . size ] == 0 );
            rc = VSimpleProdMake ( out, self -> owned, self -> curs, prodSimpleCast, 
                name, & fd, & desc, & sprod -> cid, * out, self -> chain );
            if ( rc == 0 )
            {
                void *ignore;
                rc = VCursorCacheSwap ( self -> cache, & sprod -> cid, * out, & ignore );
            }
        }
    }

    return rc;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
/* ResolvePhysical
 *  resolves a physical column
 */
static
rc_t VProdResolvePhysicalWrite ( const VProdResolve *self, VPhysical *phys )
{
    VTypedesc desc;
    VFormatdecl fd;
    VProdResolve pr;
    VProduction *prod;
    VCursor *curs = self -> curs;

    const char *name;
    const SExpression *enc;
    const SPhysMember *smbr;

    /* open the physical column for write
       load column metadata/schema, complete
       physical member description. */
    rc_t rc = VPhysicalOpenWrite ( phys,
        ( VSchema* ) self -> schema, curs -> tbl );
    if ( rc != 0 )
        return rc;

    /* there are two conditions under which a physical member
       definition would be incommplete prior to opening the
       column: 1) if the physical column were only forwarded
       within table schema, or 2) if the column were added as
       the result of a file system scan.

       for the column to be writable, it must have had a complete
       member definition from table schema, with a type and an
       assignment expression, or it must have been added as the
       result of an fs scan with a simple reciprocal expression.
       the test for these two cases is for a resolved typedecl
       and an assignment expression. */

    /* nothing more to do if column does not exist
       and member was undeclared, or is declared read-only */
    smbr = phys -> smbr;
    if ( smbr -> td . type_id == 0 || smbr -> expr == NULL )
        return 0;

    /* build fmtdecl */
    fd . td = smbr -> td;
    fd . fmt = 0;

    /* shift to encode chain */
    pr = * self;
    pr . chain = chainEncoding;

    /* resolve the input expression */
    rc = VProdResolveExpr ( & pr, & phys -> in, & desc, & fd, smbr -> expr, false );
    if ( rc == 0 && phys -> in == NULL )
        return RC ( rcVDB, rcCursor, rcOpening, rcColumn, rcUndefined );

    /* NB - at this point, fd and desc
       represent the column's well-defined type */

    /* member name */
    name = smbr -> name -> name . addr;

    /* physical encoding */
    enc = phys -> enc;
    if ( enc == NULL )
        enc = smbr -> type;

    /* build encoding schema in steps:
         in <- page-to-blob
    */
    rc = VSimpleProdMake ( & prod, pr . owned,
        prodSimplePage2Blob, name, & fd, & desc, NULL, phys -> in, chainEncoding );
    if ( rc == 0 && enc != NULL )
    {
        /* in <- p2b <- encoding-func */
        pr . blobbing = true;
        rc = VProdResolveEncodingExpr ( & pr, & prod,
            prod, ( const SPhysEncExpr* ) enc );
        if ( rc == 0 )
        {
            fd = prod -> fd;
            desc = prod -> desc;
        }
    }
    if ( rc == 0 )
    {
        rc = VSimpleProdMake ( & phys -> b2s, pr . owned,
            prodSimpleBlob2Serial, name, & fd, & desc, NULL, prod, chainEncoding );
    }

    return rc;
}
Exemplo n.º 5
0
/* ResolvePhysical
 *  resolves a physical column
 */
rc_t VProdResolvePhysicalRead ( const VProdResolve *self, VPhysical *phys )
{
    rc_t rc;
    VTypedesc desc;
    VFormatdecl fd;
    VProduction *prod;
    VFunctionProd *bs;
    VCursor *curs = self -> curs;

    const char *name;
    const SExpression *enc;
    const SPhysMember *smbr;

    /* a write cursor would have opened this already */
    if ( curs -> read_only )
    {
        /* open the physical column for read */
        rc = VPhysicalOpenRead ( phys,
            ( VSchema* ) self -> schema, curs -> tbl );
        if ( rc != 0 )
        {
            /* trying to open a column that doesn't exist
               is not an error, but it didn't resolve */
            if ( GetRCState ( rc ) == rcNotFound )
                return 0;

            return rc;
        }
    }

    /* should be completely resolved */
    smbr = phys -> smbr;
    if ( smbr -> td . type_id == 0 )
        return 0;

    /* production name */
    name = smbr -> name -> name . addr;

    /* type information */
    fd . td = smbr -> td;
    fd . fmt = 0;
    rc = VSchemaDescribeTypedecl ( self -> schema, & desc, & fd . td );
    if ( rc != 0 )
        return rc;

    /* create output adapter */
    rc = VPhysicalProdMake ( & prod, self -> owned,
        curs, phys, prodPhysicalOut, name, & fd, & desc );
    if ( rc != 0 )
        return rc;

    /* create byte-swap function with transparent type information */
    rc = VFunctionProdMake ( & bs, self -> owned,
        curs, prodFuncByteswap, name, & fd, & desc, chainDecoding );
    if ( rc != 0 )
        return rc;

    /* set adapter as input to byte swap */
    rc = VectorAppend ( & bs -> parms, NULL, prod );
    if ( rc != 0 )
        return rc;

    /* take byte-swap function as output */
    phys -> out = & bs -> dad;

    /* NB - we now have byte-order native output via an adapter
       it remains to create a decoding path for physical blobs */


    /* create adapter */
    rc = VPhysicalProdMake ( & prod, self -> owned,
        curs, phys, prodPhysicalKCol, name, & fd, & desc );
    if ( rc != 0 )
        return rc;

    /* create serial-to-blob stage */
    rc = VSimpleProdMake ( & prod, self -> owned, self->curs,
        prodSimpleSerial2Blob, name, & fd, & desc, NULL, prod, chainDecoding );
    if ( rc != 0 )
        return rc;

    /* determine physical encoding */
    enc = phys -> enc;
    if ( enc == NULL )
        enc = smbr -> type;

    /* if unencoded */
    if ( enc == NULL )
        phys -> b2p = prod;
    else
    {
        /* the adapter type should be undefined */
        memset ( & prod -> fd, 0, sizeof prod -> fd );
        prod -> desc . intrinsic_bits = prod -> desc . intrinsic_dim = 1;
        prod -> desc . domain = 0;

        /* create decoding production */
        rc = VProdResolveEncodingExpr ( self, & phys -> b2p,
            prod, ( const SPhysEncExpr* ) enc );
    }

    return rc;
}
Exemplo n.º 6
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;
}