summaryrefslogtreecommitdiff
path: root/src/backend/tioga
diff options
context:
space:
mode:
authorMarc G. Fournier1996-07-09 06:22:35 +0000
committerMarc G. Fournier1996-07-09 06:22:35 +0000
commitd31084e9d1118b25fd16580d9d8c2924b5740dff (patch)
tree3179e66307d54df9c7b966543550e601eb55e668 /src/backend/tioga
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/tioga')
-rw-r--r--src/backend/tioga/Arr_TgRecipe.h120
-rw-r--r--src/backend/tioga/Makefile.inc21
-rw-r--r--src/backend/tioga/Varray.c48
-rw-r--r--src/backend/tioga/Varray.h45
-rw-r--r--src/backend/tioga/tgRecipe.c694
-rw-r--r--src/backend/tioga/tgRecipe.h121
6 files changed, 1049 insertions, 0 deletions
diff --git a/src/backend/tioga/Arr_TgRecipe.h b/src/backend/tioga/Arr_TgRecipe.h
new file mode 100644
index 00000000000..365f4647d6e
--- /dev/null
+++ b/src/backend/tioga/Arr_TgRecipe.h
@@ -0,0 +1,120 @@
+#include "tioga/Varray.h"
+
+/* Modify the following size macros to suit your need. */
+
+#ifndef Arr_TgString_INITIAL_SIZE
+#define Arr_TgString_INITIAL_SIZE 32
+#endif
+
+#ifndef Arr_TgElementPtr_INITIAL_SIZE
+#define Arr_TgElementPtr_INITIAL_SIZE 32
+#endif
+
+#ifndef Arr_TgNodePtr_INITIAL_SIZE
+#define Arr_TgNodePtr_INITIAL_SIZE 32
+#endif
+/***************************************************************/
+/* Do not modify anything below this line. */
+/***************************************************************/
+
+/* -- Defining types and function for Arr_TgString type -- */
+/* -- the following must be supplied by the user:
+
+ void copyTgString(TgString* from, TgString* to); - make a copy of TgString.
+*/
+
+#ifndef _ARR_TgString_
+#define _ARR_TgString_
+
+#ifndef ARR_TgString_INITIAL_SIZE
+#define ARR_TgString_INITIAL_SIZE 32 /* change this size to suit your need */
+#endif /* ARR_TgString_INITIAL_SIZE */
+
+typedef struct Arr_TgString {
+ size_t num;
+ size_t size;
+ size_t valSize;
+ TgString *val;
+} Arr_TgString;
+
+#define newArr_TgString() \
+ (Arr_TgString *) NewVarray(ARR_TgString_INITIAL_SIZE, sizeof(TgString))
+
+#define enlargeArr_TgString(A, I) \
+ (A)->size += (I); \
+ (A)->val = (TgString *) realloc((A)->val, (A)->valSize * (A)->size)
+
+#define addArr_TgString(A, V) \
+ AppendVarray((Varray *) (A), (void *) (V), (CopyingFunct) copyTgString)
+
+#define deleteArr_TgString(A) FreeVarray(A)
+
+#endif /* _ARR_TgString_ */
+
+/* -- Defining types and function for Arr_TgElementPtr type -- */
+/* -- the following must be supplied by the user:
+
+ void copyTgElementPtr(TgElementPtr* from, TgElementPtr* to); - make a copy of TgElementPtr.
+*/
+
+#ifndef _ARR_TgElementPtr_
+#define _ARR_TgElementPtr_
+
+#ifndef ARR_TgElementPtr_INITIAL_SIZE
+#define ARR_TgElementPtr_INITIAL_SIZE 32 /* change this size to suit your need */
+#endif /* ARR_TgElementPtr_INITIAL_SIZE */
+
+typedef struct Arr_TgElementPtr {
+ size_t num;
+ size_t size;
+ size_t valSize;
+ TgElementPtr *val;
+} Arr_TgElementPtr;
+
+#define newArr_TgElementPtr() \
+ (Arr_TgElementPtr *) NewVarray(ARR_TgElementPtr_INITIAL_SIZE, sizeof(TgElementPtr))
+
+#define enlargeArr_TgElementPtr(A, I) \
+ (A)->size += (I); \
+ (A)->val = (TgElementPtr *) realloc((A)->val, (A)->valSize * (A)->size)
+
+#define addArr_TgElementPtr(A, V) \
+ AppendVarray((Varray *) (A), (void *) (V), (CopyingFunct) copyTgElementPtr)
+
+#define deleteArr_TgElementPtr(A) FreeVarray(A)
+
+#endif /* _ARR_TgElementPtr_ */
+
+/* -- Defining types and function for Arr_TgNodePtr type -- */
+/* -- the following must be supplied by the user:
+
+ void copyTgNodePtr(TgNodePtr* from, TgNodePtr* to); - make a copy of TgNodePtr.
+*/
+
+#ifndef _ARR_TgNodePtr_
+#define _ARR_TgNodePtr_
+
+#ifndef ARR_TgNodePtr_INITIAL_SIZE
+#define ARR_TgNodePtr_INITIAL_SIZE 32 /* change this size to suit your need */
+#endif /* ARR_TgNodePtr_INITIAL_SIZE */
+
+typedef struct Arr_TgNodePtr {
+ size_t num;
+ size_t size;
+ size_t valSize;
+ TgNodePtr *val;
+} Arr_TgNodePtr;
+
+#define newArr_TgNodePtr() \
+ (Arr_TgNodePtr *) NewVarray(ARR_TgNodePtr_INITIAL_SIZE, sizeof(TgNodePtr))
+
+#define enlargeArr_TgNodePtr(A, I) \
+ (A)->size += (I); \
+ (A)->val = (TgNodePtr *) realloc((A)->val, (A)->valSize * (A)->size)
+
+#define addArr_TgNodePtr(A, V) \
+ AppendVarray((Varray *) (A), (void *) (V), (CopyingFunct) copyTgNodePtr)
+
+#define deleteArr_TgNodePtr(A) FreeVarray(A)
+
+#endif /* _ARR_TgNodePtr_ */
diff --git a/src/backend/tioga/Makefile.inc b/src/backend/tioga/Makefile.inc
new file mode 100644
index 00000000000..57086e6db6d
--- /dev/null
+++ b/src/backend/tioga/Makefile.inc
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for the Tioga module
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/backend/tioga/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:22:00 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+VPATH:= $(VPATH):$(CURDIR)/tioga
+
+SRCS_TIOGA= tgRecipe.c Varray.c
+
+HEADERS+= tgRecipe.h Arr_TgRecipe.h Varray.h
+
+
+
diff --git a/src/backend/tioga/Varray.c b/src/backend/tioga/Varray.c
new file mode 100644
index 00000000000..3ed45c66561
--- /dev/null
+++ b/src/backend/tioga/Varray.c
@@ -0,0 +1,48 @@
+/* ************************************************************************
+ *
+ * Varray.c --
+ *
+ * routines to provide a generic set of functions to handle variable sized
+ * arrays. originally by Jiang Wu
+ * ************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "Varray.h"
+
+Varray *NewVarray(size_t nobj, size_t size)
+/*
+ * NewVarray -- allocate a Varray to contain an array of val each of which
+ * is size valSize. Returns the Varray if successful,
+ * returns NULL otherwise.
+ */
+{
+ Varray *result;
+
+ if (nobj == 0)
+ nobj = VARRAY_INITIAL_SIZE;
+ result = (Varray *) malloc(sizeof(Varray));
+ result->val = (void *) calloc(nobj, size);
+ if (result == NULL)
+ return NULL;
+ result->size = size;
+ result->nobj = 0;
+ result->maxObj = nobj;
+ return result;
+}
+
+int AppendVarray(Varray *array, void *value, CopyingFunct copy)
+/*
+ * AppendVarray -- append value to the end of array. This function
+ * returns the size of the array after the addition of
+ * the new element.
+ */
+{
+ copy(value, VARRAY_NTH(array->val, array->size, array->nobj));
+ array->nobj++;
+ if (array->nobj >= array->maxObj) {
+ ENLARGE_VARRAY(array, array->maxObj / 2);
+ }
+ return array->nobj;
+}
+
diff --git a/src/backend/tioga/Varray.h b/src/backend/tioga/Varray.h
new file mode 100644
index 00000000000..f6d01c23db4
--- /dev/null
+++ b/src/backend/tioga/Varray.h
@@ -0,0 +1,45 @@
+/* ********************************************************************
+ *
+ * Varray.h -- header file for varray.c which provides a generic
+ * set of functions to handle variable sized arrays.
+ *
+ * originally by Jiang Wu
+ * ********************************************************************/
+
+#ifndef _VARRAY_H_
+#define _VARRAY_H_
+
+typedef struct _varray {
+ size_t nobj; /* number of objects in this array */
+ size_t maxObj; /* max. number of objects in this array */
+ size_t size; /* size of each element in the array */
+ void *val; /* array of elements */
+} Varray;
+
+/* type for custom copying function */
+typedef void (*CopyingFunct) (void *from, void *to);
+
+#define VARRAY_INITIAL_SIZE 32
+
+#define ENLARGE_VARRAY(ARRAY, INC) \
+ (ARRAY)->maxObj += (INC); \
+ (ARRAY)->val = (void *) realloc((ARRAY)->val, \
+ (ARRAY)->size * (ARRAY)->maxObj)
+
+#define VARRAY_NTH(VAL, SIZE, N) (((char *) (VAL)) + (SIZE) * (N))
+
+#define FreeVarray(ARRAY) \
+ if ((ARRAY) != NULL) { free((ARRAY)->val); free((ARRAY)); (ARRAY) = NULL ; }
+
+#define ModifyVarray(ARRAY, N, NEW, COPY) \
+ if ((N) < (ARRAY)->nobj) \
+ (COPY)(VARRAY_NTH((ARRAY)->val, (ARRAY)->size, (N)), (NEW))
+
+#define GetVarray(ARRAY, N) \
+ ((N) < (ARRAY)->nobj ? VARRAY_NTH((ARRAY)->val, (ARRAY)->size, (N)) \
+ : NULL)
+
+extern Varray *NewVarray(size_t nobj, size_t size);
+extern int AppendVarray(Varray *array, void *value, CopyingFunct copy);
+
+#endif /* _VARRAY_H_ */
diff --git a/src/backend/tioga/tgRecipe.c b/src/backend/tioga/tgRecipe.c
new file mode 100644
index 00000000000..ea52a715104
--- /dev/null
+++ b/src/backend/tioga/tgRecipe.c
@@ -0,0 +1,694 @@
+/*-------------------------------------------------------------------------
+ *
+ * tgRecipe.c--
+ * Tioga recipe-related definitions
+ * these functions can be used in both the frontend and the
+ * backend
+ *
+ * this file must be kept current with recipe-schema.sql
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/tioga/Attic/tgRecipe.c,v 1.1.1.1 1996/07/09 06:22:00 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include <stdlib.h>
+#include "tioga/tgRecipe.h"
+
+#include "catalog/catalog.h" /*for newoid() */
+
+static Arr_TgString *TextArray2ArrTgString(char *str);
+
+#define ARRAY_LEFT_DELIM '{'
+#define ARRAY_RIGHT_DELIM '}'
+#define ARRAY_ELEM_LEFT '"'
+#define ARRAY_ELEM_RIGHT '"'
+#define ARRAY_ELEM_SEPARATOR ','
+
+/* maximum length of query string */
+#define MAX_QBUF_LENGTH 2048
+
+/**** the queries being used ********/
+#define Q_RETRIEVE_RECIPE_BYNAME \
+ "select * from Recipes where Recipes.elemName = '%s';"
+#define Q_RETRIEVE_ELEMENTS_IN_RECIPE \
+ "select e.* from Element e, Node n where n.belongsTo = '%s' and n.nodeElem = e.elemName;"
+#define Q_RETRIEVE_NODES_IN_RECIPE \
+ "select * from Node n where n.belongsTo = '%s'"
+#define Q_LOOKUP_EDGES_IN_RECIPE \
+ "select * from Edge e where e.belongsTo = '%s'"
+
+/* static functions only used here */
+static void fillTgElement(TgElement *elem, PortalBuffer *pbuf, int tupno);
+static void fillTgNode(TgRecipe *r, TgNode *node, PortalBuffer *pbuf, int tupno);
+static TgRecipe* fillTgRecipe(PortalBuffer* pbuf, int tupno);
+static void lookupEdges(TgRecipe *r, char* name);
+static void fillAllNodes(TgRecipe *r, char* name);
+static void fillAllElements(TgRecipe *r, char* name);
+static TgNode* connectTee(TgRecipe *r, TgNodePtr fromNode, TgNodePtr toNode,
+ int fromPort, int toPort);
+
+/*
+ * TextArray2ArrTgString -- take a string of the form:
+ * {"fooo", "bar", "xxxxx"} (for postgres)
+ * and parse it into a Array of TgString's
+ *
+ * always returns a valid Arr_TgString. It could be a newly initialized one with
+ * zero elements
+ */
+Arr_TgString*
+TextArray2ArrTgString(char *str)
+{
+ Arr_TgString *result;
+
+ char* beginQuote;
+ char* endQuote;
+ int nextlen;
+ char* word;
+
+ result = newArr_TgString();
+
+ if ((str == NULL) || (str[0] == '\0'))
+ return result;
+
+ if (*str != ARRAY_LEFT_DELIM) {
+ elog(NOTICE,"TextArray2ArrTgString: badly formed string, must have %c as \
+first character\n", ARRAY_LEFT_DELIM);
+ return result;
+ }
+
+ str++; /* skip the first { */
+ while ( *str != '}' ) {
+ if (*str == '\0') {
+ elog(NOTICE,"TextArray2ArrTgString: text string ended prematurely\n");
+ return result;
+ }
+
+ if ((beginQuote = index(str, ARRAY_ELEM_LEFT)) == NULL) {
+ elog(NOTICE,"textArray2ArrTgString: missing a begin quote\n");
+ return result;
+ }
+ if ( (endQuote = index(beginQuote+1,'"')) == NULL) {
+ elog(NOTICE,"textArray2ArrTgString: missing an end quote\n");
+ return result;
+ }
+ nextlen = endQuote - beginQuote; /* don't subtract one here because we
+ need the extra character for \0 anyway */
+ word = (char*) malloc(nextlen);
+ strncpy(word, beginQuote+1, nextlen-1);
+ word[nextlen-1] ='\0';
+ addArr_TgString(result, (TgString*)&word);
+ free (word);
+ str = endQuote + 1;
+ }
+ return result;
+}
+
+/* -------------------------------------
+findElemInRecipe()
+ given an element name, find that element in the TgRecipe structure and return it.
+
+ XXX Currently, this is done by linear search. Change to using a hash table.
+-------------------------------------- */
+
+TgElement*
+findElemInRecipe(TgRecipe *r, char* elemName)
+{
+ int i;
+ Arr_TgElementPtr* arr = r->elements;
+ TgElement* e;
+
+ for (i=0;i<arr->num;i++) {
+ e = (TgElement*)arr->val[i];
+ if (strcmp(e->elemName, elemName) == 0)
+ return e;
+ }
+ elog (NOTICE, "Element named %s not found in recipe named %s", elemName, r->elmValue.elemName);
+ return NULL;
+}
+
+/* -------------------------------------
+findNodeInRecipe()
+ given an node name, find that node in the TgRecipe structure and return it.
+
+ XXX Currently, this is done by linear search. Change to using a hash table.
+-------------------------------------- */
+
+TgNode*
+findNodeInRecipe(TgRecipe *r, char* nodeName)
+{
+ int i;
+ Arr_TgNodePtr* arr = r->allNodes;
+ TgNode *n;
+
+ for (i=0;i<arr->num;i++) {
+ n = (TgNode*)arr->val[i];
+ if (strcmp(n->nodeName, nodeName) == 0)
+ return n;
+ }
+ elog (NOTICE, "Node named %s not found in recipe named %s", nodeName, r->elmValue.elemName);
+ return NULL;
+}
+
+
+/* -------------------------------------
+fillTgNode
+ takes a query result in the PortalBuffer containing a Node
+ and converts it to a C Node strcture.
+ The Node structure passed in is 'filled' appropriately
+
+-------------------------------------- */
+
+void
+fillTgNode(TgRecipe* r, TgNode *node, PortalBuffer *pbuf, int tupno)
+{
+ char* nodeType;
+ char* nodeElem;
+ char* locString; /* ascii string rep of the point */
+ static int attnums_initialized = 0;
+ static int nodeName_attnum;
+ static int nodeElem_attnum;
+ static int nodeType_attnum;
+ static int loc_attnum;
+ TgNodePtr BlankNodePtr;
+ int i;
+
+ if (!attnums_initialized) {
+ /* the first time fillTgNode is called,
+ we find out all the relevant attribute numbers in a TgNode
+ so subsequent calls are speeded up,
+ the assumption is that the schema won't change between calls*/
+ nodeName_attnum = PQfnumber(pbuf, tupno, "nodeName");
+ nodeElem_attnum = PQfnumber(pbuf, tupno, "nodeElem");
+ nodeType_attnum = PQfnumber(pbuf, tupno, "nodeType");
+ loc_attnum = PQfnumber(pbuf, tupno, "loc");
+ attnums_initialized = 1;
+ }
+ node->nodeName = PQgetAttr(pbuf, tupno, nodeName_attnum);
+ locString = PQgetvalue(pbuf, tupno, loc_attnum);
+ if (locString == NULL || locString[0] == '\0') {
+ node->loc.x = 0; node->loc.y = 0; /* assign to zero for default */
+ }
+ else
+ {
+ float x,y;
+ sscanf(locString, "(%f, %f)", &x, &y);
+ node->loc.x = x;
+ node->loc.y = y;
+ }
+ nodeElem = PQgetvalue(pbuf, tupno, nodeElem_attnum);
+ node->nodeElem = findElemInRecipe(r,nodeElem);
+ node->inNodes = newArr_TgNodePtr();
+ node->outNodes = newArr_TgNodePtr();
+
+ /* fill the inNodes array with as many NULL's are there are inPorts in
+ * the underlying element */
+ BlankNodePtr = (TgNodePtr)NULL;
+ for (i = 0 ; i < node->nodeElem->inPorts->num ; i++)
+ addArr_TgNodePtr(node->inNodes, &BlankNodePtr);
+
+ /* fill the outNodes array with as many NULL's are there are inPorts in
+ * the underlying element */
+ for (i = 0 ; i < node->nodeElem->outPorts->num ; i++)
+ addArr_TgNodePtr(node->outNodes, &BlankNodePtr);
+
+ nodeType = PQgetvalue(pbuf, tupno, nodeType_attnum);
+
+ if (strcmp(nodeType, "Ingred") == 0)
+ node->nodeType = TG_INGRED_NODE;
+ else if (strcmp(nodeType, "Eye") == 0)
+ node->nodeType = TG_EYE_NODE;
+ else if (strcmp(nodeType, "Recipe") == 0)
+ node->nodeType = TG_RECIPE_NODE;
+ else
+ elog(NOTICE, "fillTgNode: unknown nodeType field value : %s\n", nodeType);
+
+}
+
+/* -------------------------------------
+fillTgElement
+ takes a query result in the PortalBuffer containing a Element
+ and converts it to a C TgElement strcture.
+ The TgElement structure passed in is 'filled' appropriately
+ ------------------------------------ */
+
+void
+fillTgElement(TgElement *elem, PortalBuffer *pbuf, int tupno)
+{
+ char* srcLang, *elemType;
+ static int attnums_initialized = 0;
+ static int elemName_attnum;
+ static int elemType_attnum;
+ static int inPorts_attnum;
+ static int inTypes_attnum;
+ static int outPorts_attnum;
+ static int outTypes_attnum;
+ static int doc_attnum;
+ static int keywords_attnum;
+ static int icon_attnum;
+ static int srcLang_attnum;
+ static int src_attnum;
+ static int owner_attnum;
+
+ if (!attnums_initialized) {
+ /* the first time fillTgElement is called,
+ we find out all the relevant attribute numbers in a TgElement
+ so subsequent calls are speeded up,
+ the assumption is that the schema won't change between calls*/
+ elemName_attnum = PQfnumber(pbuf, tupno, "elemName");
+ elemType_attnum = PQfnumber(pbuf, tupno, "elemType");
+ inPorts_attnum = PQfnumber(pbuf, tupno, "inPorts");
+ inTypes_attnum = PQfnumber(pbuf, tupno, "inTypes");
+ outPorts_attnum = PQfnumber(pbuf, tupno, "outPorts");
+ outTypes_attnum = PQfnumber(pbuf, tupno, "outTypes");
+ doc_attnum = PQfnumber(pbuf, tupno, "doc");
+ keywords_attnum = PQfnumber(pbuf, tupno, "keywords");
+ icon_attnum = PQfnumber(pbuf, tupno, "icon");
+ srcLang_attnum = PQfnumber(pbuf, tupno, "srcLang");
+ src_attnum = PQfnumber(pbuf, tupno, "src");
+ attnums_initialized = 1;
+ }
+
+ elem->elemName = PQgetAttr(pbuf, tupno, elemName_attnum);
+ elem->inPorts = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, inPorts_attnum));
+ elem->inTypes = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, inTypes_attnum));
+ elem->outPorts = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, outPorts_attnum));
+ elem->outTypes = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, outTypes_attnum));
+ elem->doc = PQgetAttr(pbuf, tupno, doc_attnum);
+ elem->keywords = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, keywords_attnum));
+ elem->icon = PQgetAttr(pbuf,tupno, icon_attnum);
+ elem->src = PQgetAttr(pbuf,tupno, src_attnum);
+ elem->owner = PQgetAttr(pbuf,tupno, owner_attnum);
+
+ /* we don't need to keep the value returned so use PQgetvalue()
+ instead of PQgetAttr() */
+ srcLang = PQgetvalue(pbuf,tupno, srcLang_attnum);
+
+ if (strcmp(srcLang, "SQL") == 0)
+ elem->srcLang = TG_SQL;
+ else
+ if (strcmp(srcLang, "C") == 0)
+ elem->srcLang = TG_C;
+ else
+ if (strcmp(srcLang, "RecipeGraph") == 0)
+ elem->srcLang = TG_RECIPE_GRAPH;
+ else
+ if (strcmp(srcLang, "Compiled") == 0)
+ elem->srcLang = TG_COMPILED;
+ else
+ elog(NOTICE, "fillTgElement(): unknown srcLang field value : %s\n", srcLang);
+
+ elemType = PQgetvalue(pbuf, tupno, elemType_attnum);
+ if (strcmp(elemType, "Ingred") == 0)
+ elem->elemType = TG_INGRED;
+ else if (strcmp(elemType, "Eye") == 0)
+ elem->elemType = TG_EYE;
+ else if (strcmp(elemType, "Recipe") == 0)
+ elem->elemType = TG_RECIPE;
+ else
+ elog(NOTICE, "fillTgElement(): unknown elemType field value : %s\n", elemType);
+
+
+}
+/* -------------------------------------
+lookupEdges -
+ look up the edges of a recipe and fill in the inNodes
+ and outNodes of each node.
+ In the process of connecting edges, we detect tee's and create
+ teeNodes. We add the teeNodes to the allNodes field of r as well
+------------------------------------ */
+void
+lookupEdges(TgRecipe *r, char* name)
+{
+ char qbuf[MAX_QBUF_LENGTH];
+ int i;
+ char *pqres;
+ char *pbufname;
+ PortalBuffer *pbuf;
+ int ntups;
+ int fromNode_attnum;
+ int fromPort_attnum;
+ int toPort_attnum;
+ int toNode_attnum;
+ char *toNode, *fromNode;
+ char *toPortStr, *fromPortStr;
+ int toPort, fromPort;
+
+ TgNodePtr fromNodePtr, toNodePtr;
+
+ sprintf(qbuf, Q_LOOKUP_EDGES_IN_RECIPE, name);
+ pqres = PQexec(qbuf);
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E') {
+ elog(NOTICE, "lookupEdges(): Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf,0);
+
+ if (ntups == 0) { return; }
+
+ fromNode_attnum = PQfnumber(pbuf, 0, "fromNode");
+ fromPort_attnum = PQfnumber(pbuf, 0, "fromPort");
+ toNode_attnum = PQfnumber(pbuf, 0, "toNode");
+ toPort_attnum = PQfnumber(pbuf, 0, "toPort");
+
+ for (i=0;i<ntups;i++) {
+
+ fromNode = PQgetvalue(pbuf, i, fromNode_attnum);
+ toNode = PQgetvalue(pbuf, i, toNode_attnum);
+ fromPortStr = PQgetvalue(pbuf, i, fromPort_attnum);
+ toPortStr = PQgetvalue(pbuf, i, toPort_attnum);
+
+ if (!fromPortStr || fromPortStr[0] == '\0') {
+ elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with invalid fromPort value!");
+ return;
+ }
+ if (!toPortStr || toPortStr[0] == '\0') {
+ elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with invalid toPort value!!");
+ return;
+ }
+ fromPort = atoi(fromPortStr);
+ toPort = atoi(toPortStr);
+
+ fromNodePtr = findNodeInRecipe(r, fromNode);
+ if (!fromNodePtr) {
+ elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with bad fromNode value!");
+ return;
+ }
+ toNodePtr = findNodeInRecipe(r, toNode);
+ if (!toNodePtr) {
+ elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with bad toNode value!");
+ return;
+ }
+
+ /* check to see if the from port is already connected.
+ if it is, then this means we should construct a Tee node
+ */
+ if (fromNodePtr->outNodes->val[fromPort-1] != NULL) {
+ TgNodePtr tn;
+
+ tn = connectTee(r,fromNodePtr, toNodePtr, fromPort, toPort);
+ addArr_TgNodePtr(r->allNodes,&tn);
+ } else {
+ fromNodePtr->outNodes->val[fromPort-1] = toNodePtr;
+ toNodePtr->inNodes->val[toPort-1] = fromNodePtr;
+ }
+ }
+
+ PQclear(pbufname);
+}
+
+/*
+ handle tee connections here
+ Everytime an output port is connected multiply,
+ we explicitly insert TgTeeNode
+
+ returns the teeNode created
+*/
+static TgNode*
+connectTee(TgRecipe *r, TgNodePtr fromNode, TgNodePtr toNode,
+ int fromPort, int toPort)
+{
+ TgNodePtr origToNode;
+ TgNodePtr tn;
+ TgNodePtr BlankNodePtr;
+ int origToPort;
+ int i;
+
+ /* the toNode formerly pointed to */
+ origToNode = fromNode->outNodes->val[fromPort-1];
+
+ if (origToNode == NULL) {
+ elog(NOTICE,"Internal Error: connectTee() called with a null origToNode");
+ return;
+ }
+
+ for (i=0;i<origToNode->inNodes->num;i++) {
+ if (origToNode->inNodes->val[i] == fromNode)
+ break;
+ }
+
+ /* the inport of the former toNode */
+ /* ports start with 1, array indices start from 0 */
+ origToPort = i + 1;
+
+ /* add a tee node now. */
+ tn = malloc(sizeof(TgNode));
+ /* generate a name for the tee node table */
+ tn->nodeName = malloc(50);
+ sprintf(tn->nodeName, "tee_%d", newoid());
+/* tn->nodeName = NULL; */
+
+ tn->nodeType = TG_TEE_NODE;
+ tn->nodeElem = NULL;
+ tn->inNodes = newArr_TgNodePtr();
+ tn->outNodes = newArr_TgNodePtr();
+
+ BlankNodePtr = (TgNodePtr)NULL;
+ /* each TgTeeNode has one input and two outputs, NULL them initiallly */
+ addArr_TgNodePtr(tn->inNodes, &BlankNodePtr);
+ addArr_TgNodePtr(tn->outNodes, &BlankNodePtr);
+ addArr_TgNodePtr(tn->outNodes, &BlankNodePtr);
+
+ /* make the old toNode the left parent of the tee node
+ add the new toNode as the right parent of the tee node */
+ tn->outNodes->val[0] = origToNode;
+ origToNode->inNodes->val[origToPort-1] = tn;
+
+ tn->outNodes->val[1] = toNode;
+ toNode->inNodes->val[toPort-1] = tn;
+
+ /* connect the fromNode to the new tee node */
+ fromNode->outNodes->val[fromPort-1] = tn;
+ tn->inNodes->val[0] = fromNode;
+
+ return tn;
+}
+
+/* -------------------------------------
+fillAllNodes
+ fill out the nodes of a recipe
+ ------------------------------------ */
+void
+fillAllNodes(TgRecipe *r, char* name)
+{
+ char qbuf[MAX_QBUF_LENGTH];
+ int i;
+ char *pqres;
+ char *pbufname;
+ PortalBuffer *pbuf;
+ int ntups;
+ TgElement *elem;
+ TgNode *node;
+
+ /* 1) fill out the elements that are in the recipe */
+ sprintf(qbuf, Q_RETRIEVE_ELEMENTS_IN_RECIPE, name);
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E') {
+ elog(NOTICE, "fillAllNodes(): Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf,0);
+ for (i=0;i<ntups;i++) {
+ elem = malloc(sizeof(TgElement));
+ fillTgElement(elem, pbuf, i);
+ addArr_TgElementPtr(r->elements, &elem);
+ }
+ PQclear(pbufname);
+
+ sprintf(qbuf, Q_RETRIEVE_NODES_IN_RECIPE, name);
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E') {
+ elog(NOTICE, "fillAllNodes(): Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf,0);
+ for (i=0;i<ntups;i++) {
+ node = malloc(sizeof(TgNode));
+ fillTgNode(r, node, pbuf, i);
+ addArr_TgNodePtr(r->allNodes, &node);
+ }
+ PQclear(pbufname);
+
+}
+
+
+/* -------------------------------------
+fillAllElements
+ fill out the elements of a recipe
+ ------------------------------------ */
+void
+fillAllElements(TgRecipe *r, char* name)
+{
+ char qbuf[MAX_QBUF_LENGTH];
+ int i;
+ char *pqres;
+ char *pbufname;
+ PortalBuffer *pbuf;
+ int ntups;
+ TgElement *elem;
+
+ sprintf(qbuf, Q_RETRIEVE_ELEMENTS_IN_RECIPE, name);
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E') {
+ elog(NOTICE, "fillAllElements(): Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf,0);
+ for (i=0;i<ntups;i++) {
+ elem = malloc(sizeof(TgElement));
+ fillTgElement(elem, pbuf, i);
+ addArr_TgElementPtr(r->elements, &elem);
+ }
+ PQclear(pbufname);
+
+}
+
+
+/* -------------------------------------
+fillTgRecipe
+ takes a query result in the PortalBuffer containing a Recipe
+ and converts it to a C TgRecipe strcture
+ ------------------------------------ */
+TgRecipe*
+fillTgRecipe(PortalBuffer* pbuf, int tupno)
+{
+ TgRecipe* r;
+ int i,j;
+
+ /* 1) set up the recipe structure */
+ r = (TgRecipe*)malloc(sizeof(TgRecipe));
+ fillTgElement(&r->elmValue, pbuf, 0);
+ r->elmValue.elemType = TG_RECIPE;
+ r->allNodes = newArr_TgNodePtr();
+ r->rootNodes = newArr_TgNodePtr();
+ r->eyes = newArr_TgNodePtr();
+ r->tees = newArr_TgNodePtr();
+ r->elements = newArr_TgElementPtr();
+
+ /* 2) find all the elements. There may be less elements than nodes
+ because you can have multiple instantiations of an element
+ in a recipe*/
+ fillAllElements(r, r->elmValue.elemName);
+
+ /* 3) find all the nodes in the recipe*/
+ fillAllNodes(r, r->elmValue.elemName);
+
+ /* 4) find all the edges, and connect the nodes,
+ may also add tee nodes to the allNodes field*/
+ lookupEdges(r, r->elmValue.elemName);
+
+ /* 5) find all the rootNodes in the recipe */
+ /* root nodes are nodes with no incoming nodes or
+ whose incoming nodes are all null */
+ /* 6) find all the eyes in the recipe */
+ /* eye nodes are nodes with the node type TG_EYE_NODE */
+ /* 7) find all the tee nodes in the recipe */
+ /* tee nodes are nodes with the node type TG_TEE_NODE */
+ for (i=0;i<r->allNodes->num;i++) {
+ TgNode* nptr = r->allNodes->val[i];
+
+ if (nptr->nodeType == TG_EYE_NODE)
+ addArr_TgNodePtr(r->eyes, &nptr);
+ else
+ if (nptr->nodeType == TG_TEE_NODE)
+ addArr_TgNodePtr(r->tees, &nptr);
+
+ if (nptr->inNodes->num == 0)
+ addArr_TgNodePtr(r->rootNodes, &nptr);
+ else {
+ for (j=0;
+ j<nptr->inNodes->num && (nptr->inNodes->val[j] == NULL);
+ j++);
+ if (j == nptr->inNodes->num)
+ addArr_TgNodePtr(r->rootNodes, &nptr);
+ }
+ }
+
+ return r;
+
+}
+
+
+/* -------------------------------------
+retrieveRecipe
+ find the recipe with the given name
+ ------------------------------------ */
+TgRecipe*
+retrieveRecipe(char* name)
+{
+ char qbuf[MAX_QBUF_LENGTH];
+ TgRecipe* recipe;
+ char *pqres;
+ char *pbufname;
+ PortalBuffer *pbuf;
+ int ntups;
+
+ sprintf(qbuf, Q_RETRIEVE_RECIPE_BYNAME, name);
+
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E') {
+ elog(NOTICE, "retrieveRecipe: Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return NULL;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf,0);
+ if (ntups == 0) {
+ elog(NOTICE, "retrieveRecipe(): No recipe named %s exists\n", name);
+ return NULL;
+ }
+ if (ntups != 1) {
+ elog(NOTICE, "retrieveRecipe(): Multiple (%d) recipes named %s exists\n", ntups, name);
+ return NULL;
+ }
+
+ recipe = fillTgRecipe(pbuf,0);
+
+ PQclear(pbufname);
+ return recipe;
+
+}
+
+/* -------------------- copyXXX functions ----------------------- */
+void copyTgElementPtr(TgElementPtr* from, TgElementPtr* to)
+{
+ *to = *from;
+}
+
+void copyTgNodePtr(TgNodePtr* from, TgNodePtr* to)
+{
+ *to = *from;
+}
+
+void copyTgRecipePtr(TgRecipePtr* from, TgRecipePtr* to)
+{
+ *to = *from;
+}
+
+void copyTgString(TgString* from, TgString* to)
+{
+ TgString fromTgString = *from;
+ TgString toTgString;
+ toTgString = (TgString)malloc(strlen(fromTgString)+1);
+ strcpy(toTgString, fromTgString);
+ *to = toTgString;
+}
+
diff --git a/src/backend/tioga/tgRecipe.h b/src/backend/tioga/tgRecipe.h
new file mode 100644
index 00000000000..c6ee78e5068
--- /dev/null
+++ b/src/backend/tioga/tgRecipe.h
@@ -0,0 +1,121 @@
+/*-------------------------------------------------------------------------
+ *
+ * tgRecipe.h--
+ * Tioga recipe-related definitions and declarations
+ * these functions can be used in both the frontend and the
+ * backend
+ *
+ * to use this header, you must also include
+ * "utils/geo-decls.h"
+ * and "libpq/libpq.h"
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: tgRecipe.h,v 1.1.1.1 1996/07/09 06:22:00 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "libpq/libpq.h"
+#ifndef TIOGA_FRONTEND
+#include "libpq/libpq-be.h"
+#include "utils/elog.h"
+#include "utils/geo-decls.h"
+#else
+#include "libpq-fe.h"
+typedef struct {
+ double x, y;
+} Point; /* this should match whatever is in geo-decls.h*/
+#endif /* TIOGA_FRONTEND */
+
+typedef enum {TG_INGRED,
+ TG_EYE,
+ TG_RECIPE} TgElemType;
+
+typedef enum { TG_SQL,
+ TG_C,
+ TG_RECIPE_GRAPH,
+ TG_COMPILED
+ } TgSrcLangType;
+
+typedef enum { TG_INGRED_NODE,
+ TG_EYE_NODE,
+ TG_RECIPE_NODE,
+ TG_TEE_NODE /* tee nodes are not stored in the db
+ we create them when we read the recipe
+ back */
+ } TgNodeType;
+
+/* -- type definition for setting up in memory Tioga recipe structure -- */
+/* -- see 'recipe-schema.sql' for their corresponding database types -- */
+
+typedef char *TgString;
+
+typedef struct _tgelement *TgElementPtr;
+typedef struct _tgnode *TgNodePtr;
+typedef struct _tgrecipe *TgRecipePtr;
+
+/* auto-generated header containing Arr_TgString, Arr_TgElementPtr,
+ and Arr_TgNodePtr */
+#include "tioga/Arr_TgRecipe.h"
+
+/* C structure representation of a Tioga Element */
+typedef struct _tgelement {
+ char *elemName; /* name of function this element represent */
+ TgElemType elemType; /* type of this element */
+ Arr_TgString *inPorts; /* names of inputs */
+ Arr_TgString *inTypes; /* name of input types */
+ Arr_TgString *outPorts; /* type of output */
+ Arr_TgString *outTypes; /* name of output types */
+ char *doc; /* description of this element */
+ Arr_TgString *keywords; /* keywords used to search for this element */
+ char *icon; /* iconic representation */
+ char *src; /* source code for this element */
+ TgSrcLangType srcLang; /* source language */
+ char *owner; /* owner recipe name */
+} TgElement;
+
+
+/* C structure representation of a Tioga Node */
+typedef struct _tgnode {
+ char *nodeName; /* name of this node */
+ TgNodeType nodeType; /* type of this node */
+ Point loc; /* screen location of the node. */
+ TgElement *nodeElem; /* the underlying element of this node */
+ Arr_TgNodePtr *inNodes; /* variable array of in node pointers
+ * a NULL TgNodePtr indicates a run-time
+ * parameter*/
+ Arr_TgNodePtr *outNodes; /* variable array of out node pointers. */
+} TgNode;
+
+/* C structure representation of a Tioga Recipe */
+typedef struct _tgrecipe {
+ TgElement elmValue; /* "inherits" TgElement attributes. */
+ Arr_TgNodePtr *allNodes; /* array of all nodes for this recipe. */
+ Arr_TgNodePtr *rootNodes; /* array of root nodes for this recipe. --
+ root nodes are nodes with no parents */
+ Arr_TgNodePtr *eyes; /* array of pointers for the browser nodes
+ * recipe, execution of recipe starts
+ * by traversing the recipe C structure
+ * from the eye nodes pointed by these
+ * pointers. */
+ Arr_TgNodePtr *tees; /* array of pointers of all the tee nodes */
+ Arr_TgElementPtr *elements; /* array of all the elements in this recipe,
+ * elements may be shared by multiple nodes */
+
+} TgRecipe;
+
+/* functions defined in tgRecipe.c */
+extern TgRecipe* retrieveRecipe(char* name);
+extern TgElement* findElemInRecipe(TgRecipe *r, char* elemName);
+extern TgNode* findNodeInRecipe(TgRecipe *r, char* nodeName);
+
+/* ---- copyXXX functions ---- */
+extern void copyTgElementPtr(TgElementPtr *, TgElementPtr *);
+extern void copyTgNodePtr(TgNodePtr *, TgNodePtr *);
+extern void copyTgRecipePtr(TgRecipePtr *, TgRecipePtr *);
+extern void copyTgString(TgString *, TgString *);
+
+
+
+