aboutsummaryrefslogtreecommitdiff
path: root/src/backend/libpq/be-pqexec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/libpq/be-pqexec.c')
-rw-r--r--src/backend/libpq/be-pqexec.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/src/backend/libpq/be-pqexec.c b/src/backend/libpq/be-pqexec.c
new file mode 100644
index 00000000000..1b1738d4fc4
--- /dev/null
+++ b/src/backend/libpq/be-pqexec.c
@@ -0,0 +1,382 @@
+/*-------------------------------------------------------------------------
+ *
+ * be-pqexec.c--
+ * 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.1.1.1 1996/07/09 06:21:30 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ * PQfn - call a POSTGRES function
+ * PQexec - execute a POSTGRES query
+ *
+ * NOTES
+ * These routines are compiled into the postgres backend.
+ */
+#include "postgres.h"
+
+#include "nodes/pg_list.h"
+#include "tcop/dest.h"
+#include "tcop/fastpath.h"
+#include "tcop/tcopprot.h"
+#include "lib/dllist.h"
+#include "libpq/libpq-be.h"
+#include "fmgr.h"
+#include "utils/exc.h"
+#include "utils/builtins.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+
+/* ----------------------------------------------------------------
+ * PQ interface routines
+ * ----------------------------------------------------------------
+ */
+
+/* ----------------
+ * 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.
+ *
+ * This code scavanged from HandleFunctionRequest() in tcop/fastpath.h
+ * ----------------
+ */
+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)
+{
+ 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";
+}
+
+/* ----------------
+ * 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".
+ *
+ * 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 *
+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')
+ {
+ /* 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_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;
+}
+
+/* ----------------
+ * utilities for pqtest_PQfn()
+ * ----------------
+ */
+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);
+ (void) strncpy(newstr, str, len);
+ newstr[len] = (char) 0;
+ return newstr;
+}
+
+#define SKIP 0
+#define SCAN 1
+
+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;
+
+ }
+ }
+ return i;
+}
+
+/* ----------------
+ * 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*/
+ }
+ }
+
+ /* ----------------
+ * 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.
+ * ----------------
+ */
+int32
+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);
+}