diff -dcrpN postgresql.orig/src/backend/nodes/bitmapset.c postgresql/src/backend/nodes/bitmapset.c
*** postgresql.orig/src/backend/nodes/bitmapset.c	2010-09-21 13:49:56.000000000 +0200
--- postgresql/src/backend/nodes/bitmapset.c	2010-10-19 10:56:19.000000000 +0200
*************** bms_equal(const Bitmapset *a, const Bitm
*** 173,178 ****
--- 173,232 ----
  }
  
  /*
+  * bms_compare - are one of the two bitmapsets equal, less or greater than the other?
+  *
+  * This is logical not physical equality; in particular, a NULL pointer will
+  * be reported as equal to a palloc'd value containing no members.
+  */
+ int
+ bms_compare(const Bitmapset *a, const Bitmapset *b)
+ {
+ 	const Bitmapset *shorter;
+ 	const Bitmapset *longer;
+ 	int			shortlen;
+ 	int			longlen;
+ 	int			i;
+ 
+ 	/* Handle cases where either input is NULL */
+ 	if (a == NULL)
+ 	{
+ 		if (b == NULL)
+ 			return 0;
+ 		if (bms_is_empty(b))
+ 			return 0;
+ 	}
+ 	else if (b == NULL && bms_is_empty(a))
+ 		return 0;
+ 	/* Identify shorter and longer input */
+ 	if (a->nwords <= b->nwords)
+ 	{
+ 		shorter = a;
+ 		longer = b;
+ 	}
+ 	else
+ 	{
+ 		shorter = b;
+ 		longer = a;
+ 	}
+ 	/* And process */
+ 	shortlen = shorter->nwords;
+ 	for (i = 0; i < shortlen; i++)
+ 	{
+ 		if (shorter->words[i] < longer->words[i])
+ 			return -1;
+ 		else if (shorter->words[i] > longer->words[i])
+ 			return 1;
+ 	}
+ 	longlen = longer->nwords;
+ 	for (; i < longlen; i++)
+ 	{
+ 		if (longer->words[i] != 0)
+ 			return (longer == a ? 1 : -1);
+ 	}
+ 	return 0;
+ }
+ 
+ /*
   * bms_make_singleton - build a bitmapset containing a single member
   */
  Bitmapset *
