Index: src/backend/catalog/Makefile
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/Makefile,v
retrieving revision 1.66
diff -c -r1.66 Makefile
*** src/backend/catalog/Makefile	19 Feb 2008 10:30:07 -0000	1.66
--- src/backend/catalog/Makefile	6 Apr 2008 20:24:30 -0000
***************
*** 13,19 ****
  OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
         pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
         pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
!        pg_type.o toasting.o
  
  BKIFILES = postgres.bki postgres.description postgres.shdescription
  
--- 13,19 ----
  OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
         pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
         pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
!        pg_type.o toasting.o pg_module.o
  
  BKIFILES = postgres.bki postgres.description postgres.shdescription
  
***************
*** 35,41 ****
  	pg_database.h pg_tablespace.h pg_pltemplate.h \
  	pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
  	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
! 	pg_ts_parser.h pg_ts_template.h \
  	toasting.h indexing.h \
      )
  
--- 35,41 ----
  	pg_database.h pg_tablespace.h pg_pltemplate.h \
  	pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
  	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
! 	pg_ts_parser.h pg_ts_template.h pg_module.h \
  	toasting.h indexing.h \
      )
  
Index: src/backend/catalog/pg_module.c
===================================================================
RCS file: src/backend/catalog/pg_module.c
diff -N src/backend/catalog/pg_module.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/backend/catalog/pg_module.c	6 Apr 2008 20:24:30 -0000
***************
*** 0 ****
--- 1,116 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_module.c
+  *	  routines to support manipulation of the pg_module relation
+  *
+  * Copyright (c) 2008, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *	  $PostgreSQL: pgsql/src/backend/catalog/pg_enum.c,v 1.6 2008/03/26 21:10:37 alvherre Exp $
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ #include "access/genam.h"
+ #include "access/heapam.h"
+ /*
+ #include "catalog/catalog.h"
+ */
+ #include "catalog/indexing.h"
+ #include "catalog/pg_module.h"
+ #include "utils/builtins.h"
+ #include "utils/fmgroids.h"
+ #include "utils/tqual.h"
+ 
+ HeapTuple
+ FindModuleTuple(Relation rel, char *name);
+ /*
+  * EnumValuesCreate
+  *		Create an entry in pg_enum for each of the supplied enum values.
+  *
+  * vals is a list of Value strings.
+  */
+ Oid
+ ModuleCreate(char *name)
+ {
+ 	Relation	pg_module;
+ 	TupleDesc	tupDesc;
+ 	NameData	modulename;
+ 	Oid		oid;
+ 	Datum		values[Natts_pg_module];
+ 	char		nulls[Natts_pg_module];
+ 	HeapTuple	tup;
+ 
+ 
+ 	pg_module = heap_open(ModuleRelationId, RowExclusiveLock);
+         
+ 	tup = FindModuleTuple(pg_module, name);
+         if (HeapTupleIsValid(tup))
+                 elog(ERROR, "Module \"%s\" is already installed", name);
+ 
+ 
+ 	tupDesc = pg_module->rd_att;
+ 
+ 	/* and make the entries */
+ 	memset(nulls, ' ', sizeof(nulls));
+ 
+ 	namestrcpy(&modulename, name);
+ 	values[Anum_pg_module_modulename - 1] = NameGetDatum(&modulename);
+ 
+ 	tup = heap_formtuple(tupDesc, values, nulls);
+ 
+ 	oid = simple_heap_insert(pg_module, tup);
+ 	CatalogUpdateIndexes(pg_module, tup);
+ 	heap_freetuple(tup);
+ 
+ 
+ 	/* clean up */
+ 	heap_close(pg_module, RowExclusiveLock);
+ 
+ 	return oid;
+ }
+ 
+ 
+ 
+ void
+ ModuleRemove(char *name)
+ {
+         Relation        relation;
+         HeapTuple       tup;
+ 
+         relation = heap_open(ModuleRelationId, RowExclusiveLock);
+ 
+ 	
+         tup = FindModuleTuple(relation, name);
+         if (!HeapTupleIsValid(tup))
+                 elog(ERROR, "Module \"%s\" is not installed", name);
+ 
+         simple_heap_delete(relation, &tup->t_self);
+ 
+         heap_close(relation, RowExclusiveLock);
+ }
+ 
+ HeapTuple
+ FindModuleTuple(Relation rel, char *name)
+ {
+ 	HeapTuple	tup = 0, scantup;
+         ScanKeyData     key;
+ 	SysScanDesc	scan;
+ 
+ 	ScanKeyInit(&key,
+                                 Anum_pg_module_modulename,
+                                 BTEqualStrategyNumber, F_NAMEEQ,
+                                 CStringGetDatum(name));
+ 
+ 	scan = systable_beginscan(rel, ModuleNameIndexId, true,
+                                                           SnapshotNow, 1, &key);
+ 
+ 	if((scantup = systable_getnext(scan)) != NULL)
+ 	{
+ 		tup = heap_copytuple(scantup);
+ 	}
+ 	systable_endscan(scan);
+ 	
+ 	return tup;	
+ }
Index: src/backend/commands/Makefile
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/Makefile,v
retrieving revision 1.38
diff -c -r1.38 Makefile
*** src/backend/commands/Makefile	19 Feb 2008 10:30:07 -0000	1.38
--- src/backend/commands/Makefile	6 Apr 2008 20:24:30 -0000
***************
*** 15,21 ****
  OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o  \
  	conversioncmds.o copy.o \
  	dbcommands.o define.o discard.o explain.o functioncmds.o \
