mirror of https://github.com/postgres/postgres
parent
27b12bfd54
commit
d3cf6f98c7
@ -1,42 +0,0 @@ |
||||
|
||||
|
||||
Pginterface 2.0 |
||||
|
||||
Attached is a copy of the Postgres support routines I wrote to allow me |
||||
to more cleanly interface to the libpg library, more like a 4gl SQL |
||||
interface. |
||||
|
||||
It has several features that may be useful for others: |
||||
|
||||
I have simplified the C code that calls libpq by wrapping all the |
||||
functionality of libpq in calls to connectdb(), doquery(), fetch(), |
||||
fetchwithnulls() and disconnectdb(). Each call returns a structure or |
||||
value, so if you need to do more work with the result, you can. Also, I |
||||
have a global variable that allows you to disable the error checking I |
||||
have added to the doquery() routine. |
||||
|
||||
I have added a function called fetch(), which allows you to pass |
||||
pointers as parameters, and on return the variables are filled with the |
||||
data from the binary cursor you opened. These binary cursors are not |
||||
useful if you are running the query engine on a system with a different |
||||
architecture than the database server. If you pass a NULL pointer, the |
||||
column is skipped, and you can use libpq to handle it as you wish. |
||||
|
||||
I have used sigprocmask() to block the reception of certain signals |
||||
while the program is executing SQL queries. This prevents a user |
||||
pressing Control-C from stopping all the back ends. It blocks SIGHUP, |
||||
SIGINT, and SIGTERM, but does not block SIGQUIT or obviously kill -9. |
||||
If your platform does not support sigprocmask(), you can remove those |
||||
function calls. ( Am I correct that abnormal termination can cause |
||||
shared memory resynchronization?) |
||||
|
||||
There is a demo program called pginsert that demonstrates how the |
||||
library can be used. |
||||
|
||||
You can create a library of pginterface.c and halt.c, and just include |
||||
pginterface.h in your source code. |
||||
|
||||
I am willing to maintain this if people find problems or want additional |
||||
functionality. |
||||
|
||||
Bruce Momjian (root@candle.pha.pa.us) |
@ -1,102 +0,0 @@ |
||||
/*
|
||||
* insert.c |
||||
* |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <signal.h> |
||||
#include <time.h> |
||||
#include <libpq-fe.h> |
||||
#include "halt.h" |
||||
#include "pginterface.h" |
||||
|
||||
int |
||||
main(int argc, char **argv) |
||||
{ |
||||
char query[4000]; |
||||
int row = 1; |
||||
int aint; |
||||
float afloat; |
||||
double adouble; |
||||
char achar[11], |
||||
achar16[17], |
||||
abpchar[11], |
||||
avarchar[51], |
||||
atext[51]; |
||||
time_t aabstime; |
||||
|
||||
if (argc != 2) |
||||
halt("Usage: %s database\n", argv[0]); |
||||
|
||||
connectdb(argv[1], NULL, NULL, NULL, NULL); |
||||
|
||||
on_error_continue(); |
||||
doquery("DROP TABLE testfetch"); |
||||
on_error_stop(); |
||||
|
||||
doquery("\
|
||||
CREATE TABLE testfetch( \
|
||||
aint int4, \
|
||||
afloat float4, \
|
||||
adouble float8, \
|
||||
achar char, \
|
||||
achar16 char16, \
|
||||
abpchar char(10), \
|
||||
avarchar varchar(50), \
|
||||
atext text, \
|
||||
aabstime abstime) \
|
||||
"); |
||||
|
||||
while (1) |
||||
{ |
||||
sprintf(query, "INSERT INTO testfetch VALUES ( \
|
||||
%d, \
|
||||
2322.12, \
|
||||
'923121.0323'::float8, \
|
||||
'A', \
|
||||
'Betty', \
|
||||
'Charley', \
|
||||
'Doug', \
|
||||
'Ernie', \
|
||||
'now' )", row); |
||||
doquery(query); |
||||
|
||||
doquery("BEGIN WORK"); |
||||
doquery("DECLARE c_testfetch BINARY CURSOR FOR \
|
||||
SELECT * FROM testfetch"); |
||||
|
||||
doquery("FETCH ALL IN c_testfetch"); |
||||
|
||||
while (fetch( |
||||
&aint, |
||||
&afloat, |
||||
&adouble, |
||||
achar, |
||||
achar16, |
||||
abpchar, |
||||
avarchar, |
||||
atext, |
||||
&aabstime) != END_OF_TUPLES) |
||||
printf("int %d\nfloat %f\ndouble %f\nchar %s\nchar16 %s\n\
|
||||
bpchar %s\nvarchar %s\ntext %s\nabstime %s", |
||||
aint, |
||||
afloat, |
||||
adouble, |
||||
achar, |
||||
achar16, |
||||
abpchar, |
||||
avarchar, |
||||
atext, |
||||
ctime(&aabstime)); |
||||
|
||||
|
||||
doquery("CLOSE c_testfetch"); |
||||
doquery("COMMIT WORK"); |
||||
printf("--- %-d rows inserted so far\n", row); |
||||
|
||||
row++; |
||||
} |
||||
|
||||
disconnectdb(); |
||||
return 0; |
||||
} |
@ -1,232 +0,0 @@ |
||||
/*
|
||||
* pginterface.c |
||||
* |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <signal.h> |
||||
#include <string.h> |
||||
#include <stdarg.h> |
||||
|
||||
#include <libpq-fe.h> |
||||
#include "halt.h" |
||||
#include "pginterface.h" |
||||
|
||||
static void sig_disconnect(); |
||||
static void set_signals(); |
||||
|
||||
#define NUL '\0' |
||||
|
||||
/* GLOBAL VARIABLES */ |
||||
static PGconn *conn; |
||||
static PGresult *res = NULL; |
||||
|
||||
#define ON_ERROR_STOP 0 |
||||
#define ON_ERROR_CONTINUE 1 |
||||
|
||||
static int on_error_state = ON_ERROR_STOP; |
||||
|
||||
/* LOCAL VARIABLES */ |
||||
static sigset_t block_sigs, |
||||
unblock_sigs; |
||||
static int tuple; |
||||
|
||||
/*
|
||||
** |
||||
** connectdb - returns PGconn structure |
||||
** |
||||
*/ |
||||
PGconn * |
||||
connectdb(char *dbName, |
||||
char *pghost, |
||||
char *pgport, |
||||
char *pgoptions, |
||||
char *pgtty) |
||||
{ |
||||
/* make a connection to the database */ |
||||
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); |
||||
if (PQstatus(conn) == CONNECTION_BAD) |
||||
halt("Connection to database '%s' failed.\n%s\n", dbName, |
||||
PQerrorMessage(conn)); |
||||
set_signals(); |
||||
return conn; |
||||
} |
||||
|
||||
/*
|
||||
** |
||||
** disconnectdb |
||||
** |
||||
*/ |
||||
void |
||||
disconnectdb() |
||||
{ |
||||
PQfinish(conn); |
||||
} |
||||
|
||||
/*
|
||||
** |
||||
** doquery - returns PGresult structure |
||||
** |
||||
*/ |
||||
PGresult * |
||||
doquery(char *query) |
||||
{ |
||||
if (res != NULL) |
||||
PQclear(res); |
||||
|
||||
sigprocmask(SIG_SETMASK, &block_sigs, NULL); |
||||
res = PQexec(conn, query); |
||||
sigprocmask(SIG_SETMASK, &unblock_sigs, NULL); |
||||
|
||||
if (on_error_state == ON_ERROR_STOP && |
||||
(res == NULL || |
||||
PQresultStatus(res) == PGRES_BAD_RESPONSE || |
||||
PQresultStatus(res) == PGRES_NONFATAL_ERROR || |
||||
PQresultStatus(res) == PGRES_FATAL_ERROR)) |
||||
{ |
||||
if (res != NULL) |
||||
fprintf(stderr, "query error: %s\n", PQcmdStatus(res)); |
||||
else |
||||
fprintf(stderr, "connection error: %s\n", PQerrorMessage(conn)); |
||||
PQfinish(conn); |
||||
halt("failed request: %s\n", query); |
||||
} |
||||
tuple = 0; |
||||
return res; |
||||
} |
||||
|
||||
/*
|
||||
** |
||||
** fetch - returns tuple number (starts at 0), or the value END_OF_TUPLES |
||||
** NULL pointers are skipped |
||||
** |
||||
*/ |
||||
int |
||||
fetch(void *param,...) |
||||
{ |
||||
va_list ap; |
||||
int arg, |
||||
num_fields; |
||||
|
||||
num_fields = PQnfields(res); |
||||
|
||||
if (tuple >= PQntuples(res)) |
||||
return END_OF_TUPLES; |
||||
|
||||
va_start(ap, param); |
||||
for (arg = 0; arg < num_fields; arg++) |
||||
{ |
||||
if (param != NULL) |
||||
{ |
||||
if (PQfsize(res, arg) == -1) |
||||
{ |
||||
memcpy(param, PQgetvalue(res, tuple, arg), PQgetlength(res, tuple, arg)); |
||||
((char *) param)[PQgetlength(res, tuple, arg)] = NUL; |
||||
} |
||||
else |
||||
memcpy(param, PQgetvalue(res, tuple, arg), PQfsize(res, arg)); |
||||
} |
||||
param = va_arg(ap, char *); |
||||
} |
||||
va_end(ap); |
||||
return tuple++; |
||||
} |
||||
|
||||
/*
|
||||
** |
||||
** fetchwithnulls - returns tuple number (starts at 0), |
||||
** or the value END_OF_TUPLES |
||||
** Returns true or false into null indicator variables |
||||
** NULL pointers are skipped |
||||
*/ |
||||
int |
||||
fetchwithnulls(void *param,...) |
||||
{ |
||||
va_list ap; |
||||
int arg, |
||||
num_fields; |
||||
|
||||
num_fields = PQnfields(res); |
||||
|
||||
if (tuple >= PQntuples(res)) |
||||
return END_OF_TUPLES; |
||||
|
||||
va_start(ap, param); |
||||
for (arg = 0; arg < num_fields; arg++) |
||||
{ |
||||
if (param != NULL) |
||||
{ |
||||
if (PQfsize(res, arg) == -1) |
||||
{ |
||||
memcpy(param, PQgetvalue(res, tuple, arg), PQgetlength(res, tuple, arg)); |
||||
((char *) param)[PQgetlength(res, tuple, arg)] = NUL; |
||||
} |
||||
else |
||||
memcpy(param, PQgetvalue(res, tuple, arg), PQfsize(res, arg)); |
||||
} |
||||
param = va_arg(ap, char *); |
||||
if (PQgetisnull(res, tuple, arg) != 0) |
||||
*(int *) param = 1; |
||||
else |
||||
*(int *) param = 0; |
||||
param = va_arg(ap, char *); |
||||
} |
||||
va_end(ap); |
||||
return tuple++; |
||||
} |
||||
|
||||
/*
|
||||
** |
||||
** on_error_stop |
||||
** |
||||
*/ |
||||
void |
||||
on_error_stop() |
||||
{ |
||||
on_error_state = ON_ERROR_STOP; |
||||
} |
||||
|
||||
/*
|
||||
** |
||||
** on_error_continue |
||||
** |
||||
*/ |
||||
void |
||||
on_error_continue() |
||||
{ |
||||
on_error_state = ON_ERROR_CONTINUE; |
||||
} |
||||
|
||||
/*
|
||||
** |
||||
** sig_disconnect |
||||
** |
||||
*/ |
||||
static void |
||||
sig_disconnect() |
||||
{ |
||||
fprintf(stderr, "exiting...\n"); |
||||
PQfinish(conn); |
||||
exit(1); |
||||
} |
||||
|
||||
/*
|
||||
** |
||||
** set_signals |
||||
** |
||||
*/ |
||||
static void |
||||
set_signals() |
||||
{ |
||||
sigemptyset(&block_sigs); |
||||
sigemptyset(&unblock_sigs); |
||||
sigaddset(&block_sigs, SIGTERM); |
||||
sigaddset(&block_sigs, SIGHUP); |
||||
sigaddset(&block_sigs, SIGINT); |
||||
/* sigaddset(&block_sigs,SIGQUIT); no block */ |
||||
sigprocmask(SIG_SETMASK, &unblock_sigs, NULL); |
||||
signal(SIGTERM, sig_disconnect); |
||||
signal(SIGHUP, sig_disconnect); |
||||
signal(SIGINT, sig_disconnect); |
||||
signal(SIGQUIT, sig_disconnect); |
||||
} |
@ -1,143 +0,0 @@ |
||||
/*
|
||||
* pgnulltest.c |
||||
* |
||||
*/ |
||||
|
||||
#define TEST_NON_NULLS |
||||
|
||||
#include <stdio.h> |
||||
#include <signal.h> |
||||
#include <time.h> |
||||
#include <halt.h> |
||||
#include <libpq-fe.h> |
||||
#include <pginterface.h> |
||||
|
||||
int |
||||
main(int argc, char **argv) |
||||
{ |
||||
char query[4000]; |
||||
int row = 1; |
||||
int aint; |
||||
float afloat; |
||||
double adouble; |
||||
char achar[11], |
||||
achar16[17], |
||||
abpchar[11], |
||||
avarchar[51], |
||||
atext[51]; |
||||
time_t aabstime; |
||||
int aint_null, |
||||
afloat_null, |
||||
adouble_null, |
||||
achar_null, |
||||
achar16_null, |
||||
abpchar_null, |
||||
avarchar_null, |
||||
atext_null, |
||||
aabstime_null; |
||||
|
||||
if (argc != 2) |
||||
halt("Usage: %s database\n", argv[0]); |
||||
|
||||
connectdb(argv[1], NULL, NULL, NULL, NULL); |
||||
|
||||
on_error_continue(); |
||||
doquery("DROP TABLE testfetch"); |
||||
on_error_stop(); |
||||
|
||||
doquery("\
|
||||
CREATE TABLE testfetch( \
|
||||
aint int4, \
|
||||
afloat float4, \
|
||||
adouble float8, \
|
||||
achar char, \
|
||||
achar16 char16, \
|
||||
abpchar char(10), \
|
||||
avarchar varchar(50), \
|
||||
atext text, \
|
||||
aabstime abstime) \
|
||||
"); |
||||
|
||||
#ifdef TEST_NON_NULLS |
||||
sprintf(query, "INSERT INTO testfetch VALUES ( \
|
||||
0, \
|
||||
0, \
|
||||
0, \
|
||||
'', \
|
||||
'', \
|
||||
'', \
|
||||
'', \
|
||||
'', \
|
||||
'');"); |
||||
#else |
||||
sprintf(query, "INSERT INTO testfetch VALUES ( \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
NULL);"); |
||||
#endif |
||||
doquery(query); |
||||
|
||||
doquery("BEGIN WORK"); |
||||
doquery("DECLARE c_testfetch BINARY CURSOR FOR \
|
||||
SELECT * FROM testfetch"); |
||||
|
||||
doquery("FETCH ALL IN c_testfetch"); |
||||
|
||||
if (fetchwithnulls( |
||||
&aint, |
||||
&aint_null, |
||||
&afloat, |
||||
&afloat_null, |
||||
&adouble, |
||||
&adouble_null, |
||||
achar, |
||||
&achar_null, |
||||
achar16, |
||||
&achar16_null, |
||||
abpchar, |
||||
&abpchar_null, |
||||
avarchar, |
||||
&avarchar_null, |
||||
atext, |
||||
&atext_null, |
||||
&aabstime, |
||||
&aabstime_null) != END_OF_TUPLES) |
||||
printf("int %d\nfloat %f\ndouble %f\nchar %s\nchar16 %s\n\
|
||||
bpchar %s\nvarchar %s\ntext %s\nabstime %s\n", |
||||
aint, |
||||
afloat, |
||||
adouble, |
||||
achar, |
||||
achar16, |
||||
abpchar, |
||||
avarchar, |
||||
atext, |
||||
ctime(&aabstime)); |
||||
printf("NULL:\nint %d\nfloat %d\ndouble %d\nchar %d\nchar16 %d\n\
|
||||
bpchar %d\nvarchar %d\ntext %d\nabstime %d\n", |
||||
aint_null, |
||||
afloat_null, |
||||
adouble_null, |
||||
achar_null, |
||||
achar16_null, |
||||
abpchar_null, |
||||
avarchar_null, |
||||
atext_null, |
||||
aabstime_null); |
||||
|
||||
|
||||
doquery("CLOSE c_testfetch"); |
||||
doquery("COMMIT WORK"); |
||||
printf("--- %-d rows inserted so far\n", row); |
||||
|
||||
row++; |
||||
|
||||
disconnectdb(); |
||||
return 0; |
||||
} |
@ -1,72 +0,0 @@ |
||||
/*
|
||||
* wordcount.c |
||||
* |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <signal.h> |
||||
#include <time.h> |
||||
#include "halt.h" |
||||
#include <libpq-fe.h> |
||||
#include "pginterface.h" |
||||
|
||||
int |
||||
main(int argc, char **argv) |
||||
{ |
||||
char query[4000]; |
||||
int row = 0; |
||||
int count; |
||||
char line[4000]; |
||||
|
||||
if (argc != 2) |
||||
halt("Usage: %s database\n", argv[0]); |
||||
|
||||
connectdb(argv[1], NULL, NULL, NULL, NULL); |
||||
on_error_continue(); |
||||
doquery("DROP TABLE words"); |
||||
on_error_stop(); |
||||
|
||||
doquery("\
|
||||
CREATE TABLE words( \
|
||||
matches int4, \
|
||||
word text ) \
|
||||
"); |
||||
doquery("\
|
||||
CREATE INDEX i_words_1 ON words USING btree ( \
|
||||
word text_ops )\
|
||||
"); |
||||
|
||||
while (1) |
||||
{ |
||||
if (scanf("%s", line) != 1) |
||||
break; |
||||
doquery("BEGIN WORK"); |
||||
sprintf(query, "\
|
||||
DECLARE c_words BINARY CURSOR FOR \
|
||||
SELECT count(*) \
|
||||
FROM words \
|
||||
WHERE word = '%s'", line); |
||||
doquery(query); |
||||
doquery("FETCH ALL IN c_words"); |
||||
|
||||
while (fetch(&count) == END_OF_TUPLES) |
||||
count = 0; |
||||
doquery("CLOSE c_words"); |
||||
doquery("COMMIT WORK"); |
||||
|
||||
if (count == 0) |
||||
sprintf(query, "\
|
||||
INSERT INTO words \
|
||||
VALUES (1, '%s')", line); |
||||
else |
||||
sprintf(query, "\
|
||||
UPDATE words \
|
||||
SET matches = matches + 1 \
|
||||
WHERE word = '%s'", line); |
||||
doquery(query); |
||||
row++; |
||||
} |
||||
|
||||
disconnectdb(); |
||||
return 0; |
||||
} |
Loading…
Reference in new issue