]> granicus.if.org Git - postgresql/blob - src/backend/commands/copy.c
4ad772d0a38c6657af39e3f8645ada6f511823a6
[postgresql] / src / backend / commands / copy.c
1 /*-------------------------------------------------------------------------
2  *
3  * copy.c--
4  *
5  * Copyright (c) 1994, Regents of the University of California
6  *
7  *
8  * IDENTIFICATION
9  *        $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.49 1998/07/15 18:53:40 momjian Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13
14 #include <string.h>
15 #include <unistd.h>
16
17 #include <postgres.h>
18
19 #include <access/heapam.h>
20 #include <tcop/dest.h>
21 #include <fmgr.h>
22 #include <miscadmin.h>
23 #include <utils/builtins.h>
24 #include <utils/acl.h>
25 #include <sys/stat.h>
26 #include <catalog/pg_index.h>
27 #include <utils/syscache.h>
28 #include <utils/memutils.h>
29 #include <executor/executor.h>
30 #include <access/transam.h>
31 #include <catalog/index.h>
32 #include <access/genam.h>
33 #include <catalog/pg_type.h>
34 #include <catalog/catname.h>
35 #include <catalog/pg_shadow.h>
36 #include <commands/copy.h>
37 #include "commands/trigger.h"
38 #include <storage/fd.h>
39
40 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
41 #define VALUE(c) ((c) - '0')
42
43
44 /* non-export function prototypes */
45 static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
46 static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
47 static Oid      GetOutputFunction(Oid type);
48 static Oid      GetTypeElement(Oid type);
49 static Oid      GetInputFunction(Oid type);
50 static Oid      IsTypeByVal(Oid type);
51 static void
52 GetIndexRelations(Oid main_relation_oid,
53                                   int *n_indices,
54                                   Relation **index_rels);
55
56 #ifdef COPY_PATCH
57 static void CopyReadNewline(FILE *fp, int *newline);
58 static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline);
59
60 #else
61 static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim);
62
63 #endif
64 static void CopyAttributeOut(FILE *fp, char *string, char *delim, int is_array);
65 static int      CountTuples(Relation relation);
66
67 extern FILE *Pfout,
68                    *Pfin;
69
70 static int      lineno;
71
72 /*
73  *       DoCopy executes a the SQL COPY statement.
74  */
75
76 void
77 DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
78            char *filename, char *delim)
79 {
80 /*----------------------------------------------------------------------------
81   Either unload or reload contents of class <relname>, depending on <from>.
82
83   If <pipe> is false, transfer is between the class and the file named
84   <filename>.  Otherwise, transfer is between the class and our regular
85   input/output stream.  The latter could be either stdin/stdout or a
86   socket, depending on whether we're running under Postmaster control.
87
88   Iff <binary>, unload or reload in the binary format, as opposed to the
89   more wasteful but more robust and portable text format.
90
91   If in the text format, delimit columns with delimiter <delim>.
92
93   When loading in the text format from an input stream (as opposed to
94   a file), recognize a "." on a line by itself as EOF.  Also recognize
95   a stream EOF.  When unloading in the text format to an output stream,
96   write a "." on a line by itself at the end of the data.
97
98   Iff <oids>, unload or reload the format that includes OID information.
99
100   Do not allow a Postgres user without superuser privilege to read from
101   or write to a file.
102
103   Do not allow the copy if user doesn't have proper permission to access
104   the class.
105 ----------------------------------------------------------------------------*/
106
107         FILE       *fp;
108         Relation        rel;
109         extern char *UserName;          /* defined in global.c */
110         const AclMode required_access = from ? ACL_WR : ACL_RD;
111         int                     result;
112
113         rel = heap_openr(relname);
114         if (rel == NULL)
115                 elog(ERROR, "COPY command failed.  Class %s "
116                          "does not exist.", relname);
117
118         result = pg_aclcheck(relname, UserName, required_access);
119         if (result != ACLCHECK_OK)
120                 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[result]);
121         /* Above should not return */
122         else if (!superuser() && !pipe)
123                 elog(ERROR, "You must have Postgres superuser privilege to do a COPY "
124                          "directly to or from a file.  Anyone can COPY to stdout or "
125                          "from stdin.  Psql's \\copy command also works for anyone.");
126         /* Above should not return. */
127         else
128         {
129                 if (from)
130                 {                                               /* copy from file to database */
131                         if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
132                                 elog(ERROR, "You can't change sequence relation %s", relname);
133                         if (pipe)
134                         {
135                                 if (IsUnderPostmaster)
136                                 {
137                                         ReceiveCopyBegin();
138                                         fp = Pfin;
139                                 }
140                                 else
141                                         fp = stdin;
142                         }
143                         else
144                         {
145                                 fp = AllocateFile(filename, "r");
146                                 if (fp == NULL)
147                                         elog(ERROR, "COPY command, running in backend with "
148                                                  "effective uid %d, could not open file '%s' for "
149                                                  "reading.  Errno = %s (%d).",
150                                                  geteuid(), filename, strerror(errno), errno);
151                                 /* Above should not return */
152                         }
153                         CopyFrom(rel, binary, oids, fp, delim);
154                 }
155                 else
156                 {                                               /* copy from database to file */
157                         if (pipe)
158                         {
159                                 if (IsUnderPostmaster)
160                                 {
161                                         SendCopyBegin();
162                                         fp = Pfout;
163                                 }
164                                 else
165                                         fp = stdout;
166                         }
167                         else
168                         {
169                                 mode_t          oumask;         /* Pre-existing umask value */
170
171                                 oumask = umask((mode_t) 0);
172                                 fp = AllocateFile(filename, "w");
173                                 umask(oumask);
174                                 if (fp == NULL)
175                                         elog(ERROR, "COPY command, running in backend with "
176                                                  "effective uid %d, could not open file '%s' for "
177                                                  "writing.  Errno = %s (%d).",
178                                                  geteuid(), filename, strerror(errno), errno);
179                                 /* Above should not return */
180                         }
181                         CopyTo(rel, binary, oids, fp, delim);
182                 }
183                 if (!pipe)
184                         FreeFile(fp);
185                 else if (!from && !binary)
186                 {
187                         fputs("\\.\n", fp);
188                         if (IsUnderPostmaster)
189                                 fflush(Pfout);
190                 }
191         }
192 }
193
194
195
196 static void
197 CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
198 {
199         HeapTuple       tuple;
200         HeapScanDesc scandesc;
201
202         int32           attr_count,
203                                 i;
204         AttributeTupleForm *attr;
205         FmgrInfo   *out_functions;
206         Oid                     out_func_oid;
207         Oid                *elements;
208         int32      *typmod;
209         Datum           value;
210         bool            isnull;                 /* The attribute we are copying is null */
211         char       *nulls;
212
213         /*
214          * <nulls> is a (dynamically allocated) array with one character per
215          * attribute in the instance being copied.      nulls[I-1] is 'n' if
216          * Attribute Number I is null, and ' ' otherwise.
217          *
218          * <nulls> is meaningful only if we are doing a binary copy.
219          */
220         char       *string;
221         int32           ntuples;
222         TupleDesc       tupDesc;
223
224         scandesc = heap_beginscan(rel, 0, false, 0, NULL);
225
226         attr_count = rel->rd_att->natts;
227         attr = rel->rd_att->attrs;
228         tupDesc = rel->rd_att;
229
230         if (!binary)
231         {
232                 out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
233                 elements = (Oid *) palloc(attr_count * sizeof(Oid));
234                 typmod = (int32 *) palloc(attr_count * sizeof(int32));
235                 for (i = 0; i < attr_count; i++)
236                 {
237                         out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid);
238                         fmgr_info(out_func_oid, &out_functions[i]);
239                         elements[i] = GetTypeElement(attr[i]->atttypid);
240                         typmod[i] = attr[i]->atttypmod;
241                 }
242                 nulls = NULL;                   /* meaningless, but compiler doesn't know
243                                                                  * that */
244         }
245         else
246         {
247                 elements = NULL;
248                 typmod = NULL;
249                 out_functions = NULL;
250                 nulls = (char *) palloc(attr_count);
251                 for (i = 0; i < attr_count; i++)
252                         nulls[i] = ' ';
253
254                 /* XXX expensive */
255
256                 ntuples = CountTuples(rel);
257                 fwrite(&ntuples, sizeof(int32), 1, fp);
258         }
259
260         for (tuple = heap_getnext(scandesc, 0, NULL);
261                  tuple != NULL;
262                  tuple = heap_getnext(scandesc, 0, NULL))
263         {
264
265                 if (oids && !binary)
266                 {
267                         fputs(oidout(tuple->t_oid), fp);
268                         fputc(delim[0], fp);
269                 }
270
271                 for (i = 0; i < attr_count; i++)
272                 {
273                         value = heap_getattr(tuple, i + 1, tupDesc, &isnull);
274                         if (!binary)
275                         {
276                                 if (!isnull)
277                                 {
278                                         string = (char *) (*fmgr_faddr(&out_functions[i]))
279                                                 (value, elements[i], typmod[i]);
280                                         CopyAttributeOut(fp, string, delim, attr[i]->attnelems);
281                                         pfree(string);
282                                 }
283                                 else
284                                         fputs("\\N", fp);       /* null indicator */
285
286                                 if (i == attr_count - 1)
287                                         fputc('\n', fp);
288                                 else
289                                 {
290
291                                         /*
292                                          * when copying out, only use the first char of the
293                                          * delim string
294                                          */
295                                         fputc(delim[0], fp);
296                                 }
297                         }
298                         else
299                         {
300
301                                 /*
302                                  * only interesting thing heap_getattr tells us in this
303                                  * case is if we have a null attribute or not.
304                                  */
305                                 if (isnull)
306                                         nulls[i] = 'n';
307                         }
308                 }
309
310                 if (binary)
311                 {
312                         int32           null_ct = 0,
313                                                 length;
314
315                         for (i = 0; i < attr_count; i++)
316                         {
317                                 if (nulls[i] == 'n')
318                                         null_ct++;
319                         }
320
321                         length = tuple->t_len - tuple->t_hoff;
322                         fwrite(&length, sizeof(int32), 1, fp);
323                         if (oids)
324                                 fwrite((char *) &tuple->t_oid, sizeof(int32), 1, fp);
325
326                         fwrite(&null_ct, sizeof(int32), 1, fp);
327                         if (null_ct > 0)
328                         {
329                                 for (i = 0; i < attr_count; i++)
330                                 {
331                                         if (nulls[i] == 'n')
332                                         {
333                                                 fwrite(&i, sizeof(int32), 1, fp);
334                                                 nulls[i] = ' ';
335                                         }
336                                 }
337                         }
338                         fwrite((char *) tuple + tuple->t_hoff, length, 1, fp);
339                 }
340         }
341
342         heap_endscan(scandesc);
343         if (binary)
344                 pfree(nulls);
345         else
346         {
347                 pfree(out_functions);
348                 pfree(elements);
349                 pfree(typmod);
350         }
351
352         heap_close(rel);
353 }
354
355 static void
356 CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
357 {
358         HeapTuple       tuple;
359         AttrNumber      attr_count;
360         AttributeTupleForm *attr;
361         FmgrInfo   *in_functions;
362         int                     i;
363         Oid                     in_func_oid;
364         Datum      *values;
365         char       *nulls,
366                            *index_nulls;
367         bool       *byval;
368         bool            isnull;
369         bool            has_index;
370         int                     done = 0;
371         char       *string = NULL,
372                            *ptr;
373         Relation   *index_rels;
374         int32           len,
375                                 null_ct,
376                                 null_id;
377         int32           ntuples,
378                                 tuples_read = 0;
379         bool            reading_to_eof = true;
380         Oid                *elements;
381         int32      *typmod;
382         FuncIndexInfo *finfo,
383                           **finfoP = NULL;
384         TupleDesc  *itupdescArr;
385         HeapTuple       pgIndexTup;
386         IndexTupleForm *pgIndexP = NULL;
387         int                *indexNatts = NULL;
388         char       *predString;
389         Node      **indexPred = NULL;
390         TupleDesc       rtupdesc;
391         ExprContext *econtext = NULL;
392
393 #ifndef OMIT_PARTIAL_INDEX
394         TupleTable      tupleTable;
395         TupleTableSlot *slot = NULL;
396
397 #endif
398         int                     natts;
399         AttrNumber *attnumP;
400         Datum      *idatum;
401         int                     n_indices;
402         InsertIndexResult indexRes;
403         TupleDesc       tupDesc;
404         Oid                     loaded_oid;
405         bool            skip_tuple = false;
406
407         tupDesc = RelationGetTupleDescriptor(rel);
408         attr = tupDesc->attrs;
409         attr_count = tupDesc->natts;
410
411         has_index = false;
412
413         /*
414          * This may be a scalar or a functional index.  We initialize all
415          * kinds of arrays here to avoid doing extra work at every tuple copy.
416          */
417
418         if (rel->rd_rel->relhasindex)
419         {
420                 GetIndexRelations(rel->rd_id, &n_indices, &index_rels);
421                 if (n_indices > 0)
422                 {
423                         has_index = true;
424                         itupdescArr =
425                                 (TupleDesc *) palloc(n_indices * sizeof(TupleDesc));
426                         pgIndexP =
427                                 (IndexTupleForm *) palloc(n_indices * sizeof(IndexTupleForm));
428                         indexNatts = (int *) palloc(n_indices * sizeof(int));
429                         finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
430                         finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
431                         indexPred = (Node **) palloc(n_indices * sizeof(Node *));
432                         econtext = NULL;
433                         for (i = 0; i < n_indices; i++)
434                         {
435                                 itupdescArr[i] = RelationGetTupleDescriptor(index_rels[i]);
436                                 pgIndexTup =
437                                         SearchSysCacheTuple(INDEXRELID,
438                                                                   ObjectIdGetDatum(index_rels[i]->rd_id),
439                                                                                 0, 0, 0);
440                                 Assert(pgIndexTup);
441                                 pgIndexP[i] = (IndexTupleForm) GETSTRUCT(pgIndexTup);
442                                 for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
443                                          *attnumP != InvalidAttrNumber;
444                                          attnumP++, natts++);
445                                 if (pgIndexP[i]->indproc != InvalidOid)
446                                 {
447                                         FIgetnArgs(&finfo[i]) = natts;
448                                         natts = 1;
449                                         FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc;
450                                         *(FIgetname(&finfo[i])) = '\0';
451                                         finfoP[i] = &finfo[i];
452                                 }
453                                 else
454                                         finfoP[i] = (FuncIndexInfo *) NULL;
455                                 indexNatts[i] = natts;
456                                 if (VARSIZE(&pgIndexP[i]->indpred) != 0)
457                                 {
458                                         predString = fmgr(F_TEXTOUT, &pgIndexP[i]->indpred);
459                                         indexPred[i] = stringToNode(predString);
460                                         pfree(predString);
461                                         /* make dummy ExprContext for use by ExecQual */
462                                         if (econtext == NULL)
463                                         {
464 #ifndef OMIT_PARTIAL_INDEX
465                                                 tupleTable = ExecCreateTupleTable(1);
466                                                 slot = ExecAllocTableSlot(tupleTable);
467                                                 econtext = makeNode(ExprContext);
468                                                 econtext->ecxt_scantuple = slot;
469                                                 rtupdesc = RelationGetTupleDescriptor(rel);
470                                                 slot->ttc_tupleDescriptor = rtupdesc;
471
472                                                 /*
473                                                  * There's no buffer associated with heap tuples
474                                                  * here, so I set the slot's buffer to NULL.
475                                                  * Currently, it appears that the only way a
476                                                  * buffer could be needed would be if the partial
477                                                  * index predicate referred to the "lock" system
478                                                  * attribute.  If it did, then heap_getattr would
479                                                  * call HeapTupleGetRuleLock, which uses the
480                                                  * buffer's descriptor to get the relation id.
481                                                  * Rather than try to fix this, I'll just disallow
482                                                  * partial indexes on "lock", which wouldn't be
483                                                  * useful anyway. --Nels, Nov '92
484                                                  */
485                                                 /* SetSlotBuffer(slot, (Buffer) NULL); */
486                                                 /* SetSlotShouldFree(slot, false); */
487                                                 slot->ttc_buffer = (Buffer) NULL;
488                                                 slot->ttc_shouldFree = false;
489 #endif                                                  /* OMIT_PARTIAL_INDEX */
490                                         }
491                                 }
492                                 else
493                                         indexPred[i] = NULL;
494                         }
495                 }
496         }
497
498         if (!binary)
499         {
500                 in_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
501                 elements = (Oid *) palloc(attr_count * sizeof(Oid));
502                 typmod = (int32 *) palloc(attr_count * sizeof(int32));
503                 for (i = 0; i < attr_count; i++)
504                 {
505                         in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
506                         fmgr_info(in_func_oid, &in_functions[i]);
507                         elements[i] = GetTypeElement(attr[i]->atttypid);
508                         typmod[i] = attr[i]->atttypmod;
509                 }
510         }
511         else
512         {
513                 in_functions = NULL;
514                 elements = NULL;
515                 typmod = NULL;
516                 fread(&ntuples, sizeof(int32), 1, fp);
517                 if (ntuples != 0)
518                         reading_to_eof = false;
519         }
520
521         values = (Datum *) palloc(sizeof(Datum) * attr_count);
522         nulls = (char *) palloc(attr_count);
523         index_nulls = (char *) palloc(attr_count);
524         idatum = (Datum *) palloc(sizeof(Datum) * attr_count);
525         byval = (bool *) palloc(attr_count * sizeof(bool));
526
527         for (i = 0; i < attr_count; i++)
528         {
529                 nulls[i] = ' ';
530                 index_nulls[i] = ' ';
531                 byval[i] = (bool) IsTypeByVal(attr[i]->atttypid);
532         }
533
534         lineno = 0;
535         while (!done)
536         {
537                 if (!binary)
538                 {
539 #ifdef COPY_PATCH
540                         int                     newline = 0;
541
542 #endif
543                         lineno++;
544                         if (oids)
545                         {
546 #ifdef COPY_PATCH
547                                 string = CopyReadAttribute(fp, &isnull, delim, &newline);
548 #else
549                                 string = CopyReadAttribute(fp, &isnull, delim);
550 #endif
551                                 if (string == NULL)
552                                         done = 1;
553                                 else
554                                 {
555                                         loaded_oid = oidin(string);
556                                         if (loaded_oid < BootstrapObjectIdData)
557                                                 elog(ERROR, "COPY TEXT: Invalid Oid. line: %d", lineno);
558                                 }
559                         }
560                         for (i = 0; i < attr_count && !done; i++)
561                         {
562 #ifdef COPY_PATCH
563                                 string = CopyReadAttribute(fp, &isnull, delim, &newline);
564 #else
565                                 string = CopyReadAttribute(fp, &isnull, delim);
566 #endif
567                                 if (isnull)
568                                 {
569                                         values[i] = PointerGetDatum(NULL);
570                                         nulls[i] = 'n';
571                                 }
572                                 else if (string == NULL)
573                                         done = 1;
574                                 else
575                                 {
576                                         values[i] =
577                                                 (Datum) (*fmgr_faddr(&in_functions[i])) (string,
578                                                                                                                          elements[i],
579                                                                                                                           typmod[i]);
580
581                                         /*
582                                          * Sanity check - by reference attributes cannot
583                                          * return NULL
584                                          */
585                                         if (!PointerIsValid(values[i]) &&
586                                                 !(rel->rd_att->attrs[i]->attbyval))
587                                                 elog(ERROR, "copy from line %d: Bad file format", lineno);
588                                 }
589                         }
590 #ifdef COPY_PATCH
591                         if (!done)
592                                 CopyReadNewline(fp, &newline);
593 #endif
594                 }
595                 else
596                 {                                               /* binary */
597                         fread(&len, sizeof(int32), 1, fp);
598                         if (feof(fp))
599                                 done = 1;
600                         else
601                         {
602                                 if (oids)
603                                 {
604                                         fread(&loaded_oid, sizeof(int32), 1, fp);
605                                         if (loaded_oid < BootstrapObjectIdData)
606                                                 elog(ERROR, "COPY BINARY: Invalid Oid line: %d", lineno);
607                                 }
608                                 fread(&null_ct, sizeof(int32), 1, fp);
609                                 if (null_ct > 0)
610                                 {
611                                         for (i = 0; i < null_ct; i++)
612                                         {
613                                                 fread(&null_id, sizeof(int32), 1, fp);
614                                                 nulls[null_id] = 'n';
615                                         }
616                                 }
617
618                                 string = (char *) palloc(len);
619                                 fread(string, len, 1, fp);
620
621                                 ptr = string;
622
623                                 for (i = 0; i < attr_count; i++)
624                                 {
625                                         if (byval[i] && nulls[i] != 'n')
626                                         {
627
628                                                 switch (attr[i]->attlen)
629                                                 {
630                                                         case sizeof(char):
631                                                                 values[i] = (Datum) *(unsigned char *) ptr;
632                                                                 ptr += sizeof(char);
633                                                                 break;
634                                                         case sizeof(short):
635                                                                 ptr = (char *) SHORTALIGN(ptr);
636                                                                 values[i] = (Datum) *(unsigned short *) ptr;
637                                                                 ptr += sizeof(short);
638                                                                 break;
639                                                         case sizeof(int32):
640                                                                 ptr = (char *) INTALIGN(ptr);
641                                                                 values[i] = (Datum) *(uint32 *) ptr;
642                                                                 ptr += sizeof(int32);
643                                                                 break;
644                                                         default:
645                                                                 elog(ERROR, "COPY BINARY: impossible size! line: %d", lineno);
646                                                                 break;
647                                                 }
648                                         }
649                                         else if (nulls[i] != 'n')
650                                         {
651                                                 switch (attr[i]->attlen)
652                                                 {
653                                                         case -1:
654                                                                 if (attr[i]->attalign == 'd')
655                                                                         ptr = (char *) DOUBLEALIGN(ptr);
656                                                                 else
657                                                                         ptr = (char *) INTALIGN(ptr);
658                                                                 values[i] = (Datum) ptr;
659                                                                 ptr += *(uint32 *) ptr;
660                                                                 break;
661                                                         case sizeof(char):
662                                                                 values[i] = (Datum) ptr;
663                                                                 ptr += attr[i]->attlen;
664                                                                 break;
665                                                         case sizeof(short):
666                                                                 ptr = (char *) SHORTALIGN(ptr);
667                                                                 values[i] = (Datum) ptr;
668                                                                 ptr += attr[i]->attlen;
669                                                                 break;
670                                                         case sizeof(int32):
671                                                                 ptr = (char *) INTALIGN(ptr);
672                                                                 values[i] = (Datum) ptr;
673                                                                 ptr += attr[i]->attlen;
674                                                                 break;
675                                                         default:
676                                                                 if (attr[i]->attalign == 'd')
677                                                                         ptr = (char *) DOUBLEALIGN(ptr);
678                                                                 else
679                                                                         ptr = (char *) LONGALIGN(ptr);
680                                                                 values[i] = (Datum) ptr;
681                                                                 ptr += attr[i]->attlen;
682                                                 }
683                                         }
684                                 }
685                         }
686                 }
687                 if (done)
688                         continue;
689
690                 /*
691                  * Does it have any sence ? - vadim 12/14/96
692                  *
693                  * tupDesc = CreateTupleDesc(attr_count, attr);
694                  */
695                 tuple = heap_formtuple(tupDesc, values, nulls);
696                 if (oids)
697                         tuple->t_oid = loaded_oid;
698
699                 skip_tuple = false;
700                 /* BEFORE ROW INSERT Triggers */
701                 if (rel->trigdesc &&
702                         rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
703                 {
704                         HeapTuple       newtuple;
705
706                         newtuple = ExecBRInsertTriggers(rel, tuple);
707
708                         if (newtuple == NULL)           /* "do nothing" */
709                                 skip_tuple = true;
710                         else if (newtuple != tuple) /* modified by Trigger(s) */
711                         {
712                                 pfree(tuple);
713                                 tuple = newtuple;
714                         }
715                 }
716
717                 if (!skip_tuple)
718                 {
719                         /* ----------------
720                          * Check the constraints of a tuple
721                          * ----------------
722                          */
723
724                         if (rel->rd_att->constr)
725                         {
726                                 HeapTuple       newtuple;
727
728                                 newtuple = ExecConstraints("CopyFrom", rel, tuple);
729
730                                 if (newtuple != tuple)
731                                 {
732                                         pfree(tuple);
733                                         tuple = newtuple;
734                                 }
735                         }
736
737                         heap_insert(rel, tuple);
738
739                         if (has_index)
740                         {
741                                 for (i = 0; i < n_indices; i++)
742                                 {
743                                         if (indexPred[i] != NULL)
744                                         {
745 #ifndef OMIT_PARTIAL_INDEX
746
747                                                 /*
748                                                  * if tuple doesn't satisfy predicate, don't
749                                                  * update index
750                                                  */
751                                                 slot->val = tuple;
752                                                 /* SetSlotContents(slot, tuple); */
753                                                 if (ExecQual((List *) indexPred[i], econtext) == false)
754                                                         continue;
755 #endif                                                  /* OMIT_PARTIAL_INDEX */
756                                         }
757                                         FormIndexDatum(indexNatts[i],
758                                                                 (AttrNumber *) &(pgIndexP[i]->indkey[0]),
759                                                                    tuple,
760                                                                    tupDesc,
761                                                                    InvalidBuffer,
762                                                                    idatum,
763                                                                    index_nulls,
764                                                                    finfoP[i]);
765                                         indexRes = index_insert(index_rels[i], idatum, index_nulls,
766                                                                                         &(tuple->t_ctid), rel);
767                                         if (indexRes)
768                                                 pfree(indexRes);
769                                 }
770                         }
771                         /* AFTER ROW INSERT Triggers */
772                         if (rel->trigdesc &&
773                                 rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
774                                 ExecARInsertTriggers(rel, tuple);
775                 }
776
777                 if (binary)
778                         pfree(string);
779
780                 for (i = 0; i < attr_count; i++)
781                 {
782                         if (!byval[i] && nulls[i] != 'n')
783                         {
784                                 if (!binary)
785                                         pfree((void *) values[i]);
786                         }
787                         else if (nulls[i] == 'n')
788                                 nulls[i] = ' ';
789                 }
790
791                 pfree(tuple);
792                 tuples_read++;
793
794                 if (!reading_to_eof && ntuples == tuples_read)
795                         done = true;
796         }
797         pfree(values);
798         pfree(nulls);
799         if (!binary)
800         {
801                 pfree(in_functions);
802                 pfree(elements);
803                 pfree(typmod);
804         }
805         pfree(byval);
806         heap_close(rel);
807 }
808
809
810
811 static Oid
812 GetOutputFunction(Oid type)
813 {
814         HeapTuple       typeTuple;
815
816         typeTuple = SearchSysCacheTuple(TYPOID,
817                                                                         ObjectIdGetDatum(type),
818                                                                         0, 0, 0);
819
820         if (HeapTupleIsValid(typeTuple))
821                 return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput);
822
823         elog(ERROR, "GetOutputFunction: Cache lookup of type %d failed", type);
824         return (InvalidOid);
825 }
826
827 static Oid
828 GetTypeElement(Oid type)
829 {
830         HeapTuple       typeTuple;
831
832         typeTuple = SearchSysCacheTuple(TYPOID,
833                                                                         ObjectIdGetDatum(type),
834                                                                         0, 0, 0);
835
836
837         if (HeapTupleIsValid(typeTuple))
838                 return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem);
839
840         elog(ERROR, "GetOutputFunction: Cache lookup of type %d failed", type);
841         return (InvalidOid);
842 }
843
844 static Oid
845 GetInputFunction(Oid type)
846 {
847         HeapTuple       typeTuple;
848
849         typeTuple = SearchSysCacheTuple(TYPOID,
850                                                                         ObjectIdGetDatum(type),
851                                                                         0, 0, 0);
852
853         if (HeapTupleIsValid(typeTuple))
854                 return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typinput);
855
856         elog(ERROR, "GetInputFunction: Cache lookup of type %d failed", type);
857         return (InvalidOid);
858 }
859
860 static Oid
861 IsTypeByVal(Oid type)
862 {
863         HeapTuple       typeTuple;
864
865         typeTuple = SearchSysCacheTuple(TYPOID,
866                                                                         ObjectIdGetDatum(type),
867                                                                         0, 0, 0);
868
869         if (HeapTupleIsValid(typeTuple))
870                 return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typbyval);
871
872         elog(ERROR, "GetInputFunction: Cache lookup of type %d failed", type);
873
874         return (InvalidOid);
875 }
876
877 /*
878  * Given the OID of a relation, return an array of index relation descriptors
879  * and the number of index relations.  These relation descriptors are open
880  * using heap_open().
881  *
882  * Space for the array itself is palloc'ed.
883  */
884
885 typedef struct rel_list
886 {
887         Oid                     index_rel_oid;
888         struct rel_list *next;
889 } RelationList;
890
891 static void
892 GetIndexRelations(Oid main_relation_oid,
893                                   int *n_indices,
894                                   Relation **index_rels)
895 {
896         RelationList *head,
897                            *scan;
898         Relation        pg_index_rel;
899         HeapScanDesc scandesc;
900         Oid                     index_relation_oid;
901         HeapTuple       tuple;
902         TupleDesc       tupDesc;
903         int                     i;
904         bool            isnull;
905
906         pg_index_rel = heap_openr(IndexRelationName);
907         scandesc = heap_beginscan(pg_index_rel, 0, false, 0, NULL);
908         tupDesc = RelationGetTupleDescriptor(pg_index_rel);
909
910         *n_indices = 0;
911
912         head = (RelationList *) palloc(sizeof(RelationList));
913         scan = head;
914         head->next = NULL;
915
916         for (tuple = heap_getnext(scandesc, 0, NULL);
917                  tuple != NULL;
918                  tuple = heap_getnext(scandesc, 0, NULL))
919         {
920
921                 index_relation_oid =
922                         (Oid) DatumGetInt32(heap_getattr(tuple, 2,
923                                                                                          tupDesc, &isnull));
924                 if (index_relation_oid == main_relation_oid)
925                 {
926                         scan->index_rel_oid =
927                                 (Oid) DatumGetInt32(heap_getattr(tuple,
928                                                                                                  Anum_pg_index_indexrelid,
929                                                                                                  tupDesc, &isnull));
930                         (*n_indices)++;
931                         scan->next = (RelationList *) palloc(sizeof(RelationList));
932                         scan = scan->next;
933                 }
934         }
935
936         heap_endscan(scandesc);
937         heap_close(pg_index_rel);
938
939         /* We cannot trust to relhasindex of the main_relation now, so... */
940         if (*n_indices == 0)
941                 return;
942
943         *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
944
945         for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
946                 (*index_rels)[i] = index_open(scan->index_rel_oid);
947
948         for (i = 0, scan = head; i < *n_indices + 1; i++)
949         {
950                 scan = head->next;
951                 pfree(head);
952                 head = scan;
953         }
954 }
955
956 #define EXT_ATTLEN 5*8192
957
958 /*
959    returns 1 is c is in s
960 */
961 static bool
962 inString(char c, char *s)
963 {
964         int                     i;
965
966         if (s)
967         {
968                 i = 0;
969                 while (s[i] != '\0')
970                 {
971                         if (s[i] == c)
972                                 return 1;
973                         i++;
974                 }
975         }
976         return 0;
977 }
978
979 #ifdef COPY_PATCH
980 /*
981  * Reads input from fp until an end of line is seen.
982  */
983
984 void
985 CopyReadNewline(FILE *fp, int *newline)
986 {
987         if (!*newline)
988         {
989                 elog(NOTICE, "CopyReadNewline: line %d - extra fields ignored", lineno);
990                 while (!feof(fp) && (getc(fp) != '\n'));
991         }
992         *newline = 0;
993 }
994
995 #endif
996
997 /*
998  * Reads input from fp until eof is seen.  If we are reading from standard
999  * input, AND we see a dot on a line by itself (a dot followed immediately
1000  * by a newline), we exit as if we saw eof.  This is so that copy pipelines
1001  * can be used as standard input.
1002  */
1003
1004 static char *
1005 #ifdef COPY_PATCH
1006 CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline)
1007 #else
1008 CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
1009 #endif
1010 {
1011         static char attribute[EXT_ATTLEN];
1012         char            c;
1013         int                     done = 0;
1014         int                     i = 0;
1015
1016 #ifdef COPY_PATCH
1017         /* if last delimiter was a newline return a NULL attribute */
1018         if (*newline)
1019         {
1020                 *isnull = (bool) true;
1021                 return (NULL);
1022         }
1023 #endif
1024
1025         *isnull = (bool) false;         /* set default */
1026         if (feof(fp))
1027                 return (NULL);
1028
1029         while (!done)
1030         {
1031                 c = getc(fp);
1032
1033                 if (feof(fp))
1034                         return (NULL);
1035                 else if (c == '\\')
1036                 {
1037                         c = getc(fp);
1038                         if (feof(fp))
1039                                 return (NULL);
1040                         switch (c)
1041                         {
1042                                 case '0':
1043                                 case '1':
1044                                 case '2':
1045                                 case '3':
1046                                 case '4':
1047                                 case '5':
1048                                 case '6':
1049                                 case '7':
1050                                         {
1051                                                 int                     val;
1052
1053                                                 val = VALUE(c);
1054                                                 c = getc(fp);
1055                                                 if (ISOCTAL(c))
1056                                                 {
1057                                                         val = (val << 3) + VALUE(c);
1058                                                         c = getc(fp);
1059                                                         if (ISOCTAL(c))
1060                                                                 val = (val << 3) + VALUE(c);
1061                                                         else
1062                                                         {
1063                                                                 if (feof(fp))
1064                                                                         return (NULL);
1065                                                                 ungetc(c, fp);
1066                                                         }
1067                                                 }
1068                                                 else
1069                                                 {
1070                                                         if (feof(fp))
1071                                                                 return (NULL);
1072                                                         ungetc(c, fp);
1073                                                 }
1074                                                 c = val & 0377;
1075                                         }
1076                                         break;
1077                                 case 'b':
1078                                         c = '\b';
1079                                         break;
1080                                 case 'f':
1081                                         c = '\f';
1082                                         break;
1083                                 case 'n':
1084                                         c = '\n';
1085                                         break;
1086                                 case 'r':
1087                                         c = '\r';
1088                                         break;
1089                                 case 't':
1090                                         c = '\t';
1091                                         break;
1092                                 case 'v':
1093                                         c = '\v';
1094                                         break;
1095                                 case 'N':
1096                                         attribute[0] = '\0';            /* just to be safe */
1097                                         *isnull = (bool) true;
1098                                         break;
1099                                 case '.':
1100                                         c = getc(fp);
1101                                         if (c != '\n')
1102                                                 elog(ERROR, "CopyReadAttribute - end of record marker corrupted. line: %d", lineno);
1103                                         return (NULL);
1104                                         break;
1105                         }
1106                 }
1107                 else if (inString(c, delim) || c == '\n')
1108                 {
1109 #ifdef COPY_PATCH
1110                         if (c == '\n')
1111                                 *newline = 1;
1112 #endif
1113                         done = 1;
1114                 }
1115                 if (!done)
1116                         attribute[i++] = c;
1117                 if (i == EXT_ATTLEN - 1)
1118                         elog(ERROR, "CopyReadAttribute - attribute length too long. line: %d", lineno);
1119         }
1120         attribute[i] = '\0';
1121         return (&attribute[0]);
1122 }
1123
1124 static void
1125 CopyAttributeOut(FILE *fp, char *string, char *delim, int is_array)
1126 {
1127         char            c;
1128
1129         for (; (c = *string) != '\0'; string++)
1130         {
1131                 if (c == delim[0] || c == '\n' ||
1132                         (c == '\\' && !is_array))
1133                         fputc('\\', fp);
1134                 else if (c == '\\' && is_array)
1135                 {
1136                         if (*(string + 1) == '\\')
1137                         {
1138                                 /* translate \\ to \\\\ */
1139                                 fputc('\\', fp);
1140                                 fputc('\\', fp);
1141                                 fputc('\\', fp);
1142                                 string++;
1143                         }
1144                         else if (*(string + 1) == '"')
1145                         {
1146                                 /* translate \" to \\\" */
1147                                 fputc('\\', fp);
1148                                 fputc('\\', fp);
1149                         }
1150                 }
1151                 fputc(*string, fp);
1152         }
1153 }
1154
1155 /*
1156  * Returns the number of tuples in a relation.  Unfortunately, currently
1157  * must do a scan of the entire relation to determine this.
1158  *
1159  * relation is expected to be an open relation descriptor.
1160  */
1161 static int
1162 CountTuples(Relation relation)
1163 {
1164         HeapScanDesc scandesc;
1165         HeapTuple       tuple;
1166
1167         int                     i;
1168
1169         scandesc = heap_beginscan(relation, 0, false, 0, NULL);
1170
1171         for (tuple = heap_getnext(scandesc, 0, NULL), i = 0;
1172                  tuple != NULL;
1173                  tuple = heap_getnext(scandesc, 0, NULL), i++)
1174                 ;
1175         heap_endscan(scandesc);
1176         return (i);
1177 }