! 	indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
  	portalcmds.o prepare.o proclang.o \
  	schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
  	tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
--- 15,21 ----
  OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o  \
  	conversioncmds.o copy.o \
  	dbcommands.o define.o discard.o explain.o functioncmds.o \
! 	indexcmds.o lockcmds.o modulecmds.o operatorcmds.o opclasscmds.o \
  	portalcmds.o prepare.o proclang.o \
  	schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
  	tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
Index: src/backend/commands/modulecmds.c
===================================================================
RCS file: src/backend/commands/modulecmds.c
diff -N src/backend/commands/modulecmds.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/backend/commands/modulecmds.c	6 Apr 2008 20:24:30 -0000
***************
*** 0 ****
--- 1,110 ----
+ /*-------------------------------------------------------------------------
+  *
+  * modulecmds.c
+  *	  Routines for SQL commands that (un)install modules.
+  *
+  * Portions Copyright (c) 2008, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *	  $PostgreSQL$
+  *
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ #include "fmgr.h"
+ #include "miscadmin.h"
+ #include "catalog/pg_module.h"
+ #include "commands/modulecmds.h"
+ #include "executor/spi.h"
+ #include "storage/fd.h"
+ #include "utils/acl.h"
+ 
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ 
+ static char* MODULE_DIR = "modules";
+ static char* MODULE_INSTALL_SCRIPT = "install.sql";
+ static char* MODULE_UNINSTALL_SCRIPT = "uninstall.sql";
+ 
+ void module_execute_script(char *modulename, char *filename);
+ void module_check_perms();
+ 
+ void
+ InstallModule(char *name)
+ {
+ 	module_check_perms();
+ 	in_module_install = true;
+ 	ModuleCreate(name);
+ 	module_execute_script(name, MODULE_INSTALL_SCRIPT);
+ 	/* fixme, need to put inside PG_TRY etc so that a user can't
+            escalate privs here by engineering an error somehow */
+ 	in_module_install = false;
+ }
+ 
+ void
+ UninstallModule(char *name)
+ {
+ 	module_check_perms();
+ 	ModuleRemove(name);
+ 	in_module_install = true;
+ 	module_execute_script(name, MODULE_UNINSTALL_SCRIPT);
+ 	/* fixme, need to put inside PG_TRY etc so that a user can't
+            escalate privs here by engineering an error somehow */
+ 	in_module_install = false;
+ }
+ 
+ void
+ module_check_perms()
+ {
+ 	if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
+ 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ 				get_database_name(MyDatabaseId));
+ }
+ 
+ void
+ module_execute_script(char *modulename, char *filename)
+ {
+ 	int	ret, size;
+ 	File	fd;
+ 	char	*buf, filepath[MAXPGPATH], modulepath[MAXPGPATH];
+ 	struct stat file_stat;
+ 
+ 
+ 	join_path_components(modulepath, pkglib_path, MODULE_DIR);
+ 	join_path_components(modulepath, modulepath, modulename);
+ 	if((ret = stat(modulepath, &file_stat)) == -1)
+ 	{
+ 		elog(ERROR, "Could not find module directory %s. Is the module installed? Error was: %s", modulepath, strerror(errno));
+ 	}
+ 
+ 	join_path_components(filepath, modulepath, filename);
+ 	/* let's make sure it's actually there */
+ 	if((ret = stat(filepath, &file_stat)) == -1)
+ 	{
+ 		elog(ERROR, "Could not stat file %s: %s", filepath, strerror(errno));
+ 	}
+ 	size = file_stat.st_size;
+ 
+ 	/* read into buffer */
+ 	fd = PathNameOpenFile(filepath, O_RDONLY, 0);
+ 	if(fd == -1)
+ 	{
+ 		elog(ERROR, "Could not open file %s: %s", filepath, strerror(errno));
+ 	}
+ 	buf = (char*) palloc(size + 1);
+ 	/* NOTE: being lazy and assuming we read the whole lot in first go. Should fix */
+ 	FileRead(fd, buf, size);
+ 	buf[size] = 0;
+ 
+ 
+ 	SPI_connect();
+ 	//ret = SPI_execute("select * from pg_module; create table foo(id int4); create table bar(id int4);", false, 0);
+ 	ret = SPI_execute(buf, false, 0);
+ 	if (ret < 0)
+ 		elog(ERROR, "eek");
+ 	SPI_finish();
+ 
+ }
+ 
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.611
diff -c -r2.611 gram.y
*** src/backend/parser/gram.y	28 Mar 2008 00:21:55 -0000	2.611
--- src/backend/parser/gram.y	6 Apr 2008 20:24:35 -0000
***************
*** 175,180 ****
--- 175,181 ----
  		DeallocateStmt PrepareStmt ExecuteStmt
  		DropOwnedStmt ReassignOwnedStmt
  		AlterTSConfigurationStmt AlterTSDictionaryStmt
