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
#include "postgres.h"
#include "miscadmin.h"
+#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "utils/datum.h"
return new;
}
+/* ****************************************************************
+ * 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
* ****************************************************************
retval = list_copy(from);
break;
+ /*
+ * EXTENSIBLE NODES
+ */
+ case T_ExtensibleNode:
+ retval = _copyExtensibleNode(from);
+ break;
+
/*
* PARSE NODES
*/
#include "postgres.h"
+#include "nodes/extensible.h"
#include "nodes/relation.h"
#include "utils/datum.h"
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
retval = _equalValue(a, b);
break;
+ /*
+ * EXTENSIBLE NODES
+ */
+ case T_ExtensibleNode:
+ retval = _equalExtensibleNode(a, b);
+ break;
+
/*
* PARSE NODES
*/
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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;
+}
#include <ctype.h>
#include "lib/stringinfo.h"
+#include "nodes/extensible.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "utils/datum.h"
}
}
+/* 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)
{
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.
*/
WRITE_INT_FIELD(paramId);
}
+/*****************************************************************************
+ *
+ * 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.
_outPlannerParamItem(str, obj);
break;
+ case T_ExtensibleNode:
+ _outExtensibleNode(str, obj);
+ break;
+
case T_CreateStmt:
_outCreateStmt(str, obj);
break;
#include <math.h>
#include "fmgr.h"
+#include "nodes/extensible.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/readfuncs.h"
return result;
}
+/*
+ * for use by extensions which define extensible nodes
+ */
+Bitmapset *
+readBitmapset(void)
+{
+ return _readBitmapset();
+}
/*
* _readQuery
READ_DONE();
}
+/*
+ * _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
*
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);
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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 */
T_IntList,
T_OidList,
+ /*
+ * TAGS FOR EXTENSIBLE NODES (extensible.h)
+ */
+ T_ExtensibleNode,
+
/*
* TAGS FOR STATEMENT NODES (mostly in parsenodes.h)
*/
*/
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