Skip to content

Commit e92dc1e

Browse files
committed
Bring the libpq example programs into the 21st century.
1 parent 21e0b7b commit e92dc1e

File tree

8 files changed

+574
-602
lines changed

8 files changed

+574
-602
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 356 additions & 358 deletions
Large diffs are not rendered by default.

src/test/examples/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ top_builddir = ../../..
77
include $(top_builddir)/src/Makefile.global
88

99
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
10-
LIBS += $(libpq)
10+
LDFLAGS += $(libpq)
1111

1212

13-
# PROGS= testlibpq0 testlibpq1 testlibpq2 testlibpq3 testlibpq4 testlo
1413
PROGS = testlibpq testlibpq2 testlibpq3 testlibpq4 testlo
1514

1615
all: $(PROGS)

src/test/examples/testlibpq.c

Lines changed: 35 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/*
22
* testlibpq.c
3-
* Test the C version of LIBPQ, the POSTGRES frontend library.
4-
*
53
*
4+
* Test the C version of LIBPQ, the POSTGRES frontend library.
65
*/
76
#include <stdio.h>
7+
#include <stdlib.h>
88
#include "libpq-fe.h"
99

1010
static void
@@ -15,76 +15,66 @@ exit_nicely(PGconn *conn)
1515
}
1616