+ 		InstallModuleStmt UninstallModuleStmt
  
  %type <node>	select_no_parens select_with_parens select_clause
  				simple_select values_clause
***************
*** 398,404 ****
  
  	IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT
  	INDEX INDEXES INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P
! 	INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT
  	INTERVAL INTO INVOKER IS ISNULL ISOLATION
  
  	JOIN
--- 399,405 ----
  
  	IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT
  	INDEX INDEXES INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P
! 	INSENSITIVE INSERT INSTALL INSTEAD INT_P INTEGER INTERSECT
  	INTERVAL INTO INVOKER IS ISNULL ISOLATION
  
  	JOIN
***************
*** 409,415 ****
  	LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
  	LOCK_P LOGIN_P
  
! 	MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
  
  	NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
  	NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
--- 410,416 ----
  	LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
  	LOCK_P LOGIN_P
  
! 	MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MODULE MONTH_P MOVE
  
  	NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
  	NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
***************
*** 438,444 ****
  	TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
  	TRUNCATE TRUSTED TYPE_P
  
! 	UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
  	UPDATE USER USING
  
  	VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARYING
--- 439,445 ----
  	TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
  	TRUNCATE TRUSTED TYPE_P
  
! 	UNCOMMITTED UNENCRYPTED UNINSTALL UNION UNIQUE UNKNOWN UNLISTEN UNTIL
  	UPDATE USER USING
  
  	VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARYING
***************
*** 596,601 ****
--- 597,603 ----
  			| GrantRoleStmt
  			| IndexStmt
  			| InsertStmt
+ 			| InstallModuleStmt
  			| ListenStmt
  			| LoadStmt
  			| LockStmt
***************
*** 613,618 ****
--- 615,621 ----
  			| SelectStmt
  			| TransactionStmt
  			| TruncateStmt
+ 			| UninstallModuleStmt
  			| UnlistenStmt
  			| UpdateStmt
  			| VacuumStmt
***************
*** 3351,3356 ****
--- 3354,3384 ----
  /*****************************************************************************
   *
   *		QUERY:
+  *
+  *		INSTALL MODULE name
+  *              UNINSTALL MODULE name
+  *
+  *****************************************************************************/
+ 
+ InstallModuleStmt:	INSTALL MODULE name 
+ 				{
+ 					InstallModuleStmt *n = makeNode(InstallModuleStmt);
+ 					n->name = $3;
+ 					$$ = (Node *)n;
+ 				}
+ 		;
+ 
+ UninstallModuleStmt:	UNINSTALL MODULE name 
+ 				{
+ 					UninstallModuleStmt *n = makeNode(UninstallModuleStmt);
+ 					n->name = $3;
+ 					$$ = (Node *)n;
+ 				}
+ 		;
+ 
+ /*****************************************************************************
+  *
+  *		QUERY:
   *				truncate table relname1, relname2, ...
   *
   *****************************************************************************/
