/* 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; }
/* ParamExpr * resolve a simple parameter by name */ LIB_EXPORT rc_t CC VProdResolveParamExpr ( const VProdResolve *self, VProduction **out, const KSymbol *sym ) { const SProduction *sprod = sym -> u . obj; VProduction *vprod = VCursorCacheGet ( self -> cache, & sprod -> cid ); if ( vprod != NULL ) { * out = vprod; return 0; } PLOGMSG ( klogWarn, ( klogWarn, "unknown parameter '$(param)' used in expression" , "param=%.*s" , ( int ) sprod -> name -> name . size , sprod -> name -> name . addr )); return 0; }
/* PhysExpr */ rc_t VProdResolveSPhysMember ( const VProdResolve *self, VProduction **out, const SPhysMember *smbr ) { rc_t rc; VCursor *curs; VPhysical *phys; curs = self -> curs; phys = VCursorCacheGet ( & curs -> phys, & smbr -> cid ); if ( phys != NULL ) { /* this guy should be readable, but it is not guaranteed */ if ( phys != FAILED_PHYSICAL ) * out = phys -> out; return 0; } /* pre-fail */ rc = VCursorCacheSet ( & curs -> phys, & smbr -> cid, FAILED_PHYSICAL ); if ( rc == 0 ) { /* create physical object */ rc = VPhysicalMake ( & phys, curs, smbr ); if ( rc == 0 ) { /* build physical */ rc = VProdResolvePhysical ( self, phys ); if ( rc == 0 && phys -> out > FAILED_PRODUCTION && phys -> b2p > FAILED_PRODUCTION ) { /* set success */ void *ignore; rc = VCursorCacheSwap ( & curs -> phys, & smbr -> cid, phys, & ignore ); if ( rc == 0 ) { * out = phys -> out; return 0; } } if ( GetRCState ( rc ) == rcUndefined ) rc = 0; VPhysicalWhack ( phys, NULL ); } } return rc; }
/* AddSColumn */ static rc_t VViewCursorAddSColumn ( VViewCursor * p_self, uint32_t * p_idx, const SColumn * p_scol, const VTypedecl * p_cast, Vector * p_cx_bind ) { rc_t rc = 0; VColumn *col; /* must be readable */ if ( p_scol -> read == NULL ) { return RC ( rcVDB, rcCursor, rcUpdating, rcColumn, rcWriteonly ); } /* must not already be there - benign error */ col = VCursorCacheGet ( & p_self -> dad . col, & p_scol -> cid ); if ( col != NULL ) { * p_idx = col -> ord; rc = RC ( rcVDB, rcCursor, rcUpdating, rcColumn, rcExists ); } else { /* make object */ rc = VColumnMake ( & col, p_self -> view -> schema, p_scol ); if ( rc == 0 ) { #if 0 /* open column if cursor open or type unknown */ if ( self -> dad . state >= vcReady || scol -> td . type_id == 0 ) { rc = RC ( rcVDB, rcCursor, rcUpdating, rcColumn, ?? ); } else { /* check cast of SColumn against requested type this is to handle the case where the column was created incomplete, i.e. with unknown type */ if ( cast != NULL && | VTypedeclToTypedecl ( & scol -> td, self -> schema, cast, & col -> td, NULL ) ) { rc = RC ( rcVDB, rcCursor, rcUpdating, rcColumn, ?? ); } }
/* 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; }
rc_t VProdResolveColumn ( const VProdResolve *self, VProduction **out, const SColumn *scol, bool alt ) { rc_t rc; VColumn *vcol; WColumn *wcol; VCursor *curs = self -> curs; /* decide upon behavior */ if ( curs -> read_only ) { if ( alt ) { /* TODO: Generate warning message */ return RC ( rcVDB, rcCursor, rcOpening, rcSchema, rcInvalid ); } vcol = VCursorCacheGet ( & curs -> col, & scol -> cid ); if ( vcol == NULL ) { rc = VCursorMakeColumn ( curs, & vcol, scol ); if ( rc != 0 ) return rc; #if OPEN_COLUMN_ALTERS_ROW rc = VectorAppend ( & curs -> row, & vcol -> ord, vcol ); if ( rc != 0 ) { VColumnWhack ( vcol, NULL ); return rc; } #endif rc = VCursorCacheSet ( & curs -> col, & scol -> cid, vcol ); if ( rc != 0 ) { #if OPEN_COLUMN_ALTERS_ROW void *ignore; VectorSwap ( & curs -> row, vcol -> ord, NULL, & ignore ); vcol -> ord = 0; #endif VColumnWhack ( vcol, NULL ); return rc; } } return VProdResolveColumnRead ( self, out, scol ); } /* write cursor but read side */ if ( self -> chain == chainDecoding ) { if ( alt ) { /* TODO: Generate warning message */ return RC ( rcVDB, rcCursor, rcOpening, rcSchema, rcInvalid ); } return VProdResolveColumnRead ( self, out, scol ); } /* get existing column */ wcol = VCursorCacheGet ( & curs -> col, & scol -> cid ); if ( wcol == NULL ) { /* normally write-only cursor must have existing column */ if ( ! self -> discover_writable_columns ) return 0; /* auto-create writable column for purposes of discovery */ if ( scol -> read_only ) return 0; rc = VCursorMakeColumn ( curs, & vcol, scol ); if ( rc != 0 ) return rc; /* add it to the row as if user had done it */ rc = VectorAppend ( & curs -> row, & vcol -> ord, vcol ); if ( rc == 0 ) { /* add it to the indexed vector */ rc = VCursorCacheSet ( & curs -> col, & scol -> cid, vcol ); if ( rc != 0 ) { void *ignore; VectorSwap ( & curs -> row, vcol -> ord, NULL, & ignore ); vcol -> ord = 0; } } if ( rc != 0 ) { VColumnWhack ( vcol, NULL ); return rc; } wcol = ( WColumn* ) vcol; } /* create output production as required */ if ( wcol -> out == NULL ) { const char *name = scol -> name -> name . addr; rc = VColumnProdMake ( & wcol -> out, self -> owned, & wcol -> dad, prodColumnOut, name ); if ( rc != 0 ) return rc; } if ( alt ) { * out = wcol -> dad . in; assert ( * out != NULL ); } else { * out = wcol -> out; } return 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; }