testlibpq3-v2.diff

text/plain

Filename: testlibpq3-v2.diff
Type: text/plain
Part: 0
Message: Re: real/float example for testlibpq3

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v2
File+
src/test/examples/testlibpq3.c 189 47
src/test/examples/testlibpq3.sql 26 3
diff --git a/src/test/examples/testlibpq3.c b/src/test/examples/testlibpq3.c
index 4f7b791388..68972f17f3 100644
--- a/src/test/examples/testlibpq3.c
+++ b/src/test/examples/testlibpq3.c
@@ -11,21 +11,56 @@
  * CREATE SCHEMA testlibpq3;
  * SET search_path = testlibpq3;
  * SET standard_conforming_strings = ON;
- * 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');
+ * CREATE SCHEMA testlibpq3;
+ * SET search_path = testlibpq3;
+ * SET standard_conforming_strings = ON;
+ * CREATE TABLE test1 (
+ *     i int4
+ *   , r real
+ *   , bo boolean
+ *   , ts timestamp
+ *   , t text
+ *   , b bytea
+ * );
+ * INSERT INTO test1
+ * VALUES (
+ *     1
+ *   , 3.141593
+ *   , true
+ *   , '2000-01-01 00:00:02.414213'
+ *   , 'joe''s place'
+ *   , '\000\001\002\003\004'
+ * );
+ * INSERT INTO test1
+ * VALUES (
+ *     2
+ *   , 1.618033
+ *   , false
+ *   , '2000-01-01 00:00:01.465571'
+ *   , 'ho there'
+ *   , '\004\003\002\001\000'
+ * );
  *
  * The expected output is:
  *
  * tuple 0: got
  *	i = (4 bytes) 1
+ *	r = (4 bytes) 3.141593
+ *	bo = (1 bytes) 1
  *	t = (11 bytes) 'joe's place'
  *	b = (5 bytes) \000\001\002\003\004
  *
  * tuple 0: got
  *	i = (4 bytes) 2
+ *	r = (4 bytes) 1.618033
+ *	bo = (1 bytes) 0
  *	t = (8 bytes) 'ho there'
  *	b = (5 bytes) \004\003\002\001\000
+ *
+ * General notes about this example:
+ *
+ * Use PQfnumber to avoid assumptions about field order in result but when
+ * getting the field values we ignore possibility they are null!
  */
 
 #ifdef WIN32
@@ -36,6 +71,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <time.h>
 #include <sys/types.h>
 #include "libpq-fe.h"
 
@@ -44,6 +80,13 @@
 #include <arpa/inet.h>
 
 
+/* These macros hopefully make reading calculations for timestamps easier. */
+#define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
+#define UNIX_EPOCH_JDATE 2440588 /* == date2j(1970, 1, 1) */
+#define SECS_PER_DAY 86400
+
+uint64_t ntohll(uint64_t);
+
 static void
 exit_nicely(PGconn *conn)
 {
@@ -51,6 +94,142 @@ exit_nicely(PGconn *conn)
 	exit(1);
 }
 