***************
*** 9114,9119 ****
--- 9142,9148 ----
  			| INPUT_P
  			| INSENSITIVE
  			| INSERT
+ 			| INSTALL
  			| INSTEAD
  			| INVOKER
  			| ISOLATION
***************
*** 9135,9140 ****
--- 9164,9170 ----
  			| MINUTE_P
  			| MINVALUE
  			| MODE
+ 			| MODULE
  			| MONTH_P
  			| MOVE
  			| NAME_P
***************
*** 9227,9232 ****
--- 9257,9263 ----
  			| TYPE_P
  			| UNCOMMITTED
  			| UNENCRYPTED
+ 			| UNINSTALL
  			| UNKNOWN
  			| UNLISTEN
  			| UNTIL
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.195
diff -c -r1.195 keywords.c
*** src/backend/parser/keywords.c	27 Mar 2008 03:57:33 -0000	1.195
--- src/backend/parser/keywords.c	6 Apr 2008 20:24:36 -0000
***************
*** 199,204 ****
--- 199,205 ----
  	{"input", INPUT_P, UNRESERVED_KEYWORD},
  	{"insensitive", INSENSITIVE, UNRESERVED_KEYWORD},
  	{"insert", INSERT, UNRESERVED_KEYWORD},
+ 	{"install", INSTALL, UNRESERVED_KEYWORD},
  	{"instead", INSTEAD, UNRESERVED_KEYWORD},
  	{"int", INT_P, COL_NAME_KEYWORD},
  	{"integer", INTEGER, COL_NAME_KEYWORD},
***************
*** 235,240 ****
--- 236,242 ----
  	{"minute", MINUTE_P, UNRESERVED_KEYWORD},
  	{"minvalue", MINVALUE, UNRESERVED_KEYWORD},
  	{"mode", MODE, UNRESERVED_KEYWORD},
+ 	{"module", MODULE, UNRESERVED_KEYWORD},
  	{"month", MONTH_P, UNRESERVED_KEYWORD},
  	{"move", MOVE, UNRESERVED_KEYWORD},
  	{"name", NAME_P, UNRESERVED_KEYWORD},
