mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-28 01:37:18 +02:00
this is an old patch which I have already submitted and never seen in the sources. It corrects the datatype oids used in some iterator functions. This bug has been reported to me by many other people. contrib-datetime.patch some code contributed by Reiner Dassing <dassing@wettzell.ifag.de> contrib-makefiles.patch fixes all my contrib makefiles which don't work with some compilers, as reported to me by another user. contrib-miscutil.patch an old patch for one of my old contribs. contrib-string.patch a small change to the c-like text output functions. Now the '{' is escaped only at the beginning of the string to distinguish it from arrays, and the '}' is no more escaped. elog-lineno.patch adds the current lineno of CopyFrom to elog messages. This is very useful when you load a 1 million tuples table from an external file and there is a bad value somehere. Currently you get an error message but you can't know where is the bad data. The patch uses a variable which was declared static in copy.c. The variable is now exported and initialized to 0. It is always cleared at the end of the copy or at the first elog message or when the copy is canceled. I know this is very ugly but I can't find any better way of knowing where the copy fails and I have this problem quite often. plperl-makefile.patch fixes a typo in a makefile, but the error must be elsewhere because it is a file generated automatically. Please have a look. tprintf-timestamp.patch restores the original 2-digit year format, assuming that the two century digits don't carry much information and that '000202' is easier to read than 20000202. Being only a log file it shouldn't break anything. Please apply the patches before the next scheduled code freeze. I also noticed that some of the contribs don't compile correcly. Should we ask people to fix their code or rename their makefiles so that they are ignored by the top makefile? -- Massimo Dal Zotto
375 lines
6.6 KiB
C
375 lines
6.6 KiB
C
/*
|
|
* string_io.c --
|
|
*
|
|
* This file defines C-like input/output conversion routines for strings.
|
|
*
|
|
* Copyright (C) 1999, Massimo Dal Zotto <dz@cs.unitn.it>
|
|
*
|
|
* This software is distributed under the GNU General Public License
|
|
* either version 2, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "postgres.h"
|
|
#include "utils/elog.h"
|
|
#include "utils/palloc.h"
|
|
#include "utils/builtins.h"
|
|
|
|
#include "string_io.h"
|
|
|
|
/* define this if you want to see iso-8859 characters */
|
|
#define ISO8859
|
|
|
|
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
|
#define VALUE(char) ((char) - '0')
|
|
#define DIGIT(val) ((val) + '0')
|
|
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
|
|
#ifndef ISO8859
|
|
#define NOTPRINTABLE(c) (!isprint(c))
|
|
#else
|
|
#define NOTPRINTABLE(c) (!isprint(c) && ((c) < 0xa0))
|
|
#endif
|
|
|
|
/*
|
|
* string_output() --
|
|
*
|
|
* This function takes a pointer to a string data and an optional
|
|
* data size and returns a printable representation of the string
|
|
* translating all escape sequences to C-like \nnn or \c escapes.
|
|
* The function is used by output methods of various string types.
|
|
*
|
|
* Arguments:
|
|
* data - input data (can be NULL)
|
|
* size - optional size of data. A negative value indicates
|
|
* that data is a null terminated string.
|
|
*
|
|
* Returns:
|
|
* a pointer to a new string containing the printable
|
|
* representation of data.
|
|
*/
|
|
|
|
unsigned char *
|
|
string_output(unsigned char *data, int size)
|
|
{
|
|
register unsigned char c,
|
|
*p,
|
|
*r,
|
|
*result;
|
|
register int l,
|
|
len;
|
|
|
|
if (data == NULL)
|
|
{
|
|
result = (char *) palloc(2);
|
|
result[0] = '-';
|
|
result[1] = '\0';
|
|
return (result);
|
|
}
|
|
|
|
if (size < 0)
|
|
size = strlen(data);
|
|
|
|
/* adjust string length for escapes */
|
|
len = size;
|
|
for (p = data, l = size; l > 0; p++, l--)
|
|
{
|
|
switch (*p)
|
|
{
|
|
case '\\':
|
|
case '"':
|
|
case '\b':
|
|
case '\f':
|
|
case '\n':
|
|
case '\r':
|
|
case '\t':
|
|
case '\v':
|
|
len++;
|
|
break;
|
|
case '{':
|
|
/* Escape beginning of string, to distinguish from arrays */
|
|
if (p == data) {
|
|
len++;
|
|
}
|
|
break;
|
|
default:
|
|
if (NOTPRINTABLE(*p))
|
|
len += 3;
|
|
}
|
|
}
|
|
len++;
|
|
|
|
result = (char *) palloc(len);
|
|
|
|
for (p = data, r = result, l = size; (l > 0) && (c = *p); p++, l--)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '\\':
|
|
case '"':
|
|
*r++ = '\\';
|
|
*r++ = c;
|
|
break;
|
|
case '\b':
|
|
*r++ = '\\';
|
|
*r++ = 'b';
|
|
break;
|
|
case '\f':
|
|
*r++ = '\\';
|
|
*r++ = 'f';
|
|
break;
|
|
case '\n':
|
|
*r++ = '\\';
|
|
*r++ = 'n';
|
|
break;
|
|
case '\r':
|
|
*r++ = '\\';
|
|
*r++ = 'r';
|
|
break;
|
|
case '\t':
|
|
*r++ = '\\';
|
|
*r++ = 't';
|
|
break;
|
|
case '\v':
|
|
*r++ = '\\';
|
|
*r++ = 'v';
|
|
break;
|
|
case '{':
|
|
/* Escape beginning of string, to distinguish from arrays */
|
|
if (p == data) {
|
|
*r++ = '\\';
|
|
}
|
|
*r++ = c;
|
|
break;
|
|
default:
|
|
if (NOTPRINTABLE(c))
|
|
{
|
|
*r = '\\';
|
|
r += 3;
|
|
*r-- = DIGIT(c & 07);
|
|
c >>= 3;
|
|
*r-- = DIGIT(c & 07);
|
|
c >>= 3;
|
|
*r = DIGIT(c & 03);
|
|
r += 3;
|
|
}
|
|
else
|
|
*r++ = c;
|
|
}
|
|
}
|
|
*r = '\0';
|
|
|
|
return ((char *) result);
|
|
}
|
|
|
|
/*
|
|
* string_input() --
|
|
*
|
|
* This function accepts a C string in input and copies it into a new
|
|
* object allocated with palloc() translating all escape sequences.
|
|
* An optional header can be allocatd before the string, for example
|
|
* to hold the length of a varlena object.
|
|
* This function is not necessary for input from sql commands because
|
|
* the parser already does escape translation, all data input routines
|
|
* receive strings in internal form.
|
|
*
|
|
* Arguments:
|
|
* str - input string possibly with escapes
|
|
* size - the required size of new data. A value of 0
|
|
* indicates a variable size string, while a
|
|
* negative value indicates a variable size string
|
|
* of size not greater than this absolute value.
|
|
* hdrsize - size of an optional header to be allocated before
|
|
* the data. It must then be filled by the caller.
|
|
* rtn_size - an optional pointer to an int variable where the
|
|
* size of the new string is stored back.
|
|
*
|
|
* Returns:
|
|
* a pointer to the new string or the header.
|
|
*/
|
|
|
|
unsigned char *
|
|
string_input(unsigned char *str, int size, int hdrsize, int *rtn_size)
|
|
{
|
|
register unsigned char *p,
|
|
*r;
|
|
unsigned char *result;
|
|
int len;
|
|
|
|
if ((str == NULL) || (hdrsize < 0))
|
|
return (char *) NULL;
|
|
|
|
/* Compute result size */
|
|
len = strlen(str);
|
|
for (p = str; *p;)
|
|
{
|
|
if (*p++ == '\\')
|
|
{
|
|
if (ISOCTAL(*p))
|
|
{
|
|
if (ISOCTAL(*(p + 1)))
|
|
{
|
|
p++;
|
|
len--;
|
|
}
|
|
if (ISOCTAL(*(p + 1)))
|
|
{
|
|
p++;
|
|
len--;
|
|
}
|
|
}
|
|
if (*p)
|
|
p++;
|
|
len--;
|
|
}
|
|
}
|
|
|
|
/* result has variable length */
|
|
if (size == 0)
|
|
size = len + 1;
|
|
else
|
|
/* result has variable length with maximum size */
|
|
if (size < 0)
|
|
size = MIN(len, -size) + 1;
|
|
|
|
result = (char *) palloc(hdrsize + size);
|
|
memset(result, 0, hdrsize + size);
|
|
if (rtn_size)
|
|
*rtn_size = size;
|
|
|
|
r = result + hdrsize;
|
|
for (p = str; *p;)
|
|
{
|
|
register unsigned char c;
|
|
|
|
if ((c = *p++) == '\\')
|
|
{
|
|
switch (c = *p++)
|
|
{
|
|
case '\0':
|
|
p--;
|
|
break;
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
c = VALUE(c);
|
|
if (isdigit(*p))
|
|
c = (c << 3) + VALUE(*p++);
|
|
if (isdigit(*p))
|
|
c = (c << 3) + VALUE(*p++);
|
|
*r++ = c;
|
|
break;
|
|
case 'b':
|
|
*r++ = '\b';
|
|
break;
|
|
case 'f':
|
|
*r++ = '\f';
|
|
break;
|
|
case 'n':
|
|
*r++ = '\n';
|
|
break;
|
|
case 'r':
|
|
*r++ = '\r';
|
|
break;
|
|
case 't':
|
|
*r++ = '\t';
|
|
break;
|
|
case 'v':
|
|
*r++ = '\v';
|
|
break;
|
|
default:
|
|
*r++ = c;
|
|
}
|
|
}
|
|
else
|
|
*r++ = c;
|
|
}
|
|
|
|
return ((char *) result);
|
|
}
|
|
|
|
unsigned char *
|
|
c_charout(int32 c)
|
|
{
|
|
char str[2];
|
|
|
|
str[0] = (char) c;
|
|
str[1] = '\0';
|
|
|
|
return (string_output(str, 1));
|
|
}
|
|
|
|
/*
|
|
* This can be used for SET, bytea, text and unknown data types
|
|
*/
|
|
|
|
unsigned char *
|
|
c_textout(struct varlena * vlena)
|
|
{
|
|
int len = 0;
|
|
char *s = NULL;
|
|
|
|
if (vlena)
|
|
{
|
|
len = VARSIZE(vlena) - VARHDRSZ;
|
|
s = VARDATA(vlena);
|
|
}
|
|
return (string_output(s, len));
|
|
}
|
|
|
|
/*
|
|
* This can be used for varchar and bpchar strings
|
|
*/
|
|
|
|
unsigned char *
|
|
c_varcharout(unsigned char *s)
|
|
{
|
|
int len = 0;
|
|
|
|
if (s)
|
|
{
|
|
len = *(int32 *) s - 4;
|
|
s += 4;
|
|
}
|
|
return (string_output(s, len));
|
|
}
|
|
|
|
#if 0
|
|
struct varlena *
|
|
c_textin(unsigned char *str)
|
|
{
|
|
struct varlena *result;
|
|
int len;
|
|
|
|
if (str == NULL)
|
|
return ((struct varlena *) NULL);
|
|
|
|
result = (struct varlena *) string_input(str, 0, VARHDRSZ, &len);
|
|
VARSIZE(result) = len;
|
|
|
|
return (result);
|
|
}
|
|
|
|
int32 *
|
|
c_charin(unsigned char *str)
|
|
{
|
|
return (string_input(str, 1, 0, NULL));
|
|
}
|
|
#endif
|
|
|
|
/* end of file */
|
|
|
|
/*
|
|
* Local Variables:
|
|
* tab-width: 4
|
|
* c-indent-level: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
*/
|