From b1ee615a7f9b645d72ee560b74e4621ed5936cf8 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 9 May 2003 21:19:50 +0000 Subject: [PATCH] COPY BINARY uses the new binary I/O routines. Update a few more datatypes so that COPY BINARY regression test passes. --- doc/src/sgml/ref/copy.sgml | 30 +-- src/backend/commands/copy.c | 370 +++++++++++++++---------------- src/backend/libpq/pqformat.c | 143 +++++++++++- src/backend/utils/adt/float.c | 61 ++++- src/backend/utils/adt/geo_ops.c | 34 ++- src/backend/utils/adt/name.c | 69 +++--- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_proc.h | 18 +- src/include/catalog/pg_type.h | 12 +- src/include/libpq/pqformat.h | 6 +- src/include/utils/builtins.h | 8 +- src/include/utils/geo_decls.h | 4 +- 12 files changed, 502 insertions(+), 257 deletions(-) diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml index f60388bb05..0e24f8b3ee 100644 --- a/doc/src/sgml/ref/copy.sgml +++ b/doc/src/sgml/ref/copy.sgml @@ -1,5 +1,5 @@ @@ -541,28 +541,22 @@ ZW ZIMBABWE - XXX the following example is OBSOLETE and needs to be updated for the - 7.4 binary format: - - - - The following is the same data, output in binary format on a - Linux/i586 machine. The data is shown after filtering through the + The following is the same data, output in binary format. + The data is shown after filtering through the Unix utility od -c. The table has three columns; the first has type char(2), the second has type text, and the third has type integer. All the rows have a null value in the third column. -0000000 P G B C O P Y \n 377 \r \n \0 004 003 002 001 -0000020 \0 \0 \0 \0 \0 \0 \0 \0 003 \0 377 377 006 \0 \0 \0 -0000040 A F 377 377 017 \0 \0 \0 A F G H A N I S -0000060 T A N \0 \0 003 \0 377 377 006 \0 \0 \0 A L 377 -0000100 377 \v \0 \0 \0 A L B A N I A \0 \0 003 \0 -0000120 377 377 006 \0 \0 \0 D Z 377 377 \v \0 \0 \0 A L -0000140 G E R I A \0 \0 003 \0 377 377 006 \0 \0 \0 Z -0000160 M 377 377 \n \0 \0 \0 Z A M B I A \0 \0 003 -0000200 \0 377 377 006 \0 \0 \0 Z W 377 377 \f \0 \0 \0 Z -0000220 I M B A B W E \0 \0 377 377 +0000000 P G C O P Y \n 377 \r \n \0 \0 \0 \0 \0 \0 +0000020 \0 \0 \0 \0 003 \0 \0 \0 002 A F \0 \0 \0 013 A +0000040 F G H A N I S T A N 377 377 377 377 \0 003 +0000060 \0 \0 \0 002 A L \0 \0 \0 007 A L B A N I +0000100 A 377 377 377 377 \0 003 \0 \0 \0 002 D Z \0 \0 \0 +0000120 007 A L G E R I A 377 377 377 377 \0 003 \0 \0 +0000140 \0 002 Z M \0 \0 \0 006 Z A M B I A 377 377 +0000160 377 377 \0 003 \0 \0 \0 002 Z W \0 \0 \0 \b Z I +0000200 M B A B W E 377 377 377 377 377 377 diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 06c29c4894..20a46cc922 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.199 2003/05/09 18:08:48 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.200 2003/05/09 21:19:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "access/genam.h" #include "access/heapam.h" @@ -88,13 +90,13 @@ static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print); static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, char *delim, char *null_print); -static Oid GetInputFunction(Oid type); -static Oid GetTypeElement(Oid type); static char *CopyReadAttribute(const char *delim, CopyReadResult *result); +static Datum CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, + Oid typelem, bool *isnull); static void CopyAttributeOut(char *string, char *delim); static List *CopyGetAttnums(Relation rel, List *attnamelist); -static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0"; +static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; /* * Static communication variables ... pretty grotty, but COPY has @@ -137,6 +139,10 @@ static int CopyGetChar(void); #define CopyGetEof() (fe_eof) static int CopyPeekChar(void); static void CopyDonePeek(int c, bool pickup); +static void CopySendInt32(int32 val); +static int32 CopyGetInt32(void); +static void CopySendInt16(int16 val); +static int16 CopyGetInt16(void); /* * Send copy start/stop messages for frontend copies. These have changed @@ -519,6 +525,58 @@ CopyDonePeek(int c, bool pickup) } +/* + * These functions do apply some data conversion + */ + +/* + * CopySendInt32 sends an int32 in network byte order + */ +static void +CopySendInt32(int32 val) +{ + uint32 buf; + + buf = htonl((uint32) val); + CopySendData(&buf, sizeof(buf)); +} + +/* + * CopyGetInt32 reads an int32 that appears in network byte order + */ +static int32 +CopyGetInt32(void) +{ + uint32 buf; + + CopyGetData(&buf, sizeof(buf)); + return (int32) ntohl(buf); +} + +/* + * CopySendInt16 sends an int16 in network byte order + */ +static void +CopySendInt16(int16 val) +{ + uint16 buf; + + buf = htons((uint16) val); + CopySendData(&buf, sizeof(buf)); +} + +/* + * CopyGetInt16 reads an int16 that appears in network byte order + */ +static int16 +CopyGetInt16(void) +{ + uint16 buf; + + CopyGetData(&buf, sizeof(buf)); + return (int16) ntohs(buf); +} + /* * DoCopy executes the SQL COPY statement. @@ -802,7 +860,6 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, FmgrInfo *out_functions; Oid *elements; bool *isvarlena; - int16 fld_size; char *string; Snapshot mySnapshot; List *cur; @@ -817,7 +874,6 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, /* * Get info about the columns we need to process. * - * For binary copy we really only need isvarlena, but compute it all... * +1's here are to avoid palloc(0) in a zero-column table. */ out_functions = (FmgrInfo *) palloc((num_phys_attrs + 1) * sizeof(FmgrInfo)); @@ -828,12 +884,15 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, int attnum = lfirsti(cur); Oid out_func_oid; - getTypeOutputInfo(attr[attnum - 1]->atttypid, - &out_func_oid, &elements[attnum - 1], - &isvarlena[attnum - 1]); + if (binary) + getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid, + &out_func_oid, &elements[attnum - 1], + &isvarlena[attnum - 1]); + else + getTypeOutputInfo(attr[attnum - 1]->atttypid, + &out_func_oid, &elements[attnum - 1], + &isvarlena[attnum - 1]); fmgr_info(out_func_oid, &out_functions[attnum - 1]); - if (binary && attr[attnum - 1]->attlen == -2) - elog(ERROR, "COPY BINARY: cstring not supported"); } /* @@ -854,18 +913,15 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, int32 tmp; /* Signature */ - CopySendData((char *) BinarySignature, 12); - /* Integer layout field */ - tmp = 0x01020304; - CopySendData(&tmp, sizeof(int32)); + CopySendData((char *) BinarySignature, 11); /* Flags field */ tmp = 0; if (oids) tmp |= (1 << 16); - CopySendData(&tmp, sizeof(int32)); + CopySendInt32(tmp); /* No header extension */ tmp = 0; - CopySendData(&tmp, sizeof(int32)); + CopySendInt32(tmp); } mySnapshot = CopyQuerySnapshot(); @@ -884,17 +940,15 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, if (binary) { /* Binary per-tuple header */ - int16 fld_count = attr_count; - - CopySendData(&fld_count, sizeof(int16)); - /* Send OID if wanted --- note fld_count doesn't include it */ + CopySendInt16(attr_count); + /* Send OID if wanted --- note attr_count doesn't include it */ if (oids) { Oid oid = HeapTupleGetOid(tuple); - fld_size = sizeof(Oid); - CopySendData(&fld_size, sizeof(int16)); - CopySendData(&oid, sizeof(Oid)); + /* Hack --- assume Oid is same size as int32 */ + CopySendInt32(sizeof(int32)); + CopySendInt32(oid); } } else @@ -927,14 +981,9 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, if (isnull) { if (!binary) - { CopySendString(null_print); /* null indicator */ - } else - { - fld_size = 0; /* null marker */ - CopySendData(&fld_size, sizeof(int16)); - } + CopySendInt32(-1); /* null marker */ } else { @@ -948,40 +997,15 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, } else { - fld_size = attr[attnum - 1]->attlen; - CopySendData(&fld_size, sizeof(int16)); - if (isvarlena[attnum - 1]) - { - /* varlena */ - Assert(fld_size == -1); + bytea *outputbytes; - /* If we have a toasted datum, detoast it */ - value = PointerGetDatum(PG_DETOAST_DATUM(value)); - - CopySendData(DatumGetPointer(value), - VARSIZE(value)); - } - else if (!attr[attnum - 1]->attbyval) - { - /* fixed-length pass-by-reference */ - Assert(fld_size > 0); - CopySendData(DatumGetPointer(value), - fld_size); - } - else - { - /* pass-by-value */ - Datum datumBuf; - - /* - * We need this horsing around because we don't - * know how shorter data values are aligned within - * a Datum. - */ - store_att_byval(&datumBuf, value, fld_size); - CopySendData(&datumBuf, - fld_size); - } + outputbytes = DatumGetByteaP(FunctionCall2(&out_functions[attnum - 1], + value, + ObjectIdGetDatum(elements[attnum - 1]))); + /* We assume the result will not have been toasted */ + CopySendInt32(VARSIZE(outputbytes) - VARHDRSZ); + CopySendData(VARDATA(outputbytes), + VARSIZE(outputbytes) - VARHDRSZ); } } } @@ -996,9 +1020,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, if (binary) { /* Generate trailer for a binary copy */ - int16 fld_count = -1; - - CopySendData(&fld_count, sizeof(int16)); + CopySendInt16(-1); } MemoryContextDelete(mycontext); @@ -1033,7 +1055,9 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, attr_count, num_defaults; FmgrInfo *in_functions; + FmgrInfo oid_in_function; Oid *elements; + Oid oid_in_element; ExprState **constraintexprs; bool hasConstraints = false; int i; @@ -1042,6 +1066,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, Datum *values; char *nulls; bool done = false; + bool isnull; ResultRelInfo *resultRelInfo; EState *estate = CreateExecutorState(); /* for ExecConstraints() */ TupleTable tupleTable; @@ -1086,7 +1111,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, * Pick up the required catalog information for each attribute in the * relation, including the input function, the element type (to pass * to the input function), and info about defaults and constraints. - * (We don't actually use the input function if it's a binary copy.) + * (Which input function we use depends on text/binary format choice.) * +1's here are to avoid palloc(0) in a zero-column table. */ in_functions = (FmgrInfo *) palloc((num_phys_attrs + 1) * sizeof(FmgrInfo)); @@ -1101,21 +1126,19 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, if (attr[i]->attisdropped) continue; - /* Fetch the input function */ - in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); + /* Fetch the input function and typelem info */ + if (binary) + getTypeBinaryInputInfo(attr[i]->atttypid, + &in_func_oid, &elements[i]); + else + getTypeInputInfo(attr[i]->atttypid, + &in_func_oid, &elements[i]); fmgr_info(in_func_oid, &in_functions[i]); - elements[i] = GetTypeElement(attr[i]->atttypid); /* Get default info if needed */ - if (intMember(i + 1, attnumlist)) + if (!intMember(i + 1, attnumlist)) { - /* attribute is to be copied */ - if (binary && attr[i]->attlen == -2) - elog(ERROR, "COPY BINARY: cstring not supported"); - } - else - { - /* attribute is NOT to be copied */ + /* attribute is NOT to be copied from input */ /* use default value if one exists */ Node *defexpr = build_column_default(rel, i + 1); @@ -1174,19 +1197,15 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, else { /* Read and verify binary header */ - char readSig[12]; + char readSig[11]; int32 tmp; /* Signature */ - CopyGetData(readSig, 12); - if (CopyGetEof() || memcmp(readSig, BinarySignature, 12) != 0) + CopyGetData(readSig, 11); + if (CopyGetEof() || memcmp(readSig, BinarySignature, 11) != 0) elog(ERROR, "COPY BINARY: file signature not recognized"); - /* Integer layout field */ - CopyGetData(&tmp, sizeof(int32)); - if (CopyGetEof() || tmp != 0x01020304) - elog(ERROR, "COPY BINARY: incompatible integer layout"); /* Flags field */ - CopyGetData(&tmp, sizeof(int32)); + tmp = CopyGetInt32(); if (CopyGetEof()) elog(ERROR, "COPY BINARY: bogus file header (missing flags)"); file_has_oids = (tmp & (1 << 16)) != 0; @@ -1194,7 +1213,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, if ((tmp >> 16) != 0) elog(ERROR, "COPY BINARY: unrecognized critical flags in header"); /* Header extension length */ - CopyGetData(&tmp, sizeof(int32)); + tmp = CopyGetInt32(); if (CopyGetEof() || tmp < 0) elog(ERROR, "COPY BINARY: bogus file header (missing length)"); /* Skip extension header, if present */ @@ -1206,6 +1225,13 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, } } + if (file_has_oids && binary) + { + getTypeBinaryInputInfo(OIDOID, + &in_func_oid, &oid_in_element); + fmgr_info(in_func_oid, &oid_in_function); + } + values = (Datum *) palloc((num_phys_attrs + 1) * sizeof(Datum)); nulls = (char *) palloc((num_phys_attrs + 1) * sizeof(char)); @@ -1351,10 +1377,9 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, else { /* binary */ - int16 fld_count, - fld_size; + int16 fld_count; - CopyGetData(&fld_count, sizeof(int16)); + fld_count = CopyGetInt16(); if (CopyGetEof() || fld_count == -1) { done = true; @@ -1367,16 +1392,12 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, if (file_has_oids) { - CopyGetData(&fld_size, sizeof(int16)); - if (CopyGetEof()) - elog(ERROR, "COPY BINARY: unexpected EOF"); - if (fld_size != (int16) sizeof(Oid)) - elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d", - (int) fld_size, (int) sizeof(Oid)); - CopyGetData(&loaded_oid, sizeof(Oid)); - if (CopyGetEof()) - elog(ERROR, "COPY BINARY: unexpected EOF"); - if (loaded_oid == InvalidOid) + loaded_oid = + DatumGetObjectId(CopyReadBinaryAttribute(0, + &oid_in_function, + oid_in_element, + &isnull)); + if (isnull || loaded_oid == InvalidOid) elog(ERROR, "COPY BINARY: Invalid Oid"); } @@ -1387,63 +1408,11 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, int m = attnum - 1; i++; - - CopyGetData(&fld_size, sizeof(int16)); - if (CopyGetEof()) - elog(ERROR, "COPY BINARY: unexpected EOF"); - if (fld_size == 0) - continue; /* it's NULL; nulls[attnum-1] already set */ - if (fld_size != attr[m]->attlen) - elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d", - i, (int) fld_size, (int) attr[m]->attlen); - if (fld_size == -1) - { - /* varlena field */ - int32 varlena_size; - Pointer varlena_ptr; - - CopyGetData(&varlena_size, sizeof(int32)); - if (CopyGetEof()) - elog(ERROR, "COPY BINARY: unexpected EOF"); - if (varlena_size < (int32) sizeof(int32)) - elog(ERROR, "COPY BINARY: bogus varlena length"); - varlena_ptr = (Pointer) palloc(varlena_size); - VARATT_SIZEP(varlena_ptr) = varlena_size; - CopyGetData(VARDATA(varlena_ptr), - varlena_size - sizeof(int32)); - if (CopyGetEof()) - elog(ERROR, "COPY BINARY: unexpected EOF"); - values[m] = PointerGetDatum(varlena_ptr); - } - else if (!attr[m]->attbyval) - { - /* fixed-length pass-by-reference */ - Pointer refval_ptr; - - Assert(fld_size > 0); - refval_ptr = (Pointer) palloc(fld_size); - CopyGetData(refval_ptr, fld_size); - if (CopyGetEof()) - elog(ERROR, "COPY BINARY: unexpected EOF"); - values[m] = PointerGetDatum(refval_ptr); - } - else - { - /* pass-by-value */ - Datum datumBuf; - - /* - * We need this horsing around because we don't know - * how shorter data values are aligned within a Datum. - */ - Assert(fld_size > 0 && fld_size <= sizeof(Datum)); - CopyGetData(&datumBuf, fld_size); - if (CopyGetEof()) - elog(ERROR, "COPY BINARY: unexpected EOF"); - values[m] = fetch_att(&datumBuf, true, fld_size); - } - - nulls[m] = ' '; + values[m] = CopyReadBinaryAttribute(i, + &in_functions[m], + elements[m], + &isnull); + nulls[m] = isnull ? 'n' : ' '; } } @@ -1454,8 +1423,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, */ for (i = 0; i < num_defaults; i++) { - bool isnull; - values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, &isnull, NULL); if (!isnull) @@ -1472,7 +1439,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, for (i = 0; i < num_phys_attrs; i++) { ExprState *exprstate = constraintexprs[i]; - bool isnull; if (exprstate == NULL) continue; /* no constraint for this attr */ @@ -1577,38 +1543,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, } -static Oid -GetInputFunction(Oid type) -{ - HeapTuple typeTuple; - Oid result; - - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(type), - 0, 0, 0); - if (!HeapTupleIsValid(typeTuple)) - elog(ERROR, "GetInputFunction: Cache lookup of type %u failed", type); - result = ((Form_pg_type) GETSTRUCT(typeTuple))->typinput; - ReleaseSysCache(typeTuple); - return result; -} - -static Oid -GetTypeElement(Oid type) -{ - HeapTuple typeTuple; - Oid result; - - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(type), - 0, 0, 0); - if (!HeapTupleIsValid(typeTuple)) - elog(ERROR, "GetTypeElement: Cache lookup of type %u failed", type); - result = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem; - ReleaseSysCache(typeTuple); - return result; -} - /* * Read the value of a single attribute. * @@ -1624,7 +1558,6 @@ GetTypeElement(Oid type) * * delim is the column delimiter string. */ - static char * CopyReadAttribute(const char *delim, CopyReadResult *result) { @@ -1848,6 +1781,57 @@ copy_eof: return attribute_buf.data; } +/* + * Read a binary attribute + */ +static Datum +CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem, + bool *isnull) +{ + int32 fld_size; + Datum result; + + fld_size = CopyGetInt32(); + if (CopyGetEof()) + elog(ERROR, "COPY BINARY: unexpected EOF"); + if (fld_size == -1) + { + *isnull = true; + return (Datum) 0; + } + if (fld_size < 0) + elog(ERROR, "COPY BINARY: bogus size for field %d", column_no); + + /* reset attribute_buf to empty, and load raw data in it */ + attribute_buf.len = 0; + attribute_buf.data[0] = '\0'; + attribute_buf.cursor = 0; + + enlargeStringInfo(&attribute_buf, fld_size); + + CopyGetData(attribute_buf.data, fld_size); + if (CopyGetEof()) + elog(ERROR, "COPY BINARY: unexpected EOF"); + + attribute_buf.len = fld_size; + attribute_buf.data[fld_size] = '\0'; + + /* Call the column type's binary input converter */ + result = FunctionCall2(flinfo, + PointerGetDatum(&attribute_buf), + ObjectIdGetDatum(typelem)); + + /* Trouble if it didn't eat the whole buffer */ + if (attribute_buf.cursor != attribute_buf.len) + elog(ERROR, "Improper binary format in field %d", column_no); + + *isnull = false; + return result; +} + +/* + * Send text representation of one attribute, with conversion and escaping + */ static void CopyAttributeOut(char *server_string, char *delim) { diff --git a/src/backend/libpq/pqformat.c b/src/backend/libpq/pqformat.c index 65fb49f48a..0ea055b522 100644 --- a/src/backend/libpq/pqformat.c +++ b/src/backend/libpq/pqformat.c @@ -24,7 +24,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.30 2003/05/09 15:44:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.31 2003/05/09 21:19:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,6 +35,8 @@ * pq_sendbyte - append a raw byte to a StringInfo buffer * pq_sendint - append a binary integer to a StringInfo buffer * pq_sendint64 - append a binary 8-byte int to a StringInfo buffer + * pq_sendfloat4 - append a float4 to a StringInfo buffer + * pq_sendfloat8 - append a float8 to a StringInfo buffer * pq_sendbytes - append raw data to a StringInfo buffer * pq_sendcountedtext - append a counted text string (with character set conversion) * pq_sendtext - append a text string (with conversion) @@ -56,6 +58,8 @@ * pq_getmsgbyte - get a raw byte from a message buffer * pq_getmsgint - get a binary integer from a message buffer * pq_getmsgint64 - get a binary 8-byte int from a message buffer + * pq_getmsgfloat4 - get a float4 from a message buffer + * pq_getmsgfloat8 - get a float8 from a message buffer * pq_getmsgbytes - get raw data from a message buffer * pq_copymsgbytes - copy raw data from a message buffer * pq_getmsgtext - get a counted text string (with conversion) @@ -261,6 +265,82 @@ pq_sendint64(StringInfo buf, int64 i) appendBinaryStringInfo(buf, (char *) &n32, 4); } +/* -------------------------------- + * pq_sendfloat4 - append a float4 to a StringInfo buffer + * + * The point of this routine is to localize knowledge of the external binary + * representation of float4, which is a component of several datatypes. + * + * We currently assume that float4 should be byte-swapped in the same way + * as int4. This rule is not perfect but it gives us portability across + * most IEEE-float-using architectures. + * -------------------------------- + */ +void +pq_sendfloat4(StringInfo buf, float4 f) +{ + union + { + float4 f; + uint32 i; + } swap; + + swap.f = f; + swap.i = htonl(swap.i); + + appendBinaryStringInfo(buf, (char *) &swap.i, 4); +} + +/* -------------------------------- + * pq_sendfloat8 - append a float8 to a StringInfo buffer + * + * The point of this routine is to localize knowledge of the external binary + * representation of float8, which is a component of several datatypes. + * + * We currently assume that float8 should be byte-swapped in the same way + * as int8. This rule is not perfect but it gives us portability across + * most IEEE-float-using architectures. + * -------------------------------- + */ +void +pq_sendfloat8(StringInfo buf, float8 f) +{ +#ifdef INT64_IS_BUSTED + union + { + float8 f; + uint32 h[2]; + } swap; + + swap.f = f; + swap.h[0] = htonl(swap.h[0]); + swap.h[1] = htonl(swap.h[1]); + + /* Have to figure out endianness by testing... */ + if (((uint32) 1) == htonl((uint32) 1)) + { + /* machine seems to be big-endian, send h[0] first */ + appendBinaryStringInfo(buf, (char *) &swap.h[0], 4); + appendBinaryStringInfo(buf, (char *) &swap.h[1], 4); + } + else + { + /* machine seems to be little-endian, send h[1] first */ + appendBinaryStringInfo(buf, (char *) &swap.h[1], 4); + appendBinaryStringInfo(buf, (char *) &swap.h[0], 4); + } +#else + union + { + float8 f; + int64 i; + } swap; + + swap.f = f; + pq_sendint64(buf, swap.i); +#endif +} + /* -------------------------------- * pq_endmessage - send the completed message to the frontend * @@ -432,6 +512,67 @@ pq_getmsgint64(StringInfo msg) return result; } +/* -------------------------------- + * pq_getmsgfloat4 - get a float4 from a message buffer + * + * See notes for pq_sendfloat4. + * -------------------------------- + */ +float4 +pq_getmsgfloat4(StringInfo msg) +{ + union + { + float4 f; + uint32 i; + } swap; + + swap.i = pq_getmsgint(msg, 4); + return swap.f; +} + +/* -------------------------------- + * pq_getmsgfloat8 - get a float8 from a message buffer + * + * See notes for pq_sendfloat8. + * -------------------------------- + */ +float8 +pq_getmsgfloat8(StringInfo msg) +{ +#ifdef INT64_IS_BUSTED + union + { + float8 f; + uint32 h[2]; + } swap; + + /* Have to figure out endianness by testing... */ + if (((uint32) 1) == htonl((uint32) 1)) + { + /* machine seems to be big-endian, receive h[0] first */ + swap.h[0] = pq_getmsgint(msg, 4); + swap.h[1] = pq_getmsgint(msg, 4); + } + else + { + /* machine seems to be little-endian, receive h[1] first */ + swap.h[1] = pq_getmsgint(msg, 4); + swap.h[0] = pq_getmsgint(msg, 4); + } + return swap.f; +#else + union + { + float8 f; + int64 i; + } swap; + + swap.i = pq_getmsgint64(msg); + return swap.f; +#endif +} + /* -------------------------------- * pq_getmsgbytes - get raw data from a message buffer * diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 4f770a2e97..e954e7e949 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -8,16 +8,18 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.86 2003/05/09 16:31:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.87 2003/05/09 21:19:49 tgl Exp $ * *------------------------------------------------------------------------- */ /*---------- * OLD COMMENTS * Basic float4 ops: - * float4in, float4out, float4abs, float4um, float4up + * float4in, float4out, float4recv, float4send + * float4abs, float4um, float4up * Basic float8 ops: - * float8in, float8out, float8abs, float8um, float8up + * float8in, float8out, float8recv, float8send + * float8abs, float8um, float8up * Arithmetic operators: * float4pl, float4mi, float4mul, float4div * float8pl, float8mi, float8mul, float8div @@ -63,6 +65,7 @@ #include "catalog/pg_type.h" #include "fmgr.h" +#include "libpq/pqformat.h" #include "utils/array.h" #include "utils/builtins.h" @@ -242,6 +245,31 @@ float4out(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(ascii); } +/* + * float4recv - converts external binary format to float4 + */ +Datum +float4recv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + + PG_RETURN_FLOAT4(pq_getmsgfloat4(buf)); +} + +/* + * float4send - converts float4 to binary format + */ +Datum +float4send(PG_FUNCTION_ARGS) +{ + float4 num = PG_GETARG_FLOAT4(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendfloat4(&buf, num); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + /* * float8in - converts "num" to float8 * restricted syntax: @@ -280,7 +308,6 @@ float8in(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(val); } - /* * float8out - converts float8 number to a string * using a standard output format @@ -310,6 +337,32 @@ float8out(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(ascii); } +/* + * float8recv - converts external binary format to float8 + */ +Datum +float8recv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + + PG_RETURN_FLOAT8(pq_getmsgfloat8(buf)); +} + +/* + * float8send - converts float8 to binary format + */ +Datum +float8send(PG_FUNCTION_ARGS) +{ + float8 num = PG_GETARG_FLOAT8(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendfloat8(&buf, num); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + + /* ========== PUBLIC ROUTINES ========== */ diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index d8d1f7c3af..956bd1753f 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.75 2003/03/11 21:01:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.76 2003/05/09 21:19:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,11 +19,11 @@ #include #include +#include "libpq/pqformat.h" #include "utils/builtins.h" #include "utils/geo_decls.h" #ifndef M_PI -/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */ #define M_PI 3.14159265358979323846 #endif @@ -1589,6 +1589,36 @@ point_out(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(path_encode(-1, 1, pt)); } +/* + * point_recv - converts external binary format to point + */ +Datum +point_recv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + Point *point; + + point = (Point *) palloc(sizeof(Point)); + point->x = pq_getmsgfloat8(buf); + point->y = pq_getmsgfloat8(buf); + PG_RETURN_POINT_P(point); +} + +/* + * point_send - converts point to binary format + */ +Datum +point_send(PG_FUNCTION_ARGS) +{ + Point *pt = PG_GETARG_POINT_P(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendfloat8(&buf, pt->x); + pq_sendfloat8(&buf, pt->y); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + static Point * point_construct(double x, double y) diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c index 607f7876a8..b7a56cb1cb 100644 --- a/src/backend/utils/adt/name.c +++ b/src/backend/utils/adt/name.c @@ -2,8 +2,10 @@ * * name.c * Functions for the built-in type "name". + * * name replaces char16 and is carefully implemented so that it - * is a string of length NAMEDATALEN. DO NOT use hard-coded constants anywhere + * is a string of physical length NAMEDATALEN. + * DO NOT use hard-coded constants anywhere * always use NAMEDATALEN as the symbolic constant! - jolly 8/21/95 * * @@ -12,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/name.c,v 1.44 2003/04/27 23:22:13 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/name.c,v 1.45 2003/05/09 21:19:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,11 +22,13 @@ #include "catalog/namespace.h" #include "catalog/pg_type.h" +#include "libpq/pqformat.h" +#include "mb/pg_wchar.h" #include "miscadmin.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" -#include "mb/pg_wchar.h" + /***************************************************************************** * USER I/O ROUTINES (none) * @@ -53,9 +57,7 @@ namein(PG_FUNCTION_ARGS) len = pg_mbcliplen(s, len, NAMEDATALEN - 1); - result = (NameData *) palloc(NAMEDATALEN); - /* always keep it null-padded */ - memset(result, 0, NAMEDATALEN); + result = (NameData *) palloc0(NAMEDATALEN); memcpy(NameStr(*result), s, len); PG_RETURN_NAME(result); @@ -72,6 +74,40 @@ nameout(PG_FUNCTION_ARGS) PG_RETURN_CSTRING(pstrdup(NameStr(*s))); } +/* + * namerecv - converts external binary format to name + */ +Datum +namerecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + Name result; + char *str; + int nbytes; + + str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); + if (nbytes >= NAMEDATALEN) + elog(ERROR, "namerecv: input name too long"); + result = (NameData *) palloc0(NAMEDATALEN); + memcpy(result, str, nbytes); + pfree(str); + PG_RETURN_NAME(result); +} + +/* + * namesend - converts name to binary format + */ +Datum +namesend(PG_FUNCTION_ARGS) +{ + Name s = PG_GETARG_NAME(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendtext(&buf, NameStr(*s), strlen(NameStr(*s))); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + /***************************************************************************** * PUBLIC ROUTINES * @@ -283,24 +319,3 @@ current_schemas(PG_FUNCTION_ARGS) PG_RETURN_POINTER(array); } - - -/***************************************************************************** - * PRIVATE ROUTINES * - *****************************************************************************/ - -#ifdef NOT_USED -uint32 -NameComputeLength(Name name) -{ - char *charP; - int length; - - for (length = 0, charP = NameStr(*name); - length < NAMEDATALEN && *charP != '\0'; - length++, charP++) - ; - return (uint32) length; -} - -#endif diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 8046e5c4c6..e205448ec6 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.188 2003/05/09 15:44:40 tgl Exp $ + * $Id: catversion.h,v 1.189 2003/05/09 21:19:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200305091 +#define CATALOG_VERSION_NO 200305092 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 0d801214f5..bc186f2eed 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.295 2003/05/09 15:44:40 tgl Exp $ + * $Id: pg_proc.h,v 1.296 2003/05/09 21:19:49 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -3197,6 +3197,22 @@ DATA(insert OID = 2420 ( oidvectorrecv PGNSP PGUID 12 f f t f i 1 30 "2281" DESCR("I/O"); DATA(insert OID = 2421 ( oidvectorsend PGNSP PGUID 12 f f t f i 1 17 "30" oidvectorsend - _null_ )); DESCR("I/O"); +DATA(insert OID = 2422 ( namerecv PGNSP PGUID 12 f f t f s 1 19 "2281" namerecv - _null_ )); +DESCR("I/O"); +DATA(insert OID = 2423 ( namesend PGNSP PGUID 12 f f t f s 1 17 "19" namesend - _null_ )); +DESCR("I/O"); +DATA(insert OID = 2424 ( float4recv PGNSP PGUID 12 f f t f i 1 700 "2281" float4recv - _null_ )); +DESCR("I/O"); +DATA(insert OID = 2425 ( float4send PGNSP PGUID 12 f f t f i 1 17 "700" float4send - _null_ )); +DESCR("I/O"); +DATA(insert OID = 2426 ( float8recv PGNSP PGUID 12 f f t f i 1 701 "2281" float8recv - _null_ )); +DESCR("I/O"); +DATA(insert OID = 2427 ( float8send PGNSP PGUID 12 f f t f i 1 17 "701" float8send - _null_ )); +DESCR("I/O"); +DATA(insert OID = 2428 ( point_recv PGNSP PGUID 12 f f t f i 1 600 "2281" point_recv - _null_ )); +DESCR("I/O"); +DATA(insert OID = 2429 ( point_send PGNSP PGUID 12 f f t f i 1 17 "600" point_send - _null_ )); +DESCR("I/O"); /* diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 3091578b60..ea504bd793 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_type.h,v 1.142 2003/05/09 15:44:41 tgl Exp $ + * $Id: pg_type.h,v 1.143 2003/05/09 21:19:50 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -250,8 +250,8 @@ DATA(insert OID = 18 ( char PGNSP PGUID 1 t b t \054 0 0 charin charout - - DESCR("single character"); #define CHAROID 18 -DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein nameout - - i p f 0 -1 0 _null_ _null_ )); -DESCR("31-character type for storing system identifiers"); +DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein nameout namerecv namesend i p f 0 -1 0 _null_ _null_ )); +DESCR("63-character type for storing system identifiers"); #define NAMEOID 19 DATA(insert OID = 20 ( int8 PGNSP PGUID 8 f b t \054 0 0 int8in int8out int8recv int8send d p f 0 -1 0 _null_ _null_ )); @@ -323,7 +323,7 @@ DESCR("storage manager"); /* OIDS 500 - 599 */ /* OIDS 600 - 699 */ -DATA(insert OID = 600 ( point PGNSP PGUID 16 f b t \054 0 701 point_in point_out - - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 600 ( point PGNSP PGUID 16 f b t \054 0 701 point_in point_out point_recv point_send d p f 0 -1 0 _null_ _null_ )); DESCR("geometric point '(x, y)'"); #define POINTOID 600 DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b t \054 0 600 lseg_in lseg_out - - d p f 0 -1 0 _null_ _null_ )); @@ -347,10 +347,10 @@ DESCR(""); /* OIDS 700 - 799 */ -DATA(insert OID = 700 ( float4 PGNSP PGUID 4 f b t \054 0 0 float4in float4out - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 700 ( float4 PGNSP PGUID 4 f b t \054 0 0 float4in float4out float4recv float4send i p f 0 -1 0 _null_ _null_ )); DESCR("single-precision floating point number, 4-byte storage"); #define FLOAT4OID 700 -DATA(insert OID = 701 ( float8 PGNSP PGUID 8 f b t \054 0 0 float8in float8out - - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 701 ( float8 PGNSP PGUID 8 f b t \054 0 0 float8in float8out float8recv float8send d p f 0 -1 0 _null_ _null_ )); DESCR("double-precision floating point number, 8-byte storage"); #define FLOAT8OID 701 DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b t \054 0 0 nabstimein nabstimeout - - i p f 0 -1 0 _null_ _null_ )); diff --git a/src/include/libpq/pqformat.h b/src/include/libpq/pqformat.h index bbeff288c4..2102960e88 100644 --- a/src/include/libpq/pqformat.h +++ b/src/include/libpq/pqformat.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pqformat.h,v 1.17 2003/05/09 15:44:42 tgl Exp $ + * $Id: pqformat.h,v 1.18 2003/05/09 21:19:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,8 @@ extern void pq_sendtext(StringInfo buf, const char *str, int slen); extern void pq_sendstring(StringInfo buf, const char *str); extern void pq_sendint(StringInfo buf, int i, int b); extern void pq_sendint64(StringInfo buf, int64 i); +extern void pq_sendfloat4(StringInfo buf, float4 f); +extern void pq_sendfloat8(StringInfo buf, float8 f); extern void pq_endmessage(StringInfo buf); extern void pq_begintypsend(StringInfo buf); @@ -35,6 +37,8 @@ extern void pq_putemptymessage(char msgtype); extern int pq_getmsgbyte(StringInfo msg); extern unsigned int pq_getmsgint(StringInfo msg, int b); extern int64 pq_getmsgint64(StringInfo msg); +extern float4 pq_getmsgfloat4(StringInfo msg); +extern float8 pq_getmsgfloat8(StringInfo msg); extern const char *pq_getmsgbytes(StringInfo msg, int datalen); extern void pq_copymsgbytes(StringInfo msg, char *buf, int datalen); extern char *pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 15dfd11a1f..85b34308ee 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: builtins.h,v 1.213 2003/05/09 15:44:42 tgl Exp $ + * $Id: builtins.h,v 1.214 2003/05/09 21:19:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -181,6 +181,8 @@ extern Datum int2shr(PG_FUNCTION_ARGS); /* name.c */ extern Datum namein(PG_FUNCTION_ARGS); extern Datum nameout(PG_FUNCTION_ARGS); +extern Datum namerecv(PG_FUNCTION_ARGS); +extern Datum namesend(PG_FUNCTION_ARGS); extern Datum nameeq(PG_FUNCTION_ARGS); extern Datum namene(PG_FUNCTION_ARGS); extern Datum namelt(PG_FUNCTION_ARGS); @@ -222,8 +224,12 @@ extern int extra_float_digits; extern Datum float4in(PG_FUNCTION_ARGS); extern Datum float4out(PG_FUNCTION_ARGS); +extern Datum float4recv(PG_FUNCTION_ARGS); +extern Datum float4send(PG_FUNCTION_ARGS); extern Datum float8in(PG_FUNCTION_ARGS); extern Datum float8out(PG_FUNCTION_ARGS); +extern Datum float8recv(PG_FUNCTION_ARGS); +extern Datum float8send(PG_FUNCTION_ARGS); extern Datum float4abs(PG_FUNCTION_ARGS); extern Datum float4um(PG_FUNCTION_ARGS); extern Datum float4up(PG_FUNCTION_ARGS); diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h index 0e29908977..91cbe10d35 100644 --- a/src/include/utils/geo_decls.h +++ b/src/include/utils/geo_decls.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: geo_decls.h,v 1.38 2002/06/20 20:29:52 momjian Exp $ + * $Id: geo_decls.h,v 1.39 2003/05/09 21:19:50 tgl Exp $ * * NOTE * These routines do *not* use the float types from adt/. @@ -188,6 +188,8 @@ typedef struct /* public point routines */ extern Datum point_in(PG_FUNCTION_ARGS); extern Datum point_out(PG_FUNCTION_ARGS); +extern Datum point_recv(PG_FUNCTION_ARGS); +extern Datum point_send(PG_FUNCTION_ARGS); extern Datum construct_point(PG_FUNCTION_ARGS); extern Datum point_left(PG_FUNCTION_ARGS); extern Datum point_right(PG_FUNCTION_ARGS);