***************
*** 374,379 ****
--- 376,382 ----
  	{"type", TYPE_P, UNRESERVED_KEYWORD},
  	{"uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD},
  	{"unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD},
+ 	{"uninstall", UNINSTALL, UNRESERVED_KEYWORD},
  	{"union", UNION, RESERVED_KEYWORD},
  	{"unique", UNIQUE, RESERVED_KEYWORD},
  	{"unknown", UNKNOWN, UNRESERVED_KEYWORD},
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.291
diff -c -r1.291 utility.c
*** src/backend/tcop/utility.c	19 Mar 2008 18:38:30 -0000	1.291
--- src/backend/tcop/utility.c	6 Apr 2008 20:24:38 -0000
***************
*** 32,37 ****
--- 32,38 ----
  #include "commands/discard.h"
  #include "commands/explain.h"
  #include "commands/lockcmds.h"
+ #include "commands/modulecmds.h"
  #include "commands/portalcmds.h"
  #include "commands/prepare.h"
  #include "commands/proclang.h"
***************
*** 1218,1223 ****
--- 1219,1232 ----
  			AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
  			break;
  
+ 		case T_InstallModuleStmt:
+ 			InstallModule(((InstallModuleStmt *) parsetree)->name);
+ 			break;
+ 
+ 		case T_UninstallModuleStmt:
+ 			UninstallModule(((UninstallModuleStmt *) parsetree)->name);
+ 			break;
+ 
  		default:
  			elog(ERROR, "unrecognized node type: %d",
  				 (int) nodeTag(parsetree));
***************
*** 2143,2148 ****
--- 2152,2165 ----
  			}
  			break;
  
+ 		case T_InstallModuleStmt:
+ 			tag = "INSTALL MODULE";
+ 			break;
+ 
+ 		case T_UninstallModuleStmt:
+ 			tag = "UNINSTALL MODULE";
+ 			break;
+ 
  		default:
  			elog(WARNING, "unrecognized node type: %d",
  				 (int) nodeTag(parsetree));
***************
*** 2327,2332 ****
--- 2344,2357 ----
  			lev = LOGSTMT_DDL;
  			break;
  
+ 		case T_InstallModuleStmt:
+ 			lev = LOGSTMT_DDL;
+ 			break;
+ 
+ 		case T_UninstallModuleStmt:
+ 			lev = LOGSTMT_DDL;
+ 			break;
+ 
  		case T_NotifyStmt:
  			lev = LOGSTMT_ALL;
  			break;
Index: src/backend/utils/misc/superuser.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/superuser.c,v
retrieving revision 1.37
diff -c -r1.37 superuser.c
*** src/backend/utils/misc/superuser.c	1 Jan 2008 19:45:54 -0000	1.37
--- src/backend/utils/misc/superuser.c	6 Apr 2008 20:24:39 -0000
***************
*** 38,43 ****
--- 38,46 ----
  
  static void RoleidCallback(Datum arg, Oid relid);
  
+ /* Module installs happen as superuser, so act as superuser when that's happening */
+ bool in_module_install = false;
+ 
  
  /*
   * The Postgres user running this command has Postgres superuser privileges
***************
*** 58,63 ****
--- 61,71 ----
  	bool		result;
  	HeapTuple	rtup;
  
+ 	/* If in module install, act as superuser. Should be above the
+ 	   cache check below in case the user's permissions are cached */
+ 	if(in_module_install)
+ 		return true; 
+ 
  	/* Quick out for cache hit */
  	if (OidIsValid(last_roleid) && last_roleid == roleid)
  		return last_roleid_is_super;
Index: src/include/miscadmin.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/miscadmin.h,v
retrieving revision 1.201
diff -c -r1.201 miscadmin.h
*** src/include/miscadmin.h	20 Feb 2008 22:46:24 -0000	1.201
--- src/include/miscadmin.h	6 Apr 2008 20:24:40 -0000
***************
*** 252,258 ****
  /* in utils/misc/superuser.c */
  extern bool superuser(void);	/* current user is superuser */
  extern bool superuser_arg(Oid roleid);	/* given user is superuser */
! 
  
  /*****************************************************************************
   *	  pmod.h --																 *
--- 252,258 ----
  /* in utils/misc/superuser.c */
  extern bool superuser(void);	/* current user is superuser */
  extern bool superuser_arg(Oid roleid);	/* given user is superuser */
! extern bool in_module_install;
  
  /*****************************************************************************
   *	  pmod.h --																 *
Index: src/include/catalog/indexing.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/indexing.h,v
retrieving revision 1.102
diff -c -r1.102 indexing.h
*** src/include/catalog/indexing.h	1 Jan 2008 19:45:56 -0000	1.102
--- src/include/catalog/indexing.h	6 Apr 2008 20:24:40 -0000
***************
*** 168,173 ****
--- 168,178 ----
  DECLARE_UNIQUE_INDEX(pg_largeobject_loid_pn_index, 2683, on pg_largeobject using btree(loid oid_ops, pageno int4_ops));
  #define LargeObjectLOidPNIndexId  2683
  
+ DECLARE_UNIQUE_INDEX(pg_module_modulename_index, 3535, on pg_module using btree(modulename name_ops));
+ #define ModuleNameIndexId  3535
+ DECLARE_UNIQUE_INDEX(pg_module_oid_index, 3536, on pg_module using btree(oid oid_ops));
+ #define ModuleNameOidId  3536
+ 
  DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btree(nspname name_ops));
  #define NamespaceNameIndexId  2684
  DECLARE_UNIQUE_INDEX(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops));
Index: src/include/catalog/pg_module.h
===================================================================
RCS file: src/include/catalog/pg_module.h
diff -N src/include/catalog/pg_module.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/include/catalog/pg_module.h	6 Apr 2008 20:24:40 -0000
***************
*** 0 ****
--- 1,62 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_module.h
+  *	  keep track of installed modules
+  *
+  *
+  * Copyright (c) 2008, PostgreSQL Global Development Group
+  *
+  * $PostgreSQL$
+  *
+  * NOTES
+  *	  the genbki.sh script reads this file and generates .bki
+  *	  information from the DATA() statements.
+  *
+  *	  XXX do NOT break up DATA() statements into multiple lines!
+  *		  the scripts are not as smart as you might think...
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef PG_MODULE_H
+ #define PG_MODULE_H
+ 
+ #include "catalog/genbki.h"
+ /*#include "nodes/pg_list.h"*/
+ 
+ /* ----------------
+  *		pg_module definition.  cpp turns this into
+  *		typedef struct FormData_pg_module
+  * ----------------
+  */
+ #define ModuleRelationId	3534
+ 
+ CATALOG(pg_module,3534)
+ {
+ 	NameData	modulename;
+ } FormData_pg_module;
+ 
+ /* ----------------
+  *		Form_pg_module corresponds to a pointer to a tuple with
+  *		the format of pg_module relation.
+  * ----------------
+  */
+ typedef FormData_pg_module *Form_pg_module;
+ 
+ /* ----------------
+  *		compiler constants for pg_module
+  * ----------------
+  */
+ #define Natts_pg_module				1
+ #define Anum_pg_module_modulename		1
+ 
+ /* ----------------
+  *		pg_module has no initial contents
+  * ----------------
+  */
+ 
+ /*
+  * prototypes for functions in pg_module.c
+  */
+ extern Oid ModuleCreate(char *name);
+ extern void ModuleRemove(char *name);
+ #endif   /* PG_MODULE_H */
Index: src/include/commands/modulecmds.h
===================================================================
RCS file: src/include/commands/modulecmds.h
diff -N src/include/commands/modulecmds.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- src/include/commands/modulecmds.h	6 Apr 2008 20:24:40 -0000
***************
*** 0 ****
--- 1,20 ----
+ /*-------------------------------------------------------------------------
+  *
+  * modulecmds.h
+  *	  prototypes for modulecmds.c.
+  *
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef MODULECMDS_H
+ #define MODULECMDS_H
+ 
+ extern void InstallModule(char *name);
+ extern void UninstallModule(char *name);
+ 
+ #endif   /* MODULECMDS_H */
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.206
diff -c -r1.206 nodes.h
*** src/include/nodes/nodes.h	20 Mar 2008 21:42:48 -0000	1.206
--- src/include/nodes/nodes.h	6 Apr 2008 20:24:41 -0000
***************
*** 313,318 ****
--- 313,320 ----
  	T_CreateEnumStmt,
  	T_AlterTSDictionaryStmt,
  	T_AlterTSConfigurationStmt,
+ 	T_InstallModuleStmt,
+ 	T_UninstallModuleStmt,
  
  	/*
  	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.361
diff -c -r1.361 parsenodes.h
*** src/include/nodes/parsenodes.h	21 Mar 2008 22:41:48 -0000	1.361
--- src/include/nodes/parsenodes.h	6 Apr 2008 20:24:43 -0000
***************
*** 2072,2075 ****
--- 2072,2090 ----
  	bool		missing_ok;		/* for DROP - skip error if missing? */
  } AlterTSConfigurationStmt;
  
+ /*
+  * Module Installation / uninstallation commands
+  */
+ typedef struct InstallModuleStmt
+ {
+ 	NodeTag	type;
+ 	char	*name;
+ } InstallModuleStmt;
+ 
+ typedef struct UninstallModuleStmt
+ {
+ 	NodeTag	type;
+ 	char	*name;
+ } UninstallModuleStmt;
+ 
  #endif   /* PARSENODES_H */
Index: src/test/regress/expected/sanity_check.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/sanity_check.out,v
retrieving revision 1.37
diff -c -r1.37 sanity_check.out
*** src/test/regress/expected/sanity_check.out	24 Nov 2007 19:49:23 -0000	1.37
--- src/test/regress/expected/sanity_check.out	6 Apr 2008 20:24:45 -0000
***************
*** 104,109 ****
--- 104,110 ----
   pg_language             | t
   pg_largeobject          | t
   pg_listener             | f
+  pg_module               | t
   pg_namespace            | t
   pg_opclass              | t
   pg_operator             | t
***************
*** 149,155 ****
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (138 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
--- 150,156 ----
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (139 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
