void itof(register sym_t *p) { #ifdef xOTR3 if (tTf(87, 2)) { printf("itof: "); prsym(p); } #endif if (p->len == 4) p->value.sym_data.f8type = p->value.sym_data.i4type; else if (p->len == 2) p->value.sym_data.f8type = p->value.sym_data.i2type; else p->value.sym_data.f8type = p->value.sym_data.i1type; p->type = FLOAT_CONST; p->len= 8; #ifdef xOTR3 if (tTf(87, 2)) { printf("itof rets: "); prsym(p); } #endif }
int get(desc_t *d, tid_t *tid, tid_t *limtid, void *tuple, int getnxt) { register int i; long pageid, lpageid; #ifdef xATR1 if (tTf(23, 0)) { printf("get: %.14s,", d->d_r.r_id); dumptid(tid); printf("get: lim"); dumptid(limtid); } #endif if (get_page(d, tid)) { return (-1); } if (getnxt) { pluck_page(limtid, &lpageid); do { while (((++(tid->line_id)) & I1MASK) >= Acc_head->am_nextline) { tid->line_id = -1; pageid = Acc_head->am_overflowpg; stuff_page(tid, &pageid); if (pageid == 0) { pageid = Acc_head->am_mainpg; stuff_page(tid, &pageid); if (pageid == 0 || pageid == lpageid + 1) return (1); } if ((i = resetacc(Acc_head)) != 0) return (i); if ((i = get_page(d, tid)) != 0) return (i); } } while (!Acc_head->am_linev[-(tid->line_id & I1MASK)]); } else { if ((i = invalid(tid)) != 0) return (i); } get_tuple(d, tid, tuple); #ifdef xATR2 if (tTf(23, 1)) { printf("get: "); printup(d, tuple); } #endif return (0); }
int display(int pc, paramv_t *pv) { register int ac; register paramv_t *av; int err; char err_array[PV_MAXPC]; int mode; #ifdef xZTR1 if (tTf(50, -1)) { printf("display: "); prvect(pc, pv); } #endif err = 0; if (pc % 2 != 0) syserr("display: bad param count %d", pc); opencatalog("tree", OR_READ); for (ac = 0, av = pv; ac < pc; av++, ac++) { mode = atoi(av->pv_val.pv_str); av++; err_array[ac++] = 0; err_array[ac] = disp(av->pv_val.pv_str, mode); } for (ac = 0, av = pv; ac < pc; av++, ac++) { if (err_array[ac]) err = error(DISPERRBASE + err_array[ac], (av->pv_val).pv_str, 0); } return (err); }
/* ** Check the range table to see if any ** relations changed since the last call ** to newquery. If so, they were caused ** by reformat. Restore back the orig relation ** Reopen it if reopen == TRUE. */ void endquery(int *locrang, int reopen) { register struct rang_tab *rp; register int *ip, i; int old; bool dstr_flag; rp = De.de_rangev; ip = locrang; dstr_flag = FALSE; initp(); for (i = 0; i < MAX_RANGES; i++) { if (rp->relnum != *ip) { #ifdef xDTR1 if (tTf(63, -1)) printf("reformat or reduct changed var %d (%d,%d)\n", i, *ip, rp->relnum); #endif old = new_range(i, *ip); dstr_flag |= dstr_mark(old); if (reopen) openr1(i); } ip++; rp++; } if (dstr_flag) call_dbu(mdDESTROY, FALSE); else resetp(); }
/* ** PR_INTEGRITY -- print out integrity constraints on a relation ** ** Finds all integrity tuples for this unique relation, and ** calls pr_int() to print a query from them. ** ** Parameters: ** relid -- rel name ** relowner -- 2 byte owner id ** ** Returns: ** none ** ** Side Effects: ** file activity, query printing ** ** Trace Flags: ** 33, 9 */ void pr_integrity(char *relid, char *relowner) { extern desc_t Intdes; tid_t hitid, lotid; struct integrity key, tuple; register int i; #ifdef xZTR1 if (tTf(50, 9)) printf("pr_integrity(relid =%s, relowner=%s)\n", relid, relowner); #endif printf("Integrity constraints on %s are:\n\n", relid); opencatalog("integrities", OR_READ); /* get integrities tuples for relid, relowner */ clearkeys(&Intdes); ingres_setkey(&Intdes, &key, relid, INTRELID); ingres_setkey(&Intdes, &key, relowner, INTRELOWNER); if ((i = find(&Intdes, EXACTKEY, &lotid, &hitid, &key)) != 0) syserr("pr_integrity: find %d", i); for (;;) { if ((i = get(&Intdes, &lotid, &hitid, &tuple, TRUE)) != 0) break; if (kcompare(&Intdes, &tuple, &key) == 0) pr_int(&tuple, relid); } if (i != 1) syserr("pr_integrity: get %d", i); }
branch() { register char c; register int i; extern char getch(); # ifdef xMTR2 if (tTf(16, -1)) printf(">>branch: "); # endif /* see if conditional */ while ((c = getch()) > 0) if (c != ' ' && c != '\t') break; if (c == '?') { /* got a conditional; evaluate it */ Oneline = TRUE; macinit(&getch, 0, 0); i = expr(); if (i <= 0) { /* no branch */ # ifdef xMTR2 if (tTf(16, 0)) printf("no branch\n"); # endif getfilename(); return; } } else { Peekch = c; } /* get the target label */ if (branchto(getfilename()) == 0) if (branchto(macro("{default}")) == 0) { Peekch = -1; printf("Cannot branch\n"); } return; }
/* ** EXEC_SQ ** ** Execute the subqueries in sqlist. Associated with ** each sub-query is a relation number stored in sqrange. ** If the sub-query has a non-null target list, the range ** table is updated to reflect the new range of the relation. ** ** If any sub-query is false, all subsequent ones are ignored ** by ovqp and exec_sq returns the var number of the false subquery. ** ** As a side effect, "disj" is incremented for each disjoint sub-query ** ** Trace Flags: ** 35 */ int exec_sq(qtree_t **sqlist, int *sqrange, int *disj) { register qtree_t *sq; register int i, qualfound; #ifdef xDTR1 if (tTf(35, 0)) printf("EXEC_SQ--\n"); #endif *disj = 0; for (i = 0; i < MAX_RANGES; i++) { if ((sq = sqlist[i]) != 0) { #ifdef xDTR1 if (tTf(35, 1)) printf("sq[%d]=%p\n", i, sq); #endif qualfound = execsq1(sq, i, sqrange[i]); #ifdef xDTR1 if (tTf(35, 2)) printf("qualfound=%d\n", qualfound); #endif if (!qualfound) { return(i); } if (sq->left->sym.type != TREE) { /* ** Update the range table and open ** the relation's restricted replacement. */ new_range(i, sqrange[i]); openr1(i); } else { (*disj)++; } } } return (-1); }
void i4toi2(sym_t *pp) { register sym_t *p; #ifdef xOTR3 if (tTf(87, 1)) { printf("i4toi2: "); prsym(pp); } #endif p = pp; *(i2type *)&p->value = *(i4type *)&p->value; p->len = 2; #ifdef xOTR3 if (tTf(87, 1)) { printf("i4toi2 rets: "); prsym(p); } #endif }
void i2toi4(sym_t *pp) { register sym_t *p; #ifdef xOTR3 if (tTf(87, 0)) { printf("i2toi4: "); prsym(pp); } #endif p = pp; *(i4type *)&p->value = *(i2type *)&p->value; p->len = 4; #ifdef xOTR3 if (tTf(87, 0)) { printf("i2toi4 rets: "); prsym(p); } #endif }
void ftoi4(register sym_t *p) { #ifdef xOTR3 if (tTf(87, 4)) { printf("ftoi4: "); prsym(p); } #endif if (p->len == 4) p->value.sym_data.i4type = p->value.sym_data.f4type; else p->value.sym_data.i4type = p->value.sym_data.f8type; p->type = INT_CONST; p->len = 4; #ifdef xOTR3 if (tTf(87, 4)) { printf("ftoi4 rets: "); prsym(p); } #endif }
/* ** UNDO_SQ ** ** Undo the effects of one variable detachment on ** the range table. The two parameters "limit" and ** "maxlimit" describe how far down the list of ** subqueries were processed. Maxlimit represents ** the furthest every attained and limit represents ** the last variable processed the last time. ** ** Trace Flags: ** 36 */ void undo_sq(qtree_t **sqlist, int *locrang, int *sqrange, int limit, int maxlimit, int reopen) { register qtree_t *sq; register int i, lim; bool dstr_flag; dstr_flag = 0; #ifdef xDTR1 if (tTf(36, 0)) printf("UNDO_SQ--\n"); #endif initp(); /* setup parm vector for destroys */ lim = limit == -1 ? MAX_RANGES : limit; if (maxlimit == -1) maxlimit = MAX_RANGES; for (i = 0; i < MAX_RANGES; i++) if ((sq = sqlist[i]) != 0) { if (sq->left->sym.type != TREE) { if (i < lim) { /* The query was run. Close the temp rel */ closer1(i); } /* mark the temporary to be destroyed */ dstr_mark(sqrange[i]); dstr_flag = TRUE; /* reopen the original relation. If maxlimit ** never reached the variable "i" then the ** original relation was never closed and thus ** doesn't need to be reopened. */ rstrang(locrang, i); if (reopen && i < maxlimit) openr1(i); } } /* Only call destroy if there's something to destroy */ if (dstr_flag) call_dbu(mdDESTROY, FALSE); else resetp(); }
/* ** MERGEVAR -- merge variable numbers to link terms ** ** One specified variable gets mapped into another, effectively ** merging those two variables. This is used for protection ** and integrity, since the constraint read from the tree ** must coincide with one of the variables in the query tree. ** ** Parameters: ** va -- the variable which will dissappear. ** vb -- the variable which 'va' gets mapped into. ** root -- the root of the tree to map. ** ** Returns: ** none ** ** Side Effects: ** The tree pointed at by 'root' gets VAR and RESDOM ** nodes mapped. ** Range table entry for 'va' is deallocated. ** The 'Qt.qt_remap' vector gets reset and left in an ** undefined state. ** ** Trace Flags: ** 72 */ void mergevar(register int a, register int b, qtree_t *root) { register int i; #ifdef xQTR1 if (tTf(72, 0)) { printf("\nmergevar(%d->%d)", a, b); treepr(root); } #endif /* ** Insure that 'a' and 'b' are consistant, that is, ** that they both are in range, are defined, and range over ** the same relation. */ if (a < 0 || b < 0 || a >= MAX_VARS + 1 || b >= MAX_VARS + 1) syserr("mergevar: range %d %d", a, b); if (Qt.qt_rangev[a].rngvdesc == NULL || Qt.qt_rangev[b].rngvdesc == NULL) syserr("mergevar: undef %d %d", a, b); if (!bequal(Qt.qt_rangev[a].rngvdesc->d_r.r_id, Qt.qt_rangev[b].rngvdesc->d_r.r_id, MAX_NAME_SIZE) || !bequal(Qt.qt_rangev[a].rngvdesc->d_r.r_owner, Qt.qt_rangev[b].rngvdesc->d_r.r_owner, 2)) { syserr("mergevar: incon %.14s %.14s", Qt.qt_rangev[a].rngvdesc->d_r.r_id, Qt.qt_rangev[b].rngvdesc->d_r.r_id); } /* ** To do the actual mapping, we will set up 'Qt.qt_remap' and ** call 'mapvars()'. This is because I am too lazy to ** do it myself. */ for (i = 0; i < MAX_RANGES; i++) Qt.qt_remap[i] = i; Qt.qt_remap[a] = b; mapvars(root); /* delete a from the range table */ declare(a, NULL); }
/* ** PR_DEF -- Print "define view" query of a view ** ** Parameters: ** relation -- relation in question ** owner -- relowner ** ** Returns: ** none ** ** Side Effects: ** reads a tree, clears range table ** ** Trace Flags: ** 33, 9 */ void pr_def(char *relation, char *owner) { register qtree_t *t; #ifdef xZTR1 if (tTf(50, 9)) printf("pr_def(relation=\"%s\", owner=%s)\n", relation, owner); #endif printf("View %s defined:\n\n", relation); clrrange(); /* Treeid == 0 because views have only one definition */ t = gettree(relation, owner, mdVIEW, 0,FALSE); pr_range(); printf("define view "); pr_tree(t); }
/* ** DISP -- display integrity, permit, or define query on a relation ** ** Finds a relation owned by the user or the DBA and passes ** the name and owner to the appropritae routine depending on ** mode. ** ** Parameters: ** relation -- relation on which query is to be printed ** mode -- the print mode: ** 4 -- view ** 5 -- permit ** 6 -- integrity ** ** Returns: ** 0 -- success ** 1 -- no such relation, or none seeable by the user. ** 3 -- VIEW mode and relation not a view ** 4 -- PERMIT and no permissions on relation ** 5 -- INTEGRITY mode and no integrity constraints ** ** Trace Flags: ** 33, 8 */ int disp(char *relation, int mode) { desc_t d; register int i; extern char *Resrel; #ifdef xZTR1 if (tTf(50, 8)) printf("disp: relation %s\n", relation); #endif Resrel = relation; i = openr(&d, OR_RELTID, relation); if (i > 0) return (1); else if (i < 0) syserr("disp: openr(%s) ret %d", relation, i); switch (mode) { case 4: /* View query */ if (d.d_r.r_status & S_VIEW) pr_def(relation, d.d_r.r_owner); else return (3); break; case 5: if (pr_prot(relation, (relation_t *) &d)) return (4); break; case 6: if (d.d_r.r_status & S_INTEG) pr_integrity(relation, d.d_r.r_owner); else return (5); break; default: syserr("disp: mode == %d", mode); } return (0); }
/* ** CM_CLEANUP -- cleanup after interrupt or error. ** ** This routine does things like call the interrupt cleanup ** function, reset the input, etc. ** ** Parameters: ** typ -- the type of cleanup: ** 1 -- fatal error (from error [error.c]). ** 2 -- keyboard interrupt. ** ** Returns: ** never (uses non-local jump to ctlmod/main.c). ** ** Side Effects: ** Proc_name & Cm.cm_input are reset. ** ** Trace Flags: ** 0 */ void cm_cleanup(int typ) { register int i; register func_t *f; extern jmp_buf CmReset; register ctx_t *ctx; #ifdef xCTR2 if (tTf(0, 13)) printf("cm_cleanup: %d\n", typ); #endif /* ** Call all interrupt cleanup functions for active ** modules. */ for (i = 0; i < NumFunc; i++) { f = FuncVect[i]; if (f->fn_active > 0) { setprocname(Ctx.ctx_name = f->fn_name); (*f->fn_cleanup)(typ); } } /* clean up memory */ for (ctx = &Ctx; ctx != NULL; ctx = ctx->ctx_link) { if (ctx->ctx_qt != NULL) { xfree(ctx->ctx_qt); } if (ctx->ctx_glob != NULL) { bmove(ctx->ctx_glob, ctx->ctx_fn->fn_gptr, ctx->ctx_fn->fn_gsize); xfree(ctx->ctx_glob); } } /* return to top of loop */ longjmp(CmReset, typ); }
/* ** PB_PUT -- buffered put on pipe ** ** This routine puts the named data out onto the pipe ** determined by ppb->pb_proc. ** ** Parameters: ** dp -- a pointer to the data to write. ** len -- the length of the data to write. ** ppb -- a pointer to the pipe block. ** ** Returns: ** none ** ** Side Effects: ** none ** ** Trace Flags: ** 18.8 - 18.15 */ void pb_put(register char *dp, register int len, register pb_t *ppb) { register int i; #ifdef xCTR2 if (tTf(18, 9)) lprintf("pb_put: len %d\n", len); #endif /* ** Top loop. ** Loop until we have run out of things to write. */ while (len > 0) { /* compute the length to move */ i = min(ppb->pb_nleft, len); #ifdef xCM_DEBUG if (i <= 0) syserr("pb_put: zero"); #endif /* move data into buffer and adjust ptrs & counts */ bmove(dp, ppb->pb_xptr, i); dp += i; len -= i; ppb->pb_xptr += i; ppb->pb_nleft -= i; ppb->pb_nused += i; /* flush block if full */ if (ppb->pb_nleft <= 0) pb_write(ppb); } }
int copy(int pc, paramv_t *pv) { extern char *Usercode; extern int Noupdt; register int i, pid; register char *cp; int stat; int op; #ifdef xZTR1 if (tTf(30,1)) { printf("entered copy\n"); prvect(pc, pv); } #endif Duptuple = 0; Truncount = 0; Tupcount = 0; Baddoms = 0; Relname = pv[0].pv_val.pv_str; Into = (pv[pc-2].pv_val.pv_str[0] == 'i'); Filename = pv[pc-1].pv_val.pv_str; /* relation must exist and not be a system relation */ /* in addition a copy "from" can't be done if the user */ /* doesn't own the relation */ /* and furthermore it can't have an index */ i = 0; /* assume all is well */ if ((op = openr(&Des, OR_WRITE, Relname)) != 0) { if (op == AMOPNVIEW_ERR) i = NOCPVIEW; else { if (op < 0) syserr("COPY: openr 1 (%.14s) %d", Relname, op); else /* non-existant relation */ i = NOEXIST; } } else { if (Into) { if ((Des.d_r.r_status & S_PROTALL) && (Des.d_r.r_status & S_PROTRET) && !bequal(Usercode, Des.d_r.r_owner, USERCODE_SIZE)) i = RELPROTECT; } else { /* extra checking if this is a copy "from" */ /* must be owned by the user */ if (!bequal(Usercode, Des.d_r.r_owner, USERCODE_SIZE)) i = NOTOWNER; else /* must be updateable */ if ((Des.d_r.r_status & S_NOUPDT) && Noupdt) i = NOUPDT; else /* must not be indexed */ if (Des.d_r.r_indexed > 0) i = DESTINDEX; } } if (i) { closer(&Des); return (error(i, Relname, 0)); /* relation doesn't exist for this user */ } /* check that file name begins with a "/" */ cp = Filename; while (*cp == ' ') cp++; if (*cp != '/') { closer(&Des); return (error(FULLPATH, Filename, 0)); } /* fill map structures with transfer information */ if ((i = mapfill(&pv[1])) != 0) { closer(&Des); return (i); /* error in user semantics */ } /* fork a child process which will run as the real user */ /* that child will complete the copy and exit */ if (pipe(Piped)) syserr("copy:can't make pipe"); if ((pid = fork()) < 0) syserr("copy:can't fork"); if (pid) { /* the ingres parent */ close(Piped[1]); ruboff(0); /* interrupts off */ stat = fullwait(pid, "copy"); if (read(Piped[0], &Des.d_addc, 4) != 4) syserr("copy:can't read pipe"); close(Piped[0]); closer(&Des); /* close the rel */ rubon(); /* if stat is != 0 then add on 5800 for error */ if (stat) stat += 5800; return (stat); /* done */ } /* the child. change to run as the real user */ if (signal(SIGINT, SIG_IGN) != SIG_IGN) { signal(SIGINT, copydone); /* clean up on rubout */ } setuid(getuid()); setgid(getgid()); if (Into) { /* from relation into file */ if ((File_iop = fopen(Filename, "w")) == NULL) /* create file for user */ i = nferror(NOFILECRT, Filename, 0); /* cant create file */ else { if (Lockrel) /* set a shared lock on relation*/ setrll(A_SLP, &Des.d_tid, M_SHARE); i = rel_file(); } } else { /* from UNIX file into relation */ if ((File_iop = fopen(Filename, "r")) == NULL) i = nferror(NOFILEOPN, Filename, 0); /* cant open user file */ else { if (Lockrel) /* set an exclusive lock on relat*/ setrll(A_SLP, &Des.d_tid, M_EXCL); i = file_rel(); if (Duptuple) nferror(DUPTUPS, locv(Duptuple), 0); /* warning only */ if (Baddoms) nferror(BADDOMS, locv(Baddoms), 0); /* warning only */ } } copydone(i); return(0); }
qryproc() { register struct querytree *root, *q; register int i; int mode, result_num, retr_uniq; struct querytree *trbuild(); extern long Accuread, Accuwrite, Accusread; extern int derror(); extern struct querytree *readqry(); # ifdef xDTM if (tTf(76, 1)) timtrace(23, 0); # endif # ifdef xDTR1 if (tTf(50, 0)) { Accuread = 0; Accusread = 0; Accuwrite = 0; } # endif /* initialize query buffer */ initbuf(Qbuf, QBUFSIZ, QBUFFULL, &derror); /* init various variables in decomp for start of this query */ startdecomp(); /* Read in query, range table and mode */ root = readqry(); mode = Qmode; /* Initialize relation descriptors */ initdesc(mode); /* re-build the tree */ root = trbuild(root); if (root == NULL) derror(STACKFULL); /* locate pointers to QLEND and TREE nodes */ for (q = root->right; q->sym.type != QLEND; q = q->right); Qle = q; for (q = root->left; q->sym.type != TREE; q = q->left); Tr = q; /* map the complete tree */ mapvar(root, 0); /* set logical locks */ if (Lockrel) lockit(root, Resultvar); /* If there is no result variable then this must be a retrieve to the terminal */ Qry_mode = Resultvar < 0 ? mdRETTERM : mode; /* if the mode is retrieve_unique, then make a result rel */ retr_uniq = mode == mdRET_UNI; if (retr_uniq) { mk_unique(root); mode = mdRETR; } /* get id of result relation */ if (Resultvar < 0) result_num = NORESULT; else result_num = Rangev[Resultvar].relnum; /* evaluate aggregates in query */ aggregate(root); /* decompose and process aggregate free query */ decomp(root, mode, result_num); /* If this is a retrieve unique, then retrieve results */ if (retr_uniq) pr_unique(root, Resultvar); if (mode != mdRETR) i = ACK; else i = NOACK; i = endovqp(i); /* call update processor if batch mode */ if (i == UPDATE) { initp(); call_dbu(mdUPDATE, -1); } /* ** send eop back to parser to indicate completion ** if UPDATE then return block comes from dbu else ** return block comes from decomp */ writeback(i == UPDATE ? -1 : 1); # ifdef xDTM if(tTf(76, 1)) timtrace(24,0); # endif # ifdef xDTR1 if (tTf(50, 1)) { printf("DECOMP read %s pages,", locv(Accuread)); printf("%s catalog pages,", locv(Accusread)); printf("wrote %s pages\n", locv(Accuwrite)); } # endif /* clean decomp */ reinit(); /* return */ }
/* ** STRATEGY ** ** Attempts to limit access scan to less than the entire De.ov_source ** relation by finding a key which can be used for associative ** access to the De.ov_source reln or an index thereon. The key is ** constructed from domain-value specifications found in the ** clauses of the qualification list using sub-routine findsimp ** in findsimp.c and other subroutines in file key.c */ int strategy(void) { register int i, allexact; acc_param_t sourceparm, indexparm; index_t itup, rtup; key_t lowikey[MAX_2ND_KEYS+1], highikey[MAX_2ND_KEYS+1]; key_t lowbkey[MAX_2ND_KEYS+1], highbkey[MAX_2ND_KEYS+1]; register desc_t *d; extern desc_t Inddes; char *tp; long l_lid[MAXLID], h_lid[MAXLID]; int keytype; long page, l, t; int lidsize; locator_t tidloc; keytype = allexact = 0; #ifdef xOTR1 if (tTf(70, 0)) printf("STRATEGY\tSource=%.12s\tNewq = %d\n", De.ov_source ? De.ov_source->d_r.r_id : "(none)", De.de_newq); #endif while (De.de_newq) /* if De.de_newq=TRUE then compute a new strategy */ /* NOTE: This while loop is executed only once */ { De.ov_scanr = De.ov_source; if (!De.ov_scanr) return (1); /* return immediately if there is no source relation */ De.ov_fmode = NOKEY; /* assume a find mode with no key */ if (!De.ov_qlist) break; /* if no qualification then you must scan entire rel */ /* ** Here we check for the special condition ** of a where clause consisting only of a tid. */ if (tid_only_test()) return(1); /* copy structure of source relation into sourceparm */ paramd(De.ov_source, &sourceparm); /* if source is unkeyed and has no sec index then give up */ if (sourceparm.mode == NOKEY && De.ov_source->d_r.r_indexed <= 0 && !De.ov_source->d_r.r_dim) break; /* find all simple clauses if any */ if (!findsimps()) break; /* break if there are no simple clauses */ /* Four steps are now performed to try and find a key. ** First if the relation is hashed then an exact key is search for ** ** Second if there are secondary indices, then a search is made ** for an exact key. If that fails then a check is made for ** a range key. The result of the rangekey check is saved. ** ** A step to check for possible use of Btrees is made here, ** although in actuality, an exact btreekey search is used ** after an exact range key search but before a range key search. ** A BTree range search is used only as a last alternative ** to a no key search. ** ** Third if the relation is an ISAM a check is made for ** an exact key or a range key. ** ** Fourth if there is a secondary index, then if step two ** found a key, that key is used. ** ** Lastly, give up and scan the entire relation */ /* step one. Try to find exact key on primary */ if (exactkey(&sourceparm, De.ov_lkey_struct)) { De.ov_fmode = EXACTKEY; break; } /* step two. If there is an index, try to find an exactkey on one of them */ if (De.ov_source->d_r.r_indexed > 0) { opencatalog("indices", OR_READ); ingres_setkey(&Inddes, &itup, De.ov_source->d_r.r_id, IRELIDP); ingres_setkey(&Inddes, &itup, De.ov_source->d_r.r_owner, IOWNERP); if ((i = find(&Inddes, EXACTKEY, &De.ov_lotid, &De.ov_hitid, (char *)&itup)) != 0) syserr("strategy:find indices %d", i); while (!(i = get(&Inddes, &De.ov_lotid, &De.ov_hitid, (char *)&itup, NXTTUP))) { #ifdef xOTR1 if (tTf(70, 3)) printup(&Inddes, (char *)&itup); #endif if (!bequal(itup.i_relname, De.ov_source->d_r.r_id, MAX_NAME_SIZE) || !bequal(itup.i_owner, De.ov_source->d_r.r_owner, 2)) continue; parami(&itup, &indexparm); if (exactkey(&indexparm, De.ov_lkey_struct)) { De.ov_fmode = EXACTKEY; d = openindex(itup.i_index); /* temp check for 6.0 index */ if ((int) d->d_r.r_indexed == -1) ov_err(BADSECINDX); De.ov_scanr = d; break; } if (De.ov_fmode == LRANGEKEY) continue; /* a range key on a s.i. has already been found */ if ((allexact = rangekey(&indexparm, lowikey, highikey)) != 0) { bmove((char *)&itup, (char *)&rtup, sizeof(itup)); /* save tuple */ De.ov_fmode = LRANGEKEY; } } if (i < 0) syserr("stragery:bad get from index-rel %d", i); /* If an exactkey on a secondary index was found, look no more. */ if (De.ov_fmode == EXACTKEY) break; } /* attempt to use Btree in aiding search */ if ((i = btreekey(lowbkey, highbkey)) != 0) { if (i > 0) De.ov_fmode = BTREEKEY; else if (De.ov_fmode != LRANGEKEY) { /* use range key search over btree range search */ keytype = i; De.ov_fmode = BTREERANGE; } } /* step three. Look for a range key on primary */ if ((i = rangekey(&sourceparm, De.ov_lkey_struct, De.ov_hkey_struct)) != 0) { if (i < 0) De.ov_fmode = EXACTKEY; else if (De.ov_fmode == BTREEKEY) { /* use exact btree search over range search */ bmove((char *) lowbkey, (char *) De.ov_lkey_struct, sizeof(lowbkey)); bmove((char *) highbkey, (char *) De.ov_hkey_struct, sizeof(highbkey)); } else De.ov_fmode = LRANGEKEY; break; } if (De.ov_fmode == BTREEKEY) { bmove((char *) lowbkey, (char *) De.ov_lkey_struct, sizeof(lowbkey)); bmove((char *) highbkey, (char *) De.ov_hkey_struct, sizeof(highbkey)); break; } /* last step. If a secondary index range key was found, use it */ if (De.ov_fmode == LRANGEKEY) { if (allexact < 0) De.ov_fmode = EXACTKEY; d = openindex(rtup.i_index); /* temp check for 6.0 index */ if ((int) d->d_r.r_indexed == -1) ov_err(BADSECINDX); De.ov_scanr = d; bmove((char *)lowikey, (char *)De.ov_lkey_struct, sizeof(lowikey)); bmove((char *)highikey, (char *)De.ov_hkey_struct, sizeof(highikey)); break; } /* nothing will work. give up! */ break; } /* check for De.de_newq = FALSE and no source relation */ if (!De.ov_scanr) return (1); /* ** At this point the strategy is determined. ** ** If De.ov_fmode is EXACTKEY then De.ov_lkey_struct contains ** the pointers to the keys. ** ** If De.ov_fmode is LRANGEKEY then De.ov_lkey_struct contains ** the pointers to the low keys and De.ov_hkey_struct ** contains pointers to the high keys. ** ** If De.ov_fmode is BTREEKEY then De.ov_lkey_struct contains ** pointers to the key lid. ** ** If De.ov_fmode is BTREERANGE then lowbkey contains pointers ** to the low key lid and highbkey contains pointers to the ** high key lid. ** ** If De.ov_fmode is NOKEY, then a full scan will be performed */ #ifdef xOTR1 if (tTf(70, -1)) printf("De.ov_fmode= %d\n",De.ov_fmode); #endif if (De.ov_fmode == BTREERANGE) { /* requires special type of search to limit tid scan */ for (i = 0; i < De.ov_scanr->d_r.r_dim; ++i) { l_lid[i] = 0; h_lid[i] = 0; } lidsize = LIDSIZE * De.ov_scanr->d_r.r_dim; /* get low lids */ if (keytype == -1 || keytype == -3) { tp = De.ov_keyl + De.ov_scanr->d_r.r_width - lidsize; bmove(l_lid, tp, lidsize); setallkey(lowbkey, De.ov_keyl); bmove(tp, l_lid, lidsize); } /* get high lids */ if (keytype == -2 || keytype == -3) { tp = De.ov_keyh + De.ov_scanr->d_r.r_width - lidsize; bmove(h_lid, tp, lidsize); setallkey(highbkey, De.ov_keyh); bmove(tp, h_lid, lidsize); } setglobalint(BTREE_FD_NAME, De.ov_scanr->d_btreefd); /* scan through lids to fill in unprovided lids and to check ** for lids that are too big */ page = RT; for (i = 0; i < De.ov_scanr->d_r.r_dim; ++i) { if (l_lid[i] <= 0) l_lid[i] = 1; l = last_lid(page) - 1; if (h_lid[i] < 0) return(0); if (!h_lid[i] || h_lid[i] > l) h_lid[i] = l; if ((t = get_tid(page, h_lid[i], &tidloc)) < 0) syserr("bad gettid in strategy, lid = %ld\n", h_lid[i]); page = t; } /* check whether lo > hi */ for (i = 0; i < De.ov_scanr->d_r.r_dim; ++i) if (l_lid[i] < h_lid[i]) break; else if (l_lid[i] > h_lid[i]) return(0); #ifdef xOTR1 if (tTf(70,0)) for (i = 0 ; i < De.ov_scanr->d_r.r_dim; ++i) printf("hi = %ld, lo = %ld\n", h_lid[i], l_lid[i]); #endif /* find the smallest and largest possible tids of the lids ** within the provided range */ btreerange(De.ov_scanr, l_lid, h_lid, &De.ov_lotid, &De.ov_hitid); } else { /* set up the key tuples */ if (De.ov_fmode != NOKEY) { if (setallkey(De.ov_lkey_struct, De.ov_keyl)) return (0); /* query false. There is a simple ** clause which can never be satisfied. ** These simple clauses can be choosey! */ } if ((i = find(De.ov_scanr, De.ov_fmode, &De.ov_lotid, &De.ov_hitid, De.ov_keyl)) != 0) syserr("strategy:find1 %.12s, %d", De.ov_scanr->d_r.r_id, i); if (De.ov_fmode == LRANGEKEY) { setallkey(De.ov_hkey_struct, De.ov_keyh); if ((i = find(De.ov_scanr, HRANGEKEY, &De.ov_lotid, &De.ov_hitid, De.ov_keyh)) != 0) syserr("strategy:find2 %.12s, %d", De.ov_scanr->d_r.r_id, i); } } #ifdef xOTR1 if (tTf(70, 1)) { printf("Lo"); dumptid(&De.ov_lotid); printf("Hi"); dumptid(&De.ov_hitid); } #endif return (1); }
/*{ ** Name: opn_ukey - useable key - can inner node be probed ** ** Description: ** ** Returns TRUE if there are enough attributes ** to use the key of the relation. ** ** The jeqc must be the first element in the ordering that is not ** satisfied by a boolfact. This is because all in order for this ** routine to return true, keys 0..N were present in the join node. ** In opn_sjeqc, we will select the join eqc after reviewing all ** possibilities. One of the joined eqc's will be the first in the ** order list. If we only return true for this one, it will be joined. ** This only matters in the BTREE case. The prnode, in this case is ** also sorted on the first equiv class. ** If we picked an arbitrary eqc as keyed, we may do a needless sort. ** ** Inputs: ** subquery ptr to subquery being analyzed ** oeqcmp available equivalence class map of ** outer node ** jeqc primary attribute's eqc of key ** keyedvar joinop range variable number of ** possibly keyed relation ** primkey TRUE - if jeqc must be first joined ** element of orderlist ** ** Outputs: ** Returns: ** TRUE - if keyed access can be used for join ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 31-may-86 (seputis) ** initial creation ** 10-jun-96 (inkdo01) ** Support for Rtree inners of Kjoins. [@history_line@]... */ bool opn_ukey( OPS_SUBQUERY *subquery, OPE_BMEQCLS *oeqcmp, OPO_ISORT jeqc, OPV_IVARS keyedvar, bool primkey) { OPO_STORAGE storage; /* storage structure of relation */ OPV_VARS *varp; /* ptr to range variable element to ** be checked */ i4 ordercount; /* number of attributes that the ** relation is ordered on */ i4 orderindex; /* index into the OPB_MBF structure ** of the range variable element */ OPZ_AT *abase; /* ptr to base of array of ptrs to ** joinop attribute elements */ bool ret_val; /* TRUE is we can do keyed lookup */ /* Relation must be disk resident */ if (keyedvar < 0) return (FALSE); ret_val = FALSE; varp = subquery->ops_vars.opv_base->opv_rt[keyedvar]; /* get ptr to range ** variable element */ storage = varp->opv_tcop->opo_storage; /* get storage structure ** of relation */ abase = subquery->ops_attrs.opz_base; /* ptr to base of array of ptrs to ** joinop attribute elements */ #if 0 /* FIXME - why is this check here */ if ((storage) < 0) storage = -storage; #endif # ifdef xNTR1 if (tTf (1, 0)) { TRdisplay("Checking for possible keyed lookup into %s.\n", Jn.Range[keyedvar]->xrelid); TRdisplay("We %s looking for primary join key eqc %d.\n", (primkey ? "are" : "are not"), jeqc); TRdisplay("The joinop order eqcs are:"); for (i = 0; (att = order[i]) > -1; i++) TRdisplay("%d ", (i4) Jn.Attnums[att]->equcls); TRdisplay("\n"); uflush(); } # endif /* Each attribute in the ordering must be available from the outer ** or from the boolfacts */ ordercount = varp->opv_mbf.opb_count; /* number of attributes that the ** relation is ordered on */ for (orderindex = 0; orderindex < ordercount; orderindex++) { OPZ_IATTS attr; /* current ordering attribute being ** analyzed */ OPE_IEQCLS eqcls; /* equivalence class of ** of ordering attribute */ attr = varp->opv_mbf.opb_kbase->opb_keyorder[orderindex].opb_attno; eqcls = abase->opz_attnums[attr]->opz_equcls; if (storage == DB_RTRE_STORE) /* special Rtree inner logic */ { OPB_IBF bfi; OPB_BOOLFACT *bfp; for (bfi = 0; bfi < subquery->ops_bfs.opb_bv; bfi++) if ((bfp = subquery->ops_bfs.opb_base->opb_boolfact[bfi])-> opb_mask & OPB_SPATJ && BTtest((i4)eqcls, (char *)&bfp->opb_eqcmap)) { OPE_IEQCLS eqc1; if ((eqc1 = BTnext((i4)-1, (char *)&bfp->opb_eqcmap, (i4)subquery->ops_eclass.ope_ev)) == eqcls) eqc1 = BTnext((i4)eqc1, (char *)&bfp->opb_eqcmap, (i4)subquery->ops_eclass.ope_ev); if (BTtest((i4)eqc1, (char *)oeqcmp)) { eqcls = eqc1; break; /* kinda silly to let this drop into ** same test again - any alternative will ** be even uglier! */ } } } if (BTtest((i4)eqcls, (char *)oeqcmp) == TRUE) { /* Look no further if the first eqcls in the outer ** that exists in the order for the relation is not the ** joining eqcls (if primkey) */ if (primkey && (jeqc != eqcls)) { #ifdef xNTR1 if (tTf(1, 0)) { TRdisplay("We tried to join on eqcls %d but realized that it\n", eqcls); TRdisplay("was not the the primary attribute in the ordering and\n"); TRdisplay("that the primary attribute is available from the outer.\n"); uflush(); } #endif break; } /* Condition satisfied. If non-hash we are keyed */ ret_val = TRUE; primkey = FALSE; if (storage != DB_HASH_STORE) break; /* we are hashed and need all attrs in the key */ continue; } if (subquery->ops_bfs.opb_bfeqc && BTtest((i4)eqcls, (char *)subquery->ops_bfs.opb_bfeqc)) continue; /* check if constant key is ** available for this attribute*/ /* eqcls is not available. If we haven't gotten all ** of the hashed key, we can't use the key. */ if (storage == DB_HASH_STORE) { # ifdef xNTR1 if (tTf(1, 0)) { TRdisplay("Not all keys for hashed lookup were found.\n"); uflush(); } # endif ret_val = FALSE; } break; } # ifdef xNTR1 if (tTf(1, 0)) { if (ret_val == TRUE) TRdisplay("We can do keyed lookup.\n"); else TRdisplay("We can NOT do keyed lookup.\n"); uflush(); } # endif return (ret_val); }
update() { register int i, mode; struct descriptor rel; long oldtid, tupcnt; char oldtup[MAXTUP], newtup[MAXTUP]; char *batchname(); extern int Dburetflag; extern struct retcode Dburetcode; # ifdef xZTR1 if (tTf(15, -1)) printf("Update on %s\n", batchname()); # endif /* set up to read batchhd */ Batch_cnt = BATCHSIZE; /* force a read on next getbatch */ Batch_dirty = FALSE; if ((Batch_fp = open(batchname(), 2)) < 0) syserr("prim:can't open %s", batchname()); getbatch(&Batchhd, sizeof Batchhd); tupcnt = Batchhd.num_updts; # ifdef xZTR1 if (tTf(15, 0)) printf("rel=%s tups=%s\n", Batchhd.rel_name, locv(tupcnt)); # endif Dburetflag = TRUE; Dburetcode.rc_tupcount = 0; if (!tupcnt) { rmbatch(); return (1); } /* update the primary relation */ if (i = openr(&rel, 2, Batchhd.rel_name)) syserr("prim:can't openr %s %d", Batchhd.rel_name, i); mode = Batchhd.mode_up; while (tupcnt--) { getbatch(&oldtid, Batchhd.tido_size); /* read old tid */ getbatch(oldtup, Batchhd.tupo_size); /* and portions of old tuple */ getbatch(newtup, Batchhd.tupn_size); /* and the newtup */ switch (mode) { case mdDEL: if ((i = delete(&rel, &oldtid)) < 0) syserr("prim:bad del %d %s", i, Batchhd.rel_name); break; case mdREPL: if (i = replace(&rel, &oldtid, newtup, TRUE)) { /* if newtuple is a duplicate, then ok */ if (i == 1) break; /* if this is recovery and oldtup not there, try to insert newtup */ if (Batch_recovery && i == 2) goto upinsert; syserr("prim:Non-functional replace on %s (%d)", i, Batchhd.rel_name); } Dburetcode.rc_tupcount++; break; case mdAPP: upinsert: if ((i = insert(&rel, &oldtid, newtup, TRUE)) < 0) syserr("prim:bad insert %d %s", i, Batchhd.rel_name); break; default: syserr("prim:impossible mode %d", mode); } putbatch(&oldtid, Batchhd.tidn_size); /* write new tid if necessary */ } /* fix the tupchanged count if delete or append */ if (mode != mdREPL) Dburetcode.rc_tupcount = rel.reladds >= 0 ? rel.reladds : -rel.reladds; /* close the relation but secupdate will still use the decriptor */ if (i = closer(&rel)) syserr("prim:close err %d %s", i, Batchhd.rel_name); batchflush(); /* if this relation is indexed, update the indexes */ if (rel.relindxd > 0) secupdate(&rel); rmbatch(); # ifdef xZTR1 if (tTf(15, 2)) printf("%s tups changed\n", locv(Dburetcode.rc_tupcount)); # endif return (0); }
void readinput(register pb_t *ppb) { register int i; resp_t *rp; /* ** Top Loop. ** Executed once for each complete block read. Normally ** only executed once, but can be more if an error ** block is read. ** ** We mark Qbuf first, so we can free any parameters ** when they are no longer needed (such as when they ** are passed to another process). */ Ctx.ctx_pmark = markbuf(Qbuf); #ifdef xCTR1 if (tTf(10, 0)) lprintf("readinput: mark %d, errfn %x, ppb %x\n", Ctx.ctx_pmark, Ctx.ctx_errfn, ppb); #endif rp = getresp(); for (;;) { /* prime the input (reads first block) */ pb_prime(ppb, PB_NOTYPE); #ifdef xCTR2 if (tTf(10, 1)) lprintf("readinput: type %d\n", ppb->pb_type); #endif /* if this is a response block, return immediately */ if (ppb->pb_type == PB_RESP) { i = pb_get(ppb, (char *) rp, sizeof(resp_t)); if (i != sizeof(resp_t)) syserr("readinput: resp_t sz %d", i); /* read_arg(ppb, &rp->resp_rval); */ break; } /* ** Parameter Loop. ** Wander through and start reading parameters. */ for (Ctx.ctx_pc = 0; Ctx.ctx_pc < PV_MAXPC; Ctx.ctx_pc++) { if (read_arg(ppb, &Ctx.ctx_pv[Ctx.ctx_pc]) == PV_EOF) break; } /* out of loop, check for vector overflow */ if (Ctx.ctx_pc >= PV_MAXPC) syserr("readinput: overflow"); /* check for error blocks */ if (ppb->pb_type == PB_ERR) { proc_err(ppb, Ctx.ctx_pc, Ctx.ctx_pv); syserr("readinput: proc_err"); } /* non-error block */ #ifdef xCM_DEBUG if (ppb->pb_type != PB_REG) syserr("readinput: pb_type %d", ppb->pb_type); #endif Ctx.ctx_resp = ppb->pb_resp; break; } #ifdef xCTR1 if (tTf(10, 4)) { lprintf("readinput: "); pb_dump(ppb, FALSE); } #endif }
strategy() { register int i, allexact; struct accessparam sourceparam, indexparam; struct index itup, rtup; struct key lowikey[MAXKEYS+1], highikey[MAXKEYS+1]; register struct descriptor *d; extern struct descriptor Inddes; struct descriptor *openindex(); # ifdef xOTR1 if (tTf(31, 0)) printf("STRATEGY\tSource=%.12s\tNewq = %d\n", Source ? Source->relid : "(none)", Newq); # endif while (Newq) /* if Newq=TRUE then compute a new strategy */ /* NOTE: This while loop is executed only once */ { Scanr = Source; if (!Scanr) return (1); /* return immediately if there is no source relation */ Fmode = NOKEY; /* assume a find mode with no key */ if (!Qlist) break; /* if no qualification then you must scan entire rel */ /* copy structure of source relation into sourceparam */ paramd(Source, &sourceparam); /* if source is unkeyed and has no sec index then give up */ if (sourceparam.mode == NOKEY && Source->relindxd <= 0) break; /* find all simple clauses if any */ if (!findsimps()) break; /* break if there are no simple clauses */ /* Four steps are now performed to try and find a key. ** First if the relation is hashed then an exact key is search for ** ** Second if there are secondary indexes, then a search is made ** for an exact key. If that fails then a check is made for ** a range key. The result of the rangekey check is saved. ** ** Third if the relation is an ISAM a check is made for ** an exact key or a range key. ** ** Fourth if there is a secondary index, then if step two ** found a key, that key is used. ** ** Lastly, give up and scan the entire relation */ /* step one. Try to find exact key on primary */ if (exactkey(&sourceparam, &Lkey_struct)) { Fmode = EXACTKEY; break; } /* step two. If there is an index, try to find an exactkey on one of them */ if (Source->relindxd) { opencatalog("indexes", 0); setkey(&Inddes, &itup, Source->relid, IRELIDP); setkey(&Inddes, &itup, Source->relowner, IOWNERP); if (i = find(&Inddes, EXACTKEY, &Lotid, &Hitid, &itup)) syserr("strategy:find indexes %d", i); while (!(i = get(&Inddes, &Lotid, &Hitid, &itup, NXTTUP))) { # ifdef xOTR1 if (tTf(31, 3)) printup(&Inddes, &itup); # endif if (!bequal(itup.irelidp, Source->relid, MAXNAME) || !bequal(itup.iownerp, Source->relowner, 2)) continue; parami(&itup, &indexparam); if (exactkey(&indexparam, &Lkey_struct)) { Fmode = EXACTKEY; d = openindex(itup.irelidi); /* temp check for 6.0 index */ if (d->relindxd == -1) ov_err(BADSECINDX); Scanr = d; break; } if (Fmode == LRANGEKEY) continue; /* a range key on a s.i. has already been found */ if (allexact = rangekey(&indexparam, &lowikey, &highikey)) { bmove(&itup, &rtup, sizeof itup); /* save tuple */ Fmode = LRANGEKEY; } } if (i < 0) syserr("stragery:bad get from index-rel %d", i); /* If an exactkey on a secondary index was found, look no more. */ if (Fmode == EXACTKEY) break; } /* step three. Look for a range key on primary */ if (i = rangekey(&sourceparam, &Lkey_struct, &Hkey_struct)) { if (i < 0) Fmode = EXACTKEY; else Fmode = LRANGEKEY; break; } /* last step. If a secondary index range key was found, use it */ if (Fmode == LRANGEKEY) { if (allexact < 0) Fmode = EXACTKEY; d = openindex(rtup.irelidi); /* temp check for 6.0 index */ if (d->relindxd == -1) ov_err(BADSECINDX); Scanr = d; bmove(&lowikey, &Lkey_struct, sizeof lowikey); bmove(&highikey, &Hkey_struct, sizeof highikey); break; } /* nothing will work. give up! */ break; } /* check for Newq = FALSE and no source relation */ if (!Scanr) return (1); /* ** At this point the strategy is determined. ** ** If Fmode is EXACTKEY then Lkey_struct contains ** the pointers to the keys. ** ** If Fmode is LRANGEKEY then Lkey_struct contains ** the pointers to the low keys and Hkey_struct ** contains pointers to the high keys. ** ** If Fmode is NOKEY, then a full scan will be performed */ # ifdef xOTR1 if (tTf(31, -1)) printf("Fmode= %d\n",Fmode); # endif /* set up the key tuples */ if (Fmode != NOKEY) { if (setallkey(&Lkey_struct, Keyl)) return (0); /* query false. There is a simple ** clause which can never be satisfied. ** These simple clauses can be choosey! */ } if (i = find(Scanr, Fmode, &Lotid, &Hitid, Keyl)) syserr("strategy:find1 %.12s, %d", Scanr->relid, i); if (Fmode == LRANGEKEY) { setallkey(&Hkey_struct, Keyh); if (i = find(Scanr, HRANGEKEY, &Lotid, &Hitid, Keyh)) syserr("strategy:find2 %.12s, %d", Scanr->relid, i); } # ifdef xOTR1 if (tTf(31, 1)) { printf("Lo"); dumptid(&Lotid); printf("Hi"); dumptid(&Hitid); } # endif return (1); }
int proc_err(pb_t *ppb, int pc, paramv_t *pv) { register func_t *f; register int i; register ctx_t *ctx; #ifdef xCTR2 if (tTf(6, 8)) lprintf("proc_err: new = %d\n", Ctx.ctx_new); #endif pb_prime(ppb, PB_ERR); /* ** Scan back on the list of context dependencies. ** If we come to someone who can process this message, ** we go ahead and do it. We also take this ** opportunity to unwind the context list & call the ** cleanup functions. */ for (ctx = &Ctx; ctx != NULL; ctx = ctx->ctx_link) { setprocname(ctx->ctx_name); f = ctx->ctx_fn; #ifdef xCTR2 if (tTf(6, 9)) lprintf("proc_err: unwinding %s: errfn=%x, ppb=%x, link=%x, resp=%d, fn=%x\n", getprocname(), ctx->ctx_errfn, ctx->ctx_ppb, ctx->ctx_link, ctx->ctx_resp, f); #endif /* Do the actual error processing. */ ppb->pb_proc = ctx->ctx_resp; if (ctx->ctx_errfn != NULL) i = (*ctx->ctx_errfn)(pc, pv); else i = -1; #ifdef xCTR2 if (tTf(6, 11)) lprintf("proc_err: errcode %d\n", i); #endif if (i == 0) break; else if (i > 0) { /* turn into nonfatal error */ ppb->pb_stat |= PB_INFO; ppb->pb_proc = PB_FRONT; } else { /* call the cleanup function */ if (f != NULL && f->fn_active > 0) { (*f->fn_cleanup)(1); } } /* arrange to leave if parent not in this process */ if (ppb->pb_proc != Cm.cm_myproc) { send_off(ppb, pc, pv); pb_flush(ppb); /* throw away dead contexts and exit */ break; } } if (ctx == NULL) { syserr("proc_err: no parent"); } #ifdef xCTR3 MonPpb = getmonppb(); if (tTf(6, 12)) { lprintf("proc_err: cleanup: ctx=%x, ->_link=%x, MonPpb = ", ctx, ctx->ctx_link); pb_dump(MonPpb, TRUE); } #endif /* pop contexts down to ctx and exit */ ctx = ctx->ctx_link; while (Ctx.ctx_link != ctx) { if (Ctx.ctx_link == NULL) syserr("proc_err: underflow"); Ctx.ctx_new = TRUE; resetp(); } /* ** Flush input pipe. ** THIS CODE IS ONLY NEEDED TO MAKE READMON WORK, AND ** SHOULD BE REMOVED WHEN READMON GOES AWAY!! */ if (ctx == NULL) { Cm.cm_input = Cm.cm_rinput; MonPpb = getmonppb(); while (!BITISSET(PB_EOF, MonPpb->pb_stat)) { pb_read(MonPpb); } MonPpb->pb_st = PB_UNKNOWN; } longjmp(Ctx.ctx_jbuf, 1); }
int indexx(int pc, paramv_t *pv) { register int i; int j; register struct dom *dom; register paramv_t *p; char *primary, *indx; int ndoms, newpc; struct tup_id tid, hitid; struct tup_id xtid; paramv_t newpv[MAX_2ND_KEYS * 2 + 4]; char primtup[MAX_TUP_SIZE], systup[MAX_TUP_SIZE]; desc_t desc, pridesc; extern desc_t Reldes; extern desc_t Attdes; extern desc_t Inddes; relation_t relkey, reltup; attr_t attkey, atttup; index_t indtup; struct dom domain[MAX_2ND_KEYS]; primary = pv[0].pv_val.pv_str; indx = pv[1].pv_val.pv_str; #ifdef xZTR1 if (tTf(33, -1)) printf("index: (pri %s ind %s)\n", primary, indx); #endif i = openr(&pridesc, OR_READ, primary); if (i == AMOPNVIEW_ERR) return (error(NOINDVIEW, primary, 0)); if (i > 0) return (error(NOPRIMREL, primary, 0)); if (i < 0) syserr("INDEX : openr (%.14s) %d", primary, i); if (!bequal(pridesc.d_r.r_owner, Usercode, USERCODE_SIZE)) { i = NOTOWNED; } else if (pridesc.d_r.r_status & S_CATALOG) { i = NOINDXSYSREL; } else if (pridesc.d_r.r_indexed == SECINDEX) { i = ALREADYINDX; } if (i) { closer(&pridesc); return (error(i, primary, 0)); } /* ** GATHER INFO. ON DOMAINS */ opencatalog("attribute", OR_WRITE); ingres_setkey(&Attdes, &attkey, primary, ATTRELID); ingres_setkey(&Attdes, &attkey, pridesc.d_r.r_owner, ATTOWNER); pc -= 2; p = &pv[2]; dom = domain; for (i = 0; i < pc; i++) { if (i >= MAX_2ND_KEYS) { closer(&pridesc); return (error(TOOMUCHDOMS, (p->pv_val).pv_str, primary, 0)); /* too many keys */ } ingres_setkey(&Attdes, &attkey, (p->pv_val).pv_str, ATTNAME); j = getequal(&Attdes, &attkey, &atttup, &tid); if (j < 0) syserr("INDEX: geteq att %d", j); if (j) { closer(&pridesc); return (error(NODOM, (p->pv_val).pv_str, 0)); /* key not in relation */ } if (pridesc.d_r.r_dim > 0 && atttup.a_id == pridesc.d_r.r_attrc) { /* attempting to use lid field as part of index */ closer(&pridesc); return(error(NOINDXLID, primary, (p->pv_val).pv_str, 0)); } dom->id = atttup.a_id; dom->off = atttup.a_off; dom->frml = atttup.a_len & I1MASK; dom->frm[0] = atttup.a_fmt; p++; dom++; } ndoms = i; noclose(&Attdes); /* ** The "order" of the steps have been altered to improve ** recovery possibilities */ /* ** STEP 1 & 2: CREATE INDEX RELATION. */ newpv[0].pv_val.pv_str = "0202"; newpv[1].pv_val.pv_str = indx; newpc = 2; p = &pv[2]; dom = domain; for (i = 0; i < pc; i++) { newpv[newpc++].pv_val.pv_str = (p->pv_val).pv_str; itoa(dom->frml, &dom->frm[1]); newpv[newpc++].pv_val.pv_str = dom->frm; dom++; p++; } newpv[newpc++].pv_val.pv_str = "tidp"; newpv[newpc++].pv_val.pv_str = "i4"; newpv[newpc].pv_type = PV_EOF; if (create(newpc, newpv)) { closer(&pridesc); return (-1); } /* This is done for concurrency reasons */ if (noclose(&Reldes)) syserr("index: noclose"); /* ** STEP 5: FILL UP THE SECONDARY INDEX FILE ITSELF */ if (Lockrel) { /* set a shared relation lock */ setrll(A_SLP, &pridesc.d_tid, M_SHARE); } if ((i = openr(&desc, OR_WRITE, indx)) != 0) syserr("INDEX: openr %.14s %d", indx, i); find(&pridesc, NOKEY, &tid, &hitid, (void *) NULL); while ((i = get(&pridesc, &tid, &hitid, primtup, TRUE)) == 0) { dom = domain; for (i = j = 0; j < ndoms; j++) { #ifdef BIG_ENDIAN if (dom->frm[0] != 'c') i = ((i-1)|(dom->frml-1))+1; #endif bmove(&primtup[dom->off], &systup[i], dom->frml); i += dom->frml; dom++; } #ifdef BIG_ENDIAN i = ((i-1)|3)+1; #endif /* move in pointer */ bmove(&tid, &systup[i], sizeof(tid)); if ((j = insert(&desc, &xtid, systup, TRUE)) < 0) { syserr("INDEX: insert %.14s %d", indx, j); } } if (i < 0) { syserr("INDEX: get %.14s %d", primary, i); } closer(&pridesc); closer(&desc); /* ** STEP 3: ENTRIES TO INDEX-REL */ /* mv in primary name */ pmove(primary, indtup.i_relname, MAX_NAME_SIZE, ' '); /* primary owner */ bmove(pridesc.d_r.r_owner, indtup.i_owner, sizeof(pridesc.d_r.r_owner)); /* index name */ pmove(indx, indtup.i_index, MAX_NAME_SIZE, ' '); indtup.i_indrelspec = M_HEAP; for (i = 0; i < MAX_2ND_KEYS; i++) { indtup.i_dom[i] = (i < ndoms) ? domain[i].id : 0; } opencatalog("indices", OR_WRITE); if ((i = insert(&Inddes, &tid, (char *) &indtup, TRUE)) < 0) syserr("INDEX: insert ix %d", i); /* ** STEP 4: TURN BIT ON IN PRIMARY RELATION TO SHOW IT IS BEING INDEXED */ opencatalog("relation", OR_WRITE); ingres_setkey(&Reldes, &relkey, primary, RELID); ingres_setkey(&Reldes, &relkey, pridesc.d_r.r_owner, RELOWNER); if ((i = getequal(&Reldes, &relkey, &reltup, &tid)) != 0) syserr("INDEX: geteq rel %d", i); reltup.r_indexed = SECBASE; if ((i = replace(&Reldes, &tid, &reltup, TRUE)) < 0) syserr("INDEX: replace rel %d", i); if (Lockrel) unlrl(&pridesc.d_tid); /* release relation lock */ return (0); }