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:
38
src/interfaces/libpgtcl/Makefile
Normal file
38
src/interfaces/libpgtcl/Makefile
Normal 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
|
||||
|
7
src/interfaces/libpgtcl/README
Normal file
7
src/interfaces/libpgtcl/README
Normal 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
|
||||
|
21
src/interfaces/libpgtcl/libpgtcl.h
Normal file
21
src/interfaces/libpgtcl/libpgtcl.h
Normal 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 */
|
105
src/interfaces/libpgtcl/pgtcl.c
Normal file
105
src/interfaces/libpgtcl/pgtcl.c
Normal 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;
|
||||
}
|
||||
|
||||
|
812
src/interfaces/libpgtcl/pgtclCmds.c
Normal file
812
src/interfaces/libpgtcl/pgtclCmds.c
Normal 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;
|
||||
}
|
||||
|
||||
|
52
src/interfaces/libpgtcl/pgtclCmds.h
Normal file
52
src/interfaces/libpgtcl/pgtclCmds.h
Normal 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*/
|
||||
|
51
src/interfaces/libpgtcl/pgtclId.c
Normal file
51
src/interfaces/libpgtcl/pgtclId.c
Normal 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;
|
||||
}
|
18
src/interfaces/libpgtcl/pgtclId.h
Normal file
18
src/interfaces/libpgtcl/pgtclId.h
Normal 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);
|
54
src/interfaces/libpq++/Makefile
Normal file
54
src/interfaces/libpq++/Makefile
Normal 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
|
22
src/interfaces/libpq++/README
Normal file
22
src/interfaces/libpq++/README
Normal 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
|
70
src/interfaces/libpq++/examples/Makefile
Normal file
70
src/interfaces/libpq++/examples/Makefile
Normal 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
|
49
src/interfaces/libpq++/examples/testlibpq0.cc
Normal file
49
src/interfaces/libpq++/examples/testlibpq0.cc
Normal 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;
|
||||
}
|
||||
}
|
84
src/interfaces/libpq++/examples/testlibpq1.cc
Normal file
84
src/interfaces/libpq++/examples/testlibpq1.cc
Normal 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;
|
||||
}
|
||||
|
||||
|
71
src/interfaces/libpq++/examples/testlibpq2.cc
Normal file
71
src/interfaces/libpq++/examples/testlibpq2.cc
Normal 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;
|
||||
}
|
5
src/interfaces/libpq++/examples/testlibpq2.sql
Normal file
5
src/interfaces/libpq++/examples/testlibpq2.sql
Normal 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];
|
131
src/interfaces/libpq++/examples/testlibpq3.cc
Normal file
131
src/interfaces/libpq++/examples/testlibpq3.cc
Normal 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;
|
||||
}
|
6
src/interfaces/libpq++/examples/testlibpq3.sql
Normal file
6
src/interfaces/libpq++/examples/testlibpq3.sql
Normal 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);
|
||||
|
69
src/interfaces/libpq++/examples/testlibpq4.cc
Normal file
69
src/interfaces/libpq++/examples/testlibpq4.cc
Normal 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;
|
||||
}
|
63
src/interfaces/libpq++/examples/testlo.cc
Normal file
63
src/interfaces/libpq++/examples/testlo.cc
Normal 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;
|
||||
}
|
173
src/interfaces/libpq++/libpq++.H
Normal file
173
src/interfaces/libpq++/libpq++.H
Normal 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 */
|
434
src/interfaces/libpq++/man/libpq++.3
Normal file
434
src/interfaces/libpq++/man/libpq++.3
Normal 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.
|
94
src/interfaces/libpq++/pgconnection.cc
Normal file
94
src/interfaces/libpq++/pgconnection.cc
Normal 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;
|
||||
}
|
||||
}
|
109
src/interfaces/libpq++/pgenv.cc
Normal file
109
src/interfaces/libpq++/pgenv.cc
Normal 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);
|
||||
}
|
152
src/interfaces/libpq++/pglobject.cc
Normal file
152
src/interfaces/libpq++/pglobject.cc
Normal 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);
|
||||
}
|
98
src/interfaces/libpq/Makefile
Normal file
98
src/interfaces/libpq/Makefile
Normal 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
|
||||
|
1
src/interfaces/libpq/README
Normal file
1
src/interfaces/libpq/README
Normal file
@ -0,0 +1 @@
|
||||
This directory contains the C version of Libpq, the POSTGRES frontend library.
|
544
src/interfaces/libpq/fe-auth.c
Normal file
544
src/interfaces/libpq/fe-auth.c
Normal 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);
|
||||
}
|
||||
|
||||
|
38
src/interfaces/libpq/fe-auth.h
Normal file
38
src/interfaces/libpq/fe-auth.h
Normal 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 */
|
||||
|
460
src/interfaces/libpq/fe-connect.c
Normal file
460
src/interfaces/libpq/fe-connect.c
Normal 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;
|
||||
}
|
||||
}
|
1061
src/interfaces/libpq/fe-exec.c
Normal file
1061
src/interfaces/libpq/fe-exec.c
Normal file
File diff suppressed because it is too large
Load Diff
381
src/interfaces/libpq/fe-lobj.c
Normal file
381
src/interfaces/libpq/fe-lobj.c
Normal 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;
|
||||
}
|
193
src/interfaces/libpq/fe-misc.c
Normal file
193
src/interfaces/libpq/fe-misc.c
Normal 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);
|
||||
}
|
251
src/interfaces/libpq/libpq-fe.h
Normal file
251
src/interfaces/libpq/libpq-fe.h
Normal 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 */
|
||||
|
13
src/interfaces/libpq/pg_hba
Normal file
13
src/interfaces/libpq/pg_hba
Normal 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
|
||||
|
40
src/interfaces/libpq/pqsignal.c
Normal file
40
src/interfaces/libpq/pqsignal.c
Normal 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 */
|
||||
}
|
32
src/interfaces/libpq/pqsignal.h
Normal file
32
src/interfaces/libpq/pqsignal.h
Normal 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 */
|
Reference in New Issue
Block a user