summaryrefslogtreecommitdiff
path: root/src/backend/libpq/portal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/libpq/portal.c')
-rw-r--r--src/backend/libpq/portal.c783
1 files changed, 783 insertions, 0 deletions
diff --git a/src/backend/libpq/portal.c b/src/backend/libpq/portal.c
new file mode 100644
index 00000000000..ca27fd83089
--- /dev/null
+++ b/src/backend/libpq/portal.c
@@ -0,0 +1,783 @@
+/*-------------------------------------------------------------------------
+ *
+ * portal.c--
+ * generalized portal support routines
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portal.c,v 1.1.1.1 1996/07/09 06:21:30 scrappy 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
+ *
+ * INTERFACE ROUTINES
+ * PQnportals - Return the number of open portals.
+ * PQpnames - Return all the portal names
+ * PQparray - Return the portal buffer given a portal name
+ * PQrulep - Return 1 if an asynchronous portal
+ * PQntuples - Return the number of tuples in a portal buffer
+ * PQninstances - same as PQntuples using object terminology
+ * PQngroups - Return the number of tuple groups in a portal buffer
+ * PQntuplesGroup - Return the number of tuples in a tuple group
+ * PQninstancesGroup - same as PQntuplesGroup using object terminology
+ * PQnfieldsGroup - Return the number of fields in a tuple group
+ * PQfnumberGroup - Return field number given (group index, field name)
+ * PQftypeGroup - Return field type given (group index, field index)
+ * PQfsizeGroup - Return field size given (group index, field index)
+ * PQfnameGroup - Return field name given (group index, field index)
+ * PQgroup - Return the tuple group that a particular tuple is in
+ * PQgetgroup - Return the index of the group that a tuple is in
+ * PQnfields - Return the number of fields in a tuple
+ * PQfnumber - Return the field index of a field name in a tuple
+ * PQfname - Return the name of a field
+ * PQftype - Return the type of a field
+ * PQfsize - Return the size of a field
+ * PQftype - Return the type of a field
+ * PQsametype - Return 1 if the two tuples have the same type
+ * PQgetvalue - Return an attribute (field) value
+ * PQgetlength - Return an attribute (field) length
+ * PQclear - free storage claimed by named portal
+ * PQnotifies - Return a list of relations on which notification
+ * has occurred.
+ * PQremoveNotify - Remove this notification from the list.
+ *
+ * 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.
+ *
+ * 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
+ *
+ */
+#include <stdio.h> /* for sprintf() */
+#include <string.h>
+
+#include "c.h"
+#include "lib/dllist.h"
+#include "libpq/libpq.h" /* where the declarations go */
+#include "utils/exc.h"
+#include "utils/palloc.h"
+
+/* ----------------
+ * 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];
+
+int PQtracep = 0; /* 1 to print out debugging messages */
+FILE *debug_port = (FILE *) NULL;
+
+static int
+in_range(char *msg, int value, int min, int max)
+{
+ if (value < min || value >= max) {
+ (void) sprintf(PQerrormsg, "FATAL: %s, %d is not in range [%d,%d)\n",
+ msg, value, min, max);
+ pqdebug("%s", PQerrormsg);
+ fputs(PQerrormsg, stderr);
+ return(0);
+ }
+ return(1);
+}
+
+static int
+valid_pointer(char *msg, void *ptr)
+{
+ if (!ptr) {
+ (void) sprintf(PQerrormsg, "FATAL: %s\n", msg);
+ pqdebug("%s", PQerrormsg);
+ fputs(PQerrormsg, stderr);
+ return(0);
+ }
+ return(1);
+}
+
+/* ----------------------------------------------------------------
+ * 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");
+ }
+}
+
+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");
+ }
+}
+
+/* --------------------------------
+ * PQtrace() / PQuntrace()
+ * --------------------------------
+ */
+void
+PQtrace()
+{
+ PQtracep = 1;
+}
+
+void
+PQuntrace()
+{
+ PQtracep = 0;
+}
+
+/* ----------------------------------------------------------------
+ * PQ portal interface routines
+ * ----------------------------------------------------------------
+ */
+
+/* --------------------------------
+ * PQnportals - Return the number of open portals.
+ * If rule_p, only return asynchronous portals.
+ * --------------------------------
+ */
+int
+PQnportals(int rule_p)
+{
+ int i, n = 0;
+
+ for (i = 0; i < portals_array_size; ++i) {
+ if (portals[i] && portals[i]->portal) {
+ if (!rule_p || portals[i]->portal->rule_p) {
+ ++n;
+ }
+ }
+ }
+ return(n);
+}
+
+/* --------------------------------
+ * PQpnames - Return all the portal names
+ * If rule_p, only return asynchronous portals.
+ *
+ * the caller must have allocated sufficient memory for char** pnames
+ * (an array of PQnportals strings of length PortalNameLength).
+ *
+ * notice that this assumes that the user is calling PQnportals and
+ * PQpnames with the same rule_p argument, and with no intervening
+ * portal closures. if not, you can get in heap big trouble..
+ * --------------------------------
+ */
+void
+PQpnames(char **pnames, int rule_p)
+{
+ int i, cur_pname = 0;
+
+ if (!valid_pointer("PQpnames: invalid name buffer", pnames))
+ return;
+
+ for (i = 0; i < portals_array_size; ++i) {
+ if (portals[i] && portals[i]->portal) {
+ if (!rule_p || portals[i]->portal->rule_p) {
+ (void) strncpy(pnames[cur_pname], portals[i]->name, PortalNameLength);
+ ++cur_pname;
+ }
+ }
+ }
+}
+
+/* --------------------------------
+ * PQparray - Return the portal buffer given a portal name
+ * --------------------------------
+ */
+PortalBuffer *
+PQparray(char *pname)
+{
+ int i;
+
+ if (!valid_pointer("PQparray: invalid name buffer", pname))
+ return NULL;
+
+ if ((i = pbuf_getIndex(pname)) < 0)
+ return((PortalBuffer *) NULL);
+ return(portals[i]->portal);
+}
+
+/* --------------------------------
+ * PQrulep - Return 1 if an asynchronous portal
+ * --------------------------------
+ */
+int
+PQrulep(PortalBuffer *portal)
+{
+ if (!valid_pointer("PQrulep: invalid portal pointer", portal))
+ return(-1);
+
+ return(portal->rule_p);
+}
+
+/* --------------------------------
+ * PQntuples - Return the number of tuples in a portal buffer
+ * --------------------------------
+ */
+int
+PQntuples(PortalBuffer *portal)
+{
+ if (!valid_pointer("PQntuples: invalid portal pointer", portal))
+ return(-1);
+
+ return(portal->no_tuples);
+}
+
+int
+PQninstances(PortalBuffer *portal)
+{
+ return(PQntuples(portal));
+}
+
+/* --------------------------------
+ * PQngroups - Return the number of tuple groups in a portal buffer
+ * --------------------------------
+ */
+int
+PQngroups(PortalBuffer *portal)
+{
+ if (!valid_pointer("PQngroups: invalid portal pointer", portal))
+ return(-1);
+
+ return(portal->no_groups);
+}
+
+/* --------------------------------
+ * PQntuplesGroup - Return the number of tuples in a tuple group
+ * --------------------------------
+ */
+int
+PQntuplesGroup(PortalBuffer *portal, int group_index)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQntuplesGroup: invalid portal pointer", portal) ||
+ !in_range("PQntuplesGroup: group index",
+ group_index, 0, portal->no_groups))
+ return(-1);
+
+ gbp = pbuf_findGroup(portal, group_index);
+ if (gbp)
+ return(gbp->no_tuples);
+ return(-1);
+}
+
+int
+PQninstancesGroup(PortalBuffer *portal, int group_index)
+{
+ return(PQntuplesGroup(portal, group_index));
+}
+
+/* --------------------------------
+ * PQnfieldsGroup - Return the number of fields in a tuple group
+ * --------------------------------
+ */
+int
+PQnfieldsGroup(PortalBuffer *portal, int group_index)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQnfieldsGroup: invalid portal pointer", portal) ||
+ !in_range("PQnfieldsGroup: group index",
+ group_index, 0, portal->no_groups))
+ return(-1);
+ gbp = pbuf_findGroup(portal, group_index);
+ if (gbp)
+ return(gbp->no_fields);
+ return(-1);
+}
+
+/* --------------------------------
+ * PQfnumberGroup - Return the field number (index) given
+ * the group index and the field name
+ * --------------------------------
+ */
+int
+PQfnumberGroup(PortalBuffer *portal, int group_index, char *field_name)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfnumberGroup: invalid portal pointer", portal) ||
+ !valid_pointer("PQfnumberGroup: invalid field name pointer",
+ field_name) ||
+ !in_range("PQfnumberGroup: group index",
+ group_index, 0, portal->no_groups))
+ return(-1);
+ gbp = pbuf_findGroup(portal, group_index);
+ if (gbp)
+ return(pbuf_findFnumber(gbp, field_name));
+ return(-1);
+}
+
+/* --------------------------------
+ * PQfnameGroup - Return the field (attribute) name given
+ * the group index and field index.
+ * --------------------------------
+ */
+char *
+PQfnameGroup(PortalBuffer *portal, int group_index, int field_number)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfnameGroup: invalid portal pointer", portal) ||
+ !in_range("PQfnameGroup: group index",
+ group_index, 0, portal->no_groups))
+ return((char *) NULL);
+
+ if ((gbp = pbuf_findGroup(portal, group_index)) &&
+ in_range("PQfnameGroup: field number",
+ field_number, 0, gbp->no_fields))
+ return(pbuf_findFname(gbp, field_number));
+ return((char *) NULL);
+}
+
+/* --------------------------------
+ * PQftypeGroup - Return the type of a field given
+ * the group index and field index
+ * --------------------------------
+ */
+int
+PQftypeGroup(PortalBuffer *portal, int group_index, int field_number)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQftypeGroup: invalid portal pointer", portal) ||
+ !in_range("PQftypeGroup: group index",
+ group_index, 0, portal->no_groups))
+ return(-1);
+
+ if ((gbp = pbuf_findGroup(portal, group_index)) &&
+ in_range("PQftypeGroup: field number", field_number, 0, gbp->no_fields))
+ return(gbp->types[field_number].adtid);
+ return(-1);
+}
+
+/* --------------------------------
+ * PQfsizeGroup - Return the size of a field given
+ * the group index and field index
+ * --------------------------------
+ */
+int
+PQfsizeGroup(PortalBuffer *portal, int group_index, int field_number)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfsizeGroup: invalid portal pointer", portal) ||
+ !in_range("PQfsizeGroup: tuple index",
+ group_index, 0, portal->no_groups))
+ return(-1);
+
+ if ((gbp = pbuf_findGroup(portal, group_index)) &&
+ in_range("PQfsizeGroup: field number", field_number, 0, gbp->no_fields))
+ return(gbp->types[field_number].adtsize);
+ return(-1);
+}
+
+
+/* --------------------------------
+ * PQgroup - Return the tuple group that a particular tuple is in
+ * --------------------------------
+ */
+GroupBuffer *
+PQgroup(PortalBuffer *portal, int tuple_index)
+{
+ GroupBuffer *gbp;
+ int tuple_count = 0;
+
+ if (!valid_pointer("PQgroup: invalid portal pointer", portal) ||
+ !in_range("PQgroup: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return((GroupBuffer *) NULL);
+
+ for (gbp = portal->groups;
+ gbp && tuple_index >= (tuple_count += gbp->no_tuples);
+ gbp = gbp->next)
+ ;
+ if (!in_range("PQgroup: tuple not found: tuple index",
+ tuple_index, 0, tuple_count))
+ return((GroupBuffer *) NULL);
+ return(gbp);
+}
+
+/* --------------------------------
+ * PQgetgroup - Return the index of the group that a
+ * particular tuple is in
+ * --------------------------------
+ */
+int
+PQgetgroup(PortalBuffer *portal, int tuple_index)
+{
+ GroupBuffer *gbp;
+ int tuple_count = 0, group_count = 0;
+
+ if (!valid_pointer("PQgetgroup: invalid portal pointer", portal) ||
+ !in_range("PQgetgroup: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return(-1);
+
+ for (gbp = portal->groups;
+ gbp && tuple_index >= (tuple_count += gbp->no_tuples);
+ gbp = gbp->next)
+ ++group_count;
+ if (!gbp || !in_range("PQgetgroup: tuple not found: tuple index",
+ tuple_index, 0, tuple_count))
+ return(-1);
+ return(group_count);
+}
+
+/* --------------------------------
+ * PQnfields - Return the number of fields in a tuple
+ * --------------------------------
+ */
+int
+PQnfields(PortalBuffer *portal, int tuple_index)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQnfields: invalid portal pointer", portal) ||
+ !in_range("PQnfields: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return(-1);
+ gbp = PQgroup(portal, tuple_index);
+ if (gbp)
+ return(gbp->no_fields);
+ return(-1);
+}
+
+/* --------------------------------
+ * PQfnumber - Return the field index of a given
+ * field name within a tuple.
+ * --------------------------------
+ */
+int
+PQfnumber(PortalBuffer *portal, int tuple_index, char *field_name)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfnumber: invalid portal pointer", portal) ||
+ !valid_pointer("PQfnumber: invalid field name pointer", field_name) ||
+ !in_range("PQfnumber: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return(-1);
+ gbp = PQgroup(portal, tuple_index);
+ if (gbp)
+ return(pbuf_findFnumber(gbp, field_name));
+ return(-1);
+}
+
+/* --------------------------------
+ * PQfname - Return the name of a field
+ * --------------------------------
+ */
+char *
+PQfname(PortalBuffer *portal, int tuple_index, int field_number)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfname: invalid portal pointer", portal) ||
+ !in_range("PQfname: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return((char *) NULL);
+
+ if ((gbp = PQgroup(portal, tuple_index)) &&
+ in_range("PQfname: field number",
+ field_number, 0, gbp->no_fields))
+ return(pbuf_findFname(gbp, field_number));
+ return((char *) NULL);
+}
+
+/* --------------------------------
+ * PQftype - Return the type of a field
+ * --------------------------------
+ */
+int
+PQftype(PortalBuffer *portal, int tuple_index, int field_number)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQftype: invalid portal pointer", portal) ||
+ !in_range("PQfname: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return(-1);
+
+ if ((gbp = PQgroup(portal, tuple_index)) &&
+ in_range("PQftype: field number", field_number, 0, gbp->no_fields))
+ return(gbp->types[field_number].adtid);
+ return(-1);
+}
+
+/* --------------------------------
+ * PQfsize - Return the size of a field
+ * --------------------------------
+ */
+int
+PQfsize(PortalBuffer *portal, int tuple_index, int field_number)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfsize: invalid portal pointer", portal) ||
+ !in_range("PQfsize: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return(-1);
+
+ if ((gbp = PQgroup(portal, tuple_index)) &&
+ in_range("PQfsize: field number", field_number, 0, gbp->no_fields))
+ return(gbp->types[field_number].adtsize);
+ return(-1);
+}
+
+
+
+/* --------------------------------
+ * PQsametype - Return 1 if the two tuples have the same type
+ * (in the same group)
+ * --------------------------------
+ */
+int
+PQsametype(PortalBuffer *portal, int tuple_index1, int tuple_index2)
+{
+ GroupBuffer *gbp1, *gbp2;
+
+ if (!valid_pointer("PQsametype: invalid portal pointer", portal) ||
+ !in_range("PQsametype: tuple index 1",
+ tuple_index1, 0, portal->no_tuples) ||
+ !in_range("PQsametype: tuple index 2",
+ tuple_index2, 0, portal->no_tuples))
+ return(-1);
+
+ gbp1 = PQgroup(portal, tuple_index1);
+ gbp2 = PQgroup(portal, tuple_index2);
+ if (gbp1 && gbp2)
+ return(gbp1 == gbp2);
+ return(-1);
+}
+
+static TupleBlock *
+PQGetTupleBlock(PortalBuffer *portal,
+ int tuple_index,
+ int *tuple_offset)
+{
+ GroupBuffer *gbp;
+ TupleBlock *tbp;
+ int tuple_count = 0;
+
+ if (!valid_pointer("PQGetTupleBlock: invalid portal pointer", portal) ||
+ !valid_pointer("PQGetTupleBlock: invalid offset pointer",
+ tuple_offset) ||
+ !in_range("PQGetTupleBlock: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return((TupleBlock *) NULL);
+
+ for (gbp = portal->groups;
+ gbp && tuple_index >= (tuple_count += gbp->no_tuples);
+ gbp = gbp->next)
+ ;
+ if (!gbp ||
+ !in_range("PQGetTupleBlock: tuple not found: tuple index",
+ tuple_index, 0, tuple_count))
+ return((TupleBlock *) NULL);
+ tuple_count -= gbp->no_tuples;
+ for (tbp = gbp->tuples;
+ tbp && tuple_index >= (tuple_count += TupleBlockSize);
+ tbp = tbp->next)
+ ;
+ if (!tbp ||
+ !in_range("PQGetTupleBlock: tuple not found: tuple index",
+ tuple_index, 0, tuple_count))
+ return((TupleBlock *) NULL);
+ tuple_count -= TupleBlockSize;
+
+ *tuple_offset = tuple_index - tuple_count;
+ return(tbp);
+}
+
+/* --------------------------------
+ * PQgetvalue - Return an attribute (field) value
+ * --------------------------------
+ */
+char *
+PQgetvalue(PortalBuffer *portal,
+ int tuple_index,
+ int field_number)
+{
+ TupleBlock *tbp;
+ int tuple_offset;
+
+ tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
+ if (tbp)
+ return(tbp->values[tuple_offset][field_number]);
+ return((char *) NULL);
+}
+
+/* --------------------------------
+ * PQgetAttr - Return an attribute (field) value
+ * this differs from PQgetvalue in that the value returned is
+ * a copy. The CALLER is responsible for free'ing the data returned.
+ * --------------------------------
+ */
+char *
+PQgetAttr(PortalBuffer *portal,
+ int tuple_index,
+ int field_number)
+{
+ TupleBlock *tbp;
+ int tuple_offset;
+ int len;
+ char* result = NULL;
+
+ tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
+ if (tbp) {
+ len = tbp->lengths[tuple_offset][field_number];
+ result = malloc(len + 1);
+ memcpy(result,
+ tbp->values[tuple_offset][field_number],
+ len);
+ result[len] = '\0';
+ }
+ return result;
+}
+
+
+/* --------------------------------
+ * PQgetlength - Return an attribute (field) length
+ * --------------------------------
+ */
+int
+PQgetlength(PortalBuffer *portal,
+ int tuple_index,
+ int field_number)
+{
+ TupleBlock *tbp;
+ int tuple_offset;
+
+ tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
+ if (tbp)
+ return(tbp->lengths[tuple_offset][field_number]);
+ return(-1);
+}
+
+/* ----------------
+ * PQclear - free storage claimed by named portal
+ * ----------------
+ */
+void
+PQclear(char *pname)
+{
+ if (!valid_pointer("PQclear: invalid portal name pointer", pname))
+ return;
+ pbuf_close(pname);
+}
+
+/*
+ * async notification.
+ * This is going away with pending rewrite of comm. code...
+ */
+/* static SLList pqNotifyList;*/
+static Dllist *pqNotifyList = NULL;
+
+/* remove invalid notifies before returning */
+void
+PQcleanNotify()
+{
+ Dlelem *e, *next;
+ PQNotifyList *p;
+
+ e = DLGetHead(pqNotifyList);
+
+ while (e) {
+ next = DLGetSucc(e);
+ p = (PQNotifyList*)DLE_VAL(e);
+ if (p->valid == 0) {
+ DLRemove(e);
+ DLFreeElem(e);
+ pfree(p);
+ }
+ e = next;
+ }
+}
+
+void
+PQnotifies_init()
+{
+ Dlelem *e;
+ PQNotifyList *p;
+
+ if (pqNotifyList == NULL) {
+ pqNotifyList = DLNewList();
+ }
+ else {
+ /* clean all notifies */
+ for (e = DLGetHead(pqNotifyList); e != NULL; e = DLGetSucc(e)) {
+ p = (PQNotifyList*)DLE_VAL(e);
+ p->valid = 0;
+ }
+ PQcleanNotify();
+ }
+}
+
+PQNotifyList *
+PQnotifies()
+{
+ Dlelem *e;
+ PQcleanNotify();
+ e = DLGetHead(pqNotifyList);
+ return (e ? (PQNotifyList*)DLE_VAL(e) : NULL);
+}
+
+void
+PQremoveNotify(PQNotifyList *nPtr)
+{
+ nPtr->valid = 0; /* remove later */
+}
+
+void
+PQappendNotify(char *relname, int pid)
+{
+ PQNotifyList *p;
+
+ if (pqNotifyList == NULL)
+ pqNotifyList = DLNewList();
+
+ p = (PQNotifyList*)pbuf_alloc(sizeof(PQNotifyList));
+ strncpy(p->relname, relname, NAMEDATALEN);
+ p->be_pid = pid;
+ p->valid = 1;
+ DLAddTail(pqNotifyList, DLNewElem(p));
+}