1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Postgres95 1.01 Distribution - Virgin Sources

This commit is contained in:
Marc G. Fournier
1996-07-09 06:22:35 +00:00
commit d31084e9d1
868 changed files with 242656 additions and 0 deletions

View File

@ -0,0 +1,38 @@
#-------------------------------------------------------------------------
#
# Makefile
# Makefile for libpgtcl library
#
# Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
#
#-------------------------------------------------------------------------
LIB= pgtcl
MKDIR= ../mk
include $(MKDIR)/postgres.mk
CFLAGS+= -I$(HEADERDIR) \
-I$(srcdir)/backend/include \
-I$(srcdir)/backend \
-I$(CURDIR) \
-I$(TCL_INCDIR)
ifdef KRBVERS
CFLAGS+= $(KRBFLAGS)
endif
LIBSRCS= pgtcl.c pgtclCmds.c pgtclId.c
install-headers:
$(INSTALL) $(INSTLOPTS) libpgtcl.h $(HEADERDIR)/libpgtcl.h
install:: install-headers
include $(MKDIR)/postgres.lib.mk

View File

@ -0,0 +1,7 @@
libpgtcl is a library that implements Tcl commands for front-end
clients to interact with the Postgres95 backend. See libpgtcl.doc for
details.
For an example of how to build a new tclsh to use libpgtcl, see the
directory ../bin/pgtclsh

View File

@ -0,0 +1,21 @@
/*-------------------------------------------------------------------------
*
* libpgtcl.h--
* libpgtcl is a tcl package for front-ends to interface with pglite
* It's the tcl equivalent of the old libpq C interface.
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: libpgtcl.h,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LIBPGTCL_H
#define LIBPGTCL_H
#include "tcl.h"
extern int Pg_Init (Tcl_Interp *interp);
#endif /* LIBPGTCL_H */

View File

