mirror of
https://github.com/postgres/postgres.git
synced 2025-11-03 09:13:20 +03:00
Massive commit to run PGINDENT on all *.c and *.h files.
This commit is contained in:
@@ -1,65 +1,65 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* auth.c--
|
||||
* Routines to handle network authentication
|
||||
* Routines to handle network authentication
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.14 1997/08/19 21:31:23 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.15 1997/09/07 04:42:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* INTERFACE ROUTINES
|
||||
*
|
||||
* backend (postmaster) routines:
|
||||
* be_recvauth receive authentication information
|
||||
* be_setauthsvc do/do not permit an authentication service
|
||||
* be_getauthsvc is an authentication service permitted?
|
||||
* backend (postmaster) routines:
|
||||
* be_recvauth receive authentication information
|
||||
* be_setauthsvc do/do not permit an authentication service
|
||||
* be_getauthsvc is an authentication service permitted?
|
||||
*
|
||||
* NOTES
|
||||
* To add a new authentication system:
|
||||
* 0. If you can't do your authentication over an existing socket,
|
||||
* you lose -- get ready to hack around this framework instead of
|
||||
* using it. Otherwise, you can assume you have an initialized
|
||||
* and empty connection to work with. (Please don't leave leftover
|
||||
* gunk in the connection after the authentication transactions, or
|
||||
* the POSTGRES routines that follow will be very unhappy.)
|
||||
* 1. Write a set of routines that:
|
||||
* let a client figure out what user/principal name to use
|
||||
* send authentication information (client side)
|
||||
* receive authentication information (server side)
|
||||
* You can include both routines in this file, using #ifdef FRONTEND
|
||||
* to separate them.
|
||||
* 2. Edit libpq/pqcomm.h and assign a MsgType for your protocol.
|
||||
* 3. Edit the static "struct authsvc" array and the generic
|
||||
* {be,fe}_{get,set}auth{name,svc} routines in this file to reflect
|
||||
* the new service. You may have to change the arguments of these
|
||||
* routines; they basically just reflect what Kerberos v4 needs.
|
||||
* 4. Hack on src/{,bin}/Makefile.global and src/{backend,libpq}/Makefile
|
||||
* to add library and CFLAGS hooks -- basically, grep the Makefile
|
||||
* hierarchy for KRBVERS to see where you need to add things.
|
||||
* NOTES
|
||||
* To add a new authentication system:
|
||||
* 0. If you can't do your authentication over an existing socket,
|
||||
* you lose -- get ready to hack around this framework instead of
|
||||
* using it. Otherwise, you can assume you have an initialized
|
||||
* and empty connection to work with. (Please don't leave leftover
|
||||
* gunk in the connection after the authentication transactions, or
|
||||
* the POSTGRES routines that follow will be very unhappy.)
|
||||
* 1. Write a set of routines that:
|
||||
* let a client figure out what user/principal name to use
|
||||
* send authentication information (client side)
|
||||
* receive authentication information (server side)
|
||||
* You can include both routines in this file, using #ifdef FRONTEND
|
||||
* to separate them.
|
||||
* 2. Edit libpq/pqcomm.h and assign a MsgType for your protocol.
|
||||
* 3. Edit the static "struct authsvc" array and the generic
|
||||
* {be,fe}_{get,set}auth{name,svc} routines in this file to reflect
|
||||
* the new service. You may have to change the arguments of these
|
||||
* routines; they basically just reflect what Kerberos v4 needs.
|
||||
* 4. Hack on src/{,bin}/Makefile.global and src/{backend,libpq}/Makefile
|
||||
* to add library and CFLAGS hooks -- basically, grep the Makefile
|
||||
* hierarchy for KRBVERS to see where you need to add things.
|
||||
*
|
||||
* Send mail to post_hackers@postgres.Berkeley.EDU if you have to make
|
||||
* any changes to arguments, etc. Context diffs would be nice, too.
|
||||
* Send mail to post_hackers@postgres.Berkeley.EDU if you have to make
|
||||
* any changes to arguments, etc. Context diffs would be nice, too.
|
||||
*
|
||||
* Someday, this cruft will go away and magically be replaced by a
|
||||
* nice interface based on the GSS API or something. For now, though,
|
||||
* there's no (stable) UNIX security API to work with...
|
||||
* Someday, this cruft will go away and magically be replaced by a
|
||||
* nice interface based on the GSS API or something. For now, though,
|
||||
* there's no (stable) UNIX security API to work with...
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
|
||||
#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#include <netdb.h> /* for MAXHOSTNAMELEN on some */
|
||||
#include <netdb.h> /* for MAXHOSTNAMELEN on some */
|
||||
#endif
|
||||
#include <pwd.h>
|
||||
#include <ctype.h> /* isspace() declaration */
|
||||
#include <ctype.h> /* isspace() declaration */
|
||||
|
||||
#include <sys/types.h> /* needed by in.h on Ultrix */
|
||||
#include <sys/types.h> /* needed by in.h on Ultrix */
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
@@ -72,19 +72,19 @@
|
||||
#include <libpq/hba.h>
|
||||
#include <libpq/password.h>
|
||||
|
||||
static int be_getauthsvc(MsgType msgtype);
|
||||
static int be_getauthsvc(MsgType msgtype);
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* 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)?
|
||||
*/
|
||||
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)? */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -99,9 +99,11 @@ struct authsvc {
|
||||
*/
|
||||
|
||||
#if defined(HBA)
|
||||
static int useHostBasedAuth = 1;
|
||||
static int useHostBasedAuth = 1;
|
||||
|
||||
#else
|
||||
static int useHostBasedAuth = 0;
|
||||
static int useHostBasedAuth = 0;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(KRB4) || defined(KRB5) || defined(HBA)
|
||||
@@ -111,19 +113,19 @@ static int useHostBasedAuth = 0;
|
||||
#endif
|
||||
|
||||
static struct authsvc authsvcs[] = {
|
||||
{ "unauth", STARTUP_UNAUTH_MSG, UNAUTH_ALLOWED },
|
||||
{ "hba", STARTUP_HBA_MSG, 1 },
|
||||
{ "krb4", STARTUP_KRB4_MSG, 1 },
|
||||
{ "krb5", STARTUP_KRB5_MSG, 1 },
|
||||
#if defined(KRB5)
|
||||
{ "kerberos", STARTUP_KRB5_MSG, 1 },
|
||||
{"unauth", STARTUP_UNAUTH_MSG, UNAUTH_ALLOWED},
|
||||
{"hba", STARTUP_HBA_MSG, 1},
|
||||
{"krb4", STARTUP_KRB4_MSG, 1},
|
||||
{"krb5", STARTUP_KRB5_MSG, 1},
|
||||
#if defined(KRB5)
|
||||
{"kerberos", STARTUP_KRB5_MSG, 1},
|
||||
#else
|
||||
{ "kerberos", STARTUP_KRB4_MSG, 1 },
|
||||
{"kerberos", STARTUP_KRB4_MSG, 1},
|
||||
#endif
|
||||
{ "password", STARTUP_PASSWORD_MSG, 1 }
|
||||
{"password", STARTUP_PASSWORD_MSG, 1}
|
||||
};
|
||||
|
||||
static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
|
||||
static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
|
||||
|
||||
#ifdef KRB4
|
||||
/* This has to be ifdef'd out because krb.h does exist. This needs
|
||||
@@ -138,11 +140,11 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
|
||||
|
||||
#ifdef FRONTEND
|
||||
/* moves to src/libpq/fe-auth.c */
|
||||
#else /* !FRONTEND */
|
||||
#else /* !FRONTEND */
|
||||
|
||||
/*
|
||||
* pg_krb4_recvauth -- server routine to receive authentication information
|
||||
* from the client
|
||||
* from the client
|
||||
*
|
||||
* Nothing unusual here, except that we compare the username obtained from
|
||||
* the client's setup packet to the authenticated name. (We have to retain
|
||||
@@ -151,77 +153,82 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
|
||||
*/
|
||||
static int
|
||||
pg_krb4_recvauth(int sock,
|
||||
struct sockaddr_in *laddr,
|
||||
struct sockaddr_in *raddr,
|
||||
char *username)
|
||||
struct sockaddr_in * laddr,
|
||||
struct sockaddr_in * raddr,
|
||||
char *username)
|
||||
{
|
||||
long krbopts = 0; /* one-way authentication */
|
||||
KTEXT_ST clttkt;
|
||||
char instance[INST_SZ];
|
||||
AUTH_DAT auth_data;
|
||||
Key_schedule key_sched;
|
||||
char version[KRB_SENDAUTH_VLEN];
|
||||
int status;
|
||||
|
||||
strcpy(instance, "*"); /* don't care, but arg gets expanded anyway */
|
||||
status = krb_recvauth(krbopts,
|
||||
sock,
|
||||
&clttkt,
|
||||
PG_KRB_SRVNAM,
|
||||
instance,
|
||||
raddr,
|
||||
laddr,
|
||||
&auth_data,
|
||||
PG_KRB_SRVTAB,
|
||||
key_sched,
|
||||
version);
|
||||
if (status != KSUCCESS) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: kerberos error: %s\n",
|
||||
krb_err_txt[status]);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN)) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: protocol version != \"%s\"\n",
|
||||
PG_KRB4_VERSION);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
if (username && *username &&
|
||||
strncmp(username, auth_data.pname, NAMEDATALEN)) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
|
||||
username,
|
||||
auth_data.pname);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
return(STATUS_OK);
|
||||
long krbopts = 0;/* one-way authentication */
|
||||
KTEXT_ST clttkt;
|
||||
char instance[INST_SZ];
|
||||
AUTH_DAT auth_data;
|
||||
Key_schedule key_sched;
|
||||
char version[KRB_SENDAUTH_VLEN];
|
||||
int status;
|
||||
|
||||
strcpy(instance, "*"); /* don't care, but arg gets expanded
|
||||
* anyway */
|
||||
status = krb_recvauth(krbopts,
|
||||
sock,
|
||||
&clttkt,
|
||||
PG_KRB_SRVNAM,
|
||||
instance,
|
||||
raddr,
|
||||
laddr,
|
||||
&auth_data,
|
||||
PG_KRB_SRVTAB,
|
||||
key_sched,
|
||||
version);
|
||||
if (status != KSUCCESS)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: kerberos error: %s\n",
|
||||
krb_err_txt[status]);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: protocol version != \"%s\"\n",
|
||||
PG_KRB4_VERSION);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (username && *username &&
|
||||
strncmp(username, auth_data.pname, NAMEDATALEN))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
|
||||
username,
|
||||
auth_data.pname);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
#endif /* !FRONTEND */
|
||||
#endif /* !FRONTEND */
|
||||
|
||||
#else
|
||||
static int
|
||||
pg_krb4_recvauth(int sock,
|
||||
struct sockaddr_in *laddr,
|
||||
struct sockaddr_in *raddr,
|
||||
char *username)
|
||||
struct sockaddr_in * laddr,
|
||||
struct sockaddr_in * raddr,
|
||||
char *username)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: Kerberos not implemented on this "
|
||||
"server.\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb4_recvauth: Kerberos not implemented on this "
|
||||
"server.\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
|
||||
return(STATUS_ERROR);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
#endif /* KRB4 */
|
||||
|
||||
#endif /* KRB4 */
|
||||
|
||||
|
||||
#ifdef KRB5
|
||||
@@ -237,37 +244,37 @@ return(STATUS_ERROR);
|
||||
|
||||
/*
|
||||
* pg_an_to_ln -- return the local name corresponding to an authentication
|
||||
* name
|
||||
* 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.
|
||||
* 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 *
|
||||
static char *
|
||||
pg_an_to_ln(char *aname)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
|
||||
*p = '\0';
|
||||
return(aname);
|
||||
char *p;
|
||||
|
||||
if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
|
||||
*p = '\0';
|
||||
return (aname);
|
||||
}
|
||||
|
||||
#ifdef FRONTEND
|
||||
/* moves to src/libpq/fe-auth.c */
|
||||
#else /* !FRONTEND */
|
||||
#else /* !FRONTEND */
|
||||
|
||||
/*
|
||||
* pg_krb5_recvauth -- server routine to receive authentication information
|
||||
* from the client
|
||||
* from the client
|
||||
*
|
||||
* We still need to compare the username obtained from the client's setup
|
||||
* packet to the authenticated name, as described in pg_krb4_recvauth. This
|
||||
* packet to the authenticated name, as described in pg_krb4_recvauth. This
|
||||
* is a bit more problematic in v5, as described above in pg_an_to_ln.
|
||||
*
|
||||
* In addition, as described above in pg_krb5_sendauth, we still need to
|
||||
@@ -286,315 +293,348 @@ pg_an_to_ln(char *aname)
|
||||
*/
|
||||
static int
|
||||
pg_krb5_recvauth(int sock,
|
||||
struct sockaddr_in *laddr,
|
||||
struct sockaddr_in *raddr,
|
||||
char *username)
|
||||
struct sockaddr_in * laddr,
|
||||
struct sockaddr_in * raddr,
|
||||
char *username)
|
||||
{
|
||||
char servbuf[MAXHOSTNAMELEN + 1 +
|
||||
sizeof(PG_KRB_SRVNAM)];
|
||||
char *hostp, *kusername = (char *) NULL;
|
||||
krb5_error_code code;
|
||||
krb5_principal client, server;
|
||||
krb5_address sender_addr;
|
||||
krb5_rdreq_key_proc keyproc = (krb5_rdreq_key_proc) NULL;
|
||||
krb5_pointer keyprocarg = (krb5_pointer) NULL;
|
||||
|
||||
/*
|
||||
* Set up server side -- since we have no ticket file to make this
|
||||
* easy, we construct our own name and parse it. See note on
|
||||
* canonicalization above.
|
||||
*/
|
||||
strcpy(servbuf, PG_KRB_SRVNAM);
|
||||
*(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
|
||||
if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
|
||||
strcpy(hostp, "localhost");
|
||||
if (hostp = strchr(hostp, '.'))
|
||||
*hostp = '\0';
|
||||
if (code = krb5_parse_name(servbuf, &server)) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n",
|
||||
code);
|
||||
com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* krb5_sendauth needs this to verify the address in the client
|
||||
* authenticator.
|
||||
*/
|
||||
sender_addr.addrtype = raddr->sin_family;
|
||||
sender_addr.length = sizeof(raddr->sin_addr);
|
||||
sender_addr.contents = (krb5_octet *) &(raddr->sin_addr);
|
||||
|
||||
if (strcmp(PG_KRB_SRVTAB, "")) {
|
||||
keyproc = krb5_kt_read_service_key;
|
||||
keyprocarg = PG_KRB_SRVTAB;
|
||||
}
|
||||
|
||||
if (code = krb5_recvauth((krb5_pointer) &sock,
|
||||
PG_KRB5_VERSION,
|
||||
server,
|
||||
&sender_addr,
|
||||
(krb5_pointer) NULL,
|
||||
keyproc,
|
||||
keyprocarg,
|
||||
(char *) NULL,
|
||||
(krb5_int32 *) NULL,
|
||||
&client,
|
||||
(krb5_ticket **) NULL,
|
||||
(krb5_authenticator **) NULL)) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n",
|
||||
code);
|
||||
com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
|
||||
char servbuf[MAXHOSTNAMELEN + 1 +
|
||||
sizeof(PG_KRB_SRVNAM)];
|
||||
char *hostp,
|
||||
*kusername = (char *) NULL;
|
||||
krb5_error_code code;
|
||||
krb5_principal client,
|
||||
server;
|
||||
krb5_address sender_addr;
|
||||
krb5_rdreq_key_proc keyproc = (krb5_rdreq_key_proc) NULL;
|
||||
krb5_pointer keyprocarg = (krb5_pointer) NULL;
|
||||
|
||||
/*
|
||||
* Set up server side -- since we have no ticket file to make this
|
||||
* easy, we construct our own name and parse it. See note on
|
||||
* canonicalization above.
|
||||
*/
|
||||
strcpy(servbuf, PG_KRB_SRVNAM);
|
||||
*(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
|
||||
if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
|
||||
strcpy(hostp, "localhost");
|
||||
if (hostp = strchr(hostp, '.'))
|
||||
*hostp = '\0';
|
||||
if (code = krb5_parse_name(servbuf, &server))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n",
|
||||
code);
|
||||
com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* krb5_sendauth needs this to verify the address in the client
|
||||
* authenticator.
|
||||
*/
|
||||
sender_addr.addrtype = raddr->sin_family;
|
||||
sender_addr.length = sizeof(raddr->sin_addr);
|
||||
sender_addr.contents = (krb5_octet *) & (raddr->sin_addr);
|
||||
|
||||
if (strcmp(PG_KRB_SRVTAB, ""))
|
||||
{
|
||||
keyproc = krb5_kt_read_service_key;
|
||||
keyprocarg = PG_KRB_SRVTAB;
|
||||
}
|
||||
|
||||
if (code = krb5_recvauth((krb5_pointer) & sock,
|
||||
PG_KRB5_VERSION,
|
||||
server,
|
||||
&sender_addr,
|
||||
(krb5_pointer) NULL,
|
||||
keyproc,
|
||||
keyprocarg,
|
||||
(char *) NULL,
|
||||
(krb5_int32 *) NULL,
|
||||
&client,
|
||||
(krb5_ticket **) NULL,
|
||||
(krb5_authenticator **) NULL))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n",
|
||||
code);
|
||||
com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
|
||||
krb5_free_principal(server);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
krb5_free_principal(server);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
krb5_free_principal(server);
|
||||
|
||||
/*
|
||||
* The "client" structure comes out of the ticket and is therefore
|
||||
* authenticated. Use it to check the username obtained from the
|
||||
* postmaster startup packet.
|
||||
*/
|
||||
if ((code = krb5_unparse_name(client, &kusername))) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n",
|
||||
code);
|
||||
com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
|
||||
|
||||
/*
|
||||
* The "client" structure comes out of the ticket and is therefore
|
||||
* authenticated. Use it to check the username obtained from the
|
||||
* postmaster startup packet.
|
||||
*/
|
||||
if ((code = krb5_unparse_name(client, &kusername)))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n",
|
||||
code);
|
||||
com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
|
||||
krb5_free_principal(client);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
krb5_free_principal(client);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
krb5_free_principal(client);
|
||||
if (!kusername) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: could not decode username\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
kusername = pg_an_to_ln(kusername);
|
||||
if (username && strncmp(username, kusername, NAMEDATALEN)) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
|
||||
username, kusername);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
if (!kusername)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: could not decode username\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
kusername = pg_an_to_ln(kusername);
|
||||
if (username && strncmp(username, kusername, NAMEDATALEN))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
|
||||
username, kusername);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
free(kusername);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
free(kusername);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
free(kusername);
|
||||
return(STATUS_OK);
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
#endif /* !FRONTEND */
|
||||
#endif /* !FRONTEND */
|
||||
|
||||
|
||||
#else
|
||||
static int
|
||||
pg_krb5_recvauth(int sock,
|
||||
struct sockaddr_in *laddr,
|
||||
struct sockaddr_in *raddr,
|
||||
char *username)
|
||||
struct sockaddr_in * laddr,
|
||||
struct sockaddr_in * raddr,
|
||||
char *username)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_krb5_recvauth: Kerberos not implemented on this "
|
||||
"server.\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
#endif /* KRB5 */
|
||||
|
||||
static int
|
||||
pg_password_recvauth(Port *port, char *database, char *DataDir)
|
||||
{
|
||||
PacketBuf buf;
|
||||
char *user, *password;
|
||||
|
||||
if(PacketReceive(port, &buf, BLOCKING) != STATUS_OK) {
|
||||
sprintf(PQerrormsg,
|
||||
"pg_password_recvauth: failed to receive authentication packet.\n");
|
||||
"pg_krb5_recvauth: Kerberos not implemented on this "
|
||||
"server.\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
user = buf.data;
|
||||
password = buf.data + strlen(user) + 1;
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
return verify_password(user, password, port, database, DataDir);
|
||||
#endif /* KRB5 */
|
||||
|
||||
static int
|
||||
pg_password_recvauth(Port * port, char *database, char *DataDir)
|
||||
{
|
||||
PacketBuf buf;
|
||||
char *user,
|
||||
*password;
|
||||
|
||||
if (PacketReceive(port, &buf, BLOCKING) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"pg_password_recvauth: failed to receive authentication packet.\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
user = buf.data;
|
||||
password = buf.data + strlen(user) + 1;
|
||||
|
||||
return verify_password(user, password, port, database, DataDir);
|
||||
}
|
||||
|
||||
/*
|
||||
* be_recvauth -- server demux routine for incoming authentication information
|
||||
*/
|
||||
int
|
||||
be_recvauth(MsgType msgtype_arg, Port *port, char *username, StartupInfo* sp)
|
||||
be_recvauth(MsgType msgtype_arg, Port * port, char *username, StartupInfo * sp)
|
||||
{
|
||||
MsgType msgtype;
|
||||
MsgType msgtype;
|
||||
|
||||
/* A message type of STARTUP_MSG (which once upon a time was the only
|
||||
startup message type) means user wants us to choose. "unauth" is
|
||||
what used to be the only choice, but installation may choose "hba"
|
||||
instead.
|
||||
*/
|
||||
if (msgtype_arg == STARTUP_MSG) {
|
||||
if(useHostBasedAuth)
|
||||
msgtype = STARTUP_HBA_MSG;
|
||||
else
|
||||
msgtype = STARTUP_UNAUTH_MSG;
|
||||
} else
|
||||
msgtype = msgtype_arg;
|
||||
|
||||
|
||||
if (!username) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: no user name passed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
if (!port) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: no port structure passed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
|
||||
switch (msgtype) {
|
||||
case STARTUP_KRB4_MSG:
|
||||
if (!be_getauthsvc(msgtype)) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb4 authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
if (pg_krb4_recvauth(port->sock, &port->laddr, &port->raddr,
|
||||
username) != STATUS_OK) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb4 authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_KRB5_MSG:
|
||||
if (!be_getauthsvc(msgtype)) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb5 authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
if (pg_krb5_recvauth(port->sock, &port->laddr, &port->raddr,
|
||||
username) != STATUS_OK) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb5 authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_UNAUTH_MSG:
|
||||
if (!be_getauthsvc(msgtype)) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: "
|
||||
"unauthenticated connections disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_HBA_MSG:
|
||||
if (hba_recvauth(port, sp->database, sp->user, DataDir) != STATUS_OK) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: host-based authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_PASSWORD_MSG:
|
||||
if(!be_getauthsvc(msgtype)) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: "
|
||||
"plaintext password authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
/*
|
||||
* A message type of STARTUP_MSG (which once upon a time was the only
|
||||
* startup message type) means user wants us to choose. "unauth" is
|
||||
* what used to be the only choice, but installation may choose "hba"
|
||||
* instead.
|
||||
*/
|
||||
if (msgtype_arg == STARTUP_MSG)
|
||||
{
|
||||
if (useHostBasedAuth)
|
||||
msgtype = STARTUP_HBA_MSG;
|
||||
else
|
||||
msgtype = STARTUP_UNAUTH_MSG;
|
||||
}
|
||||
if(pg_password_recvauth(port, sp->database, DataDir) != STATUS_OK) {
|
||||
/* pg_password_recvauth or lower-level routines have already set */
|
||||
/* the error message */
|
||||
return(STATUS_ERROR);
|
||||
else
|
||||
msgtype = msgtype_arg;
|
||||
|
||||
|
||||
if (!username)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: no user name passed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: unrecognized message type: %d\n",
|
||||
msgtype);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
return(STATUS_OK);
|
||||
if (!port)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: no port structure passed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
switch (msgtype)
|
||||
{
|
||||
case STARTUP_KRB4_MSG:
|
||||
if (!be_getauthsvc(msgtype))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb4 authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (pg_krb4_recvauth(port->sock, &port->laddr, &port->raddr,
|
||||
username) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb4 authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_KRB5_MSG:
|
||||
if (!be_getauthsvc(msgtype))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb5 authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (pg_krb5_recvauth(port->sock, &port->laddr, &port->raddr,
|
||||
username) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: krb5 authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_UNAUTH_MSG:
|
||||
if (!be_getauthsvc(msgtype))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: "
|
||||
"unauthenticated connections disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_HBA_MSG:
|
||||
if (hba_recvauth(port, sp->database, sp->user, DataDir) != STATUS_OK)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: host-based authentication failed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case STARTUP_PASSWORD_MSG:
|
||||
if (!be_getauthsvc(msgtype))
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: "
|
||||
"plaintext password authentication disallowed\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
if (pg_password_recvauth(port, sp->database, DataDir) != STATUS_OK)
|
||||
{
|
||||
|
||||
/*
|
||||
* pg_password_recvauth or lower-level routines have already
|
||||
* set
|
||||
*/
|
||||
/* the error message */
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sprintf(PQerrormsg,
|
||||
"be_recvauth: unrecognized message type: %d\n",
|
||||
msgtype);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* be_setauthsvc -- enable/disable the authentication services currently
|
||||
* selected for use by the backend
|
||||
* selected for use by the backend
|
||||
* be_getauthsvc -- returns whether a particular authentication system
|
||||
* (indicated by its message type) is permitted by the
|
||||
* current selections
|
||||
* (indicated by its message type) is permitted by the
|
||||
* current selections
|
||||
*
|
||||
* be_setauthsvc encodes the command-line syntax that
|
||||
* -a "<service-name>"
|
||||
* -a "<service-name>"
|
||||
* enables a service, whereas
|
||||
* -a "no<service-name>"
|
||||
* -a "no<service-name>"
|
||||
* disables it.
|
||||
*/
|
||||
void
|
||||
be_setauthsvc(char *name)
|
||||
{
|
||||
int i, j;
|
||||
int turnon = 1;
|
||||
|
||||
if (!name)
|
||||
return;
|
||||
if (!strncmp("no", name, 2)) {
|
||||
turnon = 0;
|
||||
name += 2;
|
||||
}
|
||||
if (name[0] == '\0')
|
||||
return;
|
||||
for (i = 0; i < n_authsvcs; ++i)
|
||||
if (!strcmp(name, authsvcs[i].name)) {
|
||||
for (j = 0; j < n_authsvcs; ++j)
|
||||
if (authsvcs[j].msgtype == authsvcs[i].msgtype)
|
||||
authsvcs[j].allowed = turnon;
|
||||
break;
|
||||
int i,
|
||||
j;
|
||||
int turnon = 1;
|
||||
|
||||
if (!name)
|
||||
return;
|
||||
if (!strncmp("no", name, 2))
|
||||
{
|
||||
turnon = 0;
|
||||
name += 2;
|
||||
}
|
||||
if (i == n_authsvcs) {
|
||||
sprintf(PQerrormsg,
|
||||
"be_setauthsvc: invalid name %s, ignoring...\n",
|
||||
name);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
}
|
||||
return;
|
||||
if (name[0] == '\0')
|
||||
return;
|
||||
for (i = 0; i < n_authsvcs; ++i)
|
||||
if (!strcmp(name, authsvcs[i].name))
|
||||
{
|
||||
for (j = 0; j < n_authsvcs; ++j)
|
||||
if (authsvcs[j].msgtype == authsvcs[i].msgtype)
|
||||
authsvcs[j].allowed = turnon;
|
||||
break;
|
||||
}
|
||||
if (i == n_authsvcs)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"be_setauthsvc: invalid name %s, ignoring...\n",
|
||||
name);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
be_getauthsvc(MsgType msgtype)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_authsvcs; ++i)
|
||||
if (msgtype == authsvcs[i].msgtype)
|
||||
return(authsvcs[i].allowed);
|
||||
return(0);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_authsvcs; ++i)
|
||||
if (msgtype == authsvcs[i].msgtype)
|
||||
return (authsvcs[i].allowed);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* be-dumpdata.c--
|
||||
* support for collection of returned tuples from an internal
|
||||
* PQ call into a backend buffer.
|
||||
* support for collection of returned tuples from an internal
|
||||
* PQ call into a backend buffer.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.5 1997/08/18 20:52:31 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.6 1997/09/07 04:42:12 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* INTERFACE ROUTINES
|
||||
* be_portalinit - initialize backend portal administration
|
||||
* be_portalpush - add a portal to the top of the portal stack
|
||||
* be_portalpop - remove portal on the top of the stack & return it
|
||||
* be_currentportal - return the top portal on the portal stack
|
||||
* be_newportal - return a new portal.
|
||||
* be_portalinit - initialize backend portal expected to hold results.
|
||||
* be_printtup - add a tuple to a backend portal
|
||||
* be_portalinit - initialize backend portal administration
|
||||
* be_portalpush - add a portal to the top of the portal stack
|
||||
* be_portalpop - remove portal on the top of the stack & return it
|
||||
* be_currentportal - return the top portal on the portal stack
|
||||
* be_newportal - return a new portal.
|
||||
* be_portalinit - initialize backend portal expected to hold results.
|
||||
* be_printtup - add a tuple to a backend portal
|
||||
*
|
||||
* NOTES
|
||||
* Since backend user-defined operators can call queries
|
||||
* which in turn call user-defined operators can call queries...
|
||||
* we have to keep track of portals on a stack. BeginCommand()
|
||||
* puts portals on the stack and the PQ functions remove them.
|
||||
* Since backend user-defined operators can call queries
|
||||
* which in turn call user-defined operators can call queries...
|
||||
* we have to keep track of portals on a stack. BeginCommand()
|
||||
* puts portals on the stack and the PQ functions remove them.
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
@@ -48,274 +48,288 @@
|
||||
#include <access/printtup.h>
|
||||
|
||||
/* ----------------
|
||||
* backend portal stack for recursive PQexec calls
|
||||
* backend portal stack for recursive PQexec calls
|
||||
* ----------------
|
||||
*/
|
||||
static Dllist *be_portalstack;
|
||||
static Dllist *be_portalstack;
|
||||
|
||||
/* ----------------
|
||||
* be_portalinit - initialize backend portal administration
|
||||
* be_portalinit - initialize backend portal administration
|
||||
*
|
||||
* This is called once from InitPostgres() to initialize
|
||||
* the portal stack.
|
||||
* This is called once from InitPostgres() to initialize
|
||||
* the portal stack.
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
be_portalinit(void)
|
||||
{
|
||||
be_portalstack = DLNewList();
|
||||
be_portalstack = DLNewList();
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* be_portalpush - add a portal to the top of the portal stack
|
||||
* be_portalpush - add a portal to the top of the portal stack
|
||||
*
|
||||
* used by BeginCommand()
|
||||
* used by BeginCommand()
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
be_portalpush(PortalEntry *entry)
|
||||
be_portalpush(PortalEntry * entry)
|
||||
{
|
||||
DLAddTail(be_portalstack, DLNewElem(entry));
|
||||
DLAddTail(be_portalstack, DLNewElem(entry));
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* be_portalpop - remove the portal on the top of the stack & return it
|
||||
* be_portalpop - remove the portal on the top of the stack & return it
|
||||
*
|
||||
* used by PQexec()
|
||||
* used by PQexec()
|
||||
* ----------------
|
||||
*/
|
||||
PortalEntry *
|
||||
PortalEntry *
|
||||
be_portalpop(void)
|
||||
{
|
||||
PortalEntry *p;
|
||||
Dlelem* elt;
|
||||
elt = DLRemTail(be_portalstack);
|
||||
PortalEntry *p;
|
||||
Dlelem *elt;
|
||||
|
||||
elt = DLRemTail(be_portalstack);
|
||||
|
||||
p = (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
|
||||
DLFreeElem(elt);
|
||||
return p;
|
||||
|
||||
p = (elt ? (PortalEntry*)DLE_VAL(elt) : NULL);
|
||||
DLFreeElem(elt);
|
||||
return p;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* be_currentportal - return the top portal on the portal stack
|
||||
* be_currentportal - return the top portal on the portal stack
|
||||
*
|
||||
* used by be_printtup()
|
||||
* used by be_printtup()
|
||||
* ----------------
|
||||
*/
|
||||
PortalEntry *
|
||||
PortalEntry *
|
||||
be_currentportal(void)
|
||||
{
|
||||
Dlelem* elt;
|
||||
elt = DLGetTail(be_portalstack);
|
||||
return (elt ? (PortalEntry*)DLE_VAL(elt) : NULL);
|
||||
Dlelem *elt;
|
||||
|
||||
elt = DLGetTail(be_portalstack);
|
||||
return (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* be_newportal - return a new portal.
|
||||
* be_newportal - return a new portal.
|
||||
*
|
||||
* If the user-defined function does not specify a portal name,
|
||||
* we generate a unique one. Names are generated from a combination
|
||||
* of a postgres oid and an integer counter which is incremented
|
||||
* every time we ask for a local portal.
|
||||
* If the user-defined function does not specify a portal name,
|
||||
* we generate a unique one. Names are generated from a combination
|
||||
* of a postgres oid and an integer counter which is incremented
|
||||
* every time we ask for a local portal.
|
||||
*
|
||||
* used by BeginCommand()
|
||||
* used by BeginCommand()
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
static Oid be_portaloid;
|
||||
static Oid be_portaloid;
|
||||
static u_int be_portalcnt = 0;
|
||||
|
||||
PortalEntry *
|
||||
be_newportal(void)
|
||||
PortalEntry *
|
||||
be_newportal(void)
|
||||
{
|
||||
PortalEntry *entry;
|
||||
char buf[PortalNameLength];
|
||||
|
||||
/* ----------------
|
||||
* generate a new name
|
||||
* ----------------
|
||||
*/
|
||||
if (be_portalcnt == 0)
|
||||
be_portaloid = newoid();
|
||||
be_portalcnt++;
|
||||
sprintf(buf, "be_%d_%d", be_portaloid, be_portalcnt);
|
||||
|
||||
/* ----------------
|
||||
* initialize the new portal entry and keep track
|
||||
* of the current memory context for be_printtup().
|
||||
* This is important - otherwise whatever we allocate
|
||||
* will go away and the contents of the portal after
|
||||
* PQexec() returns will be meaningless.
|
||||
* ----------------
|
||||
*/
|
||||
entry = pbuf_setup(buf);
|
||||
entry->portalcxt = (Pointer) CurrentMemoryContext;
|
||||
|
||||
return entry;
|
||||
PortalEntry *entry;
|
||||
char buf[PortalNameLength];
|
||||
|
||||
/* ----------------
|
||||
* generate a new name
|
||||
* ----------------
|
||||
*/
|
||||
if (be_portalcnt == 0)
|
||||
be_portaloid = newoid();
|
||||
be_portalcnt++;
|
||||
sprintf(buf, "be_%d_%d", be_portaloid, be_portalcnt);
|
||||
|
||||
/* ----------------
|
||||
* initialize the new portal entry and keep track
|
||||
* of the current memory context for be_printtup().
|
||||
* This is important - otherwise whatever we allocate
|
||||
* will go away and the contents of the portal after
|
||||
* PQexec() returns will be meaningless.
|
||||
* ----------------
|
||||
*/
|
||||
entry = pbuf_setup(buf);
|
||||
entry->portalcxt = (Pointer) CurrentMemoryContext;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* be_typeinit - initialize backend portal expected to hold
|
||||
* query results.
|
||||
* be_typeinit - initialize backend portal expected to hold
|
||||
* query results.
|
||||
*
|
||||
* used by BeginCommand()
|
||||
* used by BeginCommand()
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
be_typeinit(PortalEntry *entry,
|
||||
TupleDesc tupDesc,
|
||||
int natts)
|
||||
be_typeinit(PortalEntry * entry,
|
||||
TupleDesc tupDesc,
|
||||
int natts)
|
||||
{
|
||||
PortalBuffer *portal;
|
||||
GroupBuffer *group;
|
||||
int i;
|
||||
AttributeTupleForm *attrs = tupDesc->attrs;
|
||||
|
||||
/* ----------------
|
||||
* add a new portal group to the portal
|
||||
* ----------------
|
||||
*/
|
||||
portal = entry->portal;
|
||||
portal->no_groups++;
|
||||
portal->groups = group = pbuf_addGroup(portal);
|
||||
group->no_fields = natts;
|
||||
|
||||
/* ----------------
|
||||
* initialize portal group type info
|
||||
* ----------------
|
||||
*/
|
||||
if (natts > 0) {
|
||||
group->types = pbuf_addTypes(natts);
|
||||
for (i = 0; i < natts; ++i) {
|
||||
strncpy(group->types[i].name, attrs[i]->attname.data, NAMEDATALEN);
|
||||
group->types[i].adtid = attrs[i]->atttypid;
|
||||
group->types[i].adtsize = attrs[i]->attlen;
|
||||
PortalBuffer *portal;
|
||||
GroupBuffer *group;
|
||||
int i;
|
||||
AttributeTupleForm *attrs = tupDesc->attrs;
|
||||
|
||||
/* ----------------
|
||||
* add a new portal group to the portal
|
||||
* ----------------
|
||||
*/
|
||||
portal = entry->portal;
|
||||
portal->no_groups++;
|
||||
portal->groups = group = pbuf_addGroup(portal);
|
||||
group->no_fields = natts;
|
||||
|
||||
/* ----------------
|
||||
* initialize portal group type info
|
||||
* ----------------
|
||||
*/
|
||||
if (natts > 0)
|
||||
{
|
||||
group->types = pbuf_addTypes(natts);
|
||||
for (i = 0; i < natts; ++i)
|
||||
{
|
||||
strncpy(group->types[i].name, attrs[i]->attname.data, NAMEDATALEN);
|
||||
group->types[i].adtid = attrs[i]->atttypid;
|
||||
group->types[i].adtsize = attrs[i]->attlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* be_printtup - add a tuple to a backend portal
|
||||
* be_printtup - add a tuple to a backend portal
|
||||
*
|
||||
* used indirectly by ExecRetrieve()
|
||||
* used indirectly by ExecRetrieve()
|
||||
*
|
||||
* This code is pretty much copied from printtup(), dump_type()
|
||||
* and dump_data(). -cim 2/12/91
|
||||
* This code is pretty much copied from printtup(), dump_type()
|
||||
* and dump_data(). -cim 2/12/91
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
be_printtup(HeapTuple tuple, TupleDesc typeinfo)
|
||||
{
|
||||
int i;
|
||||
char *attr;
|
||||
bool isnull;
|
||||
Oid typoutput;
|
||||
|
||||
PortalEntry *entry = NULL;
|
||||
PortalBuffer *portal = NULL;
|
||||
GroupBuffer *group = NULL ;
|
||||
TupleBlock *tuples = NULL;
|
||||
char **values;
|
||||
int *lengths;
|
||||
|
||||
MemoryContext savecxt;
|
||||
|
||||
/* ----------------
|
||||
* get the current portal and group
|
||||
* ----------------
|
||||
*/
|
||||
entry = be_currentportal();
|
||||
portal = entry->portal;
|
||||
group = portal->groups;
|
||||
|
||||
/* ----------------
|
||||
* switch to the portal's memory context so that
|
||||
* the tuples we allocate are returned to the user.
|
||||
* ----------------
|
||||
*/
|
||||
savecxt = MemoryContextSwitchTo((MemoryContext)entry->portalcxt);
|
||||
|
||||
/* ----------------
|
||||
* If no tuple block yet, allocate one.
|
||||
* If the current block is full, allocate another one.
|
||||
* ----------------
|
||||
*/
|
||||
if (group->tuples == NULL) {
|
||||
tuples = group->tuples = pbuf_addTuples();
|
||||
tuples->tuple_index = 0;
|
||||
} else {
|
||||
tuples = group->tuples;
|
||||
/* walk to the end of the linked list of TupleBlocks */
|
||||
while (tuples->next)
|
||||
tuples = tuples->next;
|
||||
/* now, tuples is the last TupleBlock, check to see if it is full.
|
||||
If so, allocate a new TupleBlock and add it to the end of
|
||||
the chain */
|
||||
|
||||
if (tuples->tuple_index == TupleBlockSize) {
|
||||
tuples->next = pbuf_addTuples();
|
||||
tuples = tuples->next;
|
||||
tuples->tuple_index = 0;
|
||||
int i;
|
||||
char *attr;
|
||||
bool isnull;
|
||||
Oid typoutput;
|
||||
|
||||
PortalEntry *entry = NULL;
|
||||
PortalBuffer *portal = NULL;
|
||||
GroupBuffer *group = NULL;
|
||||
TupleBlock *tuples = NULL;
|
||||
char **values;
|
||||
int *lengths;
|
||||
|
||||
MemoryContext savecxt;
|
||||
|
||||
/* ----------------
|
||||
* get the current portal and group
|
||||
* ----------------
|
||||
*/
|
||||
entry = be_currentportal();
|
||||
portal = entry->portal;
|
||||
group = portal->groups;
|
||||
|
||||
/* ----------------
|
||||
* switch to the portal's memory context so that
|
||||
* the tuples we allocate are returned to the user.
|
||||
* ----------------
|
||||
*/
|
||||
savecxt = MemoryContextSwitchTo((MemoryContext) entry->portalcxt);
|
||||
|
||||
/* ----------------
|
||||
* If no tuple block yet, allocate one.
|
||||
* If the current block is full, allocate another one.
|
||||
* ----------------
|
||||
*/
|
||||
if (group->tuples == NULL)
|
||||
{
|
||||
tuples = group->tuples = pbuf_addTuples();
|
||||
tuples->tuple_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* Allocate space for a tuple.
|
||||
* ----------------
|
||||
*/
|
||||
tuples->values[tuples->tuple_index] = pbuf_addTuple(tuple->t_natts);
|
||||
tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_natts);
|
||||
/* ----------------
|
||||
* copy printable representations of the tuple's attributes
|
||||
* to the portal.
|
||||
*
|
||||
* This seems silly, because the user's function which is calling
|
||||
* PQexec() or PQfn() will probably just convert this back into the
|
||||
* internal form anyways, but the point here is to provide a uniform
|
||||
* libpq interface and this is how the fe libpq interface currently
|
||||
* works. Pretty soon we'll have to add code to let the fe or be
|
||||
* select the desired data representation and then deal with that.
|
||||
* This should not be too hard, as there already exist typrecieve()
|
||||
* and typsend() procedures for user-defined types (see pg_type.h)
|
||||
* -cim 2/11/91
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
values = tuples->values[tuples->tuple_index];
|
||||
lengths = tuples->lengths[tuples->tuple_index];
|
||||
|
||||
for (i = 0; i < tuple->t_natts; i++) {
|
||||
attr = heap_getattr(tuple, InvalidBuffer, i+1, typeinfo, &isnull);
|
||||
typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
|
||||
|
||||
lengths[i] = typeinfo->attrs[i]->attlen;
|
||||
|
||||
if (lengths[i] == -1) /* variable length attribute */
|
||||
if (!isnull)
|
||||
lengths[i] = VARSIZE(attr)-VARHDRSZ;
|
||||
else
|
||||
lengths[i] = 0;
|
||||
|
||||
if (!isnull && OidIsValid(typoutput)) {
|
||||
values[i] = fmgr(typoutput, attr, gettypelem(typeinfo->attrs[i]->atttypid));
|
||||
} else
|
||||
values[i] = NULL;
|
||||
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* increment tuple group counters
|
||||
* ----------------
|
||||
*/
|
||||
portal->no_tuples++;
|
||||
group->no_tuples++;
|
||||
tuples->tuple_index++;
|
||||
|
||||
/* ----------------
|
||||
* return to the original memory context
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(savecxt);
|
||||
else
|
||||
{
|
||||
tuples = group->tuples;
|
||||
/* walk to the end of the linked list of TupleBlocks */
|
||||
while (tuples->next)
|
||||
tuples = tuples->next;
|
||||
|
||||
/*
|
||||
* now, tuples is the last TupleBlock, check to see if it is full.
|
||||
* If so, allocate a new TupleBlock and add it to the end of the
|
||||
* chain
|
||||
*/
|
||||
|
||||
if (tuples->tuple_index == TupleBlockSize)
|
||||
{
|
||||
tuples->next = pbuf_addTuples();
|
||||
tuples = tuples->next;
|
||||
tuples->tuple_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* Allocate space for a tuple.
|
||||
* ----------------
|
||||
*/
|
||||
tuples->values[tuples->tuple_index] = pbuf_addTuple(tuple->t_natts);
|
||||
tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_natts);
|
||||
/* ----------------
|
||||
* copy printable representations of the tuple's attributes
|
||||
* to the portal.
|
||||
*
|
||||
* This seems silly, because the user's function which is calling
|
||||
* PQexec() or PQfn() will probably just convert this back into the
|
||||
* internal form anyways, but the point here is to provide a uniform
|
||||
* libpq interface and this is how the fe libpq interface currently
|
||||
* works. Pretty soon we'll have to add code to let the fe or be
|
||||
* select the desired data representation and then deal with that.
|
||||
* This should not be too hard, as there already exist typrecieve()
|
||||
* and typsend() procedures for user-defined types (see pg_type.h)
|
||||
* -cim 2/11/91
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
values = tuples->values[tuples->tuple_index];
|
||||
lengths = tuples->lengths[tuples->tuple_index];
|
||||
|
||||
for (i = 0; i < tuple->t_natts; i++)
|
||||
{
|
||||
attr = heap_getattr(tuple, InvalidBuffer, i + 1, typeinfo, &isnull);
|
||||
typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
|
||||
|
||||
lengths[i] = typeinfo->attrs[i]->attlen;
|
||||
|
||||
if (lengths[i] == -1) /* variable length attribute */
|
||||
if (!isnull)
|
||||
lengths[i] = VARSIZE(attr) - VARHDRSZ;
|
||||
else
|
||||
lengths[i] = 0;
|
||||
|
||||
if (!isnull && OidIsValid(typoutput))
|
||||
{
|
||||
values[i] = fmgr(typoutput, attr, gettypelem(typeinfo->attrs[i]->atttypid));
|
||||
}
|
||||
else
|
||||
values[i] = NULL;
|
||||
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* increment tuple group counters
|
||||
* ----------------
|
||||
*/
|
||||
portal->no_tuples++;
|
||||
group->no_tuples++;
|
||||
tuples->tuple_index++;
|
||||
|
||||
/* ----------------
|
||||
* return to the original memory context
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(savecxt);
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* be-fsstubs.c--
|
||||
* support for filesystem operations on large objects
|
||||
* support for filesystem operations on large objects
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.12 1997/08/12 22:52:48 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.13 1997/09/07 04:42:15 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This should be moved to a more appropriate place. It is here
|
||||
* for lack of a better place.
|
||||
* This should be moved to a more appropriate place. It is here
|
||||
* for lack of a better place.
|
||||
*
|
||||
* Builtin functions for open/close/read/write operations on large objects.
|
||||
* Builtin functions for open/close/read/write operations on large objects.
|
||||
*
|
||||
* These functions operate in the current portal variable context, which
|
||||
* means the large object descriptors hang around between transactions and
|
||||
* are not deallocated until explicitly closed, or until the portal is
|
||||
* closed.
|
||||
* These functions operate in the current portal variable context, which
|
||||
* means the large object descriptors hang around between transactions and
|
||||
* are not deallocated until explicitly closed, or until the portal is
|
||||
* closed.
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -37,340 +37,364 @@
|
||||
#include <utils/memutils.h>
|
||||
#include <lib/fstack.h>
|
||||
#include <utils/mcxt.h>
|
||||
#include <storage/fd.h> /* for O_ */
|
||||
#include <storage/fd.h> /* for O_ */
|
||||
#include <storage/large_object.h>
|
||||
#include <libpq/be-fsstubs.h>
|
||||
|
||||
/*#define FSDB 1*/
|
||||
#define MAX_LOBJ_FDS 256
|
||||
|
||||
static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
|
||||
static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
|
||||
|
||||
static GlobalMemory fscxt = NULL;
|
||||
|
||||
|
||||
static int newLOfd(LargeObjectDesc *lobjCookie);
|
||||
static void deleteLOfd(int fd);
|
||||
static int newLOfd(LargeObjectDesc * lobjCookie);
|
||||
static void deleteLOfd(int fd);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* File Interfaces for Large Objects
|
||||
* File Interfaces for Large Objects
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
lo_open(Oid lobjId, int mode)
|
||||
{
|
||||
LargeObjectDesc *lobjDesc;
|
||||
int fd;
|
||||
MemoryContext currentContext;
|
||||
|
||||
LargeObjectDesc *lobjDesc;
|
||||
int fd;
|
||||
MemoryContext currentContext;
|
||||
|
||||
#if FSDB
|
||||
elog(NOTICE,"LOopen(%d,%d)",lobjId,mode);
|
||||
elog(NOTICE, "LOopen(%d,%d)", lobjId, mode);
|
||||
#endif
|
||||
|
||||
if (fscxt == NULL) {
|
||||
fscxt = CreateGlobalMemory("Filesystem");
|
||||
}
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
|
||||
if (fscxt == NULL)
|
||||
{
|
||||
fscxt = CreateGlobalMemory("Filesystem");
|
||||
}
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
|
||||
lobjDesc = inv_open(lobjId, mode);
|
||||
|
||||
if (lobjDesc == NULL) { /* lookup failed */
|
||||
lobjDesc = inv_open(lobjId, mode);
|
||||
|
||||
if (lobjDesc == NULL)
|
||||
{ /* lookup failed */
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
#if FSDB
|
||||
elog(NOTICE, "cannot open large object %d", lobjId);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = newLOfd(lobjDesc);
|
||||
|
||||
/* switch context back to orig. */
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
#if FSDB
|
||||
elog(NOTICE,"cannot open large object %d", lobjId);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = newLOfd(lobjDesc);
|
||||
|
||||
/* switch context back to orig. */
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
|
||||
return fd;
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
lo_close(int fd)
|
||||
{
|
||||
MemoryContext currentContext;
|
||||
MemoryContext currentContext;
|
||||
|
||||
if (fd >= MAX_LOBJ_FDS) {
|
||||
elog(WARN,"lo_close: large obj descriptor (%d) out of range", fd);
|
||||
return -2;
|
||||
}
|
||||
if (cookies[fd] == NULL) {
|
||||
elog(WARN,"lo_close: invalid large obj descriptor (%d)", fd);
|
||||
return -3;
|
||||
}
|
||||
if (fd >= MAX_LOBJ_FDS)
|
||||
{
|
||||
elog(WARN, "lo_close: large obj descriptor (%d) out of range", fd);
|
||||
return -2;
|
||||
}
|
||||
if (cookies[fd] == NULL)
|
||||
{
|
||||
elog(WARN, "lo_close: invalid large obj descriptor (%d)", fd);
|
||||
return -3;
|
||||
}
|
||||
#if FSDB
|
||||
elog(NOTICE,"LOclose(%d)",fd);
|
||||
elog(NOTICE, "LOclose(%d)", fd);
|
||||
#endif
|
||||
|
||||
Assert(fscxt != NULL);
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
|
||||
Assert(fscxt != NULL);
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
|
||||
inv_close(cookies[fd]);
|
||||
inv_close(cookies[fd]);
|
||||
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
|
||||
deleteLOfd(fd);
|
||||
return 0;
|
||||
deleteLOfd(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We assume the large object supports byte oriented reads and seeks so
|
||||
* that our work is easier.
|
||||
* We assume the large object supports byte oriented reads and seeks so
|
||||
* that our work is easier.
|
||||
*/
|
||||
int
|
||||
lo_read(int fd, char *buf, int len)
|
||||
{
|
||||
Assert(cookies[fd]!=NULL);
|
||||
return inv_read(cookies[fd], buf, len);
|
||||
Assert(cookies[fd] != NULL);
|
||||
return inv_read(cookies[fd], buf, len);
|
||||
}
|
||||
|
||||
int
|
||||
lo_write(int fd, char *buf, int len)
|
||||
{
|
||||
Assert(cookies[fd]!=NULL);
|
||||
return inv_write(cookies[fd], buf, len);
|
||||
Assert(cookies[fd] != NULL);
|
||||
return inv_write(cookies[fd], buf, len);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lo_lseek(int fd, int offset, int whence)
|
||||
{
|
||||
MemoryContext currentContext;
|
||||
int ret;
|
||||
MemoryContext currentContext;
|
||||
int ret;
|
||||
|
||||
if (fd >= MAX_LOBJ_FDS) {
|
||||
elog(WARN,"lo_seek: large obj descriptor (%d) out of range", fd);
|
||||
return -2;
|
||||
}
|
||||
if (fd >= MAX_LOBJ_FDS)
|
||||
{
|
||||
elog(WARN, "lo_seek: large obj descriptor (%d) out of range", fd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
|
||||
ret = inv_seek(cookies[fd], offset, whence);
|
||||
ret = inv_seek(cookies[fd], offset, whence);
|
||||
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Oid
|
||||
lo_creat(int mode)
|
||||
{
|
||||
LargeObjectDesc *lobjDesc;
|
||||
MemoryContext currentContext;
|
||||
Oid lobjId;
|
||||
|
||||
if (fscxt == NULL) {
|
||||
fscxt = CreateGlobalMemory("Filesystem");
|
||||
}
|
||||
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
|
||||
|
||||
lobjDesc = inv_create(mode);
|
||||
|
||||
if (lobjDesc == NULL) {
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
return InvalidOid;
|
||||
}
|
||||
LargeObjectDesc *lobjDesc;
|
||||
MemoryContext currentContext;
|
||||
Oid lobjId;
|
||||
|
||||
lobjId = lobjDesc->heap_r->rd_id;
|
||||
|
||||
inv_close(lobjDesc);
|
||||
|
||||
/* switch context back to original memory context */
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
|
||||
return lobjId;
|
||||
if (fscxt == NULL)
|
||||
{
|
||||
fscxt = CreateGlobalMemory("Filesystem");
|
||||
}
|
||||
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
|
||||
lobjDesc = inv_create(mode);
|
||||
|
||||
if (lobjDesc == NULL)
|
||||
{
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
lobjId = lobjDesc->heap_r->rd_id;
|
||||
|
||||
inv_close(lobjDesc);
|
||||
|
||||
/* switch context back to original memory context */
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
|
||||
return lobjId;
|
||||
}
|
||||
|
||||
int
|
||||
lo_tell(int fd)
|
||||
{
|
||||
if (fd >= MAX_LOBJ_FDS) {
|
||||
elog(WARN,"lo_tell: large object descriptor (%d) out of range",fd);
|
||||
return -2;
|
||||
}
|
||||
if (cookies[fd] == NULL) {
|
||||
elog(WARN,"lo_tell: invalid large object descriptor (%d)",fd);
|
||||
return -3;
|
||||
}
|
||||
return inv_tell(cookies[fd]);
|
||||
if (fd >= MAX_LOBJ_FDS)
|
||||
{
|
||||
elog(WARN, "lo_tell: large object descriptor (%d) out of range", fd);
|
||||
return -2;
|
||||
}
|
||||
if (cookies[fd] == NULL)
|
||||
{
|
||||
elog(WARN, "lo_tell: invalid large object descriptor (%d)", fd);
|
||||
return -3;
|
||||
}
|
||||
return inv_tell(cookies[fd]);
|
||||
}
|
||||
|
||||
int
|
||||
lo_unlink(Oid lobjId)
|
||||
{
|
||||
return (inv_destroy(lobjId));
|
||||
return (inv_destroy(lobjId));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Read/Write using varlena
|
||||
* Read/Write using varlena
|
||||
*****************************************************************************/
|
||||
|
||||
struct varlena *
|
||||
loread(int fd, int len)
|
||||
{
|
||||
struct varlena *retval;
|
||||
int totalread = 0;
|
||||
|
||||
retval = (struct varlena *)palloc(sizeof(int32) + len);
|
||||
totalread = lo_read(fd, VARDATA(retval), len);
|
||||
VARSIZE(retval) = totalread + sizeof(int32);
|
||||
|
||||
return retval;
|
||||
struct varlena *retval;
|
||||
int totalread = 0;
|
||||
|
||||
retval = (struct varlena *) palloc(sizeof(int32) + len);
|
||||
totalread = lo_read(fd, VARDATA(retval), len);
|
||||
VARSIZE(retval) = totalread + sizeof(int32);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int lowrite(int fd, struct varlena *wbuf)
|
||||
int
|
||||
lowrite(int fd, struct varlena * wbuf)
|
||||
{
|
||||
int totalwritten;
|
||||
int bytestowrite;
|
||||
|
||||
bytestowrite = VARSIZE(wbuf) - sizeof(int32);
|
||||
totalwritten = lo_write(fd, VARDATA(wbuf), bytestowrite);
|
||||
return totalwritten;
|
||||
int totalwritten;
|
||||
int bytestowrite;
|
||||
|
||||
bytestowrite = VARSIZE(wbuf) - sizeof(int32);
|
||||
totalwritten = lo_write(fd, VARDATA(wbuf), bytestowrite);
|
||||
return totalwritten;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Import/Export of Large Object
|
||||
* Import/Export of Large Object
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* lo_import -
|
||||
* imports a file as an (inversion) large object.
|
||||
* imports a file as an (inversion) large object.
|
||||
*/
|
||||
Oid
|
||||
lo_import(text *filename)
|
||||
lo_import(text * filename)
|
||||
{
|
||||
int fd;
|
||||
int nbytes, tmp;
|
||||
#define BUFSIZE 1024
|
||||
char buf[BUFSIZE];
|
||||
char fnamebuf[8192];
|
||||
LargeObjectDesc *lobj;
|
||||
Oid lobjOid;
|
||||
int fd;
|
||||
int nbytes,
|
||||
tmp;
|
||||
|
||||
/*
|
||||
* open the file to be read in
|
||||
*/
|
||||
strNcpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ);
|
||||
fd = open(fnamebuf, O_RDONLY, 0666);
|
||||
if (fd < 0) { /* error */
|
||||
elog(WARN, "be_lo_import: can't open unix file\"%s\"\n",
|
||||
fnamebuf);
|
||||
}
|
||||
#define BUFSIZE 1024
|
||||
char buf[BUFSIZE];
|
||||
char fnamebuf[8192];
|
||||
LargeObjectDesc *lobj;
|
||||
Oid lobjOid;
|
||||
|
||||
/*
|
||||
* create an inversion "object"
|
||||
*/
|
||||
lobj = inv_create(INV_READ|INV_WRITE);
|
||||
if (lobj == NULL) {
|
||||
elog(WARN, "lo_import: can't create inv object for \"%s\"",
|
||||
fnamebuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* the oid for the large object is just the oid of the relation
|
||||
* XInv??? which contains the data.
|
||||
*/
|
||||
lobjOid = lobj->heap_r->rd_id;
|
||||
|
||||
/*
|
||||
* read in from the Unix file and write to the inversion file
|
||||
*/
|
||||
while ((nbytes = read(fd, buf, BUFSIZE)) > 0) {
|
||||
tmp = inv_write(lobj, buf, nbytes);
|
||||
if (tmp < nbytes) {
|
||||
elog(WARN, "lo_import: error while reading \"%s\"",
|
||||
fnamebuf);
|
||||
/*
|
||||
* open the file to be read in
|
||||
*/
|
||||
strNcpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ);
|
||||
fd = open(fnamebuf, O_RDONLY, 0666);
|
||||
if (fd < 0)
|
||||
{ /* error */
|
||||
elog(WARN, "be_lo_import: can't open unix file\"%s\"\n",
|
||||
fnamebuf);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
inv_close(lobj);
|
||||
/*
|
||||
* create an inversion "object"
|
||||
*/
|
||||
lobj = inv_create(INV_READ | INV_WRITE);
|
||||
if (lobj == NULL)
|
||||
{
|
||||
elog(WARN, "lo_import: can't create inv object for \"%s\"",
|
||||
fnamebuf);
|
||||
}
|
||||
|
||||
return lobjOid;
|
||||
/*
|
||||
* the oid for the large object is just the oid of the relation
|
||||
* XInv??? which contains the data.
|
||||
*/
|
||||
lobjOid = lobj->heap_r->rd_id;
|
||||
|
||||
/*
|
||||
* read in from the Unix file and write to the inversion file
|
||||
*/
|
||||
while ((nbytes = read(fd, buf, BUFSIZE)) > 0)
|
||||
{
|
||||
tmp = inv_write(lobj, buf, nbytes);
|
||||
if (tmp < nbytes)
|
||||
{
|
||||
elog(WARN, "lo_import: error while reading \"%s\"",
|
||||
fnamebuf);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
inv_close(lobj);
|
||||
|
||||
return lobjOid;
|
||||
}
|
||||
|
||||
/*
|
||||
* lo_export -
|
||||
* exports an (inversion) large object.
|
||||
* exports an (inversion) large object.
|
||||
*/
|
||||
int4
|
||||
lo_export(Oid lobjId, text *filename)
|
||||
lo_export(Oid lobjId, text * filename)
|
||||
{
|
||||
int fd;
|
||||
int nbytes, tmp;
|
||||
#define BUFSIZE 1024
|
||||
char buf[BUFSIZE];
|
||||
char fnamebuf[8192];
|
||||
LargeObjectDesc *lobj;
|
||||
mode_t oumask;
|
||||
int fd;
|
||||
int nbytes,
|
||||
tmp;
|
||||
|
||||
/*
|
||||
* create an inversion "object"
|
||||
*/
|
||||
lobj = inv_open(lobjId, INV_READ);
|
||||
if (lobj == NULL) {
|
||||
elog(WARN, "lo_export: can't open inv object %d",
|
||||
lobjId);
|
||||
}
|
||||
#define BUFSIZE 1024
|
||||
char buf[BUFSIZE];
|
||||
char fnamebuf[8192];
|
||||
LargeObjectDesc *lobj;
|
||||
mode_t oumask;
|
||||
|
||||
/*
|
||||
* open the file to be written to
|
||||
*/
|
||||
oumask = umask((mode_t) 0);
|
||||
strNcpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ);
|
||||
fd = open(fnamebuf, O_CREAT|O_WRONLY, 0666);
|
||||
umask(oumask);
|
||||
if (fd < 0) { /* error */
|
||||
elog(WARN, "lo_export: can't open unix file\"%s\"",
|
||||
fnamebuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* read in from the Unix file and write to the inversion file
|
||||
*/
|
||||
while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0) {
|
||||
tmp = write(fd, buf, nbytes);
|
||||
if (tmp < nbytes) {
|
||||
elog(WARN, "lo_export: error while writing \"%s\"",
|
||||
fnamebuf);
|
||||
/*
|
||||
* create an inversion "object"
|
||||
*/
|
||||
lobj = inv_open(lobjId, INV_READ);
|
||||
if (lobj == NULL)
|
||||
{
|
||||
elog(WARN, "lo_export: can't open inv object %d",
|
||||
lobjId);
|
||||
}
|
||||
}
|
||||
|
||||
inv_close(lobj);
|
||||
close(fd);
|
||||
/*
|
||||
* open the file to be written to
|
||||
*/
|
||||
oumask = umask((mode_t) 0);
|
||||
strNcpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ);
|
||||
fd = open(fnamebuf, O_CREAT | O_WRONLY, 0666);
|
||||
umask(oumask);
|
||||
if (fd < 0)
|
||||
{ /* error */
|
||||
elog(WARN, "lo_export: can't open unix file\"%s\"",
|
||||
fnamebuf);
|
||||
}
|
||||
|
||||
return 1;
|
||||
/*
|
||||
* read in from the Unix file and write to the inversion file
|
||||
*/
|
||||
while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0)
|
||||
{
|
||||
tmp = write(fd, buf, nbytes);
|
||||
if (tmp < nbytes)
|
||||
{
|
||||
elog(WARN, "lo_export: error while writing \"%s\"",
|
||||
fnamebuf);
|
||||
}
|
||||
}
|
||||
|
||||
inv_close(lobj);
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Support routines for this file
|
||||
* Support routines for this file
|
||||
*****************************************************************************/
|
||||
|
||||
static int
|
||||
newLOfd(LargeObjectDesc *lobjCookie)
|
||||
newLOfd(LargeObjectDesc * lobjCookie)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_LOBJ_FDS; i++) {
|
||||
|
||||
if (cookies[i] == NULL) {
|
||||
cookies[i] = lobjCookie;
|
||||
return i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_LOBJ_FDS; i++)
|
||||
{
|
||||
|
||||
if (cookies[i] == NULL)
|
||||
{
|
||||
cookies[i] = lobjCookie;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
deleteLOfd(int fd)
|
||||
{
|
||||
cookies[fd] = NULL;
|
||||
cookies[fd] = NULL;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* be-pqexec.c--
|
||||
* support for executing POSTGRES commands and functions from a
|
||||
* user-defined function in a backend.
|
||||
* support for executing POSTGRES commands and functions from a
|
||||
* user-defined function in a backend.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.4 1997/08/19 21:31:31 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.5 1997/09/07 04:42:17 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* INTERFACE ROUTINES
|
||||
* PQfn - call a POSTGRES function
|
||||
* PQexec - execute a POSTGRES query
|
||||
*
|
||||
* PQfn - call a POSTGRES function
|
||||
* PQexec - execute a POSTGRES query
|
||||
*
|
||||
* NOTES
|
||||
* These routines are compiled into the postgres backend.
|
||||
* These routines are compiled into the postgres backend.
|
||||
*/
|
||||
#include <postgres.h>
|
||||
|
||||
@@ -32,356 +32,395 @@
|
||||
#include <utils/exc.h>
|
||||
#include <utils/builtins.h>
|
||||
#ifndef HAVE_MEMMOVE
|
||||
# include <regex/utils.h>
|
||||
#include <regex/utils.h>
|
||||
#else
|
||||
# include <string.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
static char *strmake(char *str, int len);
|
||||
static char *strmake(char *str, int len);
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* PQ interface routines
|
||||
* PQ interface routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* PQfn - Send a function call to the POSTGRES backend.
|
||||
* PQfn - Send a function call to the POSTGRES backend.
|
||||
*
|
||||
* fnid : function id
|
||||
* result_buf : pointer to result buffer (&int if integer)
|
||||
* result_len : length of return value.
|
||||
* result_is_int : If the result is an integer, this must be non-zero
|
||||
* args : pointer to a NULL terminated arg array.
|
||||
* (length, if integer, and result-pointer)
|
||||
* nargs : # of arguments in args array.
|
||||
* fnid : function id
|
||||
* result_buf : pointer to result buffer (&int if integer)
|
||||
* result_len : length of return value.
|
||||
* result_is_int : If the result is an integer, this must be non-zero
|
||||
* args : pointer to a NULL terminated arg array.
|
||||
* (length, if integer, and result-pointer)
|
||||
* nargs : # of arguments in args array.
|
||||
*
|
||||
* This code scavanged from HandleFunctionRequest() in tcop/fastpath.h
|
||||
* This code scavanged from HandleFunctionRequest() in tcop/fastpath.h
|
||||
* ----------------
|
||||
*/
|
||||
char *
|
||||
char *
|
||||
PQfn(int fnid,
|
||||
int *result_buf, /* can't use void, dec compiler barfs */
|
||||
int result_len,
|
||||
int result_is_int,
|
||||
PQArgBlock *args,
|
||||
int nargs)
|
||||
int *result_buf, /* can't use void, dec compiler barfs */
|
||||
int result_len,
|
||||
int result_is_int,
|
||||
PQArgBlock * args,
|
||||
int nargs)
|
||||
{
|
||||
char *retval; /* XXX - should be datum, maybe ? */
|
||||
char *arg[8];
|
||||
int i;
|
||||
|
||||
/* ----------------
|
||||
* fill args[] array
|
||||
* ----------------
|
||||
*/
|
||||
for (i = 0; i < nargs; i++) {
|
||||
if (args[i].len == VAR_LENGTH_ARG) {
|
||||
arg[i] = (char*) args[i].u.ptr;
|
||||
} else if (args[i].len > 4) {
|
||||
elog(WARN,"arg_length of argument %d too long",i);
|
||||
} else {
|
||||
arg[i] = (char*)args[i].u.integer;
|
||||
char *retval; /* XXX - should be datum, maybe ? */
|
||||
char *arg[8];
|
||||
int i;
|
||||
|
||||
/* ----------------
|
||||
* fill args[] array
|
||||
* ----------------
|
||||
*/
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
if (args[i].len == VAR_LENGTH_ARG)
|
||||
{
|
||||
arg[i] = (char *) args[i].u.ptr;
|
||||
}
|
||||
else if (args[i].len > 4)
|
||||
{
|
||||
elog(WARN, "arg_length of argument %d too long", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
arg[i] = (char *) args[i].u.integer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* call the postgres function manager
|
||||
* ----------------
|
||||
*/
|
||||
retval = (char *)
|
||||
fmgr(fnid, arg[0], arg[1], arg[2], arg[3],
|
||||
arg[4], arg[5], arg[6], arg[7]);
|
||||
|
||||
/* ----------------
|
||||
* put the result in the buffer the user specified and
|
||||
* return the proper code.
|
||||
* ----------------
|
||||
*/
|
||||
if (retval == (char *) NULL) /* void retval */
|
||||
return "0";
|
||||
|
||||
if (result_is_int) {
|
||||
*result_buf = (int) retval;
|
||||
} else {
|
||||
memmove(result_buf, retval, result_len);
|
||||
}
|
||||
return "G";
|
||||
|
||||
/* ----------------
|
||||
* call the postgres function manager
|
||||
* ----------------
|
||||
*/
|
||||
retval = (char *)
|
||||
fmgr(fnid, arg[0], arg[1], arg[2], arg[3],
|
||||
arg[4], arg[5], arg[6], arg[7]);
|
||||
|
||||
/* ----------------
|
||||
* put the result in the buffer the user specified and
|
||||
* return the proper code.
|
||||
* ----------------
|
||||
*/
|
||||
if (retval == (char *) NULL)/* void retval */
|
||||
return "0";
|
||||
|
||||
if (result_is_int)
|
||||
{
|
||||
*result_buf = (int) retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(result_buf, retval, result_len);
|
||||
}
|
||||
return "G";
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PQexec - Send a query to the POSTGRES backend
|
||||
* PQexec - Send a query to the POSTGRES backend
|
||||
*
|
||||
* The return value is a string.
|
||||
* If 0 or more tuples fetched from the backend, return "P portal-name".
|
||||
* If a query is does not return tuples, return "C query-command".
|
||||
* If there is an error: return "E error-message".
|
||||
* The return value is a string.
|
||||
* If 0 or more tuples fetched from the backend, return "P portal-name".
|
||||
* If a query is does not return tuples, return "C query-command".
|
||||
* If there is an error: return "E error-message".
|
||||
*
|
||||
* Note: if we get a serious error or an elog(WARN), then PQexec never
|
||||
* returns because the system longjmp's back to the main loop.
|
||||
* Note: if we get a serious error or an elog(WARN), then PQexec never
|
||||
* returns because the system longjmp's back to the main loop.
|
||||
* ----------------
|
||||
*/
|
||||
char *
|
||||
char *
|
||||
PQexec(char *query)
|
||||
{
|
||||
PortalEntry *entry = NULL;
|
||||
char *result = NULL;
|
||||
|
||||
/* ----------------
|
||||
* create a new portal and put it on top of the portal stack.
|
||||
* ----------------
|
||||
*/
|
||||
entry = (PortalEntry *) be_newportal();
|
||||
be_portalpush(entry);
|
||||
|
||||
/* ----------------
|
||||
* pg_eval_dest will put the query results in a portal which will
|
||||
* end up on the top of the portal stack.
|
||||
* ----------------
|
||||
*/
|
||||
pg_eval_dest(query, (char **) NULL, (Oid *) NULL, 0, Local);
|
||||
|
||||
/* ----------------
|
||||
* pop the portal off the portal stack and return the
|
||||
* result. Note if result is null, we return C.
|
||||
* ----------------
|
||||
*/
|
||||
entry = (PortalEntry *) be_portalpop();
|
||||
result = entry->result;
|
||||
if (result == NULL) {
|
||||
char *PQE = "Cnull PQexec result";
|
||||
result = pstrdup(PQE);
|
||||
}
|
||||
|
||||
if (result[0] != 'P')
|
||||
PortalEntry *entry = NULL;
|
||||
char *result = NULL;
|
||||
|
||||
/* ----------------
|
||||
* create a new portal and put it on top of the portal stack.
|
||||
* ----------------
|
||||
*/
|
||||
entry = (PortalEntry *) be_newportal();
|
||||
be_portalpush(entry);
|
||||
|
||||
/* ----------------
|
||||
* pg_eval_dest will put the query results in a portal which will
|
||||
* end up on the top of the portal stack.
|
||||
* ----------------
|
||||
*/
|
||||
pg_eval_dest(query, (char **) NULL, (Oid *) NULL, 0, Local);
|
||||
|
||||
/* ----------------
|
||||
* pop the portal off the portal stack and return the
|
||||
* result. Note if result is null, we return C.
|
||||
* ----------------
|
||||
*/
|
||||
entry = (PortalEntry *) be_portalpop();
|
||||
result = entry->result;
|
||||
if (result == NULL)
|
||||
{
|
||||
/* some successful command was executed,
|
||||
but it's not one where we return the portal name so
|
||||
here we should be sure to clear out the portal
|
||||
(since the caller has no handle on it)
|
||||
*/
|
||||
pbuf_close(entry->name);
|
||||
|
||||
char *PQE = "Cnull PQexec result";
|
||||
|
||||
result = pstrdup(PQE);
|
||||
}
|
||||
return result;
|
||||
|
||||
if (result[0] != 'P')
|
||||
{
|
||||
|
||||
/*
|
||||
* some successful command was executed, but it's not one where we
|
||||
* return the portal name so here we should be sure to clear out
|
||||
* the portal (since the caller has no handle on it)
|
||||
*/
|
||||
pbuf_close(entry->name);
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* pqtest support
|
||||
* pqtest support
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* pqtest_PQexec takes a text query and returns the number of
|
||||
* tuples it returns. Note: there is no need to PQclear()
|
||||
* here - the memory will go away at end transaction.
|
||||
* pqtest_PQexec takes a text query and returns the number of
|
||||
* tuples it returns. Note: there is no need to PQclear()
|
||||
* here - the memory will go away at end transaction.
|
||||
* ----------------
|
||||
*/
|
||||
int
|
||||
pqtest_PQexec(char *q)
|
||||
{
|
||||
PortalBuffer *a;
|
||||
char *res;
|
||||
int t;
|
||||
|
||||
/* ----------------
|
||||
* execute the postgres query
|
||||
* ----------------
|
||||
*/
|
||||
res = PQexec(q);
|
||||
|
||||
/* ----------------
|
||||
* return number of tuples in portal or 0 if command returns no tuples.
|
||||
* ----------------
|
||||
*/
|
||||
t = 0;
|
||||
switch(res[0]) {
|
||||
case 'P':
|
||||
a = PQparray(&res[1]);
|
||||
if (a == NULL)
|
||||
elog(WARN, "pqtest_PQexec: PQparray could not find portal %s",
|
||||
res);
|
||||
|
||||
t = PQntuples(a);
|
||||
break;
|
||||
case 'C':
|
||||
break;
|
||||
default:
|
||||
elog(NOTICE, "pqtest_PQexec: PQexec(%s) returns %s", q, res);
|
||||
break;
|
||||
}
|
||||
|
||||
return t;
|
||||
PortalBuffer *a;
|
||||
char *res;
|
||||
int t;
|
||||
|
||||
/* ----------------
|
||||
* execute the postgres query
|
||||
* ----------------
|
||||
*/
|
||||
res = PQexec(q);
|
||||
|
||||
/* ----------------
|
||||
* return number of tuples in portal or 0 if command returns no tuples.
|
||||
* ----------------
|
||||
*/
|
||||
t = 0;
|
||||
switch (res[0])
|
||||
{
|
||||
case 'P':
|
||||
a = PQparray(&res[1]);
|
||||
if (a == NULL)
|
||||
elog(WARN, "pqtest_PQexec: PQparray could not find portal %s",
|
||||
res);
|
||||
|
||||
t = PQntuples(a);
|
||||
break;
|
||||
case 'C':
|
||||
break;
|
||||
default:
|
||||
elog(NOTICE, "pqtest_PQexec: PQexec(%s) returns %s", q, res);
|
||||
break;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* utilities for pqtest_PQfn()
|
||||
* utilities for pqtest_PQfn()
|
||||
* ----------------
|
||||
*/
|
||||
static char *
|
||||
static char *
|
||||
strmake(char *str, int len)
|
||||
{
|
||||
char *newstr;
|
||||
if (str == NULL) return NULL;
|
||||
if (len <= 0) len = strlen(str);
|
||||
|
||||
newstr = (char *) palloc((unsigned) len+1);
|
||||
strNcpy(newstr, str, len);
|
||||
newstr[len] = (char) 0;
|
||||
return newstr;
|
||||
char *newstr;
|
||||
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
if (len <= 0)
|
||||
len = strlen(str);
|
||||
|
||||
newstr = (char *) palloc((unsigned) len + 1);
|
||||
strNcpy(newstr, str, len);
|
||||
newstr[len] = (char) 0;
|
||||
return newstr;
|
||||
}
|
||||
|
||||
#define SKIP 0
|
||||
#define SCAN 1
|
||||
|
||||
static char spacestr[] = " ";
|
||||
static char spacestr[] = " ";
|
||||
|
||||
static int
|
||||
strparse(char *s, char **fields, int *offsets, int maxfields)
|
||||
{
|
||||
int len = strlen(s);
|
||||
char *cp = s, *end = cp + len, *ep;
|
||||
int parsed = 0;
|
||||
int mode = SKIP, i = 0;
|
||||
|
||||
if (*(end - 1) == '\n') end--;
|
||||
|
||||
for (i=0; i<maxfields; i++)
|
||||
fields[i] = spacestr;
|
||||
|
||||
i = 0;
|
||||
while (!parsed) {
|
||||
if (mode == SKIP) {
|
||||
|
||||
while ((cp < end) &&
|
||||
(*cp == ' ' || *cp == '\t'))
|
||||
cp++;
|
||||
if (cp < end) mode = SCAN;
|
||||
else parsed = 1;
|
||||
|
||||
} else {
|
||||
|
||||
ep = cp;
|
||||
while ((ep < end) && (*ep != ' ' && *ep != '\t'))
|
||||
ep++;
|
||||
|
||||
if (ep < end) mode = SKIP;
|
||||
else parsed = 1;
|
||||
|
||||
fields[i] = strmake(cp, ep - cp);
|
||||
if (offsets != NULL)
|
||||
offsets[i] = cp - s;
|
||||
|
||||
i++;
|
||||
cp = ep;
|
||||
if (i > maxfields)
|
||||
parsed = 1;
|
||||
|
||||
int len = strlen(s);
|
||||
char *cp = s,
|
||||
*end = cp + len,
|
||||
*ep;
|
||||
int parsed = 0;
|
||||
int mode = SKIP,
|
||||
i = 0;
|
||||
|
||||
if (*(end - 1) == '\n')
|
||||
end--;
|
||||
|
||||
for (i = 0; i < maxfields; i++)
|
||||
fields[i] = spacestr;
|
||||
|
||||
i = 0;
|
||||
while (!parsed)
|
||||
{
|
||||
if (mode == SKIP)
|
||||
{
|
||||
|
||||
while ((cp < end) &&
|
||||
(*cp == ' ' || *cp == '\t'))
|
||||
cp++;
|
||||
if (cp < end)
|
||||
mode = SCAN;
|
||||
else
|
||||
parsed = 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ep = cp;
|
||||
while ((ep < end) && (*ep != ' ' && *ep != '\t'))
|
||||
ep++;
|
||||
|
||||
if (ep < end)
|
||||
mode = SKIP;
|
||||
else
|
||||
parsed = 1;
|
||||
|
||||
fields[i] = strmake(cp, ep - cp);
|
||||
if (offsets != NULL)
|
||||
offsets[i] = cp - s;
|
||||
|
||||
i++;
|
||||
cp = ep;
|
||||
if (i > maxfields)
|
||||
parsed = 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* pqtest_PQfn converts it's string into a PQArgBlock and
|
||||
* calls the specified function, which is assumed to return
|
||||
* an integer value.
|
||||
* pqtest_PQfn converts it's string into a PQArgBlock and
|
||||
* calls the specified function, which is assumed to return
|
||||
* an integer value.
|
||||
* ----------------
|
||||
*/
|
||||
int
|
||||
pqtest_PQfn(char *q)
|
||||
{
|
||||
int k, j, i, v, f, offsets;
|
||||
char *fields[8];
|
||||
PQArgBlock pqargs[7];
|
||||
int res;
|
||||
char *pqres;
|
||||
|
||||
/* ----------------
|
||||
* parse q into fields
|
||||
* ----------------
|
||||
*/
|
||||
i = strparse(q, fields, &offsets, 8);
|
||||
printf("pqtest_PQfn: strparse returns %d fields\n", i); /* debug */
|
||||
if (i == 0)
|
||||
return -1;
|
||||
|
||||
/* ----------------
|
||||
* get the function id
|
||||
* ----------------
|
||||
*/
|
||||
f = atoi(fields[0]);
|
||||
printf("pqtest_PQfn: func is %d\n", f); /* debug */
|
||||
if (f == 0)
|
||||
return -1;
|
||||
|
||||
/* ----------------
|
||||
* build a PQArgBlock
|
||||
* ----------------
|
||||
*/
|
||||
for (j=1; j<i && j<8; j++) {
|
||||
k = j-1;
|
||||
v = atoi(fields[j]);
|
||||
if (v != 0 || (v == 0 && fields[j][0] == '0')) {
|
||||
pqargs[k].len = 4;
|
||||
pqargs[k].u.integer = v;
|
||||
printf("pqtest_PQfn: arg %d is int %d\n", k, v); /* debug */
|
||||
} else {
|
||||
pqargs[k].len = VAR_LENGTH_ARG;
|
||||
pqargs[k].u.ptr = (int *) textin(fields[j]);
|
||||
printf("pqtest_PQfn: arg %d is text %s\n", k, fields[j]); /*debug*/
|
||||
int k,
|
||||
j,
|
||||
i,
|
||||
v,
|
||||
f,
|
||||
offsets;
|
||||
char *fields[8];
|
||||
PQArgBlock pqargs[7];
|
||||
int res;
|
||||
char *pqres;
|
||||
|
||||
/* ----------------
|
||||
* parse q into fields
|
||||
* ----------------
|
||||
*/
|
||||
i = strparse(q, fields, &offsets, 8);
|
||||
printf("pqtest_PQfn: strparse returns %d fields\n", i); /* debug */
|
||||
if (i == 0)
|
||||
return -1;
|
||||
|
||||
/* ----------------
|
||||
* get the function id
|
||||
* ----------------
|
||||
*/
|
||||
f = atoi(fields[0]);
|
||||
printf("pqtest_PQfn: func is %d\n", f); /* debug */
|
||||
if (f == 0)
|
||||
return -1;
|
||||
|
||||
/* ----------------
|
||||
* build a PQArgBlock
|
||||
* ----------------
|
||||
*/
|
||||
for (j = 1; j < i && j < 8; j++)
|
||||
{
|
||||
k = j - 1;
|
||||
v = atoi(fields[j]);
|
||||
if (v != 0 || (v == 0 && fields[j][0] == '0'))
|
||||
{
|
||||
pqargs[k].len = 4;
|
||||
pqargs[k].u.integer = v;
|
||||
printf("pqtest_PQfn: arg %d is int %d\n", k, v); /* debug */
|
||||
}
|
||||
else
|
||||
{
|
||||
pqargs[k].len = VAR_LENGTH_ARG;
|
||||
pqargs[k].u.ptr = (int *) textin(fields[j]);
|
||||
printf("pqtest_PQfn: arg %d is text %s\n", k, fields[j]); /* debug */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* call PQfn
|
||||
* ----------------
|
||||
*/
|
||||
pqres = PQfn(f, &res, 4, 1, pqargs, i-1);
|
||||
printf("pqtest_PQfn: pqres is %s\n", pqres); /* debug */
|
||||
|
||||
/* ----------------
|
||||
* free memory used
|
||||
* ----------------
|
||||
*/
|
||||
for (j=0; j<i; j++) {
|
||||
pfree(fields[j]);
|
||||
if (pqargs[j].len == VAR_LENGTH_ARG)
|
||||
pfree(pqargs[j].u.ptr);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* return result
|
||||
* ----------------
|
||||
*/
|
||||
printf("pqtest_PQfn: res is %d\n", res); /* debugg */
|
||||
return res;
|
||||
|
||||
/* ----------------
|
||||
* call PQfn
|
||||
* ----------------
|
||||
*/
|
||||
pqres = PQfn(f, &res, 4, 1, pqargs, i - 1);
|
||||
printf("pqtest_PQfn: pqres is %s\n", pqres); /* debug */
|
||||
|
||||
/* ----------------
|
||||
* free memory used
|
||||
* ----------------
|
||||
*/
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
pfree(fields[j]);
|
||||
if (pqargs[j].len == VAR_LENGTH_ARG)
|
||||
pfree(pqargs[j].u.ptr);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* return result
|
||||
* ----------------
|
||||
*/
|
||||
printf("pqtest_PQfn: res is %d\n", res); /* debugg */
|
||||
return res;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* pqtest looks at the first character of it's test argument
|
||||
* and decides which of pqtest_PQexec or pqtest_PQfn to call.
|
||||
* pqtest looks at the first character of it's test argument
|
||||
* and decides which of pqtest_PQexec or pqtest_PQfn to call.
|
||||
* ----------------
|
||||
*/
|
||||
int32
|
||||
pqtest(struct varlena *vlena)
|
||||
pqtest(struct varlena * vlena)
|
||||
{
|
||||
char *q;
|
||||
|
||||
/* ----------------
|
||||
* get the query
|
||||
* ----------------
|
||||
*/
|
||||
q = textout(vlena);
|
||||
if (q == NULL)
|
||||
return -1;
|
||||
|
||||
switch(q[0]) {
|
||||
case '%':
|
||||
return pqtest_PQfn(&q[1]);
|
||||
break;
|
||||
default:
|
||||
return pqtest_PQexec(q);
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
char *q;
|
||||
|
||||
/* ----------------
|
||||
* get the query
|
||||
* ----------------
|
||||
*/
|
||||
q = textout(vlena);
|
||||
if (q == NULL)
|
||||
return -1;
|
||||
|
||||
switch (q[0])
|
||||
{
|
||||
case '%':
|
||||
return pqtest_PQfn(&q[1]);
|
||||
break;
|
||||
default:
|
||||
return pqtest_PQexec(q);
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,106 +6,116 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_CRYPT_H
|
||||
# include <crypt.h>
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
verify_password(char *user, char *password, Port *port,
|
||||
char *database, char *DataDir)
|
||||
verify_password(char *user, char *password, Port * port,
|
||||
char *database, char *DataDir)
|
||||
{
|
||||
bool host_ok;
|
||||
enum Userauth userauth;
|
||||
char pw_file_name[PWFILE_NAME_SIZE+1];
|
||||
bool host_ok;
|
||||
enum Userauth userauth;
|
||||
char pw_file_name[PWFILE_NAME_SIZE + 1];
|
||||
|
||||
char *pw_file_fullname;
|
||||
FILE *pw_file;
|
||||
char *pw_file_fullname;
|
||||
FILE *pw_file;
|
||||
|
||||
char pw_file_line[255];
|
||||
char *p, *test_user, *test_pw;
|
||||
char salt[3];
|
||||
char pw_file_line[255];
|
||||
char *p,
|
||||
*test_user,
|
||||
*test_pw;
|
||||
char salt[3];
|
||||
|
||||
find_hba_entry(DataDir, port->raddr.sin_addr, database,
|
||||
&host_ok, &userauth, pw_file_name, true);
|
||||
find_hba_entry(DataDir, port->raddr.sin_addr, database,
|
||||
&host_ok, &userauth, pw_file_name, true);
|
||||
|
||||
if(!host_ok) {
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: couldn't find entry for connecting host\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if(userauth != Password) {
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: couldn't find entry of type 'password' "
|
||||
"for this host\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if(!pw_file_name || pw_file_name[0] == '\0') {
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: no password file specified\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
pw_file_fullname = (char *)malloc(strlen(DataDir) + strlen(pw_file_name) + 2);
|
||||
strcpy(pw_file_fullname, DataDir);
|
||||
strcat(pw_file_fullname, "/");
|
||||
strcat(pw_file_fullname, pw_file_name);
|
||||
|
||||
pw_file = AllocateFile(pw_file_fullname, "r");
|
||||
if(!pw_file) {
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: couldn't open password file '%s'\n",
|
||||
pw_file_fullname);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
while(!feof(pw_file)) {
|
||||
fgets(pw_file_line, 255, pw_file);
|
||||
p = pw_file_line;
|
||||
|
||||
test_user = strtok(p, ":");
|
||||
test_pw = strtok(NULL, ":");
|
||||
if(!test_user || !test_pw ||
|
||||
test_user[0] == '\0' || test_pw[0] == '\0') {
|
||||
continue;
|
||||
if (!host_ok)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: couldn't find entry for connecting host\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
/* kill the newline */
|
||||
if (test_pw[strlen(test_pw)-1] == '\n')
|
||||
test_pw[strlen(test_pw)-1] = '\0';
|
||||
|
||||
strNcpy(salt, test_pw, 2);
|
||||
|
||||
if(strcmp(user, test_user) == 0) {
|
||||
/* we're outta here one way or the other. */
|
||||
FreeFile(pw_file);
|
||||
|
||||
if(strcmp(crypt(password, salt), test_pw) == 0) {
|
||||
/* it matched. */
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: password mismatch for '%s'.\n",
|
||||
user);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
if (userauth != Password)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: couldn't find entry of type 'password' "
|
||||
"for this host\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: user '%s' not found in password file.\n",
|
||||
user);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
if (!pw_file_name || pw_file_name[0] == '\0')
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: no password file specified\n");
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
pw_file_fullname = (char *) malloc(strlen(DataDir) + strlen(pw_file_name) + 2);
|
||||
strcpy(pw_file_fullname, DataDir);
|
||||
strcat(pw_file_fullname, "/");
|
||||
strcat(pw_file_fullname, pw_file_name);
|
||||
|
||||
pw_file = AllocateFile(pw_file_fullname, "r");
|
||||
if (!pw_file)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: couldn't open password file '%s'\n",
|
||||
pw_file_fullname);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
while (!feof(pw_file))
|
||||
{
|
||||
fgets(pw_file_line, 255, pw_file);
|
||||
p = pw_file_line;
|
||||
|
||||
test_user = strtok(p, ":");
|
||||
test_pw = strtok(NULL, ":");
|
||||
if (!test_user || !test_pw ||
|
||||
test_user[0] == '\0' || test_pw[0] == '\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* kill the newline */
|
||||
if (test_pw[strlen(test_pw) - 1] == '\n')
|
||||
test_pw[strlen(test_pw) - 1] = '\0';
|
||||
|
||||
strNcpy(salt, test_pw, 2);
|
||||
|
||||
if (strcmp(user, test_user) == 0)
|
||||
{
|
||||
/* we're outta here one way or the other. */
|
||||
FreeFile(pw_file);
|
||||
|
||||
if (strcmp(crypt(password, salt), test_pw) == 0)
|
||||
{
|
||||
/* it matched. */
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: password mismatch for '%s'.\n",
|
||||
user);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(PQerrormsg,
|
||||
"verify_password: user '%s' not found in password file.\n",
|
||||
user);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,50 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* portalbuf.c--
|
||||
* portal buffer support routines for src/libpq/portal.c
|
||||
* portal buffer support routines for src/libpq/portal.c
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portalbuf.c,v 1.4 1997/08/12 20:15:23 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portalbuf.c,v 1.5 1997/09/07 04:42:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* INTERFACE ROUTINES
|
||||
* pbuf_alloc - allocate memory for libpq routines
|
||||
* pbuf_free - free memory for libpq routines
|
||||
* pbuf_addPortal - Allocate a new portal buffer
|
||||
* pbuf_addGroup - Add a new tuple group to the portal
|
||||
* pbuf_addTypes - Allocate n type blocks
|
||||
* pbuf_addTuples - Allocate a tuple block
|
||||
* pbuf_addTuple - Allocate a tuple of n fields (attributes)
|
||||
* pbuf_addValues - Allocate n bytes for a value
|
||||
* pbuf_addEntry - Allocate a portal entry
|
||||
* pbuf_freeEntry - Free a portal entry in the portal table
|
||||
* pbuf_freeTypes - Free up the space used by a portal
|
||||
* pbuf_freeTuples - free space used by tuple block
|
||||
* pbuf_freeGroup - free space used by group, types and tuples
|
||||
* pbuf_freePortal - free space used by portal and portal's group
|
||||
* pbuf_getIndex - Return the index of the portal entry
|
||||
* pbuf_setup - Set up a portal for dumping data
|
||||
* pbuf_close - Close a portal, remove it from the portal table
|
||||
* pbuf_findGroup - Return group given the group_index
|
||||
* pbuf_findFnumber - Return field index of a given field within a group
|
||||
* pbuf_findFname - Find the field name given the field index
|
||||
* pbuf_checkFnumber - signal an error if field number is out of bounds
|
||||
* pbuf_alloc - allocate memory for libpq routines
|
||||
* pbuf_free - free memory for libpq routines
|
||||
* pbuf_addPortal - Allocate a new portal buffer
|
||||
* pbuf_addGroup - Add a new tuple group to the portal
|
||||
* pbuf_addTypes - Allocate n type blocks
|
||||
* pbuf_addTuples - Allocate a tuple block
|
||||
* pbuf_addTuple - Allocate a tuple of n fields (attributes)
|
||||
* pbuf_addValues - Allocate n bytes for a value
|
||||
* pbuf_addEntry - Allocate a portal entry
|
||||
* pbuf_freeEntry - Free a portal entry in the portal table
|
||||
* pbuf_freeTypes - Free up the space used by a portal
|
||||
* pbuf_freeTuples - free space used by tuple block
|
||||
* pbuf_freeGroup - free space used by group, types and tuples
|
||||
* pbuf_freePortal - free space used by portal and portal's group
|
||||
* pbuf_getIndex - Return the index of the portal entry
|
||||
* pbuf_setup - Set up a portal for dumping data
|
||||
* pbuf_close - Close a portal, remove it from the portal table
|
||||
* pbuf_findGroup - Return group given the group_index
|
||||
* pbuf_findFnumber - Return field index of a given field within a group
|
||||
* pbuf_findFname - Find the field name given the field index
|
||||
* pbuf_checkFnumber - signal an error if field number is out of bounds
|
||||
*
|
||||
* NOTES
|
||||
* These functions may be used by both frontend routines which
|
||||
* communicate with a backend or by user-defined functions which
|
||||
* are compiled or dynamically loaded into a backend.
|
||||
* These functions may be used by both frontend routines which
|
||||
* communicate with a backend or by user-defined functions which
|
||||
* are compiled or dynamically loaded into a backend.
|
||||
*
|
||||
* the portals[] array should be organized as a hash table for
|
||||
* quick portal-by-name lookup.
|
||||
* the portals[] array should be organized as a hash table for
|
||||
* quick portal-by-name lookup.
|
||||
*
|
||||
* Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
|
||||
* see utils/mmgr/portalmem.c for why. -cim 2/22/91
|
||||
* Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
|
||||
* see utils/mmgr/portalmem.c for why. -cim 2/22/91
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
@@ -55,407 +55,417 @@
|
||||
#include <libpq/libpq.h> /* where the declarations go */
|
||||
#include <utils/exc.h>
|
||||
|
||||
PortalEntry** portals = (PortalEntry**) NULL;
|
||||
size_t portals_array_size = 0;
|
||||
PortalEntry **portals = (PortalEntry **) NULL;
|
||||
size_t portals_array_size = 0;
|
||||
|
||||
/* portals array memory is malloc'd instead of using MemoryContexts */
|
||||
/* since it will be used by both front and backend programs*/
|
||||
/* GlobalMemory portals_mmcxt = (GlobalMemory) NULL; */
|
||||
/* GlobalMemory portals_mmcxt = (GlobalMemory) NULL; */
|
||||
|
||||
/* -------------------------------
|
||||
/* -------------------------------
|
||||
* portals_realloc --
|
||||
* grow the size of the portals array by size
|
||||
* grow the size of the portals array by size
|
||||
*
|
||||
* also ensures that elements are initially NULL
|
||||
* also ensures that elements are initially NULL
|
||||
*/
|
||||
|
||||
static void
|
||||
portals_realloc(size_t size)
|
||||
{
|
||||
size_t oldsize;
|
||||
int i;
|
||||
PortalEntry** newp;
|
||||
|
||||
oldsize = portals_array_size;
|
||||
|
||||
portals_array_size += size;
|
||||
if (portals)
|
||||
newp= (PortalEntry**)realloc(portals,
|
||||
portals_array_size*sizeof(PortalEntry*));
|
||||
else
|
||||
newp= (PortalEntry**)malloc(portals_array_size*sizeof(PortalEntry*));
|
||||
|
||||
if (newp)
|
||||
portals = newp;
|
||||
else
|
||||
libpq_raise(&PortalError,
|
||||
form("Cannot alloc more memory in portals_realloc"));
|
||||
|
||||
for (i=oldsize;i<portals_array_size;i++)
|
||||
portals[i]=(PortalEntry*)NULL;
|
||||
|
||||
size_t oldsize;
|
||||
int i;
|
||||
PortalEntry **newp;
|
||||
|
||||
oldsize = portals_array_size;
|
||||
|
||||
portals_array_size += size;
|
||||
if (portals)
|
||||
newp = (PortalEntry **) realloc(portals,
|
||||
portals_array_size * sizeof(PortalEntry *));
|
||||
else
|
||||
newp = (PortalEntry **) malloc(portals_array_size * sizeof(PortalEntry *));
|
||||
|
||||
if (newp)
|
||||
portals = newp;
|
||||
else
|
||||
libpq_raise(&PortalError,
|
||||
form("Cannot alloc more memory in portals_realloc"));
|
||||
|
||||
for (i = oldsize; i < portals_array_size; i++)
|
||||
portals[i] = (PortalEntry *) NULL;
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_alloc - allocate memory for portal buffers
|
||||
* pbuf_alloc - allocate memory for portal buffers
|
||||
*
|
||||
* remember: palloc() in the backend uses the postgres MemoryContext
|
||||
* library and palloc() in the frontend (fe-pqstubs.c) calls malloc().
|
||||
* remember: palloc() in the backend uses the postgres MemoryContext
|
||||
* library and palloc() in the frontend (fe-pqstubs.c) calls malloc().
|
||||
* --------------------------------
|
||||
*/
|
||||
caddr_t
|
||||
pbuf_alloc(size_t size)
|
||||
{
|
||||
caddr_t addr;
|
||||
|
||||
if (size <= 0)
|
||||
libpq_raise(&MemoryError, form("Invalid argument to pbuf_alloc()."));
|
||||
|
||||
addr = (caddr_t) palloc(size);
|
||||
if (addr == (caddr_t) NULL)
|
||||
libpq_raise(&MemoryError, form("Cannot Allocate space."));
|
||||
|
||||
return (addr);
|
||||
caddr_t addr;
|
||||
|
||||
if (size <= 0)
|
||||
libpq_raise(&MemoryError, form("Invalid argument to pbuf_alloc()."));
|
||||
|
||||
addr = (caddr_t) palloc(size);
|
||||
if (addr == (caddr_t) NULL)
|
||||
libpq_raise(&MemoryError, form("Cannot Allocate space."));
|
||||
|
||||
return (addr);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_free - free memory for portal buffers
|
||||
* pbuf_free - free memory for portal buffers
|
||||
*
|
||||
* remember: pfree() in the backend uses the postgres MemoryContext
|
||||
* library and pfree() in the frontend (fe-pqstubs.c) calls free().
|
||||
* remember: pfree() in the backend uses the postgres MemoryContext
|
||||
* library and pfree() in the frontend (fe-pqstubs.c) calls free().
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_free(caddr_t pointer)
|
||||
{
|
||||
if (pointer)
|
||||
pfree(pointer);
|
||||
else
|
||||
libpq_raise(&MemoryError, form("Tried to free NULL memory pointer"));
|
||||
|
||||
if (pointer)
|
||||
pfree(pointer);
|
||||
else
|
||||
libpq_raise(&MemoryError, form("Tried to free NULL memory pointer"));
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_addPortal - Allocate a new portal buffer
|
||||
* pbuf_addPortal - Allocate a new portal buffer
|
||||
* --------------------------------
|
||||
*/
|
||||
PortalBuffer *
|
||||
PortalBuffer *
|
||||
pbuf_addPortal()
|
||||
{
|
||||
PortalBuffer *portal;
|
||||
|
||||
portal = (PortalBuffer *)
|
||||
pbuf_alloc(sizeof (PortalBuffer));
|
||||
|
||||
portal->rule_p = 0;
|
||||
portal->no_tuples = 0;
|
||||
portal->no_groups = 0;
|
||||
portal->groups = NULL;
|
||||
|
||||
return (portal);
|
||||
PortalBuffer *portal;
|
||||
|
||||
portal = (PortalBuffer *)
|
||||
pbuf_alloc(sizeof(PortalBuffer));
|
||||
|
||||
portal->rule_p = 0;
|
||||
portal->no_tuples = 0;
|
||||
portal->no_groups = 0;
|
||||
portal->groups = NULL;
|
||||
|
||||
return (portal);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_addGroup - Add a new tuple group to the portal
|
||||
* pbuf_addGroup - Add a new tuple group to the portal
|
||||
* --------------------------------
|
||||
*/
|
||||
GroupBuffer *
|
||||
pbuf_addGroup(PortalBuffer *portal)
|
||||
GroupBuffer *
|
||||
pbuf_addGroup(PortalBuffer * portal)
|
||||
{
|
||||
GroupBuffer *group, *group1;
|
||||
|
||||
group = (GroupBuffer *)
|
||||
pbuf_alloc(sizeof (GroupBuffer));
|
||||
|
||||
/* Initialize the new group buffer. */
|
||||
group->no_tuples = 0;
|
||||
group->no_fields = 0;
|
||||
group->types = NULL;
|
||||
group->tuples = NULL;
|
||||
group->next = NULL;
|
||||
|
||||
if ((group1 = portal->groups) == NULL)
|
||||
portal->groups = group;
|
||||
else {
|
||||
while (group1->next != NULL)
|
||||
group1 = group1->next;
|
||||
group1->next = group;
|
||||
}
|
||||
|
||||
return (group);
|
||||
GroupBuffer *group,
|
||||
*group1;
|
||||
|
||||
group = (GroupBuffer *)
|
||||
pbuf_alloc(sizeof(GroupBuffer));
|
||||
|
||||
/* Initialize the new group buffer. */
|
||||
group->no_tuples = 0;
|
||||
group->no_fields = 0;
|
||||
group->types = NULL;
|
||||
group->tuples = NULL;
|
||||
group->next = NULL;
|
||||
|
||||
if ((group1 = portal->groups) == NULL)
|
||||
portal->groups = group;
|
||||
else
|
||||
{
|
||||
while (group1->next != NULL)
|
||||
group1 = group1->next;
|
||||
group1->next = group;
|
||||
}
|
||||
|
||||
return (group);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_addTypes - Allocate n type blocks
|
||||
* pbuf_addTypes - Allocate n type blocks
|
||||
* --------------------------------
|
||||
*/
|
||||
TypeBlock *
|
||||
TypeBlock *
|
||||
pbuf_addTypes(int n)
|
||||
{
|
||||
TypeBlock *types;
|
||||
|
||||
types = (TypeBlock *)
|
||||
pbuf_alloc(n * sizeof (TypeBlock));
|
||||
|
||||
return (types);
|
||||
TypeBlock *types;
|
||||
|
||||
types = (TypeBlock *)
|
||||
pbuf_alloc(n * sizeof(TypeBlock));
|
||||
|
||||
return (types);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_addTuples - Allocate a tuple block
|
||||
* pbuf_addTuples - Allocate a tuple block
|
||||
* --------------------------------
|
||||
*/
|
||||
TupleBlock *
|
||||
TupleBlock *
|
||||
pbuf_addTuples()
|
||||
{
|
||||
TupleBlock *tuples;
|
||||
|
||||
tuples = (TupleBlock *)
|
||||
pbuf_alloc(sizeof (TupleBlock));
|
||||
|
||||
tuples->next = NULL;
|
||||
tuples->tuple_index = 0;
|
||||
|
||||
return (tuples);
|
||||
TupleBlock *tuples;
|
||||
|
||||
tuples = (TupleBlock *)
|
||||
pbuf_alloc(sizeof(TupleBlock));
|
||||
|
||||
tuples->next = NULL;
|
||||
tuples->tuple_index = 0;
|
||||
|
||||
return (tuples);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_addTuple - Allocate a tuple of n fields (attributes)
|
||||
* pbuf_addTuple - Allocate a tuple of n fields (attributes)
|
||||
* --------------------------------
|
||||
*/
|
||||
char **
|
||||
char **
|
||||
pbuf_addTuple(int n)
|
||||
{
|
||||
return (char **)
|
||||
pbuf_alloc(n * sizeof (char *));
|
||||
return (char **)
|
||||
pbuf_alloc(n * sizeof(char *));
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_addTupleValueLengths - Allocate a tuple of n lengths (attributes)
|
||||
* pbuf_addTupleValueLengths - Allocate a tuple of n lengths (attributes)
|
||||
* --------------------------------
|
||||
*/
|
||||
int *
|
||||
int *
|
||||
pbuf_addTupleValueLengths(int n)
|
||||
{
|
||||
return (int *)
|
||||
return (int *)
|
||||
pbuf_alloc(n * sizeof(int));
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_addValues - Allocate n bytes for a value
|
||||
* pbuf_addValues - Allocate n bytes for a value
|
||||
* --------------------------------
|
||||
*/
|
||||
char *
|
||||
char *
|
||||
pbuf_addValues(int n)
|
||||
{
|
||||
return
|
||||
return
|
||||
pbuf_alloc(n);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_addEntry - Allocate a portal entry
|
||||
* pbuf_addEntry - Allocate a portal entry
|
||||
* --------------------------------
|
||||
*/
|
||||
PortalEntry *pbuf_addEntry()
|
||||
PortalEntry *
|
||||
pbuf_addEntry()
|
||||
{
|
||||
return (PortalEntry *)
|
||||
pbuf_alloc (sizeof (PortalEntry));
|
||||
return (PortalEntry *)
|
||||
pbuf_alloc(sizeof(PortalEntry));
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_freeEntry - Free a portal entry in the portal table
|
||||
* the portal is freed separately.
|
||||
* pbuf_freeEntry - Free a portal entry in the portal table
|
||||
* the portal is freed separately.
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_freeEntry(int i)
|
||||
{
|
||||
if (portals)
|
||||
if (portals)
|
||||
{
|
||||
pbuf_free ((caddr_t)portals[i]);
|
||||
portals[i] = NULL;
|
||||
pbuf_free((caddr_t) portals[i]);
|
||||
portals[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_freeTypes - Free up the space used by a portal
|
||||
* pbuf_freeTypes - Free up the space used by a portal
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_freeTypes(TypeBlock *types)
|
||||
pbuf_freeTypes(TypeBlock * types)
|
||||
{
|
||||
pbuf_free((caddr_t)types);
|
||||
pbuf_free((caddr_t) types);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_freeTuples - free space used by tuple block
|
||||
* pbuf_freeTuples - free space used by tuple block
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_freeTuples(TupleBlock *tuples,
|
||||
int no_tuples,
|
||||
int no_fields)
|
||||
pbuf_freeTuples(TupleBlock * tuples,
|
||||
int no_tuples,
|
||||
int no_fields)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (no_tuples > TupleBlockSize) {
|
||||
pbuf_freeTuples (tuples->next, no_tuples - TupleBlockSize, no_fields);
|
||||
no_tuples = TupleBlockSize;
|
||||
}
|
||||
|
||||
/* For each tuple, free all its attribute values. */
|
||||
for (i = 0; i < no_tuples; i++) {
|
||||
for (j = 0; j < no_fields; j++)
|
||||
if (tuples->values[i][j] != NULL)
|
||||
pbuf_free((caddr_t)tuples->values[i][j]);
|
||||
if (tuples->lengths[i])
|
||||
pbuf_free((caddr_t)tuples->lengths[i]);
|
||||
if (tuples->values[i])
|
||||
pbuf_free((caddr_t)tuples->values[i]);
|
||||
}
|
||||
|
||||
pbuf_free((caddr_t)tuples);
|
||||
int i,
|
||||
j;
|
||||
|
||||
if (no_tuples > TupleBlockSize)
|
||||
{
|
||||
pbuf_freeTuples(tuples->next, no_tuples - TupleBlockSize, no_fields);
|
||||
no_tuples = TupleBlockSize;
|
||||
}
|
||||
|
||||
/* For each tuple, free all its attribute values. */
|
||||
for (i = 0; i < no_tuples; i++)
|
||||
{
|
||||
for (j = 0; j < no_fields; j++)
|
||||
if (tuples->values[i][j] != NULL)
|
||||
pbuf_free((caddr_t) tuples->values[i][j]);
|
||||
if (tuples->lengths[i])
|
||||
pbuf_free((caddr_t) tuples->lengths[i]);
|
||||
if (tuples->values[i])
|
||||
pbuf_free((caddr_t) tuples->values[i]);
|
||||
}
|
||||
|
||||
pbuf_free((caddr_t) tuples);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_freeGroup - free space used by group, types and tuples
|
||||
* pbuf_freeGroup - free space used by group, types and tuples
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_freeGroup(GroupBuffer *group)
|
||||
pbuf_freeGroup(GroupBuffer * group)
|
||||
{
|
||||
if (group->next != NULL)
|
||||
pbuf_freeGroup(group->next);
|
||||
|
||||
if (group->types != NULL)
|
||||
pbuf_freeTypes(group->types);
|
||||
|
||||
if (group->tuples != NULL)
|
||||
pbuf_freeTuples(group->tuples, group->no_tuples,group->no_fields);
|
||||
|
||||
pbuf_free((caddr_t)group);
|
||||
if (group->next != NULL)
|
||||
pbuf_freeGroup(group->next);
|
||||
|
||||
if (group->types != NULL)
|
||||
pbuf_freeTypes(group->types);
|
||||
|
||||
if (group->tuples != NULL)
|
||||
pbuf_freeTuples(group->tuples, group->no_tuples, group->no_fields);
|
||||
|
||||
pbuf_free((caddr_t) group);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_freePortal - free space used by portal and portal's group
|
||||
* pbuf_freePortal - free space used by portal and portal's group
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_freePortal(PortalBuffer *portal)
|
||||
pbuf_freePortal(PortalBuffer * portal)
|
||||
{
|
||||
if (portal->groups != NULL)
|
||||
pbuf_freeGroup(portal->groups);
|
||||
|
||||
pbuf_free((caddr_t)portal);
|
||||
if (portal->groups != NULL)
|
||||
pbuf_freeGroup(portal->groups);
|
||||
|
||||
pbuf_free((caddr_t) portal);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_getIndex - Return the index of the portal entry
|
||||
* note: portals[] maps portal names to portal buffers.
|
||||
* pbuf_getIndex - Return the index of the portal entry
|
||||
* note: portals[] maps portal names to portal buffers.
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pbuf_getIndex(char *pname)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (portals) {
|
||||
for (i = 0; i < portals_array_size; i++)
|
||||
if (portals[i] != NULL &&
|
||||
strncmp(portals[i]->name, pname, PortalNameLength) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return (-1);
|
||||
int i;
|
||||
|
||||
if (portals)
|
||||
{
|
||||
for (i = 0; i < portals_array_size; i++)
|
||||
if (portals[i] != NULL &&
|
||||
strncmp(portals[i]->name, pname, PortalNameLength) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_setportalname - assign a user given name to a portal
|
||||
* pbuf_setportalname - assign a user given name to a portal
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_setportalinfo(PortalEntry *entry, char *pname)
|
||||
pbuf_setportalinfo(PortalEntry * entry, char *pname)
|
||||
{
|
||||
if (entry)
|
||||
strNcpy(entry->name, pname, PortalNameLength-1);
|
||||
if (entry)
|
||||
strNcpy(entry->name, pname, PortalNameLength - 1);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_setup - Set up a portal for dumping data
|
||||
* pbuf_setup - Set up a portal for dumping data
|
||||
* --------------------------------
|
||||
*/
|
||||
PortalEntry *
|
||||
PortalEntry *
|
||||
pbuf_setup(char *pname)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!portals) /* the portals array has not been allocated yet */
|
||||
int i;
|
||||
|
||||
if (!portals) /* the portals array has not been
|
||||
* allocated yet */
|
||||
{
|
||||
/* allocate portals[] array here */
|
||||
portals_realloc(PORTALS_INITIAL_SIZE);
|
||||
/* allocate portals[] array here */
|
||||
portals_realloc(PORTALS_INITIAL_SIZE);
|
||||
}
|
||||
|
||||
/* If a portal with the same name already exists, close it. */
|
||||
/* else look for an empty entry in the portal table. */
|
||||
if ((i = pbuf_getIndex(pname)) != -1)
|
||||
pbuf_freePortal(portals[i]->portal);
|
||||
else {
|
||||
for (i = 0; i < portals_array_size; i++)
|
||||
if (portals[i] == NULL)
|
||||
break;
|
||||
|
||||
/* If the portal table is full, enlarge it */
|
||||
if (i >= portals_array_size)
|
||||
portals_realloc(PORTALS_GROW_BY);
|
||||
|
||||
portals[i] = pbuf_addEntry();
|
||||
strncpy(portals[i]->name, pname, PortalNameLength);
|
||||
}
|
||||
portals[i]->portal = pbuf_addPortal();
|
||||
portals[i]->portalcxt = NULL;
|
||||
portals[i]->result = NULL;
|
||||
|
||||
return portals[i];
|
||||
|
||||
/* If a portal with the same name already exists, close it. */
|
||||
/* else look for an empty entry in the portal table. */
|
||||
if ((i = pbuf_getIndex(pname)) != -1)
|
||||
pbuf_freePortal(portals[i]->portal);
|
||||
else
|
||||
{
|
||||
for (i = 0; i < portals_array_size; i++)
|
||||
if (portals[i] == NULL)
|
||||
break;
|
||||
|
||||
/* If the portal table is full, enlarge it */
|
||||
if (i >= portals_array_size)
|
||||
portals_realloc(PORTALS_GROW_BY);
|
||||
|
||||
portals[i] = pbuf_addEntry();
|
||||
strncpy(portals[i]->name, pname, PortalNameLength);
|
||||
}
|
||||
portals[i]->portal = pbuf_addPortal();
|
||||
portals[i]->portalcxt = NULL;
|
||||
portals[i]->result = NULL;
|
||||
|
||||
return portals[i];
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_close - Close a portal, remove it from the portal table
|
||||
* and free up the space
|
||||
* pbuf_close - Close a portal, remove it from the portal table
|
||||
* and free up the space
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_close(char *pname)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((i = pbuf_getIndex(pname)) == -1)
|
||||
libpq_raise(&PortalError, form("Portal %s does not exist.", pname));
|
||||
|
||||
pbuf_freePortal(portals[i]->portal);
|
||||
pbuf_freeEntry(i);
|
||||
int i;
|
||||
|
||||
if ((i = pbuf_getIndex(pname)) == -1)
|
||||
libpq_raise(&PortalError, form("Portal %s does not exist.", pname));
|
||||
|
||||
pbuf_freePortal(portals[i]->portal);
|
||||
pbuf_freeEntry(i);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_findGroup - Return the group given the group_index
|
||||
* pbuf_findGroup - Return the group given the group_index
|
||||
* --------------------------------
|
||||
*/
|
||||
GroupBuffer *
|
||||
pbuf_findGroup(PortalBuffer *portal,
|
||||
int group_index)
|
||||
GroupBuffer *
|
||||
pbuf_findGroup(PortalBuffer * portal,
|
||||
int group_index)
|
||||
{
|
||||
GroupBuffer *group;
|
||||
|
||||
group = portal->groups;
|
||||
while (group_index > 0 && group != NULL) {
|
||||
group = group->next;
|
||||
group_index--;
|
||||
}
|
||||
|
||||
if (group == NULL)
|
||||
libpq_raise(&PortalError,
|
||||
form("Group index %d out of bound.", group_index));
|
||||
|
||||
return (group);
|
||||
GroupBuffer *group;
|
||||
|
||||
group = portal->groups;
|
||||
while (group_index > 0 && group != NULL)
|
||||
{
|
||||
group = group->next;
|
||||
group_index--;
|
||||
}
|
||||
|
||||
if (group == NULL)
|
||||
libpq_raise(&PortalError,
|
||||
form("Group index %d out of bound.", group_index));
|
||||
|
||||
return (group);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
@@ -463,49 +473,48 @@ pbuf_findGroup(PortalBuffer *portal,
|
||||
* --------------------------------
|
||||
*/
|
||||
int
|
||||
pbuf_findFnumber(GroupBuffer *group,
|
||||
char *field_name)
|
||||
{
|
||||
TypeBlock *types;
|
||||
int i;
|
||||
|
||||
types = group->types;
|
||||
|
||||
for (i = 0; i < group->no_fields; i++)
|
||||
if (strncmp(types[i].name, field_name, NAMEDATALEN) == 0)
|
||||
return (i);
|
||||
|
||||
libpq_raise(&PortalError,
|
||||
form("Field-name %s does not exist.", field_name));
|
||||
|
||||
/* not reached, here to make compiler happy */
|
||||
return 0;
|
||||
pbuf_findFnumber(GroupBuffer * group,
|
||||
char *field_name)
|
||||
{
|
||||
TypeBlock *types;
|
||||
int i;
|
||||
|
||||
types = group->types;
|
||||
|
||||
for (i = 0; i < group->no_fields; i++)
|
||||
if (strncmp(types[i].name, field_name, NAMEDATALEN) == 0)
|
||||
return (i);
|
||||
|
||||
libpq_raise(&PortalError,
|
||||
form("Field-name %s does not exist.", field_name));
|
||||
|
||||
/* not reached, here to make compiler happy */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_checkFnumber - signal an error if field number is out of bounds
|
||||
* pbuf_checkFnumber - signal an error if field number is out of bounds
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
pbuf_checkFnumber(GroupBuffer *group,
|
||||
int field_number)
|
||||
pbuf_checkFnumber(GroupBuffer * group,
|
||||
int field_number)
|
||||
{
|
||||
if (field_number < 0 || field_number >= group->no_fields)
|
||||
libpq_raise(&PortalError,
|
||||
form("Field number %d out of bound.", field_number));
|
||||
if (field_number < 0 || field_number >= group->no_fields)
|
||||
libpq_raise(&PortalError,
|
||||
form("Field number %d out of bound.", field_number));
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* pbuf_findFname - Find the field name given the field index
|
||||
* pbuf_findFname - Find the field name given the field index
|
||||
* --------------------------------
|
||||
*/
|
||||
char *
|
||||
pbuf_findFname(GroupBuffer *group,
|
||||
int field_number)
|
||||
char *
|
||||
pbuf_findFname(GroupBuffer * group,
|
||||
int field_number)
|
||||
{
|
||||
pbuf_checkFnumber(group, field_number);
|
||||
return
|
||||
(group->types[field_number]).name;
|
||||
pbuf_checkFnumber(group, field_number);
|
||||
return
|
||||
(group->types[field_number]).name;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,171 +4,185 @@
|
||||
#include "postgres.h"
|
||||
#include "libpq/pqcomm.h"
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h>
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* These definitions for ntoh/hton are the other way around from the
|
||||
* default system definitions, so we roll our own here.
|
||||
* default system definitions, so we roll our own here.
|
||||
*/
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#ifndef BYTE_ORDER
|
||||
#error BYTE_ORDER must be defined as LITTLE_ENDIAN, BIG_ENDIAN or PDP_ENDIAN
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define ntoh_s(n) n
|
||||
# define ntoh_l(n) n
|
||||
# define hton_s(n) n
|
||||
# define hton_l(n) n
|
||||
#else /* BYTE_ORDER != LITTLE_ENDIAN */
|
||||
# if BYTE_ORDER == BIG_ENDIAN
|
||||
# define ntoh_s(n) (u_short)(((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0])
|
||||
# define ntoh_l(n) (u_long) (((u_char *)&n)[3] << 24 \
|
||||
| ((u_char *)&n)[2] << 16 \
|
||||
| ((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0])
|
||||
# define hton_s(n) (ntoh_s(n))
|
||||
# define hton_l(n) (ntoh_l(n))
|
||||
# else /* BYTE_ORDER != BIG_ENDIAN */
|
||||
# if BYTE_ORDER == PDP_ENDIAN
|
||||
# error PDP_ENDIAN macros not written yet
|
||||
# else /* BYTE_ORDER != anything known */
|
||||
# error BYTE_ORDER not defined as anything understood
|
||||
# endif /* BYTE_ORDER == PDP_ENDIAN */
|
||||
# endif /* BYTE_ORDER == BIG_ENDIAN */
|
||||
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
||||
#define ntoh_s(n) n
|
||||
#define ntoh_l(n) n
|
||||
#define hton_s(n) n
|
||||
#define hton_l(n) n
|
||||
#else /* BYTE_ORDER != LITTLE_ENDIAN */
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define ntoh_s(n) (u_short)(((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0])
|
||||
#define ntoh_l(n) (u_long) (((u_char *)&n)[3] << 24 \
|
||||
| ((u_char *)&n)[2] << 16 \
|
||||
| ((u_char *)&n)[1] << 8 \
|
||||
| ((u_char *)&n)[0])
|
||||
#define hton_s(n) (ntoh_s(n))
|
||||
#define hton_l(n) (ntoh_l(n))
|
||||
#else
|
||||
/* BYTE_ORDER != BIG_ENDIAN */
|
||||
#if BYTE_ORDER == PDP_ENDIAN
|
||||
#error PDP_ENDIAN macros not written yet
|
||||
#else
|
||||
/* BYTE_ORDER != anything known */
|
||||
#error BYTE_ORDER not defined as anything understood
|
||||
#endif /* BYTE_ORDER == PDP_ENDIAN */
|
||||
#endif /* BYTE_ORDER == BIG_ENDIAN */
|
||||
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqPutShort(int integer, FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_short n,s;
|
||||
|
||||
s = integer;
|
||||
n = hton_s(s);
|
||||
if(fwrite(&n, sizeof(u_short), 1, f) != 1)
|
||||
retval = EOF;
|
||||
|
||||
return retval;
|
||||
}
|
||||
int
|
||||
pqPutShort(int integer, FILE * f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_short n,
|
||||
s;
|
||||
|
||||
s = integer;
|
||||
n = hton_s(s);
|
||||
if (fwrite(&n, sizeof(u_short), 1, f) != 1)
|
||||
retval = EOF;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqPutLong(int integer, FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_long n;
|
||||
|
||||
n = hton_l(integer);
|
||||
if(fwrite(&n, sizeof(u_long), 1, f) != 1)
|
||||
retval = EOF;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqGetShort(int *result, FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_short n;
|
||||
int
|
||||
pqPutLong(int integer, FILE * f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_long n;
|
||||
|
||||
if(fread(&n, sizeof(u_short), 1, f) != 1)
|
||||
retval = EOF;
|
||||
|
||||
*result = ntoh_s(n);
|
||||
return retval;
|
||||
}
|
||||
n = hton_l(integer);
|
||||
if (fwrite(&n, sizeof(u_long), 1, f) != 1)
|
||||
retval = EOF;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqGetLong(int *result, FILE *f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_long n;
|
||||
|
||||
if(fread(&n, sizeof(u_long), 1, f) != 1)
|
||||
retval = EOF;
|
||||
|
||||
*result = ntoh_l(n);
|
||||
return retval;
|
||||
}
|
||||
int
|
||||
pqGetShort(int *result, FILE * f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_short n;
|
||||
|
||||
if (fread(&n, sizeof(u_short), 1, f) != 1)
|
||||
retval = EOF;
|
||||
|
||||
*result = ntoh_s(n);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
pqGetLong(int *result, FILE * f)
|
||||
{
|
||||
int retval = 0;
|
||||
u_long n;
|
||||
|
||||
if (fread(&n, sizeof(u_long), 1, f) != 1)
|
||||
retval = EOF;
|
||||
|
||||
*result = ntoh_l(n);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s.
|
||||
Return 0 if ok.
|
||||
Return 0 if ok.
|
||||
*/
|
||||
int pqGetNBytes(char *s, size_t len, FILE *f)
|
||||
{
|
||||
int cnt;
|
||||
int
|
||||
pqGetNBytes(char *s, size_t len, FILE * f)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
if (f == NULL)
|
||||
return EOF;
|
||||
|
||||
|
||||
cnt = fread(s, 1, len, f);
|
||||
s[cnt] = '\0';
|
||||
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
|
||||
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
|
||||
|
||||
return (cnt == len) ? 0 : EOF;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqPutNBytes(const char *s, size_t len, FILE *f)
|
||||
{
|
||||
int
|
||||
pqPutNBytes(const char *s, size_t len, FILE * f)
|
||||
{
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
|
||||
if(fwrite(s, 1, len, f) != len)
|
||||
return EOF;
|
||||
if (fwrite(s, 1, len, f) != len)
|
||||
return EOF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqGetString(char *s, size_t len, FILE *f)
|
||||
{
|
||||
int c;
|
||||
int
|
||||
pqGetString(char *s, size_t len, FILE * f)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (f == NULL)
|
||||
return EOF;
|
||||
|
||||
return EOF;
|
||||
|
||||
while (len-- && (c = getc(f)) != EOF && c)
|
||||
*s++ = c;
|
||||
*s = '\0';
|
||||
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
|
||||
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqPutString(const char *s, FILE *f)
|
||||
{
|
||||
int
|
||||
pqPutString(const char *s, FILE * f)
|
||||
{
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
|
||||
|
||||
if (fputs(s, f) == EOF)
|
||||
return EOF;
|
||||
|
||||
fputc('\0', f); /* important to send an ending \0 since backend expects it */
|
||||
fputc('\0', f); /* important to send an ending \0 since
|
||||
* backend expects it */
|
||||
fflush(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqGetByte(FILE *f)
|
||||
{
|
||||
int
|
||||
pqGetByte(FILE * f)
|
||||
{
|
||||
return getc(f);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int pqPutByte(int c, FILE *f)
|
||||
{
|
||||
if(!f) return 0;
|
||||
|
||||
return (putc(c, f) == c) ? 0 : EOF;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
int
|
||||
pqPutByte(int c, FILE * f)
|
||||
{
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
return (putc(c, f) == c) ? 0 : EOF;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pqpacket.c--
|
||||
* routines for reading and writing data packets sent/received by
|
||||
* POSTGRES clients and servers
|
||||
* routines for reading and writing data packets sent/received by
|
||||
* POSTGRES clients and servers
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.5 1997/08/12 22:53:00 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.6 1997/09/07 04:42:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/* NOTES
|
||||
* This is the module that understands the lowest-level part
|
||||
* of the communication protocol. All of the trickiness in
|
||||
* this module is for making sure that non-blocking I/O in
|
||||
* the Postmaster works correctly. Check the notes in PacketRecv
|
||||
* on non-blocking I/O.
|
||||
* This is the module that understands the lowest-level part
|
||||
* of the communication protocol. All of the trickiness in
|
||||
* this module is for making sure that non-blocking I/O in
|
||||
* the Postmaster works correctly. Check the notes in PacketRecv
|
||||
* on non-blocking I/O.
|
||||
*
|
||||
* Data Structures:
|
||||
* Port has two important functions. (1) It records the
|
||||
* sock/addr used in communication. (2) It holds partially
|
||||
* read in messages. This is especially important when
|
||||
* we haven't seen enough to construct a complete packet
|
||||
* header.
|
||||
* Port has two important functions. (1) It records the
|
||||
* sock/addr used in communication. (2) It holds partially
|
||||
* read in messages. This is especially important when
|
||||
* we haven't seen enough to construct a complete packet
|
||||
* header.
|
||||
*
|
||||
* PacketBuf -- None of the clients of this module should know
|
||||
* what goes into a packet hdr (although they know how big
|
||||
* it is). This routine is in charge of host to net order
|
||||
* conversion for headers. Data conversion is someone elses
|
||||
* responsibility.
|
||||
* what goes into a packet hdr (although they know how big
|
||||
* it is). This routine is in charge of host to net order
|
||||
* conversion for headers. Data conversion is someone elses
|
||||
* responsibility.
|
||||
*
|
||||
* IMPORTANT: these routines are called by backends, clients, and
|
||||
* the Postmaster.
|
||||
* the Postmaster.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
@@ -57,134 +57,156 @@
|
||||
*
|
||||
*/
|
||||
int
|
||||
PacketReceive(Port *port, /* receive port */
|
||||
PacketBuf *buf, /* MAX_PACKET_SIZE-worth of buffer space */
|
||||
bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
|
||||
PacketReceive(Port * port, /* receive port */
|
||||
PacketBuf * buf, /* MAX_PACKET_SIZE-worth of buffer space */
|
||||
bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
|
||||
{
|
||||
PacketLen max_size = sizeof(PacketBuf);
|
||||
PacketLen cc; /* character count -- bytes recvd */
|
||||
PacketLen packetLen; /* remaining packet chars to read */
|
||||
Addr tmp; /* curr recv buf pointer */
|
||||
int addrLen = sizeof(struct sockaddr_in);
|
||||
int hdrLen;
|
||||
int flag;
|
||||
int decr;
|
||||
|
||||
hdrLen = sizeof(buf->len);
|
||||
PacketLen max_size = sizeof(PacketBuf);
|
||||
PacketLen cc; /* character count -- bytes recvd */
|
||||
PacketLen packetLen; /* remaining packet chars to read */
|
||||
Addr tmp; /* curr recv buf pointer */
|
||||
int addrLen = sizeof(struct sockaddr_in);
|
||||
int hdrLen;
|
||||
int flag;
|
||||
int decr;
|
||||
|
||||
if (nonBlocking == NON_BLOCKING) {
|
||||
flag = MSG_PEEK;
|
||||
decr = 0;
|
||||
} else {
|
||||
flag = 0;
|
||||
decr = hdrLen;
|
||||
}
|
||||
/*
|
||||
* Assume port->nBytes is zero unless we were interrupted during
|
||||
* non-blocking I/O. This first recvfrom() is to get the hdr
|
||||
* information so we know how many bytes to read. Life would
|
||||
* be very complicated if we read too much data (buffering).
|
||||
*/
|
||||
tmp = ((Addr)buf) + port->nBytes;
|
||||
hdrLen = sizeof(buf->len);
|
||||
|
||||
if (port->nBytes >= hdrLen) {
|
||||
packetLen = ntohl(buf->len) - port->nBytes;
|
||||
}
|
||||
else {
|
||||
/* peeking into the incoming message */
|
||||
cc = recvfrom(port->sock, (char *)&(buf->len), hdrLen, flag,
|
||||
(struct sockaddr*) &(port->raddr), &addrLen);
|
||||
if (cc < hdrLen) {
|
||||
/* if cc is negative, the system call failed */
|
||||
if (cc < 0) {
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
/*
|
||||
* cc == 0 means the connection was broken at the
|
||||
* other end.
|
||||
*/
|
||||
else if (! cc) {
|
||||
return(STATUS_INVALID);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Worst case. We didn't even read in enough data to
|
||||
* get the header length.
|
||||
* since we are using a data stream,
|
||||
* this happens only if the client is mallicious.
|
||||
*
|
||||
* Don't save the number of bytes we've read so far.
|
||||
* Since we only peeked at the incoming message, the
|
||||
* kernel is going to keep it for us.
|
||||
*/
|
||||
return(STATUS_NOT_DONE);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This is an attempt to shield the Postmaster
|
||||
* from mallicious attacks by placing tighter
|
||||
* restrictions on the reported packet length.
|
||||
*
|
||||
* Check for negative packet length
|
||||
*/
|
||||
if ((buf->len) <= 0) {
|
||||
return(STATUS_INVALID);
|
||||
}
|
||||
/*
|
||||
* Check for oversize packet
|
||||
*/
|
||||
if ((ntohl(buf->len)) > max_size) {
|
||||
return(STATUS_INVALID);
|
||||
}
|
||||
/*
|
||||
* great. got the header. now get the true length (including
|
||||
* header size).
|
||||
*/
|
||||
packetLen = ntohl(buf->len);
|
||||
/*
|
||||
* if someone is sending us junk, close the connection
|
||||
*/
|
||||
if (packetLen > max_size) {
|
||||
port->nBytes = packetLen;
|
||||
return(STATUS_BAD_PACKET);
|
||||
}
|
||||
packetLen -= decr;
|
||||
tmp += decr - port->nBytes;
|
||||
if (nonBlocking == NON_BLOCKING)
|
||||
{
|
||||
flag = MSG_PEEK;
|
||||
decr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we know how big it is, read the packet. We read
|
||||
* the entire packet, since the last call was just a peek.
|
||||
*/
|
||||
while (packetLen) {
|
||||
cc = recvfrom(port->sock, tmp, packetLen, 0,
|
||||
(struct sockaddr*) &(port->raddr), &addrLen);
|
||||
if (cc < 0)
|
||||
return(STATUS_ERROR);
|
||||
/*
|
||||
* cc == 0 means the connection was broken at the
|
||||
* other end.
|
||||
else
|
||||
{
|
||||
flag = 0;
|
||||
decr = hdrLen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume port->nBytes is zero unless we were interrupted during
|
||||
* non-blocking I/O. This first recvfrom() is to get the hdr
|
||||
* information so we know how many bytes to read. Life would be very
|
||||
* complicated if we read too much data (buffering).
|
||||
*/
|
||||
else if (! cc)
|
||||
return(STATUS_INVALID);
|
||||
|
||||
tmp = ((Addr) buf) + port->nBytes;
|
||||
|
||||
if (port->nBytes >= hdrLen)
|
||||
{
|
||||
packetLen = ntohl(buf->len) - port->nBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* peeking into the incoming message */
|
||||
cc = recvfrom(port->sock, (char *) &(buf->len), hdrLen, flag,
|
||||
(struct sockaddr *) & (port->raddr), &addrLen);
|
||||
if (cc < hdrLen)
|
||||
{
|
||||
/* if cc is negative, the system call failed */
|
||||
if (cc < 0)
|
||||
{
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* cc == 0 means the connection was broken at the other end.
|
||||
*/
|
||||
else if (!cc)
|
||||
{
|
||||
return (STATUS_INVALID);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Worst case. We didn't even read in enough data to get
|
||||
* the header length. since we are using a data stream,
|
||||
* this happens only if the client is mallicious.
|
||||
*
|
||||
* Don't save the number of bytes we've read so far. Since we
|
||||
* only peeked at the incoming message, the kernel is
|
||||
* going to keep it for us.
|
||||
*/
|
||||
return (STATUS_NOT_DONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This is an attempt to shield the Postmaster from mallicious
|
||||
* attacks by placing tighter restrictions on the reported
|
||||
* packet length.
|
||||
*
|
||||
* Check for negative packet length
|
||||
*/
|
||||
if ((buf->len) <= 0)
|
||||
{
|
||||
return (STATUS_INVALID);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for oversize packet
|
||||
*/
|
||||
if ((ntohl(buf->len)) > max_size)
|
||||
{
|
||||
return (STATUS_INVALID);
|
||||
}
|
||||
|
||||
/*
|
||||
* great. got the header. now get the true length (including
|
||||
* header size).
|
||||
*/
|
||||
packetLen = ntohl(buf->len);
|
||||
|
||||
/*
|
||||
* if someone is sending us junk, close the connection
|
||||
*/
|
||||
if (packetLen > max_size)
|
||||
{
|
||||
port->nBytes = packetLen;
|
||||
return (STATUS_BAD_PACKET);
|
||||
}
|
||||
packetLen -= decr;
|
||||
tmp += decr - port->nBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we know how big it is, read the packet. We read the
|
||||
* entire packet, since the last call was just a peek.
|
||||
*/
|
||||
while (packetLen)
|
||||
{
|
||||
cc = recvfrom(port->sock, tmp, packetLen, 0,
|
||||
(struct sockaddr *) & (port->raddr), &addrLen);
|
||||
if (cc < 0)
|
||||
return (STATUS_ERROR);
|
||||
|
||||
/*
|
||||
* cc == 0 means the connection was broken at the other end.
|
||||
*/
|
||||
else if (!cc)
|
||||
return (STATUS_INVALID);
|
||||
|
||||
/*
|
||||
fprintf(stderr,"expected packet of %d bytes, got %d bytes\n",
|
||||
packetLen, cc);
|
||||
packetLen, cc);
|
||||
*/
|
||||
tmp += cc;
|
||||
packetLen -= cc;
|
||||
|
||||
/* if non-blocking, we're done. */
|
||||
if (nonBlocking && packetLen) {
|
||||
port->nBytes += cc;
|
||||
return(STATUS_NOT_DONE);
|
||||
tmp += cc;
|
||||
packetLen -= cc;
|
||||
|
||||
/* if non-blocking, we're done. */
|
||||
if (nonBlocking && packetLen)
|
||||
{
|
||||
port->nBytes += cc;
|
||||
return (STATUS_NOT_DONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
port->nBytes = 0;
|
||||
return(STATUS_OK);
|
||||
|
||||
port->nBytes = 0;
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -192,46 +214,47 @@ PacketReceive(Port *port, /* receive port */
|
||||
*
|
||||
* 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.
|
||||
* NOTES: Non-blocking writes would significantly complicate
|
||||
* buffer management. For now, we're not going to do it.
|
||||
*
|
||||
*/
|
||||
int
|
||||
PacketSend(Port *port,
|
||||
PacketBuf *buf,
|
||||
PacketLen len,
|
||||
bool nonBlocking)
|
||||
PacketSend(Port * port,
|
||||
PacketBuf * buf,
|
||||
PacketLen len,
|
||||
bool nonBlocking)
|
||||
{
|
||||
PacketLen totalLen;
|
||||
int addrLen = sizeof(struct sockaddr_in);
|
||||
|
||||
Assert(!nonBlocking);
|
||||
Assert(buf);
|
||||
|
||||
totalLen = len;
|
||||
|
||||
len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
|
||||
(struct sockaddr *)&(port->raddr), addrLen);
|
||||
|
||||
if (len < totalLen) {
|
||||
sprintf(PQerrormsg,
|
||||
"FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
|
||||
errno);
|
||||
fputs(PQerrormsg, stderr);
|
||||
return(STATUS_ERROR);
|
||||
}
|
||||
|
||||
return(STATUS_OK);
|
||||
PacketLen totalLen;
|
||||
int addrLen = sizeof(struct sockaddr_in);
|
||||
|
||||
Assert(!nonBlocking);
|
||||
Assert(buf);
|
||||
|
||||
totalLen = len;
|
||||
|
||||
len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
|
||||
(struct sockaddr *) & (port->raddr), addrLen);
|
||||
|
||||
if (len < totalLen)
|
||||
{
|
||||
sprintf(PQerrormsg,
|
||||
"FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
|
||||
errno);
|
||||
fputs(PQerrormsg, stderr);
|
||||
return (STATUS_ERROR);
|
||||
}
|
||||
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* StartupInfo2PacketBuf -
|
||||
* convert the fields of the StartupInfo to a PacketBuf
|
||||
* convert the fields of the StartupInfo to a PacketBuf
|
||||
*
|
||||
*/
|
||||
/* moved to src/libpq/fe-connect.c */
|
||||
/*
|
||||
PacketBuf*
|
||||
PacketBuf*
|
||||
StartupInfo2PacketBuf(StartupInfo* s)
|
||||
{
|
||||
PacketBuf* res;
|
||||
@@ -259,10 +282,10 @@ StartupInfo2PacketBuf(StartupInfo* s)
|
||||
|
||||
/*
|
||||
* PacketBuf2StartupInfo -
|
||||
* convert the fields of the StartupInfo to a PacketBuf
|
||||
* convert the fields of the StartupInfo to a PacketBuf
|
||||
*
|
||||
*/
|
||||
/* moved to postmaster.c
|
||||
/* moved to postmaster.c
|
||||
StartupInfo*
|
||||
PacketBuf2StartupInfo(PacketBuf* p)
|
||||
{
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pqsignal.c--
|
||||
* reliable BSD-style signal(2) routine stolen from RWW who stole it
|
||||
* from Stevens...
|
||||
* 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/backend/libpq/pqsignal.c,v 1.5 1996/12/26 22:07:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.6 1997/09/07 04:42:29 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This shouldn't be in libpq, but the monitor and some other
|
||||
* things need it...
|
||||
* This shouldn't be in libpq, but the monitor and some other
|
||||
* things need it...
|
||||
*
|
||||
* A NOTE ABOUT SIGNAL HANDLING ACROSS THE VARIOUS PLATFORMS.
|
||||
* A NOTE ABOUT SIGNAL HANDLING ACROSS THE VARIOUS PLATFORMS.
|
||||
*
|
||||
* config.h defines the macro USE_POSIX_SIGNALS for some platforms and
|
||||
* not for others. This file and pqsignal.h use that macro to decide
|
||||
* how to handle signalling.
|
||||
* config.h defines the macro USE_POSIX_SIGNALS for some platforms and
|
||||
* not for others. This file and pqsignal.h use that macro to decide
|
||||
* how to handle signalling.
|
||||
*
|
||||
* signal(2) handling - this is here because it affects some of
|
||||
* the frontend commands as well as the backend server.
|
||||
*
|
||||
* Ultrix and SunOS provide BSD signal(2) semantics by default.
|
||||
*
|
||||
* SVID2 and POSIX signal(2) semantics differ from BSD signal(2)
|
||||
* semantics. We can use the POSIX sigaction(2) on systems that
|
||||
* allow us to request restartable signals (SA_RESTART).
|
||||
*
|
||||
* Some systems don't allow restartable signals at all unless we
|
||||
* link to a special BSD library.
|
||||
*
|
||||
* We devoutly hope that there aren't any systems that provide
|
||||
* neither POSIX signals nor BSD signals. The alternative
|
||||
* is to do signal-handler reinstallation, which doesn't work well
|
||||
* at all.
|
||||
* signal(2) handling - this is here because it affects some of
|
||||
* the frontend commands as well as the backend server.
|
||||
*
|
||||
* Ultrix and SunOS provide BSD signal(2) semantics by default.
|
||||
*
|
||||
* SVID2 and POSIX signal(2) semantics differ from BSD signal(2)
|
||||
* semantics. We can use the POSIX sigaction(2) on systems that
|
||||
* allow us to request restartable signals (SA_RESTART).
|
||||
*
|
||||
* Some systems don't allow restartable signals at all unless we
|
||||
* link to a special BSD library.
|
||||
*
|
||||
* We devoutly hope that there aren't any systems that provide
|
||||
* neither POSIX signals nor BSD signals. The alternative
|
||||
* is to do signal-handler reinstallation, which doesn't work well
|
||||
* at all.
|
||||
* ------------------------------------------------------------------------*/
|
||||
#include <postgres.h>
|
||||
|
||||
@@ -47,18 +47,20 @@ pqsigfunc
|
||||
pqsignal(int signo, pqsigfunc func)
|
||||
{
|
||||
#if !defined(USE_POSIX_SIGNALS)
|
||||
return signal(signo, func);
|
||||
return signal(signo, func);
|
||||
#else
|
||||
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);
|
||||
#endif /* !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);
|
||||
#endif /* !USE_POSIX_SIGNALS */
|
||||
}
|
||||
|
||||
@@ -1,100 +1,100 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* util.c--
|
||||
* general routines for libpq backend
|
||||
* general routines for libpq backend
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/util.c,v 1.3 1996/11/06 08:48:33 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/util.c,v 1.4 1997/09/07 04:42:31 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* UTILITY ROUTINES
|
||||
* pqdebug - send a string to the debugging output port
|
||||
* pqdebug2 - send two strings to stdout
|
||||
* PQtrace - turn on pqdebug() tracing
|
||||
* PQuntrace - turn off pqdebug() tracing
|
||||
* UTILITY ROUTINES
|
||||
* pqdebug - send a string to the debugging output port
|
||||
* pqdebug2 - send two strings to stdout
|
||||
* PQtrace - turn on pqdebug() tracing
|
||||
* PQuntrace - turn off pqdebug() tracing
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* for sprintf() */
|
||||
#include <stdio.h> /* for sprintf() */
|
||||
#include <string.h>
|
||||
|
||||
#include <postgres.h>
|
||||
#include <lib/dllist.h>
|
||||
#include <libpq/libpq.h> /* where the declarations go */
|
||||
#include <libpq/libpq.h> /* where the declarations go */
|
||||
#include <utils/exc.h>
|
||||
|
||||
|
||||
/* ----------------
|
||||
* exceptions
|
||||
* exceptions
|
||||
* ----------------
|
||||
*/
|
||||
Exception MemoryError = {"Memory Allocation Error"};
|
||||
Exception PortalError = {"Invalid arguments to portal functions"};
|
||||
Exception PostquelError = {"Sql Error"};
|
||||
Exception ProtocolError = {"Protocol Error"};
|
||||
char PQerrormsg[ERROR_MSG_LENGTH];
|
||||
Exception MemoryError = {"Memory Allocation Error"};
|
||||
Exception PortalError = {"Invalid arguments to portal functions"};
|
||||
Exception PostquelError = {"Sql Error"};
|
||||
Exception ProtocolError = {"Protocol Error"};
|
||||
char PQerrormsg[ERROR_MSG_LENGTH];
|
||||
|
||||
int PQtracep = 0; /* 1 to print out debugging messages */
|
||||
FILE *debug_port = (FILE *) NULL;
|
||||
int PQtracep = 0; /* 1 to print out debugging messages */
|
||||
FILE *debug_port = (FILE *) NULL;
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* PQ utility routines
|
||||
* PQ utility routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
pqdebug(char *target, char *msg)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (PQtracep) {
|
||||
/*
|
||||
* if nothing else was suggested default to stdout
|
||||
*/
|
||||
if (!debug_port)
|
||||
debug_port = stdout;
|
||||
fprintf(debug_port, target, msg);
|
||||
fprintf(debug_port, "\n");
|
||||
}
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (PQtracep)
|
||||
{
|
||||
|
||||
/*
|
||||
* if nothing else was suggested default to stdout
|
||||
*/
|
||||
if (!debug_port)
|
||||
debug_port = stdout;
|
||||
fprintf(debug_port, target, msg);
|
||||
fprintf(debug_port, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pqdebug2(char *target, char *msg1, char *msg2)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (PQtracep) {
|
||||
/*
|
||||
* if nothing else was suggested default to stdout
|
||||
*/
|
||||
if (!debug_port)
|
||||
debug_port = stdout;
|
||||
fprintf(debug_port, target, msg1, msg2);
|
||||
fprintf(debug_port, "\n");
|
||||
}
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (PQtracep)
|
||||
{
|
||||
|
||||
/*
|
||||
* if nothing else was suggested default to stdout
|
||||
*/
|
||||
if (!debug_port)
|
||||
debug_port = stdout;
|
||||
fprintf(debug_port, target, msg1, msg2);
|
||||
fprintf(debug_port, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* PQtrace() / PQuntrace()
|
||||
* PQtrace() / PQuntrace()
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
PQtrace()
|
||||
{
|
||||
PQtracep = 1;
|
||||
PQtracep = 1;
|
||||
}
|
||||
|
||||
void
|
||||
PQuntrace()
|
||||
{
|
||||
PQtracep = 0;
|
||||
PQtracep = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user