*** ./src/backend/catalog/pg_proc.c.orig Thu Sep 20 00:17:36 2001 --- ./src/backend/catalog/pg_proc.c Sat Sep 22 21:45:37 2001 *************** *** 29,35 **** #include "utils/lsyscache.h" #include "utils/sets.h" #include "utils/syscache.h" ! static void checkretval(Oid rettype, List *queryTreeList); --- 29,35 ---- #include "utils/lsyscache.h" #include "utils/sets.h" #include "utils/syscache.h" ! #include "commands/defrem.h" static void checkretval(Oid rettype, List *queryTreeList); *************** *** 40,45 **** --- 40,46 ---- */ Oid ProcedureCreate(char *procedureName, + bool replace, bool returnsSet, char *returnTypeName, char *languageName, *************** *** 57,67 **** { int i; Relation rel; ! HeapTuple tup; bool defined; uint16 parameterCount; char nulls[Natts_pg_proc]; Datum values[Natts_pg_proc]; Oid languageObjectId; Oid typeObjectId; List *x; --- 58,69 ---- { int i; Relation rel; ! HeapTuple tup = (HeapTuple)NULL; // silence gcc bool defined; uint16 parameterCount; char nulls[Natts_pg_proc]; Datum values[Natts_pg_proc]; + char replaces[Natts_pg_proc]; Oid languageObjectId; Oid typeObjectId; List *x; *************** *** 72,77 **** --- 74,81 ---- NameData procname; TupleDesc tupDesc; Oid retval; + HeapTuple oldfunctup; + int4 oldfuncowner; /* * sanity checks *************** *** 120,134 **** typev[parameterCount++] = toid; } ! /* Check for duplicate definition */ ! if (SearchSysCacheExists(PROCNAME, ! PointerGetDatum(procedureName), ! UInt16GetDatum(parameterCount), ! PointerGetDatum(typev), ! 0)) ! elog(ERROR, "ProcedureCreate: procedure %s already exists with same arguments", ! procedureName); ! if (languageObjectId == SQLlanguageId) { --- 124,130 ---- typev[parameterCount++] = toid; } ! if (languageObjectId == SQLlanguageId) { *************** *** 267,274 **** --- 263,308 ---- { nulls[i] = ' '; values[i] = (Datum) NULL; + replaces[i] = 'r'; } + /* Lets see if the function already exists */ + + oldfunctup = SearchSysCache(PROCNAME, + PointerGetDatum(procedureName), + UInt16GetDatum(parameterCount), + PointerGetDatum(typev),0); + + if(HeapTupleIsValid(oldfunctup)) { + Oid oldretid = InvalidOid, oldfuncid = InvalidOid; + // oldretid = oldfunctup->prorettype; + oldfuncid = oldfunctup->t_data->t_oid; + oldretid = ((Form_pg_proc) GETSTRUCT(oldfunctup))->prorettype; + // oldfuncid = ((Form_pg_proc) GETSTRUCT(oldfunctup))->t_data->toid; + oldfuncowner = ((Form_pg_proc) GETSTRUCT(oldfunctup))->proowner; + Assert(oidfuncid); + Assert(oldretid); + if(replace) { + if(oldretid != typeObjectId) { + elog(ERROR,"ProcedureCreate: procedure %s has " + "different return type to existing procedure." + " Use DROP FUNCTION first.",procedureName); + } + if(GetUserId() != oldfuncowner) { + elog(ERROR,"ProcedureCreate: you do not have permission to " + "replace function %s",procedureName); + } + tup = oldfunctup; + } else { + elog(ERROR,"ProcedureCreate: procedure %s already exists " + "with same arguments", + procedureName); + } + } else { + /* user specified replace, but procedure does not exist */ + replace = false; + } + // ReleaseSysCache(oldfunctup); i = 0; namestrcpy(&procname, procedureName); values[i++] = NameGetDatum(&procname); *************** *** 295,310 **** rel = heap_openr(ProcedureRelationName, RowExclusiveLock); tupDesc = rel->rd_att; ! tup = heap_formtuple(tupDesc, values, nulls); ! ! heap_insert(rel, tup); ! if (RelationGetForm(rel)->relhasindex) { Relation idescs[Num_pg_proc_indices]; - CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs); CatalogIndexInsert(idescs, Num_pg_proc_indices, rel, tup); CatalogCloseIndices(Num_pg_proc_indices, idescs); --- 329,347 ---- rel = heap_openr(ProcedureRelationName, RowExclusiveLock); tupDesc = rel->rd_att; ! if(replace) { ! tup = heap_modifytuple(tup,rel,values,nulls,replaces); ! simple_heap_update(rel,&tup->t_self,tup); ! ReleaseSysCache(oldfunctup); ! } else { ! tup = heap_formtuple(tupDesc, values, nulls); ! heap_insert(rel, tup); ! } if (RelationGetForm(rel)->relhasindex) { Relation idescs[Num_pg_proc_indices]; CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs); CatalogIndexInsert(idescs, Num_pg_proc_indices, rel, tup); CatalogCloseIndices(Num_pg_proc_indices, idescs); *** ./src/backend/commands/define.c.orig Sat Sep 22 19:16:28 2001 --- ./src/backend/commands/define.c Sat Sep 22 21:22:38 2001 *************** *** 325,330 **** --- 325,331 ---- * to do so, go ahead and create the function. */ ProcedureCreate(stmt->funcname, + stmt->replace, returnsSet, prorettype, languageName, *** ./src/backend/parser/gram.y.orig Thu Sep 20 16:20:52 2001 --- ./src/backend/parser/gram.y Thu Sep 20 18:48:13 2001 *************** *** 161,167 **** %type user_valid_clause %type user_list, user_group_clause, users_in_new_group_clause ! %type TriggerActionTime, TriggerForSpec, PLangTrusted, opt_procedural %type OptConstrFromTable --- 161,168 ---- %type user_valid_clause %type user_list, user_group_clause, users_in_new_group_clause ! %type TriggerActionTime, TriggerForSpec, PLangTrusted, opt_procedural, ! func_replace %type OptConstrFromTable *************** *** 349,355 **** MAXVALUE, MINVALUE, MODE, MOVE, NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL, OFFSET, OIDS, OPERATOR, OWNER, PASSWORD, PROCEDURAL, ! REINDEX, RENAME, RESET, RETURNS, ROW, RULE, SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID, TEMP, TEMPLATE, TOAST, TRUNCATE, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION --- 350,356 ---- MAXVALUE, MINVALUE, MODE, MOVE, NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL, OFFSET, OIDS, OPERATOR, OWNER, PASSWORD, PROCEDURAL, ! REINDEX, RENAME, REPLACE, RESET, RETURNS, ROW, RULE, SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID, TEMP, TEMPLATE, TOAST, TRUNCATE, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION *************** *** 2435,2453 **** * *****************************************************************************/ ! ProcedureStmt: CREATE FUNCTION func_name func_args RETURNS func_return AS func_as LANGUAGE Sconst opt_with { ProcedureStmt *n = makeNode(ProcedureStmt); ! n->funcname = $3; ! n->argTypes = $4; ! n->returnType = (Node *)$6; ! n->withClause = $11; ! n->as = $8; ! n->language = $10; $$ = (Node *)n; }; opt_with: WITH definition { $$ = $2; } | /*EMPTY*/ { $$ = NIL; } ; --- 2436,2458 ---- * *****************************************************************************/ ! ProcedureStmt: CREATE func_replace FUNCTION func_name func_args RETURNS func_return AS func_as LANGUAGE Sconst opt_with { ProcedureStmt *n = makeNode(ProcedureStmt); ! n->replace = $2; ! n->funcname = $4; ! n->argTypes = $5; ! n->returnType = (Node *)$7; ! n->withClause = $12; ! n->as = $9; ! n->language = $11; $$ = (Node *)n; }; + func_replace: OR REPLACE { $$ = TRUE; } + | /* EMPTY */ { $$ = FALSE; } + ; opt_with: WITH definition { $$ = $2; } | /*EMPTY*/ { $$ = NIL; } ; *** ./src/backend/parser/keywords.c.orig Thu Sep 20 17:12:02 2001 --- ./src/backend/parser/keywords.c Thu Sep 20 18:07:00 2001 *************** *** 214,219 **** --- 214,220 ---- {"reindex", REINDEX}, {"relative", RELATIVE}, {"rename", RENAME}, + {"replace",REPLACE}, {"reset", RESET}, {"restrict", RESTRICT}, {"returns", RETURNS}, *** ./src/backend/utils/adt/sets.c.orig Thu Sep 20 19:53:49 2001 --- ./src/backend/utils/adt/sets.c Thu Sep 20 18:06:50 2001 *************** *** 53,59 **** char repl[Natts_pg_proc]; setoid = ProcedureCreate(procname, /* changed below, after oid known */ ! true, /* returnsSet */ typename, /* returnTypeName */ "sql", /* languageName */ querystr, /* sourceCode */ --- 53,60 ---- char repl[Natts_pg_proc]; setoid = ProcedureCreate(procname, /* changed below, after oid known */ ! false, /* no need to replace */ ! true, /* returnsSet */ typename, /* returnTypeName */ "sql", /* languageName */ querystr, /* sourceCode */ *** ./src/include/catalog/pg_proc.h.orig Thu Sep 20 17:27:45 2001 --- ./src/include/catalog/pg_proc.h Thu Sep 20 18:06:53 2001 *************** *** 2610,2615 **** --- 2610,2616 ---- * prototypes for functions pg_proc.c */ extern Oid ProcedureCreate(char *procedureName, + bool replace, bool returnsSet, char *returnTypeName, char *languageName, *** ./src/include/nodes/parsenodes.h.orig Thu Sep 20 16:24:14 2001 --- ./src/include/nodes/parsenodes.h Thu Sep 20 16:24:30 2001 *************** *** 522,527 **** --- 522,528 ---- typedef struct ProcedureStmt { NodeTag type; + bool replace; /* replace if exists? */ char *funcname; /* name of function to create */ List *argTypes; /* list of argument types (TypeName nodes) */ Node *returnType; /* the return type (a TypeName node) */