diff options
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r-- | src/backend/commands/copy.c | 1884 |
1 files changed, 1017 insertions, 867 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 687cd1eb12e..795e9f5584f 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -6,7 +6,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.29 1997/09/04 13:18:59 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.30 1997/09/07 04:40:40 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -42,736 +42,857 @@ /* non-export function prototypes */ -static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim); -static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim); -static Oid GetOutputFunction(Oid type); -static Oid GetTypeElement(Oid type); -static Oid GetInputFunction(Oid type); -static Oid IsTypeByVal(Oid type); -static void GetIndexRelations(Oid main_relation_oid, - int *n_indices, - Relation **index_rels); +static void CopyTo(Relation rel, bool binary, bool oids, FILE * fp, char *delim); +static void CopyFrom(Relation rel, bool binary, bool oids, FILE * fp, char *delim); +static Oid GetOutputFunction(Oid type); +static Oid GetTypeElement(Oid type); +static Oid GetInputFunction(Oid type); +static Oid IsTypeByVal(Oid type); +static void +GetIndexRelations(Oid main_relation_oid, + int *n_indices, + Relation ** index_rels); + #ifdef COPY_PATCH -static void CopyReadNewline(FILE *fp, int *newline); -static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline); +static void CopyReadNewline(FILE * fp, int *newline); +static char *CopyReadAttribute(FILE * fp, bool * isnull, char *delim, int *newline); + #else -static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim); +static char *CopyReadAttribute(FILE * fp, bool * isnull, char *delim); + #endif -static void CopyAttributeOut(FILE *fp, char *string, char *delim); -static int CountTuples(Relation relation); +static void CopyAttributeOut(FILE * fp, char *string, char *delim); +static int CountTuples(Relation relation); -extern FILE *Pfout, *Pfin; +extern FILE *Pfout, + *Pfin; #ifdef COPY_DEBUG -static int lineno; +static int lineno; + #endif - + /* - * DoCopy executes a the SQL COPY statement. + * DoCopy executes a the SQL COPY statement. */ void -DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, - char *filename, char *delim) { +DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, + char *filename, char *delim) +{ /*---------------------------------------------------------------------------- Either unload or reload contents of class <relname>, depending on <from>. If <pipe> is false, transfer is between the class and the file named <filename>. Otherwise, transfer is between the class and our regular - input/output stream. The latter could be either stdin/stdout or a + input/output stream. The latter could be either stdin/stdout or a socket, depending on whether we're running under Postmaster control. Iff <binary>, unload or reload in the binary format, as opposed to the - more wasteful but more robust and portable text format. + more wasteful but more robust and portable text format. - If in the text format, delimit columns with delimiter <delim>. + If in the text format, delimit columns with delimiter <delim>. When loading in the text format from an input stream (as opposed to - a file), recognize a "." on a line by itself as EOF. Also recognize + a file), recognize a "." on a line by itself as EOF. Also recognize a stream EOF. When unloading in the text format to an output stream, write a "." on a line by itself at the end of the data. Iff <oids>, unload or reload the format that includes OID information. Do not allow a Postgres user without superuser privilege to read from - or write to a file. + or write to a file. Do not allow the copy if user doesn't have proper permission to access the class. ----------------------------------------------------------------------------*/ - FILE *fp; - Relation rel; - extern char *UserName; /* defined in global.c */ - const AclMode required_access = from ? ACL_WR : ACL_RD; - int result; - - rel = heap_openr(relname); - if (rel == NULL) elog(WARN, "COPY command failed. Class %s " - "does not exist.", relname); - - result = pg_aclcheck(relname, UserName, required_access); - if(result != ACLCHECK_OK) - elog(WARN, "%s: %s", relname, aclcheck_error_strings[result]); - /* Above should not return */ - else if (!superuser() && !pipe) - elog(WARN, "You must have Postgres superuser privilege to do a COPY " - "directly to or from a file. Anyone can COPY to stdout or " - "from stdin. Psql's \\copy command also works for anyone."); - /* Above should not return. */ - else { - if (from) { /* copy from file to database */ - if ( rel->rd_rel->relkind == RELKIND_SEQUENCE ) - elog (WARN, "You can't change sequence relation %s", relname); - if (pipe) { - if (IsUnderPostmaster) { - ReceiveCopyBegin(); - fp = Pfin; - } else fp = stdin; - } else { - fp = AllocateFile(filename, "r"); - if (fp == NULL) - elog(WARN, "COPY command, running in backend with " - "effective uid %d, could not open file '%s' for " - "reading. Errno = %s (%d).", - geteuid(), filename, strerror(errno), errno); - /* Above should not return */ - } - CopyFrom(rel, binary, oids, fp, delim); - } else { /* copy from database to file */ - if (pipe) { - if (IsUnderPostmaster) { - SendCopyBegin(); - fp = Pfout; - } else fp = stdout; - } else { - mode_t oumask; /* Pre-existing umask value */ - oumask = umask((mode_t) 0); - fp = AllocateFile(filename, "w"); - umask(oumask); - if (fp == NULL) - elog(WARN, "COPY command, running in backend with " - "effective uid %d, could not open file '%s' for " - "writing. Errno = %s (%d).", - geteuid(), filename, strerror(errno), errno); - /* Above should not return */ - } - CopyTo(rel, binary, oids, fp, delim); - } - if (!pipe) - FreeFile(fp); - else if (!from && !binary) { - fputs("\\.\n", fp); - if (IsUnderPostmaster) fflush(Pfout); - } - } + FILE *fp; + Relation rel; + extern char *UserName; /* defined in global.c */ + const AclMode required_access = from ? ACL_WR : ACL_RD; + int result; + + rel = heap_openr(relname); + if (rel == NULL) + elog(WARN, "COPY command failed. Class %s " + "does not exist.", relname); + + result = pg_aclcheck(relname, UserName, required_access); + if (result != ACLCHECK_OK) + elog(WARN, "%s: %s", relname, aclcheck_error_strings[result]); + /* Above should not return */ + else if (!superuser() && !pipe) + elog(WARN, "You must have Postgres superuser privilege to do a COPY " + "directly to or from a file. Anyone can COPY to stdout or " + "from stdin. Psql's \\copy command also works for anyone."); + /* Above should not return. */ + else + { + if (from) + { /* copy from file to database */ + if (rel->rd_rel->relkind == RELKIND_SEQUENCE) + elog(WARN, "You can't change sequence relation %s", relname); + if (pipe) + { + if (IsUnderPostmaster) + { + ReceiveCopyBegin(); + fp = Pfin; + } + else + fp = stdin; + } + else + { + fp = AllocateFile(filename, "r"); + if (fp == NULL) + elog(WARN, "COPY command, running in backend with " + "effective uid %d, could not open file '%s' for " + "reading. Errno = %s (%d).", + geteuid(), filename, strerror(errno), errno); + /* Above should not return */ + } + CopyFrom(rel, binary, oids, fp, delim); + } + else + { /* copy from database to file */ + if (pipe) + { + if (IsUnderPostmaster) + { + SendCopyBegin(); + fp = Pfout; + } + else + fp = stdout; + } + else + { + mode_t oumask; /* Pre-existing umask value */ + + oumask = umask((mode_t) 0); + fp = AllocateFile(filename, "w"); + umask(oumask); + if (fp == NULL) + elog(WARN, "COPY command, running in backend with " + "effective uid %d, could not open file '%s' for " + "writing. Errno = %s (%d).", + geteuid(), filename, strerror(errno), errno); + /* Above should not return */ + } + CopyTo(rel, binary, oids, fp, delim); + } + if (!pipe) + FreeFile(fp); + else if (!from && !binary) + { + fputs("\\.\n", fp); + if (IsUnderPostmaster) + fflush(Pfout); + } + } } static void -CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim) +CopyTo(Relation rel, bool binary, bool oids, FILE * fp, char *delim) { - HeapTuple tuple; - HeapScanDesc scandesc; - - int32 attr_count, i; - AttributeTupleForm *attr; - func_ptr *out_functions; - int dummy; - Oid out_func_oid; - Oid *elements; - Datum value; - bool isnull; /* The attribute we are copying is null */ - char *nulls; - /* <nulls> is a (dynamically allocated) array with one character - per attribute in the instance being copied. nulls[I-1] is - 'n' if Attribute Number I is null, and ' ' otherwise. - - <nulls> is meaningful only if we are doing a binary copy. - */ - char *string; - int32 ntuples; - TupleDesc tupDesc; - - scandesc = heap_beginscan(rel, 0, NULL, 0, NULL); - - attr_count = rel->rd_att->natts; - attr = rel->rd_att->attrs; - tupDesc = rel->rd_att; - - if (!binary) { - out_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr)); - elements = (Oid *) palloc(attr_count * sizeof(Oid)); - for (i = 0; i < attr_count; i++) { - out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid); - fmgr_info(out_func_oid, &out_functions[i], &dummy); - elements[i] = GetTypeElement(attr[i]->atttypid); - } - nulls = NULL; /* meaningless, but compiler doesn't know that */ - }else { - elements = NULL; - out_functions = NULL; - nulls = (char *) palloc(attr_count); - for (i = 0; i < attr_count; i++) nulls[i] = ' '; - - /* XXX expensive */ - - ntuples = CountTuples(rel); - fwrite(&ntuples, sizeof(int32), 1, fp); - } - - for (tuple = heap_getnext(scandesc, 0, NULL); - tuple != NULL; - tuple = heap_getnext(scandesc, 0, NULL)) { - - if (oids && !binary) { - fputs(oidout(tuple->t_oid),fp); - fputc(delim[0], fp); - } - - for (i = 0; i < attr_count; i++) { - value = (Datum) - heap_getattr(tuple, InvalidBuffer, i+1, tupDesc, &isnull); - if (!binary) { - if (!isnull) { - string = (char *) (out_functions[i]) (value, elements[i]); - CopyAttributeOut(fp, string, delim); - pfree(string); - } - else - fputs("\\N", fp); /* null indicator */ - - if (i == attr_count - 1) { - fputc('\n', fp); - }else { - /* when copying out, only use the first char of the delim - string */ - fputc(delim[0], fp); - } - }else { - /* - * only interesting thing heap_getattr tells us in this case - * is if we have a null attribute or not. - */ - if (isnull) nulls[i] = 'n'; - } - } - - if (binary) { - int32 null_ct = 0, length; - - for (i = 0; i < attr_count; i++) { - if (nulls[i] == 'n') null_ct++; - } - - length = tuple->t_len - tuple->t_hoff; - fwrite(&length, sizeof(int32), 1, fp); - if (oids) - fwrite((char *) &tuple->t_oid, sizeof(int32), 1, fp); - - fwrite(&null_ct, sizeof(int32), 1, fp); - if (null_ct > 0) { - for (i = 0; i < attr_count; i++) { - if (nulls[i] == 'n') { - fwrite(&i, sizeof(int32), 1, fp); - nulls[i] = ' '; - } - } - } - fwrite((char *) tuple + tuple->t_hoff, length, 1, fp); - } - } - - heap_endscan(scandesc); - if (binary) { - pfree(nulls); - }else { - pfree(out_functions); - pfree(elements); - } - - heap_close(rel); + HeapTuple tuple; + HeapScanDesc scandesc; + + int32 attr_count, + i; + AttributeTupleForm *attr; + func_ptr *out_functions; + int dummy; + Oid out_func_oid; + Oid *elements; + Datum value; + bool isnull; /* The attribute we are copying is null */ + char *nulls; + + /* + * <nulls> is a (dynamically allocated) array with one character per + * attribute in the instance being copied. nulls[I-1] is 'n' if + * Attribute Number I is null, and ' ' otherwise. + * + * <nulls> is meaningful only if we are doing a binary copy. + */ + char *string; + int32 ntuples; + TupleDesc tupDesc; + + scandesc = heap_beginscan(rel, 0, NULL, 0, NULL); + + attr_count = rel->rd_att->natts; + attr = rel->rd_att->attrs; + tupDesc = rel->rd_att; + + if (!binary) + { + out_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr)); + elements = (Oid *) palloc(attr_count * sizeof(Oid)); + for (i = 0; i < attr_count; i++) + { + out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid); + fmgr_info(out_func_oid, &out_functions[i], &dummy); + elements[i] = GetTypeElement(attr[i]->atttypid); + } + nulls = NULL; /* meaningless, but compiler doesn't know + * that */ + } + else + { + elements = NULL; + out_functions = NULL; + nulls = (char *) palloc(attr_count); + for (i = 0; i < attr_count; i++) + nulls[i] = ' '; + + /* XXX expensive */ + + ntuples = CountTuples(rel); + fwrite(&ntuples, sizeof(int32), 1, fp); + } + + for (tuple = heap_getnext(scandesc, 0, NULL); + tuple != NULL; + tuple = heap_getnext(scandesc, 0, NULL)) + { + + if (oids && !binary) + { + fputs(oidout(tuple->t_oid), fp); + fputc(delim[0], fp); + } + + for (i = 0; i < attr_count; i++) + { + value = (Datum) + heap_getattr(tuple, InvalidBuffer, i + 1, tupDesc, &isnull); + if (!binary) + { + if (!isnull) + { + string = (char *) (out_functions[i]) (value, elements[i]); + CopyAttributeOut(fp, string, delim); + pfree(string); + } + else + fputs("\\N", fp); /* null indicator */ + + if (i == attr_count - 1) + { + fputc('\n', fp); + } + else + { + + /* + * when copying out, only use the first char of the + * delim string + */ + fputc(delim[0], fp); + } + } + else + { + + /* + * only interesting thing heap_getattr tells us in this + * case is if we have a null attribute or not. + */ + if (isnull) + nulls[i] = 'n'; + } + } + + if (binary) + { + int32 null_ct = 0, + length; + + for (i = 0; i < attr_count; i++) + { + if (nulls[i] == 'n') + null_ct++; + } + + length = tuple->t_len - tuple->t_hoff; + fwrite(&length, sizeof(int32), 1, fp); + if (oids) + fwrite((char *) &tuple->t_oid, sizeof(int32), 1, fp); + + fwrite(&null_ct, sizeof(int32), 1, fp); + if (null_ct > 0) + { + for (i = 0; i < attr_count; i++) + { + if (nulls[i] == 'n') + { + fwrite(&i, sizeof(int32), 1, fp); + nulls[i] = ' '; + } + } + } + fwrite((char *) tuple + tuple->t_hoff, length, 1, fp); + } + } + + heap_endscan(scandesc); + if (binary) + { + pfree(nulls); + } + else + { + pfree(out_functions); + pfree(elements); + } + + heap_close(rel); } static void -CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim) +CopyFrom(Relation rel, bool binary, bool oids, FILE * fp, char *delim) { - HeapTuple tuple; - AttrNumber attr_count; - AttributeTupleForm *attr; - func_ptr *in_functions; - int i, dummy; - Oid in_func_oid; - Datum *values; - char *nulls, *index_nulls; - bool *byval; - bool isnull; - bool has_index; - int done = 0; - char *string = NULL, *ptr; - Relation *index_rels; - int32 len, null_ct, null_id; - int32 ntuples, tuples_read = 0; - bool reading_to_eof = true; - Oid *elements; - FuncIndexInfo *finfo, **finfoP = NULL; - TupleDesc *itupdescArr; - HeapTuple pgIndexTup; - IndexTupleForm *pgIndexP = NULL; - int *indexNatts = NULL; - char *predString; - Node **indexPred = NULL; - TupleDesc rtupdesc; - ExprContext *econtext = NULL; + HeapTuple tuple; + AttrNumber attr_count; + AttributeTupleForm *attr; + func_ptr *in_functions; + int i, + dummy; + Oid in_func_oid; + Datum *values; + char *nulls, + *index_nulls; + bool *byval; + bool isnull; + bool has_index; + int done = 0; + char *string = NULL, + *ptr; + Relation *index_rels; + int32 len, + null_ct, + null_id; + int32 ntuples, + tuples_read = 0; + bool reading_to_eof = true; + Oid *elements; + FuncIndexInfo *finfo, + **finfoP = NULL; + TupleDesc *itupdescArr; + HeapTuple pgIndexTup; + IndexTupleForm *pgIndexP = NULL; + int *indexNatts = NULL; + char *predString; + Node **indexPred = NULL; + TupleDesc rtupdesc; + ExprContext *econtext = NULL; + #ifndef OMIT_PARTIAL_INDEX - TupleTable tupleTable; - TupleTableSlot *slot = NULL; + TupleTable tupleTable; + TupleTableSlot *slot = NULL; + #endif - int natts; - AttrNumber *attnumP; - Datum *idatum; - int n_indices; - InsertIndexResult indexRes; - TupleDesc tupDesc; - Oid loaded_oid; - bool skip_tuple = false; - - tupDesc = RelationGetTupleDescriptor(rel); - attr = tupDesc->attrs; - attr_count = tupDesc->natts; - - has_index = false; - - /* - * This may be a scalar or a functional index. We initialize all - * kinds of arrays here to avoid doing extra work at every tuple - * copy. - */ - - if (rel->rd_rel->relhasindex) { - GetIndexRelations(rel->rd_id, &n_indices, &index_rels); - if (n_indices > 0) { - has_index = true; - itupdescArr = - (TupleDesc *)palloc(n_indices * sizeof(TupleDesc)); - pgIndexP = - (IndexTupleForm *)palloc(n_indices * sizeof(IndexTupleForm)); - indexNatts = (int *) palloc(n_indices * sizeof(int)); - finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo)); - finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *)); - indexPred = (Node **) palloc(n_indices * sizeof(Node*)); - econtext = NULL; - for (i = 0; i < n_indices; i++) { - itupdescArr[i] = RelationGetTupleDescriptor(index_rels[i]); - pgIndexTup = - SearchSysCacheTuple(INDEXRELID, - ObjectIdGetDatum(index_rels[i]->rd_id), - 0,0,0); - Assert(pgIndexTup); - pgIndexP[i] = (IndexTupleForm)GETSTRUCT(pgIndexTup); - for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0; - *attnumP != InvalidAttrNumber; - attnumP++, natts++); - if (pgIndexP[i]->indproc != InvalidOid) { - FIgetnArgs(&finfo[i]) = natts; - natts = 1; - FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc; - *(FIgetname(&finfo[i])) = '\0'; - finfoP[i] = &finfo[i]; - } else - finfoP[i] = (FuncIndexInfo *) NULL; - indexNatts[i] = natts; - if (VARSIZE(&pgIndexP[i]->indpred) != 0) { - predString = fmgr(F_TEXTOUT, &pgIndexP[i]->indpred); - indexPred[i] = stringToNode(predString); - pfree(predString); - /* make dummy ExprContext for use by ExecQual */ - if (econtext == NULL) { + int natts; + AttrNumber *attnumP; + Datum *idatum; + int n_indices; + InsertIndexResult indexRes; + TupleDesc tupDesc; + Oid loaded_oid; + bool skip_tuple = false; + + tupDesc = RelationGetTupleDescriptor(rel); + attr = tupDesc->attrs; + attr_count = tupDesc->natts; + + has_index = false; + + /* + * This may be a scalar or a functional index. We initialize all + * kinds of arrays here to avoid doing extra work at every tuple copy. + */ + + if (rel->rd_rel->relhasindex) + { + GetIndexRelations(rel->rd_id, &n_indices, &index_rels); + if (n_indices > 0) + { + has_index = true; + itupdescArr = + (TupleDesc *) palloc(n_indices * sizeof(TupleDesc)); + pgIndexP = + (IndexTupleForm *) palloc(n_indices * sizeof(IndexTupleForm)); + indexNatts = (int *) palloc(n_indices * sizeof(int)); + finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo)); + finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *)); + indexPred = (Node **) palloc(n_indices * sizeof(Node *)); + econtext = NULL; + for (i = 0; i < n_indices; i++) + { + itupdescArr[i] = RelationGetTupleDescriptor(index_rels[i]); + pgIndexTup = + SearchSysCacheTuple(INDEXRELID, + ObjectIdGetDatum(index_rels[i]->rd_id), + 0, 0, 0); + Assert(pgIndexTup); + pgIndexP[i] = (IndexTupleForm) GETSTRUCT(pgIndexTup); + for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0; + *attnumP != InvalidAttrNumber; + attnumP++, natts++); + if (pgIndexP[i]->indproc != InvalidOid) + { + FIgetnArgs(&finfo[i]) = natts; + natts = 1; + FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc; + *(FIgetname(&finfo[i])) = '\0'; + finfoP[i] = &finfo[i]; + } + else + finfoP[i] = (FuncIndexInfo *) NULL; + indexNatts[i] = natts; + if (VARSIZE(&pgIndexP[i]->indpred) != 0) + { + predString = fmgr(F_TEXTOUT, &pgIndexP[i]->indpred); + indexPred[i] = stringToNode(predString); + pfree(predString); + /* make dummy ExprContext for use by ExecQual */ + if (econtext == NULL) + { #ifndef OMIT_PARTIAL_INDEX - tupleTable = ExecCreateTupleTable(1); - slot = ExecAllocTableSlot(tupleTable); - econtext = makeNode(ExprContext); - econtext->ecxt_scantuple = slot; - rtupdesc = RelationGetTupleDescriptor(rel); - slot->ttc_tupleDescriptor = rtupdesc; - /* - * There's no buffer associated with heap tuples here, - * so I set the slot's buffer to NULL. Currently, it - * appears that the only way a buffer could be needed - * would be if the partial index predicate referred to - * the "lock" system attribute. If it did, then - * heap_getattr would call HeapTupleGetRuleLock, which - * uses the buffer's descriptor to get the relation id. - * Rather than try to fix this, I'll just disallow - * partial indexes on "lock", which wouldn't be useful - * anyway. --Nels, Nov '92 - */ - /* SetSlotBuffer(slot, (Buffer) NULL); */ - /* SetSlotShouldFree(slot, false); */ - slot->ttc_buffer = (Buffer)NULL; - slot->ttc_shouldFree = false; -#endif /* OMIT_PARTIAL_INDEX */ - } - } else { - indexPred[i] = NULL; - } - } - } - } - - if (!binary) - { - in_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr)); - elements = (Oid *) palloc(attr_count * sizeof(Oid)); - for (i = 0; i < attr_count; i++) - { - in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); - fmgr_info(in_func_oid, &in_functions[i], &dummy); - elements[i] = GetTypeElement(attr[i]->atttypid); - } - } - else - { - in_functions = NULL; - elements = NULL; - fread(&ntuples, sizeof(int32), 1, fp); - if (ntuples != 0) reading_to_eof = false; - } - - values = (Datum *) palloc(sizeof(Datum) * attr_count); - nulls = (char *) palloc(attr_count); - index_nulls = (char *) palloc(attr_count); - idatum = (Datum *) palloc(sizeof(Datum) * attr_count); - byval = (bool *) palloc(attr_count * sizeof(bool)); - - for (i = 0; i < attr_count; i++) { - nulls[i] = ' '; - index_nulls[i] = ' '; - byval[i] = (bool) IsTypeByVal(attr[i]->atttypid); - } - + tupleTable = ExecCreateTupleTable(1); + slot = ExecAllocTableSlot(tupleTable); + econtext = makeNode(ExprContext); + econtext->ecxt_scantuple = slot; + rtupdesc = RelationGetTupleDescriptor(rel); + slot->ttc_tupleDescriptor = rtupdesc; + + /* + * There's no buffer associated with heap tuples + * here, so I set the slot's buffer to NULL. + * Currently, it appears that the only way a + * buffer could be needed would be if the partial + * index predicate referred to the "lock" system + * attribute. If it did, then heap_getattr would + * call HeapTupleGetRuleLock, which uses the + * buffer's descriptor to get the relation id. + * Rather than try to fix this, I'll just disallow + * partial indexes on "lock", which wouldn't be + * useful anyway. --Nels, Nov '92 + */ + /* SetSlotBuffer(slot, (Buffer) NULL); */ + /* SetSlotShouldFree(slot, false); */ + slot->ttc_buffer = (Buffer) NULL; + slot->ttc_shouldFree = false; +#endif /* OMIT_PARTIAL_INDEX */ + } + } + else + { + indexPred[i] = NULL; + } + } + } + } + + if (!binary) + { + in_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr)); + elements = (Oid *) palloc(attr_count * sizeof(Oid)); + for (i = 0; i < attr_count; i++) + { + in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); + fmgr_info(in_func_oid, &in_functions[i], &dummy); + elements[i] = GetTypeElement(attr[i]->atttypid); + } + } + else + { + in_functions = NULL; + elements = NULL; + fread(&ntuples, sizeof(int32), 1, fp); + if (ntuples != 0) + reading_to_eof = false; + } + + values = (Datum *) palloc(sizeof(Datum) * attr_count); + nulls = (char *) palloc(attr_count); + index_nulls = (char *) palloc(attr_count); + idatum = (Datum *) palloc(sizeof(Datum) * attr_count); + byval = (bool *) palloc(attr_count * sizeof(bool)); + + for (i = 0; i < attr_count; i++) + { + nulls[i] = ' '; + index_nulls[i] = ' '; + byval[i] = (bool) IsTypeByVal(attr[i]->atttypid); + } + #ifdef COPY_DEBUG - lineno = 0; + lineno = 0; #endif - while (!done) { - if (!binary) { + while (!done) + { + if (!binary) + { #ifdef COPY_PATCH - int newline = 0; + int newline = 0; + #endif #ifdef COPY_DEBUG - lineno++; - elog(DEBUG, "line %d", lineno); + lineno++; + elog(DEBUG, "line %d", lineno); #endif - if (oids) { + if (oids) + { #ifdef COPY_PATCH - string = CopyReadAttribute(fp, &isnull, delim, &newline); + string = CopyReadAttribute(fp, &isnull, delim, &newline); #else - string = CopyReadAttribute(fp, &isnull, delim); + string = CopyReadAttribute(fp, &isnull, delim); #endif - if (string == NULL) - done = 1; - else { - loaded_oid = oidin(string); - if (loaded_oid < BootstrapObjectIdData) - elog(WARN, "COPY TEXT: Invalid Oid"); - } - } - for (i = 0; i < attr_count && !done; i++) { + if (string == NULL) + done = 1; + else + { + loaded_oid = oidin(string); + if (loaded_oid < BootstrapObjectIdData) + elog(WARN, "COPY TEXT: Invalid Oid"); + } + } + for (i = 0; i < attr_count && !done; i++) + { #ifdef COPY_PATCH - string = CopyReadAttribute(fp, &isnull, delim, &newline); + string = CopyReadAttribute(fp, &isnull, delim, &newline); #else - string = CopyReadAttribute(fp, &isnull, delim); + string = CopyReadAttribute(fp, &isnull, delim); #endif - if (isnull) { - values[i] = PointerGetDatum(NULL); - nulls[i] = 'n'; - }else if (string == NULL) { - done = 1; - }else { - values[i] = - (Datum)(in_functions[i])(string, - elements[i], - attr[i]->attlen); - /* - * Sanity check - by reference attributes cannot return - * NULL - */ - if (!PointerIsValid(values[i]) && - !(rel->rd_att->attrs[i]->attbyval)) { + if (isnull) + { + values[i] = PointerGetDatum(NULL); + nulls[i] = 'n'; + } + else if (string == NULL) + { + done = 1; + } + else + { + values[i] = + (Datum) (in_functions[i]) (string, + elements[i], + attr[i]->attlen); + + /* + * Sanity check - by reference attributes cannot + * return NULL + */ + if (!PointerIsValid(values[i]) && + !(rel->rd_att->attrs[i]->attbyval)) + { #ifdef COPY_DEBUG - elog(WARN, - "copy from: line %d - Bad file format", lineno); + elog(WARN, + "copy from: line %d - Bad file format", lineno); #else - elog(WARN, "copy from: Bad file format"); + elog(WARN, "copy from: Bad file format"); #endif - } - } - } + } + } + } #ifdef COPY_PATCH - if (!done) { - CopyReadNewline(fp, &newline); - } + if (!done) + { + CopyReadNewline(fp, &newline); + } #endif - }else { /* binary */ - fread(&len, sizeof(int32), 1, fp); - if (feof(fp)) { - done = 1; - }else { - if (oids) { - fread(&loaded_oid, sizeof(int32), 1, fp); - if (loaded_oid < BootstrapObjectIdData) - elog(WARN, "COPY BINARY: Invalid Oid"); - } - fread(&null_ct, sizeof(int32), 1, fp); - if (null_ct > 0) { - for (i = 0; i < null_ct; i++) { - fread(&null_id, sizeof(int32), 1, fp); - nulls[null_id] = 'n'; - } - } - - string = (char *) palloc(len); - fread(string, len, 1, fp); - - ptr = string; - - for (i = 0; i < attr_count; i++) { - if (byval[i] && nulls[i] != 'n') { - - switch(attr[i]->attlen) { - case sizeof(char): - values[i] = (Datum) *(unsigned char *) ptr; - ptr += sizeof(char); - break; - case sizeof(short): - ptr = (char *) SHORTALIGN(ptr); - values[i] = (Datum) *(unsigned short *) ptr; - ptr += sizeof(short); - break; - case sizeof(int32): - ptr = (char *) INTALIGN(ptr); - values[i] = (Datum) *(uint32 *) ptr; - ptr += sizeof(int32); - break; - default: - elog(WARN, "COPY BINARY: impossible size!"); - break; - } - }else if (nulls[i] != 'n') { - switch (attr[i]->attlen) { - case -1: - if (attr[i]->attalign == 'd') - ptr = (char *)DOUBLEALIGN(ptr); - else - ptr = (char *)INTALIGN(ptr); - values[i] = (Datum) ptr; - ptr += * (uint32 *) ptr; - break; - case sizeof(char): - values[i] = (Datum)ptr; - ptr += attr[i]->attlen; - break; - case sizeof(short): - ptr = (char*)SHORTALIGN(ptr); - values[i] = (Datum)ptr; - ptr += attr[i]->attlen; - break; - case sizeof(int32): - ptr = (char*)INTALIGN(ptr); - values[i] = (Datum)ptr; - ptr += attr[i]->attlen; - break; - default: - if (attr[i]->attalign == 'd') - ptr = (char *)DOUBLEALIGN(ptr); - else - ptr = (char *)LONGALIGN(ptr); - values[i] = (Datum) ptr; - ptr += attr[i]->attlen; - } - } - } - } - } - if (done) continue; + } + else + { /* binary */ + fread(&len, sizeof(int32), 1, fp); + if (feof(fp)) + { + done = 1; + } + else + { + if (oids) + { + fread(&loaded_oid, sizeof(int32), 1, fp); + if (loaded_oid < BootstrapObjectIdData) + elog(WARN, "COPY BINARY: Invalid Oid"); + } + fread(&null_ct, sizeof(int32), 1, fp); + if (null_ct > 0) + { + for (i = 0; i < null_ct; i++) + { + fread(&null_id, sizeof(int32), 1, fp); + nulls[null_id] = 'n'; + } + } - /* - * Does it have any sence ? - vadim 12/14/96 - * - tupDesc = CreateTupleDesc(attr_count, attr); - */ - tuple = heap_formtuple(tupDesc, values, nulls); - if (oids) - tuple->t_oid = loaded_oid; - - skip_tuple = false; - /* BEFORE ROW INSERT Triggers */ - if ( rel->trigdesc && - rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0 ) - { - HeapTuple newtuple; - - newtuple = ExecBRInsertTriggers (rel, tuple); - - if ( newtuple == NULL ) /* "do nothing" */ - skip_tuple = true; - else if ( newtuple != tuple ) /* modified by Trigger(s) */ - { - pfree (tuple); - tuple = newtuple; - } - } - - if ( !skip_tuple ) - { - /* ---------------- - * Check the constraints of a tuple - * ---------------- - */ - - if ( rel->rd_att->constr ) - { - HeapTuple newtuple; - - newtuple = ExecConstraints ("CopyFrom", rel, tuple); - - if ( newtuple != tuple ) - { - pfree (tuple); - tuple = newtuple; - } - } - - heap_insert(rel, tuple); - - if (has_index) - { - for (i = 0; i < n_indices; i++) - { - if (indexPred[i] != NULL) - { + string = (char *) palloc(len); + fread(string, len, 1, fp); + + ptr = string; + + for (i = 0; i < attr_count; i++) + { + if (byval[i] && nulls[i] != 'n') + { + + switch (attr[i]->attlen) + { + case sizeof(char): + values[i] = (Datum) * (unsigned char *) ptr; + ptr += sizeof(char); + break; + case sizeof(short): + ptr = (char *) SHORTALIGN(ptr); + values[i] = (Datum) * (unsigned short *) ptr; + ptr += sizeof(short); + break; + case sizeof(int32): + ptr = (char *) INTALIGN(ptr); + values[i] = (Datum) * (uint32 *) ptr; + ptr += sizeof(int32); + break; + default: + elog(WARN, "COPY BINARY: impossible size!"); + break; + } + } + else if (nulls[i] != 'n') + { + switch (attr[i]->attlen) + { + case -1: + if (attr[i]->attalign == 'd') + ptr = (char *) DOUBLEALIGN(ptr); + else + ptr = (char *) INTALIGN(ptr); + values[i] = (Datum) ptr; + ptr += *(uint32 *) ptr; + break; + case sizeof(char): + values[i] = (Datum) ptr; + ptr += attr[i]->attlen; + break; + case sizeof(short): + ptr = (char *) SHORTALIGN(ptr); + values[i] = (Datum) ptr; + ptr += attr[i]->attlen; + break; + case sizeof(int32): + ptr = (char *) INTALIGN(ptr); + values[i] = (Datum) ptr; + ptr += attr[i]->attlen; + break; + default: + if (attr[i]->attalign == 'd') + ptr = (char *) DOUBLEALIGN(ptr); + else + ptr = (char *) LONGALIGN(ptr); + values[i] = (Datum) ptr; + ptr += attr[i]->attlen; + } + } + } + } + } + if (done) + continue; + + /* + * Does it have any sence ? - vadim 12/14/96 + * + * tupDesc = CreateTupleDesc(attr_count, attr); + */ + tuple = heap_formtuple(tupDesc, values, nulls); + if (oids) + tuple->t_oid = loaded_oid; + + skip_tuple = false; + /* BEFORE ROW INSERT Triggers */ + if (rel->trigdesc && + rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) + { + HeapTuple newtuple; + + newtuple = ExecBRInsertTriggers(rel, tuple); + + if (newtuple == NULL) /* "do nothing" */ + skip_tuple = true; + else if (newtuple != tuple) /* modified by Trigger(s) */ + { + pfree(tuple); + tuple = newtuple; + } + } + + if (!skip_tuple) + { + /* ---------------- + * Check the constraints of a tuple + * ---------------- + */ + + if (rel->rd_att->constr) + { + HeapTuple newtuple; + + newtuple = ExecConstraints("CopyFrom", rel, tuple); + + if (newtuple != tuple) + { + pfree(tuple); + tuple = newtuple; + } + } + + heap_insert(rel, tuple); + + if (has_index) + { + for (i = 0; i < n_indices; i++) + { + if (indexPred[i] != NULL) + { #ifndef OMIT_PARTIAL_INDEX - /* - * if tuple doesn't satisfy predicate, - * don't update index - */ - slot->val = tuple; - /*SetSlotContents(slot, tuple); */ - if (ExecQual((List*)indexPred[i], econtext) == false) - continue; -#endif /* OMIT_PARTIAL_INDEX */ - } - FormIndexDatum(indexNatts[i], - (AttrNumber *)&(pgIndexP[i]->indkey[0]), - tuple, - tupDesc, - InvalidBuffer, - idatum, - index_nulls, - finfoP[i]); - indexRes = index_insert(index_rels[i], idatum, index_nulls, - &(tuple->t_ctid), rel); - if (indexRes) pfree(indexRes); - } - } - /* AFTER ROW INSERT Triggers */ - if ( rel->trigdesc && - rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 ) - ExecARInsertTriggers (rel, tuple); - } - - if (binary) pfree(string); - - for (i = 0; i < attr_count; i++) { - if (!byval[i] && nulls[i] != 'n') { - if (!binary) pfree((void*)values[i]); - }else if (nulls[i] == 'n') { - nulls[i] = ' '; - } - } - - pfree(tuple); - tuples_read++; - - if (!reading_to_eof && ntuples == tuples_read) done = true; - } - pfree(values); - if (!binary) pfree(in_functions); - pfree(nulls); - pfree(byval); - heap_close(rel); + + /* + * if tuple doesn't satisfy predicate, don't + * update index + */ + slot->val = tuple; + /* SetSlotContents(slot, tuple); */ + if (ExecQual((List *) indexPred[i], econtext) == false) + continue; +#endif /* OMIT_PARTIAL_INDEX */ + } + FormIndexDatum(indexNatts[i], + (AttrNumber *) & (pgIndexP[i]->indkey[0]), + tuple, + tupDesc, + InvalidBuffer, + idatum, + index_nulls, + finfoP[i]); + indexRes = index_insert(index_rels[i], idatum, index_nulls, + &(tuple->t_ctid), rel); + if (indexRes) + pfree(indexRes); + } + } + /* AFTER ROW INSERT Triggers */ + if (rel->trigdesc && + rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0) + ExecARInsertTriggers(rel, tuple); + } + + if (binary) + pfree(string); + + for (i = 0; i < attr_count; i++) + { + if (!byval[i] && nulls[i] != 'n') + { + if (!binary) + pfree((void *) values[i]); + } + else if (nulls[i] == 'n') + { + nulls[i] = ' '; + } + } + + pfree(tuple); + tuples_read++; + + if (!reading_to_eof && ntuples == tuples_read) + done = true; + } + pfree(values); + if (!binary) + pfree(in_functions); + pfree(nulls); + pfree(byval); + heap_close(rel); } -static Oid +static Oid GetOutputFunction(Oid type) { - HeapTuple typeTuple; - - typeTuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type), - 0,0,0); - - if (HeapTupleIsValid(typeTuple)) - return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput); - - elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type); - return(InvalidOid); + HeapTuple typeTuple; + + typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type), + 0, 0, 0); + + if (HeapTupleIsValid(typeTuple)) + return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput); + + elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type); + return (InvalidOid); } -static Oid +static Oid GetTypeElement(Oid type) { - HeapTuple typeTuple; - - typeTuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type), - 0,0,0); - - - if (HeapTupleIsValid(typeTuple)) - return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem); - - elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type); - return(InvalidOid); + HeapTuple typeTuple; + + typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type), + 0, 0, 0); + + + if (HeapTupleIsValid(typeTuple)) + return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem); + + elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type); + return (InvalidOid); } -static Oid +static Oid GetInputFunction(Oid type) { - HeapTuple typeTuple; - - typeTuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type), - 0,0,0); - - if (HeapTupleIsValid(typeTuple)) - return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typinput); - - elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type); - return(InvalidOid); + HeapTuple typeTuple; + + typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type), + 0, 0, 0); + + if (HeapTupleIsValid(typeTuple)) + return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typinput); + + elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type); + return (InvalidOid); } -static Oid +static Oid IsTypeByVal(Oid type) { - HeapTuple typeTuple; - - typeTuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type), - 0,0,0); - - if (HeapTupleIsValid(typeTuple)) - return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typbyval); - - elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type); - - return(InvalidOid); + HeapTuple typeTuple; + + typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type), + 0, 0, 0); + + if (HeapTupleIsValid(typeTuple)) + return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typbyval); + + elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type); + + return (InvalidOid); } -/* +/* * Given the OID of a relation, return an array of index relation descriptors * and the number of index relations. These relation descriptors are open * using heap_open(). @@ -779,71 +900,77 @@ IsTypeByVal(Oid type) * Space for the array itself is palloc'ed. */ -typedef struct rel_list { - Oid index_rel_oid; - struct rel_list *next; -} RelationList; +typedef struct rel_list +{ + Oid index_rel_oid; + struct rel_list *next; +} RelationList; static void GetIndexRelations(Oid main_relation_oid, - int *n_indices, - Relation **index_rels) + int *n_indices, + Relation ** index_rels) { - RelationList *head, *scan; - Relation pg_index_rel; - HeapScanDesc scandesc; - Oid index_relation_oid; - HeapTuple tuple; - TupleDesc tupDesc; - int i; - bool isnull; - - pg_index_rel = heap_openr(IndexRelationName); - scandesc = heap_beginscan(pg_index_rel, 0, NULL, 0, NULL); - tupDesc = RelationGetTupleDescriptor(pg_index_rel); - - *n_indices = 0; - - head = (RelationList *) palloc(sizeof(RelationList)); - scan = head; - head->next = NULL; - - for (tuple = heap_getnext(scandesc, 0, NULL); - tuple != NULL; - tuple = heap_getnext(scandesc, 0, NULL)) { - - index_relation_oid = - (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer, 2, - tupDesc, &isnull)); - if (index_relation_oid == main_relation_oid) { - scan->index_rel_oid = - (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer, - Anum_pg_index_indexrelid, - tupDesc, &isnull)); - (*n_indices)++; - scan->next = (RelationList *) palloc(sizeof(RelationList)); - scan = scan->next; - } - } - - heap_endscan(scandesc); - heap_close(pg_index_rel); - - /* We cannot trust to relhasindex of the main_relation now, so... */ - if ( *n_indices == 0 ) - return; - - *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation)); - - for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next) { - (*index_rels)[i] = index_open(scan->index_rel_oid); - } - - for (i = 0, scan = head; i < *n_indices + 1; i++) { - scan = head->next; - pfree(head); - head = scan; - } + RelationList *head, + *scan; + Relation pg_index_rel; + HeapScanDesc scandesc; + Oid index_relation_oid; + HeapTuple tuple; + TupleDesc tupDesc; + int i; + bool isnull; + + pg_index_rel = heap_openr(IndexRelationName); + scandesc = heap_beginscan(pg_index_rel, 0, NULL, 0, NULL); + tupDesc = RelationGetTupleDescriptor(pg_index_rel); + + *n_indices = 0; + + head = (RelationList *) palloc(sizeof(RelationList)); + scan = head; + head->next = NULL; + + for (tuple = heap_getnext(scandesc, 0, NULL); + tuple != NULL; + tuple = heap_getnext(scandesc, 0, NULL)) + { + + index_relation_oid = + (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer, 2, + tupDesc, &isnull)); + if (index_relation_oid == main_relation_oid) + { + scan->index_rel_oid = + (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer, + Anum_pg_index_indexrelid, + tupDesc, &isnull)); + (*n_indices)++; + scan->next = (RelationList *) palloc(sizeof(RelationList)); + scan = scan->next; + } + } + + heap_endscan(scandesc); + heap_close(pg_index_rel); + + /* We cannot trust to relhasindex of the main_relation now, so... */ + if (*n_indices == 0) + return; + + *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation)); + + for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next) + { + (*index_rels)[i] = index_open(scan->index_rel_oid); + } + + for (i = 0, scan = head; i < *n_indices + 1; i++) + { + scan = head->next; + pfree(head); + head = scan; + } } #define EXT_ATTLEN 5*8192 @@ -851,20 +978,22 @@ GetIndexRelations(Oid main_relation_oid, /* returns 1 is c is in s */ -static bool -inString(char c, char* s) +static bool +inString(char c, char *s) { - int i; - - if (s) { - i = 0; - while (s[i] != '\0') { - if (s[i] == c) - return 1; - i++; - } - } - return 0; + int i; + + if (s) + { + i = 0; + while (s[i] != '\0') + { + if (s[i] == c) + return 1; + i++; + } + } + return 0; } #ifdef COPY_PATCH @@ -873,19 +1002,21 @@ inString(char c, char* s) */ void -CopyReadNewline(FILE *fp, int *newline) +CopyReadNewline(FILE * fp, int *newline) { - if (!*newline) { + if (!*newline) + { #ifdef COPY_DEBUG - elog(NOTICE, "CopyReadNewline: line %d - extra fields ignored", - lineno); + elog(NOTICE, "CopyReadNewline: line %d - extra fields ignored", + lineno); #else - elog(NOTICE, "CopyReadNewline: line - extra fields ignored"); + elog(NOTICE, "CopyReadNewline: line - extra fields ignored"); #endif - while (!feof(fp) && (getc(fp) != '\n')); - } - *newline = 0; + while (!feof(fp) && (getc(fp) != '\n')); + } + *newline = 0; } + #endif /* @@ -895,148 +1026,167 @@ CopyReadNewline(FILE *fp, int *newline) * can be used as standard input. */ -static char * +static char * #ifdef COPY_PATCH -CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline) +CopyReadAttribute(FILE * fp, bool * isnull, char *delim, int *newline) #else -CopyReadAttribute(FILE *fp, bool *isnull, char *delim) +CopyReadAttribute(FILE * fp, bool * isnull, char *delim) #endif { - static char attribute[EXT_ATTLEN]; - char c; - int done = 0; - int i = 0; - + static char attribute[EXT_ATTLEN]; + char c; + int done = 0; + int i = 0; + #ifdef COPY_PATCH - /* if last delimiter was a newline return a NULL attribute */ - if (*newline) { - *isnull = (bool) true; - return(NULL); - } + /* if last delimiter was a newline return a NULL attribute */ + if (*newline) + { + *isnull = (bool) true; + return (NULL); + } #endif - *isnull = (bool) false; /* set default */ - if (feof(fp)) - return(NULL); - - while (!done) { - c = getc(fp); - - if (feof(fp)) - return(NULL); - else if (c == '\\') { - c = getc(fp); - if (feof(fp)) - return(NULL); - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - int val; - val = VALUE(c); - c = getc(fp); - if (ISOCTAL(c)) { - val = (val<<3) + VALUE(c); - c = getc(fp); - if (ISOCTAL(c)) { - val = (val<<3) + VALUE(c); - } else { - if (feof(fp)) - return(NULL); - ungetc(c, fp); - } - } else { - if (feof(fp)) - return(NULL); - ungetc(c, fp); - } - c = val & 0377; - } - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case 'N': - attribute[0] = '\0'; /* just to be safe */ - *isnull = (bool) true; - break; - case '.': - c = getc(fp); - if (c != '\n') - elog(WARN, "CopyReadAttribute - end of record marker corrupted"); - return(NULL); - break; - } - }else if (inString(c,delim) || c == '\n') { + *isnull = (bool) false; /* set default */ + if (feof(fp)) + return (NULL); + + while (!done) + { + c = getc(fp); + + if (feof(fp)) + return (NULL); + else if (c == '\\') + { + c = getc(fp); + if (feof(fp)) + return (NULL); + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int val; + + val = VALUE(c); + c = getc(fp); + if (ISOCTAL(c)) + { + val = (val << 3) + VALUE(c); + c = getc(fp); + if (ISOCTAL(c)) + { + val = (val << 3) + VALUE(c); + } + else + { + if (feof(fp)) + return (NULL); + ungetc(c, fp); + } + } + else + { + if (feof(fp)) + return (NULL); + ungetc(c, fp); + } + c = val & 0377; + } + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case 'N': + attribute[0] = '\0'; /* just to be safe */ + *isnull = (bool) true; + break; + case '.': + c = getc(fp); + if (c != '\n') + elog(WARN, "CopyReadAttribute - end of record marker corrupted"); + return (NULL); + break; + } + } + else if (inString(c, delim) || c == '\n') + { #ifdef COPY_PATCH - if (c == '\n') { - *newline = 1; - } + if (c == '\n') + { + *newline = 1; + } #endif - done = 1; - } - if (!done) attribute[i++] = c; - if (i == EXT_ATTLEN - 1) - elog(WARN, "CopyReadAttribute - attribute length too long"); - } - attribute[i] = '\0'; - return(&attribute[0]); + done = 1; + } + if (!done) + attribute[i++] = c; + if (i == EXT_ATTLEN - 1) + elog(WARN, "CopyReadAttribute - attribute length too long"); + } + attribute[i] = '\0'; + return (&attribute[0]); } static void -CopyAttributeOut(FILE *fp, char *string, char *delim) +CopyAttributeOut(FILE * fp, char *string, char *delim) { - char c; - int is_array = false; - int len = strlen(string); - - /* XXX - This is a kludge, we should check the data type */ - if (len && (string[0] == '{') && (string[len-1] == '}')) - is_array = true; - - for ( ; (c = *string) != '\0'; string++) { - if (c == delim[0] || c == '\n' || - (c == '\\' && !is_array)) - fputc('\\', fp); - else - if (c == '\\' && is_array) - if (*(string+1) == '\\') { - /* translate \\ to \\\\ */ - fputc('\\', fp); - fputc('\\', fp); - fputc('\\', fp); - string++; - } else if (*(string+1) == '"') { - /* translate \" to \\\" */ - fputc('\\', fp); - fputc('\\', fp); - } - fputc(*string, fp); - } + char c; + int is_array = false; + int len = strlen(string); + + /* XXX - This is a kludge, we should check the data type */ + if (len && (string[0] == '{') && (string[len - 1] == '}')) + is_array = true; + + for (; (c = *string) != '\0'; string++) + { + if (c == delim[0] || c == '\n' || + (c == '\\' && !is_array)) + fputc('\\', fp); + else if (c == '\\' && is_array) + if (*(string + 1) == '\\') + { + /* translate \\ to \\\\ */ + fputc('\\', fp); + fputc('\\', fp); + fputc('\\', fp); + string++; + } + else if (*(string + 1) == '"') + { + /* translate \" to \\\" */ + fputc('\\', fp); + fputc('\\', fp); + } + fputc(*string, fp); + } } /* - * Returns the number of tuples in a relation. Unfortunately, currently + * Returns the number of tuples in a relation. Unfortunately, currently * must do a scan of the entire relation to determine this. * * relation is expected to be an open relation descriptor. @@ -1044,17 +1194,17 @@ CopyAttributeOut(FILE *fp, char *string, char *delim) static int CountTuples(Relation relation) { - HeapScanDesc scandesc; - HeapTuple tuple; - - int i; - - scandesc = heap_beginscan(relation, 0, NULL, 0, NULL); - - for (tuple = heap_getnext(scandesc, 0, NULL), i = 0; - tuple != NULL; - tuple = heap_getnext(scandesc, 0, NULL), i++) - ; - heap_endscan(scandesc); - return(i); + HeapScanDesc scandesc; + HeapTuple tuple; + + int i; + + scandesc = heap_beginscan(relation, 0, NULL, 0, NULL); + + for (tuple = heap_getnext(scandesc, 0, NULL), i = 0; + tuple != NULL; + tuple = heap_getnext(scandesc, 0, NULL), i++) + ; + heap_endscan(scandesc); + return (i); } |