diff -dcrpN postgresql.orig/src/backend/nodes/comparefuncs.c postgresql/src/backend/nodes/comparefuncs.c
*** postgresql.orig/src/backend/nodes/comparefuncs.c	1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/backend/nodes/comparefuncs.c	2010-10-19 11:26:16.000000000 +0200
***************
*** 0 ****
--- 1,2952 ----
+ /*-------------------------------------------------------------------------
+  *
+  * comparefuncs.c
+  *	  Tree comparator functions to compare node trees.
+  *
+  * This file is a straight conversion of equalfuncs.c, see the NOTE there.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * IDENTIFICATION
+  *	  src/backend/nodes/comparefuncs.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include "nodes/relation.h"
+ #include "utils/datum.h"
+ 
+ 
+ /*
+  * Macros to simplify comparison of different kinds of fields.	Use these
+  * wherever possible to reduce the chance for silly typos.	Note that these
+  * hard-wire the convention that the local variables in a Compare routine are
+  * named 'a' and 'b'.
+  */
+ 
+ /* Compare a simple scalar field (int, float, bool, enum, etc) */
+ #define COMPARE_SCALAR_FIELD(fldname) \
+ 	do { \
+ 		if (a->fldname < b->fldname) \
+ 			return -1; \
+ 		else if (a->fldname > b->fldname) \
+ 			return 1; \
+ 	} while (0)
+ 
+ /* Compare a field that is a pointer to some kind of Node or Node tree */
+ #define COMPARE_NODE_FIELD(fldname) \
+ 	do { \
+ 		int	ret; \
+ 		ret = compare(a->fldname, b->fldname); \
+ 		if (ret != 0) \
+ 			return ret; \
+ 	} while (0)
+ 
+ /* Compare a field that is a pointer to a Bitmapset */
+ #define COMPARE_BITMAPSET_FIELD(fldname) \
+ 	do { \
+ 		int	ret; \
+ 		ret = bms_compare(a->fldname, b->fldname); \
+ 		if (ret != 0) \
+ 			return ret; \
+ 	} while (0)
+ 
+ /* Compare a field that is a pointer to a C string, or perhaps NULL */
+ #define COMPARE_STRING_FIELD(fldname) \
+ 	do { \
+ 		int	ret; \
+ 		ret = comparestr(a->fldname, b->fldname); \
+ 		if (ret != 0) \
+ 			return ret; \
+ 	} while (0)
+ 
+ /* Macro for comparing string fields that might be NULL */
+ #define comparestr(a, b)	\
+ 	(((a) != NULL && (b) != NULL) ? strcmp(a, b) : ((a) < (b) ? -1 : ((a) > (b) ? -1 : 0 )))
+ 
+ /* Compare a field that is a pointer to a simple palloc'd object of size sz */
+ #define COMPARE_POINTER_FIELD(fldname, sz) \
+ 	do { \
+ 		int	ret; \
+ 		ret = memcmp(a->fldname, b->fldname, (sz)); \
+ 		if (ret != 0) \
+ 			return ret; \
+ 	} while (0)
+ 
+ /* Compare a parse location field (this is a no-op, per note above) */
+ #define COMPARE_LOCATION_FIELD(fldname) \
+ 	((void) 0)
+ 
+ 
+ /*
+  *	Stuff from primnodes.h
+  */
+ 
+ static int
+ _compareAlias(Alias *a, Alias *b)
+ {
+ 	COMPARE_STRING_FIELD(aliasname);
+ 	COMPARE_NODE_FIELD(colnames);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRangeVar(RangeVar *a, RangeVar *b)
+ {
+ 	COMPARE_STRING_FIELD(catalogname);
+ 	COMPARE_STRING_FIELD(schemaname);
+ 	COMPARE_STRING_FIELD(relname);
+ 	COMPARE_SCALAR_FIELD(inhOpt);
+ 	COMPARE_SCALAR_FIELD(istemp);
+ 	COMPARE_NODE_FIELD(alias);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareIntoClause(IntoClause *a, IntoClause *b)
+ {
+ 	COMPARE_NODE_FIELD(rel);
+ 	COMPARE_NODE_FIELD(colNames);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_SCALAR_FIELD(onCommit);
+ 	COMPARE_STRING_FIELD(tableSpaceName);
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * We don't need an _compareExpr because Expr is an abstract supertype which
+  * should never actually get instantiated.	Also, since it has no common
+  * fields except NodeTag, there's no need for a helper routine to factor
+  * out comparing the common fields...
+  */
+ 
+ static int
+ _compareVar(Var *a, Var *b)
+ {
+ 	COMPARE_SCALAR_FIELD(varno);
+ 	COMPARE_SCALAR_FIELD(varattno);
+ 	COMPARE_SCALAR_FIELD(vartype);
+ 	COMPARE_SCALAR_FIELD(vartypmod);
+ 	COMPARE_SCALAR_FIELD(varlevelsup);
+ 	COMPARE_SCALAR_FIELD(varnoold);
+ 	COMPARE_SCALAR_FIELD(varoattno);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareConst(Const *a, Const *b)
+ {
+ 	COMPARE_SCALAR_FIELD(consttype);
+ 	COMPARE_SCALAR_FIELD(consttypmod);
+ 	COMPARE_SCALAR_FIELD(constlen);
+ 	COMPARE_SCALAR_FIELD(constisnull);
+ 	COMPARE_SCALAR_FIELD(constbyval);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	/*
+ 	 * We treat all NULL constants of the same type as equal. Someday this
+ 	 * might need to change?  But datumCompare doesn't work on nulls, so...
+ 	 */
+ 	if (a->constisnull)
+ 		return 0;
+ 	return datumCompare(a->constvalue, b->constvalue,
+ 						a->constbyval, a->constlen);
+ }
+ 
+ static int
+ _compareParam(Param *a, Param *b)
+ {
+ 	COMPARE_SCALAR_FIELD(paramkind);
+ 	COMPARE_SCALAR_FIELD(paramid);
+ 	COMPARE_SCALAR_FIELD(paramtype);
+ 	COMPARE_SCALAR_FIELD(paramtypmod);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAggref(Aggref *a, Aggref *b)
+ {
+ 	COMPARE_SCALAR_FIELD(aggfnoid);
+ 	COMPARE_SCALAR_FIELD(aggtype);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_NODE_FIELD(aggorder);
+ 	COMPARE_NODE_FIELD(aggdistinct);
+ 	COMPARE_SCALAR_FIELD(aggstar);
+ 	COMPARE_SCALAR_FIELD(agglevelsup);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareWindowFunc(WindowFunc *a, WindowFunc *b)
+ {
+ 	COMPARE_SCALAR_FIELD(winfnoid);
+ 	COMPARE_SCALAR_FIELD(wintype);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_SCALAR_FIELD(winref);
+ 	COMPARE_SCALAR_FIELD(winstar);
+ 	COMPARE_SCALAR_FIELD(winagg);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareArrayRef(ArrayRef *a, ArrayRef *b)
+ {
+ 	COMPARE_SCALAR_FIELD(refarraytype);
+ 	COMPARE_SCALAR_FIELD(refelemtype);
+ 	COMPARE_SCALAR_FIELD(reftypmod);
+ 	COMPARE_NODE_FIELD(refupperindexpr);
+ 	COMPARE_NODE_FIELD(reflowerindexpr);
+ 	COMPARE_NODE_FIELD(refexpr);
+ 	COMPARE_NODE_FIELD(refassgnexpr);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareFuncExpr(FuncExpr *a, FuncExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(funcid);
+ 	COMPARE_SCALAR_FIELD(funcresulttype);
+ 	COMPARE_SCALAR_FIELD(funcretset);
+ 
+ 	/*
+ 	 * Special-case COERCE_DONTCARE, so that planner can build coercion nodes
+ 	 * that are equal() to both explicit and implicit coercions.
+ 	 */
+ 	if (a->funcformat != COERCE_DONTCARE && b->funcformat != COERCE_DONTCARE)
+ 		COMPARE_SCALAR_FIELD(funcformat);
+ 
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareNamedArgExpr(NamedArgExpr *a, NamedArgExpr *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_SCALAR_FIELD(argnumber);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareOpExpr(OpExpr *a, OpExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(opno);
+ 
+ 	/*
+ 	 * Special-case opfuncid: it is allowable for it to differ if one node
+ 	 * contains zero and the other doesn't.  This just means that the one node
+ 	 * isn't as far along in the parse/plan pipeline and hasn't had the
+ 	 * opfuncid cache filled yet.
+ 	 */
+ 	if (a->opfuncid != 0 &&
+ 		b->opfuncid != 0)
+ 		COMPARE_SCALAR_FIELD(opfuncid);
+ 
+ 	COMPARE_SCALAR_FIELD(opresulttype);
+ 	COMPARE_SCALAR_FIELD(opretset);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDistinctExpr(DistinctExpr *a, DistinctExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(opno);
+ 
+ 	/*
+ 	 * Special-case opfuncid: it is allowable for it to differ if one node
+ 	 * contains zero and the other doesn't.  This just means that the one node
+ 	 * isn't as far along in the parse/plan pipeline and hasn't had the
+ 	 * opfuncid cache filled yet.
+ 	 */
+ 	if (a->opfuncid != 0 &&
+ 		b->opfuncid != 0)
+ 		COMPARE_SCALAR_FIELD(opfuncid);
+ 
+ 	COMPARE_SCALAR_FIELD(opresulttype);
+ 	COMPARE_SCALAR_FIELD(opretset);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareScalarArrayOpExpr(ScalarArrayOpExpr *a, ScalarArrayOpExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(opno);
+ 
+ 	/*
+ 	 * Special-case opfuncid: it is allowable for it to differ if one node
+ 	 * contains zero and the other doesn't.  This just means that the one node
+ 	 * isn't as far along in the parse/plan pipeline and hasn't had the
+ 	 * opfuncid cache filled yet.
+ 	 */
+ 	if (a->opfuncid != 0 &&
+ 		b->opfuncid != 0)
+ 		COMPARE_SCALAR_FIELD(opfuncid);
+ 
+ 	COMPARE_SCALAR_FIELD(useOr);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareBoolExpr(BoolExpr *a, BoolExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(boolop);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareSubLink(SubLink *a, SubLink *b)
+ {
+ 	COMPARE_SCALAR_FIELD(subLinkType);
+ 	COMPARE_NODE_FIELD(testexpr);
+ 	COMPARE_NODE_FIELD(operName);
+ 	COMPARE_NODE_FIELD(subselect);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareSubPlan(SubPlan *a, SubPlan *b)
+ {
+ 	COMPARE_SCALAR_FIELD(subLinkType);
+ 	COMPARE_NODE_FIELD(testexpr);
+ 	COMPARE_NODE_FIELD(paramIds);
+ 	COMPARE_SCALAR_FIELD(plan_id);
+ 	COMPARE_STRING_FIELD(plan_name);
+ 	COMPARE_SCALAR_FIELD(firstColType);
+ 	COMPARE_SCALAR_FIELD(firstColTypmod);
+ 	COMPARE_SCALAR_FIELD(useHashTable);
+ 	COMPARE_SCALAR_FIELD(unknownEqFalse);
+ 	COMPARE_NODE_FIELD(setParam);
+ 	COMPARE_NODE_FIELD(parParam);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_SCALAR_FIELD(startup_cost);
+ 	COMPARE_SCALAR_FIELD(per_call_cost);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlternativeSubPlan(AlternativeSubPlan *a, AlternativeSubPlan *b)
+ {
+ 	COMPARE_NODE_FIELD(subplans);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareFieldSelect(FieldSelect *a, FieldSelect *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(fieldnum);
+ 	COMPARE_SCALAR_FIELD(resulttype);
+ 	COMPARE_SCALAR_FIELD(resulttypmod);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareFieldStore(FieldStore *a, FieldStore *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_NODE_FIELD(newvals);
+ 	COMPARE_NODE_FIELD(fieldnums);
+ 	COMPARE_SCALAR_FIELD(resulttype);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRelabelType(RelabelType *a, RelabelType *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(resulttype);
+ 	COMPARE_SCALAR_FIELD(resulttypmod);
+ 
+ 	/*
+ 	 * Special-case COERCE_DONTCARE, so that planner can build coercion nodes
+ 	 * that are equal() to both explicit and implicit coercions.
+ 	 */
+ 	if (a->relabelformat != COERCE_DONTCARE &&
+ 		b->relabelformat != COERCE_DONTCARE)
+ 		COMPARE_SCALAR_FIELD(relabelformat);
+ 
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCoerceViaIO(CoerceViaIO *a, CoerceViaIO *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(resulttype);
+ 
+ 	/*
+ 	 * Special-case COERCE_DONTCARE, so that planner can build coercion nodes
+ 	 * that are equal() to both explicit and implicit coercions.
+ 	 */
+ 	if (a->coerceformat != COERCE_DONTCARE &&
+ 		b->coerceformat != COERCE_DONTCARE)
+ 		COMPARE_SCALAR_FIELD(coerceformat);
+ 
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(elemfuncid);
+ 	COMPARE_SCALAR_FIELD(resulttype);
+ 	COMPARE_SCALAR_FIELD(resulttypmod);
+ 	COMPARE_SCALAR_FIELD(isExplicit);
+ 
+ 	/*
+ 	 * Special-case COERCE_DONTCARE, so that planner can build coercion nodes
+ 	 * that are equal() to both explicit and implicit coercions.
+ 	 */
+ 	if (a->coerceformat != COERCE_DONTCARE &&
+ 		b->coerceformat != COERCE_DONTCARE)
+ 		COMPARE_SCALAR_FIELD(coerceformat);
+ 
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareConvertRowtypeExpr(ConvertRowtypeExpr *a, ConvertRowtypeExpr *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(resulttype);
+ 
+ 	/*
+ 	 * Special-case COERCE_DONTCARE, so that planner can build coercion nodes
+ 	 * that are equal() to both explicit and implicit coercions.
+ 	 */
+ 	if (a->convertformat != COERCE_DONTCARE &&
+ 		b->convertformat != COERCE_DONTCARE)
+ 		COMPARE_SCALAR_FIELD(convertformat);
+ 
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCaseExpr(CaseExpr *a, CaseExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(casetype);
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_NODE_FIELD(defresult);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCaseWhen(CaseWhen *a, CaseWhen *b)
+ {
+ 	COMPARE_NODE_FIELD(expr);
+ 	COMPARE_NODE_FIELD(result);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCaseTestExpr(CaseTestExpr *a, CaseTestExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(typeId);
+ 	COMPARE_SCALAR_FIELD(typeMod);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareArrayExpr(ArrayExpr *a, ArrayExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(array_typeid);
+ 	COMPARE_SCALAR_FIELD(element_typeid);
+ 	COMPARE_NODE_FIELD(elements);
+ 	COMPARE_SCALAR_FIELD(multidims);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRowExpr(RowExpr *a, RowExpr *b)
+ {
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_SCALAR_FIELD(row_typeid);
+ 
+ 	/*
+ 	 * Special-case COERCE_DONTCARE, so that planner can build coercion nodes
+ 	 * that are equal() to both explicit and implicit coercions.
+ 	 */
+ 	if (a->row_format != COERCE_DONTCARE &&
+ 		b->row_format != COERCE_DONTCARE)
+ 		COMPARE_SCALAR_FIELD(row_format);
+ 
+ 	COMPARE_NODE_FIELD(colnames);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRowCompareExpr(RowCompareExpr *a, RowCompareExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(rctype);
+ 	COMPARE_NODE_FIELD(opnos);
+ 	COMPARE_NODE_FIELD(opfamilies);
+ 	COMPARE_NODE_FIELD(largs);
+ 	COMPARE_NODE_FIELD(rargs);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCoalesceExpr(CoalesceExpr *a, CoalesceExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(coalescetype);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareMinMaxExpr(MinMaxExpr *a, MinMaxExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(minmaxtype);
+ 	COMPARE_SCALAR_FIELD(op);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareXmlExpr(XmlExpr *a, XmlExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(op);
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(named_args);
+ 	COMPARE_NODE_FIELD(arg_names);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_SCALAR_FIELD(xmloption);
+ 	COMPARE_SCALAR_FIELD(type);
+ 	COMPARE_SCALAR_FIELD(typmod);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareNullIfExpr(NullIfExpr *a, NullIfExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(opno);
+ 
+ 	/*
+ 	 * Special-case opfuncid: it is allowable for it to differ if one node
+ 	 * contains zero and the other doesn't.  This just means that the one node
+ 	 * isn't as far along in the parse/plan pipeline and hasn't had the
+ 	 * opfuncid cache filled yet.
+ 	 */
+ 	if (a->opfuncid != 0 &&
+ 		b->opfuncid != 0)
+ 		COMPARE_SCALAR_FIELD(opfuncid);
+ 
+ 	COMPARE_SCALAR_FIELD(opresulttype);
+ 	COMPARE_SCALAR_FIELD(opretset);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareNullTest(NullTest *a, NullTest *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(nulltesttype);
+ 	COMPARE_SCALAR_FIELD(argisrow);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareBooleanTest(BooleanTest *a, BooleanTest *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(booltesttype);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCoerceToDomain(CoerceToDomain *a, CoerceToDomain *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(resulttype);
+ 	COMPARE_SCALAR_FIELD(resulttypmod);
+ 
+ 	/*
+ 	 * Special-case COERCE_DONTCARE, so that planner can build coercion nodes
+ 	 * that are equal() to both explicit and implicit coercions.
+ 	 */
+ 	if (a->coercionformat != COERCE_DONTCARE &&
+ 		b->coercionformat != COERCE_DONTCARE)
+ 		COMPARE_SCALAR_FIELD(coercionformat);
+ 
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCoerceToDomainValue(CoerceToDomainValue *a, CoerceToDomainValue *b)
+ {
+ 	COMPARE_SCALAR_FIELD(typeId);
+ 	COMPARE_SCALAR_FIELD(typeMod);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareSetToDefault(SetToDefault *a, SetToDefault *b)
+ {
+ 	COMPARE_SCALAR_FIELD(typeId);
+ 	COMPARE_SCALAR_FIELD(typeMod);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCurrentOfExpr(CurrentOfExpr *a, CurrentOfExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(cvarno);
+ 	COMPARE_STRING_FIELD(cursor_name);
+ 	COMPARE_SCALAR_FIELD(cursor_param);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareTargetEntry(TargetEntry *a, TargetEntry *b)
+ {
+ 	COMPARE_NODE_FIELD(expr);
+ 	COMPARE_SCALAR_FIELD(resno);
+ 	COMPARE_STRING_FIELD(resname);
+ 	COMPARE_SCALAR_FIELD(ressortgroupref);
+ 	COMPARE_SCALAR_FIELD(resorigtbl);
+ 	COMPARE_SCALAR_FIELD(resorigcol);
+ 	COMPARE_SCALAR_FIELD(resjunk);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRangeTblRef(RangeTblRef *a, RangeTblRef *b)
+ {
+ 	COMPARE_SCALAR_FIELD(rtindex);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareJoinExpr(JoinExpr *a, JoinExpr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(jointype);
+ 	COMPARE_SCALAR_FIELD(isNatural);
+ 	COMPARE_NODE_FIELD(larg);
+ 	COMPARE_NODE_FIELD(rarg);
+ 	COMPARE_NODE_FIELD(usingClause);
+ 	COMPARE_NODE_FIELD(quals);
+ 	COMPARE_NODE_FIELD(alias);
+ 	COMPARE_SCALAR_FIELD(rtindex);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareFromExpr(FromExpr *a, FromExpr *b)
+ {
+ 	COMPARE_NODE_FIELD(fromlist);
+ 	COMPARE_NODE_FIELD(quals);
+ 
+ 	return 0;
+ }
+ 
+ 
+ /*
+  * Stuff from relation.h
+  */
+ 
+ static int
+ _comparePathKey(PathKey *a, PathKey *b)
+ {
+ 	/*
+ 	 * This is normally used on non-canonicalized PathKeys, so must chase up
+ 	 * to the topmost merged EquivalenceClass and see if those are the same
+ 	 * (by pointer equality).
+ 	 */
+ 	EquivalenceClass *a_eclass;
+ 	EquivalenceClass *b_eclass;
+ 
+ 	a_eclass = a->pk_eclass;
+ 	while (a_eclass->ec_merged)
+ 		a_eclass = a_eclass->ec_merged;
+ 	b_eclass = b->pk_eclass;
+ 	while (b_eclass->ec_merged)
+ 		b_eclass = b_eclass->ec_merged;
+ 	if (a_eclass < b_eclass)
+ 		return -1;
+ 	else if (a_eclass > b_eclass)
+ 		return 1;
+ 
+ 	COMPARE_SCALAR_FIELD(pk_opfamily);
+ 	COMPARE_SCALAR_FIELD(pk_strategy);
+ 	COMPARE_SCALAR_FIELD(pk_nulls_first);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRestrictInfo(RestrictInfo *a, RestrictInfo *b)
+ {
+ 	COMPARE_NODE_FIELD(clause);
+ 	COMPARE_SCALAR_FIELD(is_pushed_down);
+ 	COMPARE_SCALAR_FIELD(outerjoin_delayed);
+ 	COMPARE_BITMAPSET_FIELD(required_relids);
+ 	COMPARE_BITMAPSET_FIELD(nullable_relids);
+ 
+ 	/*
+ 	 * We ignore all the remaining fields, since they may not be set yet, and
+ 	 * should be derivable from the clause anyway.
+ 	 */
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _comparePlaceHolderVar(PlaceHolderVar *a, PlaceHolderVar *b)
+ {
+ 	/*
+ 	 * We intentionally do not compare phexpr.	Two PlaceHolderVars with the
+ 	 * same ID and levelsup should be considered equal even if the contained
+ 	 * expressions have managed to mutate to different states.	One way in
+ 	 * which that can happen is that initplan sublinks would get replaced by
+ 	 * differently-numbered Params when sublink folding is done.  (The end
+ 	 * result of such a situation would be some unreferenced initplans, which
+ 	 * is annoying but not really a problem.)
+ 	 *
+ 	 * COMPARE_NODE_FIELD(phexpr);
+ 	 */
+ 	COMPARE_BITMAPSET_FIELD(phrels);
+ 	COMPARE_SCALAR_FIELD(phid);
+ 	COMPARE_SCALAR_FIELD(phlevelsup);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareSpecialJoinInfo(SpecialJoinInfo *a, SpecialJoinInfo *b)
+ {
+ 	COMPARE_BITMAPSET_FIELD(min_lefthand);
+ 	COMPARE_BITMAPSET_FIELD(min_righthand);
+ 	COMPARE_BITMAPSET_FIELD(syn_lefthand);
+ 	COMPARE_BITMAPSET_FIELD(syn_righthand);
+ 	COMPARE_SCALAR_FIELD(jointype);
+ 	COMPARE_SCALAR_FIELD(lhs_strict);
+ 	COMPARE_SCALAR_FIELD(delay_upper_joins);
+ 	COMPARE_NODE_FIELD(join_quals);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAppendRelInfo(AppendRelInfo *a, AppendRelInfo *b)
+ {
+ 	COMPARE_SCALAR_FIELD(parent_relid);
+ 	COMPARE_SCALAR_FIELD(child_relid);
+ 	COMPARE_SCALAR_FIELD(parent_reltype);
+ 	COMPARE_SCALAR_FIELD(child_reltype);
+ 	COMPARE_NODE_FIELD(translated_vars);
+ 	COMPARE_SCALAR_FIELD(parent_reloid);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _comparePlaceHolderInfo(PlaceHolderInfo *a, PlaceHolderInfo *b)
+ {
+ 	COMPARE_SCALAR_FIELD(phid);
+ 	COMPARE_NODE_FIELD(ph_var);
+ 	COMPARE_BITMAPSET_FIELD(ph_eval_at);
+ 	COMPARE_BITMAPSET_FIELD(ph_needed);
+ 	COMPARE_SCALAR_FIELD(ph_width);
+ 
+ 	return 0;
+ }
+ 
+ 
+ /*
+  * Stuff from parsenodes.h
+  */
+ 
+ static int
+ _compareQuery(Query *a, Query *b)
+ {
+ 	COMPARE_SCALAR_FIELD(commandType);
+ 	COMPARE_SCALAR_FIELD(querySource);
+ 	COMPARE_SCALAR_FIELD(canSetTag);
+ 	COMPARE_NODE_FIELD(utilityStmt);
+ 	COMPARE_SCALAR_FIELD(resultRelation);
+ 	COMPARE_NODE_FIELD(intoClause);
+ 	COMPARE_SCALAR_FIELD(hasAggs);
+ 	COMPARE_SCALAR_FIELD(hasWindowFuncs);
+ 	COMPARE_SCALAR_FIELD(hasSubLinks);
+ 	COMPARE_SCALAR_FIELD(hasDistinctOn);
+ 	COMPARE_SCALAR_FIELD(hasRecursive);
+ 	COMPARE_SCALAR_FIELD(hasForUpdate);
+ 	COMPARE_NODE_FIELD(cteList);
+ 	COMPARE_NODE_FIELD(rtable);
+ 	COMPARE_NODE_FIELD(jointree);
+ 	COMPARE_NODE_FIELD(targetList);
+ 	COMPARE_NODE_FIELD(returningList);
+ 	COMPARE_NODE_FIELD(groupClause);
+ 	COMPARE_NODE_FIELD(havingQual);
+ 	COMPARE_NODE_FIELD(windowClause);
+ 	COMPARE_NODE_FIELD(distinctClause);
+ 	COMPARE_NODE_FIELD(sortClause);
+ 	COMPARE_NODE_FIELD(limitOffset);
+ 	COMPARE_NODE_FIELD(limitCount);
+ 	COMPARE_NODE_FIELD(rowMarks);
+ 	COMPARE_NODE_FIELD(setOperations);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareInsertStmt(InsertStmt *a, InsertStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(cols);
+ 	COMPARE_NODE_FIELD(selectStmt);
+ 	COMPARE_NODE_FIELD(returningList);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDeleteStmt(DeleteStmt *a, DeleteStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(usingClause);
+ 	COMPARE_NODE_FIELD(whereClause);
+ 	COMPARE_NODE_FIELD(returningList);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareUpdateStmt(UpdateStmt *a, UpdateStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(targetList);
+ 	COMPARE_NODE_FIELD(whereClause);
+ 	COMPARE_NODE_FIELD(fromClause);
+ 	COMPARE_NODE_FIELD(returningList);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareSelectStmt(SelectStmt *a, SelectStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(distinctClause);
+ 	COMPARE_NODE_FIELD(intoClause);
+ 	COMPARE_NODE_FIELD(targetList);
+ 	COMPARE_NODE_FIELD(fromClause);
+ 	COMPARE_NODE_FIELD(whereClause);
+ 	COMPARE_NODE_FIELD(groupClause);
+ 	COMPARE_NODE_FIELD(havingClause);
+ 	COMPARE_NODE_FIELD(windowClause);
+ 	COMPARE_NODE_FIELD(withClause);
+ 	COMPARE_NODE_FIELD(valuesLists);
+ 	COMPARE_NODE_FIELD(sortClause);
+ 	COMPARE_NODE_FIELD(limitOffset);
+ 	COMPARE_NODE_FIELD(limitCount);
+ 	COMPARE_NODE_FIELD(lockingClause);
+ 	COMPARE_SCALAR_FIELD(op);
+ 	COMPARE_SCALAR_FIELD(all);
+ 	COMPARE_NODE_FIELD(larg);
+ 	COMPARE_NODE_FIELD(rarg);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareSetOperationStmt(SetOperationStmt *a, SetOperationStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(op);
+ 	COMPARE_SCALAR_FIELD(all);
+ 	COMPARE_NODE_FIELD(larg);
+ 	COMPARE_NODE_FIELD(rarg);
+ 	COMPARE_NODE_FIELD(colTypes);
+ 	COMPARE_NODE_FIELD(colTypmods);
+ 	COMPARE_NODE_FIELD(groupClauses);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterTableStmt(AlterTableStmt *a, AlterTableStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(cmds);
+ 	COMPARE_SCALAR_FIELD(relkind);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterTableCmd(AlterTableCmd *a, AlterTableCmd *b)
+ {
+ 	COMPARE_SCALAR_FIELD(subtype);
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(def);
+ 	COMPARE_NODE_FIELD(transform);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterDomainStmt(AlterDomainStmt *a, AlterDomainStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(subtype);
+ 	COMPARE_NODE_FIELD(typeName);
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(def);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareGrantStmt(GrantStmt *a, GrantStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(is_grant);
+ 	COMPARE_SCALAR_FIELD(targtype);
+ 	COMPARE_SCALAR_FIELD(objtype);
+ 	COMPARE_NODE_FIELD(objects);
+ 	COMPARE_NODE_FIELD(privileges);
+ 	COMPARE_NODE_FIELD(grantees);
+ 	COMPARE_SCALAR_FIELD(grant_option);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _comparePrivGrantee(PrivGrantee *a, PrivGrantee *b)
+ {
+ 	COMPARE_STRING_FIELD(rolname);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareFuncWithArgs(FuncWithArgs *a, FuncWithArgs *b)
+ {
+ 	COMPARE_NODE_FIELD(funcname);
+ 	COMPARE_NODE_FIELD(funcargs);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAccessPriv(AccessPriv *a, AccessPriv *b)
+ {
+ 	COMPARE_STRING_FIELD(priv_name);
+ 	COMPARE_NODE_FIELD(cols);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareGrantRoleStmt(GrantRoleStmt *a, GrantRoleStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(granted_roles);
+ 	COMPARE_NODE_FIELD(grantee_roles);
+ 	COMPARE_SCALAR_FIELD(is_grant);
+ 	COMPARE_SCALAR_FIELD(admin_opt);
+ 	COMPARE_STRING_FIELD(grantor);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *a, AlterDefaultPrivilegesStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_NODE_FIELD(action);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDeclareCursorStmt(DeclareCursorStmt *a, DeclareCursorStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(portalname);
+ 	COMPARE_SCALAR_FIELD(options);
+ 	COMPARE_NODE_FIELD(query);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(portalname);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareClusterStmt(ClusterStmt *a, ClusterStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_STRING_FIELD(indexname);
+ 	COMPARE_SCALAR_FIELD(verbose);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCopyStmt(CopyStmt *a, CopyStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(query);
+ 	COMPARE_NODE_FIELD(attlist);
+ 	COMPARE_SCALAR_FIELD(is_from);
+ 	COMPARE_STRING_FIELD(filename);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateStmt(CreateStmt *a, CreateStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(tableElts);
+ 	COMPARE_NODE_FIELD(inhRelations);
+ 	COMPARE_NODE_FIELD(ofTypename);
+ 	COMPARE_NODE_FIELD(constraints);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_SCALAR_FIELD(oncommit);
+ 	COMPARE_STRING_FIELD(tablespacename);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareInhRelation(InhRelation *a, InhRelation *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_SCALAR_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDefineStmt(DefineStmt *a, DefineStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(kind);
+ 	COMPARE_SCALAR_FIELD(oldstyle);
+ 	COMPARE_NODE_FIELD(defnames);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_NODE_FIELD(definition);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropStmt(DropStmt *a, DropStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(objects);
+ 	COMPARE_SCALAR_FIELD(removeType);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareTruncateStmt(TruncateStmt *a, TruncateStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relations);
+ 	COMPARE_SCALAR_FIELD(restart_seqs);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCommentStmt(CommentStmt *a, CommentStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(objtype);
+ 	COMPARE_NODE_FIELD(objname);
+ 	COMPARE_NODE_FIELD(objargs);
+ 	COMPARE_STRING_FIELD(comment);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareFetchStmt(FetchStmt *a, FetchStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(direction);
+ 	COMPARE_SCALAR_FIELD(howMany);
+ 	COMPARE_STRING_FIELD(portalname);
+ 	COMPARE_SCALAR_FIELD(ismove);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareIndexStmt(IndexStmt *a, IndexStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(idxname);
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_STRING_FIELD(accessMethod);
+ 	COMPARE_STRING_FIELD(tableSpace);
+ 	COMPARE_NODE_FIELD(indexParams);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_NODE_FIELD(whereClause);
+ 	COMPARE_NODE_FIELD(excludeOpNames);
+ 	COMPARE_SCALAR_FIELD(unique);
+ 	COMPARE_SCALAR_FIELD(primary);
+ 	COMPARE_SCALAR_FIELD(isconstraint);
+ 	COMPARE_SCALAR_FIELD(deferrable);
+ 	COMPARE_SCALAR_FIELD(initdeferred);
+ 	COMPARE_SCALAR_FIELD(concurrent);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateFunctionStmt(CreateFunctionStmt *a, CreateFunctionStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(replace);
+ 	COMPARE_NODE_FIELD(funcname);
+ 	COMPARE_NODE_FIELD(parameters);
+ 	COMPARE_NODE_FIELD(returnType);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_NODE_FIELD(withClause);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareFunctionParameter(FunctionParameter *a, FunctionParameter *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(argType);
+ 	COMPARE_SCALAR_FIELD(mode);
+ 	COMPARE_NODE_FIELD(defexpr);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterFunctionStmt(AlterFunctionStmt *a, AlterFunctionStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(func);
+ 	COMPARE_NODE_FIELD(actions);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(kind);
+ 	COMPARE_NODE_FIELD(name);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDoStmt(DoStmt *a, DoStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(args);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(opclassname);
+ 	COMPARE_STRING_FIELD(amname);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRemoveOpFamilyStmt(RemoveOpFamilyStmt *a, RemoveOpFamilyStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(opfamilyname);
+ 	COMPARE_STRING_FIELD(amname);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRenameStmt(RenameStmt *a, RenameStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(renameType);
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(object);
+ 	COMPARE_NODE_FIELD(objarg);
+ 	COMPARE_STRING_FIELD(subname);
+ 	COMPARE_STRING_FIELD(newname);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterObjectSchemaStmt(AlterObjectSchemaStmt *a, AlterObjectSchemaStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(objectType);
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(object);
+ 	COMPARE_NODE_FIELD(objarg);
+ 	COMPARE_STRING_FIELD(addname);
+ 	COMPARE_STRING_FIELD(newschema);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterOwnerStmt(AlterOwnerStmt *a, AlterOwnerStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(objectType);
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(object);
+ 	COMPARE_NODE_FIELD(objarg);
+ 	COMPARE_STRING_FIELD(addname);
+ 	COMPARE_STRING_FIELD(newowner);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRuleStmt(RuleStmt *a, RuleStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_STRING_FIELD(rulename);
+ 	COMPARE_NODE_FIELD(whereClause);
+ 	COMPARE_SCALAR_FIELD(event);
+ 	COMPARE_SCALAR_FIELD(instead);
+ 	COMPARE_NODE_FIELD(actions);
+ 	COMPARE_SCALAR_FIELD(replace);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareNotifyStmt(NotifyStmt *a, NotifyStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(conditionname);
+ 	COMPARE_STRING_FIELD(payload);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareListenStmt(ListenStmt *a, ListenStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(conditionname);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareUnlistenStmt(UnlistenStmt *a, UnlistenStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(conditionname);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareTransactionStmt(TransactionStmt *a, TransactionStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(kind);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_STRING_FIELD(gid);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCompositeTypeStmt(CompositeTypeStmt *a, CompositeTypeStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(typevar);
+ 	COMPARE_NODE_FIELD(coldeflist);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(typeName);
+ 	COMPARE_NODE_FIELD(vals);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareViewStmt(ViewStmt *a, ViewStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(view);
+ 	COMPARE_NODE_FIELD(aliases);
+ 	COMPARE_NODE_FIELD(query);
+ 	COMPARE_SCALAR_FIELD(replace);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareLoadStmt(LoadStmt *a, LoadStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(filename);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(domainname);
+ 	COMPARE_NODE_FIELD(typeName);
+ 	COMPARE_NODE_FIELD(constraints);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateOpClassStmt(CreateOpClassStmt *a, CreateOpClassStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(opclassname);
+ 	COMPARE_NODE_FIELD(opfamilyname);
+ 	COMPARE_STRING_FIELD(amname);
+ 	COMPARE_NODE_FIELD(datatype);
+ 	COMPARE_NODE_FIELD(items);
+ 	COMPARE_SCALAR_FIELD(isDefault);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
+ {
+ 	COMPARE_SCALAR_FIELD(itemtype);
+ 	COMPARE_NODE_FIELD(name);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_SCALAR_FIELD(number);
+ 	COMPARE_NODE_FIELD(class_args);
+ 	COMPARE_NODE_FIELD(storedtype);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateOpFamilyStmt(CreateOpFamilyStmt *a, CreateOpFamilyStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(opfamilyname);
+ 	COMPARE_STRING_FIELD(amname);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterOpFamilyStmt(AlterOpFamilyStmt *a, AlterOpFamilyStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(opfamilyname);
+ 	COMPARE_STRING_FIELD(amname);
+ 	COMPARE_SCALAR_FIELD(isDrop);
+ 	COMPARE_NODE_FIELD(items);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(dbname);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterDatabaseStmt(AlterDatabaseStmt *a, AlterDatabaseStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(dbname);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterDatabaseSetStmt(AlterDatabaseSetStmt *a, AlterDatabaseSetStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(dbname);
+ 	COMPARE_NODE_FIELD(setstmt);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropdbStmt(DropdbStmt *a, DropdbStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(dbname);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareVacuumStmt(VacuumStmt *a, VacuumStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(options);
+ 	COMPARE_SCALAR_FIELD(freeze_min_age);
+ 	COMPARE_SCALAR_FIELD(freeze_table_age);
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(va_cols);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareExplainStmt(ExplainStmt *a, ExplainStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(query);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateSeqStmt(CreateSeqStmt *a, CreateSeqStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(sequence);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_SCALAR_FIELD(ownerId);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterSeqStmt(AlterSeqStmt *a, AlterSeqStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(sequence);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareVariableSetStmt(VariableSetStmt *a, VariableSetStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(kind);
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_SCALAR_FIELD(is_local);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareVariableShowStmt(VariableShowStmt *a, VariableShowStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDiscardStmt(DiscardStmt *a, DiscardStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(target);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateTableSpaceStmt(CreateTableSpaceStmt *a, CreateTableSpaceStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(tablespacename);
+ 	COMPARE_STRING_FIELD(owner);
+ 	COMPARE_STRING_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropTableSpaceStmt(DropTableSpaceStmt *a, DropTableSpaceStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(tablespacename);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterTableSpaceOptionsStmt(AlterTableSpaceOptionsStmt *a,
+ 								 AlterTableSpaceOptionsStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(tablespacename);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_SCALAR_FIELD(isReset);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(fdwname);
+ 	COMPARE_NODE_FIELD(validator);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterFdwStmt(AlterFdwStmt *a, AlterFdwStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(fdwname);
+ 	COMPARE_NODE_FIELD(validator);
+ 	COMPARE_SCALAR_FIELD(change_validator);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropFdwStmt(DropFdwStmt *a, DropFdwStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(fdwname);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateForeignServerStmt(CreateForeignServerStmt *a, CreateForeignServerStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(servername);
+ 	COMPARE_STRING_FIELD(servertype);
+ 	COMPARE_STRING_FIELD(version);
+ 	COMPARE_STRING_FIELD(fdwname);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterForeignServerStmt(AlterForeignServerStmt *a, AlterForeignServerStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(servername);
+ 	COMPARE_STRING_FIELD(version);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_SCALAR_FIELD(has_version);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropForeignServerStmt(DropForeignServerStmt *a, DropForeignServerStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(servername);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateUserMappingStmt(CreateUserMappingStmt *a, CreateUserMappingStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(username);
+ 	COMPARE_STRING_FIELD(servername);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterUserMappingStmt(AlterUserMappingStmt *a, AlterUserMappingStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(username);
+ 	COMPARE_STRING_FIELD(servername);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropUserMappingStmt(DropUserMappingStmt *a, DropUserMappingStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(username);
+ 	COMPARE_STRING_FIELD(servername);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(trigname);
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_NODE_FIELD(funcname);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_SCALAR_FIELD(row);
+ 	COMPARE_SCALAR_FIELD(timing);
+ 	COMPARE_SCALAR_FIELD(events);
+ 	COMPARE_NODE_FIELD(columns);
+ 	COMPARE_NODE_FIELD(whenClause);
+ 	COMPARE_SCALAR_FIELD(isconstraint);
+ 	COMPARE_SCALAR_FIELD(deferrable);
+ 	COMPARE_SCALAR_FIELD(initdeferred);
+ 	COMPARE_NODE_FIELD(constrrel);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropPropertyStmt(DropPropertyStmt *a, DropPropertyStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_STRING_FIELD(property);
+ 	COMPARE_SCALAR_FIELD(removeType);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(replace);
+ 	COMPARE_STRING_FIELD(plname);
+ 	COMPARE_NODE_FIELD(plhandler);
+ 	COMPARE_NODE_FIELD(plinline);
+ 	COMPARE_NODE_FIELD(plvalidator);
+ 	COMPARE_SCALAR_FIELD(pltrusted);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropPLangStmt(DropPLangStmt *a, DropPLangStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(plname);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateRoleStmt(CreateRoleStmt *a, CreateRoleStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(stmt_type);
+ 	COMPARE_STRING_FIELD(role);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterRoleStmt(AlterRoleStmt *a, AlterRoleStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(role);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_SCALAR_FIELD(action);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterRoleSetStmt(AlterRoleSetStmt *a, AlterRoleSetStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(role);
+ 	COMPARE_STRING_FIELD(database);
+ 	COMPARE_NODE_FIELD(setstmt);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropRoleStmt(DropRoleStmt *a, DropRoleStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(roles);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareLockStmt(LockStmt *a, LockStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(relations);
+ 	COMPARE_SCALAR_FIELD(mode);
+ 	COMPARE_SCALAR_FIELD(nowait);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareConstraintsSetStmt(ConstraintsSetStmt *a, ConstraintsSetStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(constraints);
+ 	COMPARE_SCALAR_FIELD(deferred);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareReindexStmt(ReindexStmt *a, ReindexStmt *b)
+ {
+ 	COMPARE_SCALAR_FIELD(kind);
+ 	COMPARE_NODE_FIELD(relation);
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_SCALAR_FIELD(do_system);
+ 	COMPARE_SCALAR_FIELD(do_user);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateSchemaStmt(CreateSchemaStmt *a, CreateSchemaStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(schemaname);
+ 	COMPARE_STRING_FIELD(authid);
+ 	COMPARE_NODE_FIELD(schemaElts);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateConversionStmt(CreateConversionStmt *a, CreateConversionStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(conversion_name);
+ 	COMPARE_STRING_FIELD(for_encoding_name);
+ 	COMPARE_STRING_FIELD(to_encoding_name);
+ 	COMPARE_NODE_FIELD(func_name);
+ 	COMPARE_SCALAR_FIELD(def);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCreateCastStmt(CreateCastStmt *a, CreateCastStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(sourcetype);
+ 	COMPARE_NODE_FIELD(targettype);
+ 	COMPARE_NODE_FIELD(func);
+ 	COMPARE_SCALAR_FIELD(context);
+ 	COMPARE_SCALAR_FIELD(inout);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropCastStmt(DropCastStmt *a, DropCastStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(sourcetype);
+ 	COMPARE_NODE_FIELD(targettype);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _comparePrepareStmt(PrepareStmt *a, PrepareStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(argtypes);
+ 	COMPARE_NODE_FIELD(query);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareExecuteStmt(ExecuteStmt *a, ExecuteStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(into);
+ 	COMPARE_NODE_FIELD(params);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDeallocateStmt(DeallocateStmt *a, DeallocateStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDropOwnedStmt(DropOwnedStmt *a, DropOwnedStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(roles);
+ 	COMPARE_SCALAR_FIELD(behavior);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareReassignOwnedStmt(ReassignOwnedStmt *a, ReassignOwnedStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(roles);
+ 	COMPARE_NODE_FIELD(newrole);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterTSDictionaryStmt(AlterTSDictionaryStmt *a, AlterTSDictionaryStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(dictname);
+ 	COMPARE_NODE_FIELD(options);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAlterTSConfigurationStmt(AlterTSConfigurationStmt *a,
+ 							   AlterTSConfigurationStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(cfgname);
+ 	COMPARE_NODE_FIELD(tokentype);
+ 	COMPARE_NODE_FIELD(dicts);
+ 	COMPARE_SCALAR_FIELD(override);
+ 	COMPARE_SCALAR_FIELD(replace);
+ 	COMPARE_SCALAR_FIELD(missing_ok);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAExpr(A_Expr *a, A_Expr *b)
+ {
+ 	COMPARE_SCALAR_FIELD(kind);
+ 	COMPARE_NODE_FIELD(name);
+ 	COMPARE_NODE_FIELD(lexpr);
+ 	COMPARE_NODE_FIELD(rexpr);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareColumnRef(ColumnRef *a, ColumnRef *b)
+ {
+ 	COMPARE_NODE_FIELD(fields);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareParamRef(ParamRef *a, ParamRef *b)
+ {
+ 	COMPARE_SCALAR_FIELD(number);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAConst(A_Const *a, A_Const *b)
+ {
+ 	int	ret;
+ 	if ((ret = compare(&a->val, &b->val)) != 0)	/* hack for in-line Value field */
+ 		return ret;
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareFuncCall(FuncCall *a, FuncCall *b)
+ {
+ 	COMPARE_NODE_FIELD(funcname);
+ 	COMPARE_NODE_FIELD(args);
+ 	COMPARE_NODE_FIELD(agg_order);
+ 	COMPARE_SCALAR_FIELD(agg_star);
+ 	COMPARE_SCALAR_FIELD(agg_distinct);
+ 	COMPARE_SCALAR_FIELD(func_variadic);
+ 	COMPARE_NODE_FIELD(over);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareAStar(A_Star *a, A_Star *b)
+ {
+ 	return 0;
+ }
+ 
+ static int
+ _compareAIndices(A_Indices *a, A_Indices *b)
+ {
+ 	COMPARE_NODE_FIELD(lidx);
+ 	COMPARE_NODE_FIELD(uidx);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareA_Indirection(A_Indirection *a, A_Indirection *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_NODE_FIELD(indirection);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareA_ArrayExpr(A_ArrayExpr *a, A_ArrayExpr *b)
+ {
+ 	COMPARE_NODE_FIELD(elements);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareResTarget(ResTarget *a, ResTarget *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(indirection);
+ 	COMPARE_NODE_FIELD(val);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareTypeName(TypeName *a, TypeName *b)
+ {
+ 	COMPARE_NODE_FIELD(names);
+ 	COMPARE_SCALAR_FIELD(typeOid);
+ 	COMPARE_SCALAR_FIELD(setof);
+ 	COMPARE_SCALAR_FIELD(pct_type);
+ 	COMPARE_NODE_FIELD(typmods);
+ 	COMPARE_SCALAR_FIELD(typemod);
+ 	COMPARE_NODE_FIELD(arrayBounds);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareTypeCast(TypeCast *a, TypeCast *b)
+ {
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_NODE_FIELD(typeName);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareSortBy(SortBy *a, SortBy *b)
+ {
+ 	COMPARE_NODE_FIELD(node);
+ 	COMPARE_SCALAR_FIELD(sortby_dir);
+ 	COMPARE_SCALAR_FIELD(sortby_nulls);
+ 	COMPARE_NODE_FIELD(useOp);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareWindowDef(WindowDef *a, WindowDef *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_STRING_FIELD(refname);
+ 	COMPARE_NODE_FIELD(partitionClause);
+ 	COMPARE_NODE_FIELD(orderClause);
+ 	COMPARE_SCALAR_FIELD(frameOptions);
+ 	COMPARE_NODE_FIELD(startOffset);
+ 	COMPARE_NODE_FIELD(endOffset);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRangeSubselect(RangeSubselect *a, RangeSubselect *b)
+ {
+ 	COMPARE_NODE_FIELD(subquery);
+ 	COMPARE_NODE_FIELD(alias);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRangeFunction(RangeFunction *a, RangeFunction *b)
+ {
+ 	COMPARE_NODE_FIELD(funccallnode);
+ 	COMPARE_NODE_FIELD(alias);
+ 	COMPARE_NODE_FIELD(coldeflist);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareIndexElem(IndexElem *a, IndexElem *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_NODE_FIELD(expr);
+ 	COMPARE_STRING_FIELD(indexcolname);
+ 	COMPARE_NODE_FIELD(opclass);
+ 	COMPARE_SCALAR_FIELD(ordering);
+ 	COMPARE_SCALAR_FIELD(nulls_ordering);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareColumnDef(ColumnDef *a, ColumnDef *b)
+ {
+ 	COMPARE_STRING_FIELD(colname);
+ 	COMPARE_NODE_FIELD(typeName);
+ 	COMPARE_SCALAR_FIELD(inhcount);
+ 	COMPARE_SCALAR_FIELD(is_local);
+ 	COMPARE_SCALAR_FIELD(is_not_null);
+ 	COMPARE_SCALAR_FIELD(storage);
+ 	COMPARE_NODE_FIELD(raw_default);
+ 	COMPARE_NODE_FIELD(cooked_default);
+ 	COMPARE_NODE_FIELD(constraints);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareConstraint(Constraint *a, Constraint *b)
+ {
+ 	COMPARE_SCALAR_FIELD(contype);
+ 	COMPARE_STRING_FIELD(conname);
+ 	COMPARE_SCALAR_FIELD(deferrable);
+ 	COMPARE_SCALAR_FIELD(initdeferred);
+ 	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_NODE_FIELD(raw_expr);
+ 	COMPARE_STRING_FIELD(cooked_expr);
+ 	COMPARE_NODE_FIELD(keys);
+ 	COMPARE_NODE_FIELD(exclusions);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_STRING_FIELD(indexspace);
+ 	COMPARE_STRING_FIELD(access_method);
+ 	COMPARE_NODE_FIELD(where_clause);
+ 	COMPARE_NODE_FIELD(pktable);
+ 	COMPARE_NODE_FIELD(fk_attrs);
+ 	COMPARE_NODE_FIELD(pk_attrs);
+ 	COMPARE_SCALAR_FIELD(fk_matchtype);
+ 	COMPARE_SCALAR_FIELD(fk_upd_action);
+ 	COMPARE_SCALAR_FIELD(fk_del_action);
+ 	COMPARE_SCALAR_FIELD(skip_validation);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareDefElem(DefElem *a, DefElem *b)
+ {
+ 	COMPARE_STRING_FIELD(defnamespace);
+ 	COMPARE_STRING_FIELD(defname);
+ 	COMPARE_NODE_FIELD(arg);
+ 	COMPARE_SCALAR_FIELD(defaction);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareLockingClause(LockingClause *a, LockingClause *b)
+ {
+ 	COMPARE_NODE_FIELD(lockedRels);
+ 	COMPARE_SCALAR_FIELD(forUpdate);
+ 	COMPARE_SCALAR_FIELD(noWait);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
+ {
+ 	COMPARE_SCALAR_FIELD(rtekind);
+ 	COMPARE_SCALAR_FIELD(relid);
+ 	COMPARE_NODE_FIELD(subquery);
+ 	COMPARE_SCALAR_FIELD(jointype);
+ 	COMPARE_NODE_FIELD(joinaliasvars);
+ 	COMPARE_NODE_FIELD(funcexpr);
+ 	COMPARE_NODE_FIELD(funccoltypes);
+ 	COMPARE_NODE_FIELD(funccoltypmods);
+ 	COMPARE_NODE_FIELD(values_lists);
+ 	COMPARE_STRING_FIELD(ctename);
+ 	COMPARE_SCALAR_FIELD(ctelevelsup);
+ 	COMPARE_SCALAR_FIELD(self_reference);
+ 	COMPARE_NODE_FIELD(ctecoltypes);
+ 	COMPARE_NODE_FIELD(ctecoltypmods);
+ 	COMPARE_NODE_FIELD(alias);
+ 	COMPARE_NODE_FIELD(eref);
+ 	COMPARE_SCALAR_FIELD(inh);
+ 	COMPARE_SCALAR_FIELD(inFromCl);
+ 	COMPARE_SCALAR_FIELD(requiredPerms);
+ 	COMPARE_SCALAR_FIELD(checkAsUser);
+ 	COMPARE_BITMAPSET_FIELD(selectedCols);
+ 	COMPARE_BITMAPSET_FIELD(modifiedCols);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareSortGroupClause(SortGroupClause *a, SortGroupClause *b)
+ {
+ 	COMPARE_SCALAR_FIELD(tleSortGroupRef);
+ 	COMPARE_SCALAR_FIELD(eqop);
+ 	COMPARE_SCALAR_FIELD(sortop);
+ 	COMPARE_SCALAR_FIELD(nulls_first);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareWindowClause(WindowClause *a, WindowClause *b)
+ {
+ 	COMPARE_STRING_FIELD(name);
+ 	COMPARE_STRING_FIELD(refname);
+ 	COMPARE_NODE_FIELD(partitionClause);
+ 	COMPARE_NODE_FIELD(orderClause);
+ 	COMPARE_SCALAR_FIELD(frameOptions);
+ 	COMPARE_NODE_FIELD(startOffset);
+ 	COMPARE_NODE_FIELD(endOffset);
+ 	COMPARE_SCALAR_FIELD(winref);
+ 	COMPARE_SCALAR_FIELD(copiedOrder);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareRowMarkClause(RowMarkClause *a, RowMarkClause *b)
+ {
+ 	COMPARE_SCALAR_FIELD(rti);
+ 	COMPARE_SCALAR_FIELD(forUpdate);
+ 	COMPARE_SCALAR_FIELD(noWait);
+ 	COMPARE_SCALAR_FIELD(pushedDown);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareWithClause(WithClause *a, WithClause *b)
+ {
+ 	COMPARE_NODE_FIELD(ctes);
+ 	COMPARE_SCALAR_FIELD(recursive);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareCommonTableExpr(CommonTableExpr *a, CommonTableExpr *b)
+ {
+ 	COMPARE_STRING_FIELD(ctename);
+ 	COMPARE_NODE_FIELD(aliascolnames);
+ 	COMPARE_NODE_FIELD(ctequery);
+ 	COMPARE_LOCATION_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(cterecursive);
+ 	COMPARE_SCALAR_FIELD(cterefcount);
+ 	COMPARE_NODE_FIELD(ctecolnames);
+ 	COMPARE_NODE_FIELD(ctecoltypes);
+ 	COMPARE_NODE_FIELD(ctecoltypmods);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ _compareXmlSerialize(XmlSerialize *a, XmlSerialize *b)
+ {
+ 	COMPARE_SCALAR_FIELD(xmloption);
+ 	COMPARE_NODE_FIELD(expr);
+ 	COMPARE_NODE_FIELD(typeName);
+ 	COMPARE_LOCATION_FIELD(location);
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * Stuff from pg_list.h
+  */
+ 
+ static int
+ _compareList(List *a, List *b)
+ {
+ 	ListCell   *item_a;
+ 	ListCell   *item_b;
+ 	int		ret;
+ 
+ 	/*
+ 	 * Try to reject by simple scalar checks before grovelling through all the
+ 	 * list elements...
+ 	 */
+ 	COMPARE_SCALAR_FIELD(type);
+ 	COMPARE_SCALAR_FIELD(length);
+ 
+ 	/*
+ 	 * We place the switch outside the loop for the sake of efficiency; this
+ 	 * may not be worth doing...
+ 	 */
+ 	switch (a->type)
+ 	{
+ 		case T_List:
+ 			forboth(item_a, a, item_b, b)
+ 			{
+ 				ret = compare(lfirst(item_a), lfirst(item_b));
+ 				if (ret != 0)
+ 					return ret;
+ 			}
+ 			break;
+ 		case T_IntList:
+ 			forboth(item_a, a, item_b, b)
+ 			{
+ 				int	val_a = lfirst_int(item_a);
+ 				int	val_b = lfirst_int(item_b);
+ 
+ 				if (val_a < val_b)
+ 					return -1;
+ 				else if (val_a > val_b)
+ 					return 1;
+ 			}
+ 			break;
+ 		case T_OidList:
+ 			forboth(item_a, a, item_b, b)
+ 			{
+ 				Oid	val_a = lfirst_oid(item_a);
+ 				Oid	val_b = lfirst_oid(item_b);
+ 
+ 				if (val_a < val_b)
+ 					return -1;
+ 				else if (val_a > val_b)
+ 					return 1;
+ 			}
+ 			break;
+ 		default:
+ 			elog(ERROR, "unrecognized list node type: %d",
+ 				 (int) a->type);
+ 			return 0;		/* keep compiler quiet */
+ 	}
+ 
+ 	/*
+ 	 * If we got here, we should have run out of elements of both lists
+ 	 */
+ 	Assert(item_a == NULL);
+ 	Assert(item_b == NULL);
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * Stuff from value.h
+  */
+ 
+ static int
+ _compareValue(Value *a, Value *b)
+ {
+ 	COMPARE_SCALAR_FIELD(type);
+ 
+ 	switch (a->type)
+ 	{
+ 		case T_Integer:
+ 			COMPARE_SCALAR_FIELD(val.ival);
+ 			break;
+ 		case T_Float:
+ 		case T_String:
+ 		case T_BitString:
+ 			COMPARE_STRING_FIELD(val.str);
+ 			break;
+ 		case T_Null:
+ 			/* nothing to do */
+ 			break;
+ 		default:
+ 			elog(ERROR, "unrecognized node type: %d", (int) a->type);
+ 			break;
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * equal
+  *	  returns whether two nodes are equal
+  */
+ int
+ compare(void *a, void *b)
+ {
+ 	int		retval;
+ 
+ 	if (a == b)
+ 		return 0;
+ 
+ 	/*
+ 	 * note that a!=b, so only one of them can be NULL
+ 	 */
+ 	if (a == NULL || b == NULL)
+ 	{
+ 		if (a < b)
+ 			return -1;
+ 		else if (a > b)
+ 			return 1;
+ 	}
+ 
+ 	/*
+ 	 * are they the same type of nodes?
+ 	 */
+ 	if (nodeTag(a) < nodeTag(b))
+ 		return -1;
+ 	else if (nodeTag(a) > nodeTag(b))
+ 		return 1;
+ 
+ 	switch (nodeTag(a))
+ 	{
+ 			/*
+ 			 * PRIMITIVE NODES
+ 			 */
+ 		case T_Alias:
+ 			retval = _compareAlias(a, b);
+ 			break;
+ 		case T_RangeVar:
+ 			retval = _compareRangeVar(a, b);
+ 			break;
+ 		case T_IntoClause:
+ 			retval = _compareIntoClause(a, b);
+ 			break;
+ 		case T_Var:
+ 			retval = _compareVar(a, b);
+ 			break;
+ 		case T_Const:
+ 			retval = _compareConst(a, b);
+ 			break;
+ 		case T_Param:
+ 			retval = _compareParam(a, b);
+ 			break;
+ 		case T_Aggref:
+ 			retval = _compareAggref(a, b);
+ 			break;
+ 		case T_WindowFunc:
+ 			retval = _compareWindowFunc(a, b);
+ 			break;
+ 		case T_ArrayRef:
+ 			retval = _compareArrayRef(a, b);
+ 			break;
+ 		case T_FuncExpr:
+ 			retval = _compareFuncExpr(a, b);
+ 			break;
+ 		case T_NamedArgExpr:
+ 			retval = _compareNamedArgExpr(a, b);
+ 			break;
+ 		case T_OpExpr:
+ 			retval = _compareOpExpr(a, b);
+ 			break;
+ 		case T_DistinctExpr:
+ 			retval = _compareDistinctExpr(a, b);
+ 			break;
+ 		case T_ScalarArrayOpExpr:
+ 			retval = _compareScalarArrayOpExpr(a, b);
+ 			break;
+ 		case T_BoolExpr:
+ 			retval = _compareBoolExpr(a, b);
+ 			break;
+ 		case T_SubLink:
+ 			retval = _compareSubLink(a, b);
+ 			break;
+ 		case T_SubPlan:
+ 			retval = _compareSubPlan(a, b);
+ 			break;
+ 		case T_AlternativeSubPlan:
+ 			retval = _compareAlternativeSubPlan(a, b);
+ 			break;
+ 		case T_FieldSelect:
+ 			retval = _compareFieldSelect(a, b);
+ 			break;
+ 		case T_FieldStore:
+ 			retval = _compareFieldStore(a, b);
+ 			break;
+ 		case T_RelabelType:
+ 			retval = _compareRelabelType(a, b);
+ 			break;
+ 		case T_CoerceViaIO:
+ 			retval = _compareCoerceViaIO(a, b);
+ 			break;
+ 		case T_ArrayCoerceExpr:
+ 			retval = _compareArrayCoerceExpr(a, b);
+ 			break;
+ 		case T_ConvertRowtypeExpr:
+ 			retval = _compareConvertRowtypeExpr(a, b);
+ 			break;
+ 		case T_CaseExpr:
+ 			retval = _compareCaseExpr(a, b);
+ 			break;
+ 		case T_CaseWhen:
+ 			retval = _compareCaseWhen(a, b);
+ 			break;
+ 		case T_CaseTestExpr:
+ 			retval = _compareCaseTestExpr(a, b);
+ 			break;
+ 		case T_ArrayExpr:
+ 			retval = _compareArrayExpr(a, b);
+ 			break;
+ 		case T_RowExpr:
+ 			retval = _compareRowExpr(a, b);
+ 			break;
+ 		case T_RowCompareExpr:
+ 			retval = _compareRowCompareExpr(a, b);
+ 			break;
+ 		case T_CoalesceExpr:
+ 			retval = _compareCoalesceExpr(a, b);
+ 			break;
+ 		case T_MinMaxExpr:
+ 			retval = _compareMinMaxExpr(a, b);
+ 			break;
+ 		case T_XmlExpr:
+ 			retval = _compareXmlExpr(a, b);
+ 			break;
+ 		case T_NullIfExpr:
+ 			retval = _compareNullIfExpr(a, b);
+ 			break;
+ 		case T_NullTest:
+ 			retval = _compareNullTest(a, b);
+ 			break;
+ 		case T_BooleanTest:
+ 			retval = _compareBooleanTest(a, b);
+ 			break;
+ 		case T_CoerceToDomain:
+ 			retval = _compareCoerceToDomain(a, b);
+ 			break;
+ 		case T_CoerceToDomainValue:
+ 			retval = _compareCoerceToDomainValue(a, b);
+ 			break;
+ 		case T_SetToDefault:
+ 			retval = _compareSetToDefault(a, b);
+ 			break;
+ 		case T_CurrentOfExpr:
+ 			retval = _compareCurrentOfExpr(a, b);
+ 			break;
+ 		case T_TargetEntry:
+ 			retval = _compareTargetEntry(a, b);
+ 			break;
+ 		case T_RangeTblRef:
+ 			retval = _compareRangeTblRef(a, b);
+ 			break;
+ 		case T_FromExpr:
+ 			retval = _compareFromExpr(a, b);
+ 			break;
+ 		case T_JoinExpr:
+ 			retval = _compareJoinExpr(a, b);
+ 			break;
+ 
+ 			/*
+ 			 * RELATION NODES
+ 			 */
+ 		case T_PathKey:
+ 			retval = _comparePathKey(a, b);
+ 			break;
+ 		case T_RestrictInfo:
+ 			retval = _compareRestrictInfo(a, b);
+ 			break;
+ 		case T_PlaceHolderVar:
+ 			retval = _comparePlaceHolderVar(a, b);
+ 			break;
+ 		case T_SpecialJoinInfo:
+ 			retval = _compareSpecialJoinInfo(a, b);
+ 			break;
+ 		case T_AppendRelInfo:
+ 			retval = _compareAppendRelInfo(a, b);
+ 			break;
+ 		case T_PlaceHolderInfo:
+ 			retval = _comparePlaceHolderInfo(a, b);
+ 			break;
+ 
+ 		case T_List:
+ 		case T_IntList:
+ 		case T_OidList:
+ 			retval = _compareList(a, b);
+ 			break;
+ 
+ 		case T_Integer:
+ 		case T_Float:
+ 		case T_String:
+ 		case T_BitString:
+ 		case T_Null:
+ 			retval = _compareValue(a, b);
+ 			break;
+ 
+ 			/*
+ 			 * PARSE NODES
+ 			 */
+ 		case T_Query:
+ 			retval = _compareQuery(a, b);
+ 			break;
+ 		case T_InsertStmt:
+ 			retval = _compareInsertStmt(a, b);
+ 			break;
+ 		case T_DeleteStmt:
+ 			retval = _compareDeleteStmt(a, b);
+ 			break;
+ 		case T_UpdateStmt:
+ 			retval = _compareUpdateStmt(a, b);
+ 			break;
+ 		case T_SelectStmt:
+ 			retval = _compareSelectStmt(a, b);
+ 			break;
+ 		case T_SetOperationStmt:
+ 			retval = _compareSetOperationStmt(a, b);
+ 			break;
+ 		case T_AlterTableStmt:
+ 			retval = _compareAlterTableStmt(a, b);
+ 			break;
+ 		case T_AlterTableCmd:
+ 			retval = _compareAlterTableCmd(a, b);
+ 			break;
+ 		case T_AlterDomainStmt:
+ 			retval = _compareAlterDomainStmt(a, b);
+ 			break;
+ 		case T_GrantStmt:
+ 			retval = _compareGrantStmt(a, b);
+ 			break;
+ 		case T_GrantRoleStmt:
+ 			retval = _compareGrantRoleStmt(a, b);
+ 			break;
+ 		case T_AlterDefaultPrivilegesStmt:
+ 			retval = _compareAlterDefaultPrivilegesStmt(a, b);
+ 			break;
+ 		case T_DeclareCursorStmt:
+ 			retval = _compareDeclareCursorStmt(a, b);
+ 			break;
+ 		case T_ClosePortalStmt:
+ 			retval = _compareClosePortalStmt(a, b);
+ 			break;
+ 		case T_ClusterStmt:
+ 			retval = _compareClusterStmt(a, b);
+ 			break;
+ 		case T_CopyStmt:
+ 			retval = _compareCopyStmt(a, b);
+ 			break;
+ 		case T_CreateStmt:
+ 			retval = _compareCreateStmt(a, b);
+ 			break;
+ 		case T_InhRelation:
+ 			retval = _compareInhRelation(a, b);
+ 			break;
+ 		case T_DefineStmt:
+ 			retval = _compareDefineStmt(a, b);
+ 			break;
+ 		case T_DropStmt:
+ 			retval = _compareDropStmt(a, b);
+ 			break;
+ 		case T_TruncateStmt:
+ 			retval = _compareTruncateStmt(a, b);
+ 			break;
+ 		case T_CommentStmt:
+ 			retval = _compareCommentStmt(a, b);
+ 			break;
+ 		case T_FetchStmt:
+ 			retval = _compareFetchStmt(a, b);
+ 			break;
+ 		case T_IndexStmt:
+ 			retval = _compareIndexStmt(a, b);
+ 			break;
+ 		case T_CreateFunctionStmt:
+ 			retval = _compareCreateFunctionStmt(a, b);
+ 			break;
+ 		case T_FunctionParameter:
+ 			retval = _compareFunctionParameter(a, b);
+ 			break;
+ 		case T_AlterFunctionStmt:
+ 			retval = _compareAlterFunctionStmt(a, b);
+ 			break;
+ 		case T_RemoveFuncStmt:
+ 			retval = _compareRemoveFuncStmt(a, b);
+ 			break;
+ 		case T_DoStmt:
+ 			retval = _compareDoStmt(a, b);
+ 			break;
+ 		case T_RemoveOpClassStmt:
+ 			retval = _compareRemoveOpClassStmt(a, b);
+ 			break;
+ 		case T_RemoveOpFamilyStmt:
+ 			retval = _compareRemoveOpFamilyStmt(a, b);
+ 			break;
+ 		case T_RenameStmt:
+ 			retval = _compareRenameStmt(a, b);
+ 			break;
+ 		case T_AlterObjectSchemaStmt:
+ 			retval = _compareAlterObjectSchemaStmt(a, b);
+ 			break;
+ 		case T_AlterOwnerStmt:
+ 			retval = _compareAlterOwnerStmt(a, b);
+ 			break;
+ 		case T_RuleStmt:
+ 			retval = _compareRuleStmt(a, b);
+ 			break;
+ 		case T_NotifyStmt:
+ 			retval = _compareNotifyStmt(a, b);
+ 			break;
+ 		case T_ListenStmt:
+ 			retval = _compareListenStmt(a, b);
+ 			break;
+ 		case T_UnlistenStmt:
+ 			retval = _compareUnlistenStmt(a, b);
+ 			break;
+ 		case T_TransactionStmt:
+ 			retval = _compareTransactionStmt(a, b);
+ 			break;
+ 		case T_CompositeTypeStmt:
+ 			retval = _compareCompositeTypeStmt(a, b);
+ 			break;
+ 		case T_CreateEnumStmt:
+ 			retval = _compareCreateEnumStmt(a, b);
+ 			break;
+ 		case T_ViewStmt:
+ 			retval = _compareViewStmt(a, b);
+ 			break;
+ 		case T_LoadStmt:
+ 			retval = _compareLoadStmt(a, b);
+ 			break;
+ 		case T_CreateDomainStmt:
+ 			retval = _compareCreateDomainStmt(a, b);
+ 			break;
+ 		case T_CreateOpClassStmt:
+ 			retval = _compareCreateOpClassStmt(a, b);
+ 			break;
+ 		case T_CreateOpClassItem:
+ 			retval = _compareCreateOpClassItem(a, b);
+ 			break;
+ 		case T_CreateOpFamilyStmt:
+ 			retval = _compareCreateOpFamilyStmt(a, b);
+ 			break;
+ 		case T_AlterOpFamilyStmt:
+ 			retval = _compareAlterOpFamilyStmt(a, b);
+ 			break;
+ 		case T_CreatedbStmt:
+ 			retval = _compareCreatedbStmt(a, b);
+ 			break;
+ 		case T_AlterDatabaseStmt:
+ 			retval = _compareAlterDatabaseStmt(a, b);
+ 			break;
+ 		case T_AlterDatabaseSetStmt:
+ 			retval = _compareAlterDatabaseSetStmt(a, b);
+ 			break;
+ 		case T_DropdbStmt:
+ 			retval = _compareDropdbStmt(a, b);
+ 			break;
+ 		case T_VacuumStmt:
+ 			retval = _compareVacuumStmt(a, b);
+ 			break;
+ 		case T_ExplainStmt:
+ 			retval = _compareExplainStmt(a, b);
+ 			break;
+ 		case T_CreateSeqStmt:
+ 			retval = _compareCreateSeqStmt(a, b);
+ 			break;
+ 		case T_AlterSeqStmt:
+ 			retval = _compareAlterSeqStmt(a, b);
+ 			break;
+ 		case T_VariableSetStmt:
+ 			retval = _compareVariableSetStmt(a, b);
+ 			break;
+ 		case T_VariableShowStmt:
+ 			retval = _compareVariableShowStmt(a, b);
+ 			break;
+ 		case T_DiscardStmt:
+ 			retval = _compareDiscardStmt(a, b);
+ 			break;
+ 		case T_CreateTableSpaceStmt:
+ 			retval = _compareCreateTableSpaceStmt(a, b);
+ 			break;
+ 		case T_DropTableSpaceStmt:
+ 			retval = _compareDropTableSpaceStmt(a, b);
+ 			break;
+ 		case T_AlterTableSpaceOptionsStmt:
+ 			retval = _compareAlterTableSpaceOptionsStmt(a, b);
+ 			break;
+ 		case T_CreateFdwStmt:
+ 			retval = _compareCreateFdwStmt(a, b);
+ 			break;
+ 		case T_AlterFdwStmt:
+ 			retval = _compareAlterFdwStmt(a, b);
+ 			break;
+ 		case T_DropFdwStmt:
+ 			retval = _compareDropFdwStmt(a, b);
+ 			break;
+ 		case T_CreateForeignServerStmt:
+ 			retval = _compareCreateForeignServerStmt(a, b);
+ 			break;
+ 		case T_AlterForeignServerStmt:
+ 			retval = _compareAlterForeignServerStmt(a, b);
+ 			break;
+ 		case T_DropForeignServerStmt:
+ 			retval = _compareDropForeignServerStmt(a, b);
+ 			break;
+ 		case T_CreateUserMappingStmt:
+ 			retval = _compareCreateUserMappingStmt(a, b);
+ 			break;
+ 		case T_AlterUserMappingStmt:
+ 			retval = _compareAlterUserMappingStmt(a, b);
+ 			break;
+ 		case T_DropUserMappingStmt:
+ 			retval = _compareDropUserMappingStmt(a, b);
+ 			break;
+ 		case T_CreateTrigStmt:
+ 			retval = _compareCreateTrigStmt(a, b);
+ 			break;
+ 		case T_DropPropertyStmt:
+ 			retval = _compareDropPropertyStmt(a, b);
+ 			break;
+ 		case T_CreatePLangStmt:
+ 			retval = _compareCreatePLangStmt(a, b);
+ 			break;
+ 		case T_DropPLangStmt:
+ 			retval = _compareDropPLangStmt(a, b);
+ 			break;
+ 		case T_CreateRoleStmt:
+ 			retval = _compareCreateRoleStmt(a, b);
+ 			break;
+ 		case T_AlterRoleStmt:
+ 			retval = _compareAlterRoleStmt(a, b);
+ 			break;
+ 		case T_AlterRoleSetStmt:
+ 			retval = _compareAlterRoleSetStmt(a, b);
+ 			break;
+ 		case T_DropRoleStmt:
+ 			retval = _compareDropRoleStmt(a, b);
+ 			break;
+ 		case T_LockStmt:
+ 			retval = _compareLockStmt(a, b);
+ 			break;
+ 		case T_ConstraintsSetStmt:
+ 			retval = _compareConstraintsSetStmt(a, b);
+ 			break;
+ 		case T_ReindexStmt:
+ 			retval = _compareReindexStmt(a, b);
+ 			break;
+ 		case T_CheckPointStmt:
+ 			retval = 0;
+ 			break;
+ 		case T_CreateSchemaStmt:
+ 			retval = _compareCreateSchemaStmt(a, b);
+ 			break;
+ 		case T_CreateConversionStmt:
+ 			retval = _compareCreateConversionStmt(a, b);
+ 			break;
+ 		case T_CreateCastStmt:
+ 			retval = _compareCreateCastStmt(a, b);
+ 			break;
+ 		case T_DropCastStmt:
+ 			retval = _compareDropCastStmt(a, b);
+ 			break;
+ 		case T_PrepareStmt:
+ 			retval = _comparePrepareStmt(a, b);
+ 			break;
+ 		case T_ExecuteStmt:
+ 			retval = _compareExecuteStmt(a, b);
+ 			break;
+ 		case T_DeallocateStmt:
+ 			retval = _compareDeallocateStmt(a, b);
+ 			break;
+ 		case T_DropOwnedStmt:
+ 			retval = _compareDropOwnedStmt(a, b);
+ 			break;
+ 		case T_ReassignOwnedStmt:
+ 			retval = _compareReassignOwnedStmt(a, b);
+ 			break;
+ 		case T_AlterTSDictionaryStmt:
+ 			retval = _compareAlterTSDictionaryStmt(a, b);
+ 			break;
+ 		case T_AlterTSConfigurationStmt:
+ 			retval = _compareAlterTSConfigurationStmt(a, b);
+ 			break;
+ 
+ 		case T_A_Expr:
+ 			retval = _compareAExpr(a, b);
+ 			break;
+ 		case T_ColumnRef:
+ 			retval = _compareColumnRef(a, b);
+ 			break;
+ 		case T_ParamRef:
+ 			retval = _compareParamRef(a, b);
+ 			break;
+ 		case T_A_Const:
+ 			retval = _compareAConst(a, b);
+ 			break;
+ 		case T_FuncCall:
+ 			retval = _compareFuncCall(a, b);
+ 			break;
+ 		case T_A_Star:
+ 			retval = _compareAStar(a, b);
+ 			break;
+ 		case T_A_Indices:
+ 			retval = _compareAIndices(a, b);
+ 			break;
+ 		case T_A_Indirection:
+ 			retval = _compareA_Indirection(a, b);
+ 			break;
+ 		case T_A_ArrayExpr:
+ 			retval = _compareA_ArrayExpr(a, b);
+ 			break;
+ 		case T_ResTarget:
+ 			retval = _compareResTarget(a, b);
+ 			break;
+ 		case T_TypeCast:
+ 			retval = _compareTypeCast(a, b);
+ 			break;
+ 		case T_SortBy:
+ 			retval = _compareSortBy(a, b);
+ 			break;
+ 		case T_WindowDef:
+ 			retval = _compareWindowDef(a, b);
+ 			break;
+ 		case T_RangeSubselect:
+ 			retval = _compareRangeSubselect(a, b);
+ 			break;
+ 		case T_RangeFunction:
+ 			retval = _compareRangeFunction(a, b);
+ 			break;
+ 		case T_TypeName:
+ 			retval = _compareTypeName(a, b);
+ 			break;
+ 		case T_IndexElem:
+ 			retval = _compareIndexElem(a, b);
+ 			break;
+ 		case T_ColumnDef:
+ 			retval = _compareColumnDef(a, b);
+ 			break;
+ 		case T_Constraint:
+ 			retval = _compareConstraint(a, b);
+ 			break;
+ 		case T_DefElem:
+ 			retval = _compareDefElem(a, b);
+ 			break;
+ 		case T_LockingClause:
+ 			retval = _compareLockingClause(a, b);
+ 			break;
+ 		case T_RangeTblEntry:
+ 			retval = _compareRangeTblEntry(a, b);
+ 			break;
+ 		case T_SortGroupClause:
+ 			retval = _compareSortGroupClause(a, b);
+ 			break;
+ 		case T_WindowClause:
+ 			retval = _compareWindowClause(a, b);
+ 			break;
+ 		case T_RowMarkClause:
+ 			retval = _compareRowMarkClause(a, b);
+ 			break;
+ 		case T_WithClause:
+ 			retval = _compareWithClause(a, b);
+ 			break;
+ 		case T_CommonTableExpr:
+ 			retval = _compareCommonTableExpr(a, b);
+ 			break;
+ 		case T_PrivGrantee:
+ 			retval = _comparePrivGrantee(a, b);
+ 			break;
+ 		case T_FuncWithArgs:
+ 			retval = _compareFuncWithArgs(a, b);
+ 			break;
+ 		case T_AccessPriv:
+ 			retval = _compareAccessPriv(a, b);
+ 			break;
+ 		case T_XmlSerialize:
+ 			retval = _compareXmlSerialize(a, b);
+ 			break;
+ 
+ 		default:
+ 			elog(ERROR, "unrecognized node type: %d",
+ 				 (int) nodeTag(a));
+ 			retval = 0;		/* keep compiler quiet */
+ 			break;
+ 	}
+ 
+ 	return retval;
+ }
diff -dcrpN postgresql.orig/src/backend/nodes/Makefile postgresql/src/backend/nodes/Makefile
*** postgresql.orig/src/backend/nodes/Makefile	2010-09-21 13:49:56.000000000 +0200
--- postgresql/src/backend/nodes/Makefile	2010-10-19 10:50:12.000000000 +0200
*************** subdir = src/backend/nodes
*** 12,19 ****
  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 \
         outfuncs.o readfuncs.o print.o read.o params.o value.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 12,19 ----
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = nodeFuncs.o nodes.o list.o tree.o bitmapset.o tidbitmap.o \
!        comparefuncs.o copyfuncs.o equalfuncs.o makefuncs.o \
         outfuncs.o readfuncs.o print.o read.o params.o value.o
  
  include $(top_srcdir)/src/backend/common.mk
diff -dcrpN postgresql.orig/src/backend/nodes/outfuncs.c postgresql/src/backend/nodes/outfuncs.c
*** postgresql.orig/src/backend/nodes/outfuncs.c	2010-10-15 10:31:47.000000000 +0200
--- postgresql/src/backend/nodes/outfuncs.c	2010-10-19 10:47:03.000000000 +0200
*************** _outList(StringInfo str, List *node)
*** 175,180 ****
--- 175,197 ----
  	appendStringInfoChar(str, ')');
  }
  
+ static void
+ _outTree(StringInfo str, Tree *node)
+ {
+ 	TreeCell   *tc;
+ 	ListCell   *lc;
+ 
+ 	appendStringInfoChar(str, '(');
+ 
+ 	tforeach(tc, lc, node)
+ 	{
+ 		Node	   *node = lfirst(lc);
+ 		_outNode(str, node);
+ 	}
+ 
+ 	appendStringInfoChar(str, ')');
+ }
+ 
  /*
   * _outBitmapset -
   *	   converts a bitmap set of integers
*************** _outPlannerInfo(StringInfo str, PlannerI
*** 1594,1601 ****
  	WRITE_NODE_FIELD(resultRelations);
  	WRITE_NODE_FIELD(init_plans);
  	WRITE_NODE_FIELD(cte_plan_ids);
! 	WRITE_NODE_FIELD(eq_classes);
! 	WRITE_NODE_FIELD(canon_pathkeys);
  	WRITE_NODE_FIELD(left_join_clauses);
  	WRITE_NODE_FIELD(right_join_clauses);
  	WRITE_NODE_FIELD(full_join_clauses);
--- 1611,1618 ----
  	WRITE_NODE_FIELD(resultRelations);
  	WRITE_NODE_FIELD(init_plans);
  	WRITE_NODE_FIELD(cte_plan_ids);
! 	WRITE_NODE_FIELD(rb_eq_classes);
! 	WRITE_NODE_FIELD(rb_canon_pathkeys);
  	WRITE_NODE_FIELD(left_join_clauses);
  	WRITE_NODE_FIELD(right_join_clauses);
  	WRITE_NODE_FIELD(full_join_clauses);
*************** _outNode(StringInfo str, void *obj)
*** 2506,2511 ****
--- 2523,2530 ----
  		appendStringInfo(str, "<>");
  	else if (IsA(obj, List) ||IsA(obj, IntList) || IsA(obj, OidList))
  		_outList(str, obj);
+ 	else if (IsA(obj, Tree))
+ 		_outTree(str, obj);
  	else if (IsA(obj, Integer) ||
  			 IsA(obj, Float) ||
  			 IsA(obj, String) ||
diff -dcrpN postgresql.orig/src/backend/nodes/tree.c postgresql/src/backend/nodes/tree.c
*** postgresql.orig/src/backend/nodes/tree.c	1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/backend/nodes/tree.c	2010-10-19 11:58:52.000000000 +0200
***************
*** 0 ****
--- 1,223 ----
+ /*-------------------------------------------------------------------------
+  *
+  * tree.c
+  *	  implementation for PostgreSQL generic rbtree package
+  *
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  $PostgreSQL: pgsql/src/backend/nodes/list.c,v 1.74 2010/02/13 02:34:11 tgl Exp $
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "nodes/pg_tree.h"
+ #include "utils/rbtree.h"
+ 
+ 
+ /*
+  * RBTree allocfunc function
+  *
+  * Allocate memory in the MemoryContext given to new_tree().
+  */
+ static RBNode *
+ tree_allocfunc(void *arg)
+ {
+ 	MemoryContext	context = arg;
+ 	MemoryContext	oldcontext;
+ 	RBNode	   *node;
+ 
+ 	oldcontext = MemoryContextSwitchTo(context);
+ 
+ 	node = palloc0(sizeof(TreeCell));
+ 
+ 	MemoryContextSwitchTo(oldcontext);
+ 
+ 	return node;
+ }
+ 
+ 
+ /*
+  * RBTree combiner function
+  *
+  * Because we store lists of Node pointers, we simply concatenate
+  * the lists together. Do this in the MemoryContext given to new_tree().
+  */
+ static void
+ tree_combiner(RBNode *existing, const RBNode *newdata, void *arg)
+ {
+ 	MemoryContext	context = arg;
+ 	MemoryContext	oldcontext;
+ 	TreeCell   *tc1 = (TreeCell *)existing;
+ 	TreeCell   *tc2 = (TreeCell *)newdata;
+ 
+ 	oldcontext = MemoryContextSwitchTo(context);
+ 
+ 	tc1->list = list_concat(tc1->list, tc2->list);
+ 
+ 	MemoryContextSwitchTo(oldcontext);
+ }
+ 
+ 
+ /*
+  * RBTree freefunc function.
+  *
+  * We must not do list_free(((TreeCell *)x)->list) because some code
+  * may still reference it. The RBNode itself can be freed.
+  */
+ static void
+ tree_freefunc(RBNode *x, void *arg)
+ {
+ 	pfree(x);
+ }
+ 
+ /*
+  * new_tree
+  *
+  * Return a freshly allocated Tree.
+  *
+  * Parameters:
+  *	comparator	- comparator function for RBTree
+  *	context		- MemoryContext to allocate the tree, its nodes and
+  *			  the list elements.
+  */
+ Tree *
+ new_tree(rb_comparator comparator, MemoryContext context)
+ {
+ 	MemoryContext	oldcontext;
+ 	Tree	   *tree;
+ 
+ 	Assert((context != NULL));
+ 
+ 	oldcontext = MemoryContextSwitchTo(context);
+ 
+ 	tree = makeNode(Tree);
+ 	tree->n_elems = 0;
+ 	tree->context = context;
+ 	tree->tree = rb_create(sizeof(TreeCell), comparator, tree_combiner, tree_allocfunc, tree_freefunc, context);
+ 
+ 	MemoryContextSwitchTo(oldcontext);
+ 
+ 	return tree;
+ }
+ 
+ /*
+  * tree_find
+  *
+  * Find the element(s) that match the node's key according to
+  * the comparator
+  */
+ List *
+ tree_find(Tree *tree, Node *node)
+ {
+ 	MemoryContext	oldcontext;
+ 	TreeCell   *cell;
+ 	TreeCell   *result;
+ 
+ 	oldcontext = MemoryContextSwitchTo(tree->context);
+ 	cell = palloc0(sizeof(TreeCell));
+ 	cell->list = list_make1(node);
+ 	MemoryContextSwitchTo(oldcontext);
+ 
+ 	result = (TreeCell *)rb_find(tree->tree, (RBNode *)cell);
+ 
+ 	list_free(cell->list);
+ 	pfree(cell);
+ 
+ 	if (result)
+ 		return result->list;
+ 	else
+ 		return NULL;
+ }
+ 
+ /*
+  * tree_add
+  *
+  * Add a Node to the tree.
+  */
+ void
+ tree_add(Tree *tree, Node *node)
+ {
+ 	TreeCell   *cell;
+ 	bool		isNew;
+ 	MemoryContext	oldcontext;
+ 
+ 	if (node == NULL)
+ 		return;
+ 
+ 	oldcontext = MemoryContextSwitchTo(tree->context);
+ 	cell = palloc0(sizeof(TreeCell));
+ 	cell->list = list_make1(node);
+ 	MemoryContextSwitchTo(oldcontext);
+ 
+ 	rb_insert(tree->tree, (RBNode *)cell, &isNew);
+ 	tree->n_elems++;
+ }
+ 
+ /*
+  * tree_add_list
+  *
+  * Add a list of Nodes to the tree.
+  */
+ void
+ tree_add_list(Tree *tree, List *list)
+ {
+ 	TreeCell   *cell;
+ 	bool		isNew;
+ 	MemoryContext	oldcontext;
+ 
+ 	if (list_length(list) == 0)
+ 		return;
+ 
+ 	oldcontext = MemoryContextSwitchTo(tree->context);
+ 	cell = palloc0(sizeof(TreeCell));
+ 	cell->list = list;
+ 	MemoryContextSwitchTo(oldcontext);
+ 
+ 	rb_insert(tree->tree, (RBNode *)cell, &isNew);
+ 	tree->n_elems += list_length(list);
+ }
+ 
+ 
+ /*
+  * tree_delete_ptr
+  *
+  * Delete a Node from the tree. Use the pointer itself
+  * for comparison with list elements.
+  */
+ void
+ tree_delete_ptr(Tree *tree, Node *node)
+ {
+ 	MemoryContext	oldcontext;
+ 	TreeCell   *cell = palloc(sizeof(TreeCell));
+ 	TreeCell   *result;
+ 	List	   *list;
+ 
+ 	/*
+ 	 * First, find the Node in the tree. rb_delete() only works on
+ 	 * RBNodes * that are actually in the tree, we have to use the
+ 	 * pointer rb_find() returns.
+ 	 */
+ 	oldcontext = MemoryContextSwitchTo(tree->context);
+ 	cell->list = list_make1(node);
+ 	MemoryContextSwitchTo(oldcontext);
+ 
+ 	result = (TreeCell *)rb_find(tree->tree, (RBNode *)cell);
+ 
+ 	if (result)
+ 	{
+ 		list = result->list;
+ 
+ 		rb_delete(tree->tree, (RBNode *)result);
+ 
+ 		tree->n_elems -= list_length(list);
+ 
+ 		list = list_delete_ptr(list, node);
+ 
+ 		tree_add_list(tree, list);
+ 	}
+ }
diff -dcrpN postgresql.orig/src/backend/optimizer/geqo/geqo_pool.c postgresql/src/backend/optimizer/geqo/geqo_pool.c
*** postgresql.orig/src/backend/optimizer/geqo/geqo_pool.c	2010-09-21 13:49:57.000000000 +0200
--- postgresql/src/backend/optimizer/geqo/geqo_pool.c	2010-10-19 11:02:57.000000000 +0200
***************
*** 32,38 ****
  #include "optimizer/geqo_recombination.h"
  
  
! static int	compare(const void *arg1, const void *arg2);
  
  /*
   * alloc_pool
--- 32,38 ----
  #include "optimizer/geqo_recombination.h"
  
  
! static int	geqo_pool_compare(const void *arg1, const void *arg2);
  
  /*
   * alloc_pool
*************** random_init_pool(PlannerInfo *root, Pool
*** 110,124 ****
  void
  sort_pool(PlannerInfo *root, Pool *pool)
  {
! 	qsort(pool->data, pool->size, sizeof(Chromosome), compare);
  }
  
  /*
!  * compare
   *	 qsort comparison function for sort_pool
   */
  static int
! compare(const void *arg1, const void *arg2)
  {
  	const Chromosome *chromo1 = (const Chromosome *) arg1;
  	const Chromosome *chromo2 = (const Chromosome *) arg2;
--- 110,124 ----
  void
  sort_pool(PlannerInfo *root, Pool *pool)
  {
! 	qsort(pool->data, pool->size, sizeof(Chromosome), geqo_pool_compare);
  }
  
  /*
!  * geqo_pool_compare
   *	 qsort comparison function for sort_pool
   */
  static int
! geqo_pool_compare(const void *arg1, const void *arg2)
  {
  	const Chromosome *chromo1 = (const Chromosome *) arg1;
  	const Chromosome *chromo2 = (const Chromosome *) arg2;
diff -dcrpN postgresql.orig/src/backend/optimizer/path/equivclass.c postgresql/src/backend/optimizer/path/equivclass.c
*** postgresql.orig/src/backend/optimizer/path/equivclass.c	2010-10-15 10:31:47.000000000 +0200
--- postgresql/src/backend/optimizer/path/equivclass.c	2010-10-19 14:57:04.000000000 +0200
*************** static bool reconsider_full_join_clause(
*** 61,66 ****
--- 61,150 ----
  
  
  /*
+  * eq_comparator
+  *
+  * RBTree comparator function for quick search, used for root->rb_eq_classes.
+  */
+ int
+ eq_comparator(const RBNode *a, const RBNode *b, void *arg)
+ {
+ 	TreeCell	   *left = (TreeCell *)a;
+ 	TreeCell	   *right = (TreeCell *)b;
+ 	EquivalenceClass   *ec1 = (EquivalenceClass *) linitial(left->list);
+ 	EquivalenceClass   *ec2 = (EquivalenceClass *) linitial(right->list);
+ 	ListCell	   *lc1;
+ 	ListCell	   *lc2;
+ 	int		res, lt, gt;
+ 
+ 	if (ec1->ec_has_volatile < ec2->ec_has_volatile)
+ 		return -1;
+ 	else if (ec1->ec_has_volatile > ec2->ec_has_volatile)
+ 		return 1;
+ 
+ 	if (ec1->ec_sortref < ec2->ec_sortref)
+ 		return -1;
+ 	else if (ec1->ec_sortref > ec2->ec_sortref)
+ 		return 1;
+ 
+ 	res = compare(ec1->ec_opfamilies, ec2->ec_opfamilies);
+ 	if (res != 0)
+ 		return res;
+ 
+ 	if (ec1->ec_below_outer_join < ec2->ec_below_outer_join)
+ 		return -1;
+ 	else if (ec1->ec_below_outer_join > ec2->ec_below_outer_join)
+ 		return 1;
+ 
+ 	gt = lt = 0;
+ 
+ 	foreach (lc1, ec1->ec_members)
+ 	{
+ 		EquivalenceMember *em1 = lfirst(lc1);
+ 
+ 		foreach (lc2, ec2->ec_members)
+ 		{
+ 			EquivalenceMember *em2 = lfirst(lc2);
+ 
+ 			if (em1->em_is_const < em2->em_is_const)
+ 			{
+ 				lt++;
+ 				continue;
+ 			}
+ 			else if (em1->em_is_const > em2->em_is_const)
+ 			{
+ 				gt++;
+ 				continue;
+ 			}
+ 
+ 			if (em1->em_datatype < em2->em_datatype)
+ 			{
+ 				lt++;
+ 				continue;
+ 			}
+ 			else if (em1->em_datatype < em2->em_datatype)
+ 			{
+ 				gt++;
+ 				continue;
+ 			}
+ 
+ 			res = compare(em1->em_expr, em2->em_expr);
+ 			if (res == 0)
+ 				return 0;
+ 			else if (res < 0)
+ 				lt++;
+ 			else
+ 				gt++;
+ 		}
+ 	}
+ 
+ 	if (lt >= gt)
+ 		return -1;
+ 	else
+ 		return 1;
+ }
+ 
+ 
+ /*
   * process_equivalence
   *	  The given clause has a mergejoinable operator and can be applied without
   *	  any delay by an outer join, so its two sides can be considered equal
*************** process_equivalence(PlannerInfo *root, R
*** 104,109 ****
--- 188,194 ----
  			   *ec2;
  	EquivalenceMember *em1,
  			   *em2;
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
  
  	/* Extract info from given clause */
*************** process_equivalence(PlannerInfo *root, R
*** 171,177 ****
  	 */
  	ec1 = ec2 = NULL;
  	em1 = em2 = NULL;
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		ListCell   *lc2;
--- 256,262 ----
  	 */
  	ec1 = ec2 = NULL;
  	em1 = em2 = NULL;
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		ListCell   *lc2;
*************** process_equivalence(PlannerInfo *root, R
*** 250,255 ****
--- 335,343 ----
  		 * leave dangling pointers in existing PathKeys.  We leave it behind
  		 * with a link so that the merged EC can be found.
  		 */
+ 		tree_delete_ptr(root->rb_eq_classes, (Node *)ec1);
+ 		tree_delete_ptr(root->rb_eq_classes, (Node *)ec2);
+ 
  		ec1->ec_members = list_concat(ec1->ec_members, ec2->ec_members);
  		ec1->ec_sources = list_concat(ec1->ec_sources, ec2->ec_sources);
  		ec1->ec_derives = list_concat(ec1->ec_derives, ec2->ec_derives);
*************** process_equivalence(PlannerInfo *root, R
*** 258,264 ****
  		/* can't need to set has_volatile */
  		ec1->ec_below_outer_join |= ec2->ec_below_outer_join;
  		ec2->ec_merged = ec1;
- 		root->eq_classes = list_delete_ptr(root->eq_classes, ec2);
  		/* just to avoid debugging confusion w/ dangling pointers: */
  		ec2->ec_members = NIL;
  		ec2->ec_sources = NIL;
--- 346,351 ----
*************** process_equivalence(PlannerInfo *root, R
*** 266,271 ****
--- 353,359 ----
  		ec2->ec_relids = NULL;
  		ec1->ec_sources = lappend(ec1->ec_sources, restrictinfo);
  		ec1->ec_below_outer_join |= below_outer_join;
+ 		tree_add(root->rb_eq_classes, (Node *)ec1);
  		/* mark the RI as usable with this pair of EMs */
  		restrictinfo->left_em = em1;
  		restrictinfo->right_em = em2;
*************** process_equivalence(PlannerInfo *root, R
*** 273,281 ****
--- 361,371 ----
  	else if (ec1)
  	{
  		/* Case 3: add item2 to ec1 */
+ 		tree_delete_ptr(root->rb_eq_classes, (Node *)ec1);
  		em2 = add_eq_member(ec1, item2, item2_relids, false, item2_type);
  		ec1->ec_sources = lappend(ec1->ec_sources, restrictinfo);
  		ec1->ec_below_outer_join |= below_outer_join;
+ 		tree_add(root->rb_eq_classes, (Node *)ec1);
  		/* mark the RI as usable with this pair of EMs */
  		restrictinfo->left_em = em1;
  		restrictinfo->right_em = em2;
*************** process_equivalence(PlannerInfo *root, R
*** 283,291 ****
--- 373,383 ----
  	else if (ec2)
  	{
  		/* Case 3: add item1 to ec2 */
+ 		tree_delete_ptr(root->rb_eq_classes, (Node *)ec2);
  		em1 = add_eq_member(ec2, item1, item1_relids, false, item1_type);
  		ec2->ec_sources = lappend(ec2->ec_sources, restrictinfo);
  		ec2->ec_below_outer_join |= below_outer_join;
+ 		tree_add(root->rb_eq_classes, (Node *)ec2);
  		/* mark the RI as usable with this pair of EMs */
  		restrictinfo->left_em = em1;
  		restrictinfo->right_em = em2;
*************** process_equivalence(PlannerInfo *root, R
*** 309,315 ****
  		em1 = add_eq_member(ec, item1, item1_relids, false, item1_type);
  		em2 = add_eq_member(ec, item2, item2_relids, false, item2_type);
  
! 		root->eq_classes = lappend(root->eq_classes, ec);
  
  		/* mark the RI as usable with this pair of EMs */
  		restrictinfo->left_em = em1;
--- 401,407 ----
  		em1 = add_eq_member(ec, item1, item1_relids, false, item1_type);
  		em2 = add_eq_member(ec, item2, item2_relids, false, item2_type);
  
! 		tree_add(root->rb_eq_classes, (Node *)ec);
  
  		/* mark the RI as usable with this pair of EMs */
  		restrictinfo->left_em = em1;
*************** get_eclass_for_sort_expr(PlannerInfo *ro
*** 386,433 ****
  {
  	EquivalenceClass *newec;
  	EquivalenceMember *newem;
  	ListCell   *lc1;
  	MemoryContext oldcontext;
  
  	/*
! 	 * Scan through the existing EquivalenceClasses for a match
! 	 */
! 	foreach(lc1, root->eq_classes)
! 	{
! 		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
! 		ListCell   *lc2;
! 
! 		/*
! 		 * Never match to a volatile EC, except when we are looking at another
! 		 * reference to the same volatile SortGroupClause.
! 		 */
! 		if (cur_ec->ec_has_volatile &&
! 			(sortref == 0 || sortref != cur_ec->ec_sortref))
! 			continue;
! 
! 		if (!equal(opfamilies, cur_ec->ec_opfamilies))
! 			continue;
! 
! 		foreach(lc2, cur_ec->ec_members)
! 		{
! 			EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
! 
! 			/*
! 			 * If below an outer join, don't match constants: they're not as
! 			 * constant as they look.
! 			 */
! 			if (cur_ec->ec_below_outer_join &&
! 				cur_em->em_is_const)
! 				continue;
! 
! 			if (expr_datatype == cur_em->em_datatype &&
! 				equal(expr, cur_em->em_expr))
! 				return cur_ec;	/* Match! */
! 		}
! 	}
! 
! 	/*
! 	 * No match, so build a new single-member EC
  	 *
  	 * Here, we must be sure that we construct the EC in the right context. We
  	 * can assume, however, that the passed expr is long-lived.
--- 478,489 ----
  {
  	EquivalenceClass *newec;
  	EquivalenceMember *newem;
+ 	List	   *found;
  	ListCell   *lc1;
  	MemoryContext oldcontext;
  
  	/*
! 	 * Build a new single-member EC
  	 *
  	 * Here, we must be sure that we construct the EC in the right context. We
  	 * can assume, however, that the passed expr is long-lived.
*************** get_eclass_for_sort_expr(PlannerInfo *ro
*** 471,480 ****
  		}
  	}
  
- 	root->eq_classes = lappend(root->eq_classes, newec);
- 
  	MemoryContextSwitchTo(oldcontext);
  
  	return newec;
  }
  
--- 527,580 ----
  		}
  	}
  
  	MemoryContextSwitchTo(oldcontext);
  
+ 	found = tree_find(root->rb_eq_classes, (Node *)newec);
+ 
+ 	/*
+ 	 * Scan through the existing EquivalenceClasses for a match
+ 	 */
+ 	foreach(lc1, found)
+ 	{
+ 		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
+ 		ListCell   *lc2;
+ 
+ 		/*
+ 		 * Never match to a volatile EC, except when we are looking at another
+ 		 * reference to the same volatile SortGroupClause.
+ 		 */
+ 		if (cur_ec->ec_has_volatile &&
+ 			(sortref == 0 || sortref != cur_ec->ec_sortref))
+ 			continue;
+ 
+ 		if (!equal(opfamilies, cur_ec->ec_opfamilies))
+ 			continue;
+ 
+ 		foreach(lc2, cur_ec->ec_members)
+ 		{
+ 			EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
+ 
+ 			/*
+ 			 * If below an outer join, don't match constants: they're not as
+ 			 * constant as they look.
+ 			 */
+ 			if (cur_ec->ec_below_outer_join &&
+ 				cur_em->em_is_const)
+ 				continue;
+ 
+ 			if (expr_datatype == cur_em->em_datatype &&
+ 				equal(expr, cur_em->em_expr))
+ 			{
+ 				list_free(newec->ec_opfamilies);
+ 				list_free(newec->ec_members);
+ 				pfree(newec);
+ 				return cur_ec;	/* Match! */
+ 			}
+ 		}
+ 	}
+ 
+ 	tree_add(root->rb_eq_classes, (Node *)newec);
+ 
  	return newec;
  }
  
*************** get_eclass_for_sort_expr(PlannerInfo *ro
*** 530,539 ****
  void
  generate_base_implied_equalities(PlannerInfo *root)
  {
  	ListCell   *lc;
  	Index		rti;
  
! 	foreach(lc, root->eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc);
  
--- 630,642 ----
  void
  generate_base_implied_equalities(PlannerInfo *root)
  {
+ 	TreeCell   *tc;
  	ListCell   *lc;
  	Index		rti;
+ 	EquivalenceClass **classes = palloc(root->rb_eq_classes->n_elems * sizeof(EquivalenceClass *));
+ 	int		n_elems = 0, i;
  
! 	tforeach(tc, lc, root->rb_eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc);
  
*************** generate_base_implied_equalities(Planner
*** 544,549 ****
--- 647,661 ----
  		if (list_length(ec->ec_members) <= 1)
  			continue;
  
+ 		classes[n_elems++] = ec;
+ 	}
+ 
+ 	for (i = 0; i < n_elems; i++)
+ 	{
+ 		EquivalenceClass *ec = classes[i];
+ 
+ 		tree_delete_ptr(root->rb_eq_classes, (Node *)ec);
+ 
  		if (ec->ec_has_const)
  			generate_base_implied_equalities_const(root, ec);
  		else
*************** generate_base_implied_equalities(Planner
*** 552,559 ****
--- 664,675 ----
  		/* Recover if we failed to generate required derived clauses */
  		if (ec->ec_broken)
  			generate_base_implied_equalities_broken(root, ec);
+ 
+ 		tree_add(root->rb_eq_classes, (Node *)ec);
  	}
  
+ 	pfree(classes);
+ 
  	/*
  	 * This is also a handy place to mark base rels (which should all exist by
  	 * now) with flags showing whether they have pending eclass joins.
*************** generate_join_implied_equalities(Planner
*** 770,781 ****
  								 RelOptInfo *inner_rel)
  {
  	List	   *result = NIL;
  	ListCell   *lc;
  
! 	foreach(lc, root->eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc);
- 		List	   *sublist = NIL;
  
  		/* ECs containing consts do not need any further enforcement */
  		if (ec->ec_has_const)
--- 886,899 ----
  								 RelOptInfo *inner_rel)
  {
  	List	   *result = NIL;
+ 	TreeCell   *tc;
  	ListCell   *lc;
+ 	EquivalenceClass **classes = palloc(root->rb_eq_classes->n_elems * sizeof(EquivalenceClass *));
+ 	int		n_elems = 0, i;
  
! 	tforeach(tc, lc, root->rb_eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc);
  
  		/* ECs containing consts do not need any further enforcement */
  		if (ec->ec_has_const)
*************** generate_join_implied_equalities(Planner
*** 788,793 ****
--- 906,920 ----
  		/* We can quickly ignore any that don't overlap the join, too */
  		if (!bms_overlap(ec->ec_relids, joinrel->relids))
  			continue;
+ 		classes[n_elems++] = ec;
+ 	}
+ 
+ 	for (i = 0; i < n_elems; i++)
+ 	{
+ 		EquivalenceClass *ec = classes[i];
+ 		List	   *sublist = NIL;
+ 
+ 		tree_delete_ptr(root->rb_eq_classes, (Node *)ec);
  
  		if (!ec->ec_broken)
  			sublist = generate_join_implied_equalities_normal(root,
*************** generate_join_implied_equalities(Planner
*** 804,812 ****
--- 931,944 ----
  															  outer_rel,
  															  inner_rel);
  
+ 
+ 		tree_add(root->rb_eq_classes, (Node *)ec);
+ 
  		result = list_concat(result, sublist);
  	}
  
+ 	pfree(classes);
+ 
  	return result;
  }
  
*************** reconsider_outer_join_clause(PlannerInfo
*** 1310,1315 ****
--- 1442,1448 ----
  				right_type,
  				inner_datatype;
  	Relids		inner_relids;
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
  
  	Assert(is_opclause(rinfo->clause));
*************** reconsider_outer_join_clause(PlannerInfo
*** 1337,1343 ****
  	}
  
  	/* Scan EquivalenceClasses for a match to outervar */
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		bool		match;
--- 1470,1476 ----
  	}
  
  	/* Scan EquivalenceClasses for a match to outervar */
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		bool		match;
*************** reconsider_full_join_clause(PlannerInfo 
*** 1423,1428 ****
--- 1556,1562 ----
  				right_type;
  	Relids		left_relids,
  				right_relids;
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
  
  	/* Can't use an outerjoin_delayed clause here */
*************** reconsider_full_join_clause(PlannerInfo 
*** 1438,1444 ****
  	left_relids = rinfo->left_relids;
  	right_relids = rinfo->right_relids;
  
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		EquivalenceMember *coal_em = NULL;
--- 1572,1578 ----
  	left_relids = rinfo->left_relids;
  	right_relids = rinfo->right_relids;
  
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		EquivalenceMember *coal_em = NULL;
*************** reconsider_full_join_clause(PlannerInfo 
*** 1576,1584 ****
  bool
  exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2)
  {
  	ListCell   *lc1;
  
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc1);
  		bool		item1member = false;
--- 1710,1719 ----
  bool
  exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2)
  {
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
  
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc1);
  		bool		item1member = false;
*************** add_child_rel_equivalences(PlannerInfo *
*** 1623,1631 ****
  						   RelOptInfo *parent_rel,
  						   RelOptInfo *child_rel)
  {
  	ListCell   *lc1;
  
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		ListCell   *lc2;
--- 1758,1769 ----
  						   RelOptInfo *parent_rel,
  						   RelOptInfo *child_rel)
  {
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
+ 	EquivalenceClass **classes = palloc(root->rb_eq_classes->n_elems * sizeof(EquivalenceClass *));
+ 	int		n_elems = 0, i;
  
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		ListCell   *lc2;
*************** add_child_rel_equivalences(PlannerInfo *
*** 1652,1657 ****
--- 1790,1817 ----
  			/* Does it reference (only) parent_rel? */
  			if (bms_equal(cur_em->em_relids, parent_rel->relids))
  			{
+ 				/* Register it for later modification */
+ 				classes[n_elems++] = cur_ec;
+ 				goto cont_outer_loop;
+ 			}
+ 		}
+ cont_outer_loop:;
+ 	}
+ 
+ 	for (i = 0; i < n_elems; i++)
+ 	{
+ 		EquivalenceClass *cur_ec = classes[i];
+ 		ListCell   *lc2;
+ 
+ 		tree_delete_ptr(root->rb_eq_classes, (Node *)cur_ec);
+ 
+ 		foreach(lc2, cur_ec->ec_members)
+ 		{
+ 			EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
+ 
+ 			/* Does it reference (only) parent_rel? */
+ 			if (bms_equal(cur_em->em_relids, parent_rel->relids))
+ 			{
  				/* Yes, generate transformed child version */
  				Expr	   *child_expr;
  
*************** add_child_rel_equivalences(PlannerInfo *
*** 1662,1668 ****
--- 1822,1832 ----
  									 true, cur_em->em_datatype);
  			}
  		}
+ 
+ 		tree_add(root->rb_eq_classes, (Node *)cur_ec);
  	}
+ 
+ 	pfree(classes);
  }
  
  
*************** mutate_eclass_expressions(PlannerInfo *r
*** 1686,1698 ****
  						  Node *(*mutator) (),
  						  void *context)
  {
  	ListCell   *lc1;
  
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		ListCell   *lc2;
  
  		foreach(lc2, cur_ec->ec_members)
  		{
  			EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
--- 1850,1874 ----
  						  Node *(*mutator) (),
  						  void *context)
  {
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
+ 	EquivalenceClass **classes = palloc(root->rb_eq_classes->n_elems * sizeof(EquivalenceClass *));
+ 	int		n_elems = 0, i;
  
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
+ 
+ 		classes[n_elems++] = cur_ec;
+ 	}
+ 
+ 	for (i = 0; i < n_elems; i++)
+ 	{
+ 		EquivalenceClass *cur_ec = classes[i];
  		ListCell   *lc2;
  
+ 		tree_delete_ptr(root->rb_eq_classes, (Node *)cur_ec);
+ 
  		foreach(lc2, cur_ec->ec_members)
  		{
  			EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
*************** mutate_eclass_expressions(PlannerInfo *r
*** 1700,1706 ****
--- 1876,1886 ----
  			cur_em->em_expr = (Expr *)
  				mutator((Node *) cur_em->em_expr, context);
  		}
+ 
+ 		tree_add(root->rb_eq_classes, (Node *)cur_ec);
  	}
+ 
+ 	pfree(classes);
  }
  
  
*************** find_eclass_clauses_for_index_join(Plann
*** 1715,1723 ****
  {
  	List	   *result = NIL;
  	bool		is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
  	ListCell   *lc1;
  
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		ListCell   *lc2;
--- 1895,1904 ----
  {
  	List	   *result = NIL;
  	bool		is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
  
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  		ListCell   *lc2;
*************** bool
*** 1816,1824 ****
  have_relevant_eclass_joinclause(PlannerInfo *root,
  								RelOptInfo *rel1, RelOptInfo *rel2)
  {
  	ListCell   *lc1;
  
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc1);
  		bool		has_rel1;
--- 1997,2006 ----
  have_relevant_eclass_joinclause(PlannerInfo *root,
  								RelOptInfo *rel1, RelOptInfo *rel2)
  {
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
  
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc1);
  		bool		has_rel1;
*************** have_relevant_eclass_joinclause(PlannerI
*** 1890,1898 ****
  bool
  has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
  {
  	ListCell   *lc1;
  
! 	foreach(lc1, root->eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc1);
  		bool		has_rel1;
--- 2072,2081 ----
  bool
  has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
  {
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
  
! 	tforeach(tc1, lc1, root->rb_eq_classes)
  	{
  		EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc1);
  		bool		has_rel1;
diff -dcrpN postgresql.orig/src/backend/optimizer/path/indxpath.c postgresql/src/backend/optimizer/path/indxpath.c
*** postgresql.orig/src/backend/optimizer/path/indxpath.c	2010-09-21 13:49:57.000000000 +0200
--- postgresql/src/backend/optimizer/path/indxpath.c	2010-10-19 12:26:30.000000000 +0200
*************** indexable_outerrelids(PlannerInfo *root,
*** 1445,1450 ****
--- 1445,1451 ----
  {
  	Relids		outer_relids = NULL;
  	bool		is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
+ 	TreeCell   *tc1;
  	ListCell   *lc1;
  
  	/*
*************** indexable_outerrelids(PlannerInfo *root,
*** 1469,1475 ****
  	 */
  	if (rel->has_eclass_joins)
  	{
! 		foreach(lc1, root->eq_classes)
  		{
  			EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  			Relids		other_rels = NULL;
--- 1470,1476 ----
  	 */
  	if (rel->has_eclass_joins)
  	{
! 		tforeach(tc1, lc1, root->rb_eq_classes)
  		{
  			EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
  			Relids		other_rels = NULL;
diff -dcrpN postgresql.orig/src/backend/optimizer/path/pathkeys.c postgresql/src/backend/optimizer/path/pathkeys.c
*** postgresql.orig/src/backend/optimizer/path/pathkeys.c	2010-09-21 13:49:57.000000000 +0200
--- postgresql/src/backend/optimizer/path/pathkeys.c	2010-10-19 10:34:47.000000000 +0200
*************** makePathKey(EquivalenceClass *eclass, Oi
*** 71,76 ****
--- 71,117 ----
  	return pk;
  }
  
+ int
+ pathkeys_comparator(const RBNode *a, const RBNode *b, void *arg)
+ {
+ 	TreeCell   *left = (TreeCell *)a;
+ 	TreeCell   *right = (TreeCell *)b;
+ 	PathKey	   *pk_left = (PathKey *)linitial(left->list);
+ 	PathKey	   *pk_right = (PathKey *)linitial(right->list);
+ 
+ 	Assert((pk_left != NULL));
+ 	Assert((pk_right != NULL));
+ 
+ 	if (pk_left->pk_eclass < pk_right->pk_eclass)
+ 		return -1;
+ 	else if (pk_left->pk_eclass > pk_right->pk_eclass)
+ 		return 1;
+ 
+ 	if (pk_left->pk_opfamily < pk_right->pk_opfamily)
+ 		return -1;
+ 	else if (pk_left->pk_opfamily > pk_right->pk_opfamily)
+ 		return 1;
+ 
+ 	if (pk_left->pk_strategy < pk_right->pk_strategy)
+ 		return -1;
+ 	else if (pk_left->pk_strategy > pk_right->pk_strategy)
+ 		return 1;
+ 
+ 	if (pk_left->pk_nulls_first < pk_right->pk_nulls_first)
+ 		return -1;
+ 	else if (pk_left->pk_nulls_first > pk_right->pk_nulls_first)
+ 		return 1;
+ 
+ 	if (pk_left == NULL)
+ 		elog(ERROR, "pk_left NULL");
+ 	if (pk_right == NULL)
+ 		elog(ERROR, "pk_right NULL");
+ 
+ 	return 0;
+ }
+ 
+ 
+ 
  /*
   * make_canonical_pathkey
   *	  Given the parameters for a PathKey, find any pre-existing matching
*************** make_canonical_pathkey(PlannerInfo *root
*** 85,119 ****
  					   EquivalenceClass *eclass, Oid opfamily,
  					   int strategy, bool nulls_first)
  {
! 	PathKey    *pk;
! 	ListCell   *lc;
  	MemoryContext oldcontext;
  
  	/* The passed eclass might be non-canonical, so chase up to the top */
  	while (eclass->ec_merged)
  		eclass = eclass->ec_merged;
  
- 	foreach(lc, root->canon_pathkeys)
- 	{
- 		pk = (PathKey *) lfirst(lc);
- 		if (eclass == pk->pk_eclass &&
- 			opfamily == pk->pk_opfamily &&
- 			strategy == pk->pk_strategy &&
- 			nulls_first == pk->pk_nulls_first)
- 			return pk;
- 	}
- 
  	/*
  	 * Be sure canonical pathkeys are allocated in the main planning context.
  	 * Not an issue in normal planning, but it is for GEQO.
  	 */
  	oldcontext = MemoryContextSwitchTo(root->planner_cxt);
  
! 	pk = makePathKey(eclass, opfamily, strategy, nulls_first);
! 	root->canon_pathkeys = lappend(root->canon_pathkeys, pk);
  
  	MemoryContextSwitchTo(oldcontext);
  
  	return pk;
  }
  
--- 126,162 ----
  					   EquivalenceClass *eclass, Oid opfamily,
  					   int strategy, bool nulls_first)
  {
! 	PathKey    *pk, *pk_new;
! 	List	   *list;
  	MemoryContext oldcontext;
  
  	/* The passed eclass might be non-canonical, so chase up to the top */
  	while (eclass->ec_merged)
  		eclass = eclass->ec_merged;
  
  	/*
  	 * Be sure canonical pathkeys are allocated in the main planning context.
  	 * Not an issue in normal planning, but it is for GEQO.
  	 */
  	oldcontext = MemoryContextSwitchTo(root->planner_cxt);
  
! 	pk_new = makePathKey(eclass, opfamily, strategy, nulls_first);
  
  	MemoryContextSwitchTo(oldcontext);
  
+ 	list = tree_find(root->rb_canon_pathkeys, (Node *)pk_new);
+ 
+ 	if (list)
+ 	{
+ 		pfree(pk_new);
+ 		pk = (PathKey *) linitial(list);
+ 	}
+ 	else
+ 	{
+ 		tree_add(root->rb_canon_pathkeys, (Node *)pk_new);
+ 		pk = pk_new;
+ 	}
+ 
  	return pk;
  }
  
diff -dcrpN postgresql.orig/src/backend/optimizer/plan/planmain.c postgresql/src/backend/optimizer/plan/planmain.c
*** postgresql.orig/src/backend/optimizer/plan/planmain.c	2010-10-08 11:04:23.000000000 +0200
--- postgresql/src/backend/optimizer/plan/planmain.c	2010-10-19 10:44:53.000000000 +0200
***************
*** 21,32 ****
--- 21,34 ----
  #include "postgres.h"
  
  #include "miscadmin.h"
+ #include "nodes/pg_tree.h"
  #include "optimizer/cost.h"
  #include "optimizer/pathnode.h"
  #include "optimizer/paths.h"
  #include "optimizer/placeholder.h"
  #include "optimizer/planmain.h"
  #include "optimizer/tlist.h"
+ #include "utils/rbtree.h"
  #include "utils/selfuncs.h"
  
  
*************** query_planner(PlannerInfo *root, List *t
*** 117,123 ****
  		 * We still are required to canonicalize any pathkeys, in case it's
  		 * something like "SELECT 2+2 ORDER BY 1".
  		 */
! 		root->canon_pathkeys = NIL;
  		root->query_pathkeys = canonicalize_pathkeys(root,
  													 root->query_pathkeys);
  		root->group_pathkeys = canonicalize_pathkeys(root,
--- 119,128 ----
  		 * We still are required to canonicalize any pathkeys, in case it's
  		 * something like "SELECT 2+2 ORDER BY 1".
  		 */
! 		if (root->rb_eq_classes == NULL)
! 			root->rb_eq_classes = new_tree(eq_comparator, root->planner_cxt);
! 		if (root->rb_canon_pathkeys == NULL)
! 			root->rb_canon_pathkeys = new_tree(pathkeys_comparator, root->planner_cxt);
  		root->query_pathkeys = canonicalize_pathkeys(root,
  													 root->query_pathkeys);
  		root->group_pathkeys = canonicalize_pathkeys(root,
*************** query_planner(PlannerInfo *root, List *t
*** 136,142 ****
  	 * for "simple" rels.
  	 *
  	 * NOTE: append_rel_list was set up by subquery_planner, so do not touch
! 	 * here; eq_classes may contain data already, too.
  	 */
  	root->simple_rel_array_size = list_length(parse->rtable) + 1;
  	root->simple_rel_array = (RelOptInfo **)
--- 141,147 ----
  	 * for "simple" rels.
  	 *
  	 * NOTE: append_rel_list was set up by subquery_planner, so do not touch
! 	 * here; rb_eq_classes may contain data already, too.
  	 */
  	root->simple_rel_array_size = list_length(parse->rtable) + 1;
  	root->simple_rel_array = (RelOptInfo **)
*************** query_planner(PlannerInfo *root, List *t
*** 145,151 ****
  	root->join_rel_hash = NULL;
  	root->join_rel_level = NULL;
  	root->join_cur_level = 0;
! 	root->canon_pathkeys = NIL;
  	root->left_join_clauses = NIL;
  	root->right_join_clauses = NIL;
  	root->full_join_clauses = NIL;
--- 150,159 ----
  	root->join_rel_hash = NULL;
  	root->join_rel_level = NULL;
  	root->join_cur_level = 0;
! 	if (root->rb_eq_classes == NULL)
! 		root->rb_eq_classes == new_tree(eq_comparator, root->planner_cxt);
! 	if (root->rb_canon_pathkeys == NULL)
! 		root->rb_canon_pathkeys = new_tree(pathkeys_comparator, root->planner_cxt);
  	root->left_join_clauses = NIL;
  	root->right_join_clauses = NIL;
  	root->full_join_clauses = NIL;
diff -dcrpN postgresql.orig/src/backend/optimizer/plan/planner.c postgresql/src/backend/optimizer/plan/planner.c
*** postgresql.orig/src/backend/optimizer/plan/planner.c	2010-10-08 11:04:23.000000000 +0200
--- postgresql/src/backend/optimizer/plan/planner.c	2010-10-19 10:46:35.000000000 +0200
*************** subquery_planner(PlannerGlobal *glob, Qu
*** 305,311 ****
  	root->planner_cxt = CurrentMemoryContext;
  	root->init_plans = NIL;
  	root->cte_plan_ids = NIL;
! 	root->eq_classes = NIL;
  	root->append_rel_list = NIL;
  	root->rowMarks = NIL;
  	root->hasInheritedTarget = false;
--- 305,312 ----
  	root->planner_cxt = CurrentMemoryContext;
  	root->init_plans = NIL;
  	root->cte_plan_ids = NIL;
! 	root->rb_eq_classes = new_tree(eq_comparator, root->planner_cxt);
! 	root->rb_canon_pathkeys = new_tree(pathkeys_comparator, root->planner_cxt);
  	root->append_rel_list = NIL;
  	root->rowMarks = NIL;
  	root->hasInheritedTarget = false;
diff -dcrpN postgresql.orig/src/backend/optimizer/prep/prepjointree.c postgresql/src/backend/optimizer/prep/prepjointree.c
*** postgresql.orig/src/backend/optimizer/prep/prepjointree.c	2010-09-21 13:49:57.000000000 +0200
--- postgresql/src/backend/optimizer/prep/prepjointree.c	2010-10-19 12:29:30.000000000 +0200
***************
*** 27,32 ****
--- 27,33 ----
  #include "nodes/nodeFuncs.h"
  #include "optimizer/clauses.h"
  #include "optimizer/placeholder.h"
+ #include "optimizer/paths.h"
  #include "optimizer/prep.h"
  #include "optimizer/subselect.h"
  #include "optimizer/tlist.h"
*************** pull_up_simple_subquery(PlannerInfo *roo
*** 626,632 ****
  	subroot->planner_cxt = CurrentMemoryContext;
  	subroot->init_plans = NIL;
  	subroot->cte_plan_ids = NIL;
! 	subroot->eq_classes = NIL;
  	subroot->append_rel_list = NIL;
  	subroot->rowMarks = NIL;
  	subroot->hasRecursion = false;
--- 627,634 ----
  	subroot->planner_cxt = CurrentMemoryContext;
  	subroot->init_plans = NIL;
  	subroot->cte_plan_ids = NIL;
! 	subroot->rb_eq_classes = new_tree(eq_comparator, subroot->planner_cxt);
! 	subroot->rb_canon_pathkeys = new_tree(pathkeys_comparator, subroot->planner_cxt);
  	subroot->append_rel_list = NIL;
  	subroot->rowMarks = NIL;
  	subroot->hasRecursion = false;
diff -dcrpN postgresql.orig/src/backend/utils/adt/datum.c postgresql/src/backend/utils/adt/datum.c
*** postgresql.orig/src/backend/utils/adt/datum.c	2010-09-21 13:49:57.000000000 +0200
--- postgresql/src/backend/utils/adt/datum.c	2010-10-19 10:54:09.000000000 +0200
*************** datumIsEqual(Datum value1, Datum value2,
*** 206,208 ****
--- 206,258 ----
  	}
  	return res;
  }
+ 
+ /*-------------------------------------------------------------------------
+  * datumCompare
+  *
+  * Return -1/0/1 for less than/equal/greater than for two datums of the same type.
+  * This is for supporting RBTree search, not a logical comparison.
+  * The same NOTE applies as above in datumIsEqual.
+  *-------------------------------------------------------------------------
+  */
+ int
+ datumCompare(Datum value1, Datum value2, bool typByVal, int typLen)
+ {
+ 	if (typByVal)
+ 	{
+ 		/*
+ 		 * just compare the two datums. NOTE: just comparing "len" bytes will
+ 		 * not do the work, because we do not know how these bytes are aligned
+ 		 * inside the "Datum".	We assume instead that any given datatype is
+ 		 * consistent about how it fills extraneous bits in the Datum.
+ 		 */
+ 		if (value1 < value2)
+ 			return -1;
+ 		else if (value1 > value2)
+ 			return 1;
+ 		else
+ 			return 0;
+ 	}
+ 	else
+ 	{
+ 		Size		size1,
+ 					size2;
+ 		char	   *s1,
+ 				   *s2;
+ 
+ 		/*
+ 		 * Compare the bytes pointed by the pointers stored in the datums.
+ 		 * Do this only for datums of equal length to speed up the decision
+ 		 * of inequality.
+ 		 */
+ 		size1 = datumGetSize(value1, typByVal, typLen);
+ 		size2 = datumGetSize(value2, typByVal, typLen);
+ 		if (size1 < size2)
+ 			return -1;
+ 		else if (size1 > size2)
+ 			return 1;
+ 		s1 = (char *) DatumGetPointer(value1);
+ 		s2 = (char *) DatumGetPointer(value2);
+ 		return memcmp(s1, s2, size1);
+ 	}
+ }
diff -dcrpN postgresql.orig/src/include/nodes/bitmapset.h postgresql/src/include/nodes/bitmapset.h
*** postgresql.orig/src/include/nodes/bitmapset.h	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/include/nodes/bitmapset.h	2010-10-19 10:55:08.000000000 +0200
*************** typedef enum
*** 51,56 ****
--- 51,57 ----
  
  extern Bitmapset *bms_copy(const Bitmapset *a);
  extern bool bms_equal(const Bitmapset *a, const Bitmapset *b);
+ extern int bms_compare(const Bitmapset *a, const Bitmapset *b);
  extern Bitmapset *bms_make_singleton(int x);
  extern void bms_free(Bitmapset *a);
  
diff -dcrpN postgresql.orig/src/include/nodes/nodes.h postgresql/src/include/nodes/nodes.h
*** postgresql.orig/src/include/nodes/nodes.h	2010-10-15 10:31:47.000000000 +0200
--- postgresql/src/include/nodes/nodes.h	2010-10-19 10:51:24.000000000 +0200
*************** typedef enum NodeTag
*** 256,261 ****
--- 256,266 ----
  	T_OidList,
  
  	/*
+ 	 * TAGS FOR TREE NODES (pg_tree.h)
+ 	 */
+ 	T_Tree,
+ 
+ 	/*
  	 * TAGS FOR STATEMENT NODES (mostly in parsenodes.h)
  	 */
  	T_Query = 700,
*************** extern void *copyObject(void *obj);
*** 489,494 ****
--- 494,504 ----
   */
  extern bool equal(void *a, void *b);
  
+ /*
+  * nodes/comparefuncs.c
+  */
+ extern int compare(void *a, void *b);
+ 
  
  /*
   * Typedefs for identifying qualifier selectivities and plan costs as such.
diff -dcrpN postgresql.orig/src/include/nodes/pg_tree.h postgresql/src/include/nodes/pg_tree.h
*** postgresql.orig/src/include/nodes/pg_tree.h	1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/include/nodes/pg_tree.h	2010-10-19 11:50:31.000000000 +0200
***************
*** 0 ****
--- 1,60 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_tree.h
+  *	  interface for PostgreSQL generic rbtree package
+  *
+  * This package implements rbtree of Node * elements of the same type.
+  * It is a replacement of List for dealing with O(n^2) behaviour
+  * found with long lists.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef PG_TREE_H
+ #define PG_TREE_H
+ 
+ #include "nodes/nodes.h"
+ #include "nodes/pg_list.h"
+ #include "utils/rbtree.h"
+ 
+ typedef struct TreeCell
+ {
+ 	RBNode		treenode;	/* base RBTree node, required by the rbtree.c code */
+ 	List	   *list;		/* multiple elements with the same key can be stored */
+ } TreeCell;
+ 
+ typedef struct Tree
+ {
+ 	NodeTag		type;		/* T_Tree */
+ 	int32		n_elems;	/* current number of stored elements */
+ 	MemoryContext	context;	/* context to allocate nodes and list elements in */
+ 	RBTree	   *tree;
+ } Tree;
+ 
+ 
+ extern Tree *new_tree(rb_comparator comparator, MemoryContext context);
+ extern List *tree_find(Tree *tree, Node *node);
+ extern void tree_add(Tree *tree, Node *node);
+ extern void tree_add_list(Tree *tree, List *list);
+ extern void tree_delete_ptr(Tree *tree, Node *node);
+ 
+ 
+ /*
+  * tforeach -
+  *	a convenience macro which loops through the tree elements
+  *	in "inorder" walk to make it look like a list
+  *
+  * WARNING WARNING WARNING
+  *
+  * Only one walk of the tree can be active at a time, it's the
+  * limitation of the current backend/utils/misc/rbtree.c code.
+  */
+ #define tforeach(tc, lc, t)	\
+ 	for (rb_begin_iterate(t->tree, LeftRightWalk) , (tc) = (TreeCell *)rb_iterate(t->tree); (tc); (tc) = (TreeCell *)rb_iterate(t->tree)) \
+ 	foreach (lc, tc->list)
+ 
+ #endif   /* PG_TREE_H */
diff -dcrpN postgresql.orig/src/include/nodes/primnodes.h postgresql/src/include/nodes/primnodes.h
*** postgresql.orig/src/include/nodes/primnodes.h	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/include/nodes/primnodes.h	2010-10-18 13:07:22.000000000 +0200
***************
*** 19,24 ****
--- 19,25 ----
  
  #include "access/attnum.h"
  #include "nodes/pg_list.h"
+ #include "nodes/pg_tree.h"
  
  
  /* ----------------------------------------------------------------
diff -dcrpN postgresql.orig/src/include/nodes/relation.h postgresql/src/include/nodes/relation.h
*** postgresql.orig/src/include/nodes/relation.h	2010-10-15 10:31:47.000000000 +0200
--- postgresql/src/include/nodes/relation.h	2010-10-19 10:40:22.000000000 +0200
*************** typedef struct PlannerInfo
*** 158,166 ****
  
  	List	   *cte_plan_ids;	/* per-CTE-item list of subplan IDs */
  
! 	List	   *eq_classes;		/* list of active EquivalenceClasses */
  
! 	List	   *canon_pathkeys; /* list of "canonical" PathKeys */
  
  	List	   *left_join_clauses;		/* list of RestrictInfos for
  										 * mergejoinable outer join clauses
--- 158,166 ----
  
  	List	   *cte_plan_ids;	/* per-CTE-item list of subplan IDs */
  
! 	Tree	   *rb_eq_classes;	/* tree of active EquivalenceClasses */
  
! 	Tree	   *rb_canon_pathkeys;	/* tree of "canonical" PathKeys */
  
  	List	   *left_join_clauses;		/* list of RestrictInfos for
  										 * mergejoinable outer join clauses
diff -dcrpN postgresql.orig/src/include/optimizer/paths.h postgresql/src/include/optimizer/paths.h
*** postgresql.orig/src/include/optimizer/paths.h	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/include/optimizer/paths.h	2010-10-19 10:45:56.000000000 +0200
***************
*** 15,20 ****
--- 15,21 ----
  #define PATHS_H
  
  #include "nodes/relation.h"
+ #include "utils/rbtree.h"
  
  
  /*
*************** extern bool have_join_order_restriction(
*** 109,114 ****
--- 110,117 ----
   * equivclass.c
   *	  routines for managing EquivalenceClasses
   */
+ extern int eq_comparator(const RBNode *a, const RBNode *b, void *arg);
+ 
  extern bool process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
  					bool below_outer_join);
  extern void reconsider_outer_join_clauses(PlannerInfo *root);
*************** typedef enum
*** 152,157 ****
--- 155,162 ----
  	PATHKEYS_DIFFERENT			/* neither pathkey includes the other */
  } PathKeysComparison;
  
+ extern int pathkeys_comparator(const RBNode *a, const RBNode *b, void *arg);
+ 
  extern List *canonicalize_pathkeys(PlannerInfo *root, List *pathkeys);
  extern PathKeysComparison compare_pathkeys(List *keys1, List *keys2);
  extern bool pathkeys_contained_in(List *keys1, List *keys2);
diff -dcrpN postgresql.orig/src/include/utils/datum.h postgresql/src/include/utils/datum.h
*** postgresql.orig/src/include/utils/datum.h	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/include/utils/datum.h	2010-10-19 10:53:03.000000000 +0200
*************** extern void datumFree(Datum value, bool 
*** 46,49 ****
--- 46,58 ----
  extern bool datumIsEqual(Datum value1, Datum value2,
  			 bool typByVal, int typLen);
  
+ /*
+  * datumCompare
+  * return -1/0/+1 if for less/equal/greater than for two datums of the same type.
+  *
+  * XXX : See comments in the code for restrictions!
+  */
+ extern int datumCompare(Datum value1, Datum value2,
+ 			 bool typByVal, int typLen);
+ 
  #endif   /* DATUM_H */
