diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index a25dc0b8a693654a493894d38d8f386ebcb19a7d..35f3d6da0b31470ac617aa0b01fb98a2a353886b 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.86 1999/07/22 02:40:06 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.87 1999/09/11 22:28:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,6 +26,7 @@ #include "commands/copy.h" #include "commands/trigger.h" #include "executor/executor.h" +#include "lib/stringinfo.h" #include "libpq/libpq.h" #include "miscadmin.h" #include "utils/acl.h" @@ -51,14 +52,10 @@ 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); -#else -static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim); -#endif -static void CopyAttributeOut(FILE *fp, char *string, char *delim, int is_array); +static void CopyAttributeOut(FILE *fp, char *string, char *delim); static int CountTuples(Relation relation); /* @@ -431,7 +428,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim) { string = (char *) (*fmgr_faddr(&out_functions[i])) (value, elements[i], typmod[i]); - CopyAttributeOut(fp, string, delim, attr[i]->attnelems); + CopyAttributeOut(fp, string, delim); pfree(string); } else @@ -691,18 +688,12 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim) { if (!binary) { -#ifdef COPY_PATCH int newline = 0; -#endif lineno++; if (oids) { -#ifdef COPY_PATCH string = CopyReadAttribute(fp, &isnull, delim, &newline); -#else - string = CopyReadAttribute(fp, &isnull, delim); -#endif if (string == NULL) done = 1; else @@ -710,19 +701,18 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim) loaded_oid = oidin(string); if (loaded_oid < BootstrapObjectIdData) elog(ERROR, "COPY TEXT: Invalid Oid. line: %d", lineno); + pfree(string); } } for (i = 0; i < attr_count && !done; i++) { -#ifdef COPY_PATCH string = CopyReadAttribute(fp, &isnull, delim, &newline); -#else - string = CopyReadAttribute(fp, &isnull, delim); -#endif if (isnull) { values[i] = PointerGetDatum(NULL); nulls[i] = 'n'; + if (string) + pfree(string); } else if (string == NULL) done = 1; @@ -739,12 +729,11 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim) if (!PointerIsValid(values[i]) && !(rel->rd_att->attrs[i]->attbyval)) elog(ERROR, "copy from line %d: Bad file format", lineno); + pfree(string); } } -#ifdef COPY_PATCH if (!done) CopyReadNewline(fp, &newline); -#endif } else { /* binary */ @@ -812,11 +801,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim) 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_data->t_oid = loaded_oid; @@ -1086,30 +1070,18 @@ GetIndexRelations(Oid main_relation_oid, } } -#define EXT_ATTLEN (5 * BLCKSZ) /* - returns 1 is c is in s + returns 1 if c is in 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++; - } - } + if (s && c) + return strchr(s, c) != NULL; return 0; } -#ifdef COPY_PATCH /* * Reads input from fp until an end of line is seen. */ @@ -1125,64 +1097,57 @@ CopyReadNewline(FILE *fp, int *newline) *newline = 0; } -#endif - /* - * Reads input from fp until eof is seen. If we are reading from standard - * input, AND we see a dot on a line by itself (a dot followed immediately - * by a newline), we exit as if we saw eof. This is so that copy pipelines - * can be used as standard input. + * Read the value of a single attribute. + * + * Result is either a palloc'd string, or NULL (if EOF or a null attribute). + * *isnull is set true if a null attribute, else false. + * + * delim is the string of acceptable delimiter characters(s). + * *newline remembers whether we've seen a newline ending this tuple. */ static char * -#ifdef COPY_PATCH CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline) -#else -CopyReadAttribute(FILE *fp, bool *isnull, char *delim) -#endif { - static char attribute[EXT_ATTLEN]; + StringInfoData attribute_buf; char c; - int done = 0; - int i = 0; - #ifdef MULTIBYTE int mblen; int encoding; unsigned char s[2]; + char *cvt; int j; -#endif - -#ifdef MULTIBYTE encoding = pg_get_client_encoding(); s[1] = 0; #endif -#ifdef COPY_PATCH /* if last delimiter was a newline return a NULL attribute */ if (*newline) { *isnull = (bool) true; return NULL; } -#endif *isnull = (bool) false; /* set default */ + + initStringInfo(&attribute_buf); + if (CopyGetEof(fp)) - return NULL; + goto endOfFile; - while (!done) + for (;;) { c = CopyGetChar(fp); - if (CopyGetEof(fp)) - return NULL; - else if (c == '\\') + goto endOfFile; + + if (c == '\\') { c = CopyGetChar(fp); if (CopyGetEof(fp)) - return NULL; + goto endOfFile; switch (c) { case '0': @@ -1212,14 +1177,14 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim) else { if (CopyGetEof(fp)) - return NULL; + goto endOfFile; CopyDonePeek(fp, c, 0); /* Return to stream! */ } } else { if (CopyGetEof(fp)) - return NULL; + goto endOfFile; CopyDonePeek(fp, c, 0); /* Return to stream! */ } c = val & 0377; @@ -1244,66 +1209,70 @@ CopyReadAttribute(FILE *fp, bool *isnull, char *delim) c = '\v'; break; case 'N': - attribute[0] = '\0'; /* just to be safe */ *isnull = (bool) true; break; case '.': c = CopyGetChar(fp); if (c != '\n') elog(ERROR, "CopyReadAttribute - end of record marker corrupted. line: %d", lineno); - return NULL; + goto endOfFile; break; } } - else if (inString(c, delim) || c == '\n') + else if (c == '\n' || inString(c, delim)) { -#ifdef COPY_PATCH if (c == '\n') *newline = 1; -#endif - done = 1; + break; } - if (!done) - attribute[i++] = c; + appendStringInfoChar(&attribute_buf, c); #ifdef MULTIBYTE + /* get additional bytes of the char, if any */ s[0] = c; mblen = pg_encoding_mblen(encoding, s); - mblen--; - for (j = 0; j < mblen; j++) + for (j = 1; j < mblen; j++) { c = CopyGetChar(fp); if (CopyGetEof(fp)) - return NULL; - attribute[i++] = c; + goto endOfFile; + appendStringInfoChar(&attribute_buf, c); } #endif - if (i == EXT_ATTLEN - 1) - elog(ERROR, "CopyReadAttribute - attribute length too long. line: %d", lineno); } - attribute[i] = '\0'; + #ifdef MULTIBYTE - return (pg_client_to_server((unsigned char *) attribute, strlen(attribute))); -#else - return &attribute[0]; + cvt = (char *) pg_client_to_server((unsigned char *) attribute_buf.data, + attribute_buf.len); + if (cvt != attribute_buf.data) + { + pfree(attribute_buf.data); + return cvt; + } #endif + return attribute_buf.data; + +endOfFile: + pfree(attribute_buf.data); + return NULL; } static void -CopyAttributeOut(FILE *fp, char *server_string, char *delim, int is_array) +CopyAttributeOut(FILE *fp, char *server_string, char *delim) { char *string; char c; - #ifdef MULTIBYTE - int mblen; + char *string_start; int encoding; + int mblen; int i; - #endif #ifdef MULTIBYTE - string = pg_server_to_client(server_string, strlen(server_string)); encoding = pg_get_client_encoding(); + string = (char *) pg_server_to_client((unsigned char *) server_string, + strlen(server_string)); + string_start = string; #else string = server_string; #endif @@ -1315,33 +1284,20 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim, int is_array) for (; (c = *string) != '\0'; string++) #endif { - if (c == delim[0] || c == '\n' || - (c == '\\' && !is_array)) + if (c == delim[0] || c == '\n' || c == '\\') CopySendChar('\\', fp); - else if (c == '\\' && is_array) - { - if (*(string + 1) == '\\') - { - /* translate \\ to \\\\ */ - CopySendChar('\\', fp); - CopySendChar('\\', fp); - CopySendChar('\\', fp); - string++; - } - else if (*(string + 1) == '"') - { - /* translate \" to \\\" */ - CopySendChar('\\', fp); - CopySendChar('\\', fp); - } - } #ifdef MULTIBYTE for (i = 0; i < mblen; i++) CopySendChar(*(string + i), fp); #else - CopySendChar(*string, fp); + CopySendChar(c, fp); #endif } + +#ifdef MULTIBYTE + if (string_start != server_string) + pfree(string_start); /* pfree pg_server_to_client result */ +#endif } /* diff --git a/src/backend/libpq/pqformat.c b/src/backend/libpq/pqformat.c index 1cc715b92a352c5dbf9f79eca23aef79bdf6c015..f6de4af17107937d67493b13a1b581f8301a6764 100644 --- a/src/backend/libpq/pqformat.c +++ b/src/backend/libpq/pqformat.c @@ -15,7 +15,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: pqformat.c,v 1.8 1999/08/31 04:26:37 tgl Exp $ + * $Id: pqformat.c,v 1.9 1999/09/11 22:28:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -125,13 +125,16 @@ void pq_sendcountedtext(StringInfo buf, const char *str, int slen) { #ifdef MULTIBYTE - const char *p; + char *p; - p = (const char *) pg_server_to_client((unsigned char *) str, slen); + p = (char *) pg_server_to_client((unsigned char *) str, slen); if (p != str) /* actual conversion has been done? */ { - str = p; - slen = strlen(str); + slen = strlen(p); + pq_sendint(buf, slen + 4, 4); + appendBinaryStringInfo(buf, p, slen); + pfree(p); + return; } #endif pq_sendint(buf, slen + 4, 4); @@ -149,15 +152,16 @@ void pq_sendstring(StringInfo buf, const char *str) { int slen = strlen(str); - #ifdef MULTIBYTE - const char *p; + char *p; - p = (const char *) pg_server_to_client((unsigned char *) str, slen); + p = (char *) pg_server_to_client((unsigned char *) str, slen); if (p != str) /* actual conversion has been done? */ { - str = p; - slen = strlen(str); + slen = strlen(p); + appendBinaryStringInfo(buf, p, slen + 1); + pfree(p); + return; } #endif appendBinaryStringInfo(buf, str, slen + 1); @@ -229,15 +233,15 @@ int pq_puttextmessage(char msgtype, const char *str) { int slen = strlen(str); - #ifdef MULTIBYTE - const char *p; + char *p; - p = (const char *) pg_server_to_client((unsigned char *) str, slen); + p = (char *) pg_server_to_client((unsigned char *) str, slen); if (p != str) /* actual conversion has been done? */ { - str = p; - slen = strlen(str); + int result = pq_putmessage(msgtype, p, strlen(p) + 1); + pfree(p); + return result; } #endif return pq_putmessage(msgtype, str, slen + 1); @@ -299,12 +303,12 @@ pq_getint(int *result, int b) int pq_getstr(StringInfo s) { - int c; + int result; #ifdef MULTIBYTE char *p; #endif - c = pq_getstring(s); + result = pq_getstring(s); #ifdef MULTIBYTE p = (char *) pg_client_to_server((unsigned char *) s->data, s->len); @@ -314,8 +318,9 @@ pq_getstr(StringInfo s) s->len = 0; s->data[0] = '\0'; appendBinaryStringInfo(s, p, strlen(p)); + pfree(p); } #endif - return c; + return result; } diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c index a63cd37332d23e598841c57ce753bcf20c77bd72..ba22ec347ff720ab677097be3fddb982402a140a 100644 --- a/src/backend/utils/mb/mbutils.c +++ b/src/backend/utils/mb/mbutils.c @@ -3,7 +3,7 @@ * client encoding and server internal encoding. * (currently mule internal code (mic) is used) * Tatsuo Ishii - * $Id: mbutils.c,v 1.8 1999/07/17 20:18:10 momjian Exp $ */ + * $Id: mbutils.c,v 1.9 1999/09/11 22:28:00 tgl Exp $ */ #include "postgres.h" @@ -93,59 +93,81 @@ pg_get_client_encoding() } /* - * convert client encoding to server encoding. if server_encoding == - * client_encoding or no conversion function exists, - * returns s. So be careful. + * convert client encoding to server encoding. + * + * CASE 1: if no conversion is required, then the given pointer s is returned. + * + * CASE 2: if conversion is required, a palloc'd string is returned. + * + * Callers must check whether return value differs from passed value + * to determine whether to pfree the result or not! + * + * Note: we assume that conversion cannot cause more than a 4-to-1 growth + * in the length of the string --- is this enough? */ unsigned char * pg_client_to_server(unsigned char *s, int len) { - static unsigned char b1[MAX_PARSE_BUFFER * 4]; /* is this enough? */ - static unsigned char b2[MAX_PARSE_BUFFER * 4]; /* is this enough? */ - unsigned char *p = s; + unsigned char *result = s; + unsigned char *buf; if (client_encoding == GetDatabaseEncoding()) - return (p); + return result; if (client_to_mic) { - (*client_to_mic) (s, b1, len); - len = strlen(b1); - p = b1; + buf = (unsigned char *) palloc(len * 4 + 1); + (*client_to_mic) (result, buf, len); + result = buf; + len = strlen(result); } if (server_from_mic) { - (*server_from_mic) (p, b2, len); - p = b2; + buf = (unsigned char *) palloc(len * 4 + 1); + (*server_from_mic) (result, buf, len); + if (result != s) + pfree(result); /* release first buffer */ + result = buf; } - return (p); + return result; } /* - * convert server encoding to client encoding. if server_encoding == - * client_encoding or no conversion function exists, - * returns s. So be careful. + * convert server encoding to client encoding. + * + * CASE 1: if no conversion is required, then the given pointer s is returned. + * + * CASE 2: if conversion is required, a palloc'd string is returned. + * + * Callers must check whether return value differs from passed value + * to determine whether to pfree the result or not! + * + * Note: we assume that conversion cannot cause more than a 4-to-1 growth + * in the length of the string --- is this enough? */ unsigned char * pg_server_to_client(unsigned char *s, int len) { - static unsigned char b1[MAX_PARSE_BUFFER * 4]; /* is this enough? */ - static unsigned char b2[MAX_PARSE_BUFFER * 4]; /* is this enough? */ - unsigned char *p = s; + unsigned char *result = s; + unsigned char *buf; if (client_encoding == GetDatabaseEncoding()) - return (p); + return result; if (server_to_mic) { - (*server_to_mic) (s, b1, len); - len = strlen(b1); - p = b1; + buf = (unsigned char *) palloc(len * 4 + 1); + (*server_to_mic) (result, buf, len); + result = buf; + len = strlen(result); } if (client_from_mic) { - (*client_from_mic) (p, b2, len); - p = b2; + buf = (unsigned char *) palloc(len * 4 + 1); + (*client_from_mic) (result, buf, len); + if (result != s) + pfree(result); /* release first buffer */ + result = buf; } - return (p); + return result; } /* convert a multi-byte string to a wchar */ diff --git a/src/include/config.h.in b/src/include/config.h.in index e7ae8b302b66475b11bbcdffcc4ece3811f3aa1e..e0711fb1cb559e4c2945eeb10615e88e59a48dcc 100644 --- a/src/include/config.h.in +++ b/src/include/config.h.in @@ -123,14 +123,6 @@ */ /* #define TCL_ARRAYS */ -/* - * The following flag allows copying tables from files with number of columns - * different than the number of attributes setting missing attributes to NULL - * and ignoring extra columns. This also avoids the shift of the attributes - * of the rest of the file if one line has a wrong column count. - */ -#define COPY_PATCH - /* * User locks are handled totally on the application side as long term * cooperative locks which extend beyond the normal transaction boundaries.