1717
int
18-
main()
18+
main(int argc, char **argv)
1919
{
20-
char *pghost,
21-
*pgport,
22-
*pgoptions,
23-
*pgtty;
24-
char *dbName;
20+
const char *conninfo;
21+
PGconn *conn;
22+
PGresult *res;
2523
int nFields;
2624
int i,
2725
j;
2826

29-
#ifdef DEBUG
30-
FILE *debug;
31-
#endif /* DEBUG */
32-
33-
PGconn *conn;
34-
PGresult *res;
35-
3627
/*
37-
* begin, by setting the parameters for a backend connection if the
38-
* parameters are null, then the system will try to use reasonable
39-
* defaults by looking up environment variables or, failing that,
40-
* using hardwired constants
28+
* If the user supplies a parameter on the command line, use it as
29+
* the conninfo string; otherwise default to setting dbname=template1
30+
* and using environment variables or defaults for all other connection
31+
* parameters.
4132
*/
42-
pghost = NULL; /* host name of the backend server */
43-
pgport = NULL; /* port of the backend server */
44-
pgoptions = NULL; /* special options to start up the backend
45-
* server */
46-
pgtty = NULL; /* debugging tty for the backend server */
47-
dbName = "template1";
48-
49-
/* make a connection to the database */
50-
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
51-
52-
/* check to see that the backend connection was successfully made */
53-
if (PQstatus(conn) == CONNECTION_BAD)
33+
if (argc > 1)
34+
conninfo = argv[1];
35+
else
36+
conninfo = "dbname = template1";
37+
38+
/* Make a connection to the database */
39+
conn = PQconnectdb(conninfo);
40+
41+
/* Check to see that the backend connection was successfully made */
42+
if (PQstatus(conn) != CONNECTION_OK)
5443
{
55-
fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
44+
fprintf(stderr, "Connection to database '%s' failed.\n", PQdb(conn));
5645
fprintf(stderr, "%s", PQerrorMessage(conn));
5746
exit_nicely(conn);
5847
}
5948

60-
#ifdef DEBUG
61-
debug = fopen("/tmp/trace.out", "w");
62-
PQtrace(conn, debug);
63-
#endif /* DEBUG */
49+
/*
50+
* Our test case here involves using a cursor, for which we must be
51+
* inside a transaction block. We could do the whole thing with a
52+
* single PQexec() of "select * from pg_database", but that's too
53+
* trivial to make a good example.
54+
*/
6455

65-
/* start a transaction block */
56+
/* Start a transaction block */
6657
res = PQexec(conn, "BEGIN");
6758
if (PQresultStatus(res) != PGRES_COMMAND_OK)
6859
{
69-
fprintf(stderr, "BEGIN command failed\n");
60+
fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
7061
PQclear(res);
7162
exit_nicely(conn);
7263
}
7364

7465
/*
75-
* should PQclear PGresult whenever it is no longer needed to avoid
66+
* Should PQclear PGresult whenever it is no longer needed to avoid
7667
* memory leaks
7768
*/
7869
PQclear(res);
7970

8071
/*
81-
* fetch instances from the pg_database, the system catalog of
82-
* databases
72+
* Fetch rows from pg_database, the system catalog of databases
8373
*/
8474
res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_database");
8575
if (PQresultStatus(res) != PGRES_COMMAND_OK)
8676
{
87-
fprintf(stderr, "DECLARE CURSOR command failed\n");
77+
fprintf(stderr, "DECLARE CURSOR failed: %s", PQerrorMessage(conn));
8878
PQclear(res);
8979
exit_nicely(conn);
9080
}
@@ -93,7 +83,7 @@ main()
9383
res = PQexec(conn, "FETCH ALL in myportal");
9484
if (PQresultStatus(res) != PGRES_TUPLES_OK)
9585
{
96-
fprintf(stderr, "FETCH ALL command didn't return tuples properly\n");
86+
fprintf(stderr, "FETCH ALL failed: %s", PQerrorMessage(conn));
9787
PQclear(res);
9888
exit_nicely(conn);
9989
}
@@ -104,7 +94,7 @@ main()
10494
printf("%-15s", PQfname(res, i));
10595
printf("\n\n");
10696

107-
/* next, print out the instances */
97+
/* next, print out the rows */
10898
for (i = 0; i < PQntuples(res); i++)
10999
{
110100
for (j = 0; j < nFields; j++)
@@ -114,7 +104,7 @@ main()
114104

115105
PQclear(res);
116106

117-
/* close the portal */
107+
/* close the portal ... we don't bother to check for errors ... */
118108
res = PQexec(conn, "CLOSE myportal");
119109
PQclear(res);
120110

@@ -125,9 +115,5 @@ main()
125115
/* close the connection to the database and cleanup */
126116
PQfinish(conn);
127117

128-
#ifdef DEBUG
129-
fclose(debug);
130-
#endif /* DEBUG */
131-
132118
return 0;
133119
}

src/test/examples/testlibpq2.c

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,30 @@
22
* testlibpq2.c
33
* Test of the asynchronous notification interface
44
*
5-
populate a database with the following:
6-
7-
CREATE TABLE TBL1 (i int4);
8-
9-
CREATE TABLE TBL2 (i int4);
10-
11-
CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2];
12-
13-
* Then start up this program
14-
* After the program has begun, do
15-
16-
INSERT INTO TBL1 values (10);
17-
5+
* Start this program, then from psql in another window do
6+
* NOTIFY TBL2;
7+
* Repeat four times to get this program to exit.
8+
*
9+
* Or, if you want to get fancy, try this:
10+
* populate a database with the following commands
11+
* (provided in src/test/examples/testlibpq2.sql):
1812
*
13+
* CREATE TABLE TBL1 (i int4);
1914
*
15+
* CREATE TABLE TBL2 (i int4);
16+
*
17+
* CREATE RULE r1 AS ON INSERT TO TBL1 DO
18+
* (INSERT INTO TBL2 VALUES (new.i); NOTIFY TBL2);
19+
*
20+
* and do this four times:
21+
*
22+
* INSERT INTO TBL1 VALUES (10);
2023
*/
2124
#include <stdio.h>
2225
#include <stdlib.h>
26+
#include <string.h>
27+
#include <errno.h>
28+
#include <sys/time.h>
2329
#include "libpq-fe.h"
2430

2531
static void
@@ -30,51 +36,43 @@ exit_nicely(PGconn *conn)
3036
}
3137

