/* ** REL_FILE -- copy from relation to file */ int rel_file(void) { int j; struct tup_id tid, limtid; char *cp, save; register int offset; register int i; register struct map *mp; /* set scan limits to scan the entire relation */ if (find(&Des, NOKEY, &tid, &limtid, (void *) NULL)) syserr("find error"); while ((i = get(&Des, &tid, &limtid, Inbuf, 1)) == 0) { mp = Map; offset = 0; for (i = 0; i < Mapcount; i++) { /* ** For cases of char to numeric conversion, ** there must be a null byte at the end of the ** string. The character just past the current ** domain is saved an a null byte inserted */ cp = &Inbuf[mp->roffset + mp->rlen]; /* compute address */ save = *cp; /* get the character */ *cp = '\0'; /* insert a null */ /* ** Special case, we want to copy the tid */ if ( mp->roffset == -1 ) { j = transfer((ANYTYPE *)&tid, mp->rtype, mp->rlen, mp->ftype, mp->flen, offset); } else { j = transfer((ANYTYPE *)&Inbuf[mp->roffset], mp->rtype, mp->rlen, mp->ftype, mp->flen, offset); } if (j) { /* bad ascii to numeric conversion or field length too small */ return (nferror(j, mp->paramname, &Inbuf[mp->roffset], locv(Tupcount), Relname, Filename, 0)); } *cp = save; /* restore the saved character */ offset += mp->flen; mp++; } Tupcount++; if (fwrite(Outbuf, 1, offset, File_iop) != offset) syserr("copy:cant write to user file %s", Filename); } if (i < 0) syserr("bad get from rel %d", i); return (0); }
/* ** file_rel is called to transfer tuples from ** the input file and append them to the relation ** ** Char domains are initialized to blank and numeric ** domains are initialized to zero. */ int file_rel(void) { register int i, j; register struct map *mp; struct tup_id tid; clr_tuple(&Des, Outbuf); /* copy domains until an end of file or an error */ for (;;) { mp = Map; for (i = 0; i < Mapcount; i++) { if ((j = bread(mp)) <= 0) { if (j < 0) { i = 1; /* force an error */ j = UNDETC0; /* unterminated string */ } else j = UNEXEOF; /* end of file */ if (i) { /* error only if end of file during a tuple or unterminated string */ i = nferror(j, mp->paramname, locv(Tupcount), Filename, Relname, 0); } return (i); } j = transfer((ANYTYPE *) Inbuf, mp->ftype, mp->flen, mp->rtype, mp->rlen, mp->roffset); if (j) { /* bad ascii to numeric or field length too small */ return (nferror(j, mp->paramname, Inbuf, locv(Tupcount), Filename, Relname, 0)); } mp++; } Tupcount++; if ((j = insert(&Des, &tid, Outbuf, 1)) < 0) syserr("insert error %d rel=%s", j, Relname); if (j == 1) Duptuple++; mp++; } return(0); }
/* ** Finish up and exit after a copy or interrupt ** ** I is the return code. Since only a byte can be ** returned, only the least significant 2 decimal ** digits are returned. i is either 0 or a number like 58?? */ RETSIGTYPE copydone(int i) { if (Lockrel) /* unlock relation */ unlrl(&Des.d_tid); if (Truncount) nferror(TRUNCCHARS, locv(Truncount), 0); /* warning only */ /* force the updates to be flushed */ cleanrel(&Des); if (File_iop) fclose(File_iop); if (write(Piped[1], &Des.d_addc, 4) != 4) syserr("copyc:can't writepipe"); exit (i % 100); }
void trapquery(struct resp *resp, char *name) { register FILE *iop; static int first; register char *sp, c; time_t timevec; if (first < 0) return; if (Trapfile == NULL) { if ((Trapfile = fopen(name, "a")) == NULL) { printf("can't trap query in %s\n", name); first = -1; return; } } if (first == 0) { (void) time(&timevec); sp = ctime(&timevec); while (*sp) putc(*sp++, Trapfile); first++; } if ((iop = fopen(Qbname, "r")) == NULL) syserr("go: open 1"); macinit(fgetc, iop, 1); while ((c = macgetch()) > 0) putc(c, Trapfile); if (resp->resp_resp == 0) { sp = (char *) locv(resp->resp_tups); while (*sp) putc(*sp++, Trapfile); putc('\n', Trapfile); } fclose(iop); }
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); }
/* ** transfer copies data from "*in" to ** Outbuf doing conversions whenever ** necessary */ int transfer(ANYTYPE *in, char sf, int sl, char df, int dl, int doff) /* in - pointer to input chars */ /* sf - source format */ /* sl - source length */ /* df - destination format */ /* dl - destination length */ /* doff - destination offset */ { register char *outp; register ANYTYPE *inp; register int i; int j; short smalli; char temp[MAX_FIELD_SIZE]; /* holds char during conversions to ascii */ float f; double d; long l; outp = &Outbuf[doff]; inp = in; if (sf == DUMMY) /* if source format is a dummy fields then nothing else need be done */ return (0); if (df == DUMMY) { /* fill field with dummy domain character */ i = dl; /* i equals the number of chars */ while (i--) *outp++ = sf; /* sf holds dummy char */ return (0); } if (sf != CHAR_CONST) { if (df == CHAR_CONST) { /* numeric to char conversion */ switch (sl) { /* int of size 1 or 2 */ case 1: itoa(inp->i1type, temp); break; case 2: itoa(inp->i2type, temp); /* convert to ascii */ break; /* int or float of size 4 */ case 4: if (sf == INT_CONST) { smove(locv(inp->i4type), temp); /* convert and copy */ } else { ftoa(inp->f4type, temp, dl, Out_arg.f4prec, Out_arg.f4style); } break; /* float of size 8 */ case 8: ftoa(inp->f8type, temp, dl, Out_arg.f8prec, Out_arg.f8style); break; /* there is no possible default */ default: syserr("bad domain length %d",sl); } j = strlen(temp); if ((i = dl - j) < 0) return (5808); /* field won't fit */ /* blank pad from left. Number will be right justified */ while (i--) *outp++ = ' '; bmove(temp, outp, j); return (0); } if (convert(inp, outp, sf, sl, df, dl)) /* numeric to numeric transfer */ return (DOMTOOSMALL); /* numeric truncation error */ return (0); } /* character to numeric conversion */ /* and character to character conversion */ switch (df) { case CHAR_CONST: i = sl; if (!i) { i = strlen(inp->c0type); } if (i > dl) i = dl; if (charmove(inp->c0type, outp, i)) Baddoms++; for (outp += i; i<dl; i++) *outp++ = ' '; return (0); case FLOAT_CONST: if (ingres_atof(inp->c0type, &d)) return (BADINPUT); /* bad conversion to numeric */ if (dl == 8) { bmove(&d, outp, dl); } else { f = d; /* f8 to f4 conversion */ bmove(&f, outp, dl); } return (0); case INT_CONST: if (dl == 4) { if (ingres_atol(inp->c0type, &l)) return (5809); bmove(&l, outp, sizeof(l)); return (0); } smalli = atoi(inp->c0type); if (dl == 1) { if ((smalli < -128) || (smalli > 127)) return (5809); df = smalli; bmove(&df, outp, dl); } else bmove(&smalli, outp, dl); return (0); } return(0); }
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); }
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 */ }