+static void
+handle_boolean(PGresult *res, int i)
+{
+	int			fnum;
+	char	   *ptr;
+	int			val;
+
+	fnum = PQfnumber(res, "bo");
+	ptr = PQgetvalue(res, i, fnum);
+	val = (int) *ptr;
+	printf(" bo = (%d bytes) %d\n", PQgetlength(res, i, fnum), val);
+}
+
+static void
+handle_bytea(PGresult *res, int i)
+{
+	int			j;
+	int			fnum;
+	char	   *ptr;
+	int			len;
+
+	fnum = PQfnumber(res, "b");
+	ptr = PQgetvalue(res, i, fnum);
+
+	/*
+	 * The binary representation of BYTEA is a bunch of bytes, which could
+	 * include embedded nulls so we have to pay attention to field length.
+	 */
+	len = PQgetlength(res, i, fnum);
+	printf(" b = (%d bytes) ", len);
+	for (j = 0; j < len; j++) printf("\\%03o", ptr[j]);
+}
+
+static void
+handle_integer(PGresult *res, int i)
+{
+	int			fnum;
+	char	   *ptr;
+	int			val;
+
+	fnum = PQfnumber(res, "i");
+	ptr = PQgetvalue(res, i, fnum);
+
+	/*
+	 * The binary representation of INT4 is in network byte order, which
+	 * we'd better coerce to the local byte order.
+	 */
+	val = ntohl(*((uint32_t *) ptr));
+
+	printf(" i = (%d bytes) %d\n", PQgetlength(res, i, fnum), val);
+}
+
+static void
+handle_real(PGresult *res, int i)
+{
+	int			fnum;
+	char	   *ptr;
+	union {
+		int		i;
+		float	f;
+	}			val;
+
+	fnum = PQfnumber(res, "r");
+	ptr = PQgetvalue(res, i, fnum);
+
+	/*
+	 * The binary representation of INT4 is in network byte order, which
+	 * we'd better coerce to the local byte order.
+	 */
+	val.i = ntohl(*((uint32_t *) ptr));
+
+	printf(" r = (%d bytes) %f\n", PQgetlength(res, i, fnum), val.f);
+}
+
+static void
+handle_text(PGresult *res, int i)
+{
+	int			fnum;
+	char	   *ptr;
+
+	fnum = PQfnumber(res, "t");
+	ptr = PQgetvalue(res, i, fnum);
+
+	/*
+	 * 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.
+	 */
+	printf(" t = (%d bytes) '%s'\n", PQgetlength(res, i, fnum), ptr);
+}
+
+static void
+handle_timestamp(PGresult *res, int i)
+{
+	int			fnum;
+	char	   *ptr;
+	uint64_t	val;
+
+	struct tm  *tm;
+	time_t		timep;
+	uint32_t	mantissa;
+
+	fnum = PQfnumber(res, "ts");
+	ptr = PQgetvalue(res, i, fnum);
+	val = ntohll(*((uint64_t *) ptr));
+
+	/*
+	 * The binary representation of a timestamp is in microseconds
+	 * from 2000-01-01.
+	 */
+	timep = val / (uint64_t) 1000000 +
+			(uint64_t) (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) *
+			(uint64_t) SECS_PER_DAY;
+	mantissa = val - (uint64_t) (timep -
+			(POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY) *
+			(uint64_t) 1000000;
+
+	/* For ease of testing, assume and print timestamps in GMT. */
+	tm = gmtime(&timep);
+
+	printf(" ts = (%d bytes) %04d-%02d-%02d %02d:%02d:%02d.%06d\n",
+			PQgetlength(res, i, fnum), tm->tm_year + 1900, tm->tm_mon + 1,
+			tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, mantissa);
+}
+
+/* This is a uint64_t version of ntohl from arpa/inet.h. */
+uint64_t
+ntohll(uint64_t netlonglong)
+{
+	if (ntohl(1) == 1)
+		return netlonglong;
+	else
+		return (uint64_t) (ntohl((int) ((netlonglong << 32) >> 32))) << 32 |
+				(uint64_t) ntohl(((int) (netlonglong >> 32)));
+}
+
 /*
  * 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
@@ -59,54 +238,17 @@ exit_nicely(PGconn *conn)
 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");
+	int			i;
 
 	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]);
+		handle_integer(res, i);
+		handle_real(res, i);
+		handle_boolean(res, i);
+		handle_timestamp(res, i);
+		handle_text(res, i);
+		handle_bytea(res, i);
 		printf("\n\n");
 	}
 }
diff --git a/src/test/examples/testlibpq3.sql b/src/test/examples/testlibpq3.sql
index 35a95ca347..94cb2b97b0 100644
--- a/src/test/examples/testlibpq3.sql
+++ b/src/test/examples/testlibpq3.sql
@@ -1,6 +1,29 @@
 CREATE SCHEMA testlibpq3;
 SET search_path = testlibpq3;
 SET standard_conforming_strings = ON;
-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');
+CREATE TABLE test1 (
+    i int4
+  , r real
+  , bo boolean
+  , ts timestamp
+  , t text
+  , b bytea
+);
+INSERT INTO test1
+VALUES (
+    1
+  , 3.141593
+  , true
+  , '2000-01-01 00:00:02.414213'
+  , 'joe''s place'
+  , '\000\001\002\003\004'
+);
+INSERT INTO test1
+VALUES (
+    2
+  , 1.618033
+  , false
+  , '2000-01-01 00:00:01.465571'
+  , 'ho there'
+  , '\004\003\002\001\000'
+);