From 20c3d9dd4883fc27735c7de777afca4f03c7a492 Mon Sep 17 00:00:00 2001 From: Mark Wong Date: Thu, 30 Jul 2026 22:19:31 +0000 Subject: [PATCH] doc: Add binary data format descriptions Create a new chapter called "Binary Format of Data Types", describing how the native data types are represented in binary format. Remove testlibpq3, which had a few code examples. Discussion: https://postgr.es/m/Yqu1MmYGrOQLsD7D%40workstation-mark-wong --- doc/src/sgml/binary-format.sgml | 970 +++++++++++++++++++++++++++++++ doc/src/sgml/datatype.sgml | 6 + doc/src/sgml/filelist.sgml | 1 + doc/src/sgml/libpq.sgml | 239 -------- doc/src/sgml/postgres.sgml | 1 + doc/src/sgml/protocol.sgml | 5 +- src/test/examples/.gitignore | 1 - src/test/examples/Makefile | 1 - src/test/examples/testlibpq3.c | 230 -------- src/test/examples/testlibpq3.sql | 5 - 10 files changed, 981 insertions(+), 478 deletions(-) create mode 100644 doc/src/sgml/binary-format.sgml delete mode 100644 src/test/examples/testlibpq3.c delete mode 100644 src/test/examples/testlibpq3.sql diff --git a/doc/src/sgml/binary-format.sgml b/doc/src/sgml/binary-format.sgml new file mode 100644 index 00000000000..5425a106365 --- /dev/null +++ b/doc/src/sgml/binary-format.sgml @@ -0,0 +1,970 @@ + + + + Binary Format of Data Types + + + binary format + + + wire format + binary format + + + + In addition to the textual representation described in , every built-in data type has a + binary format for transmitting values between + server and client without converting to and from text. It maps + directly to the value's internal representation, so for many types it + is more compact and faster to process than the text format. It is + also more sensitive to representation details, so a binary client must + know each type's exact layout. This chapter documents those layouts + for the built-in data types. + + + + The binary format is what is transmitted when a field or parameter is + sent with format code 1 (binary) rather than + format code 0 (text); see for how format codes are + negotiated at the protocol level. When using libpq, binary result + columns are requested through the resultFormat + argument of PQexecParams + and related functions, and binary parameters are supplied through + paramFormats. + + + + The authoritative definition of each format is the type's + send and receive functions + in the server source code (for example, + int4send and int4recv in + src/backend/utils/adt/int.c). These descriptions + should let a client author reproduce the encoding without reading the + source, but the source is authoritative if the two disagree. + + + + General Conventions + + + These conventions apply to all the type descriptions below. + + + + + Byte order + + + All multi-byte integer quantities are transmitted in network + byte order, that is, most significant byte first (big-endian). + This applies to integer values and to integer fields within more + complex types, such as length words and array dimensions. A + client on a little-endian machine must therefore byte-swap these + quantities. + C programs can do this with the POSIX + ntohs() and ntohl() + functions for 16-bit and 32-bit quantities; there is currently no + standard function for 64-bit quantities, so those need an + equivalent 64-bit byte swap. + + + + + + Value length + + + The binary format described here is the payload of a single field + value. The length of that payload is carried separately by the + surrounding protocol message (or, for a NULL, + is given as -1 with no payload at all), so the + formats below do not include a leading overall length word unless + one is explicitly noted. Fixed-length types always occupy exactly + the number of bytes stated; variable-length types occupy whatever + the surrounding length indicates. + + + + + + Embedded values + + + Some container types (arrays, composites, ranges, and + multiranges) embed the binary representation of other values. In + those cases each embedded value is preceded by its own four-byte + length, and a length of -1 denotes a + NULL element with no following bytes. This is + the same convention used by the protocol for top-level values. + + + + + + Encoding + + + Character data is transmitted in the client encoding in effect for + the connection (see ), just as in the + text format. No terminating zero byte is added unless one is + explicitly noted. + + + + + + + + Numeric Types + + + The integer and floating-point types are transmitted as fixed-width + quantities in network byte order. The + smallserial, serial, and + bigserial types are not distinct types but notational + conveniences for smallint, integer, and + bigint columns with an attached sequence, so they are + transmitted using the corresponding integer format below. + + + + + smallint (int2) + + + A two-byte two's-complement signed integer, most significant byte + first. + + + + + + integer (int4) + + + A four-byte two's-complement signed integer, most significant byte + first. + + + + + + bigint (int8) + + + An eight-byte two's-complement signed integer, most significant + byte first. + + + + + + real (float4) + + + A four-byte IEEE 754 single-precision floating-point number (the + binary32 interchange format). Its four bytes + are transmitted in network byte order, so a client reads the four + bytes as a 32-bit integer, converts to local byte order (for + example with ntohl()), and then reinterprets + the resulting bit pattern as a float. + + + + + + double precision (float8) + + + An eight-byte IEEE 754 double-precision floating-point number (the + binary64 interchange format), transmitted as + eight bytes in network byte order. A client reads the eight bytes + as a 64-bit integer, converts to local byte order, and reinterprets + the bit pattern as a double. + + + + + + numeric + + + A numeric value is a variable-length structure + consisting of four two-byte fields followed by a sequence of + two-byte digits, all in network byte order: + + + + + ndigits: the number of base-10000 + digits that follow. + + + + + weight: a signed two-byte integer + giving the weight of the first digit. The first digit represents + units of 10000 raised to the power + weight, the second digit units of + 10000 raised to the power + weight - 1, and so on. + + + + + sign: 0x0000 for a + positive number, 0x4000 for a negative + number, 0xC000 for + NaN, 0xD000 for + +Infinity, and 0xF000 for + -Infinity. + + + + + dscale: the display scale, that is, + the number of decimal digits to display after the decimal point. + + + + + Each of the ndigits digits is a + two-byte integer in the range 0 to 9999, most significant digit + first. For the special values (NaN, + +Infinity, and -Infinity) + ndigits is zero and no digits follow. + + + + + + + + Monetary Type + + + A money value is transmitted as an eight-byte + two's-complement signed integer in network byte order. The integer + holds the amount scaled by the number of fractional digits of the + lc_monetary locale; with the common two-digit + locales the value is expressed in hundredths, so + $1.23 is transmitted as the integer + 123. + + + + + Character Types + + + The text, character varying + (varchar), and character + (bpchar) types are all transmitted as the raw bytes of + the string in the connection's client encoding, with no leading + length word and no terminating zero byte. The number of bytes is + determined by the length that the surrounding protocol message + supplies for the field. For + character(n) the value + includes any trailing spaces used to pad it to its declared length. + + + + The special types name and "char", used + mainly in the system catalogs, follow the same idea. A + name value is transmitted as the raw string bytes in the + client encoding with no length word or terminator (its length, + normally at most 63 bytes, comes from the surrounding message). A + "char" value (note the quotes; this is the internal + single-byte type, distinct from character) is + transmitted as exactly one byte. + + + + + Binary Data (<type>bytea</type>) + + + A bytea value is transmitted as its raw byte string, with + no leading length word, no terminating byte, and no escaping. The + number of bytes is determined by the length supplied for the field by + the surrounding protocol message. Unlike the text format for + bytea (see ), the binary + format performs no hex or backslash encoding. + + + + + Date/Time Types + + + The date and time types are transmitted as fixed-width integers in + network byte order. All of them count from the + PostgreSQL epoch, + 2000-01-01, rather than the Unix epoch, and time + quantities are measured in microseconds. + + + + + date + + + A four-byte signed integer giving the number of days since + 2000-01-01. Negative values are dates before + that day. The special values -infinity and + infinity are represented by the smallest and + largest 32-bit signed integers, respectively. + + + + + + time (without time zone) + + + An eight-byte signed integer giving the number of microseconds + since midnight (00:00:00). + + + + + + time with time zone (timetz) + + + An eight-byte signed integer giving the number of microseconds + since midnight, followed by a four-byte signed integer giving the + time zone offset in seconds. The offset is counted as seconds west + of UTC, so it is the negation of the usual ISO-style offset; for + example a value at UTC+5 has a zone of -18000. + + + + + + timestamp (without time zone) + + + An eight-byte signed integer giving the number of microseconds + since 2000-01-01 00:00:00. The special values + -infinity and infinity are + represented by the smallest and largest 64-bit signed integers, + respectively. + + + + + + timestamp with time zone + (timestamptz) + + + The same eight-byte representation as timestamp, but + the count of microseconds is measured from + 2000-01-01 00:00:00 UTC. No time zone is + transmitted; the value is always in UTC, and any display time zone + is applied only when converting to text. + + + + + + interval + + + An eight-byte signed integer giving a number of microseconds, + followed by a four-byte signed integer giving a number of days, + followed by a four-byte signed integer giving a number of months, + all in network byte order. The three fields are stored separately + (rather than normalized to a single unit) because the number of + days in a month and the number of microseconds in a day are not + fixed. + + + + + + + + Boolean Type + + + A boolean value is transmitted as a single byte whose + value is 1 for true and 0 for + false. No other byte values are produced by the server. + + + + + Enumerated Types + + + An enumerated (CREATE TYPE ... AS ENUM) value is + transmitted as the raw bytes of its label in the client encoding, + with no length word and no terminator, just like a text + value. Enum values are stored internally as object identifiers, but + the binary format uses the label text so it does not depend on the + OIDs assigned in a particular database. + + + + + Geometric Types + + + The geometric types are built out of double precision + coordinates, each transmitted as an eight-byte value in network byte + order exactly as described for double precision. + + + + + point + + + Two double precision values giving the coordinates + (x, y) (16 + bytes total). + + + + + + lseg and box + + + Four double precision values giving two points, + (x1, y1) and + (x2, y2), in + that order (32 bytes total). For a box the first + point is the upper-right corner and the second is the lower-left + corner. + + + + + + line + + + Three double precision values A, + B, and C, + the coefficients of the line Ax + By + C = 0 + (24 bytes total). + + + + + + path + + + A one-byte flag that is 1 for a closed path and + 0 for an open path, then a four-byte integer + giving the number of points, then that many points, each a pair of + double precision coordinates + (x, y). + + + + + + polygon + + + A four-byte integer giving the number of points, then that many + points, each a pair of double precision coordinates + (x, y). + + + + + + circle + + + Three double precision values: the center + (x, y) + followed by the radius (24 bytes total). + + + + + + + + Network Address Types + + + + inet and cidr + + + These share a layout of four leading bytes followed by the address + bytes: + + + + + one byte for the address family: 2 for an + IPv4 address or 3 for an IPv6 address. (These + are the server's values of the C constants + AF_INET and AF_INET + 1; + AF_INET is 2 on all supported + platforms.) + + + + + one byte for the number of bits in the netmask; + + + + + one byte that is 1 for a cidr + value and 0 for an inet value + (this flag is ignored on input); + + + + + one byte for the number of address bytes that follow + (4 for IPv4 or 16 for + IPv6); + + + + + the address itself, most significant byte first. + + + + + + + + macaddr + + + Six bytes, the six octets of the IEEE EUI-48 (MAC-48) address in + order, most significant octet first. + + + + + + macaddr8 + + + Eight bytes, the eight octets of the IEEE EUI-64 address in order, + most significant octet first. + + + + + + + + Bit String Types + + + The bit and bit varying (varbit) + types share a layout: a four-byte integer giving the length of the + value in bits, followed by + ceil(length/8) bytes + holding the bits. The bits are packed most significant bit first; + any unused low-order bits in the final byte are zero. + + + + + Text Search Types + + + + tsvector + + + A four-byte integer giving the number of lexemes, followed by that + many lexeme entries. Each entry consists of the lexeme string in + the client encoding terminated by a single zero byte, then a + two-byte integer giving the number of positions, then that many + two-byte position values. Each position value packs the position + number in its low-order bits and the weight in its two high-order + bits. + + + + + + tsquery + + + A four-byte integer giving the number of nodes, followed by that + many nodes in prefix (Polish) order. Each node begins with a + one-byte type code: 1 for an operand or + 2 for an operator. + + + + + An operand node continues with a one-byte weight bitmask, a + one-byte prefix-match flag, and the operand string in the client + encoding terminated by a single zero byte. + + + + + An operator node continues with a one-byte operator code + (1 for ! (NOT), + 2 for & (AND), + 3 for | (OR), and + 4 for the phrase operator + <->). For the phrase operator a + two-byte integer giving the distance follows. + + + + + + + + + + <type>uuid</type> Type + + + A uuid value is transmitted as exactly sixteen bytes, in + the order in which they appear in the textual representation (that is, + the most significant byte of the UUID first), matching the layout + defined by RFC 9562. + No byte swapping or field reordering is applied; the sixteen bytes + are transmitted in their textual order. + + + + + <type>xml</type> Type + + + An xml value is transmitted as the raw bytes of the + document in the client encoding, with no length word and no + terminator, just like a text value. As with the text + output of xml, an encoding declaration in the document + reflects the client encoding in use. The content itself is an + XML 1.0 document or + content fragment; see . + + + + + JSON Types + + + + json + + + A json value is transmitted as the raw bytes of the + JSON text in the client encoding, with no length word and no + terminator, just like a text value. The content is + JSON as specified in RFC + 7159; see . + + + + + + jsonb + + + A jsonb value is transmitted as a one-byte version + number followed by the JSON text (as specified in RFC + 7159) in the client encoding. The version number is + currently always 1. Note that this leading + version byte is what distinguishes the jsonb binary + format from the json binary format; a client must emit + it when sending and skip it when receiving. + + + + + + jsonpath + + + A jsonpath value is transmitted as a one-byte version + number followed by the textual jsonpath expression in + the client encoding. The expression follows the SQL/JSON path + language of the SQL:2016 standard; see . The version number is currently + always 1. + + + + + + + + Arrays + + + An array value begins with a header and is followed by its elements: + + + + + a four-byte integer giving the number of dimensions (zero for an + empty array); + + + + + a four-byte flags word, of which currently only the least + significant bit is defined: it is 1 if the array + contains any NULL elements and + 0 otherwise; + + + + + a four-byte unsigned integer, the object identifier + (OID) of the element type; a client can look + this value up in the pg_type + system catalog to determine the type; + + + + + for each dimension, a four-byte integer giving the dimension's + length and a four-byte integer giving its lower bound; + + + + + the elements themselves, in row-major order. Each element is a + four-byte length followed by that many bytes of the element's own + binary representation, or a length of -1 to + denote a NULL element with no following bytes. + + + + + + The oidvector and int2vector types used in + the system catalogs are transmitted in this same array format, with + element type oid and smallint respectively. + + + + + Composite Types + + + A composite (row or record) value begins with a four-byte integer + giving the number of columns, not counting any dropped columns. Each + column then follows as: + + + + + a four-byte unsigned integer, the object identifier + (OID) of the column's data type, looked up in + pg_type + as for array elements above; + + + + + a four-byte length followed by that many bytes of the column + value's own binary representation, or a length of + -1 for a NULL column with no + following bytes. + + + + + + + Range and Multirange Types + + + + Range types + + + A range value begins with a one-byte flags field, whose bits have + the following meanings: + + + + + 0x01 — the range is empty; + + + + + 0x02 — the lower bound is inclusive; + + + + + 0x04 — the upper bound is inclusive; + + + + + 0x08 — the lower bound is unbounded + (-infinity); + + + + + 0x10 — the upper bound is unbounded + (+infinity). + + + + + If the range is non-empty and has a finite lower bound, the flags + are followed by a four-byte length and that many bytes of the + lower bound value in the subtype's binary representation. If the + range has a finite upper bound, the upper bound follows in the same + way. An empty range consists of the flags byte alone. + + + + + + Multirange types + + + A multirange value begins with a four-byte integer giving the + number of ranges it contains. Each range then follows as a + four-byte length and that many bytes of a range value in the + binary format just described. + + + + + + + + Domain Types + + + A domain (see ) does not have a binary + format of its own. A domain value is transmitted using the binary + format of its underlying base type, since the domain adds only + constraints, not a distinct representation. + + + + + Object Identifier Types + + + An oid value is transmitted as a four-byte + unsigned integer in network byte order. The + OID alias types (see ) use the same + representation. Note that, unlike the text format, the binary format + carries the numeric OID rather than the resolved name. + + + + + Transaction and System Types + + + + xid and cid + + + Each is transmitted as a four-byte unsigned integer in network + byte order. + + + + + + xid8 + + + An eight-byte unsigned integer in network byte order. + + + + + + tid + + + A four-byte unsigned integer giving the block number, followed by + a two-byte unsigned integer giving the offset number within the + block. + + + + + + pg_lsn + + + An eight-byte unsigned integer in network byte order, the log + sequence number. + + + + + + pg_snapshot + + + A four-byte unsigned integer giving the number of in-progress + transaction IDs, followed by two eight-byte unsigned integers + giving xmin and + xmax, followed by that many eight-byte + unsigned integers giving the in-progress transaction IDs, all in + network byte order. + + + + + + txid_snapshot + + + The deprecated predecessor of pg_snapshot, + transmitted in the same format. + + + + + + + + Internal and Pseudo-Types + + + A number of types exist only to support internal operations of the + server and are not intended to be consumed by client applications. + These include the pseudo-types (such as cstring, + void, unknown, and the polymorphic + anyarray) and the types used to store optimizer and + extended-statistics data (pg_node_tree, + pg_ndistinct, and pg_dependencies). Where + these types have binary send and receive functions at all, the format + is an implementation detail that is subject to change between major + releases, so it is deliberately not documented here. + + + + diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 89985ab7b16..586bc0c3a62 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -28,6 +28,12 @@ but are not listed here. + + For the binary (as opposed to textual) on-the-wire representation of + these types, used when transmitting values in binary format, see + . + + Data Types diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml index 66ea8b988a1..93515c21985 100644 --- a/doc/src/sgml/filelist.sgml +++ b/doc/src/sgml/filelist.sgml @@ -59,6 +59,7 @@ + diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 7d3c3bb66d8..42c10925510 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -11290,245 +11290,6 @@ main(int argc, char **argv) return 0; } ]]> - - - - - <application>libpq</application> Example Program 3 - - - -#endif - -#include -#include -#include -#include -#include -#include "libpq-fe.h" - -/* for ntohl/htonl */ -#include -#include - - -static void -exit_nicely(PGconn *conn) -{ - PQfinish(conn); - exit(1); -} - -/* - * This function prints a query result that is a binary-format fetch from - * a table defined as in the comment above. We split it out because the - * main() function uses it twice. - */ -static void -show_binary_results(PGresult *res) -{ - int i, - j; - int i_fnum, - t_fnum, - b_fnum; - - /* Use PQfnumber to avoid assumptions about field order in result */ - i_fnum = PQfnumber(res, "i"); - t_fnum = PQfnumber(res, "t"); - b_fnum = PQfnumber(res, "b"); - - for (i = 0; i < PQntuples(res); i++) - { - char *iptr; - char *tptr; - char *bptr; - int blen; - int ival; - - /* Get the field values (we ignore possibility they are null!) */ - iptr = PQgetvalue(res, i, i_fnum); - tptr = PQgetvalue(res, i, t_fnum); - bptr = PQgetvalue(res, i, b_fnum); - - /* - * The binary representation of INT4 is in network byte order, which - * we'd better coerce to the local byte order. - */ - ival = ntohl(*((uint32_t *) iptr)); - - /* - * The binary representation of TEXT is, well, text, and since libpq - * was nice enough to append a zero byte to it, it'll work just fine - * as a C string. - * - * The binary representation of BYTEA is a bunch of bytes, which could - * include embedded nulls so we have to pay attention to field length. - */ - blen = PQgetlength(res, i, b_fnum); - - printf("tuple %d: got\n", i); - printf(" i = (%d bytes) %d\n", - PQgetlength(res, i, i_fnum), ival); - printf(" t = (%d bytes) '%s'\n", - PQgetlength(res, i, t_fnum), tptr); - printf(" b = (%d bytes) ", blen); - for (j = 0; j < blen; j++) - printf("\\%03o", bptr[j]); - printf("\n\n"); - } -} - -int -main(int argc, char **argv) -{ - const char *conninfo; - PGconn *conn; - PGresult *res; - const char *paramValues[1]; - int paramLengths[1]; - int paramFormats[1]; - uint32_t binaryIntVal; - - /* - * If the user supplies a parameter on the command line, use it as the - * conninfo string; otherwise default to setting dbname=postgres and using - * environment variables or defaults for all other connection parameters. - */ - if (argc > 1) - conninfo = argv[1]; - else - conninfo = "dbname = postgres"; - - /* Make a connection to the database */ - conn = PQconnectdb(conninfo); - - /* Check to see that the backend connection was successfully made */ - if (PQstatus(conn) != CONNECTION_OK) - { - fprintf(stderr, "%s", PQerrorMessage(conn)); - exit_nicely(conn); - } - - /* Set always-secure search path, so malicious users can't take control. */ - res = PQexec(conn, "SET search_path = testlibpq3"); - if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - fprintf(stderr, "SET failed: %s", PQerrorMessage(conn)); - PQclear(res); - exit_nicely(conn); - } - PQclear(res); - - /* - * The point of this program is to illustrate use of PQexecParams() with - * out-of-line parameters, as well as binary transmission of data. - * - * This first example transmits the parameters as text, but receives the - * results in binary format. By using out-of-line parameters we can avoid - * a lot of tedious mucking about with quoting and escaping, even though - * the data is text. Notice how we don't have to do anything special with - * the quote mark in the parameter value. - */ - - /* Here is our out-of-line parameter value */ - paramValues[0] = "joe's place"; - - res = PQexecParams(conn, - "SELECT * FROM test1 WHERE t = $1", - 1, /* one param */ - NULL, /* let the backend deduce param type */ - paramValues, - NULL, /* don't need param lengths since text */ - NULL, /* default to all text params */ - 1); /* ask for binary results */ - - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn)); - PQclear(res); - exit_nicely(conn); - } - - show_binary_results(res); - - PQclear(res); - - /* - * In this second example we transmit an integer parameter in binary form, - * and again retrieve the results in binary form. - * - * Although we tell PQexecParams we are letting the backend deduce - * parameter type, we really force the decision by casting the parameter - * symbol in the query text. This is a good safety measure when sending - * binary parameters. - */ - - /* Convert integer value "2" to network byte order */ - binaryIntVal = htonl((uint32_t) 2); - - /* Set up parameter arrays for PQexecParams */ - paramValues[0] = (char *) &binaryIntVal; - paramLengths[0] = sizeof(binaryIntVal); - paramFormats[0] = 1; /* binary */ - - res = PQexecParams(conn, - "SELECT * FROM test1 WHERE i = $1::int4", - 1, /* one param */ - NULL, /* let the backend deduce param type */ - paramValues, - paramLengths, - paramFormats, - 1); /* ask for binary results */ - - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn)); - PQclear(res); - exit_nicely(conn); - } - - show_binary_results(res); - - PQclear(res); - - /* close the connection to the database and cleanup */ - PQfinish(conn); - - return 0; -} -]]> diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml index 2101442c90f..38d98d6ce7f 100644 --- a/doc/src/sgml/postgres.sgml +++ b/doc/src/sgml/postgres.sgml @@ -191,6 +191,7 @@ break is not needed in a wider output rendering. &lobj; &ecpg; &infoschema; + &binaryformat; diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 49f81676712..e999b65bd23 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -181,8 +181,9 @@ Binary representations for integers use network byte order (most - significant byte first). For other data types consult the documentation - or source code to learn about the binary representation. Keep in mind + significant byte first). The binary representation of each built-in + data type is documented in ; for other + types, consult the type's documentation or source code. Keep in mind that binary representations for complex data types might change across server versions; the text format is usually the more portable choice. diff --git a/src/test/examples/.gitignore b/src/test/examples/.gitignore index 1957ec198f8..a39983ce296 100644 --- a/src/test/examples/.gitignore +++ b/src/test/examples/.gitignore @@ -1,6 +1,5 @@ /testlibpq /testlibpq2 -/testlibpq3 /testlibpq4 /testlo /testlo64 diff --git a/src/test/examples/Makefile b/src/test/examples/Makefile index 3a4e36465ba..5d7e1c9ac7c 100644 --- a/src/test/examples/Makefile +++ b/src/test/examples/Makefile @@ -17,7 +17,6 @@ LDFLAGS_INTERNAL += $(libpq_pgport) PROGS = \ testlibpq \ testlibpq2 \ - testlibpq3 \ testlibpq4 \ testlo \ testlo64 diff --git a/src/test/examples/testlibpq3.c b/src/test/examples/testlibpq3.c deleted file mode 100644 index cf74865ccb9..00000000000 --- a/src/test/examples/testlibpq3.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * src/test/examples/testlibpq3.c - * - * - * testlibpq3.c - * Test out-of-line parameters and binary I/O. - * - * Before running this, populate a database with the following commands - * (provided in src/test/examples/testlibpq3.sql): - * - * CREATE SCHEMA testlibpq3; - * SET search_path = testlibpq3; - * CREATE TABLE test1 (i int4, t text, b bytea); - * INSERT INTO test1 values (1, 'joe''s place', '\000\001\002\003\004'); - * INSERT INTO test1 values (2, 'ho there', '\004\003\002\001\000'); - * - * The expected output is: - * - * tuple 0: got - * i = (4 bytes) 1 - * t = (11 bytes) 'joe's place' - * b = (5 bytes) \000\001\002\003\004 - * - * tuple 0: got - * i = (4 bytes) 2 - * t = (8 bytes) 'ho there' - * b = (5 bytes) \004\003\002\001\000 - */ - -#ifdef WIN32 -#include -#endif - -#include -#include -#include -#include -#include -#include "libpq-fe.h" - -/* for ntohl/htonl */ -#include -#include - - -static void -exit_nicely(PGconn *conn) -{ - PQfinish(conn); - exit(1); -} - -/* - * This function prints a query result that is a binary-format fetch from - * a table defined as in the comment above. We split it out because the - * main() function uses it twice. - */ -static void -show_binary_results(PGresult *res) -{ - int i, - j; - int i_fnum, - t_fnum, - b_fnum; - - /* Use PQfnumber to avoid assumptions about field order in result */ - i_fnum = PQfnumber(res, "i"); - t_fnum = PQfnumber(res, "t"); - b_fnum = PQfnumber(res, "b"); - - for (i = 0; i < PQntuples(res); i++) - { - char *iptr; - char *tptr; - char *bptr; - int blen; - int ival; - - /* Get the field values (we ignore possibility they are null!) */ - iptr = PQgetvalue(res, i, i_fnum); - tptr = PQgetvalue(res, i, t_fnum); - bptr = PQgetvalue(res, i, b_fnum); - - /* - * The binary representation of INT4 is in network byte order, which - * we'd better coerce to the local byte order. - */ - ival = ntohl(*((uint32_t *) iptr)); - - /* - * The binary representation of TEXT is, well, text, and since libpq - * was nice enough to append a zero byte to it, it'll work just fine - * as a C string. - * - * The binary representation of BYTEA is a bunch of bytes, which could - * include embedded nulls so we have to pay attention to field length. - */ - blen = PQgetlength(res, i, b_fnum); - - printf("tuple %d: got\n", i); - printf(" i = (%d bytes) %d\n", - PQgetlength(res, i, i_fnum), ival); - printf(" t = (%d bytes) '%s'\n", - PQgetlength(res, i, t_fnum), tptr); - printf(" b = (%d bytes) ", blen); - for (j = 0; j < blen; j++) - printf("\\%03o", bptr[j]); - printf("\n\n"); - } -} - -int -main(int argc, char **argv) -{ - const char *conninfo; - PGconn *conn; - PGresult *res; - const char *paramValues[1]; - int paramLengths[1]; - int paramFormats[1]; - uint32_t binaryIntVal; - - /* - * If the user supplies a parameter on the command line, use it as the - * conninfo string; otherwise default to setting dbname=postgres and using - * environment variables or defaults for all other connection parameters. - */ - if (argc > 1) - conninfo = argv[1]; - else - conninfo = "dbname = postgres"; - - /* Make a connection to the database */ - conn = PQconnectdb(conninfo); - - /* Check to see that the backend connection was successfully made */ - if (PQstatus(conn) != CONNECTION_OK) - { - fprintf(stderr, "%s", PQerrorMessage(conn)); - exit_nicely(conn); - } - - /* Set always-secure search path, so malicious users can't take control. */ - res = PQexec(conn, "SET search_path = testlibpq3"); - if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - fprintf(stderr, "SET failed: %s", PQerrorMessage(conn)); - PQclear(res); - exit_nicely(conn); - } - PQclear(res); - - /* - * The point of this program is to illustrate use of PQexecParams() with - * out-of-line parameters, as well as binary transmission of data. - * - * This first example transmits the parameters as text, but receives the - * results in binary format. By using out-of-line parameters we can avoid - * a lot of tedious mucking about with quoting and escaping, even though - * the data is text. Notice how we don't have to do anything special with - * the quote mark in the parameter value. - */ - - /* Here is our out-of-line parameter value */ - paramValues[0] = "joe's place"; - - res = PQexecParams(conn, - "SELECT * FROM test1 WHERE t = $1", - 1, /* one param */ - NULL, /* let the backend deduce param type */ - paramValues, - NULL, /* don't need param lengths since text */ - NULL, /* default to all text params */ - 1); /* ask for binary results */ - - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn)); - PQclear(res); - exit_nicely(conn); - } - - show_binary_results(res); - - PQclear(res); - - /* - * In this second example we transmit an integer parameter in binary form, - * and again retrieve the results in binary form. - * - * Although we tell PQexecParams we are letting the backend deduce - * parameter type, we really force the decision by casting the parameter - * symbol in the query text. This is a good safety measure when sending - * binary parameters. - */ - - /* Convert integer value "2" to network byte order */ - binaryIntVal = htonl((uint32_t) 2); - - /* Set up parameter arrays for PQexecParams */ - paramValues[0] = (char *) &binaryIntVal; - paramLengths[0] = sizeof(binaryIntVal); - paramFormats[0] = 1; /* binary */ - - res = PQexecParams(conn, - "SELECT * FROM test1 WHERE i = $1::int4", - 1, /* one param */ - NULL, /* let the backend deduce param type */ - paramValues, - paramLengths, - paramFormats, - 1); /* ask for binary results */ - - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn)); - PQclear(res); - exit_nicely(conn); - } - - show_binary_results(res); - - PQclear(res); - - /* close the connection to the database and cleanup */ - PQfinish(conn); - - return 0; -} diff --git a/src/test/examples/testlibpq3.sql b/src/test/examples/testlibpq3.sql deleted file mode 100644 index a113849b14b..00000000000 --- a/src/test/examples/testlibpq3.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE SCHEMA testlibpq3; -SET search_path = testlibpq3; -CREATE TABLE test1 (i int4, t text, b bytea); -INSERT INTO test1 values (1, 'joe''s place', '\000\001\002\003\004'); -INSERT INTO test1 values (2, 'ho there', '\004\003\002\001\000'); -- 2.54.0