/*{ ** Name: opl_ioutjoin - init outer join IDs for this subquery ** ** Description: ** This routine will initialize an outer join descriptor for ** this subquery. Note that a PSF var may be referenced in several ** subqueries due to link backs in aggregates, etc. but only ** one of these subqueries would contain the outer join ID. So ** that OPF delays inserting the join ID into the ** subquery until a parse tree node is discovered which references ** the join ID. ** ** Inputs: ** subquery subquery which contains outer ** join ** varp ptr to range table entry ** containing the outer join var ** ** Outputs: ** ** Returns: ** VOID ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 14-sep-89 (seputis) ** initial creation ** 15-feb-93 (ed) ** fix outer join placement bug 49317 ** 19-jan-94 (ed) ** remove obsolete structures ** 15-sep-00 (inkdo01) ** Init opl_translate to NOINIT to distinguish from legitimate ** parent of OPL_NOOUTER (to fix bug 87175). [@history_line@]... [@history_template@]... */ OPL_IOUTER opl_ioutjoin( OPS_SUBQUERY *subquery, PST_J_ID joinid) { OPS_STATE *global; OPL_OUTER *outjoinp; global = subquery->ops_global; { /* this ID has not been added to the current set */ i4 ojsize; /* size of structures needed to support ** the outer join descriptor */ ojsize = sizeof(*outjoinp) + sizeof(*outjoinp->opl_innereqc) + sizeof(*outjoinp->opl_ojtotal) + sizeof(*outjoinp->opl_onclause) + sizeof(*outjoinp->opl_ovmap) + sizeof(*outjoinp->opl_ivmap) + sizeof(*outjoinp->opl_bvmap) + sizeof(*outjoinp->opl_ojbvmap) + sizeof(*outjoinp->opl_idmap) + sizeof(*outjoinp->opl_bfmap) + sizeof(*outjoinp->opl_minojmap) + sizeof(*outjoinp->opl_maxojmap) + sizeof(*outjoinp->opl_ojattr) + sizeof(*outjoinp->opl_reqinner); outjoinp = (OPL_OUTER *)opu_memory(global, ojsize); MEfill(ojsize, (u_char)0, (PTR)outjoinp); outjoinp->opl_innereqc = (OPE_BMEQCLS *)&outjoinp[1]; /* ptr to set of equivalence classes ** which represent all the inner relations ** to this outer join */ outjoinp->opl_id = subquery->ops_oj.opl_lv++; /* query tree ID associated with this ** outer join, which should be found in ** the op node of any qualification */ outjoinp->opl_gid = joinid; /* global ID used in query tree produced ** by parser, this is different from opl_id ** since opl_id is local to the subquery ** and the op nodes were renamed to ** be opl_id */ outjoinp->opl_ojtotal= (OPV_BMVARS *)&outjoinp->opl_innereqc[1]; /* map of ** all variables which are considered ** "inner" to this join ID, this map is used ** for legal placement of variables, this ** includes all secondaries etc. */ outjoinp->opl_onclause = (OPV_BMVARS *)&outjoinp->opl_ojtotal[1]; ; outjoinp->opl_ovmap = (OPV_BMVARS *)&outjoinp->opl_onclause[1]; outjoinp->opl_ivmap = (OPV_BMVARS *)&outjoinp->opl_ovmap[1]; outjoinp->opl_bvmap = (OPV_BMVARS *)&outjoinp->opl_ivmap[1]; outjoinp->opl_ojbvmap = (OPV_BMVARS *)&outjoinp->opl_bvmap[1]; outjoinp->opl_idmap = (OPL_BMOJ *)&outjoinp->opl_ojbvmap[1]; outjoinp->opl_bfmap = (OPB_BMBF *)&outjoinp->opl_idmap[1]; outjoinp->opl_minojmap = (OPV_BMVARS *)&outjoinp->opl_bfmap[1]; outjoinp->opl_maxojmap = (OPV_BMVARS *)&outjoinp->opl_minojmap[1]; outjoinp->opl_ojattr = (OPZ_BMATTS *)&outjoinp->opl_maxojmap[1]; outjoinp->opl_reqinner = (OPL_BMOJ *)&outjoinp->opl_ojattr[1]; outjoinp->opl_type = OPL_UNKNOWN; /* type of outer join will ** be determined later */ outjoinp->opl_mask = 0; /* mask of various booleans */ outjoinp->opl_translate = OPL_NOINIT; if ((subquery->ops_oj.opl_lv >= OPL_MAXOUTER) || (joinid > global->ops_goj.opl_glv)) opx_error(E_OP038E_MAXOUTERJOIN); subquery->ops_oj.opl_base->opl_ojt[outjoinp->opl_id] = outjoinp; if (joinid == PST_NOJOIN) return (outjoinp->opl_id); /* in the case of TID joins this routine ** would be called to create a new joinid ** descriptor for a left join */ if (joinid > global->ops_goj.opl_glv) opx_error(E_OP0395_PSF_JOINID); /* join id is out of range */ if (global->ops_goj.opl_gbase->opl_gojt[joinid] != OPL_NOOUTER) opx_error(E_OP038F_OUTERJOINSCOPE); /* not expecting another translation ** for the same outer join */ BTset( (i4)joinid, (char *)&subquery->ops_oj.opl_jmap); /* mark ** outer join ID as being processed */ global->ops_goj.opl_gbase->opl_gojt[joinid] = outjoinp->opl_id; } { /* traverse range table and check for any variables which reference ** this join id */ OPV_IVARS varno; OPV_RT *vbase; /* ptr to base of array of ptrs ** to joinop variables */ OPL_PARSER *pouter; OPL_PARSER *pinner; vbase = subquery->ops_vars.opv_base; /* init ptr to base of array of ** ptrs to joinop variables */ pouter = subquery->ops_oj.opl_pouter; pinner = subquery->ops_oj.opl_pinner; for (varno = subquery->ops_vars.opv_rv; --varno>=0;) { OPV_VARS *varp; varp = vbase->opv_rt[varno]; if (varp->opv_grv /* && (varp->opv_grv->opv_gmask & OPV_GOJVAR) OPV_GOJVAR is not reliably set */ ) { OPV_IGVARS gvar; gvar = varp->opv_gvar; /* outer join semantics are defined with ** the primary */ if (BTtest((i4)joinid, (char *)&pouter->opl_parser[gvar])) { /* found variable which is an outer to this join id */ if (!varp->opv_ojmap) { /* allocate a bit map for the outer join */ varp->opv_ojmap = (OPL_BMOJ *)opu_memory(global, (i4)sizeof(*varp->opv_ojmap)); MEfill(sizeof(*varp->opv_ojmap), (u_char)0, (PTR)varp->opv_ojmap); } BTset((i4)outjoinp->opl_id, (char *)varp->opv_ojmap); } if (BTtest((i4)joinid, (char *)&pinner->opl_parser[gvar])) { /* found variable which is an inner to this join id */ if (!varp->opv_ijmap) { /* allocate a bit map for the outer join */ varp->opv_ijmap = (OPL_BMOJ *)opu_memory(global, (i4)sizeof(*varp->opv_ijmap)); MEfill(sizeof(*varp->opv_ijmap), (u_char)0, (PTR)varp->opv_ijmap); } BTset((i4)outjoinp->opl_id, (char *)varp->opv_ijmap); BTset((i4)varno, (char *)outjoinp->opl_ojtotal); } } } } return (outjoinp->opl_id); }
/*{ ** Name: opv_parser - init global range table element given parser varno ** ** Description: ** This routine will initialize the global range table element in OPF ** corresponding to the PSF range table element. ** ** Inputs: ** global ptr to global range table ** gvar element in parser range table ** which is referenced in query ** ** Outputs: ** global->ops_rangetab.opv_base[gvar] initialize corresponding element ** in optimizer range table ** Returns: ** VOID ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 2-jul-86 (seputis) ** initial creation ** 6-nov-88 (seputis) ** change RDF invalidation to include all indexes on base relation ** since this is only notification that OPF gets that its' time ** stamp is out of date ** 25-sep-89 (seputis) ** - made addition to timestamp check, to refresh if this is a ** multi-variable query and the tuple count is zero ** 9-nov-89 (seputis) ** - added OPA_NOVID initialization for b8160, and corrected ** sep 25 fix for timestamps ** 12-jan-90 (seputis) ** - detect table ID's which are the same for different range vars ** 26-feb-91 (seputis) ** - add improved diagnostics for b35862 ** 31-dec-91 (seputis) ** - flush cache entry if tuple count is zero and more than one ** range table entry, since aggregate queries and flattened queries ** are not getting handled. ** 12-feb-93 (jhahn) ** Added support for statement level rules. (FIPS) ** 12-apr-93 (ed) ** - fix bug 50673, relax range variable check for larger OPF table ** 7-dec-93 (ed) ** b56139 - add OPZ_TIDHISTO to mark tid attributes which ** need histograms,... needed since target list is traversed ** earlier than before ** 16-feb-95 (inkdo01) ** b66907 - check for explicit refs to inconsistent tabs/idxes ** 23-feb-95 (wolf) ** Recent addition of MEcopy call should have been accompanied by ** an include of me.h ** 10-aug-98 (stial01) ** opv_parser() Remove code to invalidate indexes. The invalidate ** table that follows will do the job. Invalidate indexes by table id ** can get E_OP008E_RDF_INVALIDATE, E_RD0045_ULH_ACCESS ** 31-oct-1998 (nanpr01) ** Reset the rdfcb->infoblk ptr before checking the error code. ** 18-june-99 (inkdo01) ** Init opv_ttmodel for temp table model histogram feature. ** 19-Jan-2000 (thaju02) ** relation descriptor may be out of date and contain a stale ** secondary index count, use rdfcb->rdf_info_block->rdr_no_index ** which reflects the number of index entries in the rdr_indx ** array. (b100060) ** 17-Jan-2004 (schka24) ** Rename RDR_BLD_KEY to RDR_BLD_PHYS. ** 3-Sep-2005 (schka24) ** Remove if-0'ed out section that included a ref to a member ** that is going away (opv_ghist). ** 17-Nov-2005 (schka24) ** Don't propagate RDF invalidates that we cause. Our RDF cache ** is out of date but that's not other servers' problem. ** 14-Mar-2007 (kschendel) SIR 122513 ** Light "partitioned" flag if partitioned table seen. ** 18-april-2008 (dougi) ** Add support for table procedures. ** 8-Jul-2010 (wanfr01) b123949 ** If rdf_gdesc failed with an error, don't use the column ** information - it may not be fully initialized. */ bool opv_parser( OPS_STATE *global, OPV_IGVARS gvar, OPS_SQTYPE sqtype, bool rdfinfo, bool psf_table, bool abort) { OPV_GRT *gbase; /* ptr to base of global range table */ # ifdef E_OP0387_VARNO if ((gvar < 0) || ((gvar >= PST_NUMVARS) && (gvar >= OPV_MAXVAR))) opx_error(E_OP0387_VARNO ); /* range var out of range - ** consistency check */ # endif gbase = global->ops_rangetab.opv_base; /* get base of global range table ** ptr to array of ptrs */ if ( !gbase->opv_grv[gvar] ) { /* if global range variable element has not been allocated */ OPV_GRV *grvp; /* ptr to new range var element */ if (global->ops_rangetab.opv_gv <= gvar) global->ops_rangetab.opv_gv = gvar+1; /* update the largest range ** table element assigned so far */ grvp = (OPV_GRV *) opu_memory(global, sizeof( OPV_GRV ) ); /* save ** and allocate ptr to global ** var */ /* Explicitly zero out the grv entry */ MEfill(sizeof(*grvp), (u_char)0, (PTR)grvp); grvp->opv_qrt = gvar; /* save index to ** parser range table element */ grvp->opv_created = sqtype; /* save global range table type */ grvp->opv_gvid = OPA_NOVID; /* if this base table was implicitly ** referenced then the view id of the ** explicitly reference view will be ** saved */ grvp->opv_siteid = OPD_NOSITE; /* initialize distributed site location */ grvp->opv_same = OPV_NOGVAR; /* used to map tables with similiar ** IDs */ grvp->opv_compare = OPV_NOGVAR; /* used to map tables with similiar ** IDs */ grvp->opv_ttmodel = NULL; /* RDR_INFO ptr for temp table model ** histograms */ gbase->opv_grv[gvar] = grvp; /* place into table */ /* get RDF information about the table */ if (rdfinfo) { RDF_CB *rdfcb; /* ptr to RDF control block which ** has proper db_id and sessionid ** info */ PST_RNGENTRY *rngentry; /* ptr to parse tree range entry */ DB_STATUS status; /* RDF return status */ i4 ituple; rdfcb = &global->ops_rangetab.opv_rdfcb; if (psf_table) { /* Snag table procedures and handle them elsewhere. */ if ((rngentry = global->ops_qheader->pst_rangetab[gvar]) ->pst_rgtype == PST_TPROC) { if (opv_tproc(global, gvar, grvp, rngentry) == E_DB_OK) return(FALSE); else return(TRUE); } STRUCT_ASSIGN_MACRO(global->ops_qheader->pst_rangetab[gvar]-> pst_rngvar, rdfcb->rdf_rb.rdr_tabid); /* need ** table id from parser's table */ #if 0 if ((BTnext((i4)-1, (char *)&rangep->pst_outer_rel, (i4)BITS_IN(rangep->pst_outer_rel)) >= 0) || (BTnext((i4)-1, (char *)&rangep->pst_inner_rel, (i4)BITS_IN(rangep->pst_outer_rel)) >= 0) ) grvp->opv_gmask |= OPV_GOJVAR; /* mark whether this ** variable is within the scope of an ** outer join */ /* OPV_GOJVAR is not reliably set since the subquery bitmap should be tested ** also for an aggregate temp, multi-to-one mappings may exist for global range ** variables */ #endif if (global->ops_qheader->pst_rangetab[gvar]-> pst_rgtype == PST_SETINPUT) grvp->opv_gmask |= OPV_SETINPUT; /* is this the set input ** parameter for a procedure */ rdfcb->rdf_rb.rdr_types_mask = RDR_RELATION | RDR_INDEXES | RDR_ATTRIBUTES | RDR_BLD_PHYS; /* get relation info ** - The optimizer uses attribute ** info in query tree directly ** but it is needed to be requested ** since the RDF uses attr info to ** build RDR_BLK_KEY info. The ** attribute info does not need to ** requested if RDF is changed. ** - ask for indexes so that ** invalidating the cache can also ** invalidate any indexes in the ** cache */ /* When we're ready to enable column comparison stats, uncomment the following statement. ** rdfcb->rdf_rb.rdr_2types_mask = RDR2_COLCOMPARE; /* column ** comparison stats, too */ } rdfcb->rdf_info_blk = NULL; /* get new ptr to info ** associated with global var */ status = rdf_call( RDF_GETDESC, (PTR)rdfcb); grvp->opv_relation = rdfcb->rdf_info_blk; /* save ptr to ** new info block */ if ((status != E_RD0000_OK) && (rdfcb->rdf_error.err_code != E_RD026A_OBJ_INDEXCOUNT) /* this ** is a check for distributed ** index information, which could ** be inconsistent but should not ** cause the query to be aborted ** it will cause indexes to be ** avoided */ ) { gbase->opv_grv[gvar] = NULL; if (abort) opx_verror( status, E_OP0004_RDF_GETDESC, rdfcb->rdf_error.err_code); else { return (TRUE); /* indicate failure to get RDF ** descriptor */ } } BTset( (i4)gvar, (char *)&global->ops_rangetab.opv_mrdf); /* indicate ** that RDF information is fixed */ /* Check table and all associated indexes to see if there is a ** statement level index associated with this variable */ if (grvp->opv_relation->rdr_rel->tbl_2_status_mask & DMT_STATEMENT_LEVEL_UNIQUE) grvp->opv_gmask |= OPV_STATEMENT_LEVEL_UNIQUE; for( ituple = grvp->opv_relation->rdr_no_index; ituple-- ;) { if (grvp->opv_relation->rdr_indx[ituple]->idx_status & DMT_I_STATEMENT_LEVEL_UNIQUE) grvp->opv_gmask |= OPV_STATEMENT_LEVEL_UNIQUE; } if (psf_table) { /* check if timestamp matches and invalidate RDF cache ** date of last modify do not match, this is only done ** for tables passed by PSF, the other tables should ** be dependent on the PSF time stamp */ DB_TAB_TIMESTAMP *timeptr; /* ptr to last modify ** date that RDF has cached */ DB_TAB_TIMESTAMP *psftimeptr; /* ptr to last modify ** date which parser used for the ** table */ psftimeptr = &global->ops_qheader->pst_rangetab[gvar]-> pst_timestamp; timeptr = &grvp->opv_relation->rdr_rel->tbl_date_modified; if (timeptr->db_tab_high_time != psftimeptr->db_tab_high_time || timeptr->db_tab_low_time != psftimeptr->db_tab_low_time || ( !grvp->opv_relation->rdr_rel->tbl_record_count && (global->ops_qheader->pst_rngvar_count > 1) ) /* special zero tuple count ** case check to see if tuple count ** is way off, i.e. a table create ** followed by a number of appends ** will cause a 0 tuple count, check ** for more than one variable since ** refresh is only useful when joins occur */ ) { PTR save_fcb = rdfcb->rdf_rb.rdr_fcb; /* Don't propagate this invalidate to other DBMS servers. ** There's no reason to think that they are as out of ** date as we are. (plus this might be a session temp ** which is strictly local!) */ rdfcb->rdf_rb.rdr_fcb = NULL; status = rdf_call( RDF_INVALIDATE, (PTR)rdfcb); rdfcb->rdf_rb.rdr_fcb = save_fcb; # ifdef E_OP008E_RDF_INVALIDATE if (status != E_RD0000_OK) opx_verror( E_DB_ERROR, E_OP008E_RDF_INVALIDATE, rdfcb->rdf_error.err_code); # endif status = rdf_call( RDF_GETDESC, (PTR)rdfcb); grvp->opv_relation = rdfcb->rdf_info_blk; /* save ptr to ** new info block */ if (status != E_RD0000_OK) { gbase->opv_grv[gvar] = NULL; opx_verror( E_DB_ERROR, E_OP0004_RDF_GETDESC, rdfcb->rdf_error.err_code); } timeptr = &grvp->opv_relation->rdr_rel->tbl_date_modified; if (timeptr->db_tab_high_time != psftimeptr->db_tab_high_time || timeptr->db_tab_low_time != psftimeptr->db_tab_low_time ) opx_vrecover( E_DB_ERROR, E_OP008F_RDF_MISMATCH, rdfcb->rdf_error.err_code); /* PSF timestamp is ** still out of date, so tell ** SCF to reparse the query */ } { /* search thru existing tables to discover if any ** tables have the same table ID */ OPV_IGVARS gvno; DB_TAB_ID *tabidp; OPV_IGVARS target_vno; tabidp = &global->ops_qheader->pst_rangetab[gvar]->pst_rngvar; target_vno = OPV_NOGVAR; for (gvno = 0; gvno < OPV_MAXVAR; gvno++) { OPV_GRV *grv1p; grv1p = gbase->opv_grv[gvno]; if (grv1p && grv1p->opv_relation) { DB_TAB_ID *gtabidp; if (gvno == gvar) continue; gtabidp = &grv1p->opv_relation->rdr_rel->tbl_id; if ((tabidp->db_tab_base == gtabidp->db_tab_base) && (tabidp->db_tab_index == gtabidp->db_tab_index) ) { /* found 2 table ID's which are identical */ global->ops_gmask |= OPS_IDSAME; if (target_vno == OPV_NOGVAR) { /* map all table id's vars to the lowest ** global range number of the group */ if (gvno > gvar) target_vno = gvar; else target_vno = gvno; } grv1p->opv_same = target_vno; grvp->opv_same = target_vno; if (target_vno != gvar) break; } } } } } if (global->ops_cb->ops_smask & OPS_MDISTRIBUTED) opd_addsite(global, grvp); /* add site information if a ** distributed thread */ /* Check for partitioned table, turns on additional ** analysis after enumeration. */ if (grvp->opv_relation != NULL && grvp->opv_relation->rdr_parts != NULL) global->ops_gmask |= OPS_PARTITION; if (grvp->opv_relation && grvp->opv_relation->rdr_rel-> tbl_2_status_mask & DMT_INCONSIST) /* check for inconsistent table ** (due to partial back/recov) */ { OPT_NAME tabname; i2 i; MEcopy(&grvp->opv_relation->rdr_rel->tbl_name, sizeof(grvp->opv_relation->rdr_rel->tbl_name), &tabname); /* table name is msg token */ for (i = sizeof(grvp->opv_relation->rdr_rel->tbl_name); i > 1 && tabname.buf[i-1] == ' '; i--); tabname.buf[i] = 0; /* lop blanks off name */ opx_1perror(E_OP009A_INCONSISTENT_TAB,(PTR)&tabname); } } else grvp->opv_relation = NULL; /* set to NULL if not used */ } return(FALSE); }
/*{ ** Name: ops_qinit - initialize structures needed for optimization ** ** Description: ** This routine will initialize the "global state" variable for one query ** within a procedure. It must be called prior to the optimization of ** every query in the procedure ** ** Inputs: ** global ptr to global state variable ** .ops_cb ptr to session control block ** .ops_caller_cb ptr to same object as opf_cb ** statementp ptr to statement containing query ** to be optimized ** ** Outputs: ** global all components initialized ** Returns: ** E_DB_OK, E_DB_ERROR ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 24-feb-86 (seputis) ** initial creation ** 8-sep-86 (seputis) ** DBP init range table only if statementp == NULL ** 6-nov-88 (seputis) ** initial opn_statistics ** 28-jan-89 (paul) ** Initialize rules processing flag to FALSE. Indicates we are ** not currently compiling a rule action. ** 22-may-89 (neil) ** Put PSQ_DELCURS through same fast path as PSQ_REPCURS. ** 22-sep-89 (seputis) ** added ops_gmask for boolean expansion ** 14-nov-89 (seputis) ** fixed 8629, to not use repeat parameters in procedures ** 6-jun-90 (seputis) ** fix b30463 - moved some large memory structure handling to ** the procedure level rather than query level ** 28-aug-90 (seputis) ** - fix b32757 - init opn_statistics in all cases ** 26-nov-90 (stec) ** Added initialization of ops_prbuf in OPS_STATE struct. ** 23-jan-91 (seputis) ** moved RDF_CB initialization here so that OPC can use ** this initialization also. ** 28-oct-92 (jhahn) ** Added initialization of ops_inStatementEndRules. ** 01-Jan-00 (sarjo01) ** Bug 99120: Added opn_initcollate() call ** 5-dec-02 (inkdo01) ** Changes for range table expansion. ** 30-jan-2003 (somsa01) ** Moved the initialization of ops_gmask before checking ** for !statementp. This fixes E_OP0791_ADE_INSTRGEN when ** creating a procedure after the fixes for bug 109194. ** 4-nov-04 (inkdo01) ** Init opn_fragcolist for greedy enumeration. ** 15-june-06 (dougi) ** Add support for "before" triggers. ** 21-Oct-2010 (kiria01) b123345 ** Do not assume PST_DV_TYPE is only present when the ** context is a DBP. It may also be present from temporaries ** created by the parser. [@history_template@]... */ VOID ops_qinit( OPS_STATE *global, PST_STATEMENT *statementp) { MEfill(sizeof(OPV_GBMVARS), 0, (char *)&global->ops_rangetab.opv_mrdf); /* used for deallocation */ global->ops_rangetab.opv_gv = 0; /* no global range variables defined */ global->ops_rangetab.opv_base = NULL; /* - NULL indicates that the ** global range table not been allocated ** - used by error handling to ** deallocate ULM and RDF resources */ /* Initially, we are not processing rules at the beginning of an */ /* optimization or the beginning of a PST_QT_TYPE */ global->ops_inAfterRules = global->ops_inBeforeRules = FALSE; global->ops_inAfterStatementEndRules = FALSE; global->ops_inBeforeStatementEndRules = FALSE; global->ops_gmask = 0; /* init boolean mask */ if (!statementp) return; /* only initialize if statement is provided ** otherwise, only init the global range ** table for resource deallocation */ global->ops_statement = statementp; global->ops_qheader = statementp->pst_specific.pst_tree; /* ** get the query tree header root from ** the statement */ global->ops_copiedco = NULL; /* no CO nodes have been allocated yet */ global->ops_subquery = NULL; /* initialize the subquery list */ /* global->ops_astate initialized by aggregate processing phase */ /* global->ops_estate initialized by joinop processing phase */ { global->ops_mstate.ops_usemain = FALSE; /* disable redirection of ** memory allocation */ global->ops_terror = FALSE; /* TRUE if tuple too wide for ** intermediate relation */ } /* the number of parameters may increase in a query if any simple ** aggregates are found, thus a separate count of query parameters ** is kept in the state variable. */ if (global->ops_procedure->pst_isdbp) { /* procedures do not have repeat query parameters, so use ** the local variable declaration to find the largest parameter ** number, there is an assumption that there is only one ** PST_DECVAR statement and this can be used to determine ** the largest allocated constant number */ PST_STATEMENT *decvarp; decvarp = global->ops_procedure->pst_stmts; if (decvarp->pst_type != PST_DV_TYPE) opx_error(E_OP0B81_VARIABLE_DEC); /* verify statement type, an ** assumption is that a declaration ** is always the first statement of ** a procedure */ global->ops_parmtotal = decvarp->pst_specific.pst_dbpvar->pst_nvars + decvarp->pst_specific.pst_dbpvar->pst_first_varno - 1; } else { global->ops_parmtotal = global->ops_qheader->pst_numparm; if (global->ops_procedure->pst_stmts->pst_type == PST_DV_TYPE) { /* Support local variables that may have been introduced ** as temporaries */ PST_DECVAR *decvarp = global->ops_procedure-> pst_stmts->pst_specific.pst_dbpvar; global->ops_parmtotal += decvarp->pst_nvars + decvarp->pst_first_varno - 1; } } { /* initialize outer join descriptors */ global->ops_goj.opl_gbase = (OPL_GOJT *) NULL; global->ops_goj.opl_view = (OPL_GOJT *) NULL; global->ops_goj.opl_fjview = (OPL_GOJT *) NULL; global->ops_goj.opl_glv = global->ops_qheader->pst_numjoins; if (global->ops_qheader->pst_numjoins > 0) global->ops_goj.opl_mask = OPL_OJFOUND; else global->ops_goj.opl_mask = 0; } global->ops_rqlist = NULL; /* list of repeat query descriptors */ if (( (global->ops_qheader->pst_mode != PSQ_REPCURS) && (global->ops_qheader->pst_mode != PSQ_DELCURS) ) || (global->ops_cb->ops_smask & OPS_MDISTRIBUTED) ) { opv_grtinit( global, TRUE); /* initialize the global range table ** ops_rangetab structure, ... replace ** & delete cursor do not need this */ } else { /* special case short cut "hack" for replace/delete cursor stmt which ** should not need to go through enumeration,... it should go ** directly to query compilation to compile the target list ** expressions */ /* for distributed the parse tree is traversed to handle the ** ~V case for multi-site so this section is not needed */ #if 0 /* looks like this was replaced by opv_grtinit call, with the extra ** boolean parameter */ MEfill(sizeof(OPV_GLOBAL_RANGE), (u_char)0, (PTR)&global->ops_rangetab); /* init global range table for ** query compilation */ #endif opv_grtinit( global, FALSE); global->ops_subquery = (OPS_SUBQUERY *)opu_memory(global, (i4) sizeof(OPS_SUBQUERY)); MEfill(sizeof(OPS_SUBQUERY), (u_char)0, (PTR)global->ops_subquery); /* init subquery structure for ** query compilation */ global->ops_subquery->ops_sqtype = OPS_MAIN; global->ops_subquery->ops_root = global->ops_qheader->pst_qtree; } /* these fields should be initialized once before the enumeration phase */ global->ops_estate.opn_cocount = 0; /* number of CO nodes available */ global->ops_estate.opn_statistics = FALSE; /* statistics has not been ** turned on yet */ global->ops_estate.opn_colist = NULL; /* list of avail perm CO nodes */ global->ops_estate.opn_fragcolist = NULL; global->ops_union = FALSE; /* TRUE if union view needs to be ** processed */ global->ops_tvar = OPV_NOGVAR; /* init var for special case update ** by TID */ { /* distributed initialization */ global->ops_gdist.opd_tcost = NULL; global->ops_gdist.opd_dv = 0; global->ops_gdist.opd_base = NULL; global->ops_gdist.opd_tbestco = NULL; global->ops_gdist.opd_copied = NULL; global->ops_gdist.opd_scopied = FALSE; global->ops_gdist.opd_repeat = NULL; global->ops_gdist.opd_gmask = 0; global->ops_gdist.opd_user_parameters = 0; } opn_initcollate(global); }
/*{ ** Name: opv_tproc - Load RDF defs for table procedure range table entry ** ** Description: ** This function allocates and formats simulated RDF structures for ** a table procedure, including result column descriptors that are ** used to resolve "column" references to the procedure. ** ** Inputs: ** sess_cb Pointer to session control block ** rngtable Pointer to the user range table ** scope scope that range variable belongs in ** -1 means don't care. ** corrname Correlation name of table procedure ** dbp Ptr to PSF procedure descriptor ** rngvar Place to put pointer to new range ** variable ** root Ptr to RESDOM list of parameter specs ** err_blk Place to put error information ** ** Outputs: ** rngvar Set to point to the range variable ** err_blk Filled in if an error happens ** Returns: ** E_DB_OK Success ** E_DB_ERROR Non-catastrophic failure ** E_DB_FATAL Catastrophic failure ** Exceptions: ** none ** ** Side Effects: ** Can allocate memory ** ** History: ** 17-april-2008 (dougi) ** Written for table procedures(semi-cloned from pst_stproc). ** 15-dec-2008 (dougi) BUG 121381 ** Fix computation of result column offsets. */ DB_STATUS opv_tproc( OPS_STATE *global, OPV_IGVARS gvar, OPV_GRV *grvp, PST_RNGENTRY *rngentry) { DMT_ATT_ENTRY **attarray, *attrp; DMT_ATT_ENTRY **parmarray, **rescarray; DMT_TBL_ENTRY *tblptr; RDR_INFO *rdrinfop; QEF_DATA *qp; RDF_CB *rdf_cb; RDR_RB *rdf_rb; DB_PROCEDURE *dbp; DB_DBP_NAME proc_name; DB_OWN_NAME proc_owner; i4 parameterCount, rescolCount, resrowWidth; u_i4 created; i4 i, j, totlen, offset; DB_STATUS status; i4 err_code; /* First retrieve iiprocedure row using id from range table entry. */ rdf_cb = &global->ops_rangetab.opv_rdfcb; rdf_rb = &rdf_cb->rdf_rb; STRUCT_ASSIGN_MACRO(rngentry->pst_rngvar, rdf_rb->rdr_tabid); rdf_rb->rdr_types_mask = RDR_PROCEDURE; rdf_rb->rdr_2types_mask = 0; rdf_rb->rdr_instr = RDF_NO_INSTR; /* ** need to set rdf_info_blk to NULL for otherwise RDF assumes that we ** already have the info_block */ rdf_cb->rdf_info_blk = (RDR_INFO *) NULL; status = rdf_call(RDF_GETINFO, rdf_cb); if (DB_FAILURE_MACRO(status)) { (VOID) opx_verror(status, E_OP0004_RDF_GETDESC, rdf_cb->rdf_error.err_code); } dbp = rdf_cb->rdf_info_blk->rdr_dbp; /* Before proceeding - assure this is the same proc that we think it is. */ if (rngentry->pst_timestamp.db_tab_high_time != dbp->db_created) { /* If not, bounce back to SCF to re-parse query. */ opx_vrecover(E_DB_ERROR, E_OP008F_RDF_MISMATCH, rdf_cb->rdf_error.err_code); } /* Save procedure stuff for later. */ parameterCount = dbp->db_parameterCount; rescolCount = dbp->db_rescolCount; resrowWidth = dbp->db_resrowWidth; created = dbp->db_created; STRUCT_ASSIGN_MACRO(dbp->db_dbpname, proc_name); STRUCT_ASSIGN_MACRO(dbp->db_owner, proc_owner); /* Allocate attr descriptors and address from ptr arrays. */ i = dbp->db_parameterCount + dbp->db_rescolCount; attarray = (DMT_ATT_ENTRY **) opu_memory(global, (sizeof(PTR) + sizeof(DMT_ATT_ENTRY)) * i + sizeof(PTR)); /* 1 extra ptr because array is 1-origin */ /* Set up attr pointer arrays for both parms and result columns. */ for (j = 1, attrp = (DMT_ATT_ENTRY *)&attarray[i+1], attarray[0] = (DMT_ATT_ENTRY *)NULL; j <= i; j++, attrp = &attrp[1]) { attarray[j] = attrp; MEfill(sizeof(DMT_ATT_ENTRY), (u_char)0, (char *)attrp); } rescarray = attarray; parmarray = &attarray[rescolCount+1]; /* Load iiprocedure_parameter rows for both parms and result cols. */ rdf_rb->rdr_types_mask = 0; rdf_rb->rdr_2types_mask = RDR2_PROCEDURE_PARAMETERS; rdf_rb->rdr_instr = RDF_NO_INSTR; rdf_rb->rdr_update_op = RDR_OPEN; rdf_rb->rdr_qrymod_id = 0; /* get all tuples */ rdf_rb->rdr_qtuple_count = 20; /* get 20 at a time */ rdf_cb->rdf_error.err_code = 0; /* ** must set rdr_rec_access_id since otherwise RDF will barf when we ** try to RDR_OPEN */ rdf_rb->rdr_rec_access_id = NULL; while (rdf_cb->rdf_error.err_code == 0) { status = rdf_call(RDF_READTUPLES, rdf_cb); rdf_rb->rdr_update_op = RDR_GETNEXT; /* Must not use DB_FAILURE_MACRO because E_RD0011 returns ** E_DB_WARN that would be missed. */ if (status != E_DB_OK) { switch(rdf_cb->rdf_error.err_code) { case E_RD0011_NO_MORE_ROWS: status = E_DB_OK; break; case E_RD0013_NO_TUPLE_FOUND: status = E_DB_OK; continue; default: opx_error(E_OP0013_READ_TUPLES); break; } /* switch */ } /* if status != E_DB_OK */ /* For each dbproc parameter tuple */ for (qp = rdf_cb->rdf_info_blk->rdr_pptuples->qrym_data, j = 0; j < rdf_cb->rdf_info_blk->rdr_pptuples->qrym_cnt; qp = qp->dt_next, j++) { DB_PROCEDURE_PARAMETER *param_tup = (DB_PROCEDURE_PARAMETER *) qp->dt_data; if (i-- == 0) { opx_error(E_OP0013_READ_TUPLES); } if (param_tup->dbpp_flags & DBPP_RESULT_COL) { attrp = rescarray[param_tup->dbpp_number]; attrp->att_number = param_tup->dbpp_number; } else { attrp = parmarray[param_tup->dbpp_number-1]; attrp->att_flags = DMT_F_TPROCPARM; attrp->att_number = param_tup->dbpp_number + dbp->db_rescolCount; } STRUCT_ASSIGN_MACRO(param_tup->dbpp_name, attrp->att_name); attrp->att_type = param_tup->dbpp_datatype; attrp->att_width = param_tup->dbpp_length; attrp->att_prec = param_tup->dbpp_precision; attrp->att_offset = param_tup->dbpp_offset; } } /* Reset result column offsets to remove effect of parms. */ offset = rescarray[1]->att_offset; for (j = 1; j <= rescolCount; j++) rescarray[j]->att_offset -= offset; if (rdf_rb->rdr_rec_access_id != NULL) { rdf_rb->rdr_update_op = RDR_CLOSE; status = rdf_call(RDF_READTUPLES, rdf_cb); if (DB_FAILURE_MACRO(status)) { opx_error(E_OP0013_READ_TUPLES); } } /* now unfix the dbproc description */ rdf_rb->rdr_types_mask = RDR_PROCEDURE | RDR_BY_NAME; rdf_rb->rdr_2types_mask = 0; rdf_rb->rdr_instr = RDF_NO_INSTR; status = rdf_call(RDF_UNFIX, rdf_cb); if (DB_FAILURE_MACRO(status)) { opx_error(E_OP008D_RDF_UNFIX); } /* Allocate table descriptor. */ tblptr = (DMT_TBL_ENTRY *) opu_memory(global, sizeof(DMT_TBL_ENTRY)); /* Allocate RDR_INFO block. */ rdrinfop = (RDR_INFO *) opu_memory(global, sizeof(RDR_INFO)+sizeof(PTR)); /* Now format them all. */ MEfill(sizeof(DMT_TBL_ENTRY), (u_char) 0, tblptr); MEcopy((char *)&proc_name.db_dbp_name, sizeof(DB_DBP_NAME), (char *)&tblptr->tbl_name.db_tab_name); STRUCT_ASSIGN_MACRO(proc_owner, tblptr->tbl_owner); MEfill(sizeof(DB_LOC_NAME), (u_char)' ', (char *)&tblptr->tbl_location); tblptr->tbl_attr_count = rescolCount + parameterCount; tblptr->tbl_width = resrowWidth; tblptr->tbl_date_modified.db_tab_high_time = created; tblptr->tbl_storage_type = DB_TPROC_STORE; /* Load cost parameters (if there). */ tblptr->tbl_record_count = (dbp->db_estRows) ? dbp->db_estRows : DBP_ROWEST; tblptr->tbl_page_count = (dbp->db_estCost) ? dbp->db_estCost : DBP_DIOEST; tblptr->tbl_pgsize = 2048; /* All the other DMT_TBL_ENTRY fields are being left 0 until ** something happens that suggests other values. */ /* Finally fill in the RDR_INFO structure. */ MEfill(sizeof(RDR_INFO), (u_char) 0, rdrinfop); rdrinfop->rdr_rel = tblptr; rdrinfop->rdr_attr = rescarray; rdrinfop->rdr_no_attr = tblptr->tbl_attr_count; rdrinfop->rdr_dbp = dbp; grvp->opv_relation = rdrinfop; BTset((i4)gvar, (char *)&global->ops_rangetab.opv_mrdf); /* indicate ** that RDF info is fixed */ grvp->opv_gmask |= OPV_TPROC; global->ops_gmask |= OPS_TPROCS; /* show query has table procs */ return (E_DB_OK); }
/*{ ** Name: opz_addatts - add joinop attributes to the array ** ** Description: ** This routine will add or find the appropriate joinop attribute ** to the joinop attributes array given the ** (range variable, range variable attribute number) pair. ** ** The exception to this rule occurs with function attributes which ** always results in a new joinop attribute being allocated. A ** function attribute uses "OPZ_FANUM" as the input attribute number. ** ** Inputs: ** subquery ptr to subquery being analyzed ** joinopvar index into joinop range table ** dmfattr dmf attribute number ** datatype ptr to ADT datatype ** ** Outputs: ** Returns: ** joinop attribute number ** Exceptions: ** none ** ** Side Effects: ** An entry may be allocated in the joinop attributes array ** (OPS_SUBQUERY->ops_attrs) ** ** History: ** 20-apr-86 (seputis) ** initial creation addatts ** 06-nov-89 (fred) ** Added support for non-histogrammable datatypes. This support ** entails providing a simple, coordinated replacement for this ** histogram. In our case, the datatype & length will be varchar, ** minimum & maximum being those for varchar, and adc_helem() ** replacement will be the histogram for "nohistos". ** ** This code is done in OPF as opposed to ADF because I think it ** desirable that OPF manage the histogram replacement. ADF will not ** know the appropriate values. Furthermore, it is more desirable to ** teach OPF to manage w/out histograms; however, that change is ** beyond the scope of this project. ** 26-dec-90 (seputis) ** init mask of booleans associated with attribute descriptor ** 18-jan-93 (rganski) ** Character Histogram Enhancements project: ** Initialize attr_ptr->opz_histogram.oph_dataval.db_length to 8 ** before call to adc_hg_dtln(), which has been changed; this gives ** old behavior (limit for char types was 8). This length may be ** changed later when RDF gets info from iistatistics. ** 24-may-93 (rganski) ** Character Histograms Enhancements project: ** Initialize attr_ptr->opz_histogram.oph_dataval.db_length to 0 ** before call to adc_hg_dtln(), which causes histogram value to be ** same length as attribute. This is necessary because otherwise the ** histogram value, which is used to determine selectivity of boolean ** factors, is truncated; this removes the benefits of having long ** histogram values. The histogram value length is adjusted in ** oph_catalog(), which reads the actual length from iistatistics (or ** truncates to 8, for old histograms). ** 6-dec-93 (ed) ** - bug 56139 - project union view before it is instantiated ** 09-oct-98 (matbe01) ** Added NO_OPTIM for NCR to eliminate runtime error that produces the ** message: E_OP0889 Eqc is not available at a CO node. ** 6-sep-04 (hayke02) ** Add OPZ_COLLATT attribute if OPS_COLLATION is on (resdom list, ** collation sequence). This change fixes problem INGSRV 2940, bug ** 112873. ** 8-nov-05 (hayke02) ** Add OPZ_VAREQVAR if OPS_VAREQVAR is on. Return if OPZ_VAREQVAR is ** not set and the attribute is found. This ensures that the fix for ** 110675 is limited to OPZ_VAREQVAR PST_BOP nodes. This change ** fixes bug 115420 problem INGSRV 3465. ** 15-aug-2007 (huazh01) ** ensure the datatype/length info of a created attribute matches ** the corresponding column type/length info on the user table. ** bug 117316. ** [@history_line@]... */ OPZ_IATTS opz_addatts( OPS_SUBQUERY *subquery, OPV_IVARS joinopvar, OPZ_DMFATTR dmfattr, DB_DATA_VALUE *datatype) { OPZ_IATTS attribute; /* used to save joinop attribute ** number if found by opz_findatt */ RDR_INFO *rel; /* FIXME - need to deal with unsigned compare problem here */ if ( (dmfattr != OPZ_FANUM) && (dmfattr != OPZ_SNUM) && (dmfattr != OPZ_CORRELATED) && (attribute = opz_findatt(subquery, joinopvar, dmfattr)) >= 0 && !(subquery->ops_attrs.opz_base->opz_attnums[attribute]->opz_mask & OPZ_VAREQVAR && subquery->ops_mask2 & OPS_COLLATION && (abs(datatype->db_datatype) == DB_CHA_TYPE || abs(datatype->db_datatype) == DB_VCH_TYPE || abs(datatype->db_datatype) == DB_CHR_TYPE || abs(datatype->db_datatype) == DB_TXT_TYPE)) ) return( attribute ); /* if this (joinopvar,dmfattr) pair ** exists and is not a function ** attribute, or subselect attribute ** then return */ { /* create new joinop attribute */ OPZ_IATTS nextattr; /* next available joinop attribute ** number */ OPS_STATE *global; /* ptr to global state variable */ global = subquery->ops_global; /* get ptr to global state variable */ if ( (nextattr = subquery->ops_attrs.opz_av++) >= OPZ_MAXATT) opx_error(E_OP0300_ATTRIBUTE_OVERFLOW); /* exit with error ** if no more room in attributes ** array */ { OPZ_ATTS *attr_ptr; /* ptr to newly created joinop ** attribute element */ OPV_VARS *var_ptr; /* ptr to respective joinop ** variable containing attribute */ var_ptr = subquery->ops_vars.opv_base->opv_rt[joinopvar]; /* allocate new joinop attribute structure and initialize */ subquery->ops_attrs.opz_base->opz_attnums[nextattr] = attr_ptr = (OPZ_ATTS *) opu_memory( global, (i4) sizeof(OPZ_ATTS)); MEfill(sizeof(*attr_ptr), (u_char)0, (PTR)attr_ptr); /* b117316: ** ** the fix to b109879 set PST_VAR node under the RESDOM to ** to nullable and increase the db_length by one, though ** the column corresponds to PST_VAR is defined as not null. ** Need to reset them to not null in order to prevent ** wrong db_type and db_length being used during query ** execution. e.g., wrong db_type and db_length could cause OPC ** to generate a set of ADF code which materialize tuples ** using incorrect offset and cause wrong result. ** */ rel = var_ptr->opv_grv->opv_relation; if (datatype->db_datatype < 0 && dmfattr > 0 && rel && rel->rdr_attr[dmfattr]->att_type * -1 == datatype->db_datatype && rel->rdr_attr[dmfattr]->att_width + 1 == datatype->db_length) { datatype->db_datatype = rel->rdr_attr[dmfattr]->att_type; datatype->db_length = rel->rdr_attr[dmfattr]->att_width; } attr_ptr->opz_varnm = joinopvar; /* index into local range table */ BTset( (i4)nextattr, (char *)&var_ptr->opv_attrmap); /* indicate ** that this joinop ** attribute belongs to this range ** variable */ attr_ptr->opz_gvar = var_ptr->opv_gvar; /* move global range ** variable number to attribute */ attr_ptr->opz_attnm.db_att_id = dmfattr;/* dmf attribute of ** range variable */ STRUCT_ASSIGN_MACRO((* datatype), attr_ptr->opz_dataval); attr_ptr->opz_equcls = OPE_NOEQCLS; /* this attribute has not been ** assigned an equivalence class yet */ attr_ptr->opz_func_att = OPZ_NOFUNCATT; /* this indicates that a ** function attribute is not ** associated with this joinop ** attribute element */ if ((dmfattr != OPZ_FANUM) && (dmfattr != OPZ_SNUM) && (dmfattr != OPZ_CORRELATED) && (attribute >= 0)) attr_ptr->opz_mask |= OPZ_COLLATT; if (subquery->ops_mask2 & OPS_VAREQVAR) attr_ptr->opz_mask |= OPZ_VAREQVAR; if ((var_ptr->opv_grv->opv_gmask & OPV_UVPROJECT) && (dmfattr >= 0)) { /* if union view exists in which a projection is possible ** (i.e. a UNION ALL view) then ** mark the attribute which are referenced in the union view*/ BTset((i4)dmfattr, (char *)var_ptr->opv_grv->opv_attrmap); } { /* initialize the histogram information associated with this ** attribute */ DB_STATUS hgstatus; /* ADT return status */ i4 dt_bits; hgstatus = adi_dtinfo(global->ops_adfcb, datatype->db_datatype, &dt_bits); if ((hgstatus == E_AD0000_OK) && (dt_bits & AD_NOHISTOGRAM)) { attr_ptr->opz_histogram.oph_dataval.db_datatype = OPH_NH_TYPE; attr_ptr->opz_histogram.oph_dataval.db_prec = OPH_NH_PREC; attr_ptr->opz_histogram.oph_dataval.db_length = OPH_NH_LENGTH; } else { attr_ptr->opz_histogram.oph_dataval.db_length = 0; hgstatus = adc_hg_dtln(global->ops_adfcb, datatype, &attr_ptr->opz_histogram.oph_dataval ); } # ifdef E_OP0780_ADF_HISTOGRAM if ((hgstatus != E_AD0000_OK) || (attr_ptr->opz_histogram.oph_dataval.db_datatype < 0) /* do not expect a nullable ** histogram datatype */ ) opx_verror( hgstatus, E_OP0780_ADF_HISTOGRAM, global->ops_adfcb->adf_errcb.ad_errcode); /* ** abort if unexpected error occurs */ # endif attr_ptr->opz_histogram.oph_dataval.db_data = NULL; /* init the ** data value ptr */ attr_ptr->opz_histogram.oph_numcells = OPH_NOCELLS; /* histogram ** has not been fetched so no cells ** exist at this point */ attr_ptr->opz_histogram.oph_histmm = NULL; /* no histogram ** exists at this point */ attr_ptr->opz_histogram.oph_mindomain = NULL; /* no minimum ** value for this histogram yet */ attr_ptr->opz_histogram.oph_maxdomain = NULL; /* no maximum ** value for this histogram yet */ } if (dmfattr == DB_IMTID) { /* implicit TID found so an equivalence class needs to be ** created ... so we know the equivalence class of the ** implicit TID for this (since the implicit TID is referenced ** by an index or explicitly in the qualification) */ var_ptr->opv_primary.opv_tid = ope_neweqcls( subquery, nextattr ); } } return( nextattr ); /* return joinop attribute which has ** been assigned */ } }