1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.139 2001/06/08 21:16:48 petere Exp $
12 *-------------------------------------------------------------------------
19 #include "access/genam.h"
20 #include "access/heapam.h"
21 #include "access/printtup.h"
22 #include "catalog/catname.h"
23 #include "catalog/index.h"
24 #include "catalog/pg_index.h"
25 #include "catalog/pg_shadow.h"
26 #include "catalog/pg_type.h"
27 #include "commands/copy.h"
28 #include "commands/trigger.h"
29 #include "executor/executor.h"
30 #include "libpq/libpq.h"
31 #include "miscadmin.h"
32 #include "tcop/pquery.h"
33 #include "tcop/tcopprot.h"
34 #include "utils/acl.h"
35 #include "utils/builtins.h"
36 #include "utils/relcache.h"
37 #include "utils/syscache.h"
40 #include "mb/pg_wchar.h"
43 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
44 #define VALUE(c) ((c) - '0')
47 /* non-export function prototypes */
48 static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
49 static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
50 static Oid GetInputFunction(Oid type);
51 static Oid GetTypeElement(Oid type);
52 static void CopyReadNewline(FILE *fp, int *newline);
53 static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print);
54 static void CopyAttributeOut(FILE *fp, char *string, char *delim);
56 static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0";
59 * Static communication variables ... pretty grotty, but COPY has
60 * never been reentrant...
62 int copy_lineno = 0; /* exported for use by elog() -- dz */
66 * These static variables are used to avoid incurring overhead for each
67 * attribute processed. attribute_buf is reused on each CopyReadAttribute
68 * call to hold the string being read in. Under normal use it will soon
69 * grow to a suitable size, and then we will avoid palloc/pfree overhead
70 * for subsequent attributes. Note that CopyReadAttribute returns a pointer
71 * to attribute_buf's data buffer!
72 * encoding, if needed, can be set once at the start of the copy operation.
74 static StringInfoData attribute_buf;
77 static int client_encoding;
78 static int server_encoding;
84 * Internal communications functions
86 static void CopySendData(void *databuf, int datasize, FILE *fp);
87 static void CopySendString(char *str, FILE *fp);
88 static void CopySendChar(char c, FILE *fp);
89 static void CopyGetData(void *databuf, int datasize, FILE *fp);
90 static int CopyGetChar(FILE *fp);
91 static int CopyGetEof(FILE *fp);
92 static int CopyPeekChar(FILE *fp);
93 static void CopyDonePeek(FILE *fp, int c, int pickup);
96 * CopySendData sends output data either to the file
97 * specified by fp or, if fp is NULL, using the standard
98 * backend->frontend functions
100 * CopySendString does the same for null-terminated strings
101 * CopySendChar does the same for single characters
103 * NB: no data conversion is applied by these functions
106 CopySendData(void *databuf, int datasize, FILE *fp)
110 if (pq_putbytes((char *) databuf, datasize))
115 fwrite(databuf, datasize, 1, fp);
117 elog(ERROR, "CopySendData: %m");
122 CopySendString(char *str, FILE *fp)
124 CopySendData(str, strlen(str), fp);
128 CopySendChar(char c, FILE *fp)
130 CopySendData(&c, 1, fp);
134 * CopyGetData reads output data either from the file
135 * specified by fp or, if fp is NULL, using the standard
136 * backend->frontend functions
138 * CopyGetChar does the same for single characters
139 * CopyGetEof checks if it's EOF on the input (or, check for EOF result
142 * NB: no data conversion is applied by these functions
145 CopyGetData(void *databuf, int datasize, FILE *fp)
149 if (pq_getbytes((char *) databuf, datasize))
153 fread(databuf, datasize, 1, fp);
157 CopyGetChar(FILE *fp)
163 if (pq_getbytes((char *) &ch, 1))
184 * CopyPeekChar reads a byte in "peekable" mode.
185 * after each call to CopyPeekChar, a call to CopyDonePeek _must_
186 * follow, unless EOF was returned.
187 * CopyDonePeek will either take the peeked char off the steam
188 * (if pickup is != 0) or leave it on the stream (if pickup == 0)
191 CopyPeekChar(FILE *fp)
195 int ch = pq_peekbyte();
206 CopyDonePeek(FILE *fp, int c, int pickup)
214 * We want to pick it up - just receive again into dummy
221 /* If we didn't want to pick it up, just leave it where it sits */
227 /* We don't want to pick it up - so put it back in there */
230 /* If we wanted to pick it up, it's already there */
237 * DoCopy executes the SQL COPY statement.
241 DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
242 char *filename, char *delim, char *null_print)
244 /*----------------------------------------------------------------------------
245 Either unload or reload contents of class <relname>, depending on <from>.
247 If <pipe> is false, transfer is between the class and the file named
248 <filename>. Otherwise, transfer is between the class and our regular
249 input/output stream. The latter could be either stdin/stdout or a
250 socket, depending on whether we're running under Postmaster control.
252 Iff <binary>, unload or reload in the binary format, as opposed to the
253 more wasteful but more robust and portable text format.
255 If in the text format, delimit columns with delimiter <delim> and print
256 NULL values as <null_print>.
258 When loading in the text format from an input stream (as opposed to
259 a file), recognize a "." on a line by itself as EOF. Also recognize
260 a stream EOF. When unloading in the text format to an output stream,
261 write a "." on a line by itself at the end of the data.
263 Iff <oids>, unload or reload the format that includes OID information.
265 Do not allow a Postgres user without superuser privilege to read from
268 Do not allow the copy if user doesn't have proper permission to access
270 ----------------------------------------------------------------------------*/
274 const AclMode required_access = from ? ACL_INSERT : ACL_SELECT;
278 * Open and lock the relation, using the appropriate lock type.
280 rel = heap_openr(relname, (from ? RowExclusiveLock : AccessShareLock));
282 result = pg_aclcheck(relname, GetUserId(), required_access);
283 if (result != ACLCHECK_OK)
284 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[result]);
285 if (!pipe && !superuser())
286 elog(ERROR, "You must have Postgres superuser privilege to do a COPY "
287 "directly to or from a file. Anyone can COPY to stdout or "
288 "from stdin. Psql's \\copy command also works for anyone.");
291 * This restriction is unfortunate, but necessary until the frontend
292 * COPY protocol is redesigned to be binary-safe...
295 elog(ERROR, "COPY BINARY is not supported to stdout or from stdin");
298 * Set up variables to avoid per-attribute overhead.
300 initStringInfo(&attribute_buf);
302 client_encoding = pg_get_client_encoding();
303 server_encoding = GetDatabaseEncoding();
307 { /* copy from file to database */
308 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
309 elog(ERROR, "You cannot change sequence relation %s", relname);
312 if (IsUnderPostmaster)
322 fp = AllocateFile(filename, PG_BINARY_R);
324 elog(ERROR, "COPY command, running in backend with "
325 "effective uid %d, could not open file '%s' for "
326 "reading. Errno = %s (%d).",
327 (int) geteuid(), filename, strerror(errno), errno);
329 CopyFrom(rel, binary, oids, fp, delim, null_print);
332 { /* copy from database to file */
335 if (IsUnderPostmaster)
346 mode_t oumask; /* Pre-existing umask value */
349 * Prevent write to relative path ... too easy to shoot
350 * oneself in the foot by overwriting a database file ...
352 if (filename[0] != '/')
353 elog(ERROR, "Relative path not allowed for server side"
356 oumask = umask((mode_t) 022);
357 fp = AllocateFile(filename, PG_BINARY_W);
361 elog(ERROR, "COPY command, running in backend with "
362 "effective uid %d, could not open file '%s' for "
363 "writing. Errno = %s (%d).",
364 (int) geteuid(), filename, strerror(errno), errno);
366 CopyTo(rel, binary, oids, fp, delim, null_print);
374 CopySendData("\\.\n", 3, fp);
375 if (IsUnderPostmaster)
376 pq_endcopyout(false);
378 pfree(attribute_buf.data);
381 * Close the relation. If reading, we can release the AccessShareLock
382 * we got; if writing, we should hold the lock until end of
383 * transaction to ensure that updates will be committed before lock is
386 heap_close(rel, (from ? NoLock : AccessShareLock));
391 * Copy from relation TO file.
394 CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
395 char *delim, char *null_print)
399 HeapScanDesc scandesc;
402 Form_pg_attribute *attr;
403 FmgrInfo *out_functions;
409 tupDesc = rel->rd_att;
410 attr_count = rel->rd_att->natts;
411 attr = rel->rd_att->attrs;
414 * For binary copy we really only need isvarlena, but compute it
417 out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
418 elements = (Oid *) palloc(attr_count * sizeof(Oid));
419 isvarlena = (bool *) palloc(attr_count * sizeof(bool));
420 for (i = 0; i < attr_count; i++)
424 if (!getTypeOutputInfo(attr[i]->atttypid,
425 &out_func_oid, &elements[i], &isvarlena[i]))
426 elog(ERROR, "COPY: couldn't lookup info for type %u",
428 fmgr_info(out_func_oid, &out_functions[i]);
433 /* Generate header for a binary copy */
437 CopySendData((char *) BinarySignature, 12, fp);
438 /* Integer layout field */
440 CopySendData(&tmp, sizeof(int32), fp);
445 CopySendData(&tmp, sizeof(int32), fp);
446 /* No header extension */
448 CopySendData(&tmp, sizeof(int32), fp);
451 scandesc = heap_beginscan(rel, 0, QuerySnapshot, 0, NULL);
453 while (HeapTupleIsValid(tuple = heap_getnext(scandesc, 0)))
455 bool need_delim = false;
457 CHECK_FOR_INTERRUPTS();
461 /* Binary per-tuple header */
462 int16 fld_count = attr_count;
464 CopySendData(&fld_count, sizeof(int16), fp);
465 /* Send OID if wanted --- note fld_count doesn't include it */
468 fld_size = sizeof(Oid);
469 CopySendData(&fld_size, sizeof(int16), fp);
470 CopySendData(&tuple->t_data->t_oid, sizeof(Oid), fp);
475 /* Text format has no per-tuple header, but send OID if wanted */
478 string = DatumGetCString(DirectFunctionCall1(oidout,
479 ObjectIdGetDatum(tuple->t_data->t_oid)));
480 CopySendString(string, fp);
486 for (i = 0; i < attr_count; i++)
492 origvalue = heap_getattr(tuple, i + 1, tupDesc, &isnull);
497 CopySendChar(delim[0], fp);
505 CopySendString(null_print, fp); /* null indicator */
509 fld_size = 0; /* null marker */
510 CopySendData(&fld_size, sizeof(int16), fp);
517 * If we have a toasted datum, forcibly detoast it to
518 * avoid memory leakage inside the type's output routine
519 * (or for binary case, becase we must output untoasted
523 value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
529 string = DatumGetCString(FunctionCall3(&out_functions[i],
531 ObjectIdGetDatum(elements[i]),
532 Int32GetDatum(attr[i]->atttypmod)));
533 CopyAttributeOut(fp, string, delim);
538 fld_size = attr[i]->attlen;
539 CopySendData(&fld_size, sizeof(int16), fp);
543 Assert(fld_size == -1);
544 CopySendData(DatumGetPointer(value),
548 else if (!attr[i]->attbyval)
550 /* fixed-length pass-by-reference */
551 Assert(fld_size > 0);
552 CopySendData(DatumGetPointer(value),
562 * We need this horsing around because we don't
563 * know how shorter data values are aligned within
566 store_att_byval(&datumBuf, value, fld_size);
567 CopySendData(&datumBuf,
573 /* Clean up detoasted copy, if any */
574 if (value != origvalue)
575 pfree(DatumGetPointer(value));
580 CopySendChar('\n', fp);
583 heap_endscan(scandesc);
587 /* Generate trailer for a binary copy */
588 int16 fld_count = -1;
590 CopySendData(&fld_count, sizeof(int16), fp);
593 pfree(out_functions);
600 * Copy FROM file to relation.
603 CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
604 char *delim, char *null_print)
608 Form_pg_attribute *attr;
609 AttrNumber attr_count;
610 FmgrInfo *in_functions;
619 ResultRelInfo *resultRelInfo;
620 EState *estate = CreateExecutorState(); /* for ExecConstraints() */
621 TupleTable tupleTable;
622 TupleTableSlot *slot;
623 Oid loaded_oid = InvalidOid;
624 bool skip_tuple = false;
627 tupDesc = RelationGetDescr(rel);
628 attr = tupDesc->attrs;
629 attr_count = tupDesc->natts;
632 * We need a ResultRelInfo so we can use the regular executor's
633 * index-entry-making machinery. (There used to be a huge amount of
634 * code here that basically duplicated execUtils.c ...)
636 resultRelInfo = makeNode(ResultRelInfo);
637 resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
638 resultRelInfo->ri_RelationDesc = rel;
639 resultRelInfo->ri_TrigDesc = rel->trigdesc;
641 ExecOpenIndices(resultRelInfo);
643 estate->es_result_relations = resultRelInfo;
644 estate->es_num_result_relations = 1;
645 estate->es_result_relation_info = resultRelInfo;
647 /* Set up a dummy tuple table too */
648 tupleTable = ExecCreateTupleTable(1);
649 slot = ExecAllocTableSlot(tupleTable);
650 ExecSetSlotDescriptor(slot, tupDesc, false);
654 in_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
655 elements = (Oid *) palloc(attr_count * sizeof(Oid));
656 for (i = 0; i < attr_count; i++)
658 in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
659 fmgr_info(in_func_oid, &in_functions[i]);
660 elements[i] = GetTypeElement(attr[i]->atttypid);
662 file_has_oids = oids; /* must rely on user to tell us this... */
666 /* Read and verify binary header */
671 CopyGetData(readSig, 12, fp);
672 if (CopyGetEof(fp) ||
673 memcmp(readSig, BinarySignature, 12) != 0)
674 elog(ERROR, "COPY BINARY: file signature not recognized");
675 /* Integer layout field */
676 CopyGetData(&tmp, sizeof(int32), fp);
677 if (CopyGetEof(fp) ||
679 elog(ERROR, "COPY BINARY: incompatible integer layout");
681 CopyGetData(&tmp, sizeof(int32), fp);
683 elog(ERROR, "COPY BINARY: bogus file header (missing flags)");
684 file_has_oids = (tmp & (1 << 16)) != 0;
686 if ((tmp >> 16) != 0)
687 elog(ERROR, "COPY BINARY: unrecognized critical flags in header");
688 /* Header extension length */
689 CopyGetData(&tmp, sizeof(int32), fp);
690 if (CopyGetEof(fp) ||
692 elog(ERROR, "COPY BINARY: bogus file header (missing length)");
693 /* Skip extension header, if present */
696 CopyGetData(readSig, 1, fp);
698 elog(ERROR, "COPY BINARY: bogus file header (wrong length)");
705 values = (Datum *) palloc(attr_count * sizeof(Datum));
706 nulls = (char *) palloc(attr_count * sizeof(char));
713 CHECK_FOR_INTERRUPTS();
717 /* Reset the per-output-tuple exprcontext */
718 ResetPerTupleExprContext(estate);
720 /* Initialize all values for row to NULL */
721 MemSet(values, 0, attr_count * sizeof(Datum));
722 MemSet(nulls, 'n', attr_count * sizeof(char));
730 string = CopyReadAttribute(fp, &isnull, delim,
731 &newline, null_print);
733 elog(ERROR, "COPY TEXT: NULL Oid");
734 else if (string == NULL)
735 done = 1; /* end of file */
738 loaded_oid = DatumGetObjectId(DirectFunctionCall1(oidin,
739 CStringGetDatum(string)));
740 if (loaded_oid == InvalidOid)
741 elog(ERROR, "COPY TEXT: Invalid Oid");
745 for (i = 0; i < attr_count && !done; i++)
747 string = CopyReadAttribute(fp, &isnull, delim,
748 &newline, null_print);
751 /* already set values[i] and nulls[i] */
753 else if (string == NULL)
754 done = 1; /* end of file */
757 values[i] = FunctionCall3(&in_functions[i],
758 CStringGetDatum(string),
759 ObjectIdGetDatum(elements[i]),
760 Int32GetDatum(attr[i]->atttypmod));
765 CopyReadNewline(fp, &newline);
772 CopyGetData(&fld_count, sizeof(int16), fp);
773 if (CopyGetEof(fp) ||
778 if (fld_count <= 0 || fld_count > attr_count)
779 elog(ERROR, "COPY BINARY: tuple field count is %d, expected %d",
780 (int) fld_count, attr_count);
784 CopyGetData(&fld_size, sizeof(int16), fp);
786 elog(ERROR, "COPY BINARY: unexpected EOF");
787 if (fld_size != (int16) sizeof(Oid))
788 elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d",
789 (int) fld_size, (int) sizeof(Oid));
790 CopyGetData(&loaded_oid, sizeof(Oid), fp);
792 elog(ERROR, "COPY BINARY: unexpected EOF");
793 if (loaded_oid == InvalidOid)
794 elog(ERROR, "COPY BINARY: Invalid Oid");
797 for (i = 0; i < (int) fld_count; i++)
799 CopyGetData(&fld_size, sizeof(int16), fp);
801 elog(ERROR, "COPY BINARY: unexpected EOF");
803 continue; /* it's NULL; nulls[i] already set */
804 if (fld_size != attr[i]->attlen)
805 elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d",
806 i + 1, (int) fld_size, (int) attr[i]->attlen);
813 CopyGetData(&varlena_size, sizeof(int32), fp);
815 elog(ERROR, "COPY BINARY: unexpected EOF");
816 if (varlena_size < (int32) sizeof(int32))
817 elog(ERROR, "COPY BINARY: bogus varlena length");
818 varlena_ptr = (Pointer) palloc(varlena_size);
819 VARATT_SIZEP(varlena_ptr) = varlena_size;
820 CopyGetData(VARDATA(varlena_ptr),
821 varlena_size - sizeof(int32),
824 elog(ERROR, "COPY BINARY: unexpected EOF");
825 values[i] = PointerGetDatum(varlena_ptr);
827 else if (!attr[i]->attbyval)
829 /* fixed-length pass-by-reference */
832 Assert(fld_size > 0);
833 refval_ptr = (Pointer) palloc(fld_size);
834 CopyGetData(refval_ptr, fld_size, fp);
836 elog(ERROR, "COPY BINARY: unexpected EOF");
837 values[i] = PointerGetDatum(refval_ptr);
845 * We need this horsing around because we don't
846 * know how shorter data values are aligned within
849 Assert(fld_size > 0 && fld_size <= sizeof(Datum));
850 CopyGetData(&datumBuf, fld_size, fp);
852 elog(ERROR, "COPY BINARY: unexpected EOF");
853 values[i] = fetch_att(&datumBuf, true, fld_size);
864 tuple = heap_formtuple(tupDesc, values, nulls);
866 if (oids && file_has_oids)
867 tuple->t_data->t_oid = loaded_oid;
871 /* BEFORE ROW INSERT Triggers */
872 if (resultRelInfo->ri_TrigDesc &&
873 resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
877 newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple);
879 if (newtuple == NULL) /* "do nothing" */
881 else if (newtuple != tuple) /* modified by Trigger(s) */
883 heap_freetuple(tuple);
890 ExecStoreTuple(tuple, slot, InvalidBuffer, false);
893 * Check the constraints of the tuple
895 if (rel->rd_att->constr)
896 ExecConstraints("CopyFrom", resultRelInfo, slot, estate);
899 * OK, store the tuple and create index entries for it
901 heap_insert(rel, tuple);
903 if (resultRelInfo->ri_NumIndices > 0)
904 ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
906 /* AFTER ROW INSERT Triggers */
907 if (resultRelInfo->ri_TrigDesc)
908 ExecARInsertTriggers(estate, resultRelInfo, tuple);
911 for (i = 0; i < attr_count; i++)
913 if (!attr[i]->attbyval && nulls[i] != 'n')
914 pfree(DatumGetPointer(values[i]));
917 heap_freetuple(tuple);
934 ExecDropTupleTable(tupleTable, true);
936 ExecCloseIndices(resultRelInfo);
941 GetInputFunction(Oid type)
946 typeTuple = SearchSysCache(TYPEOID,
947 ObjectIdGetDatum(type),
949 if (!HeapTupleIsValid(typeTuple))
950 elog(ERROR, "GetInputFunction: Cache lookup of type %u failed", type);
951 result = ((Form_pg_type) GETSTRUCT(typeTuple))->typinput;
952 ReleaseSysCache(typeTuple);
957 GetTypeElement(Oid type)
962 typeTuple = SearchSysCache(TYPEOID,
963 ObjectIdGetDatum(type),
965 if (!HeapTupleIsValid(typeTuple))
966 elog(ERROR, "GetTypeElement: Cache lookup of type %u failed", type);
967 result = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
968 ReleaseSysCache(typeTuple);
974 * Reads input from fp until an end of line is seen.
978 CopyReadNewline(FILE *fp, int *newline)
982 elog(NOTICE, "CopyReadNewline: extra fields ignored");
983 while (!CopyGetEof(fp) && (CopyGetChar(fp) != '\n'));
989 * Read the value of a single attribute.
991 * Result is either a string, or NULL (if EOF or a null attribute).
992 * Note that the caller should not pfree the string!
994 * *isnull is set true if a null attribute, else false.
995 * delim is the string of acceptable delimiter characters(s).
996 * *newline remembers whether we've seen a newline ending this tuple.
997 * null_print says how NULL values are represented
1001 CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print)
1014 /* reset attribute_buf to empty */
1015 attribute_buf.len = 0;
1016 attribute_buf.data[0] = '\0';
1018 /* if last delimiter was a newline return a NULL attribute */
1021 *isnull = (bool) true;
1025 *isnull = (bool) false; /* set default */
1029 c = CopyGetChar(fp);
1037 if (strchr(delim, c))
1041 c = CopyGetChar(fp);
1058 c = CopyPeekChar(fp);
1061 val = (val << 3) + VALUE(c);
1062 CopyDonePeek(fp, c, 1); /* Pick up the
1064 c = CopyPeekChar(fp);
1067 CopyDonePeek(fp, c, 1); /* pick up! */
1068 val = (val << 3) + VALUE(c);
1074 CopyDonePeek(fp, c, 0); /* Return to stream! */
1081 CopyDonePeek(fp, c, 0); /* Return to stream! */
1088 * This is a special hack to parse `\N' as
1089 * <backslash-N> rather then just 'N' to provide
1090 * compatibility with the default NULL output. -- pe
1093 appendStringInfoCharMacro(&attribute_buf, '\\');
1115 c = CopyGetChar(fp);
1117 elog(ERROR, "CopyReadAttribute: end of record marker corrupted");
1121 appendStringInfoCharMacro(&attribute_buf, c);
1123 if (client_encoding != server_encoding)
1125 /* get additional bytes of the char, if any */
1127 mblen = pg_encoding_mblen(client_encoding, s);
1128 for (j = 1; j < mblen; j++)
1130 c = CopyGetChar(fp);
1133 appendStringInfoCharMacro(&attribute_buf, c);
1140 if (client_encoding != server_encoding)
1142 cvt = (char *) pg_client_to_server((unsigned char *) attribute_buf.data,
1144 if (cvt != attribute_buf.data)
1146 /* transfer converted data back to attribute_buf */
1147 attribute_buf.len = 0;
1148 attribute_buf.data[0] = '\0';
1149 appendBinaryStringInfo(&attribute_buf, cvt, strlen(cvt));
1155 if (strcmp(attribute_buf.data, null_print) == 0)
1158 return attribute_buf.data;
1165 CopyAttributeOut(FILE *fp, char *server_string, char *delim)
1178 if (client_encoding != server_encoding)
1180 string = (char *) pg_server_to_client((unsigned char *) server_string,
1181 strlen(server_string));
1182 string_start = string;
1186 string = server_string;
1187 string_start = NULL; /* unused, but keep compiler quiet */
1190 string = server_string;
1194 for (; (mblen = (server_encoding == client_encoding ? 1 : pg_encoding_mblen(client_encoding, string))) &&
1195 ((c = *string) != '\0'); string += mblen)
1197 for (; (c = *string) != '\0'; string++)
1200 if (c == delim[0] || c == '\n' || c == '\\')
1201 CopySendChar('\\', fp);
1203 for (i = 0; i < mblen; i++)
1204 CopySendChar(*(string + i), fp);
1206 CopySendChar(c, fp);
1211 if (client_encoding != server_encoding)
1212 pfree(string_start); /* pfree pg_server_to_client result */