3238
int
33-
main()
39+
main(int argc, char **argv)
3440
{
35-
char *pghost,
36-
*pgport,
37-
*pgoptions,
38-
*pgtty;
39-
char *dbName;
40-
41-
/*
42-
* int nFields; int i, j;
43-
*/
44-
41+
const char *conninfo;
4542
PGconn *conn;
4643
PGresult *res;
4744
PGnotify *notify;
45+
int nnotifies;
4846

4947
/*
50-
* begin, by setting the parameters for a backend connection if the
51-
* parameters are null, then the system will try to use reasonable
52-
* defaults by looking up environment variables or, failing that,
53-
* using hardwired constants
48+
* If the user supplies a parameter on the command line, use it as
49+
* the conninfo string; otherwise default to setting dbname=template1
50+
* and using environment variables or defaults for all other connection
51+
* parameters.
5452
*/
55-
pghost = NULL; /* host name of the backend server */
56-
pgport = NULL; /* port of the backend server */
57-
pgoptions = NULL; /* special options to start up the backend
58-
* server */
59-
pgtty = NULL; /* debugging tty for the backend server */
60-
dbName = getenv("USER"); /* change this to the name of your test
61-
* database */
62-
63-
/* make a connection to the database */
64-
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
65-
66-
/* check to see that the backend connection was successfully made */
67-
if (PQstatus(conn) == CONNECTION_BAD)
53+
if (argc > 1)
54+
conninfo = argv[1];
55+
else
56+
conninfo = "dbname = template1";
57+
58+
/* Make a connection to the database */
59+
conn = PQconnectdb(conninfo);
60+
61+
/* Check to see that the backend connection was successfully made */
62+
if (PQstatus(conn) != CONNECTION_OK)
6863
{
69-
fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
64+
fprintf(stderr, "Connection to database '%s' failed.\n", PQdb(conn));
7065
fprintf(stderr, "%s", PQerrorMessage(conn));
7166
exit_nicely(conn);
7267
}
7368

69+
/*
70+
* Issue LISTEN command to enable notifications from the rule's NOTIFY.
71+
*/
7472
res = PQexec(conn, "LISTEN TBL2");
7573
if (PQresultStatus(res) != PGRES_COMMAND_OK)
7674
{
77-
fprintf(stderr, "LISTEN command failed\n");
75+
fprintf(stderr, "LISTEN command failed: %s", PQerrorMessage(conn));
7876
PQclear(res);
7977
exit_nicely(conn);
8078
}
@@ -85,27 +83,48 @@ main()
8583
*/
8684
PQclear(res);
8785

88-
while (1)
86+
/* Quit after four notifies are received. */
87+
nnotifies = 0;
88+
while (nnotifies < 4)
8989
{
90-
/* async notification only come back as a result of a query */
91-
/* we can send empty queries */
92-
res = PQexec(conn, " ");
93-
/* printf("res->status = %s\n", PQresStatus(PQresultStatus(res))); */
94-
/* check for asynchronous returns */
95-
notify = PQnotifies(conn);
96-
if (notify)
90+
/*
91+
* Sleep until something happens on the connection. We use select(2)
92+
* to wait for input, but you could also use poll() or similar
93+
* facilities.
94+
*/
95+
int sock;
96+
fd_set input_mask;
97+
98+
sock = PQsocket(conn);
99+
100+
if (sock < 0)
101+
break; /* shouldn't happen */
102+
103+
FD_ZERO(&input_mask);
104+
FD_SET(sock, &input_mask);
105+
106+
if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0)
107+
{
108+
fprintf(stderr, "select() failed: %s\n", strerror(errno));
109+
exit_nicely(conn);
110+
}
111+
112+
/* Now check for input */
113+
PQconsumeInput(conn);
114+
while ((notify = PQnotifies(conn)) != NULL)
97115
{
98116
fprintf(stderr,
99-
"ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
117+
"ASYNC NOTIFY of '%s' received from backend pid %d\n",
100118
notify->relname, notify->be_pid);
101119
PQfreemem(notify);
102-
break;
120+
nnotifies++;
103121
}
104-
PQclear(res);
105122
}
106123

124+
fprintf(stderr, "Done.\n");
125+
107126
/* close the connection to the database and cleanup */
108127
PQfinish(conn);
109-
return 0; /* Though PQfinish(conn1) has called
110-
* exit(1) */
128+
129+
return 0;
111130
}

src/test/examples/testlibpq2.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ CREATE TABLE TBL1 (i int4);
22

33
CREATE TABLE TBL2 (i int4);
44

5-
CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2];
5+
CREATE RULE r1 AS ON INSERT TO TBL1 DO
6+
(INSERT INTO TBL2 VALUES (new.i); NOTIFY TBL2);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy