Mostly Harmless: Welcoming our C++ friends

Started by Kurt Harrimanabout 17 years ago48 messages
#1Kurt Harriman
harriman@acm.org
4 attachment(s)

Hi,

Sometimes people would like to call C++ code in the PostgreSQL
backend environment... for example, in user-defined functions,
triggers, access methods. And there is sometimes a need for
C++ code to call back into PostgreSQL's C functions, such as
the SPI interface. Many useful software packages and
libraries are written in C++.

The attached series of 4 patches is meant to provide a minimal
level of support for C++ aficionados to easily compile and link
with the PostgreSQL backend. No new interfaces or wrappers are
provided. The goal is merely to make the backend a friendlier
place for developing extensions involving C++, with minimal
impact on the existing C code.

The proposed change is divided into 4 patches with the hope
that each will be simple and easy to review. They can be
reviewed and discussed independently, and I hope some or
all may be judged benign enough to be taken up into 8.5 or
earlier.

The patches are described in more detail below. They are:

1. c++reserved -- changes a few field and parameter
names which happened to be C++ reserved words

2. c++bookends -- adds C linkage declarations to a
few header files

3. c++configure -- adds C++ support to 'configure',
'make', and 'pg_config'. A new configure option
--enable-cplusplus links the C++ runtime library
in to the postgres backend.

4. c++exception -- converts unhandled C++ exceptions to
PostgreSQL elog(FATAL) errors

Regards,
... kurt

These patches are based on CVS head in which the latest commit was
user: petere
date: Thu Dec 04 17:51:28 2008 +0000
summary: Default values for function arguments

1. c++reserved

User-defined functions and extensions may need to access
backend data structures such as parse trees. A few of the
relevant header files contain field or parameter names
which happen to be C++ reserved words. This makes them
unusable from C++ because the compiler chokes on the
reserved word. It has been suggested that the C++ user
could surround these #includes with #defines to substitute
innocuous words for the reserved words; but that would be
unbearably kludgy, error prone and unmaintainable. A polite
host does not demand such things of a guest.

Fortunately, there are not many instances which are likely
to be encountered by our C++ guests, and these can easily
be changed. In memnodes.h, parsenodes.h, and primnodes.h,
this patch changes the following field names:

typename => typeName
typeid => typeOid
using => usingClause
delete => delete_context

Also, the patch changes a few parameter names in function
prototypes in makefuncs.h, parse_type.h, and builtins.h:

typename => typeName
typeid => typeOid
namespace => qualifier

There's no need to ask PostgreSQL developers to remember to
avoid C++ reserved words, because C++ users who are affected
by such occurrences can be asked to submit a corrective patch.

2. c++bookends

C++ code can call C functions and share global variables with C,
provided those declarations are surrounded by "bookends":

extern "C" {
...
};

Header files can be made bilingual, to declare interfaces which
look the same to both C and C++ callers. This is done by
placing C++ bookends within the header file, guarded by #ifdefs

#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}; /* extern "C" */
#endif

This way the C++ caller can just #include the header file without
worrying whether the interface is implemented in C or C++.

Usually, extension modules written in C++ will put bookends around
all of their PostgreSQL #includes.

However, "postgres.h" usually stands alone as the first #include,
followed by some system #includes, and then the rest of the
PostgreSQL #includes. It is much nicer if a C++ file has just one
pair of bookends around its main block of PostgreSQL #includes.
This patch gives postgres.h its own internal bookends, making it
bilingual, so that its #include can continue to stand alone at the
head of each file.

Just a few additional header files are mentioned in the PostgreSQL
Reference Manual for add-on developers to use: fmgr.h, funcapi.h,
and spi.h. This patch adds bookends within those three files for
the benefit of beginners writing very simple extensions in C++.
Documentation and learning are simplified because C example code
can be compiled as C or C++ without change.

3. c++configure

This patch adds C++ support to the PostgreSQL build system.

After you have applied the patch, cd to the top of the source
tree (to the directory containing the file 'configure.in') and
execute these two commands to regenerate the 'configure' script
and some related files:
autoconf
autoheader

Much as it already does for the C compiler, the 'configure' script
will try to find the C++ compiler and set up appropriate command
line options. If 'configure' finds a C++ compiler, it will set up
src/Makefile.global to define the following makefile variables:

CXX = command for invoking C++ compiler
CXXCPP = command for invoking C++ preprocessor
CXXFLAGS = C++ compiler options
GXX = 'yes' if the C++ compiler is gcc/g++

Implicit rules are defined so that gmake will automatically invoke
the C++ compiler using the above variables given a source file name
suffixed with '.cpp' or '.cc'. So, to add a file named marvin.cpp
to the build, just add 'marvin.o' to the OBJS list in the Makefile.

To C++-compile a file with '.c' suffix, the Makefile should list
the .o file in both OBJS and CXXOBJS.

The pg_config utility can be used to display the CXX and CXXFLAGS.

Most C++ code typically uses some C++ features whose implementation
makes use of the compiler's runtime library: exceptions, static
constructors, new/delete, STL containers, stream I/O, etc. Specify
the following 'configure' option to link the C++ runtime library
into the postgres backend:

--enable-cplusplus

If --enable-cplusplus is specified, the makefile variable
'enable_cplusplus' will be set to 'yes', and pg_config.h will
#define ENABLE_CPLUSPLUS.

To ensure that the C++ runtime library is properly initialized,
on some platforms it is necessary for the main() function to be
compiled as C++. Therefore, if --enable-cplusplus is configured,
src/backend/main/main.c will be compiled as C++. This is
handled by the following lines in src/backend/main/Makefile:

ifeq ($(enable_cplusplus),yes)
CXXOBJS = main.o
endif

Fortunately, main.c can be compiled as either C or C++ with no
difficulty after applying the c++reserved and c++bookends
patches. To make main.c bilingual, all that was needed was
a pair of bookends around its #includes.

Limitations:

- I haven't added support for profiling and code coverage for
C++. Automatic dependency generation is supported, however.

- This ought to work on platforms which use GCC, and maybe some
others. The only one I have tested is x86_32 Linux with GCC
4.1.2. Hopefully some interested hackers will try it on
platforms to which they have access, and post the results.

4. c++exception

When C code calls C++ code, all C++ exceptions need to be caught
and fully contained within the C++ code. Exceptions should never
be thrown outward across the C/C++ frontier.

If an exception is not caught within C++ code, and the search for
a matching 'catch' bumps into a C stack frame, the result may be
platform dependent. On my platform (Linux/GCC), if this happens
in the postgres backend, the process terminates silently as if
abort() had been called.

With this patch, if --enable-cplusplus is configured,
PostgresMain defines a handler to intercept any uncaught C++
exception and convert it to a conventional PostgreSQL error of
FATAL severity. This allows the backend to clean up and report
the error before terminating.

Attachments:

c++reserved.patchtext/plain; name=c++reserved.patchDownload
diff -r bd5a52b2681a src/backend/access/common/tupdesc.c
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -532,10 +532,10 @@
 		attnum++;
 
 		attname = entry->colname;
-		atttypid = typenameTypeId(NULL, entry->typename, &atttypmod);
-		attdim = list_length(entry->typename->arrayBounds);
+		atttypid = typenameTypeId(NULL, entry->typeName, &atttypmod);
+		attdim = list_length(entry->typeName->arrayBounds);
 
-		if (entry->typename->setof)
+		if (entry->typeName->setof)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 					 errmsg("column \"%s\" cannot be declared SETOF",
diff -r bd5a52b2681a src/backend/commands/sequence.c
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -141,53 +141,53 @@
 		switch (i)
 		{
 			case SEQ_COL_NAME:
-				coldef->typename = makeTypeNameFromOid(NAMEOID, -1);
+				coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
 				coldef->colname = "sequence_name";
 				namestrcpy(&name, seq->sequence->relname);
 				value[i - 1] = NameGetDatum(&name);
 				break;
 			case SEQ_COL_LASTVAL:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "last_value";
 				value[i - 1] = Int64GetDatumFast(new.last_value);
 				break;
 			case SEQ_COL_STARTVAL:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "start_value";
 				value[i - 1] = Int64GetDatumFast(new.start_value);
 				break;
 			case SEQ_COL_INCBY:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "increment_by";
 				value[i - 1] = Int64GetDatumFast(new.increment_by);
 				break;
 			case SEQ_COL_MAXVALUE:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "max_value";
 				value[i - 1] = Int64GetDatumFast(new.max_value);
 				break;
 			case SEQ_COL_MINVALUE:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "min_value";
 				value[i - 1] = Int64GetDatumFast(new.min_value);
 				break;
 			case SEQ_COL_CACHE:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "cache_value";
 				value[i - 1] = Int64GetDatumFast(new.cache_value);
 				break;
 			case SEQ_COL_LOG:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "log_cnt";
 				value[i - 1] = Int64GetDatum((int64) 1);
 				break;
 			case SEQ_COL_CYCLE:
-				coldef->typename = makeTypeNameFromOid(BOOLOID, -1);
+				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
 				coldef->colname = "is_cycled";
 				value[i - 1] = BoolGetDatum(new.is_cycled);
 				break;
 			case SEQ_COL_CALLED:
-				coldef->typename = makeTypeNameFromOid(BOOLOID, -1);
+				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
 				coldef->colname = "is_called";
 				value[i - 1] = BoolGetDatum(false);
 				break;
diff -r bd5a52b2681a src/backend/commands/tablecmds.c
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -303,7 +303,7 @@
 					  bool recurse, bool recursing,
 					  AlterTableCmd *cmd);
 static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
-					  const char *colName, TypeName *typename);
+					  const char *colName, TypeName *typeName);
 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab);
 static void ATPostAlterTypeParse(char *cmd, List **wqueue);
 static void change_owner_recurse_to_sequences(Oid relationOid,
@@ -1251,7 +1251,7 @@
 						(errmsg("merging multiple inherited definitions of column \"%s\"",
 								attributeName)));
 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
-				defTypeId = typenameTypeId(NULL, def->typename, &deftypmod);
+				defTypeId = typenameTypeId(NULL, def->typeName, &deftypmod);
 				if (defTypeId != attribute->atttypid ||
 					deftypmod != attribute->atttypmod)
 					ereport(ERROR,
@@ -1259,7 +1259,7 @@
 						errmsg("inherited column \"%s\" has a type conflict",
 							   attributeName),
 							 errdetail("%s versus %s",
-									   TypeNameToString(def->typename),
+									   TypeNameToString(def->typeName),
 									   format_type_be(attribute->atttypid))));
 				def->inhcount++;
 				/* Merge of NOT NULL constraints = OR 'em together */
@@ -1274,7 +1274,7 @@
 				 */
 				def = makeNode(ColumnDef);
 				def->colname = pstrdup(attributeName);
-				def->typename = makeTypeNameFromOid(attribute->atttypid,
+				def->typeName = makeTypeNameFromOid(attribute->atttypid,
 													attribute->atttypmod);
 				def->inhcount = 1;
 				def->is_local = false;
@@ -1409,16 +1409,16 @@
 				   (errmsg("merging column \"%s\" with inherited definition",
 						   attributeName)));
 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
-				defTypeId = typenameTypeId(NULL, def->typename, &deftypmod);
-				newTypeId = typenameTypeId(NULL, newdef->typename, &newtypmod);
+				defTypeId = typenameTypeId(NULL, def->typeName, &deftypmod);
+				newTypeId = typenameTypeId(NULL, newdef->typeName, &newtypmod);
 				if (defTypeId != newTypeId || deftypmod != newtypmod)
 					ereport(ERROR,
 							(errcode(ERRCODE_DATATYPE_MISMATCH),
 							 errmsg("column \"%s\" has a type conflict",
 									attributeName),
 							 errdetail("%s versus %s",
-									   TypeNameToString(def->typename),
-									   TypeNameToString(newdef->typename))));
+									   TypeNameToString(def->typeName),
+									   TypeNameToString(newdef->typeName))));
 				/* Mark the column as locally defined */
 				def->is_local = true;
 				/* Merge of NOT NULL constraints = OR 'em together */
@@ -3480,7 +3480,7 @@
 			int32		ctypmod;
 
 			/* Okay if child matches by type */
-			ctypeId = typenameTypeId(NULL, colDef->typename, &ctypmod);
+			ctypeId = typenameTypeId(NULL, colDef->typeName, &ctypmod);
 			if (ctypeId != childatt->atttypid ||
 				ctypmod != childatt->atttypmod)
 				ereport(ERROR,
@@ -3535,7 +3535,7 @@
 						MaxHeapAttributeNumber)));
 	i = minattnum + 1;
 
-	typeTuple = typenameType(NULL, colDef->typename, &typmod);
+	typeTuple = typenameType(NULL, colDef->typeName, &typmod);
 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
 	typeOid = HeapTupleGetOid(typeTuple);
 
@@ -3551,7 +3551,7 @@
 	attribute.atttypmod = typmod;
 	attribute.attnum = i;
 	attribute.attbyval = tform->typbyval;
-	attribute.attndims = list_length(colDef->typename->arrayBounds);
+	attribute.attndims = list_length(colDef->typeName->arrayBounds);
 	attribute.attstorage = tform->typstorage;
 	attribute.attalign = tform->typalign;
 	attribute.attnotnull = colDef->is_not_null;
@@ -5415,7 +5415,7 @@
 					  AlterTableCmd *cmd)
 {
 	char	   *colName = cmd->name;
-	TypeName   *typename = (TypeName *) cmd->def;
+	TypeName   *typeName = (TypeName *) cmd->def;
 	HeapTuple	tuple;
 	Form_pg_attribute attTup;
 	AttrNumber	attnum;
@@ -5450,7 +5450,7 @@
 						colName)));
 
 	/* Look up the target type */
-	targettype = typenameTypeId(NULL, typename, &targettypmod);
+	targettype = typenameTypeId(NULL, typeName, &targettypmod);
 
 	/* make sure datatype is legal for a column */
 	CheckAttributeType(colName, targettype);
@@ -5541,7 +5541,7 @@
 
 static void
 ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
-					  const char *colName, TypeName *typename)
+					  const char *colName, TypeName *typeName)
 {
 	HeapTuple	heapTup;
 	Form_pg_attribute attTup;
@@ -5578,7 +5578,7 @@
 						colName)));
 
 	/* Look up the target type (should not fail, since prep found it) */
-	typeTuple = typenameType(NULL, typename, &targettypmod);
+	typeTuple = typenameType(NULL, typeName, &targettypmod);
 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
 	targettype = HeapTupleGetOid(typeTuple);
 
@@ -5825,7 +5825,7 @@
 	 */
 	attTup->atttypid = targettype;
 	attTup->atttypmod = targettypmod;
-	attTup->attndims = list_length(typename->arrayBounds);
+	attTup->attndims = list_length(typeName->arrayBounds);
 	attTup->attlen = tform->typlen;
 	attTup->attbyval = tform->typbyval;
 	attTup->attalign = tform->typalign;
diff -r bd5a52b2681a src/backend/commands/typecmds.c
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -676,7 +676,7 @@
 	bool		saw_default = false;
 	bool		typNotNull = false;
 	bool		nullDefined = false;
-	int32		typNDims = list_length(stmt->typename->arrayBounds);
+	int32		typNDims = list_length(stmt->typeName->arrayBounds);
 	HeapTuple	typeTup;
 	List	   *schema = stmt->constraints;
 	ListCell   *listptr;
@@ -716,7 +716,7 @@
 	/*
 	 * Look up the base type.
 	 */
-	typeTup = typenameType(NULL, stmt->typename, &basetypeMod);
+	typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
 	baseType = (Form_pg_type) GETSTRUCT(typeTup);
 	basetypeoid = HeapTupleGetOid(typeTup);
 
@@ -732,7 +732,7 @@
 		ereport(ERROR,
 				(errcode(ERRCODE_DATATYPE_MISMATCH),
 				 errmsg("\"%s\" is not a valid base type for a domain",
-						TypeNameToString(stmt->typename))));
+						TypeNameToString(stmt->typeName))));
 
 	/* passed by value */
 	byValue = baseType->typbyval;
@@ -1013,7 +1013,7 @@
 	Relation	pg_type;
 
 	/* Convert list of names to a name and namespace */
-	enumNamespace = QualifiedNameGetCreationNamespace(stmt->typename,
+	enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
 													  &enumName);
 
 	/* Check we have creation rights in target namespace */
diff -r bd5a52b2681a src/backend/commands/view.c
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -118,7 +118,7 @@
 			ColumnDef  *def = makeNode(ColumnDef);
 
 			def->colname = pstrdup(tle->resname);
-			def->typename = makeTypeNameFromOid(exprType((Node *) tle->expr),
+			def->typeName = makeTypeNameFromOid(exprType((Node *) tle->expr),
 											 exprTypmod((Node *) tle->expr));
 			def->inhcount = 0;
 			def->is_local = true;
diff -r bd5a52b2681a src/backend/nodes/copyfuncs.c
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1491,7 +1491,7 @@
 	COPY_SCALAR_FIELD(isNatural);
 	COPY_NODE_FIELD(larg);
 	COPY_NODE_FIELD(rarg);
-	COPY_NODE_FIELD(using);
+	COPY_NODE_FIELD(usingClause);
 	COPY_NODE_FIELD(quals);
 	COPY_NODE_FIELD(alias);
 	COPY_SCALAR_FIELD(rtindex);
@@ -1915,7 +1915,7 @@
 	TypeName   *newnode = makeNode(TypeName);
 
 	COPY_NODE_FIELD(names);
-	COPY_SCALAR_FIELD(typeid);
+	COPY_SCALAR_FIELD(typeOid);
 	COPY_SCALAR_FIELD(setof);
 	COPY_SCALAR_FIELD(pct_type);
 	COPY_NODE_FIELD(typmods);
@@ -1969,7 +1969,7 @@
 	TypeCast   *newnode = makeNode(TypeCast);
 
 	COPY_NODE_FIELD(arg);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
@@ -1995,7 +1995,7 @@
 	ColumnDef  *newnode = makeNode(ColumnDef);
 
 	COPY_STRING_FIELD(colname);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_SCALAR_FIELD(inhcount);
 	COPY_SCALAR_FIELD(is_local);
 	COPY_SCALAR_FIELD(is_not_null);
@@ -2052,7 +2052,7 @@
 
 	COPY_SCALAR_FIELD(xmloption);
 	COPY_NODE_FIELD(expr);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
@@ -2204,7 +2204,7 @@
 	AlterDomainStmt *newnode = makeNode(AlterDomainStmt);
 
 	COPY_SCALAR_FIELD(subtype);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_STRING_FIELD(name);
 	COPY_NODE_FIELD(def);
 	COPY_SCALAR_FIELD(behavior);
@@ -2622,7 +2622,7 @@
 {
 	CreateEnumStmt *newnode = makeNode(CreateEnumStmt);
 
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
 
 	return newnode;
@@ -2657,7 +2657,7 @@
 	CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
 
 	COPY_NODE_FIELD(domainname);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(constraints);
 
 	return newnode;
diff -r bd5a52b2681a src/backend/nodes/equalfuncs.c
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -688,7 +688,7 @@
 	COMPARE_SCALAR_FIELD(isNatural);
 	COMPARE_NODE_FIELD(larg);
 	COMPARE_NODE_FIELD(rarg);
-	COMPARE_NODE_FIELD(using);
+	COMPARE_NODE_FIELD(usingClause);
 	COMPARE_NODE_FIELD(quals);
 	COMPARE_NODE_FIELD(alias);
 	COMPARE_SCALAR_FIELD(rtindex);
@@ -957,7 +957,7 @@
 _equalAlterDomainStmt(AlterDomainStmt *a, AlterDomainStmt *b)
 {
 	COMPARE_SCALAR_FIELD(subtype);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_STRING_FIELD(name);
 	COMPARE_NODE_FIELD(def);
 	COMPARE_SCALAR_FIELD(behavior);
@@ -1311,7 +1311,7 @@
 static bool
 _equalCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
 {
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
 
 	return true;
@@ -1340,7 +1340,7 @@
 _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
 {
 	COMPARE_NODE_FIELD(domainname);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(constraints);
 
 	return true;
@@ -1852,7 +1852,7 @@
 _equalTypeName(TypeName *a, TypeName *b)
 {
 	COMPARE_NODE_FIELD(names);
-	COMPARE_SCALAR_FIELD(typeid);
+	COMPARE_SCALAR_FIELD(typeOid);
 	COMPARE_SCALAR_FIELD(setof);
 	COMPARE_SCALAR_FIELD(pct_type);
 	COMPARE_NODE_FIELD(typmods);
@@ -1867,7 +1867,7 @@
 _equalTypeCast(TypeCast *a, TypeCast *b)
 {
 	COMPARE_NODE_FIELD(arg);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
@@ -1920,7 +1920,7 @@
 _equalColumnDef(ColumnDef *a, ColumnDef *b)
 {
 	COMPARE_STRING_FIELD(colname);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_SCALAR_FIELD(inhcount);
 	COMPARE_SCALAR_FIELD(is_local);
 	COMPARE_SCALAR_FIELD(is_not_null);
@@ -2062,7 +2062,7 @@
 {
 	COMPARE_SCALAR_FIELD(xmloption);
 	COMPARE_NODE_FIELD(expr);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
diff -r bd5a52b2681a src/backend/nodes/makefuncs.c
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -316,11 +316,11 @@
  *	build a TypeName node to represent a type already known by OID/typmod.
  */
 TypeName *
-makeTypeNameFromOid(Oid typeid, int32 typmod)
+makeTypeNameFromOid(Oid typeOid, int32 typmod)
 {
 	TypeName   *n = makeNode(TypeName);
 
-	n->typeid = typeid;
+	n->typeOid = typeOid;
 	n->typemod = typmod;
 	n->location = -1;
 	return n;
diff -r bd5a52b2681a src/backend/nodes/nodeFuncs.c
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -860,7 +860,7 @@
 				 * so any of the components might be leftmost.
 				 */
 				loc = exprLocation(tc->arg);
-				loc = leftmostLoc(loc, tc->typename->location);
+				loc = leftmostLoc(loc, tc->typeName->location);
 				loc = leftmostLoc(loc, tc->location);
 			}
 			break;
@@ -2359,7 +2359,7 @@
 
 				if (walker(tc->arg, context))
 					return true;
-				if (walker(tc->typename, context))
+				if (walker(tc->typeName, context))
 					return true;
 			}
 			break;
@@ -2400,7 +2400,7 @@
 			{
 				ColumnDef *coldef = (ColumnDef *) node;
 
-				if (walker(coldef->typename, context))
+				if (walker(coldef->typeName, context))
 					return true;
 				if (walker(coldef->raw_default, context))
 					return true;
@@ -2415,7 +2415,7 @@
 
 				if (walker(xs->expr, context))
 					return true;
-				if (walker(xs->typename, context))
+				if (walker(xs->typeName, context))
 					return true;
 			}
 			break;
diff -r bd5a52b2681a src/backend/nodes/outfuncs.c
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1207,7 +1207,7 @@
 	WRITE_BOOL_FIELD(isNatural);
 	WRITE_NODE_FIELD(larg);
 	WRITE_NODE_FIELD(rarg);
-	WRITE_NODE_FIELD(using);
+	WRITE_NODE_FIELD(usingClause);
 	WRITE_NODE_FIELD(quals);
 	WRITE_NODE_FIELD(alias);
 	WRITE_INT_FIELD(rtindex);
@@ -1772,7 +1772,7 @@
 
 	WRITE_ENUM_FIELD(xmloption, XmlOptionType);
 	WRITE_NODE_FIELD(expr);
-	WRITE_NODE_FIELD(typename);
+	WRITE_NODE_FIELD(typeName);
 	WRITE_LOCATION_FIELD(location);
 }
 
@@ -1782,7 +1782,7 @@
 	WRITE_NODE_TYPE("COLUMNDEF");
 
 	WRITE_STRING_FIELD(colname);
-	WRITE_NODE_FIELD(typename);
+	WRITE_NODE_FIELD(typeName);
 	WRITE_INT_FIELD(inhcount);
 	WRITE_BOOL_FIELD(is_local);
 	WRITE_BOOL_FIELD(is_not_null);
@@ -1797,7 +1797,7 @@
 	WRITE_NODE_TYPE("TYPENAME");
 
 	WRITE_NODE_FIELD(names);
-	WRITE_OID_FIELD(typeid);
+	WRITE_OID_FIELD(typeOid);
 	WRITE_BOOL_FIELD(setof);
 	WRITE_BOOL_FIELD(pct_type);
 	WRITE_NODE_FIELD(typmods);
@@ -1812,7 +1812,7 @@
 	WRITE_NODE_TYPE("TYPECAST");
 
 	WRITE_NODE_FIELD(arg);
-	WRITE_NODE_FIELD(typename);
+	WRITE_NODE_FIELD(typeName);
 	WRITE_LOCATION_FIELD(location);
 }
 
diff -r bd5a52b2681a src/backend/nodes/readfuncs.c
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -984,7 +984,7 @@
 	READ_BOOL_FIELD(isNatural);
 	READ_NODE_FIELD(larg);
 	READ_NODE_FIELD(rarg);
-	READ_NODE_FIELD(using);
+	READ_NODE_FIELD(usingClause);
 	READ_NODE_FIELD(quals);
 	READ_NODE_FIELD(alias);
 	READ_INT_FIELD(rtindex);
diff -r bd5a52b2681a src/backend/parser/gram.y
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2021,7 +2021,7 @@
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
-					n->typename = $2;
+					n->typeName = $2;
 					n->constraints = $3;
 					n->is_local = true;
 					$$ = (Node *)n;
@@ -2468,7 +2468,7 @@
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
-					n->typename = NULL;
+					n->typeName = NULL;
 					n->inhcount = 0;
 					n->is_local = true;
 					n->is_not_null = false;
@@ -3056,7 +3056,7 @@
 			| CREATE TYPE_P any_name AS ENUM_P '(' enum_val_list ')'
 				{
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
-					n->typename = $3;
+					n->typeName = $3;
 					n->vals = $7;
 					$$ = (Node *)n;
 				}
@@ -5622,7 +5622,7 @@
 				{
 					CreateDomainStmt *n = makeNode(CreateDomainStmt);
 					n->domainname = $3;
-					n->typename = $5;
+					n->typeName = $5;
 					n->constraints = $6;
 					$$ = (Node *)n;
 				}
@@ -5634,7 +5634,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'T';
-					n->typename = $3;
+					n->typeName = $3;
 					n->def = $4;
 					$$ = (Node *)n;
 				}
@@ -5643,7 +5643,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'N';
-					n->typename = $3;
+					n->typeName = $3;
 					$$ = (Node *)n;
 				}
 			/* ALTER DOMAIN <domain> SET NOT NULL */
@@ -5651,7 +5651,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'O';
-					n->typename = $3;
+					n->typeName = $3;
 					$$ = (Node *)n;
 				}
 			/* ALTER DOMAIN <domain> ADD CONSTRAINT ... */
@@ -5659,7 +5659,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'C';
-					n->typename = $3;
+					n->typeName = $3;
 					n->def = $5;
 					$$ = (Node *)n;
 				}
@@ -5668,7 +5668,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'X';
-					n->typename = $3;
+					n->typeName = $3;
 					n->name = $6;
 					n->behavior = $7;
 					$$ = (Node *)n;
@@ -6920,7 +6920,7 @@
 					n->isNatural = FALSE;
 					n->larg = $1;
 					n->rarg = $4;
-					n->using = NIL;
+					n->usingClause = NIL;
 					n->quals = NULL;
 					$$ = n;
 				}
@@ -6932,7 +6932,7 @@
 					n->larg = $1;
 					n->rarg = $4;
 					if ($5 != NULL && IsA($5, List))
-						n->using = (List *) $5; /* USING clause */
+						n->usingClause = (List *) $5; /* USING clause */
 					else
 						n->quals = $5; /* ON clause */
 					$$ = n;
@@ -6946,7 +6946,7 @@
 					n->larg = $1;
 					n->rarg = $3;
 					if ($4 != NULL && IsA($4, List))
-						n->using = (List *) $4; /* USING clause */
+						n->usingClause = (List *) $4; /* USING clause */
 					else
 						n->quals = $4; /* ON clause */
 					$$ = n;
@@ -6958,7 +6958,7 @@
 					n->isNatural = TRUE;
 					n->larg = $1;
 					n->rarg = $5;
-					n->using = NIL; /* figure out which columns later... */
+					n->usingClause = NIL; /* figure out which columns later... */
 					n->quals = NULL; /* fill later */
 					$$ = n;
 				}
@@ -6970,7 +6970,7 @@
 					n->isNatural = TRUE;
 					n->larg = $1;
 					n->rarg = $4;
-					n->using = NIL; /* figure out which columns later... */
+					n->usingClause = NIL; /* figure out which columns later... */
 					n->quals = NULL; /* fill later */
 					$$ = n;
 				}
@@ -7135,7 +7135,7 @@
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
-					n->typename = $2;
+					n->typeName = $2;
 					n->constraints = NIL;
 					n->is_local = true;
 					$$ = (Node *)n;
@@ -8694,7 +8694,7 @@
 					XmlSerialize *n = makeNode(XmlSerialize);
 					n->xmloption = $3;
 					n->expr = $4;
-					n->typename = $6;
+					n->typeName = $6;
 					n->location = @1;
 					$$ = (Node *)n;
 				}
@@ -9906,7 +9906,7 @@
 {
 	TypeCast *n = makeNode(TypeCast);
 	n->arg = arg;
-	n->typename = typename;
+	n->typeName = typename;
 	n->location = location;
 	return (Node *) n;
 }
diff -r bd5a52b2681a src/backend/parser/parse_clause.c
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -772,7 +772,7 @@
 			ListCell   *lx,
 					   *rx;
 
-			Assert(j->using == NIL);	/* shouldn't have USING() too */
+			Assert(j->usingClause == NIL);	/* shouldn't have USING() too */
 
 			foreach(lx, l_colnames)
 			{
@@ -795,7 +795,7 @@
 					rlist = lappend(rlist, m_name);
 			}
 
-			j->using = rlist;
+			j->usingClause = rlist;
 		}
 
 		/*
@@ -804,14 +804,14 @@
 		res_colnames = NIL;
 		res_colvars = NIL;
 
-		if (j->using)
+		if (j->usingClause)
 		{
 			/*
 			 * JOIN/USING (or NATURAL JOIN, as transformed above). Transform
 			 * the list into an explicit ON-condition, and generate a list of
 			 * merged result columns.
 			 */
-			List	   *ucols = j->using;
+			List	   *ucols = j->usingClause;
 			List	   *l_usingvars = NIL;
 			List	   *r_usingvars = NIL;
 			ListCell   *ucol;
diff -r bd5a52b2681a src/backend/parser/parse_expr.c
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -159,7 +159,7 @@
 					Oid			elementType;
 					int32		targetTypmod;
 
-					targetType = typenameTypeId(pstate, tc->typename,
+					targetType = typenameTypeId(pstate, tc->typeName,
 												&targetTypmod);
 					elementType = get_element_type(targetType);
 					if (OidIsValid(elementType))
@@ -1770,7 +1770,7 @@
 													 XMLOID,
 													 "XMLSERIALIZE"));
 
-	targetType = typenameTypeId(pstate, xs->typename, &targetTypmod);
+	targetType = typenameTypeId(pstate, xs->typeName, &targetTypmod);
 
 	xexpr->xmloption = xs->xmloption;
 	xexpr->location = xs->location;
@@ -1994,7 +1994,7 @@
 	int32		targetTypmod;
 	int			location;
 
-	targetType = typenameTypeId(pstate, tc->typename, &targetTypmod);
+	targetType = typenameTypeId(pstate, tc->typeName, &targetTypmod);
 
 	if (inputType == InvalidOid)
 		return expr;			/* do nothing if NULL input */
@@ -2006,7 +2006,7 @@
 	 */
 	location = tc->location;
 	if (location < 0)
-		location = tc->typename->location;
+		location = tc->typeName->location;
 
 	result = coerce_to_target_type(pstate, expr, inputType,
 								   targetType, targetTypmod,
diff -r bd5a52b2681a src/backend/parser/parse_relation.c
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1067,13 +1067,13 @@
 			int32		attrtypmod;
 
 			attrname = pstrdup(n->colname);
-			if (n->typename->setof)
+			if (n->typeName->setof)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 						 errmsg("column \"%s\" cannot be declared SETOF",
 								attrname),
-						 parser_errposition(pstate, n->typename->location)));
-			attrtype = typenameTypeId(pstate, n->typename, &attrtypmod);
+						 parser_errposition(pstate, n->typeName->location)));
+			attrtype = typenameTypeId(pstate, n->typeName, &attrtypmod);
 			eref->colnames = lappend(eref->colnames, makeString(attrname));
 			rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
 			rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod);
diff -r bd5a52b2681a src/backend/parser/parse_target.c
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1355,9 +1355,9 @@
 											 name);
 			if (strength <= 1)
 			{
-				if (((TypeCast *) node)->typename != NULL)
+				if (((TypeCast *) node)->typeName != NULL)
 				{
-					*name = strVal(llast(((TypeCast *) node)->typename->names));
+					*name = strVal(llast(((TypeCast *) node)->typeName->names));
 					return 1;
 				}
 			}
diff -r bd5a52b2681a src/backend/parser/parse_type.c
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -27,7 +27,7 @@
 #include "utils/syscache.h"
 
 
-static int32 typenameTypeMod(ParseState *pstate, const TypeName *typename,
+static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
 				Type typ);
 
 
@@ -54,57 +54,57 @@
  * pstate is only used for error location info, and may be NULL.
  */
 Type
-LookupTypeName(ParseState *pstate, const TypeName *typename,
+LookupTypeName(ParseState *pstate, const TypeName *typeName,
 			   int32 *typmod_p)
 {
 	Oid			typoid;
 	HeapTuple	tup;
 	int32		typmod;
 
-	if (typename->names == NIL)
+	if (typeName->names == NIL)
 	{
 		/* We have the OID already if it's an internally generated TypeName */
-		typoid = typename->typeid;
+		typoid = typeName->typeOid;
 	}
-	else if (typename->pct_type)
+	else if (typeName->pct_type)
 	{
 		/* Handle %TYPE reference to type of an existing field */
-		RangeVar   *rel = makeRangeVar(NULL, NULL, typename->location);
+		RangeVar   *rel = makeRangeVar(NULL, NULL, typeName->location);
 		char	   *field = NULL;
 		Oid			relid;
 		AttrNumber	attnum;
 
 		/* deconstruct the name list */
-		switch (list_length(typename->names))
+		switch (list_length(typeName->names))
 		{
 			case 1:
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 				errmsg("improper %%TYPE reference (too few dotted names): %s",
-					   NameListToString(typename->names)),
-						 parser_errposition(pstate, typename->location)));
+					   NameListToString(typeName->names)),
+						 parser_errposition(pstate, typeName->location)));
 				break;
 			case 2:
-				rel->relname = strVal(linitial(typename->names));
-				field = strVal(lsecond(typename->names));
+				rel->relname = strVal(linitial(typeName->names));
+				field = strVal(lsecond(typeName->names));
 				break;
 			case 3:
-				rel->schemaname = strVal(linitial(typename->names));
-				rel->relname = strVal(lsecond(typename->names));
-				field = strVal(lthird(typename->names));
+				rel->schemaname = strVal(linitial(typeName->names));
+				rel->relname = strVal(lsecond(typeName->names));
+				field = strVal(lthird(typeName->names));
 				break;
 			case 4:
-				rel->catalogname = strVal(linitial(typename->names));
-				rel->schemaname = strVal(lsecond(typename->names));
-				rel->relname = strVal(lthird(typename->names));
-				field = strVal(lfourth(typename->names));
+				rel->catalogname = strVal(linitial(typeName->names));
+				rel->schemaname = strVal(lsecond(typeName->names));
+				rel->relname = strVal(lthird(typeName->names));
+				field = strVal(lfourth(typeName->names));
 				break;
 			default:
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 						 errmsg("improper %%TYPE reference (too many dotted names): %s",
-								NameListToString(typename->names)),
-						 parser_errposition(pstate, typename->location)));
+								NameListToString(typeName->names)),
+						 parser_errposition(pstate, typeName->location)));
 				break;
 		}
 
@@ -116,16 +116,16 @@
 					(errcode(ERRCODE_UNDEFINED_COLUMN),
 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
 							field, rel->relname),
-					 parser_errposition(pstate, typename->location)));
+					 parser_errposition(pstate, typeName->location)));
 		typoid = get_atttype(relid, attnum);
 
 		/* this construct should never have an array indicator */
-		Assert(typename->arrayBounds == NIL);
+		Assert(typeName->arrayBounds == NIL);
 
 		/* emit nuisance notice (intentionally not errposition'd) */
 		ereport(NOTICE,
 				(errmsg("type reference %s converted to %s",
-						TypeNameToString(typename),
+						TypeNameToString(typeName),
 						format_type_be(typoid))));
 	}
 	else
@@ -135,7 +135,7 @@
 		char	   *typname;
 
 		/* deconstruct the name list */
-		DeconstructQualifiedName(typename->names, &schemaname, &typname);
+		DeconstructQualifiedName(typeName->names, &schemaname, &typname);
 
 		if (schemaname)
 		{
@@ -155,7 +155,7 @@
 		}
 
 		/* If an array reference, return the array type instead */
-		if (typename->arrayBounds != NIL)
+		if (typeName->arrayBounds != NIL)
 			typoid = get_array_type(typoid);
 	}
 
@@ -172,7 +172,7 @@
 	if (!HeapTupleIsValid(tup)) /* should not happen */
 		elog(ERROR, "cache lookup failed for type %u", typoid);
 
-	typmod = typenameTypeMod(pstate, typename, (Type) tup);
+	typmod = typenameTypeMod(pstate, typeName, (Type) tup);
 
 	if (typmod_p)
 		*typmod_p = typmod;
@@ -188,23 +188,23 @@
  * Callers of this can therefore assume the result is a fully valid type.
  */
 Type
-typenameType(ParseState *pstate, const TypeName *typename, int32 *typmod_p)
+typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
 	Type		tup;
 
-	tup = LookupTypeName(pstate, typename, typmod_p);
+	tup = LookupTypeName(pstate, typeName, typmod_p);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("type \"%s\" does not exist",
-						TypeNameToString(typename)),
-				 parser_errposition(pstate, typename->location)));
+						TypeNameToString(typeName)),
+				 parser_errposition(pstate, typeName->location)));
 	if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("type \"%s\" is only a shell",
-						TypeNameToString(typename)),
-				 parser_errposition(pstate, typename->location)));
+						TypeNameToString(typeName)),
+				 parser_errposition(pstate, typeName->location)));
 	return tup;
 }
 
@@ -215,12 +215,12 @@
  * not the syscache entry.
  */
 Oid
-typenameTypeId(ParseState *pstate, const TypeName *typename, int32 *typmod_p)
+typenameTypeId(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
 	Oid			typoid;
 	Type		tup;
 
-	tup = typenameType(pstate, typename, typmod_p);
+	tup = typenameType(pstate, typeName, typmod_p);
 	typoid = HeapTupleGetOid(tup);
 	ReleaseSysCache(tup);
 
@@ -239,7 +239,7 @@
  * pstate is only used for error location info, and may be NULL.
  */
 static int32
-typenameTypeMod(ParseState *pstate, const TypeName *typename, Type typ)
+typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
 {
 	int32		result;
 	Oid			typmodin;
@@ -250,8 +250,8 @@
 	ParseCallbackState pcbstate;
 
 	/* Return prespecified typmod if no typmod expressions */
-	if (typename->typmods == NIL)
-		return typename->typemod;
+	if (typeName->typmods == NIL)
+		return typeName->typemod;
 
 	/*
 	 * Else, type had better accept typmods.  We give a special error message
@@ -262,8 +262,8 @@
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 			errmsg("type modifier cannot be specified for shell type \"%s\"",
-				   TypeNameToString(typename)),
-				 parser_errposition(pstate, typename->location)));
+				   TypeNameToString(typeName)),
+				 parser_errposition(pstate, typeName->location)));
 
 	typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
 
@@ -271,17 +271,17 @@
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("type modifier is not allowed for type \"%s\"",
-						TypeNameToString(typename)),
-				 parser_errposition(pstate, typename->location)));
+						TypeNameToString(typeName)),
+				 parser_errposition(pstate, typeName->location)));
 
 	/*
 	 * Convert the list of raw-grammar-output expressions to a cstring array.
 	 * Currently, we allow simple numeric constants, string literals, and
 	 * identifiers; possibly this list could be extended.
 	 */
-	datums = (Datum *) palloc(list_length(typename->typmods) * sizeof(Datum));
+	datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
 	n = 0;
-	foreach(l, typename->typmods)
+	foreach(l, typeName->typmods)
 	{
 		Node	   *tm = (Node *) lfirst(l);
 		char	   *cstr = NULL;
@@ -314,7 +314,7 @@
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 			errmsg("type modifiers must be simple constants or identifiers"),
-					 parser_errposition(pstate, typename->location)));
+					 parser_errposition(pstate, typeName->location)));
 		datums[n++] = CStringGetDatum(cstr);
 	}
 
@@ -323,7 +323,7 @@
 								-2, false, 'c');
 
 	/* arrange to report location if type's typmodin function fails */
-	setup_parser_errposition_callback(&pcbstate, pstate, typename->location);
+	setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
 
 	result = DatumGetInt32(OidFunctionCall1(typmodin,
 											PointerGetDatum(arrtypmod)));
@@ -345,16 +345,16 @@
  * it is mostly used for reporting lookup errors.
  */
 static void
-appendTypeNameToBuffer(const TypeName *typename, StringInfo string)
+appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
 {
-	if (typename->names != NIL)
+	if (typeName->names != NIL)
 	{
 		/* Emit possibly-qualified name as-is */
 		ListCell   *l;
 
-		foreach(l, typename->names)
+		foreach(l, typeName->names)
 		{
-			if (l != list_head(typename->names))
+			if (l != list_head(typeName->names))
 				appendStringInfoChar(string, '.');
 			appendStringInfoString(string, strVal(lfirst(l)));
 		}
@@ -362,17 +362,17 @@
 	else
 	{
 		/* Look up internally-specified type */
-		appendStringInfoString(string, format_type_be(typename->typeid));
+		appendStringInfoString(string, format_type_be(typeName->typeOid));
 	}
 
 	/*
 	 * Add decoration as needed, but only for fields considered by
 	 * LookupTypeName
 	 */
-	if (typename->pct_type)
+	if (typeName->pct_type)
 		appendStringInfoString(string, "%TYPE");
 
-	if (typename->arrayBounds != NIL)
+	if (typeName->arrayBounds != NIL)
 		appendStringInfoString(string, "[]");
 }
 
@@ -384,12 +384,12 @@
  * it is mostly used for reporting lookup errors.
  */
 char *
-TypeNameToString(const TypeName *typename)
+TypeNameToString(const TypeName *typeName)
 {
 	StringInfoData string;
 
 	initStringInfo(&string);
-	appendTypeNameToBuffer(typename, &string);
+	appendTypeNameToBuffer(typeName, &string);
 	return string.data;
 }
 
@@ -406,12 +406,12 @@
 	initStringInfo(&string);
 	foreach(l, typenames)
 	{
-		TypeName   *typename = (TypeName *) lfirst(l);
+		TypeName   *typeName = (TypeName *) lfirst(l);
 
-		Assert(IsA(typename, TypeName));
+		Assert(IsA(typeName, TypeName));
 		if (l != list_head(typenames))
 			appendStringInfoChar(&string, ',');
-		appendTypeNameToBuffer(typename, &string);
+		appendTypeNameToBuffer(typeName, &string);
 	}
 	return string.data;
 }
@@ -574,7 +574,7 @@
 	SelectStmt *stmt;
 	ResTarget  *restarget;
 	TypeCast   *typecast;
-	TypeName   *typename;
+	TypeName   *typeName;
 	ErrorContextCallback ptserrcontext;
 
 	/* make sure we give useful error for empty input */
@@ -633,14 +633,14 @@
 		typecast->arg == NULL ||
 		!IsA(typecast->arg, A_Const))
 		goto fail;
-	typename = typecast->typename;
-	if (typename == NULL ||
-		!IsA(typename, TypeName))
+	typeName = typecast->typeName;
+	if (typeName == NULL ||
+		!IsA(typeName, TypeName))
 		goto fail;
-	if (typename->setof)
+	if (typeName->setof)
 		goto fail;
 
-	*type_id = typenameTypeId(NULL, typename, typmod_p);
+	*type_id = typenameTypeId(NULL, typeName, typmod_p);
 
 	pfree(buf.data);
 
diff -r bd5a52b2681a src/backend/parser/parse_utilcmd.c
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -266,24 +266,24 @@
 
 	/* Check for SERIAL pseudo-types */
 	is_serial = false;
-	if (list_length(column->typename->names) == 1 &&
-		!column->typename->pct_type)
+	if (list_length(column->typeName->names) == 1 &&
+		!column->typeName->pct_type)
 	{
-		char	   *typname = strVal(linitial(column->typename->names));
+		char	   *typname = strVal(linitial(column->typeName->names));
 
 		if (strcmp(typname, "serial") == 0 ||
 			strcmp(typname, "serial4") == 0)
 		{
 			is_serial = true;
-			column->typename->names = NIL;
-			column->typename->typeid = INT4OID;
+			column->typeName->names = NIL;
+			column->typeName->typeOid = INT4OID;
 		}
 		else if (strcmp(typname, "bigserial") == 0 ||
 				 strcmp(typname, "serial8") == 0)
 		{
 			is_serial = true;
-			column->typename->names = NIL;
-			column->typename->typeid = INT8OID;
+			column->typeName->names = NIL;
+			column->typeName->typeOid = INT8OID;
 		}
 
 		/*
@@ -291,7 +291,7 @@
 		 * set typeid, LookupTypeName won't notice arrayBounds.  We don't
 		 * need any special coding for serial(typmod) though.
 		 */
-		if (is_serial && column->typename->arrayBounds != NIL)
+		if (is_serial && column->typeName->arrayBounds != NIL)
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("array of serial is not implemented")));
@@ -382,7 +382,7 @@
 		snamenode->val.val.str = qstring;
 		snamenode->location = -1;
 		castnode = makeNode(TypeCast);
-		castnode->typename = SystemTypeName("regclass");
+		castnode->typeName = SystemTypeName("regclass");
 		castnode->arg = (Node *) snamenode;
 		castnode->location = -1;
 		funccallnode = makeNode(FuncCall);
@@ -622,7 +622,7 @@
 		 */
 		def = makeNode(ColumnDef);
 		def->colname = pstrdup(attributeName);
-		def->typename = makeTypeNameFromOid(attribute->atttypid,
+		def->typeName = makeTypeNameFromOid(attribute->atttypid,
 											attribute->atttypmod);
 		def->inhcount = 0;
 		def->is_local = true;
@@ -1962,7 +1962,7 @@
 	/*
 	 * All we really need to do here is verify that the type is valid.
 	 */
-	Type		ctype = typenameType(pstate, column->typename, NULL);
+	Type		ctype = typenameType(pstate, column->typeName, NULL);
 
 	ReleaseSysCache(ctype);
 }
diff -r bd5a52b2681a src/backend/tcop/utility.c
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -602,23 +602,23 @@
 						 * Recursively alter column default for table and, if
 						 * requested, for descendants
 						 */
-						AlterDomainDefault(stmt->typename,
+						AlterDomainDefault(stmt->typeName,
 										   stmt->def);
 						break;
 					case 'N':	/* ALTER DOMAIN DROP NOT NULL */
-						AlterDomainNotNull(stmt->typename,
+						AlterDomainNotNull(stmt->typeName,
 										   false);
 						break;
 					case 'O':	/* ALTER DOMAIN SET NOT NULL */
-						AlterDomainNotNull(stmt->typename,
+						AlterDomainNotNull(stmt->typeName,
 										   true);
 						break;
 					case 'C':	/* ADD CONSTRAINT */
-						AlterDomainAddConstraint(stmt->typename,
+						AlterDomainAddConstraint(stmt->typeName,
 												 stmt->def);
 						break;
 					case 'X':	/* DROP CONSTRAINT */
-						AlterDomainDropConstraint(stmt->typename,
+						AlterDomainDropConstraint(stmt->typeName,
 												  stmt->name,
 												  stmt->behavior);
 						break;
diff -r bd5a52b2681a src/backend/utils/adt/ruleutils.c
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5539,14 +5539,14 @@
 
 		if (!j->isNatural)
 		{
-			if (j->using)
+			if (j->usingClause)
 			{
 				ListCell   *col;
 
 				appendStringInfo(buf, " USING (");
-				foreach(col, j->using)
-				{
-					if (col != list_head(j->using))
+				foreach(col, j->usingClause)
+				{
+					if (col != list_head(j->usingClause))
 						appendStringInfo(buf, ", ");
 					appendStringInfoString(buf,
 									  quote_identifier(strVal(lfirst(col))));
@@ -5878,18 +5878,18 @@
 /*
  * quote_qualified_identifier	- Quote a possibly-qualified identifier
  *
- * Return a name of the form namespace.ident, or just ident if namespace
+ * Return a name of the form qualifier.ident, or just ident if qualifier
  * is NULL, quoting each component if necessary.  The result is palloc'd.
  */
 char *
-quote_qualified_identifier(const char *namespace,
+quote_qualified_identifier(const char *qualifier,
 						   const char *ident)
 {
 	StringInfoData buf;
 
 	initStringInfo(&buf);
-	if (namespace)
-		appendStringInfo(&buf, "%s.", quote_identifier(namespace));
+	if (qualifier)
+		appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
 	appendStringInfoString(&buf, quote_identifier(ident));
 	return buf.data;
 }
diff -r bd5a52b2681a src/backend/utils/misc/guc.c
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -5370,7 +5370,7 @@
 	{
 		Node       *arg = (Node *) lfirst(l);
 		char	   *val;
-		TypeName   *typename = NULL;
+		TypeName   *typeName = NULL;
 		A_Const	   *con;
 
 		if (l != list_head(args))
@@ -5381,7 +5381,7 @@
 			TypeCast *tc = (TypeCast *) arg;
 
 			arg = tc->arg;
-			typename = tc->typename;
+			typeName = tc->typeName;
 		}
 
 		if (!IsA(arg, A_Const))
@@ -5399,7 +5399,7 @@
 				break;
 			case T_String:
 				val = strVal(&con->val);
-				if (typename != NULL)
+				if (typeName != NULL)
 				{
 					/*
 					 * Must be a ConstInterval argument for TIME ZONE. Coerce
@@ -5411,7 +5411,7 @@
 					Datum		interval;
 					char	   *intervalout;
 
-					typoid = typenameTypeId(NULL, typename, &typmod);
+					typoid = typenameTypeId(NULL, typeName, &typmod);
 					Assert(typoid == INTERVALOID);
 
 					interval =
diff -r bd5a52b2681a src/backend/utils/mmgr/mcxt.c
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -193,7 +193,7 @@
 			}
 		}
 	}
-	(*context->methods->delete) (context);
+	(*context->methods->delete_context) (context);
 	pfree(context);
 }
 
diff -r bd5a52b2681a src/include/c.h
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -150,7 +150,7 @@
  * dummyret is used to set return values in macros that use ?: to make
  * assignments.  gcc wants these to be void, other compilers like char
  */
-#ifdef __GNUC__					/* GNU cc */
+#if defined(__GNUC__) && !defined(__cplusplus)	/* GNU cc */
 #define dummyret	void
 #else
 #define dummyret	char
diff -r bd5a52b2681a src/include/nodes/makefuncs.h
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -60,7 +60,7 @@
 
 extern TypeName *makeTypeName(char *typnam);
 extern TypeName *makeTypeNameFromNameList(List *names);
-extern TypeName *makeTypeNameFromOid(Oid typeid, int32 typmod);
+extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod);
 
 extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype,
 			 List *args, CoercionForm fformat);
diff -r bd5a52b2681a src/include/nodes/memnodes.h
--- a/src/include/nodes/memnodes.h
+++ b/src/include/nodes/memnodes.h
@@ -41,7 +41,7 @@
 	void	   *(*realloc) (MemoryContext context, void *pointer, Size size);
 	void		(*init) (MemoryContext context);
 	void		(*reset) (MemoryContext context);
-	void		(*delete) (MemoryContext context);
+	void		(*delete_context) (MemoryContext context);
 	Size		(*get_chunk_space) (MemoryContext context, void *pointer);
 	bool		(*is_empty) (MemoryContext context);
 	void		(*stats) (MemoryContext context, int level);
diff -r bd5a52b2681a src/include/nodes/parsenodes.h
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -157,7 +157,7 @@
  *
  * For TypeName structures generated internally, it is often easier to
  * specify the type by OID than by name.  If "names" is NIL then the
- * actual type OID is given by typeid, otherwise typeid is unused.
+ * actual type OID is given by typeOid, otherwise typeOid is unused.
  * Similarly, if "typmods" is NIL then the actual typmod is expected to
  * be prespecified in typemod, otherwise typemod is unused.
  *
@@ -169,7 +169,7 @@
 {
 	NodeTag		type;
 	List	   *names;			/* qualified name (list of Value strings) */
-	Oid			typeid;			/* type identified by OID */
+	Oid			typeOid;		/* type identified by OID */
 	bool		setof;			/* is a set? */
 	bool		pct_type;		/* %TYPE specified? */
 	List	   *typmods;		/* type modifier expression(s) */
@@ -252,7 +252,7 @@
 {
 	NodeTag		type;
 	Node	   *arg;			/* the expression being casted */
-	TypeName   *typename;		/* the target type */
+	TypeName   *typeName;		/* the target type */
 	int			location;		/* token location, or -1 if unknown */
 } TypeCast;
 
@@ -409,7 +409,7 @@
 {
 	NodeTag		type;
 	char	   *colname;		/* name of column */
-	TypeName   *typename;		/* type of column */
+	TypeName   *typeName;		/* type of column */
 	int			inhcount;		/* number of times column is inherited */
 	bool		is_local;		/* column has local (non-inherited) def'n */
 	bool		is_not_null;	/* NOT NULL constraint specified? */
@@ -490,7 +490,7 @@
 	NodeTag		type;
 	XmlOptionType xmloption;	/* DOCUMENT or CONTENT */
 	Node	   *expr;
-	TypeName   *typename;
+	TypeName   *typeName;
 	int			location;		/* token location, or -1 if unknown */
 } XmlSerialize;
 
@@ -1059,7 +1059,7 @@
 								 *	X = drop constraint
 								 *------------
 								 */
-	List	   *typename;		/* domain to work on */
+	List	   *typeName;		/* domain to work on */
 	char	   *name;			/* column or constraint name to act on */
 	Node	   *def;			/* definition of default or constraint */
 	DropBehavior behavior;		/* RESTRICT or CASCADE for DROP cases */
@@ -1459,7 +1459,7 @@
 {
 	NodeTag		type;
 	List	   *domainname;		/* qualified name (list of Value strings) */
-	TypeName   *typename;		/* the base type */
+	TypeName   *typeName;		/* the base type */
 	List	   *constraints;	/* constraints (list of Constraint nodes) */
 } CreateDomainStmt;
 
@@ -1872,7 +1872,7 @@
 typedef struct CreateEnumStmt
 {
 	NodeTag		type;
-	List	   *typename;		/* qualified name (list of Value strings) */
+	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
 } CreateEnumStmt;
 
diff -r bd5a52b2681a src/include/nodes/primnodes.h
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1107,8 +1107,8 @@
 /*----------
  * JoinExpr - for SQL JOIN expressions
  *
- * isNatural, using, and quals are interdependent.	The user can write only
- * one of NATURAL, USING(), or ON() (this is enforced by the grammar).
+ * isNatural, usingClause, and quals are interdependent.  The user can write
+ * only one of NATURAL, USING(), or ON() (this is enforced by the grammar).
  * If he writes NATURAL then parse analysis generates the equivalent USING()
  * list, and from that fills in "quals" with the right equality comparisons.
  * If he writes USING() then "quals" is filled with equality comparisons.
@@ -1132,7 +1132,7 @@
 	bool		isNatural;		/* Natural join? Will need to shape table */
 	Node	   *larg;			/* left subtree */
 	Node	   *rarg;			/* right subtree */
-	List	   *using;			/* USING clause, if any (list of String) */
+	List	   *usingClause;	/* USING clause, if any (list of String) */
 	Node	   *quals;			/* qualifiers on join, if any */
 	Alias	   *alias;			/* user-written alias clause, if any */
 	int			rtindex;		/* RT index assigned for join */
diff -r bd5a52b2681a src/include/parser/parse_type.h
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -19,14 +19,14 @@
 
 typedef HeapTuple Type;
 
-extern Type LookupTypeName(ParseState *pstate, const TypeName *typename,
+extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
 			   int32 *typmod_p);
-extern Type typenameType(ParseState *pstate, const TypeName *typename,
+extern Type typenameType(ParseState *pstate, const TypeName *typeName,
 			 int32 *typmod_p);
-extern Oid typenameTypeId(ParseState *pstate, const TypeName *typename,
+extern Oid typenameTypeId(ParseState *pstate, const TypeName *typeName,
 			   int32 *typmod_p);
 
-extern char *TypeNameToString(const TypeName *typename);
+extern char *TypeNameToString(const TypeName *typeName);
 extern char *TypeNameListToString(List *typenames);
 
 extern Type typeidType(Oid id);
diff -r bd5a52b2681a src/include/utils/builtins.h
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -560,7 +560,7 @@
 extern List *deparse_context_for_plan(Node *plan, Node *outer_plan,
 						 List *rtable, List *subplans);
 extern const char *quote_identifier(const char *ident);
-extern char *quote_qualified_identifier(const char *namespace,
+extern char *quote_qualified_identifier(const char *qualifier,
 						   const char *ident);
 
 /* tid.c */
c++bookends.patchtext/plain; name=c++bookends.patchDownload
diff -r 55d732d0fbcd src/include/executor/spi.h
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -18,6 +18,10 @@
  * included postgres.h
  */
 #include "postgres.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /*
  *	Most of these are not needed by this file, but may be used by
@@ -156,4 +160,8 @@
 extern void AtEOXact_SPI(bool isCommit);
 extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid);
 
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
 #endif   /* SPI_H */
diff -r 55d732d0fbcd src/include/fmgr.h
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -17,6 +17,10 @@
  */
 #ifndef FMGR_H
 #define FMGR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /* We don't want to include primnodes.h here, so make a stub reference */
 typedef struct Node *fmNodePtr;
@@ -544,4 +548,8 @@
  */
 extern char *fmgr(Oid procedureId,...);
 
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
 #endif   /* FMGR_H */
diff -r 55d732d0fbcd src/include/funcapi.h
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -16,11 +16,14 @@
 #ifndef FUNCAPI_H
 #define FUNCAPI_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "fmgr.h"
 #include "access/tupdesc.h"
 #include "executor/executor.h"
 #include "executor/tuptable.h"
-
 
 /*-------------------------------------------------------------------------
  *	Support to ease writing Functions returning composite types
@@ -299,4 +302,8 @@
 		PG_RETURN_NULL(); \
 	} while (0)
 
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
 #endif   /* FUNCAPI_H */
diff -r 55d732d0fbcd src/include/postgres.h
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -44,7 +44,12 @@
 #ifndef POSTGRES_H
 #define POSTGRES_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "c.h"
+
 #include "utils/elog.h"
 #include "utils/palloc.h"
 
@@ -693,4 +698,8 @@
 					 const char *errorType,
 					 const char *fileName, int lineNumber);
 
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
 #endif   /* POSTGRES_H */
c++configure.patchtext/plain; name=c++configure.patchDownload
diff -r 257c0be599ab config/c-compiler.m4
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -103,6 +103,7 @@
 # command-line option. If it does, add the string to CFLAGS.
 AC_DEFUN([PGAC_PROG_CC_CFLAGS_OPT],
 [AC_MSG_CHECKING([if $CC supports $1])
+AC_LANG_ASSERT([C])
 pgac_save_CFLAGS=$CFLAGS
 CFLAGS="$pgac_save_CFLAGS $1"
 _AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
@@ -110,6 +111,23 @@
                    [CFLAGS="$pgac_save_CFLAGS"
                     AC_MSG_RESULT(no)])
 ])# PGAC_PROG_CC_CFLAGS_OPT
+
+
+
+# PGAC_PROG_CXX_CXXFLAGS_OPT
+# -----------------------
+# Given a string, check if the C++ compiler supports the string as a
+# command-line option. If it does, add the string to CXXFLAGS.
+AC_DEFUN([PGAC_PROG_CXX_CXXFLAGS_OPT],
+[AC_MSG_CHECKING([if $CXX supports $1])
+AC_LANG_ASSERT([C++])
+pgac_save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="$pgac_save_CXXFLAGS $1"
+_AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+                   AC_MSG_RESULT(yes),
+                   [CXXFLAGS="$pgac_save_CXXFLAGS"
+                    AC_MSG_RESULT(no)])
+])# PGAC_PROG_CXX_CXXFLAGS_OPT
 
 
 
diff -r 257c0be599ab configure.in
--- a/configure.in
+++ b/configure.in
@@ -195,6 +195,14 @@
 PGAC_ARG_BOOL(enable, debug, no,
               [build with debugging symbols (-g)])
 AC_SUBST(enable_debug)
+
+#
+# --enable-cplusplus links the postgres backend with the C++ runtime library
+#
+PGAC_ARG_BOOL(enable, cplusplus, no, [build with C++ runtime library],
+              [AC_DEFINE([ENABLE_CPLUSPLUS], 1,
+                         [Define to 1 for mixed C/C++ build. (--enable-cplusplus)])])
+AC_SUBST(enable_cplusplus)
 
 #
 # --enable-profiling enables gcc profiling
@@ -365,9 +373,9 @@
 PGAC_ARG_REQ(with, CC, [CMD], [set compiler (deprecated)], [CC=$with_CC])
 
 case $template in
-  aix) pgac_cc_list="gcc xlc";;
- irix) pgac_cc_list="cc";; # no gcc
-    *) pgac_cc_list="gcc cc";;
+  aix) pgac_cc_list="gcc xlc";  pgac_cxx_list="g++ xlC";;
+ irix) pgac_cc_list="cc";       pgac_cxx_list="CC";;            # no gcc
+    *) pgac_cc_list="gcc cc";   pgac_cxx_list="g++ CC";;
 esac
 
 AC_PROG_CC([$pgac_cc_list])
@@ -387,7 +395,15 @@
 
 AC_SUBST(SUN_STUDIO_CC)
 
+#
+# C++ compiler
+#
+AC_PROG_CXX([$pgac_cxx_list])
+AC_PROG_CXXCPP
+AC_SUBST(GXX)
+
 unset CFLAGS
+unset CXXFLAGS
 
 #
 # Read the template
@@ -421,9 +437,8 @@
 # ICC pretends to be GCC but it's lying; it doesn't support these options.
 
 if test "$GCC" = yes -a "$ICC" = no; then
-  CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wpointer-arith"
+  CFLAGS="$CFLAGS -Wall -Wpointer-arith"
   # These work in some but not all gcc versions
-  PGAC_PROG_CC_CFLAGS_OPT([-Wdeclaration-after-statement])
   PGAC_PROG_CC_CFLAGS_OPT([-Wendif-labels])
   # Disable strict-aliasing rules; needed for gcc 3.3+
   PGAC_PROG_CC_CFLAGS_OPT([-fno-strict-aliasing])
@@ -470,12 +485,53 @@
   CPPFLAGS="$CPPFLAGS -I$srcdir/src/include/port/win32 -DEXEC_BACKEND"
 fi
 
+#
+# Initialize C++ flags from CFLAGS unless overridden in environment or template
+#
+if test "$ac_env_CXXFLAGS_set" = set; then
+  CXXFLAGS=$ac_env_CXXFLAGS_value
+elif test "${CXXFLAGS+set}" = set; then
+  : # (keep what template set)
+else
+  CXXFLAGS="$CFLAGS"
+fi
+
+# Some CXXFLAGS are only valid for C++, not for C.  Add them here.
+if test "$GXX" = yes -a "$ICC" = no; then
+  AC_LANG_PUSH([C++])
+  CXXFLAGS="$CXXFLAGS -Wabi"
+  PGAC_PROG_CXX_CXXFLAGS_OPT([-fno-enforce-eh-specs])
+  PGAC_PROG_CXX_CXXFLAGS_OPT([-fno-threadsafe-statics])
+  AC_LANG_POP([C++])
+fi
+
+# Some CFLAGS are only valid for C, not for C++.  Add them here.
+if test "$GCC" = yes -a "$ICC" = no; then
+  CFLAGS="$CFLAGS -Wmissing-prototypes"
+  # These work in some but not all gcc versions
+  PGAC_PROG_CC_CFLAGS_OPT([-Wdeclaration-after-statement])
+fi
+
+
+#
 # Check if the compiler still works with the template settings
+#
 AC_MSG_CHECKING([whether the C compiler still works])
 AC_TRY_LINK([], [return 0;],
   [AC_MSG_RESULT(yes)],
   [AC_MSG_RESULT(no)
    AC_MSG_ERROR([cannot proceed])])
+
+if test "$enable_cplusplus" = yes; then
+  AC_LANG_PUSH([C++])
+  AC_MSG_CHECKING([whether the C++ compiler still works])
+  AC_TRY_LINK([class X {public: bool b; X(bool bb){this->b = bb;}};],
+    [X* x = new X(true);],
+    [AC_MSG_RESULT(yes)],
+    [AC_MSG_RESULT(no)
+     AC_MSG_ERROR([cannot proceed])])
+  AC_LANG_POP([C++])
+fi
 
 # Defend against gcc -ffast-math
 if test "$GCC" = yes; then
@@ -1765,6 +1821,7 @@
 # Begin output steps
 
 AC_MSG_NOTICE([using CFLAGS=$CFLAGS])
+AC_MSG_NOTICE([using CXXFLAGS=$CXXFLAGS])
 AC_MSG_NOTICE([using CPPFLAGS=$CPPFLAGS])
 AC_MSG_NOTICE([using LDFLAGS=$LDFLAGS])
 
diff -r 257c0be599ab doc/src/sgml/installation.sgml
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1261,6 +1261,17 @@
          can be profiled.  On backend exit, a subdirectory will be created
          that contains the <filename>gmon.out</> file for use in profiling.
          This option is for use only with GCC and when doing development work.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><option>--enable-cplusplus</option></term>
+       <listitem>
+        <para>
+         Compiles the <filename>postgres</> server with C++ runtime
+         library support.  Specify this option only if you intend to use or
+         develop server extensions or modifications in the C++ language.
         </para>
        </listitem>
       </varlistentry>
diff -r 257c0be599ab doc/src/sgml/ref/pg_config-ref.sgml
--- a/doc/src/sgml/ref/pg_config-ref.sgml
+++ b/doc/src/sgml/ref/pg_config-ref.sgml
@@ -223,6 +223,27 @@
     </varlistentry>
 
     <varlistentry>
+     <term><option>--cxx</option></>
+     <listitem>
+      <para>
+       Print the value of the <varname>CXX</varname> variable showing the C++
+       compiler that was used for building C++ modules (if any) in the
+       <productname>PostgreSQL</> backend.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><option>--cxxflags</option></>
+     <listitem>
+      <para>
+       Print the value of the <varname>CXXFLAGS</varname> variable that was used for building
+       <productname>PostgreSQL</>.  This shows C++ compiler switches.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
      <term><option>--ldflags</option></>
      <listitem>
       <para>
diff -r 257c0be599ab src/Makefile.global.in
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -164,6 +164,7 @@
 enable_debug	= @enable_debug@
 enable_dtrace	= @enable_dtrace@
 enable_coverage	= @enable_coverage@
+enable_cplusplus	= @enable_cplusplus@
 enable_thread_safety	= @enable_thread_safety@
 
 python_includespec	= @python_includespec@
@@ -214,6 +215,21 @@
 GCC = @GCC@
 SUN_STUDIO_CC = @SUN_STUDIO_CC@
 CFLAGS = @CFLAGS@
+
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+GXX = @GXX@
+
+# gmake predefines these and uses them in its predefined implicit rules.
+# We include them here just in case someone uses a version of gmake which
+# doesn't have them built in.  These are as defined by gmake 3.81.
+COMPILE.c   ?= $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
+LINK.c      ?= $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
+COMPILE.cc  ?= $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
+LINK.cc     ?= $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
+COMPILE.cpp ?= $(COMPILE.cc)
+LINK.cpp    ?= $(LINK.cc)
 
 # Kind-of compilers
 
@@ -545,18 +561,25 @@
 
 ifeq ($(autodepend), yes)
 
-ifndef COMPILE.c
-COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c
-endif
-
 DEPDIR = .deps
+DEPMKDIR = @if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi
 
 ifeq ($(GCC), yes)
 
 # GCC allows us to create object and dependency file in one invocation.
+DEPFLAGS = -MMD -MP -MF $(DEPDIR)/$(*F).Po
+
 %.o : %.c
-	@if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi
-	$(COMPILE.c) -o $@ $< -MMD -MP -MF $(DEPDIR)/$(*F).Po
+	$(DEPMKDIR)
+	$(COMPILE.c) $(DEPFLAGS) -o $@ $<
+
+%.o : %.cc
+	$(DEPMKDIR)
+	$(COMPILE.cc) $(DEPFLAGS) -o $@ $<
+
+%.o: %.cpp
+	$(DEPMKDIR)
+	$(COMPILE.cpp) $(DEPFLAGS) -o $@ $<
 
 endif # GCC
 
diff -r 257c0be599ab src/backend/Makefile
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -43,7 +43,12 @@
 ifneq ($(PORTNAME), aix)
 
 postgres: $(OBJS)
+ifeq ($(enable_cplusplus), yes)
+	# Link with C++ runtime support
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o $@
+else
 	$(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o $@
+endif
 
 endif
 endif
@@ -111,7 +116,12 @@
 # The postgres.o target is needed by the rule in Makefile.global that
 # creates the exports file when MAKE_EXPORTS = true.
 postgres.o: $(OBJS)
+ifeq ($(enable_cplusplus), yes)
+	# Link with C++ runtime support
+	$(CXX) $(LDREL) $(LDFLAGS) $(call expand_subsys,$^) $(LIBS) -o $@
+else
 	$(CC) $(LDREL) $(LDFLAGS) $(call expand_subsys,$^) $(LIBS) -o $@
+endif
 
 
 # The following targets are specified in make commands that appear in
@@ -268,4 +278,9 @@
 # are up to date.  It saves the time of doing all the submakes.
 .PHONY: quick
 quick: $(OBJS)
+ifeq ($(enable_cplusplus), yes)
+	# Link with C++ runtime support
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o postgres
+else
 	$(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o postgres
+endif
diff -r 257c0be599ab src/backend/common.mk
--- a/src/backend/common.mk
+++ b/src/backend/common.mk
@@ -6,7 +6,7 @@
 
 # When including this file, set OBJS to the object files created in
 # this directory and SUBDIRS to subdirectories containing more things
-# to build.
+# to build.  Set CXXOBJS to the subset of OBJS which are to be C++ compiled.
 
 ifdef PARTIAL_LINKING
 # old style: linking using SUBSYS.o
@@ -36,6 +36,11 @@
 # Parallel make trickery
 $(SUBDIROBJS): $(SUBDIRS:%=%-recursive) ;
 
+# For .o files listed in CXXOBJS, use C++ compiler to make .o from .c
+$(CXXOBJS) : %.o: %.c
+	$(DEPMKDIR)
+	$(COMPILE.cc) $(DEPFLAGS) -o $@ $<
+
 .PHONY: $(SUBDIRS:%=%-recursive)
 $(SUBDIRS:%=%-recursive):
 	$(MAKE) -C $(subst -recursive,,$@) all
diff -r 257c0be599ab src/backend/main/Makefile
--- a/src/backend/main/Makefile
+++ b/src/backend/main/Makefile
@@ -14,4 +14,11 @@
 
 OBJS = main.o
 
+# If "configure --enable-cplusplus" was specified, make list of modules
+# which are to be compiled as C++.  The main() function should be compiled as
+# C++ to ensure proper initialization of the mixed C/C++ runtime environment.
+ifeq ($(enable_cplusplus),yes)
+CXXOBJS = main.o
+endif
+
 include $(top_srcdir)/src/backend/common.mk
diff -r 257c0be599ab src/backend/main/main.c
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -34,6 +34,14 @@
 #include <sys/param.h>
 #endif
 
+#if defined(ENABLE_CPLUSPLUS) && !defined(__cplusplus)
+#error --enable-cplusplus configure option specified; this file should be compiled as C++
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "bootstrap/bootstrap.h"
 #include "postmaster/postmaster.h"
 #include "tcop/tcopprot.h"
@@ -42,6 +50,10 @@
 #include "utils/ps_status.h"
 #ifdef WIN32
 #include "libpq/pqsignal.h"
+#endif
+
+#ifdef __cplusplus
+}   /* extern "C" */
 #endif
 
 
diff -r 257c0be599ab src/bin/pg_config/Makefile
--- a/src/bin/pg_config/Makefile
+++ b/src/bin/pg_config/Makefile
@@ -24,6 +24,8 @@
 override CPPFLAGS += -DVAL_CPPFLAGS="\"$(STD_CPPFLAGS)\""
 override CPPFLAGS += -DVAL_CFLAGS="\"$(CFLAGS)\""
 override CPPFLAGS += -DVAL_CFLAGS_SL="\"$(CFLAGS_SL)\""
+override CPPFLAGS += -DVAL_CXX="\"$(CXX)\""
+override CPPFLAGS += -DVAL_CXXFLAGS="\"$(CXXFLAGS)\""
 override CPPFLAGS += -DVAL_LDFLAGS="\"$(STD_LDFLAGS)\""
 override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
 override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
diff -r 257c0be599ab src/bin/pg_config/pg_config.c
--- a/src/bin/pg_config/pg_config.c
+++ b/src/bin/pg_config/pg_config.c
@@ -311,6 +311,38 @@
 }
 
 static void
+show_cxx(bool all)
+{
+#ifdef VAL_CXX
+	if (all)
+		printf("CXX = ");
+	printf("%s\n", VAL_CXX);
+#else
+	if (!all)
+	{
+		fprintf(stderr, _("not recorded\n"));
+		exit(1);
+	}
+#endif
+}
+
+static void
+show_cxxflags(bool all)
+{
+#ifdef VAL_CXXFLAGS
+	if (all)
+		printf("CXXFLAGS = ");
+	printf("%s\n", VAL_CXXFLAGS);
+#else
+	if (!all)
+	{
+		fprintf(stderr, _("not recorded\n"));
+		exit(1);
+	}
+#endif
+}
+
+static void
 show_ldflags(bool all)
 {
 #ifdef VAL_LDFLAGS
@@ -397,6 +429,8 @@
 	{"--cppflags", show_cppflags},
 	{"--cflags", show_cflags},
 	{"--cflags_sl", show_cflags_sl},
+	{"--cxx", show_cxx},
+	{"--cxxflags", show_cxxflags},
 	{"--ldflags", show_ldflags},
 	{"--ldflags_sl", show_ldflags_sl},
 	{"--libs", show_libs},
@@ -432,6 +466,8 @@
 	printf(_("  --cppflags            show CPPFLAGS value used when PostgreSQL was built\n"));
 	printf(_("  --cflags              show CFLAGS value used when PostgreSQL was built\n"));
 	printf(_("  --cflags_sl           show CFLAGS_SL value used when PostgreSQL was built\n"));
+	printf(_("  --cxx                 show CXX value used when PostgreSQL was built\n"));
+	printf(_("  --cxxflags            show CXXFLAGS value used when PostgreSQL was built\n"));
 	printf(_("  --ldflags             show LDFLAGS value used when PostgreSQL was built\n"));
 	printf(_("  --ldflags_sl          show LDFLAGS_SL value used when PostgreSQL was built\n"));
 	printf(_("  --libs                show LIBS value used when PostgreSQL was built\n"));
diff -r 257c0be599ab src/include/pg_config.h.in
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -44,6 +44,9 @@
 
 /* Define to the default TCP port number as a string constant. */
 #undef DEF_PGPORT_STR
+
+/* Define to 1 for mixed C/C++ build. (--enable-cplusplus) */
+#undef ENABLE_CPLUSPLUS
 
 /* Define to 1 to enable DTrace support. (--enable-dtrace) */
 #undef ENABLE_DTRACE
c++exception.patchtext/plain; name=c++exception.patchDownload
diff -r 9b2c774a6b05 src/backend/tcop/Makefile
--- a/src/backend/tcop/Makefile
+++ b/src/backend/tcop/Makefile
@@ -14,6 +14,11 @@

 OBJS= dest.o fastpath.o postgres.o pquery.o utility.o

+# Designate modules to be compiled as C++ when 'configure --enable-cplusplus'
+ifeq ($(enable_cplusplus),yes)
+CXXOBJS = postgres.o
+endif
+
 ifneq (,$(filter $(PORTNAME),cygwin win32))
 override CPPFLAGS += -DWIN32_STACK_RLIMIT=$(WIN32_STACK_RLIMIT)
 endif
diff -r 9b2c774a6b05 src/backend/tcop/postgres.c
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -33,6 +33,17 @@
 #endif
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
+#endif
+
+#ifdef ENABLE_CPLUSPLUS
+#ifndef __cplusplus
+#error --enable-cplusplus configure option specified; this file should be compiled as C++
+#endif
+#include <exception>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
 #endif

 #ifndef HAVE_GETRUSAGE
@@ -163,6 +174,11 @@
 #endif   /* TCOP_DONTUSENEWLINE */


+#ifdef __cplusplus
+}                               /* extern "C" */
+#endif
+
+
 /* ----------------------------------------------------------------
  *		decls for routines only used in this file
  * ----------------------------------------------------------------
@@ -1212,7 +1228,7 @@
 		if (log_parser_stats)
 			ResetUsage();

-		query = parse_analyze_varparams(copyObject(raw_parse_tree),
+		query = parse_analyze_varparams((Node *)copyObject(raw_parse_tree),
 										query_string,
 										&paramTypes,
 										&numParams);
@@ -1679,7 +1695,7 @@
 		 * we have to make a copy of the parse trees.  FIXME someday.
 		 */
 		oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
-		query_list = copyObject(cplan->stmt_list);
+		query_list = (List *)copyObject(cplan->stmt_list);
 		plan_list = pg_plan_queries(query_list, 0, params, true);
 		MemoryContextSwitchTo(oldContext);

@@ -2791,6 +2807,29 @@

 	return NULL;
 }
+
+
+#ifdef ENABLE_CPLUSPLUS
+/*
+ * PostgresMainUncaught
+ *      Called when C++ code throws an exception which is not caught.
+ *
+ * NB: On some platforms when C++ code calls C code, and the C code calls
+ * a deeper layer of C++ code, the outer C++ code can't catch exceptions
+ * thrown by the inner C++ code.  The search for a matching 'catch' is
+ * abandoned upon encountering an intervening C stack frame, and the
+ * exception is considered uncaught.
+ */
+static void
+PostgresMainUncaught()
+{
+    /* Context callbacks might not work right if call stack has been unwound */
+    error_context_stack = NULL;
+
+    elog(FATAL, "Unexpected internal error: Unhandled C++ exception");
+    abort();                                /* not reached */
+}
+#endif  /* ENABLE_CPLUSPLUS */


 /* ----------------------------------------------------------------
@@ -2850,6 +2889,11 @@
 	/* Set up reference point for stack depth checking */
 	stack_base_ptr = &stack_base;

+#ifdef ENABLE_CPLUSPLUS
+    /* Any unhandled C++ exception is to be treated as a FATAL error. */
+    std::set_terminate(PostgresMainUncaught);
+#endif
+
 	/* Compute paths, if we didn't inherit them from postmaster */
 	if (my_exec_path[0] == '\0')
 	{
@@ -3108,10 +3152,10 @@
 			char	   *name;
 			char	   *value;

-			name = lfirst(gucopts);
+			name = (char *)lfirst(gucopts);
 			gucopts = lnext(gucopts);

-			value = lfirst(gucopts);
+			value = (char *)lfirst(gucopts);
 			gucopts = lnext(gucopts);

 			if (IsSuperuserConfigOption(name))
#2Peter Eisentraut
peter_e@gmx.net
In reply to: Kurt Harriman (#1)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman wrote:

Sometimes people would like to call C++ code in the PostgreSQL
backend environment... for example, in user-defined functions,
triggers, access methods. And there is sometimes a need for
C++ code to call back into PostgreSQL's C functions, such as
the SPI interface.

Have you considered writing a procedural language plugin for C++?
PostgreSQL supports a lot of extension languages, and none of them
require the amount of backend changes that you outline here, because the
PL plugin serves as glue.

#3Greg Smith
gsmith@gregsmith.com
In reply to: Kurt Harriman (#1)
Re: Mostly Harmless: Welcoming our C++ friends

A seriously substantial portion of the diff for this patch all is
supporting trivial renaming, like changing everything that uses:

-       TypeName   *typename = (TypeName *) cmd->def;
+       TypeName   *typeName = (TypeName *) cmd->def;

Is that really necessary? After going through a few pages of diff code
where supporting this trivial bit was the only change, my eyes glazed
over. Minimizing diff size makes it much more likely somebody will
complete a review of the functional parts of your submission before
getting bored.

If it is needed, I'd suggest you'd get a warmer reception here submitting
two diffs, one that just did the renaming and a second that actually had
the functional bits in it. Then it would be possible to casually scan the
renaming one for a second to see it was trivial and boring, followed by a
review of the functional one that was focused on its real changes.

--
* Greg Smith gsmith@gregsmith.com http://www.gregsmith.com Baltimore, MD

#4Kurt Harriman
harriman@acm.org
In reply to: Greg Smith (#3)
Re: Mostly Harmless: Welcoming our C++ friends

Hi Greg,

Actually I did email this to the list with 4 separate diffs in
4 separate attached files. I don't know why it appears all
massed together at http://archives.postgresql.org/pgsql-hackers.
I'll try resubmitting them separately. The first diff consists
of just the renaming, which is intentionally trivial and boring.
The second diff adds a few extern "C" {...} declarations - also
trivial and boring, but small. The interesting part is in the
third diff.

Regards,
... kurt

Greg Smith wrote:

Show quoted text

A seriously substantial portion of the diff for this patch all is
supporting trivial renaming, like changing everything that uses:

-       TypeName   *typename = (TypeName *) cmd->def;
+       TypeName   *typeName = (TypeName *) cmd->def;

Is that really necessary? After going through a few pages of diff code
where supporting this trivial bit was the only change, my eyes glazed
over. Minimizing diff size makes it much more likely somebody will
complete a review of the functional parts of your submission before
getting bored.

If it is needed, I'd suggest you'd get a warmer reception here
submitting two diffs, one that just did the renaming and a second that
actually had the functional bits in it. Then it would be possible to
casually scan the renaming one for a second to see it was trivial and
boring, followed by a review of the functional one that was focused on
its real changes.

--
* Greg Smith gsmith@gregsmith.com http://www.gregsmith.com Baltimore, MD

#5Greg Smith
gsmith@gregsmith.com
In reply to: Greg Smith (#3)
Re: Mostly Harmless: Welcoming our C++ friends

On Fri, 5 Dec 2008, Greg Smith wrote:

If it is needed, I'd suggest you'd get a warmer reception here submitting two
diffs, one that just did the renaming and a second that actually had the
functional bits in it.

You can just ignore this late night bit of idiocy, or mock me for it as
you see fit. Note to other reviewers: if your e-mail client is the sort
that bunches a series of text attachments all together, make sure to
scroll completely past the first patch in the diff before you pay
attention to the rest of it. I'm going to bed.

--
* Greg Smith gsmith@gregsmith.com http://www.gregsmith.com Baltimore, MD

#6Kurt Harriman
harriman@acm.org
In reply to: Kurt Harriman (#1)
1 attachment(s)
Re: Mostly Harmless: c++reserved - patch 1 of 4

(Re-sending just the first of four patches: c++reserved)

These patches are based on CVS head in which the latest commit was
user: petere
date: Thu Dec 04 17:51:28 2008 +0000
summary: Default values for function arguments

1. c++reserved

User-defined functions and extensions may need to access
backend data structures such as parse trees. A few of the
relevant header files contain field or parameter names
which happen to be C++ reserved words. This makes them
unusable from C++ because the compiler chokes on the
reserved word. It has been suggested that the C++ user
could surround these #includes with #defines to substitute
innocuous words for the reserved words; but that would be
unbearably kludgy, error prone and unmaintainable. A polite
host does not demand such things of a guest.

Fortunately, there are not many instances which are likely
to be encountered by our C++ guests, and these can easily
be changed. In memnodes.h, parsenodes.h, and primnodes.h,
this patch changes the following field names:

typename => typeName
typeid => typeOid
using => usingClause
delete => delete_context

Also, the patch changes a few parameter names in function
prototypes in makefuncs.h, parse_type.h, and builtins.h:

typename => typeName
typeid => typeOid
namespace => qualifier

There's no need to ask PostgreSQL developers to remember to
avoid C++ reserved words, because C++ users who are affected
by such occurrences can be asked to submit a corrective patch.

Attachments:

c++reserved.patchtext/plain; name=c++reserved.patchDownload
diff -r bd5a52b2681a src/backend/access/common/tupdesc.c
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -532,10 +532,10 @@
 		attnum++;
 
 		attname = entry->colname;
-		atttypid = typenameTypeId(NULL, entry->typename, &atttypmod);
-		attdim = list_length(entry->typename->arrayBounds);
+		atttypid = typenameTypeId(NULL, entry->typeName, &atttypmod);
+		attdim = list_length(entry->typeName->arrayBounds);
 
-		if (entry->typename->setof)
+		if (entry->typeName->setof)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 					 errmsg("column \"%s\" cannot be declared SETOF",
diff -r bd5a52b2681a src/backend/commands/sequence.c
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -141,53 +141,53 @@
 		switch (i)
 		{
 			case SEQ_COL_NAME:
-				coldef->typename = makeTypeNameFromOid(NAMEOID, -1);
+				coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
 				coldef->colname = "sequence_name";
 				namestrcpy(&name, seq->sequence->relname);
 				value[i - 1] = NameGetDatum(&name);
 				break;
 			case SEQ_COL_LASTVAL:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "last_value";
 				value[i - 1] = Int64GetDatumFast(new.last_value);
 				break;
 			case SEQ_COL_STARTVAL:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "start_value";
 				value[i - 1] = Int64GetDatumFast(new.start_value);
 				break;
 			case SEQ_COL_INCBY:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "increment_by";
 				value[i - 1] = Int64GetDatumFast(new.increment_by);
 				break;
 			case SEQ_COL_MAXVALUE:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "max_value";
 				value[i - 1] = Int64GetDatumFast(new.max_value);
 				break;
 			case SEQ_COL_MINVALUE:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "min_value";
 				value[i - 1] = Int64GetDatumFast(new.min_value);
 				break;
 			case SEQ_COL_CACHE:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "cache_value";
 				value[i - 1] = Int64GetDatumFast(new.cache_value);
 				break;
 			case SEQ_COL_LOG:
-				coldef->typename = makeTypeNameFromOid(INT8OID, -1);
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
 				coldef->colname = "log_cnt";
 				value[i - 1] = Int64GetDatum((int64) 1);
 				break;
 			case SEQ_COL_CYCLE:
-				coldef->typename = makeTypeNameFromOid(BOOLOID, -1);
+				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
 				coldef->colname = "is_cycled";
 				value[i - 1] = BoolGetDatum(new.is_cycled);
 				break;
 			case SEQ_COL_CALLED:
-				coldef->typename = makeTypeNameFromOid(BOOLOID, -1);
+				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
 				coldef->colname = "is_called";
 				value[i - 1] = BoolGetDatum(false);
 				break;
diff -r bd5a52b2681a src/backend/commands/tablecmds.c
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -303,7 +303,7 @@
 					  bool recurse, bool recursing,
 					  AlterTableCmd *cmd);
 static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
-					  const char *colName, TypeName *typename);
+					  const char *colName, TypeName *typeName);
 static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab);
 static void ATPostAlterTypeParse(char *cmd, List **wqueue);
 static void change_owner_recurse_to_sequences(Oid relationOid,
@@ -1251,7 +1251,7 @@
 						(errmsg("merging multiple inherited definitions of column \"%s\"",
 								attributeName)));
 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
-				defTypeId = typenameTypeId(NULL, def->typename, &deftypmod);
+				defTypeId = typenameTypeId(NULL, def->typeName, &deftypmod);
 				if (defTypeId != attribute->atttypid ||
 					deftypmod != attribute->atttypmod)
 					ereport(ERROR,
@@ -1259,7 +1259,7 @@
 						errmsg("inherited column \"%s\" has a type conflict",
 							   attributeName),
 							 errdetail("%s versus %s",
-									   TypeNameToString(def->typename),
+									   TypeNameToString(def->typeName),
 									   format_type_be(attribute->atttypid))));
 				def->inhcount++;
 				/* Merge of NOT NULL constraints = OR 'em together */
@@ -1274,7 +1274,7 @@
 				 */
 				def = makeNode(ColumnDef);
 				def->colname = pstrdup(attributeName);
-				def->typename = makeTypeNameFromOid(attribute->atttypid,
+				def->typeName = makeTypeNameFromOid(attribute->atttypid,
 													attribute->atttypmod);
 				def->inhcount = 1;
 				def->is_local = false;
@@ -1409,16 +1409,16 @@
 				   (errmsg("merging column \"%s\" with inherited definition",
 						   attributeName)));
 				def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
-				defTypeId = typenameTypeId(NULL, def->typename, &deftypmod);
-				newTypeId = typenameTypeId(NULL, newdef->typename, &newtypmod);
+				defTypeId = typenameTypeId(NULL, def->typeName, &deftypmod);
+				newTypeId = typenameTypeId(NULL, newdef->typeName, &newtypmod);
 				if (defTypeId != newTypeId || deftypmod != newtypmod)
 					ereport(ERROR,
 							(errcode(ERRCODE_DATATYPE_MISMATCH),
 							 errmsg("column \"%s\" has a type conflict",
 									attributeName),
 							 errdetail("%s versus %s",
-									   TypeNameToString(def->typename),
-									   TypeNameToString(newdef->typename))));
+									   TypeNameToString(def->typeName),
+									   TypeNameToString(newdef->typeName))));
 				/* Mark the column as locally defined */
 				def->is_local = true;
 				/* Merge of NOT NULL constraints = OR 'em together */
@@ -3480,7 +3480,7 @@
 			int32		ctypmod;
 
 			/* Okay if child matches by type */
-			ctypeId = typenameTypeId(NULL, colDef->typename, &ctypmod);
+			ctypeId = typenameTypeId(NULL, colDef->typeName, &ctypmod);
 			if (ctypeId != childatt->atttypid ||
 				ctypmod != childatt->atttypmod)
 				ereport(ERROR,
@@ -3535,7 +3535,7 @@
 						MaxHeapAttributeNumber)));
 	i = minattnum + 1;
 
-	typeTuple = typenameType(NULL, colDef->typename, &typmod);
+	typeTuple = typenameType(NULL, colDef->typeName, &typmod);
 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
 	typeOid = HeapTupleGetOid(typeTuple);
 
@@ -3551,7 +3551,7 @@
 	attribute.atttypmod = typmod;
 	attribute.attnum = i;
 	attribute.attbyval = tform->typbyval;
-	attribute.attndims = list_length(colDef->typename->arrayBounds);
+	attribute.attndims = list_length(colDef->typeName->arrayBounds);
 	attribute.attstorage = tform->typstorage;
 	attribute.attalign = tform->typalign;
 	attribute.attnotnull = colDef->is_not_null;
@@ -5415,7 +5415,7 @@
 					  AlterTableCmd *cmd)
 {
 	char	   *colName = cmd->name;
-	TypeName   *typename = (TypeName *) cmd->def;
+	TypeName   *typeName = (TypeName *) cmd->def;
 	HeapTuple	tuple;
 	Form_pg_attribute attTup;
 	AttrNumber	attnum;
@@ -5450,7 +5450,7 @@
 						colName)));
 
 	/* Look up the target type */
-	targettype = typenameTypeId(NULL, typename, &targettypmod);
+	targettype = typenameTypeId(NULL, typeName, &targettypmod);
 
 	/* make sure datatype is legal for a column */
 	CheckAttributeType(colName, targettype);
@@ -5541,7 +5541,7 @@
 
 static void
 ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
-					  const char *colName, TypeName *typename)
+					  const char *colName, TypeName *typeName)
 {
 	HeapTuple	heapTup;
 	Form_pg_attribute attTup;
@@ -5578,7 +5578,7 @@
 						colName)));
 
 	/* Look up the target type (should not fail, since prep found it) */
-	typeTuple = typenameType(NULL, typename, &targettypmod);
+	typeTuple = typenameType(NULL, typeName, &targettypmod);
 	tform = (Form_pg_type) GETSTRUCT(typeTuple);
 	targettype = HeapTupleGetOid(typeTuple);
 
@@ -5825,7 +5825,7 @@
 	 */
 	attTup->atttypid = targettype;
 	attTup->atttypmod = targettypmod;
-	attTup->attndims = list_length(typename->arrayBounds);
+	attTup->attndims = list_length(typeName->arrayBounds);
 	attTup->attlen = tform->typlen;
 	attTup->attbyval = tform->typbyval;
 	attTup->attalign = tform->typalign;
diff -r bd5a52b2681a src/backend/commands/typecmds.c
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -676,7 +676,7 @@
 	bool		saw_default = false;
 	bool		typNotNull = false;
 	bool		nullDefined = false;
-	int32		typNDims = list_length(stmt->typename->arrayBounds);
+	int32		typNDims = list_length(stmt->typeName->arrayBounds);
 	HeapTuple	typeTup;
 	List	   *schema = stmt->constraints;
 	ListCell   *listptr;
@@ -716,7 +716,7 @@
 	/*
 	 * Look up the base type.
 	 */
-	typeTup = typenameType(NULL, stmt->typename, &basetypeMod);
+	typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
 	baseType = (Form_pg_type) GETSTRUCT(typeTup);
 	basetypeoid = HeapTupleGetOid(typeTup);
 
@@ -732,7 +732,7 @@
 		ereport(ERROR,
 				(errcode(ERRCODE_DATATYPE_MISMATCH),
 				 errmsg("\"%s\" is not a valid base type for a domain",
-						TypeNameToString(stmt->typename))));
+						TypeNameToString(stmt->typeName))));
 
 	/* passed by value */
 	byValue = baseType->typbyval;
@@ -1013,7 +1013,7 @@
 	Relation	pg_type;
 
 	/* Convert list of names to a name and namespace */
-	enumNamespace = QualifiedNameGetCreationNamespace(stmt->typename,
+	enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
 													  &enumName);
 
 	/* Check we have creation rights in target namespace */
diff -r bd5a52b2681a src/backend/commands/view.c
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -118,7 +118,7 @@
 			ColumnDef  *def = makeNode(ColumnDef);
 
 			def->colname = pstrdup(tle->resname);
-			def->typename = makeTypeNameFromOid(exprType((Node *) tle->expr),
+			def->typeName = makeTypeNameFromOid(exprType((Node *) tle->expr),
 											 exprTypmod((Node *) tle->expr));
 			def->inhcount = 0;
 			def->is_local = true;
diff -r bd5a52b2681a src/backend/nodes/copyfuncs.c
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1491,7 +1491,7 @@
 	COPY_SCALAR_FIELD(isNatural);
 	COPY_NODE_FIELD(larg);
 	COPY_NODE_FIELD(rarg);
-	COPY_NODE_FIELD(using);
+	COPY_NODE_FIELD(usingClause);
 	COPY_NODE_FIELD(quals);
 	COPY_NODE_FIELD(alias);
 	COPY_SCALAR_FIELD(rtindex);
@@ -1915,7 +1915,7 @@
 	TypeName   *newnode = makeNode(TypeName);
 
 	COPY_NODE_FIELD(names);
-	COPY_SCALAR_FIELD(typeid);
+	COPY_SCALAR_FIELD(typeOid);
 	COPY_SCALAR_FIELD(setof);
 	COPY_SCALAR_FIELD(pct_type);
 	COPY_NODE_FIELD(typmods);
@@ -1969,7 +1969,7 @@
 	TypeCast   *newnode = makeNode(TypeCast);
 
 	COPY_NODE_FIELD(arg);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
@@ -1995,7 +1995,7 @@
 	ColumnDef  *newnode = makeNode(ColumnDef);
 
 	COPY_STRING_FIELD(colname);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_SCALAR_FIELD(inhcount);
 	COPY_SCALAR_FIELD(is_local);
 	COPY_SCALAR_FIELD(is_not_null);
@@ -2052,7 +2052,7 @@
 
 	COPY_SCALAR_FIELD(xmloption);
 	COPY_NODE_FIELD(expr);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
@@ -2204,7 +2204,7 @@
 	AlterDomainStmt *newnode = makeNode(AlterDomainStmt);
 
 	COPY_SCALAR_FIELD(subtype);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_STRING_FIELD(name);
 	COPY_NODE_FIELD(def);
 	COPY_SCALAR_FIELD(behavior);
@@ -2622,7 +2622,7 @@
 {
 	CreateEnumStmt *newnode = makeNode(CreateEnumStmt);
 
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
 
 	return newnode;
@@ -2657,7 +2657,7 @@
 	CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
 
 	COPY_NODE_FIELD(domainname);
-	COPY_NODE_FIELD(typename);
+	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(constraints);
 
 	return newnode;
diff -r bd5a52b2681a src/backend/nodes/equalfuncs.c
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -688,7 +688,7 @@
 	COMPARE_SCALAR_FIELD(isNatural);
 	COMPARE_NODE_FIELD(larg);
 	COMPARE_NODE_FIELD(rarg);
-	COMPARE_NODE_FIELD(using);
+	COMPARE_NODE_FIELD(usingClause);
 	COMPARE_NODE_FIELD(quals);
 	COMPARE_NODE_FIELD(alias);
 	COMPARE_SCALAR_FIELD(rtindex);
@@ -957,7 +957,7 @@
 _equalAlterDomainStmt(AlterDomainStmt *a, AlterDomainStmt *b)
 {
 	COMPARE_SCALAR_FIELD(subtype);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_STRING_FIELD(name);
 	COMPARE_NODE_FIELD(def);
 	COMPARE_SCALAR_FIELD(behavior);
@@ -1311,7 +1311,7 @@
 static bool
 _equalCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
 {
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
 
 	return true;
@@ -1340,7 +1340,7 @@
 _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
 {
 	COMPARE_NODE_FIELD(domainname);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(constraints);
 
 	return true;
@@ -1852,7 +1852,7 @@
 _equalTypeName(TypeName *a, TypeName *b)
 {
 	COMPARE_NODE_FIELD(names);
-	COMPARE_SCALAR_FIELD(typeid);
+	COMPARE_SCALAR_FIELD(typeOid);
 	COMPARE_SCALAR_FIELD(setof);
 	COMPARE_SCALAR_FIELD(pct_type);
 	COMPARE_NODE_FIELD(typmods);
@@ -1867,7 +1867,7 @@
 _equalTypeCast(TypeCast *a, TypeCast *b)
 {
 	COMPARE_NODE_FIELD(arg);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
@@ -1920,7 +1920,7 @@
 _equalColumnDef(ColumnDef *a, ColumnDef *b)
 {
 	COMPARE_STRING_FIELD(colname);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_SCALAR_FIELD(inhcount);
 	COMPARE_SCALAR_FIELD(is_local);
 	COMPARE_SCALAR_FIELD(is_not_null);
@@ -2062,7 +2062,7 @@
 {
 	COMPARE_SCALAR_FIELD(xmloption);
 	COMPARE_NODE_FIELD(expr);
-	COMPARE_NODE_FIELD(typename);
+	COMPARE_NODE_FIELD(typeName);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
diff -r bd5a52b2681a src/backend/nodes/makefuncs.c
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -316,11 +316,11 @@
  *	build a TypeName node to represent a type already known by OID/typmod.
  */
 TypeName *
-makeTypeNameFromOid(Oid typeid, int32 typmod)
+makeTypeNameFromOid(Oid typeOid, int32 typmod)
 {
 	TypeName   *n = makeNode(TypeName);
 
-	n->typeid = typeid;
+	n->typeOid = typeOid;
 	n->typemod = typmod;
 	n->location = -1;
 	return n;
diff -r bd5a52b2681a src/backend/nodes/nodeFuncs.c
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -860,7 +860,7 @@
 				 * so any of the components might be leftmost.
 				 */
 				loc = exprLocation(tc->arg);
-				loc = leftmostLoc(loc, tc->typename->location);
+				loc = leftmostLoc(loc, tc->typeName->location);
 				loc = leftmostLoc(loc, tc->location);
 			}
 			break;
@@ -2359,7 +2359,7 @@
 
 				if (walker(tc->arg, context))
 					return true;
-				if (walker(tc->typename, context))
+				if (walker(tc->typeName, context))
 					return true;
 			}
 			break;
@@ -2400,7 +2400,7 @@
 			{
 				ColumnDef *coldef = (ColumnDef *) node;
 
-				if (walker(coldef->typename, context))
+				if (walker(coldef->typeName, context))
 					return true;
 				if (walker(coldef->raw_default, context))
 					return true;
@@ -2415,7 +2415,7 @@
 
 				if (walker(xs->expr, context))
 					return true;
-				if (walker(xs->typename, context))
+				if (walker(xs->typeName, context))
 					return true;
 			}
 			break;
diff -r bd5a52b2681a src/backend/nodes/outfuncs.c
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1207,7 +1207,7 @@
 	WRITE_BOOL_FIELD(isNatural);
 	WRITE_NODE_FIELD(larg);
 	WRITE_NODE_FIELD(rarg);
-	WRITE_NODE_FIELD(using);
+	WRITE_NODE_FIELD(usingClause);
 	WRITE_NODE_FIELD(quals);
 	WRITE_NODE_FIELD(alias);
 	WRITE_INT_FIELD(rtindex);
@@ -1772,7 +1772,7 @@
 
 	WRITE_ENUM_FIELD(xmloption, XmlOptionType);
 	WRITE_NODE_FIELD(expr);
-	WRITE_NODE_FIELD(typename);
+	WRITE_NODE_FIELD(typeName);
 	WRITE_LOCATION_FIELD(location);
 }
 
@@ -1782,7 +1782,7 @@
 	WRITE_NODE_TYPE("COLUMNDEF");
 
 	WRITE_STRING_FIELD(colname);
-	WRITE_NODE_FIELD(typename);
+	WRITE_NODE_FIELD(typeName);
 	WRITE_INT_FIELD(inhcount);
 	WRITE_BOOL_FIELD(is_local);
 	WRITE_BOOL_FIELD(is_not_null);
@@ -1797,7 +1797,7 @@
 	WRITE_NODE_TYPE("TYPENAME");
 
 	WRITE_NODE_FIELD(names);
-	WRITE_OID_FIELD(typeid);
+	WRITE_OID_FIELD(typeOid);
 	WRITE_BOOL_FIELD(setof);
 	WRITE_BOOL_FIELD(pct_type);
 	WRITE_NODE_FIELD(typmods);
@@ -1812,7 +1812,7 @@
 	WRITE_NODE_TYPE("TYPECAST");
 
 	WRITE_NODE_FIELD(arg);
-	WRITE_NODE_FIELD(typename);
+	WRITE_NODE_FIELD(typeName);
 	WRITE_LOCATION_FIELD(location);
 }
 
diff -r bd5a52b2681a src/backend/nodes/readfuncs.c
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -984,7 +984,7 @@
 	READ_BOOL_FIELD(isNatural);
 	READ_NODE_FIELD(larg);
 	READ_NODE_FIELD(rarg);
-	READ_NODE_FIELD(using);
+	READ_NODE_FIELD(usingClause);
 	READ_NODE_FIELD(quals);
 	READ_NODE_FIELD(alias);
 	READ_INT_FIELD(rtindex);
diff -r bd5a52b2681a src/backend/parser/gram.y
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2021,7 +2021,7 @@
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
-					n->typename = $2;
+					n->typeName = $2;
 					n->constraints = $3;
 					n->is_local = true;
 					$$ = (Node *)n;
@@ -2468,7 +2468,7 @@
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
-					n->typename = NULL;
+					n->typeName = NULL;
 					n->inhcount = 0;
 					n->is_local = true;
 					n->is_not_null = false;
@@ -3056,7 +3056,7 @@
 			| CREATE TYPE_P any_name AS ENUM_P '(' enum_val_list ')'
 				{
 					CreateEnumStmt *n = makeNode(CreateEnumStmt);
-					n->typename = $3;
+					n->typeName = $3;
 					n->vals = $7;
 					$$ = (Node *)n;
 				}
@@ -5622,7 +5622,7 @@
 				{
 					CreateDomainStmt *n = makeNode(CreateDomainStmt);
 					n->domainname = $3;
-					n->typename = $5;
+					n->typeName = $5;
 					n->constraints = $6;
 					$$ = (Node *)n;
 				}
@@ -5634,7 +5634,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'T';
-					n->typename = $3;
+					n->typeName = $3;
 					n->def = $4;
 					$$ = (Node *)n;
 				}
@@ -5643,7 +5643,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'N';
-					n->typename = $3;
+					n->typeName = $3;
 					$$ = (Node *)n;
 				}
 			/* ALTER DOMAIN <domain> SET NOT NULL */
@@ -5651,7 +5651,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'O';
-					n->typename = $3;
+					n->typeName = $3;
 					$$ = (Node *)n;
 				}
 			/* ALTER DOMAIN <domain> ADD CONSTRAINT ... */
@@ -5659,7 +5659,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'C';
-					n->typename = $3;
+					n->typeName = $3;
 					n->def = $5;
 					$$ = (Node *)n;
 				}
@@ -5668,7 +5668,7 @@
 				{
 					AlterDomainStmt *n = makeNode(AlterDomainStmt);
 					n->subtype = 'X';
-					n->typename = $3;
+					n->typeName = $3;
 					n->name = $6;
 					n->behavior = $7;
 					$$ = (Node *)n;
@@ -6920,7 +6920,7 @@
 					n->isNatural = FALSE;
 					n->larg = $1;
 					n->rarg = $4;
-					n->using = NIL;
+					n->usingClause = NIL;
 					n->quals = NULL;
 					$$ = n;
 				}
@@ -6932,7 +6932,7 @@
 					n->larg = $1;
 					n->rarg = $4;
 					if ($5 != NULL && IsA($5, List))
-						n->using = (List *) $5; /* USING clause */
+						n->usingClause = (List *) $5; /* USING clause */
 					else
 						n->quals = $5; /* ON clause */
 					$$ = n;
@@ -6946,7 +6946,7 @@
 					n->larg = $1;
 					n->rarg = $3;
 					if ($4 != NULL && IsA($4, List))
-						n->using = (List *) $4; /* USING clause */
+						n->usingClause = (List *) $4; /* USING clause */
 					else
 						n->quals = $4; /* ON clause */
 					$$ = n;
@@ -6958,7 +6958,7 @@
 					n->isNatural = TRUE;
 					n->larg = $1;
 					n->rarg = $5;
-					n->using = NIL; /* figure out which columns later... */
+					n->usingClause = NIL; /* figure out which columns later... */
 					n->quals = NULL; /* fill later */
 					$$ = n;
 				}
@@ -6970,7 +6970,7 @@
 					n->isNatural = TRUE;
 					n->larg = $1;
 					n->rarg = $4;
-					n->using = NIL; /* figure out which columns later... */
+					n->usingClause = NIL; /* figure out which columns later... */
 					n->quals = NULL; /* fill later */
 					$$ = n;
 				}
@@ -7135,7 +7135,7 @@
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
-					n->typename = $2;
+					n->typeName = $2;
 					n->constraints = NIL;
 					n->is_local = true;
 					$$ = (Node *)n;
@@ -8694,7 +8694,7 @@
 					XmlSerialize *n = makeNode(XmlSerialize);
 					n->xmloption = $3;
 					n->expr = $4;
-					n->typename = $6;
+					n->typeName = $6;
 					n->location = @1;
 					$$ = (Node *)n;
 				}
@@ -9906,7 +9906,7 @@
 {
 	TypeCast *n = makeNode(TypeCast);
 	n->arg = arg;
-	n->typename = typename;
+	n->typeName = typename;
 	n->location = location;
 	return (Node *) n;
 }
diff -r bd5a52b2681a src/backend/parser/parse_clause.c
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -772,7 +772,7 @@
 			ListCell   *lx,
 					   *rx;
 
-			Assert(j->using == NIL);	/* shouldn't have USING() too */
+			Assert(j->usingClause == NIL);	/* shouldn't have USING() too */
 
 			foreach(lx, l_colnames)
 			{
@@ -795,7 +795,7 @@
 					rlist = lappend(rlist, m_name);
 			}
 
-			j->using = rlist;
+			j->usingClause = rlist;
 		}
 
 		/*
@@ -804,14 +804,14 @@
 		res_colnames = NIL;
 		res_colvars = NIL;
 
-		if (j->using)
+		if (j->usingClause)
 		{
 			/*
 			 * JOIN/USING (or NATURAL JOIN, as transformed above). Transform
 			 * the list into an explicit ON-condition, and generate a list of
 			 * merged result columns.
 			 */
-			List	   *ucols = j->using;
+			List	   *ucols = j->usingClause;
 			List	   *l_usingvars = NIL;
 			List	   *r_usingvars = NIL;
 			ListCell   *ucol;
diff -r bd5a52b2681a src/backend/parser/parse_expr.c
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -159,7 +159,7 @@
 					Oid			elementType;
 					int32		targetTypmod;
 
-					targetType = typenameTypeId(pstate, tc->typename,
+					targetType = typenameTypeId(pstate, tc->typeName,
 												&targetTypmod);
 					elementType = get_element_type(targetType);
 					if (OidIsValid(elementType))
@@ -1770,7 +1770,7 @@
 													 XMLOID,
 													 "XMLSERIALIZE"));
 
-	targetType = typenameTypeId(pstate, xs->typename, &targetTypmod);
+	targetType = typenameTypeId(pstate, xs->typeName, &targetTypmod);
 
 	xexpr->xmloption = xs->xmloption;
 	xexpr->location = xs->location;
@@ -1994,7 +1994,7 @@
 	int32		targetTypmod;
 	int			location;
 
-	targetType = typenameTypeId(pstate, tc->typename, &targetTypmod);
+	targetType = typenameTypeId(pstate, tc->typeName, &targetTypmod);
 
 	if (inputType == InvalidOid)
 		return expr;			/* do nothing if NULL input */
@@ -2006,7 +2006,7 @@
 	 */
 	location = tc->location;
 	if (location < 0)
-		location = tc->typename->location;
+		location = tc->typeName->location;
 
 	result = coerce_to_target_type(pstate, expr, inputType,
 								   targetType, targetTypmod,
diff -r bd5a52b2681a src/backend/parser/parse_relation.c
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1067,13 +1067,13 @@
 			int32		attrtypmod;
 
 			attrname = pstrdup(n->colname);
-			if (n->typename->setof)
+			if (n->typeName->setof)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 						 errmsg("column \"%s\" cannot be declared SETOF",
 								attrname),
-						 parser_errposition(pstate, n->typename->location)));
-			attrtype = typenameTypeId(pstate, n->typename, &attrtypmod);
+						 parser_errposition(pstate, n->typeName->location)));
+			attrtype = typenameTypeId(pstate, n->typeName, &attrtypmod);
 			eref->colnames = lappend(eref->colnames, makeString(attrname));
 			rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
 			rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod);
diff -r bd5a52b2681a src/backend/parser/parse_target.c
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1355,9 +1355,9 @@
 											 name);
 			if (strength <= 1)
 			{
-				if (((TypeCast *) node)->typename != NULL)
+				if (((TypeCast *) node)->typeName != NULL)
 				{
-					*name = strVal(llast(((TypeCast *) node)->typename->names));
+					*name = strVal(llast(((TypeCast *) node)->typeName->names));
 					return 1;
 				}
 			}
diff -r bd5a52b2681a src/backend/parser/parse_type.c
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -27,7 +27,7 @@
 #include "utils/syscache.h"
 
 
-static int32 typenameTypeMod(ParseState *pstate, const TypeName *typename,
+static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
 				Type typ);
 
 
@@ -54,57 +54,57 @@
  * pstate is only used for error location info, and may be NULL.
  */
 Type
-LookupTypeName(ParseState *pstate, const TypeName *typename,
+LookupTypeName(ParseState *pstate, const TypeName *typeName,
 			   int32 *typmod_p)
 {
 	Oid			typoid;
 	HeapTuple	tup;
 	int32		typmod;
 
-	if (typename->names == NIL)
+	if (typeName->names == NIL)
 	{
 		/* We have the OID already if it's an internally generated TypeName */
-		typoid = typename->typeid;
+		typoid = typeName->typeOid;
 	}
-	else if (typename->pct_type)
+	else if (typeName->pct_type)
 	{
 		/* Handle %TYPE reference to type of an existing field */
-		RangeVar   *rel = makeRangeVar(NULL, NULL, typename->location);
+		RangeVar   *rel = makeRangeVar(NULL, NULL, typeName->location);
 		char	   *field = NULL;
 		Oid			relid;
 		AttrNumber	attnum;
 
 		/* deconstruct the name list */
-		switch (list_length(typename->names))
+		switch (list_length(typeName->names))
 		{
 			case 1:
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 				errmsg("improper %%TYPE reference (too few dotted names): %s",
-					   NameListToString(typename->names)),
-						 parser_errposition(pstate, typename->location)));
+					   NameListToString(typeName->names)),
+						 parser_errposition(pstate, typeName->location)));
 				break;
 			case 2:
-				rel->relname = strVal(linitial(typename->names));
-				field = strVal(lsecond(typename->names));
+				rel->relname = strVal(linitial(typeName->names));
+				field = strVal(lsecond(typeName->names));
 				break;
 			case 3:
-				rel->schemaname = strVal(linitial(typename->names));
-				rel->relname = strVal(lsecond(typename->names));
-				field = strVal(lthird(typename->names));
+				rel->schemaname = strVal(linitial(typeName->names));
+				rel->relname = strVal(lsecond(typeName->names));
+				field = strVal(lthird(typeName->names));
 				break;
 			case 4:
-				rel->catalogname = strVal(linitial(typename->names));
-				rel->schemaname = strVal(lsecond(typename->names));
-				rel->relname = strVal(lthird(typename->names));
-				field = strVal(lfourth(typename->names));
+				rel->catalogname = strVal(linitial(typeName->names));
+				rel->schemaname = strVal(lsecond(typeName->names));
+				rel->relname = strVal(lthird(typeName->names));
+				field = strVal(lfourth(typeName->names));
 				break;
 			default:
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 						 errmsg("improper %%TYPE reference (too many dotted names): %s",
-								NameListToString(typename->names)),
-						 parser_errposition(pstate, typename->location)));
+								NameListToString(typeName->names)),
+						 parser_errposition(pstate, typeName->location)));
 				break;
 		}
 
@@ -116,16 +116,16 @@
 					(errcode(ERRCODE_UNDEFINED_COLUMN),
 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
 							field, rel->relname),
-					 parser_errposition(pstate, typename->location)));
+					 parser_errposition(pstate, typeName->location)));
 		typoid = get_atttype(relid, attnum);
 
 		/* this construct should never have an array indicator */
-		Assert(typename->arrayBounds == NIL);
+		Assert(typeName->arrayBounds == NIL);
 
 		/* emit nuisance notice (intentionally not errposition'd) */
 		ereport(NOTICE,
 				(errmsg("type reference %s converted to %s",
-						TypeNameToString(typename),
+						TypeNameToString(typeName),
 						format_type_be(typoid))));
 	}
 	else
@@ -135,7 +135,7 @@
 		char	   *typname;
 
 		/* deconstruct the name list */
-		DeconstructQualifiedName(typename->names, &schemaname, &typname);
+		DeconstructQualifiedName(typeName->names, &schemaname, &typname);
 
 		if (schemaname)
 		{
@@ -155,7 +155,7 @@
 		}
 
 		/* If an array reference, return the array type instead */
-		if (typename->arrayBounds != NIL)
+		if (typeName->arrayBounds != NIL)
 			typoid = get_array_type(typoid);
 	}
 
@@ -172,7 +172,7 @@
 	if (!HeapTupleIsValid(tup)) /* should not happen */
 		elog(ERROR, "cache lookup failed for type %u", typoid);
 
-	typmod = typenameTypeMod(pstate, typename, (Type) tup);
+	typmod = typenameTypeMod(pstate, typeName, (Type) tup);
 
 	if (typmod_p)
 		*typmod_p = typmod;
@@ -188,23 +188,23 @@
  * Callers of this can therefore assume the result is a fully valid type.
  */
 Type
-typenameType(ParseState *pstate, const TypeName *typename, int32 *typmod_p)
+typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
 	Type		tup;
 
-	tup = LookupTypeName(pstate, typename, typmod_p);
+	tup = LookupTypeName(pstate, typeName, typmod_p);
 	if (tup == NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("type \"%s\" does not exist",
-						TypeNameToString(typename)),
-				 parser_errposition(pstate, typename->location)));
+						TypeNameToString(typeName)),
+				 parser_errposition(pstate, typeName->location)));
 	if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("type \"%s\" is only a shell",
-						TypeNameToString(typename)),
-				 parser_errposition(pstate, typename->location)));
+						TypeNameToString(typeName)),
+				 parser_errposition(pstate, typeName->location)));
 	return tup;
 }
 
@@ -215,12 +215,12 @@
  * not the syscache entry.
  */
 Oid
-typenameTypeId(ParseState *pstate, const TypeName *typename, int32 *typmod_p)
+typenameTypeId(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
 	Oid			typoid;
 	Type		tup;
 
-	tup = typenameType(pstate, typename, typmod_p);
+	tup = typenameType(pstate, typeName, typmod_p);
 	typoid = HeapTupleGetOid(tup);
 	ReleaseSysCache(tup);
 
@@ -239,7 +239,7 @@
  * pstate is only used for error location info, and may be NULL.
  */
 static int32
-typenameTypeMod(ParseState *pstate, const TypeName *typename, Type typ)
+typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
 {
 	int32		result;
 	Oid			typmodin;
@@ -250,8 +250,8 @@
 	ParseCallbackState pcbstate;
 
 	/* Return prespecified typmod if no typmod expressions */
-	if (typename->typmods == NIL)
-		return typename->typemod;
+	if (typeName->typmods == NIL)
+		return typeName->typemod;
 
 	/*
 	 * Else, type had better accept typmods.  We give a special error message
@@ -262,8 +262,8 @@
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 			errmsg("type modifier cannot be specified for shell type \"%s\"",
-				   TypeNameToString(typename)),
-				 parser_errposition(pstate, typename->location)));
+				   TypeNameToString(typeName)),
+				 parser_errposition(pstate, typeName->location)));
 
 	typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
 
@@ -271,17 +271,17 @@
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("type modifier is not allowed for type \"%s\"",
-						TypeNameToString(typename)),
-				 parser_errposition(pstate, typename->location)));
+						TypeNameToString(typeName)),
+				 parser_errposition(pstate, typeName->location)));
 
 	/*
 	 * Convert the list of raw-grammar-output expressions to a cstring array.
 	 * Currently, we allow simple numeric constants, string literals, and
 	 * identifiers; possibly this list could be extended.
 	 */
-	datums = (Datum *) palloc(list_length(typename->typmods) * sizeof(Datum));
+	datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
 	n = 0;
-	foreach(l, typename->typmods)
+	foreach(l, typeName->typmods)
 	{
 		Node	   *tm = (Node *) lfirst(l);
 		char	   *cstr = NULL;
@@ -314,7 +314,7 @@
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 			errmsg("type modifiers must be simple constants or identifiers"),
-					 parser_errposition(pstate, typename->location)));
+					 parser_errposition(pstate, typeName->location)));
 		datums[n++] = CStringGetDatum(cstr);
 	}
 
@@ -323,7 +323,7 @@
 								-2, false, 'c');
 
 	/* arrange to report location if type's typmodin function fails */
-	setup_parser_errposition_callback(&pcbstate, pstate, typename->location);
+	setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
 
 	result = DatumGetInt32(OidFunctionCall1(typmodin,
 											PointerGetDatum(arrtypmod)));
@@ -345,16 +345,16 @@
  * it is mostly used for reporting lookup errors.
  */
 static void
-appendTypeNameToBuffer(const TypeName *typename, StringInfo string)
+appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
 {
-	if (typename->names != NIL)
+	if (typeName->names != NIL)
 	{
 		/* Emit possibly-qualified name as-is */
 		ListCell   *l;
 
-		foreach(l, typename->names)
+		foreach(l, typeName->names)
 		{
-			if (l != list_head(typename->names))
+			if (l != list_head(typeName->names))
 				appendStringInfoChar(string, '.');
 			appendStringInfoString(string, strVal(lfirst(l)));
 		}
@@ -362,17 +362,17 @@
 	else
 	{
 		/* Look up internally-specified type */
-		appendStringInfoString(string, format_type_be(typename->typeid));
+		appendStringInfoString(string, format_type_be(typeName->typeOid));
 	}
 
 	/*
 	 * Add decoration as needed, but only for fields considered by
 	 * LookupTypeName
 	 */
-	if (typename->pct_type)
+	if (typeName->pct_type)
 		appendStringInfoString(string, "%TYPE");
 
-	if (typename->arrayBounds != NIL)
+	if (typeName->arrayBounds != NIL)
 		appendStringInfoString(string, "[]");
 }
 
@@ -384,12 +384,12 @@
  * it is mostly used for reporting lookup errors.
  */
 char *
-TypeNameToString(const TypeName *typename)
+TypeNameToString(const TypeName *typeName)
 {
 	StringInfoData string;
 
 	initStringInfo(&string);
-	appendTypeNameToBuffer(typename, &string);
+	appendTypeNameToBuffer(typeName, &string);
 	return string.data;
 }
 
@@ -406,12 +406,12 @@
 	initStringInfo(&string);
 	foreach(l, typenames)
 	{
-		TypeName   *typename = (TypeName *) lfirst(l);
+		TypeName   *typeName = (TypeName *) lfirst(l);
 
-		Assert(IsA(typename, TypeName));
+		Assert(IsA(typeName, TypeName));
 		if (l != list_head(typenames))
 			appendStringInfoChar(&string, ',');
-		appendTypeNameToBuffer(typename, &string);
+		appendTypeNameToBuffer(typeName, &string);
 	}
 	return string.data;
 }
@@ -574,7 +574,7 @@
 	SelectStmt *stmt;
 	ResTarget  *restarget;
 	TypeCast   *typecast;
-	TypeName   *typename;
+	TypeName   *typeName;
 	ErrorContextCallback ptserrcontext;
 
 	/* make sure we give useful error for empty input */
@@ -633,14 +633,14 @@
 		typecast->arg == NULL ||
 		!IsA(typecast->arg, A_Const))
 		goto fail;
-	typename = typecast->typename;
-	if (typename == NULL ||
-		!IsA(typename, TypeName))
+	typeName = typecast->typeName;
+	if (typeName == NULL ||
+		!IsA(typeName, TypeName))
 		goto fail;
-	if (typename->setof)
+	if (typeName->setof)
 		goto fail;
 
-	*type_id = typenameTypeId(NULL, typename, typmod_p);
+	*type_id = typenameTypeId(NULL, typeName, typmod_p);
 
 	pfree(buf.data);
 
diff -r bd5a52b2681a src/backend/parser/parse_utilcmd.c
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -266,24 +266,24 @@
 
 	/* Check for SERIAL pseudo-types */
 	is_serial = false;
-	if (list_length(column->typename->names) == 1 &&
-		!column->typename->pct_type)
+	if (list_length(column->typeName->names) == 1 &&
+		!column->typeName->pct_type)
 	{
-		char	   *typname = strVal(linitial(column->typename->names));
+		char	   *typname = strVal(linitial(column->typeName->names));
 
 		if (strcmp(typname, "serial") == 0 ||
 			strcmp(typname, "serial4") == 0)
 		{
 			is_serial = true;
-			column->typename->names = NIL;
-			column->typename->typeid = INT4OID;
+			column->typeName->names = NIL;
+			column->typeName->typeOid = INT4OID;
 		}
 		else if (strcmp(typname, "bigserial") == 0 ||
 				 strcmp(typname, "serial8") == 0)
 		{
 			is_serial = true;
-			column->typename->names = NIL;
-			column->typename->typeid = INT8OID;
+			column->typeName->names = NIL;
+			column->typeName->typeOid = INT8OID;
 		}
 
 		/*
@@ -291,7 +291,7 @@
 		 * set typeid, LookupTypeName won't notice arrayBounds.  We don't
 		 * need any special coding for serial(typmod) though.
 		 */
-		if (is_serial && column->typename->arrayBounds != NIL)
+		if (is_serial && column->typeName->arrayBounds != NIL)
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("array of serial is not implemented")));
@@ -382,7 +382,7 @@
 		snamenode->val.val.str = qstring;
 		snamenode->location = -1;
 		castnode = makeNode(TypeCast);
-		castnode->typename = SystemTypeName("regclass");
+		castnode->typeName = SystemTypeName("regclass");
 		castnode->arg = (Node *) snamenode;
 		castnode->location = -1;
 		funccallnode = makeNode(FuncCall);
@@ -622,7 +622,7 @@
 		 */
 		def = makeNode(ColumnDef);
 		def->colname = pstrdup(attributeName);
-		def->typename = makeTypeNameFromOid(attribute->atttypid,
+		def->typeName = makeTypeNameFromOid(attribute->atttypid,
 											attribute->atttypmod);
 		def->inhcount = 0;
 		def->is_local = true;
@@ -1962,7 +1962,7 @@
 	/*
 	 * All we really need to do here is verify that the type is valid.
 	 */
-	Type		ctype = typenameType(pstate, column->typename, NULL);
+	Type		ctype = typenameType(pstate, column->typeName, NULL);
 
 	ReleaseSysCache(ctype);
 }
diff -r bd5a52b2681a src/backend/tcop/utility.c
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -602,23 +602,23 @@
 						 * Recursively alter column default for table and, if
 						 * requested, for descendants
 						 */
-						AlterDomainDefault(stmt->typename,
+						AlterDomainDefault(stmt->typeName,
 										   stmt->def);
 						break;
 					case 'N':	/* ALTER DOMAIN DROP NOT NULL */
-						AlterDomainNotNull(stmt->typename,
+						AlterDomainNotNull(stmt->typeName,
 										   false);
 						break;
 					case 'O':	/* ALTER DOMAIN SET NOT NULL */
-						AlterDomainNotNull(stmt->typename,
+						AlterDomainNotNull(stmt->typeName,
 										   true);
 						break;
 					case 'C':	/* ADD CONSTRAINT */
-						AlterDomainAddConstraint(stmt->typename,
+						AlterDomainAddConstraint(stmt->typeName,
 												 stmt->def);
 						break;
 					case 'X':	/* DROP CONSTRAINT */
-						AlterDomainDropConstraint(stmt->typename,
+						AlterDomainDropConstraint(stmt->typeName,
 												  stmt->name,
 												  stmt->behavior);
 						break;
diff -r bd5a52b2681a src/backend/utils/adt/ruleutils.c
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5539,14 +5539,14 @@
 
 		if (!j->isNatural)
 		{
-			if (j->using)
+			if (j->usingClause)
 			{
 				ListCell   *col;
 
 				appendStringInfo(buf, " USING (");
-				foreach(col, j->using)
-				{
-					if (col != list_head(j->using))
+				foreach(col, j->usingClause)
+				{
+					if (col != list_head(j->usingClause))
 						appendStringInfo(buf, ", ");
 					appendStringInfoString(buf,
 									  quote_identifier(strVal(lfirst(col))));
@@ -5878,18 +5878,18 @@
 /*
  * quote_qualified_identifier	- Quote a possibly-qualified identifier
  *
- * Return a name of the form namespace.ident, or just ident if namespace
+ * Return a name of the form qualifier.ident, or just ident if qualifier
  * is NULL, quoting each component if necessary.  The result is palloc'd.
  */
 char *
-quote_qualified_identifier(const char *namespace,
+quote_qualified_identifier(const char *qualifier,
 						   const char *ident)
 {
 	StringInfoData buf;
 
 	initStringInfo(&buf);
-	if (namespace)
-		appendStringInfo(&buf, "%s.", quote_identifier(namespace));
+	if (qualifier)
+		appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
 	appendStringInfoString(&buf, quote_identifier(ident));
 	return buf.data;
 }
diff -r bd5a52b2681a src/backend/utils/misc/guc.c
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -5370,7 +5370,7 @@
 	{
 		Node       *arg = (Node *) lfirst(l);
 		char	   *val;
-		TypeName   *typename = NULL;
+		TypeName   *typeName = NULL;
 		A_Const	   *con;
 
 		if (l != list_head(args))
@@ -5381,7 +5381,7 @@
 			TypeCast *tc = (TypeCast *) arg;
 
 			arg = tc->arg;
-			typename = tc->typename;
+			typeName = tc->typeName;
 		}
 
 		if (!IsA(arg, A_Const))
@@ -5399,7 +5399,7 @@
 				break;
 			case T_String:
 				val = strVal(&con->val);
-				if (typename != NULL)
+				if (typeName != NULL)
 				{
 					/*
 					 * Must be a ConstInterval argument for TIME ZONE. Coerce
@@ -5411,7 +5411,7 @@
 					Datum		interval;
 					char	   *intervalout;
 
-					typoid = typenameTypeId(NULL, typename, &typmod);
+					typoid = typenameTypeId(NULL, typeName, &typmod);
 					Assert(typoid == INTERVALOID);
 
 					interval =
diff -r bd5a52b2681a src/backend/utils/mmgr/mcxt.c
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -193,7 +193,7 @@
 			}
 		}
 	}
-	(*context->methods->delete) (context);
+	(*context->methods->delete_context) (context);
 	pfree(context);
 }
 
diff -r bd5a52b2681a src/include/c.h
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -150,7 +150,7 @@
  * dummyret is used to set return values in macros that use ?: to make
  * assignments.  gcc wants these to be void, other compilers like char
  */
-#ifdef __GNUC__					/* GNU cc */
+#if defined(__GNUC__) && !defined(__cplusplus)	/* GNU cc */
 #define dummyret	void
 #else
 #define dummyret	char
diff -r bd5a52b2681a src/include/nodes/makefuncs.h
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -60,7 +60,7 @@
 
 extern TypeName *makeTypeName(char *typnam);
 extern TypeName *makeTypeNameFromNameList(List *names);
-extern TypeName *makeTypeNameFromOid(Oid typeid, int32 typmod);
+extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod);
 
 extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype,
 			 List *args, CoercionForm fformat);
diff -r bd5a52b2681a src/include/nodes/memnodes.h
--- a/src/include/nodes/memnodes.h
+++ b/src/include/nodes/memnodes.h
@@ -41,7 +41,7 @@
 	void	   *(*realloc) (MemoryContext context, void *pointer, Size size);
 	void		(*init) (MemoryContext context);
 	void		(*reset) (MemoryContext context);
-	void		(*delete) (MemoryContext context);
+	void		(*delete_context) (MemoryContext context);
 	Size		(*get_chunk_space) (MemoryContext context, void *pointer);
 	bool		(*is_empty) (MemoryContext context);
 	void		(*stats) (MemoryContext context, int level);
diff -r bd5a52b2681a src/include/nodes/parsenodes.h
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -157,7 +157,7 @@
  *
  * For TypeName structures generated internally, it is often easier to
  * specify the type by OID than by name.  If "names" is NIL then the
- * actual type OID is given by typeid, otherwise typeid is unused.
+ * actual type OID is given by typeOid, otherwise typeOid is unused.
  * Similarly, if "typmods" is NIL then the actual typmod is expected to
  * be prespecified in typemod, otherwise typemod is unused.
  *
@@ -169,7 +169,7 @@
 {
 	NodeTag		type;
 	List	   *names;			/* qualified name (list of Value strings) */
-	Oid			typeid;			/* type identified by OID */
+	Oid			typeOid;		/* type identified by OID */
 	bool		setof;			/* is a set? */
 	bool		pct_type;		/* %TYPE specified? */
 	List	   *typmods;		/* type modifier expression(s) */
@@ -252,7 +252,7 @@
 {
 	NodeTag		type;
 	Node	   *arg;			/* the expression being casted */
-	TypeName   *typename;		/* the target type */
+	TypeName   *typeName;		/* the target type */
 	int			location;		/* token location, or -1 if unknown */
 } TypeCast;
 
@@ -409,7 +409,7 @@
 {
 	NodeTag		type;
 	char	   *colname;		/* name of column */
-	TypeName   *typename;		/* type of column */
+	TypeName   *typeName;		/* type of column */
 	int			inhcount;		/* number of times column is inherited */
 	bool		is_local;		/* column has local (non-inherited) def'n */
 	bool		is_not_null;	/* NOT NULL constraint specified? */
@@ -490,7 +490,7 @@
 	NodeTag		type;
 	XmlOptionType xmloption;	/* DOCUMENT or CONTENT */
 	Node	   *expr;
-	TypeName   *typename;
+	TypeName   *typeName;
 	int			location;		/* token location, or -1 if unknown */
 } XmlSerialize;
 
@@ -1059,7 +1059,7 @@
 								 *	X = drop constraint
 								 *------------
 								 */
-	List	   *typename;		/* domain to work on */
+	List	   *typeName;		/* domain to work on */
 	char	   *name;			/* column or constraint name to act on */
 	Node	   *def;			/* definition of default or constraint */
 	DropBehavior behavior;		/* RESTRICT or CASCADE for DROP cases */
@@ -1459,7 +1459,7 @@
 {
 	NodeTag		type;
 	List	   *domainname;		/* qualified name (list of Value strings) */
-	TypeName   *typename;		/* the base type */
+	TypeName   *typeName;		/* the base type */
 	List	   *constraints;	/* constraints (list of Constraint nodes) */
 } CreateDomainStmt;
 
@@ -1872,7 +1872,7 @@
 typedef struct CreateEnumStmt
 {
 	NodeTag		type;
-	List	   *typename;		/* qualified name (list of Value strings) */
+	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
 } CreateEnumStmt;
 
diff -r bd5a52b2681a src/include/nodes/primnodes.h
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1107,8 +1107,8 @@
 /*----------
  * JoinExpr - for SQL JOIN expressions
  *
- * isNatural, using, and quals are interdependent.	The user can write only
- * one of NATURAL, USING(), or ON() (this is enforced by the grammar).
+ * isNatural, usingClause, and quals are interdependent.  The user can write
+ * only one of NATURAL, USING(), or ON() (this is enforced by the grammar).
  * If he writes NATURAL then parse analysis generates the equivalent USING()
  * list, and from that fills in "quals" with the right equality comparisons.
  * If he writes USING() then "quals" is filled with equality comparisons.
@@ -1132,7 +1132,7 @@
 	bool		isNatural;		/* Natural join? Will need to shape table */
 	Node	   *larg;			/* left subtree */
 	Node	   *rarg;			/* right subtree */
-	List	   *using;			/* USING clause, if any (list of String) */
+	List	   *usingClause;	/* USING clause, if any (list of String) */
 	Node	   *quals;			/* qualifiers on join, if any */
 	Alias	   *alias;			/* user-written alias clause, if any */
 	int			rtindex;		/* RT index assigned for join */
diff -r bd5a52b2681a src/include/parser/parse_type.h
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -19,14 +19,14 @@
 
 typedef HeapTuple Type;
 
-extern Type LookupTypeName(ParseState *pstate, const TypeName *typename,
+extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
 			   int32 *typmod_p);
-extern Type typenameType(ParseState *pstate, const TypeName *typename,
+extern Type typenameType(ParseState *pstate, const TypeName *typeName,
 			 int32 *typmod_p);
-extern Oid typenameTypeId(ParseState *pstate, const TypeName *typename,
+extern Oid typenameTypeId(ParseState *pstate, const TypeName *typeName,
 			   int32 *typmod_p);
 
-extern char *TypeNameToString(const TypeName *typename);
+extern char *TypeNameToString(const TypeName *typeName);
 extern char *TypeNameListToString(List *typenames);
 
 extern Type typeidType(Oid id);
diff -r bd5a52b2681a src/include/utils/builtins.h
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -560,7 +560,7 @@
 extern List *deparse_context_for_plan(Node *plan, Node *outer_plan,
 						 List *rtable, List *subplans);
 extern const char *quote_identifier(const char *ident);
-extern char *quote_qualified_identifier(const char *namespace,
+extern char *quote_qualified_identifier(const char *qualifier,
 						   const char *ident);
 
 /* tid.c */
#7Kurt Harriman
harriman@acm.org
In reply to: Kurt Harriman (#1)
1 attachment(s)
Re: Mostly Harmless: c++bookends - patch 2 of 4

(Re-sending just the second of four patches: c++bookends)

These patches are based on CVS head in which the latest commit was
user: petere
date: Thu Dec 04 17:51:28 2008 +0000
summary: Default values for function arguments

2. c++bookends

C++ code can call C functions and share global variables with C,
provided those declarations are surrounded by "bookends":

extern "C" {
...
};

Header files can be made bilingual, to declare interfaces which
look the same to both C and C++ callers. This is done by
placing C++ bookends within the header file, guarded by #ifdefs

#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}; /* extern "C" */
#endif

This way the C++ caller can just #include the header file without
worrying whether the interface is implemented in C or C++.

Usually, extension modules written in C++ will put bookends around
all of their PostgreSQL #includes.

However, "postgres.h" usually stands alone as the first #include,
followed by some system #includes, and then the rest of the
PostgreSQL #includes. It is much nicer if a C++ file has just one
pair of bookends around its main block of PostgreSQL #includes.
This patch gives postgres.h its own internal bookends, making it
bilingual, so that its #include can continue to stand alone at the
head of each file.

Just a few additional header files are mentioned in the PostgreSQL
Reference Manual for add-on developers to use: fmgr.h, funcapi.h,
and spi.h. This patch adds bookends within those three files for
the benefit of beginners writing very simple extensions in C++.
Documentation and learning are simplified because C example code
can be compiled as C or C++ without change.

Attachments:

c++bookends.patchtext/plain; name=c++bookends.patchDownload
diff -r 55d732d0fbcd src/include/executor/spi.h
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -18,6 +18,10 @@
  * included postgres.h
  */
 #include "postgres.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /*
  *	Most of these are not needed by this file, but may be used by
@@ -156,4 +160,8 @@
 extern void AtEOXact_SPI(bool isCommit);
 extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid);
 
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
 #endif   /* SPI_H */
diff -r 55d732d0fbcd src/include/fmgr.h
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -17,6 +17,10 @@
  */
 #ifndef FMGR_H
 #define FMGR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /* We don't want to include primnodes.h here, so make a stub reference */
 typedef struct Node *fmNodePtr;
@@ -544,4 +548,8 @@
  */
 extern char *fmgr(Oid procedureId,...);
 
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
 #endif   /* FMGR_H */
diff -r 55d732d0fbcd src/include/funcapi.h
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -16,11 +16,14 @@
 #ifndef FUNCAPI_H
 #define FUNCAPI_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "fmgr.h"
 #include "access/tupdesc.h"
 #include "executor/executor.h"
 #include "executor/tuptable.h"
-
 
 /*-------------------------------------------------------------------------
  *	Support to ease writing Functions returning composite types
@@ -299,4 +302,8 @@
 		PG_RETURN_NULL(); \
 	} while (0)
 
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
 #endif   /* FUNCAPI_H */
diff -r 55d732d0fbcd src/include/postgres.h
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -44,7 +44,12 @@
 #ifndef POSTGRES_H
 #define POSTGRES_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "c.h"
+
 #include "utils/elog.h"
 #include "utils/palloc.h"
 
@@ -693,4 +698,8 @@
 					 const char *errorType,
 					 const char *fileName, int lineNumber);
 
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
 #endif   /* POSTGRES_H */
#8Kurt Harriman
harriman@acm.org
In reply to: Kurt Harriman (#1)
1 attachment(s)
Re: Mostly Harmless: c++configure - patch 3 of 4

(Re-sending just the third of four patches: c++configure)

These patches are based on CVS head in which the latest commit was
user: petere
date: Thu Dec 04 17:51:28 2008 +0000
summary: Default values for function arguments

3. c++configure

This patch adds C++ support to the PostgreSQL build system.

After you have applied the patch, cd to the top of the source
tree (to the directory containing the file 'configure.in') and
execute these two commands to regenerate the 'configure' script
and some related files:
autoconf
autoheader

Much as it already does for the C compiler, the 'configure' script
will try to find the C++ compiler and set up appropriate command
line options. If 'configure' finds a C++ compiler, it will set up
src/Makefile.global to define the following makefile variables:

CXX = command for invoking C++ compiler
CXXCPP = command for invoking C++ preprocessor
CXXFLAGS = C++ compiler options
GXX = 'yes' if the C++ compiler is gcc/g++

Implicit rules are defined so that gmake will automatically invoke
the C++ compiler using the above variables given a source file name
suffixed with '.cpp' or '.cc'. So, to add a file named marvin.cpp
to the build, just add 'marvin.o' to the OBJS list in the Makefile.

To C++-compile a file with '.c' suffix, the Makefile should list
the .o file in both OBJS and CXXOBJS.

The pg_config utility can be used to display the CXX and CXXFLAGS.

Most C++ code typically uses some C++ features whose implementation
makes use of the compiler's runtime library: exceptions, static
constructors, new/delete, STL containers, stream I/O, etc. Specify
the following 'configure' option to link the C++ runtime library
into the postgres backend:

--enable-cplusplus

If --enable-cplusplus is specified, the makefile variable
'enable_cplusplus' will be set to 'yes', and pg_config.h will
#define ENABLE_CPLUSPLUS.

To ensure that the C++ runtime library is properly initialized,
on some platforms it is necessary for the main() function to be
compiled as C++. Therefore, if --enable-cplusplus is configured,
src/backend/main/main.c will be compiled as C++. This is
handled by the following lines in src/backend/main/Makefile:

ifeq ($(enable_cplusplus),yes)
CXXOBJS = main.o
endif

Fortunately, main.c can be compiled as either C or C++ with no
difficulty after applying the c++reserved and c++bookends
patches. To make main.c bilingual, all that was needed was
a pair of bookends around its #includes.

Limitations:

- I haven't added support for profiling and code coverage for
C++. Automatic dependency generation is supported, however.

- This ought to work on platforms which use GCC, and maybe some
others. The only one I have tested is x86_32 Linux with GCC
4.1.2. Hopefully some interested hackers will try it on
platforms to which they have access, and post the results.

Attachments:

c++configure.patchtext/plain; name=c++configure.patchDownload
diff -r 257c0be599ab config/c-compiler.m4
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -103,6 +103,7 @@
 # command-line option. If it does, add the string to CFLAGS.
 AC_DEFUN([PGAC_PROG_CC_CFLAGS_OPT],
 [AC_MSG_CHECKING([if $CC supports $1])
+AC_LANG_ASSERT([C])
 pgac_save_CFLAGS=$CFLAGS
 CFLAGS="$pgac_save_CFLAGS $1"
 _AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
@@ -110,6 +111,23 @@
                    [CFLAGS="$pgac_save_CFLAGS"
                     AC_MSG_RESULT(no)])
 ])# PGAC_PROG_CC_CFLAGS_OPT
+
+
+
+# PGAC_PROG_CXX_CXXFLAGS_OPT
+# -----------------------
+# Given a string, check if the C++ compiler supports the string as a
+# command-line option. If it does, add the string to CXXFLAGS.
+AC_DEFUN([PGAC_PROG_CXX_CXXFLAGS_OPT],
+[AC_MSG_CHECKING([if $CXX supports $1])
+AC_LANG_ASSERT([C++])
+pgac_save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="$pgac_save_CXXFLAGS $1"
+_AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+                   AC_MSG_RESULT(yes),
+                   [CXXFLAGS="$pgac_save_CXXFLAGS"
+                    AC_MSG_RESULT(no)])
+])# PGAC_PROG_CXX_CXXFLAGS_OPT
 
 
 
diff -r 257c0be599ab configure.in
--- a/configure.in
+++ b/configure.in
@@ -195,6 +195,14 @@
 PGAC_ARG_BOOL(enable, debug, no,
               [build with debugging symbols (-g)])
 AC_SUBST(enable_debug)
+
+#
+# --enable-cplusplus links the postgres backend with the C++ runtime library
+#
+PGAC_ARG_BOOL(enable, cplusplus, no, [build with C++ runtime library],
+              [AC_DEFINE([ENABLE_CPLUSPLUS], 1,
+                         [Define to 1 for mixed C/C++ build. (--enable-cplusplus)])])
+AC_SUBST(enable_cplusplus)
 
 #
 # --enable-profiling enables gcc profiling
@@ -365,9 +373,9 @@
 PGAC_ARG_REQ(with, CC, [CMD], [set compiler (deprecated)], [CC=$with_CC])
 
 case $template in
-  aix) pgac_cc_list="gcc xlc";;
- irix) pgac_cc_list="cc";; # no gcc
-    *) pgac_cc_list="gcc cc";;
+  aix) pgac_cc_list="gcc xlc";  pgac_cxx_list="g++ xlC";;
+ irix) pgac_cc_list="cc";       pgac_cxx_list="CC";;            # no gcc
+    *) pgac_cc_list="gcc cc";   pgac_cxx_list="g++ CC";;
 esac
 
 AC_PROG_CC([$pgac_cc_list])
@@ -387,7 +395,15 @@
 
 AC_SUBST(SUN_STUDIO_CC)
 
+#
+# C++ compiler
+#
+AC_PROG_CXX([$pgac_cxx_list])
+AC_PROG_CXXCPP
+AC_SUBST(GXX)
+
 unset CFLAGS
+unset CXXFLAGS
 
 #
 # Read the template
@@ -421,9 +437,8 @@
 # ICC pretends to be GCC but it's lying; it doesn't support these options.
 
 if test "$GCC" = yes -a "$ICC" = no; then
-  CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wpointer-arith"
+  CFLAGS="$CFLAGS -Wall -Wpointer-arith"
   # These work in some but not all gcc versions
-  PGAC_PROG_CC_CFLAGS_OPT([-Wdeclaration-after-statement])
   PGAC_PROG_CC_CFLAGS_OPT([-Wendif-labels])
   # Disable strict-aliasing rules; needed for gcc 3.3+
   PGAC_PROG_CC_CFLAGS_OPT([-fno-strict-aliasing])
@@ -470,12 +485,53 @@
   CPPFLAGS="$CPPFLAGS -I$srcdir/src/include/port/win32 -DEXEC_BACKEND"
 fi
 
+#
+# Initialize C++ flags from CFLAGS unless overridden in environment or template
+#
+if test "$ac_env_CXXFLAGS_set" = set; then
+  CXXFLAGS=$ac_env_CXXFLAGS_value
+elif test "${CXXFLAGS+set}" = set; then
+  : # (keep what template set)
+else
+  CXXFLAGS="$CFLAGS"
+fi
+
+# Some CXXFLAGS are only valid for C++, not for C.  Add them here.
+if test "$GXX" = yes -a "$ICC" = no; then
+  AC_LANG_PUSH([C++])
+  CXXFLAGS="$CXXFLAGS -Wabi"
+  PGAC_PROG_CXX_CXXFLAGS_OPT([-fno-enforce-eh-specs])
+  PGAC_PROG_CXX_CXXFLAGS_OPT([-fno-threadsafe-statics])
+  AC_LANG_POP([C++])
+fi
+
+# Some CFLAGS are only valid for C, not for C++.  Add them here.
+if test "$GCC" = yes -a "$ICC" = no; then
+  CFLAGS="$CFLAGS -Wmissing-prototypes"
+  # These work in some but not all gcc versions
+  PGAC_PROG_CC_CFLAGS_OPT([-Wdeclaration-after-statement])
+fi
+
+
+#
 # Check if the compiler still works with the template settings
+#
 AC_MSG_CHECKING([whether the C compiler still works])
 AC_TRY_LINK([], [return 0;],
   [AC_MSG_RESULT(yes)],
   [AC_MSG_RESULT(no)
    AC_MSG_ERROR([cannot proceed])])
+
+if test "$enable_cplusplus" = yes; then
+  AC_LANG_PUSH([C++])
+  AC_MSG_CHECKING([whether the C++ compiler still works])
+  AC_TRY_LINK([class X {public: bool b; X(bool bb){this->b = bb;}};],
+    [X* x = new X(true);],
+    [AC_MSG_RESULT(yes)],
+    [AC_MSG_RESULT(no)
+     AC_MSG_ERROR([cannot proceed])])
+  AC_LANG_POP([C++])
+fi
 
 # Defend against gcc -ffast-math
 if test "$GCC" = yes; then
@@ -1765,6 +1821,7 @@
 # Begin output steps
 
 AC_MSG_NOTICE([using CFLAGS=$CFLAGS])
+AC_MSG_NOTICE([using CXXFLAGS=$CXXFLAGS])
 AC_MSG_NOTICE([using CPPFLAGS=$CPPFLAGS])
 AC_MSG_NOTICE([using LDFLAGS=$LDFLAGS])
 
diff -r 257c0be599ab doc/src/sgml/installation.sgml
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1261,6 +1261,17 @@
          can be profiled.  On backend exit, a subdirectory will be created
          that contains the <filename>gmon.out</> file for use in profiling.
          This option is for use only with GCC and when doing development work.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><option>--enable-cplusplus</option></term>
+       <listitem>
+        <para>
+         Compiles the <filename>postgres</> server with C++ runtime
+         library support.  Specify this option only if you intend to use or
+         develop server extensions or modifications in the C++ language.
         </para>
        </listitem>
       </varlistentry>
diff -r 257c0be599ab doc/src/sgml/ref/pg_config-ref.sgml
--- a/doc/src/sgml/ref/pg_config-ref.sgml
+++ b/doc/src/sgml/ref/pg_config-ref.sgml
@@ -223,6 +223,27 @@
     </varlistentry>
 
     <varlistentry>
+     <term><option>--cxx</option></>
+     <listitem>
+      <para>
+       Print the value of the <varname>CXX</varname> variable showing the C++
+       compiler that was used for building C++ modules (if any) in the
+       <productname>PostgreSQL</> backend.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><option>--cxxflags</option></>
+     <listitem>
+      <para>
+       Print the value of the <varname>CXXFLAGS</varname> variable that was used for building
+       <productname>PostgreSQL</>.  This shows C++ compiler switches.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
      <term><option>--ldflags</option></>
      <listitem>
       <para>
diff -r 257c0be599ab src/Makefile.global.in
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -164,6 +164,7 @@
 enable_debug	= @enable_debug@
 enable_dtrace	= @enable_dtrace@
 enable_coverage	= @enable_coverage@
+enable_cplusplus	= @enable_cplusplus@
 enable_thread_safety	= @enable_thread_safety@
 
 python_includespec	= @python_includespec@
@@ -214,6 +215,21 @@
 GCC = @GCC@
 SUN_STUDIO_CC = @SUN_STUDIO_CC@
 CFLAGS = @CFLAGS@
+
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+GXX = @GXX@
+
+# gmake predefines these and uses them in its predefined implicit rules.
+# We include them here just in case someone uses a version of gmake which
+# doesn't have them built in.  These are as defined by gmake 3.81.
+COMPILE.c   ?= $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
+LINK.c      ?= $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
+COMPILE.cc  ?= $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
+LINK.cc     ?= $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
+COMPILE.cpp ?= $(COMPILE.cc)
+LINK.cpp    ?= $(LINK.cc)
 
 # Kind-of compilers
 
@@ -545,18 +561,25 @@
 
 ifeq ($(autodepend), yes)
 
-ifndef COMPILE.c
-COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c
-endif
-
 DEPDIR = .deps
+DEPMKDIR = @if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi
 
 ifeq ($(GCC), yes)
 
 # GCC allows us to create object and dependency file in one invocation.
+DEPFLAGS = -MMD -MP -MF $(DEPDIR)/$(*F).Po
+
 %.o : %.c
-	@if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi
-	$(COMPILE.c) -o $@ $< -MMD -MP -MF $(DEPDIR)/$(*F).Po
+	$(DEPMKDIR)
+	$(COMPILE.c) $(DEPFLAGS) -o $@ $<
+
+%.o : %.cc
+	$(DEPMKDIR)
+	$(COMPILE.cc) $(DEPFLAGS) -o $@ $<
+
+%.o: %.cpp
+	$(DEPMKDIR)
+	$(COMPILE.cpp) $(DEPFLAGS) -o $@ $<
 
 endif # GCC
 
diff -r 257c0be599ab src/backend/Makefile
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -43,7 +43,12 @@
 ifneq ($(PORTNAME), aix)
 
 postgres: $(OBJS)
+ifeq ($(enable_cplusplus), yes)
+	# Link with C++ runtime support
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o $@
+else
 	$(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o $@
+endif
 
 endif
 endif
@@ -111,7 +116,12 @@
 # The postgres.o target is needed by the rule in Makefile.global that
 # creates the exports file when MAKE_EXPORTS = true.
 postgres.o: $(OBJS)
+ifeq ($(enable_cplusplus), yes)
+	# Link with C++ runtime support
+	$(CXX) $(LDREL) $(LDFLAGS) $(call expand_subsys,$^) $(LIBS) -o $@
+else
 	$(CC) $(LDREL) $(LDFLAGS) $(call expand_subsys,$^) $(LIBS) -o $@
+endif
 
 
 # The following targets are specified in make commands that appear in
@@ -268,4 +278,9 @@
 # are up to date.  It saves the time of doing all the submakes.
 .PHONY: quick
 quick: $(OBJS)
+ifeq ($(enable_cplusplus), yes)
+	# Link with C++ runtime support
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o postgres
+else
 	$(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o postgres
+endif
diff -r 257c0be599ab src/backend/common.mk
--- a/src/backend/common.mk
+++ b/src/backend/common.mk
@@ -6,7 +6,7 @@
 
 # When including this file, set OBJS to the object files created in
 # this directory and SUBDIRS to subdirectories containing more things
-# to build.
+# to build.  Set CXXOBJS to the subset of OBJS which are to be C++ compiled.
 
 ifdef PARTIAL_LINKING
 # old style: linking using SUBSYS.o
@@ -36,6 +36,11 @@
 # Parallel make trickery
 $(SUBDIROBJS): $(SUBDIRS:%=%-recursive) ;
 
+# For .o files listed in CXXOBJS, use C++ compiler to make .o from .c
+$(CXXOBJS) : %.o: %.c
+	$(DEPMKDIR)
+	$(COMPILE.cc) $(DEPFLAGS) -o $@ $<
+
 .PHONY: $(SUBDIRS:%=%-recursive)
 $(SUBDIRS:%=%-recursive):
 	$(MAKE) -C $(subst -recursive,,$@) all
diff -r 257c0be599ab src/backend/main/Makefile
--- a/src/backend/main/Makefile
+++ b/src/backend/main/Makefile
@@ -14,4 +14,11 @@
 
 OBJS = main.o
 
+# If "configure --enable-cplusplus" was specified, make list of modules
+# which are to be compiled as C++.  The main() function should be compiled as
+# C++ to ensure proper initialization of the mixed C/C++ runtime environment.
+ifeq ($(enable_cplusplus),yes)
+CXXOBJS = main.o
+endif
+
 include $(top_srcdir)/src/backend/common.mk
diff -r 257c0be599ab src/backend/main/main.c
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -34,6 +34,14 @@
 #include <sys/param.h>
 #endif
 
+#if defined(ENABLE_CPLUSPLUS) && !defined(__cplusplus)
+#error --enable-cplusplus configure option specified; this file should be compiled as C++
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "bootstrap/bootstrap.h"
 #include "postmaster/postmaster.h"
 #include "tcop/tcopprot.h"
@@ -42,6 +50,10 @@
 #include "utils/ps_status.h"
 #ifdef WIN32
 #include "libpq/pqsignal.h"
+#endif
+
+#ifdef __cplusplus
+}   /* extern "C" */
 #endif
 
 
diff -r 257c0be599ab src/bin/pg_config/Makefile
--- a/src/bin/pg_config/Makefile
+++ b/src/bin/pg_config/Makefile
@@ -24,6 +24,8 @@
 override CPPFLAGS += -DVAL_CPPFLAGS="\"$(STD_CPPFLAGS)\""
 override CPPFLAGS += -DVAL_CFLAGS="\"$(CFLAGS)\""
 override CPPFLAGS += -DVAL_CFLAGS_SL="\"$(CFLAGS_SL)\""
+override CPPFLAGS += -DVAL_CXX="\"$(CXX)\""
+override CPPFLAGS += -DVAL_CXXFLAGS="\"$(CXXFLAGS)\""
 override CPPFLAGS += -DVAL_LDFLAGS="\"$(STD_LDFLAGS)\""
 override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
 override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
diff -r 257c0be599ab src/bin/pg_config/pg_config.c
--- a/src/bin/pg_config/pg_config.c
+++ b/src/bin/pg_config/pg_config.c
@@ -311,6 +311,38 @@
 }
 
 static void
+show_cxx(bool all)
+{
+#ifdef VAL_CXX
+	if (all)
+		printf("CXX = ");
+	printf("%s\n", VAL_CXX);
+#else
+	if (!all)
+	{
+		fprintf(stderr, _("not recorded\n"));
+		exit(1);
+	}
+#endif
+}
+
+static void
+show_cxxflags(bool all)
+{
+#ifdef VAL_CXXFLAGS
+	if (all)
+		printf("CXXFLAGS = ");
+	printf("%s\n", VAL_CXXFLAGS);
+#else
+	if (!all)
+	{
+		fprintf(stderr, _("not recorded\n"));
+		exit(1);
+	}
+#endif
+}
+
+static void
 show_ldflags(bool all)
 {
 #ifdef VAL_LDFLAGS
@@ -397,6 +429,8 @@
 	{"--cppflags", show_cppflags},
 	{"--cflags", show_cflags},
 	{"--cflags_sl", show_cflags_sl},
+	{"--cxx", show_cxx},
+	{"--cxxflags", show_cxxflags},
 	{"--ldflags", show_ldflags},
 	{"--ldflags_sl", show_ldflags_sl},
 	{"--libs", show_libs},
@@ -432,6 +466,8 @@
 	printf(_("  --cppflags            show CPPFLAGS value used when PostgreSQL was built\n"));
 	printf(_("  --cflags              show CFLAGS value used when PostgreSQL was built\n"));
 	printf(_("  --cflags_sl           show CFLAGS_SL value used when PostgreSQL was built\n"));
+	printf(_("  --cxx                 show CXX value used when PostgreSQL was built\n"));
+	printf(_("  --cxxflags            show CXXFLAGS value used when PostgreSQL was built\n"));
 	printf(_("  --ldflags             show LDFLAGS value used when PostgreSQL was built\n"));
 	printf(_("  --ldflags_sl          show LDFLAGS_SL value used when PostgreSQL was built\n"));
 	printf(_("  --libs                show LIBS value used when PostgreSQL was built\n"));
diff -r 257c0be599ab src/include/pg_config.h.in
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -44,6 +44,9 @@
 
 /* Define to the default TCP port number as a string constant. */
 #undef DEF_PGPORT_STR
+
+/* Define to 1 for mixed C/C++ build. (--enable-cplusplus) */
+#undef ENABLE_CPLUSPLUS
 
 /* Define to 1 to enable DTrace support. (--enable-dtrace) */
 #undef ENABLE_DTRACE
#9Kurt Harriman
harriman@acm.org
In reply to: Kurt Harriman (#1)
1 attachment(s)
Re: Mostly Harmless: c++exception - patch 4 of 4

(Re-sending just the fourth of four patches: c++exception)

These patches are based on CVS head in which the latest commit was
user: petere
date: Thu Dec 04 17:51:28 2008 +0000
summary: Default values for function arguments

4. c++exception

When C code calls C++ code, all C++ exceptions need to be caught
and fully contained within the C++ code. Exceptions should never
be thrown outward across the C/C++ frontier.

If an exception is not caught within C++ code, and the search for
a matching 'catch' bumps into a C stack frame, the result may be
platform dependent. On my platform (Linux/GCC), if this happens
in the postgres backend, the process terminates silently as if
abort() had been called.

With this patch, if --enable-cplusplus is configured,
PostgresMain defines a handler to intercept any uncaught C++
exception and convert it to a conventional PostgreSQL error of
FATAL severity. This allows the backend to clean up and report
the error before terminating.

Attachments:

c++exception.patchtext/plain; name=c++exception.patchDownload
diff -r 9b2c774a6b05 src/backend/tcop/Makefile
--- a/src/backend/tcop/Makefile
+++ b/src/backend/tcop/Makefile
@@ -14,6 +14,11 @@

 OBJS= dest.o fastpath.o postgres.o pquery.o utility.o

+# Designate modules to be compiled as C++ when 'configure --enable-cplusplus'
+ifeq ($(enable_cplusplus),yes)
+CXXOBJS = postgres.o
+endif
+
 ifneq (,$(filter $(PORTNAME),cygwin win32))
 override CPPFLAGS += -DWIN32_STACK_RLIMIT=$(WIN32_STACK_RLIMIT)
 endif
diff -r 9b2c774a6b05 src/backend/tcop/postgres.c
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -33,6 +33,17 @@
 #endif
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
+#endif
+
+#ifdef ENABLE_CPLUSPLUS
+#ifndef __cplusplus
+#error --enable-cplusplus configure option specified; this file should be compiled as C++
+#endif
+#include <exception>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
 #endif

 #ifndef HAVE_GETRUSAGE
@@ -163,6 +174,11 @@
 #endif   /* TCOP_DONTUSENEWLINE */


+#ifdef __cplusplus
+}                               /* extern "C" */
+#endif
+
+
 /* ----------------------------------------------------------------
  *		decls for routines only used in this file
  * ----------------------------------------------------------------
@@ -1212,7 +1228,7 @@
 		if (log_parser_stats)
 			ResetUsage();

-		query = parse_analyze_varparams(copyObject(raw_parse_tree),
+		query = parse_analyze_varparams((Node *)copyObject(raw_parse_tree),
 										query_string,
 										&paramTypes,
 										&numParams);
@@ -1679,7 +1695,7 @@
 		 * we have to make a copy of the parse trees.  FIXME someday.
 		 */
 		oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
-		query_list = copyObject(cplan->stmt_list);
+		query_list = (List *)copyObject(cplan->stmt_list);
 		plan_list = pg_plan_queries(query_list, 0, params, true);
 		MemoryContextSwitchTo(oldContext);

@@ -2791,6 +2807,29 @@

 	return NULL;
 }
+
+
+#ifdef ENABLE_CPLUSPLUS
+/*
+ * PostgresMainUncaught
+ *      Called when C++ code throws an exception which is not caught.
+ *
+ * NB: On some platforms when C++ code calls C code, and the C code calls
+ * a deeper layer of C++ code, the outer C++ code can't catch exceptions
+ * thrown by the inner C++ code.  The search for a matching 'catch' is
+ * abandoned upon encountering an intervening C stack frame, and the
+ * exception is considered uncaught.
+ */
+static void
+PostgresMainUncaught()
+{
+    /* Context callbacks might not work right if call stack has been unwound */
+    error_context_stack = NULL;
+
+    elog(FATAL, "Unexpected internal error: Unhandled C++ exception");
+    abort();                                /* not reached */
+}
+#endif  /* ENABLE_CPLUSPLUS */


 /* ----------------------------------------------------------------
@@ -2850,6 +2889,11 @@
 	/* Set up reference point for stack depth checking */
 	stack_base_ptr = &stack_base;

+#ifdef ENABLE_CPLUSPLUS
+    /* Any unhandled C++ exception is to be treated as a FATAL error. */
+    std::set_terminate(PostgresMainUncaught);
+#endif
+
 	/* Compute paths, if we didn't inherit them from postmaster */
 	if (my_exec_path[0] == '\0')
 	{
@@ -3108,10 +3152,10 @@
 			char	   *name;
 			char	   *value;

-			name = lfirst(gucopts);
+			name = (char *)lfirst(gucopts);
 			gucopts = lnext(gucopts);

-			value = lfirst(gucopts);
+			value = (char *)lfirst(gucopts);
 			gucopts = lnext(gucopts);

 			if (IsSuperuserConfigOption(name))
#10Greg Smith
gsmith@gregsmith.com
In reply to: Kurt Harriman (#4)
Re: Mostly Harmless: Welcoming our C++ friends

On Fri, 5 Dec 2008, Kurt Harriman wrote:

Actually I did email this to the list with 4 separate diffs in
4 separate attached files. I don't know why it appears all
massed together at http://archives.postgresql.org/pgsql-hackers.

Thanks for being so attentive. Your e-mail was fine, the archives just
mash multiple text-based attachments tagged as Text/PLAIN together like
that, as does my mail reader. 1522 lines of only renaming in part 1, no
wonder I gave up.

I see you've already started re-sending the individual parts as separate
messages; that's nice for initial casual browsing of them, but will get
boring for everybody if you do that every time. If you've got more than
one text file to attach, for future updates you might consider a tar
archive of them to keep them running together in the archives. Once
you're putting stuff into an archive, might as well compress it too,
particularly for a patch of this size.

--
* Greg Smith gsmith@gregsmith.com http://www.gregsmith.com Baltimore, MD

#11David Lee Lambert
davidl@lmert.com
In reply to: Peter Eisentraut (#2)
Re: Mostly Harmless: Welcoming our C++ friends

On Friday 05 December 2008 03:55, Peter Eisentraut wrote:

Kurt Harriman wrote:

Sometimes people would like to call C++ code in the PostgreSQL
backend environment... for example, in user-defined functions,
triggers, access methods. And there is sometimes a need for
C++ code to call back into PostgreSQL's C functions, such as
the SPI interface.

Have you considered writing a procedural language plugin for C++?
PostgreSQL supports a lot of extension languages, and none of them
require the amount of backend changes that you outline here, because the
PL plugin serves as glue.

I think this patch is great, although I haven't had time to test it yet. The
only real "backend change" is the exception-handling clause; and the fact
that the backend will also be linked against the C++ runtime library.
Everything else is routine stuff that an experienced C++ developer would end
up catching while trying to get his build-system for a new project running;
but it could certainly scare away someone with less experience. Better to
deal with this way ahead of time and test it on a few platforms.

--
David Lee Lambert ... Software Developer
Cell phone: +1 586-873-8813 ; alt. email <dlambert@bmtcarhaul.com> or
<lamber45@msu.edu>
GPG key at http://www.lmert.com/keyring.txt

#12Gregory Stark
stark@enterprisedb.com
In reply to: Greg Smith (#5)
Re: Mostly Harmless: Welcoming our C++ friends

Greg Smith <gsmith@gregsmith.com> writes:

You can just ignore this late night bit of idiocy, or mock me for it as you see
fit. Note to other reviewers: if your e-mail client is the sort that bunches
a series of text attachments all together, make sure to scroll completely past
the first patch in the diff before you pay attention to the rest of it. I'm
going to bed.

Your email client is doing the right thing. The attachments had the following
header on them which controls this:

Content-Disposition: inline;

I wonder how many email clients let the poster control this header though :(
If you post with content-disposition set to "attachment" instead of "inline"
it should appear as a separate file you can save.

Regarding the patches, we could apply the trivial stuff right around the time
of the pgindent run, after all the major patches are drained from the queue so
it doesn't cause extra conflicts. It would still cause any other pending
patches for 8.5 to bitrot but from the sounds of things shouldn't be too hard
to fix up.

It seems to me we ought to do this regardless of whether we apply the
functional changes.

--
Gregory Stark
EnterpriseDB http://www.enterprisedb.com
Ask me about EnterpriseDB's On-Demand Production Tuning

#13Kurt Harriman
harriman@acm.org
In reply to: Peter Eisentraut (#2)
Re: Mostly Harmless: Welcoming our C++ friends

Hi Peter,

Have you considered writing a procedural language plugin for C++?

C++ can masquerade as C, so I don't think it needs a separate
plugin. Just tell PostgreSQL that your user-defined function
is C even though you secretly know it is C++.

This series of patches is meant to address some of the
mechanics of getting C++ code compiled and linked for the
PostgreSQL backend environment.

At present the build system has no support for languages other
than C. To interface PostgreSQL to a C++ tool or library, it's
necessary to either hack the PostgreSQL build system, or bypass
it and set up your own build system. Either alternative is
likely to be non-portable and difficult for others to understand
or use. This presents a serious obstacle to contributing the
code to the PostgreSQL community or sharing it with others.

Because C++ is so similar to C, the PostgreSQL build system can
easily provide equal support to both languages. C++ users can
then integrate their code easily and portably, and others can
share the code with no need to wrestle with jury-rigged
makefiles. Nobody should have to figure out autoconf, m4,
and gmake unless they want to.

The 'c++configure' patch therefore addresses the necessity to
find the host platform's C++ compiler; invoke it with appropriate
options; link with the C++ runtime library; and initialize the
C++ environment.

Another obstacle which would not be addressed by a procedural
language plugin is the problem of access to the backend's APIs
and data structures. C++ can use C declarations directly with
no extra wrappers or translation layers such as other languages
usually need. However, C++ cannot parse a C header file in
which a C++ reserved word is used as an identifier. The
'c++reserved' patch renames some fields in a very few header
files so C++ code can interface with the PostgreSQL backend
environment to the extent needed for implementing a procedural
language, data type, etc. Although tedious, such renaming is
by far the most reliable, maintainable and efficient means of
exposing the PostgreSQL runtime facilities to C++. As a
straightforward renaming, it is a safe change: its completeness
and much of its correctness are checked by the C compiler.

PostgreSQL supports a lot of extension languages, and none of
them require the amount of backend changes that you outline here,
because the PL plugin serves as glue.

C++ doesn't need glue like those other languages, but it does need
just a little help so that it can be used for the same kinds of
jobs that C is used for.

Those other extension languages, such as plpgsql or plpython,
serve a different audience than C or C++. They offer quick
development, ease of use, and high-level expressiveness where
performance is not the primary concern.

C or C++ are chosen when high performance is needed with precise
control over data representation and the ability to interoperate
directly with almost any language / library / system call / network
protocol / etc - notably, PostgreSQL's own tree structures and
data types.

Thanks for your comments; I hope I've responded adequately.
In any case, I welcome further dialogue on these or other topics.

Regards,
... kurt

Peter Eisentraut wrote:

Show quoted text

Kurt Harriman wrote:

Sometimes people would like to call C++ code in the PostgreSQL
backend environment... for example, in user-defined functions,
triggers, access methods. And there is sometimes a need for
C++ code to call back into PostgreSQL's C functions, such as
the SPI interface.

Have you considered writing a procedural language plugin for C++?
PostgreSQL supports a lot of extension languages, and none of them
require the amount of backend changes that you outline here, because the
PL plugin serves as glue.

#14Gregory Stark
stark@enterprisedb.com
In reply to: Kurt Harriman (#13)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman <harriman@acm.org> writes:

Hi Peter,

Have you considered writing a procedural language plugin for C++?

C++ can masquerade as C, so I don't think it needs a separate
plugin. Just tell PostgreSQL that your user-defined function
is C even though you secretly know it is C++.

Well one thing that might be useful for a c++ procedural language would be
catching C++ exceptions and translating them into ereports which could then be
caught in Postgres.

That's actually what I thought you had done but I just reread your mail and
realized you only handled unhandled exceptions which cause the backend to die.

The other way around could be useful too -- catching ereports/elogs within a
backend API call from C++ code and throwing a C++ exception. I'm not sure if
that's doable though.

--
Gregory Stark
EnterpriseDB http://www.enterprisedb.com
Ask me about EnterpriseDB's RemoteDBA services!

#15Peter Eisentraut
peter_e@gmx.net
In reply to: Kurt Harriman (#13)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman wrote:

Have you considered writing a procedural language plugin for C++?

C++ can masquerade as C, so I don't think it needs a separate
plugin. Just tell PostgreSQL that your user-defined function
is C even though you secretly know it is C++.

FYI, we have received patches morally equivalent to yours many times
over the years, and they have all been rejected. You might want to
review the archives about that.

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: Kurt Harriman (#1)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman <harriman@acm.org> writes:

[ make the backend C++-compilable ]

This has been proposed before, and rejected before, and I don't believe
the arguments have changed in the least.

regards, tom lane

#17Tom Lane
tgl@sss.pgh.pa.us
In reply to: Gregory Stark (#14)
Re: Mostly Harmless: Welcoming our C++ friends

Gregory Stark <stark@enterprisedb.com> writes:

Well one thing that might be useful for a c++ procedural language would be
catching C++ exceptions and translating them into ereports which could then be
caught in Postgres.

That's actually what I thought you had done but I just reread your mail and
realized you only handled unhandled exceptions which cause the backend to die.

Well, that's too bad, because fixing the error-handling impedance
mismatch is the one thing that's been missing from every previous
proposal, and it's the one thing that might actually make C++ in the
backend useful rather than a toy.

It's possible/likely that this would be easier to do in the context of
a PL; that would at least provide a single point at which to catch
C++ exceptions and turn them into elogs. The hard part is turning
elogs into exceptions so that errors thrown by core backend functions
that're called by the C++ code will behave as a C++ programmer would
expect.

For comparison look at the way that errors are handled in pl/perl etc.
The relatively narrow "SPI" API for calling back into the main backend
makes it somewhat sane to convert elogs into Perl errors, though it's
less efficient than one could wish. I don't know how to scale that
solution up to the point where you could call any random internal
backend function, as Kurt seems to be hoping for.

regards, tom lane

#18Kurt Harriman
harriman@acm.org
In reply to: Peter Eisentraut (#15)
Re: Mostly Harmless: Welcoming our C++ friends

Peter Eisentraut wrote:

FYI, we have received patches morally equivalent to yours many times
over the years, and they have all been rejected. You might want to
review the archives about that.

Hi Peter,

I went back as far as 2005 in the archives, and found only this thread
covering similar territory:

* SPI-header-files safe for C++-compiler
http://groups.google.com/group/pgsql.patches/browse_frm/thread/6dab9a8134cce102/3c91e40a9e615362?lnk=gst&amp;q=rejected+c%2B%2B#3c91e40a9e615362
or http://tinyurl.com/6bjcdq
June 2007

That patch appears approximately equivalent to the first two of my
patches, c++reserved and c++bookends. The opposing arguments in
that thread seem strained, in my opinion, conveying more heat than
light. "Hey you kids, get off my lawn!" The conclusion of the
deliberative process wasn't set down in that thread; but evidently
the arguments in favor were not sufficiently persuasive: in the
end, the patch was not applied.

The foremost opposing argument seems to have been that there
should be no attempt to alleviate the existing reserved word
problem without automatic enforcement to guarantee that never
in the future can new occurrences be introduced.

But can we not separate the two problems of (1) actual identifiers
which prevent C++ compilation today, vs. (2) hypothetical code which
someone might submit in the future? The first problem is immediate;
the second would only be troublesome if the hypothetical identifier
makes it all the way through beta testing into a release.

Post #21 in the thread, by Tom Lane on July 4 2007 at 8:05 am,
suggests an automated check for non-C++-compilable header files,
and highlights the practical difficulties caused by lack of C++
support in the build system. To invoke the C++ compiler at
present, typically one would use a hard-wired compiler name
with hard-wired flags and paths. My third patch - c++configure -
begins to address the need for a portable way to build C++ code,
compatible with the way we build C code.

The notion of converting all of PostgreSQL to C++ was touched upon.
Little would be gained, at the cost of much tedium, so I advise
against it. I wouldn't want to redo the old stuff unless there's a
clear benefit. My proposal aims to make C++ a practical choice for
adding *new* things to PostgreSQL.

A topic of great interest is the relationship between C++ exceptions
and the PostgreSQL backend's error handling based on setjmp/longjmp.
My fourth patch - c++exception - adds a backstop to limit the damage
in case a C++ exception is thrown from anywhere in the backend and
not caught. The patch converts an uncaught exception to a PostgreSQL
FATAL error, so the process can clean itself up and report its failure
rather than just silently disappearing. If C++ code doesn't catch its
exceptions, that is a programming error, similar to a segment
violation or null pointer dereference, and worthy of termination.

These four patches aren't meant to create a palace of luxury for
C++ programmers. More could be done: more sophisticated error
handling could be provided; new/delete could be hooked up to
palloc/pfree; templates and class libraries could be written.
But C++ programmers can do these things for themselves, if we
give them a fighting chance: just take away the roadblocks
(primarily the reserved words) and make it easy to compile and
link.

Regards,
... kurt

PS. A few other threads had (at least somewhat) relevant discussion.
They're listed below. I didn't find any other patches. I'd appreciate
any links or pointers to any other threads which I should look at.

* STL problem in stored procedures
http://groups.google.com/group/pgsql.general/browse_frm/thread/ee352086139df2bf/400e8133b3e87d74?tvc=1&amp;q=stl+problem+in+stored+procedures#400e8133b3e87d74
http://tinyurl.com/5hhf2v
October 2005

* C++ -> C : Module for converting the WHERE clause to the canonical form with PostgreSQL
http://groups.google.com/group/pgsql.hackers/browse_frm/thread/6cb99c3521318653/d6f2b9509cda35c5?lnk=gst&amp;q=tom+lane+c%2B%2B#d6f2b9509cda35c5
or http://tinyurl.com/6atqmq
January 2006

* PG Extensions: Must be statically linked?
http://groups.google.com/group/pgsql.hackers/browse_frm/thread/89d3650c52430186/c63c94680b399827?lnk=gst&amp;q=pg+extensions+must+be+statically+linked#c63c94680b399827
or http://tinyurl.com/6q5jdz
March 2006

* Writing triggers in C++
http://groups.google.com/group/pgsql.hackers/browse_frm/thread/2a95d656b8add4dd/ded7ff4ce06ae456?lnk=gst&amp;q=writing+triggers+in+c%2B%2B#ded7ff4ce06ae456
or http://tinyurl.com/6kx8ba
February 2007

#19Kurt Harriman
harriman@acm.org
In reply to: Tom Lane (#16)
Re: Mostly Harmless: Welcoming our C++ friends

Tom Lane wrote:

Kurt Harriman <harriman@acm.org> writes:

[ make the backend C++-compilable ]

This has been proposed before, and rejected before, and I don't believe
the arguments have changed in the least.

Hi Tom,

Of the series of four patches, the first two (c++reserved and c++bookends)
appear much the same as Jacob Rief's patch submitted in June 2007.
http://tinyurl.com/6bjcdq
(Incidentally, I only just now found that thread. I hadn't seen it
earlier because I hadn't searched the now-defunct pgsql-patches list.)

The third patch (c++configure) addresses a problem which I have not
seen discussed before: There needs to be a portable way to compile
and link C++ code.

As it stands, the third patch depends upon the first two, because the
third one can optionally compile main.c as C++. Since main.c includes
some header files in which C++ reserved words are used as identifiers,
it cannot be compiled as C++ without fixing at least a subset of those
identifiers.

However, if it is decided that the identifiers cannot be changed, then
I could revise the c++configure and c++exception patches to remove the
dependency.

Of course it can be expected that, once or twice a year, some
starry-eyed newcomer will repeat the plea for the reserved words
to be fixed, until you succumb or add it to the FAQ.

If a C++ programmer needs ereport(ERROR)s to be recast as C++
exceptions, I propose they can handle that in their own code
without special provisions being made in PostgreSQL code.
Therefore, I claim it does not need to be addressed in this
series of patches. It is a separate issue.

However, PostgreSQL code should provide a last-resort exception handler
as a backstop against C++ programming errors. That is the purpose of
the fourth patch (c++exception). C++ programmers should catch their
own exceptions, but if they let one get away, PostgresMain should try
to make sure the shared segment isn't left in a corrupt state. In
other words, PostgresMain's defense against uncaught C++ exceptions
should be approximately equivalent to its existing defense against
SIGSEGVs, null pointer dereferencing errors, and similar faults in C.

Regards,
... kurt

#20David Lee Lambert
davidl@lmert.com
In reply to: Kurt Harriman (#19)
Re: Mostly Harmless: Welcoming our C++ friends

On Friday 05 December 2008 10:45, Kurt Harriman wrote:

Tom Lane wrote:

Kurt Harriman <harriman@acm.org> writes:

[ make the backend C++-compilable ]

I tested applying this patch to CVS HEAD today and compiling
with --enable-cplusplus with gcc 4.2:

$ ldd postmaster
...
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7bf9000)
...

Then I ran pgbench and played with a table with a UUID column. Performance
was great.

(I first mistakenly applied it against a not-up-to-date source-tree ---
something from mid-September --- and that ended up not compiling.)

I still have not tried this with my own C++ code, but it seems to have less
impact on the build process than some might have feared.

--
David Lee Lambert ... Software Developer
Cell phone: +1 586-873-8813 ; alt. email <dlambert@bmtcarhaul.com> or
<lamber45@msu.edu>
GPG key at http://www.lmert.com/keyring.txt

#21Robert Treat
xzilla@users.sourceforge.net
In reply to: Kurt Harriman (#18)
Re: Mostly Harmless: Welcoming our C++ friends

On Friday 05 December 2008 09:51:50 Kurt Harriman wrote:

Peter Eisentraut wrote:

FYI, we have received patches morally equivalent to yours many times
over the years, and they have all been rejected. You might want to
review the archives about that.

Hi Peter,

I went back as far as 2005 in the archives, and found only this thread
covering similar territory:

<snip>

The foremost opposing argument seems to have been that there
should be no attempt to alleviate the existing reserved word
problem without automatic enforcement to guarantee that never
in the future can new occurrences be introduced.

But can we not separate the two problems of (1) actual identifiers
which prevent C++ compilation today, vs. (2) hypothetical code which
someone might submit in the future? The first problem is immediate;
the second would only be troublesome if the hypothetical identifier
makes it all the way through beta testing into a release.

Actually, given your configure changes, istm a buildfarm member compiling
with --enablecplusplus would prevent any such issue from getting to far.

<snip>

PS. A few other threads had (at least somewhat) relevant discussion.
They're listed below. I didn't find any other patches. I'd appreciate
any links or pointers to any other threads which I should look at.

Might I suggest you collect all of these various arguments (both for and
against) and patches into a wiki page on the developers wiki?

Also, I've no real experience in masquerading c++ as c, but the main concern I
would have is possible imcompatabilities that might be introduced between
postgresql's compiled with c++ and those compiled in c. I'm not sure there
should be any, but maybe someone with more experience in this area might have
ideas on what to watch out for?

--
Robert Treat
Conjecture: http://www.xzilla.net
Consulting: http://www.omniti.com

#22Greg Smith
gsmith@gregsmith.com
In reply to: Robert Treat (#21)
Re: Mostly Harmless: Welcoming our C++ friends

On Fri, 5 Dec 2008, Robert Treat wrote:

Might I suggest you collect all of these various arguments (both for and
against) and patches into a wiki page on the developers wiki?

I'm getting the feeling this is going to take a while to sort out too.
Page with most of the relevant stuff Kurt has posted so far is now listed
under Development Projects on the wiki:
http://wiki.postgresql.org/wiki/C%2B%2B_Compatibility

--
* Greg Smith gsmith@gregsmith.com http://www.gregsmith.com Baltimore, MD

#23Bruce Momjian
bruce@momjian.us
In reply to: Greg Smith (#22)
Re: Mostly Harmless: Welcoming our C++ friends

Greg Smith wrote:

On Fri, 5 Dec 2008, Robert Treat wrote:

Might I suggest you collect all of these various arguments (both for and
against) and patches into a wiki page on the developers wiki?

I'm getting the feeling this is going to take a while to sort out too.
Page with most of the relevant stuff Kurt has posted so far is now listed
under Development Projects on the wiki:
http://wiki.postgresql.org/wiki/C%2B%2B_Compatibility

Is this a TODO?

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

#24James Mansion
james@mansionfamily.plus.com
In reply to: Kurt Harriman (#18)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman wrote:

The foremost opposing argument seems to have been that there
should be no attempt to alleviate the existing reserved word
problem without automatic enforcement to guarantee that never
in the future can new occurrences be introduced.

Is there anything in the source that would necessarily preclude using the
C++ compiler to build *all* the code?

I'd guess that this would be quite a big patch to do this in any places
where we have implicit conversions from void* to char* etc, but
the result is valid as C and C++ and arguably better documented.

C++ is picky about a few things you can do in C, but most of them
are things I'd rather not do anyway.

Run such a build on the build farm each night, and it will be obvious as
soon as C++-unfriendly code sneaks in.

And who know, maybe eventually we could use C++ properly in the
code.

James

#25Peter Eisentraut
peter_e@gmx.net
In reply to: James Mansion (#24)
Re: Mostly Harmless: Welcoming our C++ friends

On Saturday 06 December 2008 22:38:29 James Mansion wrote:

Kurt Harriman wrote:

The foremost opposing argument seems to have been that there
should be no attempt to alleviate the existing reserved word
problem without automatic enforcement to guarantee that never
in the future can new occurrences be introduced.

Is there anything in the source that would necessarily preclude using the
C++ compiler to build *all* the code?

Probably lots, but that's not the problem we are trying to solve here. And
many people are seriously not interested in using C++ for PostgreSQL.

#26Andrew Dunstan
andrew@dunslane.net
In reply to: Peter Eisentraut (#25)
Re: Mostly Harmless: Welcoming our C++ friends

Peter Eisentraut wrote:

On Saturday 06 December 2008 22:38:29 James Mansion wrote:

Kurt Harriman wrote:

The foremost opposing argument seems to have been that there
should be no attempt to alleviate the existing reserved word
problem without automatic enforcement to guarantee that never
in the future can new occurrences be introduced.

Is there anything in the source that would necessarily preclude using the
C++ compiler to build *all* the code?

Probably lots, but that's not the problem we are trying to solve here. And
many people are seriously not interested in using C++ for PostgreSQL.

The most serious problem AFAIK is that we use setjmp/longjmp, which I
understand does not play at all nicely with C++ exceptions.

cheers

andrew

#27Peter Eisentraut
peter_e@gmx.net
In reply to: Andrew Dunstan (#26)
Re: Mostly Harmless: Welcoming our C++ friends

Andrew Dunstan wrote:

The most serious problem AFAIK is that we use setjmp/longjmp, which I
understand does not play at all nicely with C++ exceptions.

Considering the complexity of the code and how it at times stretches the
C standard to the point of cheating, I think anyone's three-item list of
major problems is going to be much too short.

#28Kurt Harriman
harriman@acm.org
In reply to: James Mansion (#24)
Re: Mostly Harmless: Welcoming our C++ friends

Is there anything in the source that would necessarily preclude using the
C++ compiler to build *all* the code?

No. Most of the source files would need a sprinkling of
tiny changes: typically only a handful of casts need to be
added. Some files would need more widespread (but still
trivial) changes, such as renaming local variables or
parameters which are C++ reserved words. There are a few
head-scratchers: see this post (1 July 2007)
http://groups.google.com/group/pgsql.patches/msg/91775dc1355cdc72
or http://tinyurl.com/6a67ms

I've actually gone through the tedious experiment of fixing up
about 40 of the source files so they can be compiled as either
C or C++. With these files compiled as C++, and the remainder
compiled as C, PostgreSQL builds successfully and passes the
'make check' regression tests. The intermixture of C together
with C-compiled-as-C++ works just fine, at least on my x86-32
Linux platform. On the other hand, PostgreSQL already works
as C; trying to convert it all to C++ doesn't seem useful.

Suppose we were to use the C++ compiler to build all of
PostgreSQL. Consider the alternatives: either

A) switch over entirely to C++, no longer supporting C; or

B) let the build farm do a nightly build with a C++ compiler
merely as a test to verify that no C++ compilation errors
are introduced, but continue to use C 'officially' for
builds and releases; or

C) support C and C++ equally, allowing the choice to be made
by each person who builds PostgreSQL from source.

Alternative A breaks (almost?) all existing third party
extension code: sufficient reason to rule out this alternative.

With Alternative B, most development work would probably still
be done in C. C programmers surely won't embrace the idea
that they should conform to C++ rules and take care that their
C code is C++-compilable. Some of the C++ rules are obscure;
rare is the C++ programmer who never omits a needed cast.
Every patch will have to be checked for C++ compatibility.
If the build farm detects a C++ error, likely one of the
committers would be saddled with the burden of backing
out the patch and/or correcting the error.

Alternative C seems to just about double the amount of work
involved in every commit, build, and release. Again, much
of the burden probably falls on the committers.

All the extra work and trouble will be justified if there is
a truly spectacular payoff. What magnificence awaits us when
all of PostgreSQL is C++-compilable? I don't have a good
answer.

The best alternative, in my opinion, is "none of the above".
That's why I have instead offered some patches to enable C++
for new extensions and add-on development with minimal
impact to the C core.

As a courteous host, one might extend hospitality to a guest,
but not indeed go so far as to redecorate the house from top
to bottom to suit the guest's taste.

Regards,
... kurt

James Mansion wrote:

Show quoted text

Is there anything in the source that would necessarily preclude using the
C++ compiler to build *all* the code?

I'd guess that this would be quite a big patch to do this in any places
where we have implicit conversions from void* to char* etc, but
the result is valid as C and C++ and arguably better documented.

C++ is picky about a few things you can do in C, but most of them
are things I'd rather not do anyway.

Run such a build on the build farm each night, and it will be obvious as
soon as C++-unfriendly code sneaks in.

And who know, maybe eventually we could use C++ properly in the
code.

James

#29Tom Lane
tgl@sss.pgh.pa.us
In reply to: Kurt Harriman (#28)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman <harriman@acm.org> writes:

Suppose we were to use the C++ compiler to build all of
PostgreSQL. Consider the alternatives: either

A) switch over entirely to C++, no longer supporting C; or

B) let the build farm do a nightly build with a C++ compiler
merely as a test to verify that no C++ compilation errors
are introduced, but continue to use C 'officially' for
builds and releases; or

C) support C and C++ equally, allowing the choice to be made
by each person who builds PostgreSQL from source.

Alternative A breaks (almost?) all existing third party
extension code: sufficient reason to rule out this alternative.

This project isn't even willing to require that people use a C99
compiler ... you won't get far suggesting that the minimum tool be
upped to C++.

With Alternative B, most development work would probably still
be done in C.

s/most/all/, at least for anything that has ambitions of getting into
the core distribution. You can't code in C++ if it needs to be
C-compilable. For the same reason, I don't think alternative C is
materially different from alternative B: either way the rule is
"Write C that doesn't give a C++ compiler indigestion".

All the extra work and trouble will be justified if there is
a truly spectacular payoff. What magnificence awaits us when
all of PostgreSQL is C++-compilable? I don't have a good
answer.

Given the above constraints, I think the only real role for C++ here
would be to allow access to third-party C++ libraries as Postgres
extensions --- for instance something like an XML or numerical analysis
library. Now by definition such libraries aren't trying to call into
any core Postgres code, so it doesn't seem like converting all the
headers to be C++-safe is really an especially useful goal anyhow.
There's a subset of headers, like fmgr.h and funcapi.h, that would be
needed by the interface layer for such a project, and maybe they should
be made C++-clean.

The stumbling block, though, remains the same as I mentioned in the
message you linked to: if we fix some or all of the headers, what's the
plan for making sure that they stay fixed? Without a C++ buildfarm
member I think the chances of future breakage approach certainty. So it
seems like we have a very high initial investment to obtain something
that is really of unclear value.

regards, tom lane

#30Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#29)
Re: Mostly Harmless: Welcoming our C++ friends

I wrote:

The stumbling block, though, remains the same as I mentioned in the
message you linked to: if we fix some or all of the headers, what's the
plan for making sure that they stay fixed? Without a C++ buildfarm
member I think the chances of future breakage approach certainty.

Actually, after re-reading the whole earlier thread I see that we did
think of a possible answer to that:
http://archives.postgresql.org/pgsql-patches/2007-07/msg00056.php
which in fact is on the TODO list now. So if someone wanted to step
up and make that happen, it would become sane to try to have C++-clean
headers.

regards, tom lane

#31Ron Mayer
rm_pg@cheapcomplexdevices.com
In reply to: Tom Lane (#29)
Re: Mostly Harmless: Welcoming our C++ friends

Tom Lane wrote:

Given the above constraints, I think the only real role for C++ here
would be to allow access to third-party C++ libraries as Postgres
extensions --- for instance something like an XML or numerical analysis

I seem to recall that we're already able to do this.

IIRC, some older postgis's wrapped some C++ library that they
used internally; and some of my old scripts for installing
postgres have: "env LDFLAGS=-lstdc++ ./configure --prefix=$PGHOME"

I guess existing current c++ postgres extensions probably have a C wrapper?
and I guess the main benefit of this project would be that the C wrapper
could be thinner (or even nonexistant?) with these proposed changes?

#32Kurt Harriman
harriman@acm.org
In reply to: Tom Lane (#30)
Re: Mostly Harmless: Welcoming our C++ friends

Tom Lane wrote:

if we fix some or all of the headers, what's the
plan for making sure that they stay fixed? Without a C++ buildfarm
member I think the chances of future breakage approach certainty.

Actually, after re-reading the whole earlier thread I see that we did
think of a possible answer to that:
http://archives.postgresql.org/pgsql-patches/2007-07/msg00056.php
which in fact is on the TODO list now. So if someone wanted to step
up and make that happen, it would become sane to try to have C++-clean
headers.

I'd be happy to work on that.

However, probably an easier alternative would be to have
just one buildfarm machine do a nightly build configured
with the --enable-cplusplus option.

This would build one file - main.c - as C++ (necessary
because on some platforms the main() function needs to be
C++ to ensure the C++ runtime library is initialized).
The C++ compilation of main.c will fail if any C++
reserved words have been used as identifiers in the headers
included there. main.c already pulls in most of the headers
which are of interest for calling back in to postgres
(see attached .svg file). To complete the set, I could add
#include's for funcapi.h and spi.h.

C++-clean headers should be far less burdensome than trying
to keep the whole codebase C++-clean, because it is not very
often that someone would inadvertently choose a C++ reserved
word to use as a new field name or identifier in one of these
.h files; and main.c is not often changed.

(One of my patches - c++exception - adds a second file to
be C++ compiled (postgres.c). I'm planning to revise that
patch so that only main.c gets C++ compiled, to reduce the
exposure to inadvertent breakage of the --enable-cplusplus
build.)

Would it be worthwhile to make all the headers C++-clean,
rather than just the ones which seem likely to be pulled
in by a new access method, data type, or programming
language? The pgcompinclude proposal would be attractive
if every header file needs to be checked. (My opinion:
do that only if somebody needs it.)

Regards,
... kurt

#33Kurt Harriman
harriman@acm.org
In reply to: Kurt Harriman (#32)
1 attachment(s)
Re: Mostly Harmless: Welcoming our C++ friends

... forgot to attach the .svg file showing the files
#included by main.c. Here it is.

Attachments:

IncludeGraph-main-c.svgimage/svg+xml; name=IncludeGraph-main-c.svgDownload
#34Tom Lane
tgl@sss.pgh.pa.us
In reply to: Kurt Harriman (#32)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman <harriman@acm.org> writes:

However, probably an easier alternative would be to have
just one buildfarm machine do a nightly build configured
with the --enable-cplusplus option.

There is no such option, and won't be.

This would build one file - main.c - as C++ (necessary
because on some platforms the main() function needs to be
C++ to ensure the C++ runtime library is initialized).

Useless, since main.c doesn't include any large number of headers,
and in particular there is no reason for it to include the headers
that are critical to function libraries.

regards, tom lane

#35Kurt Harriman
harriman@acm.org
In reply to: Tom Lane (#34)
Re: Mostly Harmless: Welcoming our C++ friends

Tom Lane wrote:

Kurt Harriman <harriman@acm.org> writes:

However, probably an easier alternative would be to have
just one buildfarm machine do a nightly build configured
with the --enable-cplusplus option.

There is no such option, and won't be.

Yours is the first comment anyone has posted to the list
regarding my proposed c++configure patch, and it sounds
alarmingly definite.

May I ask you to elaborate? Have you more to say on the
subject?

This would build one file - main.c - as C++ (necessary
because on some platforms the main() function needs to be
C++ to ensure the C++ runtime library is initialized).

Useless, since main.c doesn't include any large number of headers,

main.c directly or indirectly includes these 71 headers:
access/attnum.h access/genam.h access/heapam.h
access/htup.h access/rmgr.h access/sdir.h
access/skey.h access/tupdesc.h access/tupmacs.h
access/xlog.h access/xlogdefs.h bootstrap/bootstrap.h
c.h catalog/genbki.h catalog/pg_am.h
catalog/pg_attribute.h catalog/pg_class.h catalog/pg_index.h
executor/execdesc.h executor/tuptable.h fmgr.h
lib/stringinfo.h nodes/bitmapset.h nodes/execnodes.h
nodes/nodes.h nodes/params.h nodes/parsenodes.h
nodes/pg_list.h nodes/plannodes.h nodes/primnodes.h
nodes/tidbitmap.h nodes/value.h pg_config.h
pg_config_manual.h pg_config_os.h pgtime.h
port.h postgres.h postgres_ext.h
postmaster/postmaster.h rewrite/prs2lock.h storage/backendid.h
storage/block.h storage/buf.h storage/bufpage.h
storage/item.h storage/itemid.h storage/itemptr.h
storage/lock.h storage/lwlock.h storage/off.h
storage/relfilenode.h storage/shmem.h tcop/dest.h
tcop/tcopprot.h utils/array.h utils/elog.h
utils/errcodes.h utils/guc.h utils/help_config.h
utils/hsearch.h utils/int8.h utils/palloc.h
utils/pg_crc.h utils/pg_locale.h utils/ps_status.h
utils/rel.h utils/relcache.h utils/snapshot.h
utils/timestamp.h utils/tuplestore.h

and in particular there is no reason for it to include the headers
that are critical to function libraries.

Extra #includes could be added to main.c just for the purpose of
getting them C++-syntax-checked. Or, a few more .c files could be
chosen to expand the set of C++-syntax-checked headers. For
instance, xml.c pulls in spi.h and 96 other headers. 66 of them
overlap with main.c; but these 31 are new:
access/xact.h catalog/namespace.h catalog/pg_language.h
catalog/pg_proc.h catalog/pg_type.h commands/dbcommands.h
executor/execdefs.h executor/executor.h executor/spi.h
lib/dllist.h libpq/pqformat.h mb/pg_wchar.h
miscadmin.h nodes/memnodes.h nodes/nodeFuncs.h
nodes/relation.h tcop/pquery.h tcop/utility.h
utils/builtins.h utils/catcache.h utils/date.h
utils/datetime.h utils/datum.h utils/lsyscache.h
utils/memutils.h utils/plancache.h utils/portal.h
utils/resowner.h utils/syscache.h utils/tzparser.h
utils/xml.h
funcapi.h is still missing. One file that includes it is
pl_exec.c, which pulls in 8 more headers not already listed:
access/transam.h commands/trigger.h executor/spi_priv.h
funcapi.h parser/scansup.h plpgsql.h
utils/snapmgr.h utils/typcache.h
So C++-compiling just a few source files is sufficient to syntax
check a useful subset of header files including those which are
most important for add-on development.

However, the above approach has a couple of obvious caveats:

:( It doesn't give C++ users a precise specification of exactly
which header files they may rely upon from release to release.

:( From time to time, C++ programmers will probably come along
asking for even more header files to be sanitized.

The alternative which you have suggested, using pgcompinclude,
could solve these caveats by enforcing C++ safety upon every
PostgreSQL header file. And it would not require any more .c
files beyond main.c to be kept C++-clean.

http://archives.postgresql.org/pgsql-patches/2007-07/msg00056.php

I'll get started on the pgcompinclude thing.

Regards,
... kurt

#36James Mansion
james@mansionfamily.plus.com
In reply to: Kurt Harriman (#28)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman wrote:

B) let the build farm do a nightly build with a C++ compiler
merely as a test to verify that no C++ compilation errors
are introduced, but continue to use C 'officially' for
builds and releases; or

This was the intent of my suggestion.

There can be advantages in that you can use a lot of C99 (and
still port to non-C99 envs eg MSVC) if you have a few ifdefs
to use std::vector instead of dynamic arrays, but the bigger issue
(for me) was always been that the name mangling means that
you find out pretty quickly if you have a mismatch between
declaration and definition of functions.

Attempting the link with C++ mangling can put this to rest,
even if you never try running it.

#37Kevin Grittner
Kevin.Grittner@wicourts.gov
In reply to: Kurt Harriman (#28)
Re: Mostly Harmless: Welcoming our C++ friends

Kurt Harriman <harriman@acm.org> wrote:

That's why I have instead offered some patches to enable C++
for new extensions and add-on development with minimal
impact to the C core.

I've been a bit confused by this thread. We wrote a couple PostgreSQL
functions (pdftotext and pdfisok) which use libpoppler. It didn't
seem very hard to do without any of this. Granted, it isn't likely to
be portable to all environments, which is why we haven't bothered to
try to put it out for the community; but there didn't seem to be any
great barriers for our environment (SuSE/gcc). Is this intended to
make such efforts more portable, so they can be shared with more
environments?

Did we just get lucky?

-Kevin

P.S. Our environment:

PostgreSQL 8.3.5 on x86_64-unknown-linux-gnu, compiled by GCC gcc (GCC)
4.1.2 20070115 (SUSE Linux)

#38Tom Lane
tgl@sss.pgh.pa.us
In reply to: Kurt Harriman (#35)
Re: Mostly Harmless: Welcoming our C++ friends

[ just realized that I set this message aside to reply to later, and
then forgot about it --- apologies ]

Kurt Harriman <harriman@acm.org> writes:

Tom Lane wrote:

There is no such option, and won't be.

Yours is the first comment anyone has posted to the list
regarding my proposed c++configure patch, and it sounds
alarmingly definite.
May I ask you to elaborate? Have you more to say on the
subject?

Well, as I understand it the proposal is to build main.c as C++ in the
hope of (1) identifying C++ incompatibilities in our include headers,
and (2) linking C++ instead of C library on platforms where they are
different.

As for #1, main.c doesn't (and shouldn't) include a large fraction of
the headers that might be interesting to a C++ add-on --- I'm surprised
that it hits as many as it does, because it surely has no direct use
for most of them.

Extra #includes could be added to main.c just for the purpose of
getting them C++-syntax-checked.

They'd disappear again the next time Bruce runs his unnecessary-#include
elimination script. And anyway the vast majority of the inclusions you
show here are accidental, indirect inclusions that might go away in any
header refactoring.

As for #2, thanks but no thanks: the very last thing I want is to have a
switch that causes us to start running on a different basic C library.
That would open all sorts of portability and testability concerns.
AFAIK there are only a few obsolete platforms where a C++-specific libc
is needed, and I'm perfectly happy to blow off the idea of supporting
C++ add-ons on them.

So I'm willing to support a project of making *all* our headers (or at
least all the ones a C++ addon could possibly care about) C++-safe,
if there's buildfarm support for making sure they stay that way. But
I don't approve of changing the way main.c gets compiled.

I am, btw, still waiting for an actually plausible use-case for this.
AFAICS the setjmp-vs-exceptions thing puts a very serious crimp in
what you could hope to accomplish by importing a pile of C++ code.

regards, tom lane

#39Ron Mayer
rm_pg@cheapcomplexdevices.com
In reply to: Tom Lane (#38)
Re: Mostly Harmless: Welcoming our C++ friends

Tom Lane wrote:

I am, btw, still waiting for an actually plausible use-case for this.
AFAICS the setjmp-vs-exceptions thing puts a very serious crimp in
what you could hope to accomplish by importing a pile of C++ code.

The one use-case I can think of that imports a pile of C++ code
is the GEOS library that PostGIS uses (used?):

http://postgis.refractions.net/support/wiki/index.php?GEOS
"GEOS is a C++ port of the JTS Topology Suite. It is used by PostGIS to
implement Topological functions. "

However it seems to work fine even without the C++-header project,
so I must be missing something here...

#40Josh Berkus
josh@agliodbs.com
In reply to: Ron Mayer (#39)
Re: Mostly Harmless: Welcoming our C++ friends

Ron Mayer wrote:

Tom Lane wrote:

I am, btw, still waiting for an actually plausible use-case for this.
AFAICS the setjmp-vs-exceptions thing puts a very serious crimp in
what you could hope to accomplish by importing a pile of C++ code.

The one use-case I can think of that imports a pile of C++ code
is the GEOS library that PostGIS uses (used?):

There are also quite a number of OSS algorithms, useful for query
optimization or otherwise, which are written in C++. For example, the
fully OSS implementation of annealing (potentially useful as a
replacement for GEQO) is in C++.

However, the real reason to do this is to attract C++ hackers to hack on
PostgreSQL and extend it. Most of what makes PostgreSQL cool now we got
because PostgreSQL is so easy for C geeks to hack on. Who knows what
the C++ crowd will contribute if given the opportunity? It's not the
stuff we *know* we can get which is exciting, it's the stuff we don't
know about.

(and yes, I realize this would hold true of other programming languages
as well. However, we can't support them as easily as C++)

As the Guy Who Is Obsessed With Making Our Community Grow (GWIOWMOCG), I
strongly support this goal. Although the other issues like breakage
need fixing.

--Josh

#41Tom Lane
tgl@sss.pgh.pa.us
In reply to: Josh Berkus (#40)
Re: Mostly Harmless: Welcoming our C++ friends

Josh Berkus <josh@agliodbs.com> writes:

Ron Mayer wrote:

The one use-case I can think of that imports a pile of C++ code
is the GEOS library that PostGIS uses (used?):

There are also quite a number of OSS algorithms, useful for query
optimization or otherwise, which are written in C++. For example, the
fully OSS implementation of annealing (potentially useful as a
replacement for GEQO) is in C++.

Well, if we were actually contemplating using it, we'd rewrite it in C.
I don't see anyone around here who's in favor of increasing the minimum
build requirement to C++. (Even if we were, there's exactly 0 chance
that an existing hunk of C++ code would follow our error handling and
memory allocation conventions, so we'd have to do significant rewriting
anyway.)

The PostGIS-style case, where someone writes some code to provide a
mostly arm's-length interface to an external library written in C++,
is the only case I can see much use for. And that still leaves me
wondering what's the point of making our headers C++ clean, because
that external library isn't gonna include 'em anyway.

regards, tom lane

#42Bruce Momjian
bruce@momjian.us
In reply to: Kurt Harriman (#28)
Re: Mostly Harmless: Welcoming our C++ friends

Added to TODO:

Allow C++ code to more easily access backend code

* http://archives.postgresql.org/pgsql-hackers/2008-12/msg00302.php

---------------------------------------------------------------------------

Kurt Harriman wrote:

Is there anything in the source that would necessarily preclude using the
C++ compiler to build *all* the code?

No. Most of the source files would need a sprinkling of
tiny changes: typically only a handful of casts need to be
added. Some files would need more widespread (but still
trivial) changes, such as renaming local variables or
parameters which are C++ reserved words. There are a few
head-scratchers: see this post (1 July 2007)
http://groups.google.com/group/pgsql.patches/msg/91775dc1355cdc72
or http://tinyurl.com/6a67ms

I've actually gone through the tedious experiment of fixing up
about 40 of the source files so they can be compiled as either
C or C++. With these files compiled as C++, and the remainder
compiled as C, PostgreSQL builds successfully and passes the
'make check' regression tests. The intermixture of C together
with C-compiled-as-C++ works just fine, at least on my x86-32
Linux platform. On the other hand, PostgreSQL already works
as C; trying to convert it all to C++ doesn't seem useful.

Suppose we were to use the C++ compiler to build all of
PostgreSQL. Consider the alternatives: either

A) switch over entirely to C++, no longer supporting C; or

B) let the build farm do a nightly build with a C++ compiler
merely as a test to verify that no C++ compilation errors
are introduced, but continue to use C 'officially' for
builds and releases; or

C) support C and C++ equally, allowing the choice to be made
by each person who builds PostgreSQL from source.

Alternative A breaks (almost?) all existing third party
extension code: sufficient reason to rule out this alternative.

With Alternative B, most development work would probably still
be done in C. C programmers surely won't embrace the idea
that they should conform to C++ rules and take care that their
C code is C++-compilable. Some of the C++ rules are obscure;
rare is the C++ programmer who never omits a needed cast.
Every patch will have to be checked for C++ compatibility.
If the build farm detects a C++ error, likely one of the
committers would be saddled with the burden of backing
out the patch and/or correcting the error.

Alternative C seems to just about double the amount of work
involved in every commit, build, and release. Again, much
of the burden probably falls on the committers.

All the extra work and trouble will be justified if there is
a truly spectacular payoff. What magnificence awaits us when
all of PostgreSQL is C++-compilable? I don't have a good
answer.

The best alternative, in my opinion, is "none of the above".
That's why I have instead offered some patches to enable C++
for new extensions and add-on development with minimal
impact to the C core.

As a courteous host, one might extend hospitality to a guest,
but not indeed go so far as to redecorate the house from top
to bottom to suit the guest's taste.

Regards,
... kurt

James Mansion wrote:

Is there anything in the source that would necessarily preclude using the
C++ compiler to build *all* the code?

I'd guess that this would be quite a big patch to do this in any places
where we have implicit conversions from void* to char* etc, but
the result is valid as C and C++ and arguably better documented.

C++ is picky about a few things you can do in C, but most of them
are things I'd rather not do anyway.

Run such a build on the build farm each night, and it will be obvious as
soon as C++-unfriendly code sneaks in.

And who know, maybe eventually we could use C++ properly in the
code.

James

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

#43Peter Eisentraut
peter_e@gmx.net
In reply to: Kurt Harriman (#7)
Re: Mostly Harmless: c++bookends - patch 2 of 4

On Friday 05 December 2008 11:16:37 Kurt Harriman wrote:

Just a few additional header files are mentioned in the PostgreSQL
Reference Manual for add-on developers to use: fmgr.h, funcapi.h,
and spi.h. This patch adds bookends within those three files for
the benefit of beginners writing very simple extensions in C++.

I have signed up to review this patch series for the commit fest.

I can try to debunk this approach for selecting the files to add C++
decorations in: A grep through contrib/, which includes a variety of simple
and complex extensions, shows a count of 80 different backend includes being
used.

So I think either decoration is added to all of these files or none of them.
And I think the former is not going to go over well.

Documentation and learning are simplified because C example code
can be compiled as C or C++ without change.

I think having some subset of header files work with C++ without extra
decoration and some only with extra decoration will not necessarily improve
documentation and learning. Forcing people to add the decorations around
PostgreSQL backend header files will at least make them remember what they are
dealing with.

#44Peter Eisentraut
peter_e@gmx.net
In reply to: Kurt Harriman (#8)
Re: Mostly Harmless: c++configure - patch 3 of 4

On Friday 05 December 2008 11:18:46 Kurt Harriman wrote:

This patch adds C++ support to the PostgreSQL build system.

Unless you can provide a significant specific use case, I think this patch is
rejected. Building part of PostgreSQL sometimes with C++ would just add too
much uncertainty and maintenance overhead without a known benefit.

#45Peter Eisentraut
peter_e@gmx.net
In reply to: Kurt Harriman (#6)
Re: Mostly Harmless: c++reserved - patch 1 of 4

On Friday 05 December 2008 11:13:37 Kurt Harriman wrote:

Fortunately, there are not many instances which are likely
to be encountered by our C++ guests, and these can easily
be changed. In memnodes.h, parsenodes.h, and primnodes.h,
this patch changes the following field names:

typename => typeName
typeid => typeOid
using => usingClause
delete => delete_context

Also, the patch changes a few parameter names in function
prototypes in makefuncs.h, parse_type.h, and builtins.h:

typename => typeName
typeid => typeOid
namespace => qualifier

I'll see if I can adjust pgcompinclude for checking C++ compatibility of
headers automatically. If we have such a tool, this patch should be OK to go
in.

#46Peter Eisentraut
peter_e@gmx.net
In reply to: Kurt Harriman (#6)
Re: Mostly Harmless: c++reserved - patch 1 of 4

On Friday 05 December 2008 11:13:37 Kurt Harriman wrote:

1. c++reserved

I have applied (an extended version of) this patch.

#47Robert Haas
robertmhaas@gmail.com
In reply to: Peter Eisentraut (#43)
Re: Mostly Harmless: c++bookends - patch 2 of 4

On Mon, Jul 13, 2009 at 5:51 PM, Peter Eisentraut<peter_e@gmx.net> wrote:

So I think either decoration is added to all of these files or none of them.
And I think the former is not going to go over well.

We do have some things that are conditioned on __cplusplus already,
such as "c.h", "pg_config.h.in", and "postgres_ext.h". So at some
point we at least thought about supporting inclusion of our header
files from C++. But I agree that if we're going to do it at all, we
ought to do it everywhere.

...Robert

#48Peter Eisentraut
peter_e@gmx.net
In reply to: Robert Haas (#47)
Re: Mostly Harmless: c++bookends - patch 2 of 4

On Thursday 16 July 2009 17:00:03 Robert Haas wrote:

On Mon, Jul 13, 2009 at 5:51 PM, Peter Eisentraut<peter_e@gmx.net> wrote:

So I think either decoration is added to all of these files or none of
them. And I think the former is not going to go over well.

We do have some things that are conditioned on __cplusplus already,
such as "c.h", "pg_config.h.in", and "postgres_ext.h". So at some
point we at least thought about supporting inclusion of our header
files from C++. But I agree that if we're going to do it at all, we
ought to do it everywhere.

We do support using the frontend headers (libpq, ecpg) from C++. That's what
postgres_ext.h is about. The code in pg_config.h.in is autogenerated by
Autoconf. The stuff in c.h is probably still there from before we rearranged
the header files so that the frontend includes don't use c.h.