@ -0,0 +1,105 @@
/*-------------------------------------------------------------------------
*
* pgtcl.c--
*
* libpgtcl is a tcl package for front-ends to interface with pglite
* It's the tcl equivalent of the old libpq C interface.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtcl.c,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "tcl.h"
#include "libpgtcl.h"
#include "pgtclCmds.h"
/*
* PG_Init
* initialization package for the PGLITE Tcl package
*
*/
int
Pg_Init (Tcl_Interp *interp)
{
/* register all pgtcl commands */
Tcl_CreateCommand(interp,
"pg_connect",
Pg_connect,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_disconnect",
Pg_disconnect,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_exec",
Pg_exec,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_result",
Pg_result,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_open",
Pg_lo_open,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_close",
Pg_lo_close,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_read",
Pg_lo_read,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_write",
Pg_lo_write,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_lseek",
Pg_lo_lseek,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_creat",
Pg_lo_creat,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_tell",
Pg_lo_tell,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_unlink",
Pg_lo_unlink,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_import",
Pg_lo_import,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
Tcl_CreateCommand(interp,
"pg_lo_export",
Pg_lo_export,
(ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
return TCL_OK;
}

View File

@ -0,0 +1,812 @@
/*-------------------------------------------------------------------------
*
* pgtclCmds.c--
* C functions which implement pg_* tcl commands
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <tcl.h>
#include <string.h>
#include "libpq/pqcomm.h"
#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
#include "pgtclCmds.h"
#include "pgtclId.h"
/**********************************
* pg_connect
make a connection to a backend.
syntax:
pg_connect dbName [-host hostName] [-port portNumber] [-tty pqtty]]
the return result is either an error message or a handle for a database
connection. Handles start with the prefix "pgp"
**********************************/
int
Pg_connect(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
char *pghost = NULL;
char *pgtty = NULL;
char *pgport = NULL;
char *pgoptions = NULL;
char *dbName;
int i;
PGconn *conn;
if (argc == 1) {
Tcl_AppendResult(interp, "pg_connect: database name missing\n", 0);
Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]", 0);
return TCL_ERROR;
}
if (argc > 2) {
/* parse for pg environment settings */
i = 2;
while (i+1 < argc) {
if (strcmp(argv[i], "-host") == 0) {
pghost = argv[i+1];
i += 2;
}
else
if (strcmp(argv[i], "-port") == 0) {
pgport = argv[i+1];
i += 2;
}
else
if (strcmp(argv[i], "-tty") == 0) {
pgtty = argv[i+1];
i += 2;
}
else if (strcmp(argv[i], "-options") == 0) {
pgoptions = argv[i+1];
i += 2;
}
else {
Tcl_AppendResult(interp, "Bad option to pg_connect : \n",
argv[i], 0);
Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]",0);
return TCL_ERROR;
}
} /* while */
if ((i % 2 != 0) || i != argc) {
Tcl_AppendResult(interp, "wrong # of arguments to pg_connect\n", argv[i],0);
Tcl_AppendResult(interp, "pg_connect databaseName [-host hostName] [-port portNumber] [-tty pgtty]]",0);
return TCL_ERROR;
}
}
dbName = argv[1];
conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName);
if (conn->status == CONNECTION_OK) {
PgSetId(interp->result, (void*)conn);
return TCL_OK;
}
else {
Tcl_AppendResult(interp, "Connection to ", dbName, " failed\n", 0);
Tcl_AppendResult(interp, conn->errorMessage, 0);
return TCL_ERROR;
}
}
/**********************************
* pg_disconnect
close a backend connection
syntax:
pg_disconnect connection
The argument passed in must be a connection pointer.
**********************************/
int
Pg_disconnect(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
if (argc != 2) {
Tcl_AppendResult(interp, "Wrong # of arguments\n", "pg_disconnect connection", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "First argument is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
PQfinish(conn);
return TCL_OK;
}
/**********************************
* pg_exec
send a query string to the backend connection
syntax:
pg_exec connection query
the return result is either an error message or a handle for a query
result. Handles start with the prefix "pgp"
**********************************/
int
Pg_exec(AlientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
PGresult *result;
char* connPtrName;
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_exec connection queryString", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
result = PQexec(conn, argv[2]);
if (result) {
PgSetId(interp->result, (void*)result);
return TCL_OK;
}
else {
/* error occurred during the query */
Tcl_SetResult(interp, conn->errorMessage, TCL_STATIC);
return TCL_ERROR;
}
/* check return status of result */
return TCL_OK;
}
/**********************************
* pg_result
get information about the results of a query
syntax:
pg_result result ?option?
the options are:
-status
the status of the result
-conn
the connection that produced the result
-assign arrayName
assign the results to an array
-numTuples
the number of tuples in the query
-attributes
returns a list of the name/type pairs of the tuple attributes
-getTuple tupleNumber
returns the values of the tuple in a list
-clear
clear the result buffer. Do not reuse after this
**********************************/
int
Pg_result(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
char* resultPtrName;
PGresult *result;
char *opt;
int i;
int tupno;
char arrayInd[MAX_MESSAGE_LEN];
char *arrVar;
if (argc != 3 && argc != 4) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",0);
goto Pg_result_errReturn;
}
resultPtrName = argv[1];
if (! PgValidId(resultPtrName)) {
Tcl_AppendResult(interp, "First argument is not a valid query result\n", 0);
return TCL_ERROR;
}
result = (PGresult*)PgGetId(resultPtrName);
opt = argv[2];
if (strcmp(opt, "-status") == 0) {
Tcl_AppendResult(interp, pgresStatus[PQresultStatus(result)], 0);
return TCL_OK;
}
else if (strcmp(opt, "-oid") == 0) {
Tcl_AppendResult(interp, PQoidStatus(result), 0);
return TCL_OK;
}
else if (strcmp(opt, "-conn") == 0) {
PgSetId(interp->result, (void*)result->conn);
return TCL_OK;
}
else if (strcmp(opt, "-clear") == 0) {
PQclear(result);
return TCL_OK;
}
else if (strcmp(opt, "-numTuples") == 0) {
sprintf(interp->result, "%d", PQntuples(result));
return TCL_OK;
}
else if (strcmp(opt, "-assign") == 0) {
if (argc != 4) {
Tcl_AppendResult(interp, "-assign option must be followed by a variable name",0);
return TCL_ERROR;
}
arrVar = argv[3];
/* this assignment assigns the table of result tuples into a giant
array with the name given in the argument,
the indices of the array or (tupno,attrName)*/
for (tupno = 0; tupno<PQntuples(result); tupno++) {
for (i=0;i<PQnfields(result);i++) {
sprintf(arrayInd, "%d,%s", tupno, PQfname(result,i));
Tcl_SetVar2(interp, arrVar, arrayInd,
PQgetvalue(result,tupno,i),
TCL_LEAVE_ERR_MSG);
}
}
Tcl_AppendResult(interp, arrVar, 0);
return TCL_OK;
}
else if (strcmp(opt, "-getTuple") == 0) {
if (argc != 4) {
Tcl_AppendResult(interp, "-getTuple option must be followed by a tuple number",0);
return TCL_ERROR;
}
tupno = atoi(argv[3]);
if (tupno >= PQntuples(result)) {
Tcl_AppendResult(interp, "argument to getTuple cannot exceed number of tuples - 1",0);
return TCL_ERROR;
}
/* Tcl_AppendResult(interp, PQgetvalue(result,tupno,0),NULL); */
Tcl_AppendElement(interp, PQgetvalue(result,tupno,0));
for (i=1;i<PQnfields(result);i++) {
/* Tcl_AppendResult(interp, " ", PQgetvalue(result,tupno,i),NULL);*/
Tcl_AppendElement(interp, PQgetvalue(result,tupno,i));
}
return TCL_OK;
}
else if (strcmp(opt, "-attributes") == 0) {
Tcl_AppendResult(interp, PQfname(result,0),NULL);
for (i=1;i<PQnfields(result);i++) {
Tcl_AppendResult(interp, " ", PQfname(result,i), NULL);
}
return TCL_OK;
}
else {
Tcl_AppendResult(interp, "Invalid option",0);
goto Pg_result_errReturn;
}
Pg_result_errReturn:
Tcl_AppendResult(interp,
"pg_result result ?option? where ?option is\n",
"\t-status\n",
"\t-conn\n",
"\t-assign arrayVarName\n",
"\t-numTuples\n",
"\t-attributes\n"
"\t-getTuple tupleNumber\n",
"\t-clear\n",
"\t-oid\n",
0);
return TCL_ERROR;
}
/**********************************
* pg_lo_open
open a large object
syntax:
pg_lo_open conn objOid mode
where mode can be either 'r', 'w', or 'rw'
**********************/
int
Pg_lo_open(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
int lobjId;
int mode;
int fd;
if (argc != 4) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_open connection lobjOid mode", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
lobjId = atoi(argv[2]);
if (strlen(argv[3]) < 1 ||
strlen(argv[3]) > 2)
{
Tcl_AppendResult(interp,"mode argument must be 'r', 'w', or 'rw'",0);
return TCL_ERROR;
}
switch (argv[3][0]) {
case 'r':
case 'R':
mode = INV_READ;
break;
case 'w':
case 'W':
mode = INV_WRITE;
break;
default:
Tcl_AppendResult(interp,"mode argument must be 'r', 'w', or 'rw'",0);
return TCL_ERROR;
}
switch (argv[3][1]) {
case '\0':
break;
case 'r':
case 'R':
mode = mode & INV_READ;
break;
case 'w':
case 'W':
mode = mode & INV_WRITE;
break;
default:
Tcl_AppendResult(interp,"mode argument must be 'r', 'w', or 'rw'",0);
return TCL_ERROR;
}
fd = lo_open(conn,lobjId,mode);
sprintf(interp->result,"%d",fd);
return TCL_OK;
}
/**********************************
* pg_lo_close
close a large object
syntax:
pg_lo_close conn fd
**********************/
int
Pg_lo_close(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
int fd;
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_close connection fd", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
fd = atoi(argv[2]);
sprintf(interp->result,"%d",lo_close(conn,fd));
return TCL_OK;
}
/**********************************
* pg_lo_read
reads at most len bytes from a large object into a variable named
bufVar
syntax:
pg_lo_read conn fd bufVar len
bufVar is the name of a variable in which to store the contents of the read
**********************/
int
Pg_lo_read(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
int fd;
int nbytes = 0;
char *buf;
char *bufVar;
int len;
if (argc != 5) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
" pg_lo_read conn fd bufVar len", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
fd = atoi(argv[2]);
bufVar = argv[3];
len = atoi(argv[4]);
if (len <= 0) {
sprintf(interp->result,"%d",nbytes);
return TCL_OK;
}
buf = malloc(sizeof(len+1));
nbytes = lo_read(conn,fd,buf,len);
Tcl_SetVar(interp,bufVar,buf,TCL_LEAVE_ERR_MSG);
sprintf(interp->result,"%d",nbytes);
free(buf);
return TCL_OK;
}
/***********************************
Pg_lo_write
write at most len bytes to a large object
syntax:
pg_lo_write conn fd buf len
***********************************/
int
Pg_lo_write(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char *connPtrName;
char *buf;
int fd;
int nbytes = 0;
int len;
if (argc != 5) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_write conn fd buf len", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
fd = atoi(argv[2]);
buf = argv[3];
len = atoi(argv[4]);
if (len <= 0) {
sprintf(interp->result,"%d",nbytes);
return TCL_OK;
}
nbytes = lo_write(conn,fd,buf,len);
sprintf(interp->result,"%d",nbytes);
return TCL_OK;
}
/***********************************
Pg_lo_lseek
seek to a certain position in a large object
syntax
pg_lo_lseek conn fd offset whence
whence can be either
"SEEK_CUR", "SEEK_END", or "SEEK_SET"
***********************************/
int
Pg_lo_lseek(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
int fd;
char *whenceStr;
int offset, whence;
if (argc != 5) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_lseek conn fd offset whence", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
fd = atoi(argv[2]);
offset = atoi(argv[3]);
whenceStr = argv[4];
if (strcmp(whenceStr,"SEEK_SET") == 0) {
whence = SEEK_SET;
} else if (strcmp(whenceStr,"SEEK_CUR") == 0) {
whence = SEEK_CUR;
} else if (strcmp(whenceStr,"SEEK_END") == 0) {
whence = SEEK_END;
} else {
Tcl_AppendResult(interp, "the whence argument to Pg_lo_lseek must be SEEK_SET, SEEK_CUR or SEEK_END",0);
return TCL_ERROR;
}
sprintf(interp->result,"%d",lo_lseek(conn,fd,offset,whence));
return TCL_OK;
}
/***********************************
Pg_lo_creat
create a new large object with mode
syntax:
pg_lo_creat conn mode
mode can be any OR'ing together of INV_READ, INV_WRITE, and INV_ARCHIVE,
for now, we don't support any additional storage managers.
***********************************/
int
Pg_lo_creat(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
char *modeStr;
char *modeWord;
int mode;
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_creat conn mode", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
modeStr = argv[2];
modeWord = strtok(modeStr,"|");
if (strcmp(modeWord,"INV_READ") == 0) {
mode = INV_READ;
} else if (strcmp(modeWord,"INV_WRITE") == 0) {
mode = INV_WRITE;
} else if (strcmp(modeWord,"INV_ARCHIVE") == 0) {
mode = INV_ARCHIVE;
} else {
Tcl_AppendResult(interp,
"invalid mode argument to Pg_lo_creat\nmode argument must be some OR'd combination of INV_READ, INV_WRITE, and INV_ARCHIVE",
0);
return TCL_ERROR;
}
while ( (modeWord = strtok((char*)NULL, "|")) != NULL) {
if (strcmp(modeWord,"INV_READ") == 0) {
mode |= INV_READ;
} else if (strcmp(modeWord,"INV_WRITE") == 0) {
mode |= INV_WRITE;
} else if (strcmp(modeWord,"INV_ARCHIVE") == 0) {
mode |= INV_ARCHIVE;
} else {
Tcl_AppendResult(interp,
"invalid mode argument to Pg_lo_creat\nmode argument must be some OR'd combination of INV_READ, INV_WRITE, and INV_ARCHIVE",
0);
return TCL_ERROR;
}
}
sprintf(interp->result,"%d",lo_creat(conn,mode));
return TCL_OK;
}
/***********************************
Pg_lo_tell
returns the current seek location of the large object
syntax:
pg_lo_tell conn fd
***********************************/
int
Pg_lo_tell(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
int fd;
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_tell conn fd", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
fd = atoi(argv[2]);
sprintf(interp->result,"%d",lo_tell(conn,fd));
return TCL_OK;
}
/***********************************
Pg_lo_unlink
unlink a file based on lobject id
syntax:
pg_lo_unlink conn lobjId
***********************************/
int
Pg_lo_unlink(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
int lobjId;
int retval;
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_tell conn fd", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
lobjId = atoi(argv[2]);
retval = lo_unlink(conn,lobjId);
if (retval == -1) {
sprintf(interp->result,"Pg_lo_unlink of '%d' failed",lobjId);
return TCL_ERROR;
}
sprintf(interp->result,"%d",retval);
return TCL_OK;
}
/***********************************
Pg_lo_import
import a Unix file into an (inversion) large objct
returns the oid of that object upon success
returns InvalidOid upon failure
syntax:
pg_lo_import conn filename
***********************************/
int
Pg_lo_import(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
char* filename;
Oid lobjId;
if (argc != 3) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_import conn filename", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
filename = argv[2];
lobjId = lo_import(conn,filename);
if (lobjId == InvalidOid) {
sprintf(interp->result, "Pg_lo_import of '%s' failed",filename);
return TCL_ERROR;
}
sprintf(interp->result,"%d",lobjId);
return TCL_OK;
}
/***********************************
Pg_lo_export
export an Inversion large object to a Unix file
syntax:
pg_lo_export conn lobjId filename
***********************************/
int
Pg_lo_export(ClientData cData, Tcl_Interp *interp, int argc, char* argv[])
{
PGconn *conn;
char* connPtrName;
char* filename;
Oid lobjId;
int retval;
if (argc != 4) {
Tcl_AppendResult(interp, "Wrong # of arguments\n",
"pg_lo_export conn lobjId filename", 0);
return TCL_ERROR;
}
connPtrName = argv[1];
if (! PgValidId(connPtrName)) {
Tcl_AppendResult(interp, "Argument passed in is not a valid connection\n", 0);
return TCL_ERROR;
}
conn = (PGconn*)PgGetId(connPtrName);
lobjId = atoi(argv[2]);
filename = argv[3];
retval = lo_export(conn,lobjId,filename);
if (retval == -1) {
sprintf(interp->result, "Pg_lo_export %d %s failed",lobjId, filename);
return TCL_ERROR;
}
return TCL_OK;
}

View File

@ -0,0 +1,52 @@
/*-------------------------------------------------------------------------
*
* pgtclCmds.h--
* declarations for the C functions which implement pg_* tcl commands
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pgtclCmds.h,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PGTCLCMDS_H
#define PGTCLCMDS_H
#include "tcl.h"
/* **************************/
/* registered Tcl functions */
/* **************************/
extern int Pg_connect(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_disconnect(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_exec(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_result(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_open(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_close(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_read(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_write(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_lseek(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_creat(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_tell(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_unlink(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_import(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
extern int Pg_lo_export(
ClientData cData, Tcl_Interp *interp, int argc, char* argv[]);
#endif /*PGTCLCMDS_H*/

View File

@ -0,0 +1,51 @@
/*-------------------------------------------------------------------------
*
* pgtclId.c--
* useful routines to convert between strings and pointers
* Needed because everything in tcl is a string, but we want pointers
* to data structures
*
* ASSUMPTION: sizeof(long) >= sizeof(void*)
*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdlib.h>
#include <string.h>
#include "tcl.h"
#include "pgtclId.h"
/* convert a pointer into a string */
void
PgSetId(char *id, void *ptr)
{
(void) sprintf(id, "pgp%lx", (long) ptr);
}
/* get back a pointer from a string */
void *
PgGetId(char *id)
{
long ptr;
ptr = strtol(id+3, NULL, 16);
return (void *) ptr;
}
/* check to see if the string is a valid pgtcl pointer */
int
PgValidId(char* id)
{
if ( (strlen(id) > 3) && id[0]=='p' && id[1] == 'g' && id[2] == 'p')
return 1;
else
return 0;
}

View File

@ -0,0 +1,18 @@
/*-------------------------------------------------------------------------
*
* pgtclId.h--
* useful routines to convert between strings and pointers
* Needed because everything in tcl is a string, but often, pointers
* to data structures are needed.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pgtclId.h,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
extern void PgSetId(char *id, void *ptr);
extern void* PgGetId(char *id);
extern int PgValidId(char* id);

View File

@ -0,0 +1,54 @@
#-------------------------------------------------------------------------
#
# Makefile
# Makefile for libpq++ library
#
# Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $
#
#-------------------------------------------------------------------------
CPP_LIB= true
LIB= pq++
MKDIR= ../mk
include $(MKDIR)/postgres.mk
CXXFLAGS = $(CFLAGS)
CXXFLAGS+= -I$(srcdir)/backend/include \
-I$(srcdir)/backend \
-I$(srcdir)/libpq \
-I$(CURDIR) \
ifdef KRBVERS
CXXFLAGS+= $(KRBFLAGS)
endif
LIBSRCS = pgenv.cc pgconnection.cc pglobject.cc
.PHONY: beforeinstall-headers install-headers
ifndef NO_BEFOREINSTL
beforeinstall-headers:
@-if [ ! -d $(HEADERDIR) ]; then mkdir $(HEADERDIR); fi
else
beforeinstall-headers: .dosomething
endif
HEADERFILES = libpq++.H
install-headers: beforeinstall-headers
@for i in ${HEADERFILES}; do \
echo "Installing $(HEADERDIR)/$$i."; \
$(INSTALL) -c -m 444 $$i $(HEADERDIR)/$$i; \
done
install:: install-headers
include $(MKDIR)/postgres.lib.mk

View File

@ -0,0 +1,22 @@
This directory contains libpq++, the C++ language interface to POSTGRES95.
libpq++ is implemented on of the libpq library. Users would benefit
from reading the chapter on libpq in the postgres95 users manual
before using libpq++.
The initial version of this implementation was done by William Wanders
(wwanders@sci.kun.nl)
This is only a preliminary attempt at providing something useful for
people who would like to use C++ to build frontend applications to
postgres95. The API provided herein is subject to change in later
versions of postgres95.
For details on how to to use libpq++, see the man page in the man/
subdirectory and the test programs in the examples/ subdirectory.
libpq++ has been tested with g++, version 2.7.0
- Jolly Chen
jolly@cs.berkeley.edu
Tue Sep 5 11:09:51 PDT 1995

View File

@ -0,0 +1,70 @@
#
# Makefile for example programs
#
CPP_PROG = true
MKDIR= ../../mk
include $(MKDIR)/postgres.mk
CXXFLAGS+= -I$(HEADERDIR) -I$(srcdir)/libpq -I$(srcdir)/backend \
-I$(srcdir)/backend/include
LD_ADD+=-L$(LIBDIR) -lpq++ -lpq
#
# And where libpq goes, so goes the authentication stuff...
#
ifdef KRBVERS
LD_ADD+= $(KRBLIBS)
CXXFLAGS+= $(KRBFLAGS)
endif
P0_PROG:= testlibpq0
P0_OBJS:= testlibpq0.o
$(P0_PROG): $(addprefix $(objdir)/,$(P0_OBJS))
$(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD)
P1_PROG:= testlibpq1
P1_OBJS:= testlibpq1.o
$(P1_PROG): $(addprefix $(objdir)/,$(P1_OBJS))
$(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD)
P2_PROG:= testlibpq2
P2_OBJS:= testlibpq2.o
$(P2_PROG): $(addprefix $(objdir)/,$(P2_OBJS))
$(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD)
P3_PROG:= testlibpq3
P3_OBJS:= testlibpq3.o
$(P3_PROG): $(addprefix $(objdir)/,$(P3_OBJS))
$(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD)
P4_PROG:= testlibpq4
P4_OBJS:= testlibpq4.o
$(P4_PROG): $(addprefix $(objdir)/,$(P4_OBJS))
$(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD)
P5_PROG:= testlo
P5_OBJS:= testlo.o
$(P5_PROG): $(addprefix $(objdir)/,$(P5_OBJS))
$(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD)
OBJS:= $(P0_OBJS) $(P1_OBJS) $(P2_OBJS) $(P3_OBJS) $(P4_OBJS) $(P5_OBJS)
PROGS:= $(P0_PROG) $(P1_PROG) $(P2_PROG) $(P3_PROG) $(P4_PROG) $(P5_PROG)
CLEANFILES+= $(OBJS) $(PROGS)
all:: $(PROGS)
install:: $(PROGS)
@for i in ${PROGS}; do \
echo "Installing $$i"; \
$(INSTALL) $(objdir)/$$i $(DESTDIR)$(BINDIR)/$$i;\
done

View File

@ -0,0 +1,49 @@
/*-------------------------------------------------------------------------
*
* testlibpq0.c--
* small test program for libpq++,
* small interactive loop where queries can be entered interactively
* and sent to the backend
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq++/examples/Attic/testlibpq0.cc,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include "libpq++.H"
int
main(int argc, char** argv)
{
ExecStatusType status;
PGenv env;
PGdatabase* data;
char buf[10000];
int done = 0;
data = new PGdatabase(&env, "template1");
if (data->status() == CONNECTION_BAD)
printf("connection was unsuccessful\n%s\n", data->errormessage());
else
printf("connection successful\n");
while (!done)
{
printf("> ");fflush(stdout);
if (gets(buf) && buf[0]!='\0')
if((status = data->exec(buf)) == PGRES_TUPLES_OK)
data->printtuples(stdout, 1, "|", 1, 0);
else
printf("status = %s\nerrorMessage = %s\n", status,
data->errormessage());
else
done = 1;
}
}

View File

@ -0,0 +1,84 @@
/*
* testlibpq.cc
* Test the C++ version of LIBPQ, the POSTGRES frontend library.
*
* queries the template1 database for a list of database names
*
*/
#include <stdio.h>
#include "libpq++.H"
main()
{
char* dbName;
int nFields;
int i,j;
/* begin, by creating the parameter environtment for a backend
connection. When no parameters are given then the system will
try to use reasonable defaults by looking up environment variables
or, failing that, using hardwired constants */
PGenv env;
PGdatabase* data;
/* Select a database */
dbName = "template1";
/* make a connection to the database */
data = new PGdatabase(&env, dbName);
/* check to see that the backend connection was successfully made */
if (data->status() == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.\n", dbName);
fprintf(stderr,"%s",data->errormessage());
delete data;
exit(1);
}
/* start a transaction block */
if(data->exec("BEGIN") != PGRES_COMMAND_OK) {
fprintf(stderr,"BEGIN command failed\n");
delete data;
exit(1);
}
/* fetch instances from the pg_database, the system catalog of databases*/
if (data->exec("DECLARE myportal CURSOR FOR select * from pg_database")
!= PGRES_COMMAND_OK) {
fprintf(stderr,"DECLARE CURSOR command failed\n");
delete data;
exit(1);
}
if(data->exec("FETCH ALL in myportal") != PGRES_TUPLES_OK) {
fprintf(stderr,"FETCH ALL command didn't return tuples properly\n");
delete data;
exit(1);
}
/* first, print out the attribute names */
nFields = data->nfields();
for (i=0; i < nFields; i++) {
printf("%-15s",data->fieldname(i));
}
printf("\n\n");
/* next, print out the instances */
for (i=0; i < data->ntuples(); i++) {
for (j=0 ; j < nFields; j++) {
printf("%-15s", data->getvalue(i,j));
}
printf("\n");
}
/* close the portal */
data->exec("CLOSE myportal");
/* end the transaction */
data->exec("END");
/* close the connection to the database and cleanup */
delete data;
}

View File

@ -0,0 +1,71 @@
/*
* testlibpq2.cc
* Test of the asynchronous notification interface
*
populate a database with the following:
CREATE TABLE TBL1 (i int4);
CREATE TABLE TBL2 (i int4);
CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2];
* Then start up this program
* After the program has begun, do
INSERT INTO TBL1 values (10);
*
*
*/
#include <stdio.h>
#include "libpq++.H"
main()
{
char* dbName;
int nFields;
int i,j;
/* begin, by creating the parameter environtment for a backend
connection. When no parameters are given then the system will
try to use reasonable defaults by looking up environment variables
or, failing that, using hardwired constants */
PGenv env;
PGdatabase* data;
PGnotify* notify;
dbName = getenv("USER"); /* change this to the name of your test database */
/* make a connection to the database */
data = new PGdatabase(&env, dbName);
/* check to see that the backend connection was successfully made */
if (data->status() == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.\n", dbName);
fprintf(stderr,"%s",data->errormessage());
delete data;
exit(1);
}
if (data->exec("LISTEN TBL2") != PGRES_COMMAND_OK) {
fprintf(stderr,"LISTEN command failed\n");
delete data;
exit(1);
}
while (1) {
/* check for asynchronous returns */
notify = data->notifies();
if (notify) {
fprintf(stderr,
"ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
notify->relname, notify->be_pid);
free(notify);
break;
}
}
/* close the connection to the database and cleanup */
delete data;
}

View File

@ -0,0 +1,5 @@
CREATE TABLE TBL1 (i int4);
CREATE TABLE TBL2 (i int4);
CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2];

View File

@ -0,0 +1,131 @@
/*
* testlibpq3.cc
* Test the C++ version of LIBPQ, the POSTGRES frontend library.
* tests the binary cursor interface
*
*
*
populate a database by doing the following:
CREATE TABLE test1 (i int4, d float4, p polygon);
INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0, 2.0)'::polygon);
INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0, 1.0)'::polygon);
the expected output is:
tuple 0: got
i = (4 bytes) 1,
d = (4 bytes) 3.567000,
p = (4 bytes) 2 points boundbox = (hi=3.000000/4.000000, lo = 1.000000,2.000000)
tuple 1: got
i = (4 bytes) 2,
d = (4 bytes) 89.050003,
p = (4 bytes) 2 points boundbox = (hi=4.000000/3.000000, lo = 2.000000,1.000000)
*
*/
#include <stdio.h>
#include "libpq++.H"
extern "C" {
#include "utils/geo-decls.h" /* for the POLYGON type */
}
main()
{
char* dbName;
int nFields;
int i,j;
int i_fnum, d_fnum, p_fnum;
/* begin, by creating the parameter environtment for a backend
connection. When no parameters are given then the system will
try to use reasonable defaults by looking up environment variables
or, failing that, using hardwired constants */
PGenv env;
PGdatabase* data;
dbName = getenv("USER"); /* change this to the name of your test database */
/* make a connection to the database */
data = new PGdatabase(&env, dbName);
/* check to see that the backend connection was successfully made */
if (data->status() == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.\n", dbName);
fprintf(stderr,"%s",data->errormessage());
delete data;
exit(1);
}
/* start a transaction block */
if (data->exec("BEGIN") != PGRES_COMMAND_OK) {
fprintf(stderr,"BEGIN command failed\n");
delete data;
exit(1);
}
/* fetch instances from the pg_database, the system catalog of databases*/
if (data->exec("DECLARE mycursor BINARY CURSOR FOR select * from test1")
!= PGRES_COMMAND_OK) {
fprintf(stderr,"DECLARE CURSOR command failed\n");
delete data;
exit(1);
}
if (data->exec("FETCH ALL in mycursor") != PGRES_TUPLES_OK) {
fprintf(stderr,"FETCH ALL command didn't return tuples properly\n");
delete data;
exit(1);
}
i_fnum = data->fieldnum("i");
d_fnum = data->fieldnum("d");
p_fnum = data->fieldnum("p");
/*
for (i=0;i<3;i++) {
printf("type[%d] = %d, size[%d] = %d\n",
i, data->fieldtype(i),
i, data->fieldsize(i));
}
*/
for (i=0; i < data->ntuples(); i++) {
int *ival;
float *dval;
int plen;
POLYGON* pval;
/* we hard-wire this to the 3 fields we know about */
ival = (int*)data->getvalue(i,i_fnum);
dval = (float*)data->getvalue(i,d_fnum);
plen = data->getlength(i,p_fnum);
/* plen doesn't include the length field so need to increment by VARHDSZ*/
pval = (POLYGON*) malloc(plen + VARHDRSZ);
pval->size = plen;
memmove((char*)&pval->npts, data->getvalue(i,p_fnum), plen);
printf("tuple %d: got\n", i);
printf(" i = (%d bytes) %d,\n",
data->getlength(i,i_fnum), *ival);
printf(" d = (%d bytes) %f,\n",
data->getlength(i,d_fnum), *dval);
printf(" p = (%d bytes) %d points \tboundbox = (hi=%f/%f, lo = %f,%f)\n",
data->getlength(i,d_fnum),
pval->npts,
pval->boundbox.xh,
pval->boundbox.yh,
pval->boundbox.xl,
pval->boundbox.yl);
}
/* close the portal */
data->exec("CLOSE mycursor");
/* end the transaction */
data->exec("END");
/* close the connection to the database and cleanup */
delete data;
}

View File

@ -0,0 +1,6 @@
CREATE TABLE test1 (i int4, d float4, p polygon);
INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0, 2.0)'::polygon);
INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0, 1.0)'::polygon);

View File

@ -0,0 +1,69 @@
/*
* testlibpq4.cc
* Test the C++ version of LIBPQ, the POSTGRES frontend library.
* tests the copy in features
*
*/
#include <stdio.h>
#include "libpq++.H"
#define DEBUG printf("Got here %d\n", __LINE__);
main()
{
char* dbName;
int nFields;
int i,j;
/* begin, by creating the parameter environment for a backend
connection. When no parameters are given then the system will
try to use reasonable defaults by looking up environment variables
or, failing that, using hardwired constants */
PGenv env;
PGdatabase* data;
dbName = getenv("USER"); /* change this to the name of your test database */
/* make a connection to the database */
data = new PGdatabase(&env, dbName);
/* check to see that the backend connection was successfully made */
if (data->status() == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.\n", dbName);
fprintf(stderr,"%s",data->errormessage());
delete data;
exit(1);
}
/* start a transaction block */
if(data->exec("BEGIN") != PGRES_COMMAND_OK) {
fprintf(stderr,"BEGIN command failed\n");
delete data;
exit(1);
}
if (data->exec("CREATE TABLE foo (a int4, b char16, d float8)") !=
PGRES_COMMAND_OK) {
fprintf(stderr,"CREATE TABLE foo command failed\n");
delete data;
exit(1);
}
if (data->exec("COPY foo FROM STDIN") != PGRES_COMMAND_OK) {
fprintf(stderr,"COPY foo FROM STDIN\n");
delete data;
exit(1);
}
data->putline("3\thello world\t4.5\n");
data->putline("4\tgoodbye word\t7.11\n");
data->putline(".\n");
data->endcopy();
data->exec("SELECT * FROM foo");
data->printtuples(stdout,1,"|",1,0);
data->exec("DROP TABLE foo");
// end the transaction
data->exec("END");
// close the connection to the database and cleanup
delete data;
}

View File

@ -0,0 +1,63 @@
/*-------------------------------------------------------------------------
*
* lotest.cc--
* test using large objects with libpq
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq++/examples/Attic/testlo.cc,v 1.1.1.1 1996/07/09 06:22:19 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include "libpq++.H"
extern "C" {
#include "libpq/libpq-fs.h"
}
int
main(int argc, char **argv)
{
char *in_filename, *out_filename;
char *database;
Oid lobjOid;
PGenv env;
PGlobj *object;
if (argc < 4 || argc > 5) {
fprintf(stderr, "Usage: %s database_name in_filename out_filename [oid]\n",
argv[0]);
exit(1);
}
database = argv[1];
in_filename = argv[2];
out_filename = argv[3];
/*
* set up the connection and create a largeobject for us
*/
if (argc == 4) {
object = new PGlobj(&env, database);
} else {
object = new PGlobj(&env, database, atoi(argv[4]));
}
/* check to see that the backend connection was successfully made */
if (object->status() == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.\n", database);
fprintf(stderr,"%s",object->errormessage());
delete object;
exit(1);
}
object->exec("BEGIN");
printf("importing file \"%s\" ...\n", in_filename);
object->import(in_filename);
printf("exporting large object to file \"%s\" ...\n", out_filename);
object->export(out_filename);
object->exec("END"); // WHY DOES IT CORE DUMP HERE ???
delete object;
}

View File

@ -0,0 +1,173 @@
/*-------------------------------------------------------------------------
*
* libpq++.H
*
*
* DESCRIPTION
* C++ client interface to Postgres
* used for building front-end applications
*
* NOTES
* Currently under construction.
*
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
*
* $Id: libpq++.H,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LIBPQXX_H
#define LIBPQXX_H
#include <stdio.h>
#include <strings.h>
extern "C" {
#include "libpq-fe.h"
#include "fe-auth.h"
}
// ****************************************************************
//
// PGenv - the environment for setting up a connection to postgres
//
// ****************************************************************
class PGenv {
friend class PGconnection;
char* pgauth;
char* pghost;
char* pgport;
char* pgoption;
char* pgtty;
public:
PGenv(); // default ctor will use reasonable defaults
// will use environment variables PGHOST, PGPORT,
// PGOPTION, PGTTY
PGenv(char* auth, char* host, char* port, char* option, char* tty);
void setValues(char* auth, char* host, char* port, char* option, char* tty);
~PGenv();
};
// ****************************************************************
//
// PGconnection - a connection made to a postgres backend
//
// ****************************************************************
class PGconnection {
friend class PGdatabase;
friend class PGlobj;
PGenv* env;
PGconn* conn;
PGresult* result;
char errorMessage[ERROR_MSG_LENGTH];
public:
PGconnection(); // use reasonable defaults
PGconnection(PGenv* env, char* dbName); // connect to the database with
// given environment and database name
ConnStatusType status();
char* errormessage() {return errorMessage;};
// returns the database name of the connection
char* dbName() {return PQdb(conn);};
ExecStatusType exec(char* query); // send a query to the backend
PGnotify* notifies() {exec(" "); return PQnotifies(conn);};
~PGconnection(); // close connection and clean up
protected:
ConnStatusType connect(PGenv* env, char* dbName);
};
// ****************************************************************
//
// PGdatabase - a class for accessing databases
//
// ****************************************************************
class PGdatabase : public PGconnection {
public:
PGdatabase() : PGconnection() {}; // use reasonable defaults
// connect to the database with
PGdatabase(PGenv* env, char* dbName) : PGconnection(env, dbName) {};
// query result access
int ntuples()
{return PQntuples(result);};
int nfields()
{return PQnfields(result);};
char* fieldname(int field_num)
{return PQfname(result, field_num);};
int fieldnum(char* field_name)
{return PQfnumber(result, field_name);};
Oid fieldtype(int field_num)
{return PQftype(result, field_num);};
Oid fieldtype(char* field_name)
{return PQftype(result, fieldnum(field_name));};
int2 fieldsize(int field_num)
{return PQfsize(result, field_num);};
int2 fieldsize(char* field_name)
{return PQfsize(result, fieldnum(field_name));};
char* getvalue(int tup_num, int field_num)
{return PQgetvalue(result, tup_num, field_num);};
char* getvalue(int tup_num, char* field_name)
{return PQgetvalue(result, tup_num, fieldnum(field_name));};
int getlength(int tup_num, int field_num)
{return PQgetlength(result, tup_num, field_num);};
int getlength(int tup_num, char* field_name)
{return PQgetlength(result, tup_num, fieldnum(field_name));};
void printtuples(FILE *out, int fillAlign, char *fieldSep,
int printHeader, int quiet)
{PQdisplayTuples(result, out, fillAlign, fieldSep, printHeader, quiet);};
// copy command related access
int getline(char* string, int length)
{return PQgetline(conn, string, length);};
void putline(char* string)
{PQputline(conn, string);};
int endcopy()
{return PQendcopy(conn);};
~PGdatabase() {}; // close connection and clean up
};
// ****************************************************************
//
// PGlobj - a class for accessing Large Object in a database
//
// ****************************************************************
class PGlobj : public PGconnection {
int fd;
Oid object;
public:
PGlobj(); // use reasonable defaults and create large object
PGlobj(Oid lobjId); // use reasonable defaults and open large object
PGlobj(PGenv* env, char* dbName); // create large object
PGlobj(PGenv* env, char* dbName, Oid lobjId); // open large object
int read(char* buf, int len)
{return lo_read(conn, fd, buf, len);};
int write(char* buf, int len)
{return lo_write(conn, fd, buf, len);};
int lseek(int offset, int whence)
{return lo_lseek(conn, fd, offset, whence);};
int tell()
{return lo_tell(conn, fd);};
int unlink();
int import(char* filename);
int export(char* filename);
~PGlobj(); // close connection and clean up
};
//
// these are the environment variables used for getting defaults
//
#define ENV_DEFAULT_AUTH "PGAUTH"
#define ENV_DEFAULT_DBASE "PGDATABASE"
#define ENV_DEFAULT_HOST "PGHOST"
#define ENV_DEFAULT_OPTION "PGOPTION"
#define ENV_DEFAULT_PORT "PGPORT"
#define ENV_DEFAULT_TTY "PGTTY"
// buffer size
#define BUFSIZE 1024
#endif /* LIBPQXX_H */

View File

@ -0,0 +1,434 @@
.\"
.\" POSTGRES95 Data Base Management System
.\"
.\" Copyright (c) 1994-5 Regents of the University of California
.\"
.\" POSTGRES Data Base Management System
.\" Copyright (c) 1988,1994 Regents of the University of California
.\"
.\" Permission to use, copy, modify, and distribute this software and its
.\" documentation for any purpose, without fee, and without a written agreement
.\" is hereby granted, provided that the above copyright notice and this
.\" paragraph and the following two paragraphs appear in all copies.
.\"
.\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
.\" DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
.\" LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
.\" DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
.\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
.\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
.\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
.\"
.\"
.\" $Id: libpq++.3,v 1.1.1.1 1996/07/09 06:22:19 scrappy Exp $
.\"
.\" ------------------------------------------------------------------
.\" .(l, .)l
.\" fake "-me"-style lists
.de (l
.nf
.ie '\\$1'M' .in +0n
.el .in +5n
..
.de )l
.fi
.in
..
.\" .(C, .)C
.\" constant-width font blocks
.de (C
.ft C
.(b
.(l \\$1
.sp
..
.de )C
.sp
.)l
.)b
.ft R
..
.\" ------------------------------------------------------------------
.de SE
.nr si 0
.nr so 0
.nr $0 0
.nr $i \\n(si*\\n($0
.in \\n($i+\\n(po
..
.\" ------------------------------------------------------------------
.de SP
.he '\fB\\$1 (\\$2)'\\$3'\\$1 (\\$2)\fR'
..
.\" ------------------------------------------------------------------
.de SS
.PP
.B \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
.PP
..
.\" ------------------------------------------------------------------
.SB
.ds II \s-1INGRES\s0
.ds PG \s-1POSTGRES95\s0
.ds UU \s-1UNIX\s0
.ds PQ \s-1POSTQUEL\s0
.ds LI \s-1LIBPQ++\s0
.ds PV 4.2
.SB
.TH INTRODUCTION LIBPQ++ 07/24/95
.XA 0 "Libpq++"
.BH "LIBPQ++"
.SH DESCRIPTION
\*(LI is the C++ API to \*(PG. \*(LI is a set of classes which allow
client programs to connect to the \*(PG backend server. These connections
come in two forms: a Database Class and a Large Object class.
.PP
The Database Class is intended for manipulating a database. You can
send all sorts of SQL queries to the \*(PG backend server and retrieve
the responses of the server.
.PP
The Large Object Class is intended for manipulating a large object
in a database. Although a Large Object instance can send normal
queries to the \*(PG backend server it is only intended for simple
queries that do not return any data. A large object should be seen
as a file stream. In future it should behave much like the C++ file
streams
.IR cin ,
.IR cout
and
.IR cerr .
This version of the documentation is based on the C library. Three
short programs are listed at the end of this section as examples of
\*(LI programming (though not necessarily of good programming).
.PP
There are several examples of \*(LI applications in the following
directory:
.(C
\&.../src/libpq++/examples
.)C
.XA 1 "Control and Initialization"
.SH "CONTROL AND INITIALIZATION"
.XA 2 "Environment Variables"
.SS "Environment Variables"
The following environment variables can be used to set up default
values for an environment and to avoid hard-coding database names into
an application program:
.TP 15n
.BR PGDATABASE
sets the default \*(PG database name.
.TP 15n
.BR PGHOST
sets the default server name.
.TP 15n
.BR PGOPTIONS
sets additional runtime options for the \*(PG backend.
.TP 15n
.BR PGPORT
sets the default communication port with the \*(PG backend.
.TP 15n
.BR PGTTY
sets the file or tty on which debugging messages from the backend server
are displayed.
.TP 15n
.BR PGREALM
sets the
.IR Kerberos
realm to use with \*(PG, if it is different from the local realm. If
.SM PGREALM
is set, \*(PG applications will attempt authentication with servers
for this realm and use separate ticket files to avoid conflicts with
local ticket files. This environment variable is only used if
.IR Kerberos
authentication is enabled.
.TP 15n
.BR PGAUTH
sets the type of authentication which should be used. Currently
only
.IR unauth ,
.IR krb4 ,
and
.IR krb5 .
are supported. Depending on whether you compiled in support for those.
.XA 1 "Database Connection Functions"
.SH "DATABASE ENVIRONMENT CLASS: PGenv"
The database environment class provides C++ objects for manipulating the
above environment variables.
.TP 15n
.BR PGenv
Create an environment for the running program.
.(C
PGenv()
PGenv(char* auth, char* host, char* port, char* option, char* tty)
.)C
The first form of this object's constructor sets up the defaults for
the program from the environment variables listed above.
The second allows the programmer to hardcode the values into the program.
The values of the second form relate directly to the environment variables
above.
.SH "DATABASE CLASS: PGdatabase"
The database class is a provides C++ objects that have a connection
to a backend server. To create such an object one first need
the apropriate environment for the backend to access.
The following constructors deal with making a connection to a backend
server from a C++ program.
.TP 15n
.BR PGdatabase
Make a new connection to a backend database server.
.(C
PGdatabase(PGenv *env, char *dbName);
.)C
After a PGdatabase has been created it should be checked to make sure
the connection to the database succeded before sending
queries to the object. This can easily be done by
retrieving the current status of the PGdatabase object with the
.IR status
command.
.BR PGdatabase::status
Returns the status of the PGdatabase object.
.(C
ConnStatus PGdatabase::status()
.)C
the following values are allowed
.(C
CONNECTION_OK
CONNECTION_BAD
.)C
.XA 1 "Query Execution Functions"
.SH "QUERY EXECUTION FUNCTIONS"
.TP 15n
.BR PGdatabase::exec
Submits a query to \*(PG and returns result status. In case of an error
.IR PGdatabase::errormessage
can be used to get more information on the error.
.(C
void
ExecStatusType PGdatabase::exec(char *query);
.)C
The following status results can be expected.
.(C
PGRES_EMPTY_QUERY,
PGRES_COMMAND_OK, /* the query was a command */
PGRES_TUPLES_OK, /* the query successfully returned tuples */
PGRES_COPY_OUT,
PGRES_COPY_IN,
PGRES_BAD_RESPONSE, /* an unexpected response was received */
PGRES_NONFATAL_ERROR,
PGRES_FATAL_ERROR
.)C
.IP
If the result status is PGRES_TUPLES_OK, then the following routines can
be used to retrieve the tuples returned by the query.
.IP
.BR PGdatabase::ntuples
returns the number of tuples (instances) in the query result.
.(C
int PGdatabase::ntuples();
.)C
.BR PGdatabase::nfields
returns the number of fields (attributes) in the query result.
.(C
int PGdatabase::nfields();
.)C
.BR PGdatabase::fieldname
returns the field (attribute) name associated with the given field index.
Field indices start at 0.
.(C
char* PGdatabase::fieldname(int field_index);
.)C
.BR PGdatabase::fieldnum
returns the field (attribute) index associated with the given field name.
.(C
int PGdatabase::fieldnum(char* field_name);
.)C
.BR PGdatabase::fieldtype
returns the field type of associated with the given field index or name.
The integer returned is an internal coding of the type. Field indices start
at 0.
.(C
Oid PGdatabase::fieldtype(int field_index);
Oid PGdatabase::fieldtype(char* field_name);
.)C
.BR PGdatabase::fieldsize
returns the size in bytes of the field associated with the given field
index or name. If the size returned is -1, the field is a variable length
field. Field indices start at 0.
.(C
int2 PGdatabase::fieldsize(int field_index);
int2 PGdatabase::fieldsize(char* field_name);
.)C
.BR PGdatabase::getvalue
returns the field (attribute) value. For most queries, the values
returned by
.IR PGdatabase::getvalue
is a null-terminated ASCII string representation
of the attribute value. If the query was a result of a
.BR BINARY
cursor, then the values returned by
.IR PGdatabase::getvalue
is the binary representation of the type in the internal format of the
backend server. It is the programmer's responsibility to cast and
convert the data to the correct C++ type. The value return by
.IR PGdatabase::getvalue
points to storage that is part of the PGdatabase structure. One must
explicitly copy the value into other storage if it is to be used past
the next query.
.(C
char* PGdatabase::getvalue(int tup_num, int field_index);
char* PGdatabase::getvalue(int tup_num, char* field_name);
.)C
.BR PGdatabase::getlength
returns the length of a field (attribute) in bytes. If the field
is a
.IR "struct varlena" ,
the length returned here does
.BR not
include the size field of the varlena, i.e., it is 4 bytes less.
.(C
int PGdatabase::getlength(int tup_num, int field_index);
int PGdatabase::getlength(int tup_num, char* field_name);
.)C
.BR PGdatabase::printtuples
prints out all the tuples and, optionally, the attribute names to the
specified output stream.
.(C
void PGdatabase::printtuples(
FILE* fout, /* output stream */
int printAttName,/* print attribute names or not*/
int terseOutput, /* delimiter bars or not?*/
int width /* width of column, variable width if 0*/
);
.)C
.XA 1 "Asynchronous Notification"
.SH "ASYNCHRONOUS NOTIFICATION"
\*(PG supports asynchronous notification via the
.IR LISTEN
and
.IR NOTIFY
commands. A backend registers its interest in a particular relation
with the LISTEN command. All backends that are listening on a
particular relation will be notified asynchronously when a NOTIFY of
that relation name is executed by another backend. No additional
information is passed from the notifier to the listener. Thus,
typically, any actual data that needs to be communicated is transferred
through the relation.
.PP
\*(LI applications are notified whenever a connected backend has
received an asynchronous notification. However, the communication from
the backend to the frontend is not asynchronous. The \*(LI application
must poll the backend to see if there is any pending notification
information. After the execution of a query, a frontend may call
.IR PGdatabase::notifies
to see if any notification data is currently available from the backend.
.TP 15n
.BR PGdatabase::notifies
returns the notification from a list of unhandled notifications from the
backend. Returns NULL if there is no pending notifications from the
backend.
.IR PGdatabase::notifies
behaves like the popping of a stack. Once a notification is returned
from
.IR PGdatabase::notifies,
it is considered handled and will be removed from the list of
notifications.
.(C
PGnotify* PGdatabase::notifies()
.)C
.PP
The second sample program gives an example of the use of asynchronous
notification.
.XA 1 "Functions Associated with the COPY Command"
.SH "FUNCTIONS ASSOCIATED WITH THE COPY COMMAND"
The
.IR copy
command in \*(PG has options to read from or write to the network
connection used by \*(LI. Therefore, functions are necessary to
access this network connection directly so applications may take full
advantage of this capability.
.TP 15n
.BR PGdatabase::getline
Reads a newline-terminated line of characters (transmitted by the
backend server) into a buffer
.IR string
of size
.IR length .
Like
.IR fgets (3),
this routine copies up to
.IR length "-1"
characters into
.IR string .
It is like
.IR gets (3),
however, in that it converts the terminating newline into a null
character.
.IP
.IR PGdatabase::getline
returns EOF at EOF, 0 if the entire line has been read, and 1 if the
buffer is full but the terminating newline has not yet been read.
.IP
Notice that the application must check to see if a new line consists
of the single character \*(lq.\*(rq, which indicates that the backend
server has finished sending the results of the
.IR copy
command. Therefore, if the application ever expects to receive lines
that are more than
.IR length "-1"
characters long, the application must be sure to check the return
value of
.IR PGdatabase::getline
very carefully.
.IP
.(C
int PGdatabase::getline(char* string, int length)
.)C
.TP 15n
.BR PGdatabase::putline
Sends a null-terminated
.IR string
to the backend server.
.IP
The application must explicitly send the single character \*(lq.\*(rq
to indicate to the backend that it has finished sending its data.
.(C
void PGdatabase::putline(char* string)
.)C
.TP 15n
.BR PGdatabase::endcopy
Syncs with the backend. This function waits until the backend has
finished processing the copy. It should either be issued when the
last string has been sent to the backend using
.IR PGdatabase::putline
or when the last string has been received from the backend using
.IR PGdatabase::getline .
It must be issued or the backend may get \*(lqout of sync\*(rq with
the frontend. Upon return from this function, the backend is ready to
receive the next query.
.IP
The return value is 0 on successful completion, nonzero otherwise.
.(C
int PGdatabase::endcopy()
.)C
As an example:
.(C
PGdatabase data;
data.exec("create table foo (a int4, b char16, d float8)");
data.exec("copy foo from stdin");
data.putline("3\etHello World\et4.5\en");
data.putline("4\etGoodbye World\et7.11\en");
\&...
data.putline(".\en");
data.endcopy();
.)C
.SH BUGS
The query buffer is 8192 bytes long, and queries over that length will
be silently truncated.
.bp
The PGlobj class is largely untested. Use with caution.

View File

@ -0,0 +1,94 @@
/*-------------------------------------------------------------------------
*
* FILE
* pgconnection.cc
*
* DESCRIPTION
* implementation of the PGconnection class.
* PGconnection encapsulates a frontend to backend connection
*
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgconnection.cc,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "libpq++.H"
// default constructor
// checks environment variable for database name
PGconnection::PGconnection()
{
char* name;
PGenv* newenv;
conn = NULL;
result = NULL;
errorMessage[0] = '\0';
newenv = new PGenv(); // use reasonable defaults for the environment
if (!(name = getenv(ENV_DEFAULT_DBASE)))
return;
connect(newenv, name);
}
// constructor -- for given environment and database name
PGconnection::PGconnection(PGenv* env, char* dbName)
{
conn = NULL;
result = NULL;
errorMessage[0] = '\0';
connect(env, dbName);
}
// destructor - closes down the connection and cleanup
PGconnection::~PGconnection()
{
if (result) PQclear(result);
if (conn) PQfinish(conn);
}
// PGconnection::connect
// establish a connection to a backend
ConnStatusType
PGconnection::connect(PGenv* newenv, char* dbName)
{
#if 0
FILE *debug;
debug = fopen("/tmp/trace.out","w");
PQtrace(conn, debug);
#endif
env = newenv;
fe_setauthsvc(env->pgauth, errorMessage);
conn = PQsetdb(env->pghost, env->pgport, env->pgoption, env->pgtty, dbName);
if(strlen(errorMessage))
return CONNECTION_BAD;
else
return status();
}
// PGconnection::status -- return connection or result status
ConnStatusType
PGconnection::status()
{
return PQstatus(conn);
}
// PGconnection::exec -- send a query to the backend
ExecStatusType
PGconnection::exec(char* query)
{
if (result)
PQclear(result);
result = PQexec(conn, query);
if (result)
return PQresultStatus(result);
else {
strcpy(errorMessage, PQerrorMessage(conn));
return PGRES_FATAL_ERROR;
}
}

View File

@ -0,0 +1,109 @@
/*-------------------------------------------------------------------------
*
* FILE
* PGenv.cc
*
* DESCRIPTION
* PGenv is the environment for setting up a connection to a
* postgres backend, captures the host, port, tty, options and
* authentication type.
*
* NOTES
* Currently under construction.
*
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgenv.cc,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdlib.h>
#include "libpq++.H"
#define DefaultAuth DEFAULT_CLIENT_AUTHSVC
#define DefaultPort POSTPORT
// default constructor for PGenv
// checks the environment variables
PGenv::PGenv()
{
char* temp;
pgauth = NULL;
pghost = NULL;
pgport = NULL;
pgoption = NULL;
pgtty = NULL;
setValues(getenv(ENV_DEFAULT_AUTH), getenv(ENV_DEFAULT_HOST),
getenv(ENV_DEFAULT_PORT), getenv(ENV_DEFAULT_OPTION),
getenv(ENV_DEFAULT_TTY));
}
// constructor for given environment
PGenv::PGenv(char* auth, char* host, char* port, char* option, char* tty)
{
pgauth = NULL;
pghost = NULL;
pgport = NULL;
pgoption = NULL;
pgtty = NULL;
setValues(auth, host, port, option, tty);
}
// allocate memory and set internal structures to match
// required environment
void
PGenv::setValues(char* auth, char* host, char* port, char* option, char* tty)
{
char* temp;
temp = (auth) ? auth : DefaultAuth;
if (pgauth)
free(pgauth);
pgauth = strdup(temp);
temp = (host) ? host : DefaultHost;
if (pghost)
free(pghost);
pghost = strdup(temp);
temp = (port) ? port : DefaultPort;
if (pgport)
free(pgport);
pgport = strdup(temp);
temp = (option) ? option : DefaultOption;
if (pgoption)
free(pgoption);
pgoption = strdup(temp);
temp = (tty) ? tty : DefaultTty;
if (pgtty)
free(pgtty);
pgtty = strdup(temp);
}
// default destrutor
// frees allocated memory for internal structures
PGenv::~PGenv()
{
if (pgauth)
free(pgauth);
if (pghost)
free(pghost);
if (pgport)
free(pgport);
if (pgoption)
free(pgoption);
if (pgtty)
free(pgtty);
}

View File

@ -0,0 +1,152 @@
/*-------------------------------------------------------------------------
*
* FILE
* pglobject.cc
*
* DESCRIPTION
* implementation of the PGlobj class.
* PGlobj encapsulates a frontend to backend connection
*
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pglobject.cc,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "libpq++.H"
extern "C" {
#include "libpq/libpq-fs.h"
}
// default constructor
// creates a large object in the default database
PGlobj::PGlobj() : PGconnection::PGconnection() {
object = lo_creat(conn, INV_READ|INV_WRITE);
if (object == 0) {
sprintf(errorMessage, "PGlobj: can't create large object");
}
fd = lo_open(conn, object, INV_READ|INV_WRITE);
if (fd < 0) {
sprintf(errorMessage, "PGlobj: can't open large object %d", object);
} else
sprintf(errorMessage, "PGlobj: created and opened large object %d",
object);
}
// constructor
// open an existing large object in the default database
PGlobj::PGlobj(Oid lobjId) : PGconnection::PGconnection() {
object = lobjId;
fd = lo_open(conn, object, INV_READ|INV_WRITE);
if (fd < 0) {
sprintf(errorMessage, "PGlobj: can't open large object %d", object);
} else
sprintf(errorMessage, "PGlobj: opened large object %d",
object);
}
// constructor
// create a large object in the given database
PGlobj::PGlobj(PGenv* env, char* dbName) : PGconnection::PGconnection(env,dbName) {
object = lo_creat(conn, INV_READ|INV_WRITE);
if (object == 0) {
sprintf(errorMessage, "PGlobj: can't create large object");
}
fd = lo_open(conn, object, INV_READ|INV_WRITE);
if (fd < 0) {
sprintf(errorMessage, "PGlobj: can't open large object %d", object);
} else
sprintf(errorMessage, "PGlobj: created and opened large object %d",
object);
}
// constructor
// open an existing large object in the given database
PGlobj::PGlobj(PGenv* env, char* dbName, Oid lobjId) : PGconnection::PGconnection(env,dbName) {
object = lobjId;
fd = lo_open(conn, object, INV_READ|INV_WRITE);
if (fd < 0) {
sprintf(errorMessage, "PGlobj: can't open large object %d", object);
} else
sprintf(errorMessage, "PGlobj: created and opened large object %d",
object);
}
// PGlobj::unlink
// destruct large object and delete from it from the database
int
PGlobj::unlink() {
int temp = lo_unlink(conn, object);
if (temp) {
return temp;
} else {
delete this;
return temp;
}
}
// PGlobj::import -- import a given file into the large object
int
PGlobj::import(char* filename) {
char buf[BUFSIZE];
int nbytes, tmp;
int in_fd;
// open the file to be read in
in_fd = open(filename, O_RDONLY, 0666);
if (in_fd < 0) { /* error */
sprintf(errorMessage, "PGlobj::import: can't open unix file\"%s\"", filename);
return -1;
}
// read in from the Unix file and write to the inversion file
while ((nbytes = ::read(in_fd, buf, BUFSIZE)) > 0) {
tmp = lo_write(conn, fd, buf, nbytes);
if (tmp < nbytes) {
sprintf(errorMessage, "PGlobj::import: error while reading \"%s\"",
filename);
return -1;
}
}
(void) close(in_fd);
return 0;
}
// PGlobj::export -- export large object to given file
int
PGlobj::export(char* filename) {
int out_fd;
char buf[BUFSIZE];
int nbytes, tmp;
// open the file to be written to
out_fd = open(filename, O_CREAT|O_WRONLY, 0666);
if (out_fd < 0) { /* error */
sprintf(errorMessage, "PGlobj::export: can't open unix file\"%s\"",
filename);
return -1;
}
// read in from the Unix file and write to the inversion file
while ((nbytes = lo_read(conn, fd, buf, BUFSIZE)) > 0) {
tmp = ::write(out_fd, buf, nbytes);
if (tmp < nbytes) {
sprintf(errorMessage,"PGlobj::export: error while writing \"%s\"",
filename);
return -1;
}
}
(void) close(out_fd);
return 0;
}
// default destructor -- closes large object
PGlobj::~PGlobj() {
if (fd >= 0)
lo_close(conn, fd);
}

View File

@ -0,0 +1,98 @@
#-------------------------------------------------------------------------
#
# Makefile
# Makefile for libpq library
#
# Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
#
#-------------------------------------------------------------------------
LIB= pq
MKDIR= ../mk
include $(MKDIR)/postgres.mk
CFLAGS+= -I$(srcdir)/backend/include \
-I$(srcdir)/backend \
-I$(CURDIR) \
ifdef KRBVERS
CFLAGS+= $(KRBFLAGS)
endif
# dllist.c is found in backend/lib
VPATH:= $(VPATH):$(srcdir)/backend/lib
LIBSRCS= fe-auth.c fe-connect.c fe-exec.c fe-misc.c fe-lobj.c \
dllist.c pqsignal.c
ifeq ($(PORTNAME), next)
VPATH:=$(VPATH):$(srcdir)/backend/port/$(PORTNAME)
LIBSRCS+= getcwd.c putenv.c
endif
.PHONY: beforeinstall-headers install-headers
ifndef NO_BEFOREINSTL
beforeinstall-headers:
@-if [ ! -d $(HEADERDIR) ]; then mkdir $(HEADERDIR); fi
@-if [ ! -d $(HEADERDIR)/port ]; then mkdir $(HEADERDIR)/port; fi
@-if [ ! -d $(HEADERDIR)/port/$(PORTNAME) ]; \
then mkdir $(HEADERDIR)/port/$(PORTNAME); fi
@-if [ ! -d $(HEADERDIR)/include ]; \
then mkdir $(HEADERDIR)/include; fi
@-if [ ! -d $(HEADERDIR)/lib ]; \
then mkdir $(HEADERDIR)/lib; fi
@-if [ ! -d $(HEADERDIR)/libpq ]; \
then mkdir $(HEADERDIR)/libpq; fi
@-if [ ! -d $(HEADERDIR)/utils ]; \
then mkdir $(HEADERDIR)/utils; fi
else
beforeinstall-headers: .dosomething
endif
HEADERFILES = include/postgres.h \
libpq/pqcomm.h \
libpq/libpq-fs.h \
lib/dllist.h \
utils/geo-decls.h
ifeq ($(PORTNAME), hpux)
HEADERFILES += port/hpux/fixade.h
endif
TEMPDIR=/tmp
install-headers: beforeinstall-headers
@for i in ${HEADERFILES}; do \
echo "Installing $(HEADERDIR)/$$i."; \
$(INSTALL) $(INSTLOPTS) $(srcdir)/backend/$$i $(HEADERDIR)/$$i; \
done
$(INSTALL) $(INSTLOPTS) libpq-fe.h $(HEADERDIR)/libpq-fe.h
@mv -f $(HEADERDIR)/include/* $(HEADERDIR)
@rmdir $(HEADERDIR)/include
# XXX - installing fmgr.h depends on the backend being built
$(INSTALL) $(INSTLOPTS) $(srcdir)/backend/$(objdir)/fmgr.h $(HEADERDIR)/fmgr.h
@rm -f $(TEMPDIR)/c.h
@echo "#undef PORTNAME" > $(TEMPDIR)/c.h
@echo "#define PORTNAME $(PORTNAME)" >> $(TEMPDIR)/c.h
@echo "#undef PORTNAME_$(PORTNAME)" >> $(TEMPDIR)/c.h
@echo "#define PORTNAME_$(PORTNAME)" >> $(TEMPDIR)/c.h
@cat $(srcdir)/backend/include/c.h >> $(TEMPDIR)/c.h
$(INSTALL) $(INSTLOPTS) $(TEMPDIR)/c.h $(HEADERDIR)/c.h
@rm -f $(TEMPDIR)/postgres.h
# hardwire NAMEDATALEN and OIDNAMELEN into the postgres.h for this installation
@echo "#define NAMEDATALEN $(NAMEDATALEN)" >> $(TEMPDIR)/postgres.h
@echo "#define OIDNAMELEN $(OIDNAMELEN)" >> $(TEMPDIR)/postgres.h
@cat $(srcdir)/backend/include/postgres.h >> $(TEMPDIR)/postgres.h
$(INSTALL) $(INSTLOPTS) $(TEMPDIR)/postgres.h $(HEADERDIR)/postgres.h
install:: install-headers
include $(MKDIR)/postgres.lib.mk

View File

@ -0,0 +1 @@
This directory contains the C version of Libpq, the POSTGRES frontend library.

View File

@ -0,0 +1,544 @@
/*-------------------------------------------------------------------------
*
* fe-auth.c--
* The front-end (client) authorization routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.1.1.1 1996/07/09 06:22:17 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* frontend (client) routines:
* fe_sendauth send authentication information
* fe_getauthname get user's name according to the client side
* of the authentication system
* fe_setauthsvc set frontend authentication service
* fe_getauthsvc get current frontend authentication service
*
*
*
*/
#include <stdio.h>
#include <string.h>
#include <sys/param.h> /* for MAX{HOSTNAME,PATH}LEN, NOFILE */
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include "libpq/pqcomm.h"
#include "libpq-fe.h"
#include "fe-auth.h"
/*----------------------------------------------------------------
* common definitions for generic fe/be routines
*----------------------------------------------------------------
*/
struct authsvc {
char name[16]; /* service nickname (for command line) */
MsgType msgtype; /* startup packet header type */
int allowed; /* initially allowed (before command line
* option parsing)?
*/
};
/*
* Command-line parsing routines use this structure to map nicknames
* onto service types (and the startup packets to use with them).
*
* Programs receiving an authentication request use this structure to
* decide which authentication service types are currently permitted.
* By default, all authentication systems compiled into the system are
* allowed. Unauthenticated connections are disallowed unless there
* isn't any authentication system.
*/
static struct authsvc authsvcs[] = {
#ifdef KRB4
{ "krb4", STARTUP_KRB4_MSG, 1 },
{ "kerberos", STARTUP_KRB4_MSG, 1 },
#endif /* KRB4 */
#ifdef KRB5
{ "krb5", STARTUP_KRB5_MSG, 1 },
{ "kerberos", STARTUP_KRB5_MSG, 1 },
#endif /* KRB5 */
{ UNAUTHNAME, STARTUP_MSG,
#if defined(KRB4) || defined(KRB5)
0
#else /* !(KRB4 || KRB5) */
1
#endif /* !(KRB4 || KRB5) */
}
};
static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
#ifdef KRB4
/*----------------------------------------------------------------
* MIT Kerberos authentication system - protocol version 4
*----------------------------------------------------------------
*/
#include "krb.h"
/* for some reason, this is not defined in krb.h ... */
extern char *tkt_string(void);
/*
* pg_krb4_init -- initialization performed before any Kerberos calls are made
*
* For v4, all we need to do is make sure the library routines get the right
* ticket file if we want them to see a special one. (They will open the file
* themselves.)
*/
static void pg_krb4_init()
{
char *realm;
static init_done = 0;
if (init_done)
return;
init_done = 1;
/*
* If the user set PGREALM, then we use a ticket file with a special
* name: <usual-ticket-file-name>@<PGREALM-value>
*/
if (realm = getenv("PGREALM")) {
char tktbuf[MAXPATHLEN];
(void) sprintf(tktbuf, "%s@%s", tkt_string(), realm);
krb_set_tkt_string(tktbuf);
}
}
/*
* pg_krb4_authname -- returns a pointer to static space containing whatever
* name the user has authenticated to the system
*
* We obtain this information by digging around in the ticket file.
*/
static char *
pg_krb4_authname(char* PQerrormsg)
{
char instance[INST_SZ];
char realm[REALM_SZ];
int status;
static char name[SNAME_SZ+1] = "";
if (name[0])
return(name);
pg_krb4_init();
name[SNAME_SZ] = '\0';
status = krb_get_tf_fullname(tkt_string(), name, instance, realm);
if (status != KSUCCESS) {
(void) sprintf(PQerrormsg,
"pg_krb4_authname: krb_get_tf_fullname: %s\n",
krb_err_txt[status]);
return((char *) NULL);
}
return(name);
}
/*
* pg_krb4_sendauth -- client routine to send authentication information to
* the server
*
* This routine does not do mutual authentication, nor does it return enough
* information to do encrypted connections. But then, if we want to do
* encrypted connections, we'll have to redesign the whole RPC mechanism
* anyway.
*
* If the user is too lazy to feed us a hostname, we try to come up with
* something other than "localhost" since the hostname is used as an
* instance and instance names in v4 databases are usually actual hostnames
* (canonicalized to omit all domain suffixes).
*/
static int
pg_krb4_sendauth(char* PQerrormsg, int sock,
struct sockaddr_in *laddr,
struct sockaddr_in *raddr,
char *hostname)
{
long krbopts = 0; /* one-way authentication */
KTEXT_ST clttkt;
int status;
char hostbuf[MAXHOSTNAMELEN];
char *realm = getenv("PGREALM"); /* NULL == current realm */
if (!hostname || !(*hostname)) {
if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
strcpy(hostbuf, "localhost");
hostname = hostbuf;
}
pg_krb4_init();
status = krb_sendauth(krbopts,
sock,
&clttkt,
PG_KRB_SRVNAM,
hostname,
realm,
(u_long) 0,
(MSG_DAT *) NULL,
(CREDENTIALS *) NULL,
(Key_schedule *) NULL,
laddr,
raddr,
PG_KRB4_VERSION);
if (status != KSUCCESS) {
(void) sprintf(PQerrormsg,
"pg_krb4_sendauth: kerberos error: %s\n",
krb_err_txt[status]);
return(STATUS_ERROR);
}
return(STATUS_OK);
}
#endif /* KRB4 */
#ifdef KRB5
/*----------------------------------------------------------------
* MIT Kerberos authentication system - protocol version 5
*----------------------------------------------------------------
*/
#include "krb5/krb5.h"
/*
* pg_an_to_ln -- return the local name corresponding to an authentication
* name
*
* XXX Assumes that the first aname component is the user name. This is NOT
* necessarily so, since an aname can actually be something out of your
* worst X.400 nightmare, like
* ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
* Note that the MIT an_to_ln code does the same thing if you don't
* provide an aname mapping database...it may be a better idea to use
* krb5_an_to_ln, except that it punts if multiple components are found,
* and we can't afford to punt.
*/
static char *
pg_an_to_ln(char *aname)
{
char *p;
if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
*p = '\0';
return(aname);
}
/*
* pg_krb5_init -- initialization performed before any Kerberos calls are made
*
* With v5, we can no longer set the ticket (credential cache) file name;
* we now have to provide a file handle for the open (well, "resolved")
* ticket file everywhere.
*
*/
static int
krb5_ccache pg_krb5_init()
{
krb5_error_code code;
char *realm, *defname;
char tktbuf[MAXPATHLEN];
static krb5_ccache ccache = (krb5_ccache) NULL;
if (ccache)
return(ccache);
/*
* If the user set PGREALM, then we use a ticket file with a special
* name: <usual-ticket-file-name>@<PGREALM-value>
*/
if (!(defname = krb5_cc_default_name())) {
(void) sprintf(PQerrormsg,
"pg_krb5_init: krb5_cc_default_name failed\n");
return((krb5_ccache) NULL);
}
(void) strcpy(tktbuf, defname);
if (realm = getenv("PGREALM")) {
(void) strcat(tktbuf, "@");
(void) strcat(tktbuf, realm);
}
if (code = krb5_cc_resolve(tktbuf, &ccache)) {
(void) sprintf(PQerrormsg,
"pg_krb5_init: Kerberos error %d in krb5_cc_resolve\n",
code);
com_err("pg_krb5_init", code, "in krb5_cc_resolve");
return((krb5_ccache) NULL);
}
return(ccache);
}
/*
* pg_krb5_authname -- returns a pointer to static space containing whatever
* name the user has authenticated to the system
*
* We obtain this information by digging around in the ticket file.
*/
static char *
pg_krb5_authname(char* PQerrormsg)
{
krb5_ccache ccache;
krb5_principal principal;
krb5_error_code code;
static char *authname = (char *) NULL;
if (authname)
return(authname);
ccache = pg_krb5_init(); /* don't free this */
if (code = krb5_cc_get_principal(ccache, &principal)) {
(void) sprintf(PQerrormsg,
"pg_krb5_authname: Kerberos error %d in krb5_cc_get_principal\n",
code);
com_err("pg_krb5_authname", code, "in krb5_cc_get_principal");
return((char *) NULL);
}
if (code = krb5_unparse_name(principal, &authname)) {
(void) sprintf(PQerrormsg,
"pg_krb5_authname: Kerberos error %d in krb5_unparse_name\n",
code);
com_err("pg_krb5_authname", code, "in krb5_unparse_name");
krb5_free_principal(principal);
return((char *) NULL);
}
krb5_free_principal(principal);
return(pg_an_to_ln(authname));
}
/*
* pg_krb5_sendauth -- client routine to send authentication information to
* the server
*
* This routine does not do mutual authentication, nor does it return enough
* information to do encrypted connections. But then, if we want to do
* encrypted connections, we'll have to redesign the whole RPC mechanism
* anyway.
*
* Server hostnames are canonicalized v4-style, i.e., all domain suffixes
* are simply chopped off. Hence, we are assuming that you've entered your
* server instances as
* <value-of-PG_KRB_SRVNAM>/<canonicalized-hostname>
* in the PGREALM (or local) database. This is probably a bad assumption.
*/
static int
pg_krb5_sendauth(char* PQerrormsg,int sock,
struct sockaddr_in *laddr,
struct sockaddr_in *raddr,
char *hostname)
{
char servbuf[MAXHOSTNAMELEN + 1 +
sizeof(PG_KRB_SRVNAM)];
char *hostp;
char *realm;
krb5_error_code code;
krb5_principal client, server;
krb5_ccache ccache;
krb5_error *error = (krb5_error *) NULL;
ccache = pg_krb5_init(); /* don't free this */
/*
* set up client -- this is easy, we can get it out of the ticket
* file.
*/
if (code = krb5_cc_get_principal(ccache, &client)) {
(void) sprintf(PQerrormsg,
"pg_krb5_sendauth: Kerberos error %d in krb5_cc_get_principal\n",
code);
com_err("pg_krb5_sendauth", code, "in krb5_cc_get_principal");
return(STATUS_ERROR);
}
/*
* set up server -- canonicalize as described above
*/
(void) strcpy(servbuf, PG_KRB_SRVNAM);
*(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
if (hostname || *hostname) {
(void) strncpy(++hostp, hostname, MAXHOSTNAMELEN);
} else {
if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
(void) strcpy(hostp, "localhost");
}
if (hostp = strchr(hostp, '.'))
*hostp = '\0';
if (realm = getenv("PGREALM")) {
(void) strcat(servbuf, "@");
(void) strcat(servbuf, realm);
}
if (code = krb5_parse_name(servbuf, &server)) {
(void) sprintf(PQerrormsg,
"pg_krb5_sendauth: Kerberos error %d in krb5_parse_name\n",
code);
com_err("pg_krb5_sendauth", code, "in krb5_parse_name");
krb5_free_principal(client);
return(STATUS_ERROR);
}
/*
* The only thing we want back from krb5_sendauth is an error status
* and any error messages.
*/
if (code = krb5_sendauth((krb5_pointer) &sock,
PG_KRB5_VERSION,
client,
server,
(krb5_flags) 0,
(krb5_checksum *) NULL,
(krb5_creds *) NULL,
ccache,
(krb5_int32 *) NULL,
(krb5_keyblock **) NULL,
&error,
(krb5_ap_rep_enc_part **) NULL)) {
if ((code == KRB5_SENDAUTH_REJECTED) && error) {
(void) sprintf(PQerrormsg,
"pg_krb5_sendauth: authentication rejected: \"%*s\"\n",
error->text.length, error->text.data);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
} else {
(void) sprintf(PQerrormsg,
"pg_krb5_sendauth: Kerberos error %d in krb5_sendauth\n",
code);
com_err("pg_krb5_sendauth", code, "in krb5_sendauth");
}
}
krb5_free_principal(client);
krb5_free_principal(server);
return(code ? STATUS_ERROR : STATUS_OK);
}
#endif /* KRB5 */
/*
* fe_sendauth -- client demux routine for outgoing authentication information
*/
int
fe_sendauth(MsgType msgtype, Port *port, char *hostname, char* PQerrormsg)
{
switch (msgtype) {
#ifdef KRB4
case STARTUP_KRB4_MSG:
if (pg_krb4_sendauth(PQerrormsg, port->sock, &port->laddr,
&port->raddr,
hostname) != STATUS_OK) {
(void) sprintf(PQerrormsg,
"fe_sendauth: krb4 authentication failed\n");
/* fputs(PQerrormsg, stderr); */
return(STATUS_ERROR);
}
break;
#endif
#ifdef KRB5
case STARTUP_KRB5_MSG:
if (pg_krb5_sendauth(PQerrormsg,port->sock, &port->laddr,
&port->raddr,
hostname) != STATUS_OK) {
(void) sprintf(PQerrormsg,
"fe_sendauth: krb5 authentication failed\n");
return(STATUS_ERROR);
}
break;
#endif
case STARTUP_MSG:
break;
default:
break;
}
return(STATUS_OK);
}
/*
* fe_setauthsvc
* fe_getauthsvc
*
* Set/return the authentication service currently selected for use by the
* frontend. (You can only use one in the frontend, obviously.)
*/
static pg_authsvc = -1;
void
fe_setauthsvc(char *name, char* PQerrormsg)
{
int i;
for (i = 0; i < n_authsvcs; ++i)
if (!strcmp(name, authsvcs[i].name)) {
pg_authsvc = i;
break;
}
if (i == n_authsvcs) {
(void) sprintf(PQerrormsg,
"fe_setauthsvc: invalid name: %s, ignoring...\n",
name);
}
return;
}
MsgType
fe_getauthsvc(char* PQerrormsg)
{
if (pg_authsvc < 0 || pg_authsvc >= n_authsvcs)
fe_setauthsvc(DEFAULT_CLIENT_AUTHSVC,PQerrormsg);
return(authsvcs[pg_authsvc].msgtype);
}
/*
* fe_getauthname -- returns a pointer to static space containing whatever
* name the user has authenticated to the system
* if there is an error, return the error message in PQerrormsg
*/
char*
fe_getauthname(char* PQerrormsg)
{
char *name = (char *) NULL;
MsgType authsvc;
authsvc = fe_getauthsvc(PQerrormsg);
switch ((int) authsvc) {
#ifdef KRB4
case STARTUP_KRB4_MSG:
name = pg_krb4_authname(PQerrormsg);
break;
#endif
#ifdef KRB5
case STARTUP_KRB5_MSG:
name = pg_krb5_authname(PQerrormsg);
break;
#endif
case STARTUP_MSG:
{
struct passwd *pw = getpwuid(getuid());
if (pw &&
pw->pw_name &&
(name = (char *) malloc(strlen(pw->pw_name) + 1))) {
(void) strcpy(name, pw->pw_name);
}
}
break;
default:
(void) sprintf(PQerrormsg,
"fe_getauthname: invalid authentication system: %d\n",
authsvc);
break;
}
return(name);
}

View File

@ -0,0 +1,38 @@
/*-------------------------------------------------------------------------
*
* fe-auth.h
*
* Definitions for network authentication routines
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: fe-auth.h,v 1.1.1.1 1996/07/09 06:22:17 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef FE_AUTH_H
#define FE_AUTH_H
/*----------------------------------------------------------------
* Common routines and definitions
*----------------------------------------------------------------
*/
/* what we call "no authentication system" */
#define UNAUTHNAME "unauth"
/* what a frontend uses by default */
#if !defined(KRB4) && !defined(KRB5)
#define DEFAULT_CLIENT_AUTHSVC UNAUTHNAME
#else /* KRB4 || KRB5 */
#define DEFAULT_CLIENT_AUTHSVC "kerberos"
#endif /* KRB4 || KRB5 */
extern int fe_sendauth(MsgType msgtype, Port *port, char *hostname, char* PQerromsg);
extern void fe_setauthsvc(char *name, char* PQerrormsg);
#define PG_KRB4_VERSION "PGVER4.1" /* at most KRB_SENDAUTH_VLEN chars */
#define PG_KRB5_VERSION "PGVER5.1"
#endif /* FE_AUTH_H */

View File

@ -0,0 +1,460 @@
/*-------------------------------------------------------------------------
*
* fe-connect.c--
* functions related to setting up a connection to the backend
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.1.1.1 1996/07/09 06:22:17 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include "libpq/pqcomm.h" /* for decls of MsgType, PacketBuf, StartupInfo */
#include "fe-auth.h"
#include "libpq-fe.h"
#if defined(PORTNAME_ultrix4) || defined(PORTNAME_next)
/* ultrix is lame and doesn't have strdup in libc for some reason */
/* [TRH] So doesn't NEXTSTEP. But whaddaya expect for a non-ANSI
standard function? (My, my. Touchy today, are we?) */
static
char *
strdup(char *string)
{
char *nstr;
nstr = strcpy((char *)malloc(strlen(string)+1), string);
return nstr;
}
#endif
/* use a local version instead of the one found in pqpacket.c */
static ConnStatusType connectDB(PGconn *conn);
static int packetSend(Port *port, PacketBuf *buf, PacketLen len,
bool nonBlocking);
static void startup2PacketBuf(StartupInfo* s, PacketBuf* res);
static void freePGconn(PGconn *conn);
static void closePGconn(PGconn *conn);
#define NOTIFYLIST_INITIAL_SIZE 10
#define NOTIFYLIST_GROWBY 10
/* ----------------
* PQsetdb
*
* establishes a connectin to a postgres backend through the postmaster
* at the specified host and port.
*
* returns a PGconn* which is needed for all subsequent libpq calls
* if the status field of the connection returned is CONNECTION_BAD,
* then some fields may be null'ed out instead of having valid values
* ----------------
*/
PGconn*
PQsetdb(char *pghost, char* pgport, char* pgoptions, char* pgtty, char* dbName)
{
PGconn *conn;
char *tmp;
conn = (PGconn*)malloc(sizeof(PGconn));
conn->Pfout = NULL;
conn->Pfin = NULL;
conn->Pfdebug = NULL;
conn->port = NULL;
conn->notifyList = DLNewList();
if (!pghost || pghost[0] == '\0') {
if (!(tmp = getenv("PGHOST"))) {
tmp = DefaultHost;
}
conn->pghost = strdup(tmp);
} else
conn->pghost = strdup(pghost);
if (!pgport || pgport == '\0') {
if (!(tmp = getenv("PGPORT"))) {
tmp = POSTPORT;
}
conn->pgport = strdup(tmp);
} else
conn->pgport = strdup(pgport);
if (!pgtty || pgtty == '\0') {
if (!(tmp = getenv("PGTTY"))) {
tmp = DefaultTty;
}
conn->pgtty = strdup(tmp);
} else
conn->pgtty = strdup(pgtty);
if (!pgoptions || pgoptions == '\0') {
if (!(tmp = getenv("PGOPTIONS"))) {
tmp = DefaultOption;
}
conn->pgoptions = strdup(tmp);
} else
conn->pgoptions = strdup(pgoptions);
if (!dbName || dbName[0] == '\0') {
char errorMessage[ERROR_MSG_LENGTH];
if (!(tmp = getenv("PGDATABASE")) &&
!(tmp = fe_getauthname(errorMessage))) {
sprintf(conn->errorMessage,
"FATAL: PQsetdb: Unable to determine a database name!\n");
/* pqdebug("%s", conn->errorMessage); */
conn->dbName = NULL;
return conn;
}
conn->dbName = strdup(tmp);
} else
conn->dbName = strdup(dbName);
conn->status = connectDB(conn);
return conn;
}
/*
* connectDB -
* make a connection to the database, returns 1 if successful or 0 if not
*
*/
static ConnStatusType
connectDB(PGconn *conn)
{
struct hostent *hp;
StartupInfo startup;
PacketBuf pacBuf;
int status;
MsgType msgtype;
int laddrlen = sizeof(struct sockaddr);
Port *port = conn->port;
int portno;
PGresult *res;
char *user;
/*
//
// Initialize the startup packet.
//
// This data structure is used for the seq-packet protocol. It
// describes the frontend-backend connection.
//
//
*/
user = fe_getauthname(conn->errorMessage);
if (!user)
goto connect_errReturn;
strncpy(startup.database,conn->dbName,sizeof(startup.database));
strncpy(startup.user,user,sizeof(startup.user));
strncpy(startup.tty,conn->pgtty,sizeof(startup.tty));
if (conn->pgoptions) {
strncpy(startup.options,conn->pgoptions, sizeof(startup.options));
}
else
startup.options[0]='\0';
startup.execFile[0]='\0'; /* not used */
/*
//
// Open a connection to postmaster/backend.
//
*/
port = (Port *) malloc(sizeof(Port));
memset((char *) port, 0, sizeof(Port));
if (!(hp = gethostbyname(conn->pghost)) || hp->h_addrtype != AF_INET) {
(void) sprintf(conn->errorMessage,
"connectDB() -- unknown hostname: %s\n",
conn->pghost);
goto connect_errReturn;
}
memset((char *) &port->raddr, 0, sizeof(port->raddr));
memmove((char *) &(port->raddr.sin_addr),
(char *) hp->h_addr,
hp->h_length);
port->raddr.sin_family = AF_INET;
portno = atoi(conn->pgport);
port->raddr.sin_port = htons((unsigned short)(portno));
/* connect to the server */
if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
(void) sprintf(conn->errorMessage,
"connectDB() -- socket() failed: errno=%d\n%s\n",
errno, strerror(errno));
goto connect_errReturn;
}
if (connect(port->sock, (struct sockaddr *)&port->raddr,
sizeof(port->raddr)) < 0) {
(void) sprintf(conn->errorMessage,
"connectDB() failed: Is the postmaster running at '%s' on port '%s'?\n",
conn->pghost,conn->pgport);
goto connect_errReturn;
}
/* fill in the client address */
if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
&laddrlen) < 0) {
(void) sprintf(conn->errorMessage,
"connectDB() -- getsockname() failed: errno=%d\n%s\n",
errno, strerror(errno));
goto connect_errReturn;
}
/* by this point, connection has been opened */
msgtype = fe_getauthsvc(conn->errorMessage);
/* pacBuf = startup2PacketBuf(&startup);*/
startup2PacketBuf(&startup, &pacBuf);
pacBuf.msgtype = htonl(msgtype);
status = packetSend(port, &pacBuf, sizeof(PacketBuf), BLOCKING);
if (status == STATUS_ERROR)
{
sprintf(conn->errorMessage,
"connectDB() -- couldn't send complete packet: errno=%d\n%s\n", errno,strerror(errno));
goto connect_errReturn;
}
/* authenticate as required*/
if (fe_sendauth(msgtype, port, conn->pghost,
conn->errorMessage) != STATUS_OK) {
(void) sprintf(conn->errorMessage,
"connectDB() -- authentication failed with %s\n",
conn->pghost);
goto connect_errReturn;
}
/* set up the socket file descriptors */
conn->Pfout = fdopen(port->sock, "w");
conn->Pfin = fdopen(dup(port->sock), "r");
if (!conn->Pfout || !conn->Pfin) {
(void) sprintf(conn->errorMessage,
"connectDB() -- fdopen() failed: errno=%d\n%s\n",
errno, strerror(errno));
goto connect_errReturn;
}
conn->port = port;
/* we have a connection now,
send a blank query down to make sure the database exists*/
res = PQexec(conn," ");
if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY) {
/* error will already be in conn->errorMessage */
goto connect_errReturn;
}
free(res);
return CONNECTION_OK;
connect_errReturn:
return CONNECTION_BAD;
}
/*
* freePGconn
* - free the PGconn data structure
*
*/
static void
freePGconn(PGconn *conn)
{
if (conn->pghost) free(conn->pghost);
if (conn->pgtty) free(conn->pgtty);
if (conn->pgoptions) free(conn->pgoptions);
if (conn->pgport) free(conn->pgport);
if (conn->dbName) free(conn->dbName);
if (conn->notifyList) DLFreeList(conn->notifyList);
free(conn);
}
/*
closePGconn
- properly close a connection to the backend
*/
static void
closePGconn(PGconn *conn)
{
fputs("X\0", conn->Pfout);
fflush(conn->Pfout);
if (conn->Pfout) fclose(conn->Pfout);
if (conn->Pfin) fclose(conn->Pfin);
if (conn->Pfdebug) fclose(conn->Pfdebug);
}
/*
PQfinish:
properly close a connection to the backend
also frees the PGconn data structure so it shouldn't be re-used
after this
*/
void
PQfinish(PGconn *conn)
{
if (conn->status == CONNECTION_OK)
closePGconn(conn);
freePGconn(conn);
}
/* PQreset :
resets the connection to the backend
closes the existing connection and makes a new one
*/
void
PQreset(PGconn *conn)
{
closePGconn(conn);
conn->status = connectDB(conn);
}
/*
* PacketSend()
*
this is just like PacketSend(), defined in backend/libpq/pqpacket.c
but we define it here to avoid linking in all of libpq.a
* packetSend -- send a single-packet message.
*
* RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
* SIDE_EFFECTS: may block.
* NOTES: Non-blocking writes would significantly complicate
* buffer management. For now, we're not going to do it.
*
*/
static int
packetSend(Port *port,
PacketBuf *buf,
PacketLen len,
bool nonBlocking)
{
PacketLen totalLen;
int addrLen = sizeof(struct sockaddr_in);
totalLen = len;
len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
(struct sockaddr *)&(port->raddr), addrLen);
if (len < totalLen) {
return(STATUS_ERROR);
}
return(STATUS_OK);
}
/*
* startup2PacketBuf()
*
* this is just like StartupInfo2Packet(), defined in backend/libpq/pqpacket.c
* but we repeat it here so we don't have to link in libpq.a
*
* converts a StartupInfo structure to a PacketBuf
*/
static void
startup2PacketBuf(StartupInfo* s, PacketBuf* res)
{
char* tmp;
/* res = (PacketBuf*)malloc(sizeof(PacketBuf)); */
res->len = htonl(sizeof(PacketBuf));
/* use \n to delimit the strings */
res->data[0] = '\0';
tmp= res->data;
strncpy(tmp, s->database, sizeof(s->database));
tmp += sizeof(s->database);
strncpy(tmp, s->user, sizeof(s->user));
tmp += sizeof(s->user);
strncpy(tmp, s->options, sizeof(s->options));
tmp += sizeof(s->options);
strncpy(tmp, s->execFile, sizeof(s->execFile));
tmp += sizeof(s->execFile);
strncpy(tmp, s->tty, sizeof(s->execFile));
}
/* =========== accessor functions for PGconn ========= */
char*
PQdb(PGconn* conn)
{
return conn->dbName;
}
char*
PQhost(PGconn* conn)
{
return conn->pghost;
}
char*
PQoptions(PGconn* conn)
{
return conn->pgoptions;
}
char*
PQtty(PGconn* conn)
{
return conn->pgtty;
}
char*
PQport(PGconn* conn)
{
return conn->pgport;
}
ConnStatusType
PQstatus(PGconn* conn)
{
return conn->status;
}
char*
PQerrorMessage(PGconn* conn)
{
return conn->errorMessage;
}
void
PQtrace(PGconn *conn, FILE* debug_port)
{
if (conn == NULL ||
conn->status == CONNECTION_BAD) {
return;
}
PQuntrace(conn);
conn->Pfdebug = debug_port;
}
void
PQuntrace(PGconn *conn)
{
if (conn == NULL ||
conn->status == CONNECTION_BAD) {
return;
}
if (conn->Pfdebug) {
fflush(conn->Pfdebug);
fclose(conn->Pfdebug);
conn->Pfdebug = NULL;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,381 @@
/*-------------------------------------------------------------------------
*
* fe-lobj.c--
* Front-end large object interface
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.1.1.1 1996/07/09 06:22:17 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "postgres.h"
#include "libpq-fe.h"
#include "obj/fmgr.h"
#include "libpq/libpq-fs.h"
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
#define LO_BUFSIZE 1024
/*
* lo_open
* opens an existing large object
*
* returns the file descriptor for use in later lo_* calls
* return -1 upon failure.
*/
int
lo_open(PGconn* conn, Oid lobjId, int mode)
{
int fd;
int result_len;
PQArgBlock argv[2];
PGresult *res;
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = lobjId;
argv[1].isint = 1;
argv[1].len = 4;
argv[1].u.integer = mode;
res = PQfn(conn, F_LO_OPEN,&fd,&result_len,1,argv,2);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
/* have to do this to reset offset in shared fd cache */
/* but only if fd is valid */
if (fd >= 0 && lo_lseek(conn, fd, 0L, SEEK_SET) < 0)
return -1;
return fd;
} else
return -1;
}
/*
* lo_close
* closes an existing large object
*
* returns 0 upon success
* returns -1 upon failure.
*/
int
lo_close(PGconn *conn, int fd)
{
PQArgBlock argv[1];
PGresult *res;
int retval;
int result_len;
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = fd;
res = PQfn(conn, F_LO_CLOSE,&retval,&result_len,1,argv,1);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
return retval;
} else
return -1;
}
/*
* lo_read
* read len bytes of the large object into buf
*
* returns the length of bytes read.
* the CALLER must have allocated enough space to hold the result returned
*/
int
lo_read(PGconn *conn, int fd, char *buf, int len)
{
PQArgBlock argv[2];
PGresult *res;
int result_len;
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = fd;
argv[1].isint = 1;
argv[1].len = 4;
argv[1].u.integer = len;
res = PQfn(conn, F_LOREAD,(int*)buf,&result_len,0,argv,2);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
return result_len;
} else
return -1;
}
/*
* lo_write
* write len bytes of buf into the large object fd
*
*/
int
lo_write(PGconn *conn, int fd, char *buf, int len)
{
PQArgBlock argv[2];
PGresult *res;
int result_len;
int retval;
if (len <= 0)
return 0;
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = fd;
argv[1].isint = 0;
argv[1].len = len;
argv[1].u.ptr = (int*)buf;
res = PQfn(conn, F_LOWRITE,&retval,&result_len,1,argv,2);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
return retval;
} else
return -1;
}
/*
* lo_lseek
* change the current read or write location on a large object
* currently, only L_SET is a legal value for whence
*
*/
int
lo_lseek(PGconn *conn, int fd, int offset, int whence)
{
PQArgBlock argv[3];
PGresult *res;
int retval;
int result_len;
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = fd;
argv[1].isint = 1;
argv[1].len = 4;
argv[1].u.integer = offset;
argv[2].isint = 1;
argv[2].len = 4;
argv[2].u.integer = whence;
res = PQfn(conn, F_LO_LSEEK,&retval,&result_len,1,argv,3);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
return retval;
} else
return -1;
}
/*
* lo_creat
* create a new large object
* the mode is a bitmask describing different attributes of the new object
*
* returns the oid of the large object created or
* InvalidOid upon failure
*/
Oid
lo_creat(PGconn *conn, int mode)
{
PQArgBlock argv[1];
PGresult *res;
int retval;
int result_len;
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = mode;
res = PQfn(conn, F_LO_CREAT,&retval,&result_len,1,argv,1);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
return (Oid)retval;
} else
return InvalidOid;
}
/*
* lo_tell
* returns the current seek location of the large object
*
*/
int
lo_tell(PGconn *conn, int fd)
{
int retval;
PQArgBlock argv[1];
PGresult *res;
int result_len;
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = fd;
res = PQfn(conn, F_LO_TELL,&retval,&result_len,1,argv,1);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
return retval;
} else
return -1;
}
/*
* lo_unlink
* delete a file
*
*/
int
lo_unlink(PGconn *conn, Oid lobjId)
{
PQArgBlock argv[1];
PGresult *res;
int result_len;
int retval;
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = lobjId;
res = PQfn(conn, F_LO_UNLINK,&retval,&result_len,1,argv,1);
if (PQresultStatus(res) == PGRES_COMMAND_OK) {
PQclear(res);
return retval;
} else
return -1;
}
/*
* lo_import -
* imports a file as an (inversion) large object.
* returns the oid of that object upon success,
* returns InvalidOid upon failure
*
*/
Oid
lo_import(PGconn *conn, char* filename)
{
int fd;
int nbytes, tmp;
char buf[LO_BUFSIZE];
Oid lobjOid;
int lobj;
/*
* open the file to be read in
*/
fd = open(filename, O_RDONLY, 0666);
if (fd < 0) { /* error */
sprintf(conn->errorMessage,
"lo_import: can't open unix file\"%s\"\n", filename);
return InvalidOid;
}
/*
* create an inversion "object"
*/
lobjOid = lo_creat(conn, INV_READ|INV_WRITE);
if (lobjOid == InvalidOid) {
sprintf(conn->errorMessage,
"lo_import: can't create inv object for \"%s\"", filename);
return InvalidOid;
}
lobj = lo_open(conn, lobjOid, INV_WRITE);
if (lobj == -1) {
sprintf(conn->errorMessage,
"lo_import: could not open inv object oid %d",lobjOid);
return InvalidOid;
}
/*
* read in from the Unix file and write to the inversion file
*/
while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0) {
tmp = lo_write(conn,lobj, buf, nbytes);
if (tmp < nbytes) {
sprintf(conn->errorMessage,
"lo_import: error while reading \"%s\"",filename);
return InvalidOid;
}
}
(void) close(fd);
(void) lo_close(conn, lobj);
return lobjOid;
}
/*
* lo_export -
* exports an (inversion) large object.
* returns -1 upon failure, 1 otherwise
*/
int
lo_export(PGconn *conn, Oid lobjId, char *filename)
{
int fd;
int nbytes, tmp;
char buf[LO_BUFSIZE];
int lobj;
/*
* create an inversion "object"
*/
lobj = lo_open(conn, lobjId, INV_READ);
if (lobj == -1) {
sprintf(conn->errorMessage,
"lo_export: can't open inv object %d",lobjId);
return -1;
}
/*
* open the file to be written to
*/
fd = open(filename, O_CREAT|O_WRONLY, 0666);
if (fd < 0) { /* error */
sprintf(conn->errorMessage,
"lo_export: can't open unix file\"%s\"",filename);
return 0;
}
/*
* read in from the Unix file and write to the inversion file
*/
while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0) {
tmp = write(fd, buf, nbytes);
if (tmp < nbytes) {
sprintf(conn->errorMessage,
"lo_export: error while writing \"%s\"",
filename);
return -1;
}
}
(void) lo_close(conn,lobj);
(void) close(fd);
return 1;
}

View File

@ -0,0 +1,193 @@
/*-------------------------------------------------------------------------
*
* FILE
* fe-misc.c
*
* DESCRIPTION
* miscellaneous useful functions
* these routines are analogous to the ones in libpq/pqcomm.c
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.1.1.1 1996/07/09 06:22:17 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdlib.h>
#include <stdio.h>
/* pqGetc:
get a character from stream f
if debug is set, also echo the character fetched
*/
int
pqGetc(FILE* fin, FILE* debug)
{
int c;
c = getc(fin);
if (debug && c != EOF)
putc(c,debug);
return c;
}
/* pqPutnchar:
send a string of exactly len length into stream f
returns 1 if there was an error, 0 otherwise.
*/
int
pqPutnchar(char* s, int len, FILE *f, FILE *debug)
{
int status;
if (f == NULL)
return 1;
while (len--) {
status = fputc(*s,f);
if (debug)
fputc(*s,debug);
s++;
if (status == EOF)
return 1;
}
return 0;
}
/* pqGetnchar:
get a string of exactly len length from stream f
*/
int
pqGetnchar(char* s, int len, FILE *f, FILE *debug)
{
int c;
if (f == NULL)
return 1;
while (len-- && (c = getc(f)) != EOF)
*s++ = c;
*s = '\0';
if (debug) {
fputs(s,debug);
}
return 0;
}
/* pqGets:
get a string of up to length len from stream f
*/
int
pqGets(char* s, int len, FILE *f, FILE *debug)
{
int c;
if (f == NULL)
return 1;
while (len-- && (c = getc(f)) != EOF && c)
*s++ = c;
*s = '\0';
if (debug) {
fputs(s,debug);
}
return 0;
}
/* pgPutInt
send an integer of up to 4 bytesto the file stream
do this one byte at at time.
This insures that machines with different ENDIANness can talk to each other
get a n-byte integer from the stream into result
returns 0 if successful, 1 otherwise
*/
int
pqPutInt(int i, int bytes, FILE* f, FILE *debug)
{
int status;
if (bytes > 4)
bytes = 4;
while (bytes--) {
status = fputc(i & 0xff, f);
if (debug)
fputc(i & 0xff, debug);
i >>= 8;
if (status == EOF) {
return 1;
}
}
return 0;
}
/* pgGetInt
reconstructs the integer one byte at a time.
This insures that machines with different ENDIANness can talk to each other
get a n-byte integer from the stream into result
returns 0 if successful
*/
int
pqGetInt(int* result, int bytes, FILE* f, FILE *debug)
{
int c;
int p;
int n;
if (f == NULL)
return 1;
p = 0;
n = 0;
while (bytes && (c = getc(f)) != EOF)
{
n |= (c & 0xff) << p;
p += 8;
bytes--;
}
if (bytes != 0)
return 1;
*result = n;
if (debug)
fprintf(debug,"%d",*result);
return 0;
}
int
pqPuts(char* s, FILE *f, FILE *debug)
{
if (f == NULL)
return 1;
if (fputs(s,f) == EOF)
return 1;
fputc('\0',f); /* important to send an ending EOF since backend expects it */
fflush(f);
if (debug) {
fputs(s,debug);
}
return 0;
}
void
pqFlush(FILE *f, FILE *debug)
{
if (f)
fflush(f);
if (debug)
fflush(debug);
}

View File

@ -0,0 +1,251 @@
/*-------------------------------------------------------------------------
*
* libpq-fe.h--
* This file contains definitions for structures and
* externs for functions used by frontend postgres applications.
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: libpq-fe.h,v 1.1.1.1 1996/07/09 06:22:17 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LIBPQ_FE_H
#define LIBPQ_FE_H
#ifdef __cplusplus
extern "C" {
#endif
/* ----------------
* include stuff common to fe and be
* ----------------
*/
/* #include "libpq/libpq.h" */
#include "libpq/pqcomm.h"
#include "lib/dllist.h"
typedef enum {CONNECTION_OK,
CONNECTION_BAD} ConnStatusType;
typedef enum {
PGRES_EMPTY_QUERY = 0,
PGRES_COMMAND_OK, /* a query command that doesn't return */
/* anything was executed properly by the backend */
PGRES_TUPLES_OK, /* a query command that returns tuples */
/* was executed properly by the backend, PGresult */
/* contains the resulttuples */
PGRES_COPY_OUT,
PGRES_COPY_IN,
PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from the backend */
PGRES_NONFATAL_ERROR,
PGRES_FATAL_ERROR
} ExecStatusType;
/* string descriptions of the ExecStatusTypes */
extern char* pgresStatus[];
/*
* POSTGRES backend dependent Constants.
*/
/* ERROR_MSG_LENGTH should really be the same as ELOG_MAXLEN in utils/elog.h*/
#define ERROR_MSG_LENGTH 4096
#define COMMAND_LENGTH 20
#define REMARK_LENGTH 80
#define PORTAL_NAME_LENGTH 16
/* ----------------
* PQArgBlock --
* Information (pointer to array of this structure) required
* for the PQfn() call.
* ----------------
*/
typedef struct {
int len;
int isint;
union {
int *ptr; /* can't use void (dec compiler barfs) */
int integer;
} u;
} PQArgBlock;
typedef struct pgresAttDesc {
char* name; /* type name */
Oid adtid; /* type id */
int2 adtsize; /* type size */
} PGresAttDesc;
/* use char* for Attribute values,
ASCII tuples are guaranteed to be null-terminated
For binary tuples, the first four bytes of the value is the size,
and the bytes afterwards are the value. The binary value is
not guaranteed to be null-terminated. In fact, it can have embedded nulls*/
typedef struct pgresAttValue {
int len; /* length in bytes of the value */
char *value; /* actual value */
} PGresAttValue;
typedef struct pgNotify {
char relname[NAMEDATALEN]; /* name of relation containing data */
int be_pid; /* process id of backend */
} PGnotify;
/* PGconn encapsulates a connection to the backend */
typedef struct pg_conn{
char *pghost; /* the machine on which the server is running */
char *pgtty; /* tty on which the backend messages is displayed */
char *pgport; /* the communication port with the backend */
char *pgoptions; /* options to start the backend with */
char *dbName; /* database name */
ConnStatusType status;
char errorMessage[ERROR_MSG_LENGTH];
/* pipes for be/fe communication */
FILE *Pfin;
FILE *Pfout;
FILE *Pfdebug;
void *port; /* really a Port* */
int asyncNotifyWaiting;
Dllist* notifyList;
} PGconn;
#define CMDSTATUS_LEN 40
/* PGresult encapsulates the result of a query */
/* unlike the old libpq, we assume that queries only return in one group */
typedef struct pg_result{
int ntups;
int numAttributes;
PGresAttDesc *attDescs;
PGresAttValue* *tuples; /* each PGresTuple is an array of PGresAttValue's */
int tupArrSize; /* size of tuples array allocated */
ExecStatusType resultStatus;
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the last insert query*/
int binary; /* binary tuple values if binary == 1, otherwise ASCII */
PGconn* conn;
} PGresult;
/* === in fe-connect.c === */
/* make a new client connection to the backend */
extern PGconn* PQsetdb(char* pghost, char* pgport, char* pgoptions,
char* pgtty, char* dbName);
/* close the current connection and free the PGconn data structure */
extern void PQfinish(PGconn* conn);
/* close the current connection and restablish a new one with the same
parameters */
extern void PQreset(PGconn* conn);
extern char* PQdb(PGconn* conn);
extern char* PQhost(PGconn* conn);
extern char* PQoptions(PGconn* conn);
extern char* PQport(PGconn* conn);
extern char* PQtty(PGconn* conn);
extern ConnStatusType PQstatus(PGconn* conn);
extern char* PQerrorMessage(PGconn* conn);
extern void PQtrace(PGconn *conn, FILE* debug_port);
extern void PQuntrace(PGconn *conn);
/* === in fe-exec.c === */
extern PGresult* PQexec(PGconn* conn, char* query);
extern int PQgetline(PGconn *conn, char* string, int length);
extern int PQendcopy(PGconn *conn);
extern void PQputline(PGconn *conn, char* string);
extern ExecStatusType PQresultStatus(PGresult* res);
extern int PQntuples(PGresult *res);
extern int PQnfields(PGresult *res);
extern char* PQfname(PGresult *res, int field_num);
extern int PQfnumber(PGresult *res, char* field_name);
extern Oid PQftype(PGresult *res, int field_num);
extern int2 PQfsize(PGresult *res, int field_num);
extern char* PQcmdStatus(PGresult *res);
extern char* PQoidStatus(PGresult *res);
extern char* PQgetvalue(PGresult *res, int tup_num, int field_num);
extern int PQgetlength(PGresult *res, int tup_num, int field_num);
extern void PQclear(PGresult* res);
/* PQdisplayTuples() is a better version of PQprintTuples() */
extern void PQdisplayTuples(PGresult *res,
FILE *fp, /* where to send the output */
int fillAlign, /* pad the fields with spaces */
char *fieldSep, /* field separator */
int printHeader, /* display headers? */
int quiet);
extern void PQprintTuples(PGresult* res,
FILE* fout, /* output stream */
int printAttName,/* print attribute names or not*/
int terseOutput, /* delimiter bars or not?*/
int width /* width of column,
if 0, use variable width */
);
extern PGnotify* PQnotifies(PGconn *conn);
extern PGresult* PQfn(PGconn* conn,
int fnid,
int *result_buf,
int *result_len,
int result_is_int,
PQArgBlock *args,
int nargs);
/* === in fe-auth.c === */
extern MsgType fe_getauthsvc(char* PQerrormsg);
extern void fe_setauthsvc(char *name, char* PQerrormsg);
extern char *fe_getauthname(char* PQerrormsg);
/* === in fe-misc.c === */
/* pqGets and pqPuts gets and sends strings to the file stream
returns 0 if successful
if debug is non-null, debugging output is sent to that stream
*/
extern int pqGets(char* s, int maxlen, FILE* stream, FILE* debug);
extern int pqGetnchar(char* s, int maxlen, FILE* stream, FILE* debug);
extern int pqPutnchar(char* s, int maxlen, FILE* stream, FILE* debug);
extern int pqPuts(char* s, FILE* stream, FILE* debug );
extern int pqGetc(FILE* stream, FILE *debug);
/* get a n-byte integer from the stream into result */
/* returns 0 if successful */
extern int pqGetInt(int* result, int bytes, FILE* stream, FILE *debug );
/* put a n-byte integer into the stream */
/* returns 0 if successful */
extern int pqPutInt(int n, int bytes, FILE* stream, FILE *debug );
extern void pqFlush(FILE* stream, FILE* debug);
/* === in fe-lobj.c === */
int lo_open(PGconn* conn, Oid lobjId, int mode);
int lo_close(PGconn *conn, int fd);
int lo_read(PGconn *conn, int fd, char *buf, int len);
int lo_write(PGconn *conn, int fd, char *buf, int len);
int lo_lseek(PGconn *conn, int fd, int offset, int whence);
Oid lo_creat(PGconn *conn, int mode);
int lo_tell(PGconn *conn, int fd);
int lo_unlink(PGconn *conn, Oid lobjId);
Oid lo_import(PGconn *conn, char *filename);
int lo_export(PGconn *conn, Oid lobjId, char *filename);
/* max length of message to send */
#define MAX_MESSAGE_LEN 8193
/* maximum number of fields in a tuple */
#define BYTELEN 8
#define MAX_FIELDS 512
/* fall back options if they are not specified by arguments or defined
by environment variables */
#define DefaultHost "localhost"
#define DefaultTty ""
#define DefaultOption ""
typedef void *TUPLE;
#define palloc malloc
#define pfree free
#if defined(PORTNAME_sparc)
extern char *sys_errlist[];
#define strerror(A) (sys_errlist[(A)])
#endif /* PORTNAME_sparc */
#ifdef __cplusplus
};
#endif
#endif /* LIBPQ_FE_H */

View File

@ -0,0 +1,13 @@
#
# Example config file for Postgres95 host based access
#
# Lines starting with "all" apply to all databases. Otherwise the first
# column has to match the name of the database being connected to. Up to
# ten config lines can apply to each database. Mask specifies bits that
# aren't counted. After those bits are taken out, the connection address
# must match the address in the middle column.
#
# <name> <address> <mask>
#
all 127.0.0.1 0.0.0.0

View File

@ -0,0 +1,40 @@
/*-------------------------------------------------------------------------
*
* pqsignal.c--
* reliable BSD-style signal(2) routine stolen from RWW who stole it
* from Stevens...
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/pqsignal.c,v 1.1.1.1 1996/07/09 06:22:17 scrappy Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
* things need it...
*
*-------------------------------------------------------------------------
*/
#include "libpq/pqsignal.h"
pqsigfunc
pqsignal(int signo, pqsigfunc func)
{
#if defined(USE_POSIX_SIGNALS)
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo != SIGALRM) {
act.sa_flags |= SA_RESTART;
}
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
#else /* !USE_POSIX_SIGNALS */
exit(1); /* this should never be reached, pqsignal should only
be called if USE_POSIX_SIGNALS is true*/
#endif /* !USE_POSIX_SIGNALS */
}

View File

@ -0,0 +1,32 @@
/*-------------------------------------------------------------------------
*
* pqsignal.h--
* prototypes for the reliable BSD-style signal(2) routine.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: pqsignal.h,v 1.1.1.1 1996/07/09 06:22:17 scrappy Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
* things need it...
*
*-------------------------------------------------------------------------
*/
#ifndef PQSIGNAL_H
#define PQSIGNAL_H
#include <signal.h>
#include "c.h"
typedef void (*pqsigfunc)(int);
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
#if defined(USE_POSIX_SIGNALS)
#define signal(signo, handler) pqsignal(signo, (pqsigfunc)(handler))
#endif /* USE_POSIX_SIGNALS */
#endif /* PQSIGNAL_H */