aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/Makefile2
-rw-r--r--src/backend/nodes/copyfuncs.c29
-rw-r--r--src/backend/nodes/equalfuncs.c27
-rw-r--r--src/backend/nodes/extensible.c92
-rw-r--r--src/backend/nodes/outfuncs.c40
-rw-r--r--src/backend/nodes/readfuncs.c40
-rw-r--r--src/include/nodes/extensible.h72
-rw-r--r--src/include/nodes/nodes.h12
8 files changed, 313 insertions, 1 deletions
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index fe2e46053e6..0b1e98c0190 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -13,7 +13,7 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS = nodeFuncs.o nodes.o list.o bitmapset.o tidbitmap.o \
- copyfuncs.o equalfuncs.o makefuncs.o \
+ copyfuncs.o equalfuncs.o extensible.o makefuncs.o \
outfuncs.o readfuncs.o print.o read.o params.o value.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e54d1744b0a..a9e9cc379b8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -23,6 +23,7 @@
#include "postgres.h"
#include "miscadmin.h"
+#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "utils/datum.h"
@@ -4166,6 +4167,27 @@ _copyList(const List *from)
}
/* ****************************************************************
+ * extensible.h copy functions
+ * ****************************************************************
+ */
+static ExtensibleNode *
+_copyExtensibleNode(const ExtensibleNode *from)
+{
+ ExtensibleNode *newnode;
+ const ExtensibleNodeMethods *methods;
+
+ methods = GetExtensibleNodeMethods(from->extnodename, false);
+ newnode = (ExtensibleNode *) newNode(methods->node_size,
+ T_ExtensibleNode);
+ COPY_STRING_FIELD(extnodename);
+
+ /* copy the private fields */
+ methods->nodeCopy(newnode, from);
+
+ return newnode;
+}
+
+/* ****************************************************************
* value.h copy functions
* ****************************************************************
*/
@@ -4545,6 +4567,13 @@ copyObject(const void *from)
break;
/*
+ * EXTENSIBLE NODES
+ */
+ case T_ExtensibleNode:
+ retval = _copyExtensibleNode(from);
+ break;
+
+ /*
* PARSE NODES
*/
case T_Query:
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 08ccc0de664..b9c39594283 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -29,6 +29,7 @@
#include "postgres.h"
+#include "nodes/extensible.h"
#include "nodes/relation.h"
#include "utils/datum.h"
@@ -871,6 +872,25 @@ _equalPlaceHolderInfo(const PlaceHolderInfo *a, const PlaceHolderInfo *b)
return true;
}
+/*
+ * Stuff from extensible.h
+ */
+static bool
+_equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
+{
+ const ExtensibleNodeMethods *methods;
+
+ COMPARE_STRING_FIELD(extnodename);
+
+ /* At this point, we know extnodename is the same for both nodes. */
+ methods = GetExtensibleNodeMethods(a->extnodename, false);
+
+ /* compare the private fields */
+ if (!methods->nodeEqual(a, b))
+ return false;
+
+ return true;
+}
/*
* Stuff from parsenodes.h
@@ -2874,6 +2894,13 @@ equal(const void *a, const void *b)
break;
/*
+ * EXTENSIBLE NODES
+ */
+ case T_ExtensibleNode:
+ retval = _equalExtensibleNode(a, b);
+ break;
+
+ /*
* PARSE NODES
*/
case T_Query:
diff --git a/src/backend/nodes/extensible.c b/src/backend/nodes/extensible.c
new file mode 100644
index 00000000000..8fb4767d4d2
--- /dev/null
+++ b/src/backend/nodes/extensible.c
@@ -0,0 +1,92 @@
+/*-------------------------------------------------------------------------
+ *
+ * extensible.c
+ * Support for extensible node types
+ *
+ * Loadable modules can define what are in effect new types of nodes using
+ * the routines in this file. All such nodes are flagged T_ExtensibleNode,
+ * with the extnodename field distinguishing the specific type. Use
+ * RegisterExtensibleNodeMethods to register a new type of extensible node,
+ * and GetExtensibleNodeMethods to get information about a previously
+ * registered type of extensible node.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/backend/nodes/extensible.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "nodes/extensible.h"
+#include "utils/hsearch.h"
+
+static HTAB *extensible_node_methods = NULL;
+
+typedef struct
+{
+ char extnodename[EXTNODENAME_MAX_LEN];
+ const ExtensibleNodeMethods *methods;
+} ExtensibleNodeEntry;
+
+/*
+ * Register a new type of extensible node.
+ */
+void
+RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
+{
+ ExtensibleNodeEntry *entry;
+ bool found;
+
+ if (extensible_node_methods == NULL)
+ {
+ HASHCTL ctl;
+
+ memset(&ctl, 0, sizeof(HASHCTL));
+ ctl.keysize = NAMEDATALEN;
+ ctl.entrysize = sizeof(ExtensibleNodeEntry);
+ extensible_node_methods = hash_create("Extensible Node Methods",
+ 100, &ctl, HASH_ELEM);
+ }
+
+ Assert(strlen(methods->extnodename) <= EXTNODENAME_MAX_LEN);
+
+ entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
+ methods->extnodename,
+ HASH_ENTER, &found);
+ if (found)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("extensible node type \"%s\" already exists",
+ methods->extnodename)));
+
+ entry->methods = methods;
+}
+
+/*
+ * Get the methods for a given type of extensible node.
+ */
+const ExtensibleNodeMethods *
+GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
+{
+ ExtensibleNodeEntry *entry = NULL;
+
+ if (extensible_node_methods != NULL)
+ entry = (ExtensibleNodeEntry *) hash_search(extensible_node_methods,
+ extnodename,
+ HASH_FIND, NULL);
+
+ if (!entry)
+ {
+ if (missing_ok)
+ return NULL;
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("ExtensibleNodeMethods \"%s\" was not registered",
+ extnodename)));
+ }
+
+ return entry->methods;
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3e1c3e6be57..28d983c9a87 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include "lib/stringinfo.h"
+#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "utils/datum.h"
@@ -140,6 +141,13 @@ _outToken(StringInfo str, const char *s)
}
}
+/* for use by extensions which define extensible nodes */
+void
+outToken(StringInfo str, const char *s)
+{
+ _outToken(str, s);
+}
+
static void
_outList(StringInfo str, const List *node)
{
@@ -196,6 +204,13 @@ _outBitmapset(StringInfo str, const Bitmapset *bms)
appendStringInfoChar(str, ')');
}
+/* for use by extensions which define extensible nodes */
+void
+outBitmapset(StringInfo str, const Bitmapset *bms)
+{
+ _outBitmapset(str, bms);
+}
+
/*
* Print the value of a Datum given its type.
*/
@@ -2114,6 +2129,27 @@ _outPlannerParamItem(StringInfo str, const PlannerParamItem *node)
/*****************************************************************************
*
+ * Stuff from extensible.h
+ *
+ *****************************************************************************/
+
+static void
+_outExtensibleNode(StringInfo str, const ExtensibleNode *node)
+{
+ const ExtensibleNodeMethods *methods;
+
+ methods = GetExtensibleNodeMethods(node->extnodename, false);
+
+ WRITE_NODE_TYPE("EXTENSIBLENODE");
+
+ WRITE_STRING_FIELD(extnodename);
+
+ /* serialize the private fields */
+ methods->nodeOut(str, node);
+}
+
+/*****************************************************************************
+ *
* Stuff from parsenodes.h.
*
*****************************************************************************/
@@ -3367,6 +3403,10 @@ _outNode(StringInfo str, const void *obj)
_outPlannerParamItem(str, obj);
break;
+ case T_ExtensibleNode:
+ _outExtensibleNode(str, obj);
+ break;
+
case T_CreateStmt:
_outCreateStmt(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index e4d41ee95b2..e6e6f2981c2 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -29,6 +29,7 @@
#include <math.h>
#include "fmgr.h"
+#include "nodes/extensible.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/readfuncs.h"
@@ -218,6 +219,14 @@ _readBitmapset(void)
return result;
}
+/*
+ * for use by extensions which define extensible nodes
+ */
+Bitmapset *
+readBitmapset(void)
+{
+ return _readBitmapset();
+}
/*
* _readQuery
@@ -2220,6 +2229,35 @@ _readAlternativeSubPlan(void)
}
/*
+ * _readExtensibleNode
+ */
+static ExtensibleNode *
+_readExtensibleNode(void)
+{
+ const ExtensibleNodeMethods *methods;
+ ExtensibleNode *local_node;
+ const char *extnodename;
+ READ_TEMP_LOCALS();
+
+ token = pg_strtok(&length); /* skip: extnodename */
+ token = pg_strtok(&length); /* get extnodename */
+
+ extnodename = nullable_string(token, length);
+ if (!extnodename)
+ elog(ERROR, "extnodename has to be supplied");
+ methods = GetExtensibleNodeMethods(extnodename, false);
+
+ local_node = (ExtensibleNode *) newNode(methods->node_size,
+ T_ExtensibleNode);
+ local_node->extnodename = extnodename;
+
+ /* deserialize the private fields */
+ methods->nodeRead(local_node);
+
+ READ_DONE();
+}
+
+/*
* parseNodeString
*
* Given a character string representing a node tree, parseNodeString creates
@@ -2447,6 +2485,8 @@ parseNodeString(void)
return_value = _readSubPlan();
else if (MATCH("ALTERNATIVESUBPLAN", 18))
return_value = _readAlternativeSubPlan();
+ else if (MATCH("EXTENSIBLENODE", 14))
+ return_value = _readExtensibleNode();
else
{
elog(ERROR, "badly formatted node string \"%.32s\"...", token);
diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h
new file mode 100644
index 00000000000..96ae7bc9291
--- /dev/null
+++ b/src/include/nodes/extensible.h
@@ -0,0 +1,72 @@
+/*-------------------------------------------------------------------------
+ *
+ * extensible.h
+ * Definitions for extensible node type
+ *
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/nodes/extensible.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef EXTENSIBLE_H
+#define EXTENSIBLE_H
+
+#include "nodes/nodes.h"
+
+#define EXTNODENAME_MAX_LEN 64
+
+/*
+ * An extensible node is a new type of node defined by an extension. The
+ * type is always T_ExtensibleNode, while the extnodename identifies the
+ * specific type of node. extnodename can be looked up to find the
+ * ExtensibleNodeMethods for this node type.
+ */
+typedef struct ExtensibleNode
+{
+ NodeTag type;
+ const char *extnodename; /* identifier of ExtensibleNodeMethods */
+} ExtensibleNode;
+
+/*
+ * node_size is the size of an extensible node of this type in bytes.
+ *
+ * nodeCopy is a function which performs a deep copy from oldnode to newnode.
+ * It does not need to copy type or extnodename, which are copied by the
+ * core system.
+ *
+ * nodeEqual is a function which performs a deep equality comparison between
+ * a and b and returns true or false accordingly. It does not need to compare
+ * type or extnodename, which are compared by the core system.
+ *
+ * nodeOut is a serialization function for the node type. It should use the
+ * output conventions typical for outfuncs.c. It does not need to output
+ * type or extnodename; the core system handles those.
+ *
+ * nodeRead is a deserialization function for the node type. It does not need
+ * to read type or extnodename; the core system handles those. It should fetch
+ * the next token using pg_strtok() from the current input stream, and then
+ * reconstruct the private fields according to the manner in readfuncs.c.
+ *
+ * All callbacks are mandatory.
+ */
+typedef struct ExtensibleNodeMethods
+{
+ const char *extnodename;
+ Size node_size;
+ void (*nodeCopy)(struct ExtensibleNode *newnode,
+ const struct ExtensibleNode *oldnode);
+ bool (*nodeEqual)(const struct ExtensibleNode *a,
+ const struct ExtensibleNode *b);
+ void (*nodeOut)(struct StringInfoData *str,
+ const struct ExtensibleNode *node);
+ void (*nodeRead)(struct ExtensibleNode *node);
+} ExtensibleNodeMethods;
+
+extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method);
+extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name,
+ bool missing_ok);
+
+#endif /* EXTENSIBLE_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index cf09db4e5fe..c407fa2cd49 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -276,6 +276,11 @@ typedef enum NodeTag
T_OidList,
/*
+ * TAGS FOR EXTENSIBLE NODES (extensible.h)
+ */
+ T_ExtensibleNode,
+
+ /*
* TAGS FOR STATEMENT NODES (mostly in parsenodes.h)
*/
T_Query = 700,
@@ -527,10 +532,17 @@ extern PGDLLIMPORT Node *newNodeMacroHolder;
*/
extern char *nodeToString(const void *obj);
+struct Bitmapset; /* not to include bitmapset.h here */
+struct StringInfoData; /* not to include stringinfo.h here */
+extern void outToken(struct StringInfoData *str, const char *s);
+extern void outBitmapset(struct StringInfoData *str,
+ const struct Bitmapset *bms);
+
/*
* nodes/{readfuncs.c,read.c}
*/
extern void *stringToNode(char *str);
+extern struct Bitmapset *readBitmapset(void);
/*
* nodes/copyfuncs.c