diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 3f7fdf16b45..dd103573a5d 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,4 +1,4 @@
-
+
@@ -2941,6 +2941,18 @@
+
+ laninline
+ oid
+ pg_proc.oid
+
+ This references a function that is responsible for executing
+ inline> anonymous code blocks
+ ( blocks).
+ Zero if inline blocks are not supported
+
+
+
lanvalidator
oid
@@ -3547,6 +3559,12 @@
Name of call handler function
+
+ tmplinline
+ text
+ Name of anonymous-block handler function, or NULL if none
+
+
tmplvalidator
text
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index fa2a12feab1..ee28bbb1079 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1,4 +1,4 @@
-
+
Server Configuration
@@ -3964,6 +3964,21 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
+
+ default_do_language (string)
+
+ default_do_language> configuration parameter
+
+
+
+ This parameter specifies the language to use when the
+ LANGUAGE> option is omitted in a
+ statement.
+ The default is plpgsql.
+
+
+
+
transaction isolation level
diff --git a/doc/src/sgml/keywords.sgml b/doc/src/sgml/keywords.sgml
index cb167ce10b4..8bfede77d6f 100644
--- a/doc/src/sgml/keywords.sgml
+++ b/doc/src/sgml/keywords.sgml
@@ -1,4 +1,4 @@
-
+
SQL Key Words
@@ -2375,6 +2375,14 @@
reserved
reserved
+
+ INLINE
+ non-reserved
+
+
+
+
+
INNER
reserved (can be function or type)
@@ -2575,14 +2583,6 @@
-
- LANCOMPILER
- non-reserved
-
-
-
-
-
LANGUAGE
non-reserved
diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index 6c20b623c49..845033b6b66 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -1,5 +1,5 @@
@@ -77,6 +77,7 @@ Complete list of usable sgml source files in this directory.
+
diff --git a/doc/src/sgml/ref/create_language.sgml b/doc/src/sgml/ref/create_language.sgml
index ae02995e37f..4c0463ddec1 100644
--- a/doc/src/sgml/ref/create_language.sgml
+++ b/doc/src/sgml/ref/create_language.sgml
@@ -1,5 +1,5 @@
@@ -23,7 +23,7 @@ PostgreSQL documentation
CREATE [ PROCEDURAL ] LANGUAGE name
CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name
- HANDLER call_handler [ VALIDATOR valfunction ]
+ HANDLER call_handler [ INLINE inline_handler ] [ VALIDATOR valfunction ]
@@ -133,7 +133,7 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name
call_handler is
the name of a previously registered function that will be
- called to execute the procedural language functions. The call
+ called to execute the procedural language's functions. The call
handler for a procedural language must be written in a compiled
language such as C with version 1 call convention and
registered with PostgreSQL as a
@@ -144,6 +144,27 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name
+
+ INLINE inline_handler
+
+
+
+ inline_handler is the
+ name of a previously registered function that will be called
+ to execute an anonymous code block
+ ( command)
+ in this language.
+ If no inline_handler
+ function is specified, the language does not support anonymous code
+ blocks.
+ The handler function must take one argument of
+ type internal, which will be the DO> command's
+ internal representation, and it will typically return
+ void>. The return value of the handler is ignored.
+
+
+
+
VALIDATOR valfunction
@@ -216,7 +237,8 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name
- The call handler function and the validator function (if any)
+ The call handler function, the inline handler function (if any),
+ and the validator function (if any)
must already exist if the server does not have an entry for the language
in pg_pltemplate>. But when there is an entry,
the functions need not already exist;
@@ -230,7 +252,7 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name
In PostgreSQL versions before 7.3, it was
necessary to declare handler functions as returning the placeholder
type opaque>, rather than language_handler>.
- To support loading
+ To support loading
of old dump files, CREATE LANGUAGE> will accept a function
declared as returning opaque>, but it will issue a notice and
change the function's declared return type to language_handler>.
diff --git a/doc/src/sgml/ref/do.sgml b/doc/src/sgml/ref/do.sgml
new file mode 100644
index 00000000000..2fb53806630
--- /dev/null
+++ b/doc/src/sgml/ref/do.sgml
@@ -0,0 +1,122 @@
+
+
+
+
+ DO
+ 7
+ SQL - Language Statements
+
+
+
+ DO
+ execute an anonymous code block
+
+
+
+ DO
+
+
+
+ anonymous code blocks
+
+
+
+
+DO code [ LANGUAGE lang_name ]
+
+
+
+
+ Description
+
+
+ DO executes an anonymous code block, or in other
+ words a transient anonymous function in a procedural language.
+
+
+
+ The code block is treated as though it were the body of a function
+ with no parameters, returning void>. It is parsed and
+ executed a single time.
+
+
+
+
+ Parameters
+
+
+
+ code
+
+
+ The procedural language code to be executed. This must be specified
+ as a string literal, just as in CREATE FUNCTION>.
+ Use of a dollar-quoted literal is recommended.
+
+
+
+
+
+ lang_name
+
+
+ The name of the procedural language the code is written in.
+ If omitted, the default is determined by the runtime parameter
+ .
+
+
+
+
+
+
+
+ Notes
+
+
+ The procedural language to be used must already have been installed
+ into the current database by means of CREATE LANGUAGE>.
+
+
+
+ The user must have USAGE> privilege for the procedural
+ language, or must be a superuser if the language is untrusted.
+ This is the same privilege requirement as for creating a function
+ in the language.
+
+
+
+
+ Examples
+
+ Execute a simple PL/pgsql loop without needing to create a function:
+
+DO $$
+DECLARE r record;
+BEGIN
+ FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
+ LOOP
+ RAISE NOTICE '%, %', r.roomno, r.comment;
+ END LOOP;
+END$$;
+
+
+
+
+ Compatibility
+
+
+ There is no DO statement in the SQL standard.
+
+
+
+
+ See Also
+
+
+
+
+
+
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index d3a862959d9..48f8040541d 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -1,4 +1,4 @@
-
+
Reference
@@ -105,6 +105,7 @@
&declare;
&delete;
&discard;
+ &do;
&dropAggregate;
&dropCast;
&dropConversion;
diff --git a/doc/src/sgml/xplang.sgml b/doc/src/sgml/xplang.sgml
index 9882d835e35..b48b78f95ba 100644
--- a/doc/src/sgml/xplang.sgml
+++ b/doc/src/sgml/xplang.sgml
@@ -1,4 +1,4 @@
-
+
Procedural Languages
@@ -75,9 +75,9 @@ createlang plpgsql template1
- A procedural language is installed in a database in four steps,
+ A procedural language is installed in a database in five steps,
which must be carried out by a database superuser. (For languages
- known to CREATE LANGUAGE>, the second and third steps
+ known to CREATE LANGUAGE>, the second through fourth steps
can be omitted, because they will be carried out automatically
if needed.)
@@ -110,12 +110,28 @@ CREATE FUNCTION handler_function_name()
+
+ Optionally, the language handler can provide an inline>
+ handler function that executes anonymous code blocks
+ ( commands)
+ written in this language. If an inline handler function
+ is provided by the language, declare it with a command like
+
+CREATE FUNCTION inline_function_name(internal)
+ RETURNS void
+ AS 'path-to-shared-object'
+ LANGUAGE C;
+
+
+
+
+
Optionally, the language handler can provide a validator>
function that checks a function definition for correctness without
actually executing it. The validator function is called by
CREATE FUNCTION> if it exists. If a validator function
- is provided by the handler, declare it with a command like
+ is provided by the language, declare it with a command like
CREATE FUNCTION validator_function_name(oid)
RETURNS void
@@ -125,12 +141,13 @@ CREATE FUNCTION validator_function_name(oid)
-
+
The PL must be declared with the command
CREATE TRUSTED PROCEDURAL LANGUAGE language-name
HANDLER handler_function_name
+ INLINE inline_function_name
VALIDATOR validator_function_name ;
The optional key word TRUSTED specifies that
@@ -173,10 +190,13 @@ CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS
- PL/pgSQL has a validator function,
- so we declare that too:
+ PL/pgSQL has an inline handler function
+ and a validator function, so we declare those too:
+CREATE FUNCTION plpgsql_inline_handler(internal) RETURNS void AS
+ '$libdir/plpgsql' LANGUAGE C;
+
CREATE FUNCTION plpgsql_validator(oid) RETURNS void AS
'$libdir/plpgsql' LANGUAGE C;
@@ -187,6 +207,7 @@ CREATE FUNCTION plpgsql_validator(oid) RETURNS void AS
CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
HANDLER plpgsql_call_handler
+ INLINE plpgsql_inline_handler
VALIDATOR plpgsql_validator;
then defines that the previously declared functions
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 64920f5d2a8..41c6d1e2fb1 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.164 2009/06/11 14:48:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.165 2009/09/22 23:43:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -782,11 +782,12 @@ sql_function_parse_error_callback(void *arg)
/*
* Adjust a syntax error occurring inside the function body of a CREATE
- * FUNCTION command. This can be used by any function validator, not only
- * for SQL-language functions. It is assumed that the syntax error position
- * is initially relative to the function body string (as passed in). If
- * possible, we adjust the position to reference the original CREATE command;
- * if we can't manage that, we set up an "internal query" syntax error instead.
+ * FUNCTION or DO command. This can be used by any function validator or
+ * anonymous-block handler, not only for SQL-language functions.
+ * It is assumed that the syntax error position is initially relative to the
+ * function body string (as passed in). If possible, we adjust the position
+ * to reference the original command text; if we can't manage that, we set
+ * up an "internal query" syntax error instead.
*
* Returns true if a syntax error was processed, false if not.
*/
@@ -843,8 +844,8 @@ function_parse_error_transpose(const char *prosrc)
/*
* Try to locate the string literal containing the function body in the
- * given text of the CREATE FUNCTION command. If successful, return the
- * character (not byte) index within the command corresponding to the
+ * given text of the CREATE FUNCTION or DO command. If successful, return
+ * the character (not byte) index within the command corresponding to the
* given character index within the literal. If not successful, return 0.
*/
static int
@@ -852,7 +853,7 @@ match_prosrc_to_query(const char *prosrc, const char *queryText,
int cursorpos)
{
/*
- * Rather than fully parsing the CREATE FUNCTION command, we just scan the
+ * Rather than fully parsing the original command, we just scan the
* command looking for $prosrc$ or 'prosrc'. This could be fooled (though
* not in any very probable scenarios), so fail if we find more than one
* match.
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 2151fd94f09..cf206b3f090 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.110 2009/06/11 14:48:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.111 2009/09/22 23:43:37 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@@ -1915,3 +1915,110 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
heap_close(procRel, RowExclusiveLock);
}
+
+
+/*
+ * ExecuteDoStmt
+ * Execute inline procedural-language code
+ */
+void
+ExecuteDoStmt(DoStmt *stmt)
+{
+ InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
+ ListCell *arg;
+ DefElem *as_item = NULL;
+ DefElem *language_item = NULL;
+ char *language;
+ char *languageName;
+ Oid laninline;
+ HeapTuple languageTuple;
+ Form_pg_language languageStruct;
+
+ /* Process options we got from gram.y */
+ foreach(arg, stmt->args)
+ {
+ DefElem *defel = (DefElem *) lfirst(arg);
+
+ if (strcmp(defel->defname, "as") == 0)
+ {
+ if (as_item)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ as_item = defel;
+ }
+ else if (strcmp(defel->defname, "language") == 0)
+ {
+ if (language_item)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ language_item = defel;
+ }
+ else
+ elog(ERROR, "option \"%s\" not recognized",
+ defel->defname);
+ }
+
+ if (as_item)
+ codeblock->source_text = strVal(as_item->arg);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("no inline code specified")));
+
+ /* if LANGUAGE option wasn't specified, use the default language */
+ if (language_item)
+ language = strVal(language_item->arg);
+ else
+ language = default_do_language;
+
+ /* Convert language name to canonical case */
+ languageName = case_translate_language_name(language);
+
+ /* Look up the language and validate permissions */
+ languageTuple = SearchSysCache(LANGNAME,
+ PointerGetDatum(languageName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(languageTuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("language \"%s\" does not exist", languageName),
+ (PLTemplateExists(languageName) ?
+ errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));
+
+ codeblock->langOid = HeapTupleGetOid(languageTuple);
+ languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
+
+ if (languageStruct->lanpltrusted)
+ {
+ /* if trusted language, need USAGE privilege */
+ AclResult aclresult;
+
+ aclresult = pg_language_aclcheck(codeblock->langOid, GetUserId(),
+ ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
+ NameStr(languageStruct->lanname));
+ }
+ else
+ {
+ /* if untrusted language, must be superuser */
+ if (!superuser())
+ aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
+ NameStr(languageStruct->lanname));
+ }
+
+ /* get the handler function's OID */
+ laninline = languageStruct->laninline;
+ if (!OidIsValid(laninline))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("language \"%s\" does not support inline code execution",
+ NameStr(languageStruct->lanname))));
+
+ ReleaseSysCache(languageTuple);
+
+ /* execute the inline handler */
+ OidFunctionCall1(laninline, PointerGetDatum(codeblock));
+}
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 27af379d7e1..2a5bcd6363d 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.86 2009/07/12 17:12:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.87 2009/09/22 23:43:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -44,12 +44,14 @@ typedef struct
bool tmpltrusted; /* trusted? */
bool tmpldbacreate; /* db owner allowed to create? */
char *tmplhandler; /* name of handler function */
+ char *tmplinline; /* name of anonymous-block handler, or NULL */
char *tmplvalidator; /* name of validator function, or NULL */
char *tmpllibrary; /* path of shared library */
} PLTemplate;
static void create_proc_lang(const char *languageName,
- Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted);
+ Oid languageOwner, Oid handlerOid, Oid inlineOid,
+ Oid valOid, bool trusted);
static PLTemplate *find_language_template(const char *languageName);
static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel,
Oid newOwnerId);
@@ -65,6 +67,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
char *languageName;
PLTemplate *pltemplate;
Oid handlerOid,
+ inlineOid,
valOid;
Oid funcrettype;
Oid funcargtypes[1];
@@ -154,6 +157,44 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
0);
}
+ /*
+ * Likewise for the anonymous block handler, if required;
+ * but we don't care about its return type.
+ */
+ if (pltemplate->tmplinline)
+ {
+ funcname = SystemFuncName(pltemplate->tmplinline);
+ funcargtypes[0] = INTERNALOID;
+ inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
+ if (!OidIsValid(inlineOid))
+ {
+ inlineOid = ProcedureCreate(pltemplate->tmplinline,
+ PG_CATALOG_NAMESPACE,
+ false, /* replace */
+ false, /* returnsSet */
+ VOIDOID,
+ ClanguageId,
+ F_FMGR_C_VALIDATOR,
+ pltemplate->tmplinline,
+ pltemplate->tmpllibrary,
+ false, /* isAgg */
+ false, /* isWindowFunc */
+ false, /* security_definer */
+ true, /* isStrict */
+ PROVOLATILE_VOLATILE,
+ buildoidvector(funcargtypes, 1),
+ PointerGetDatum(NULL),
+ PointerGetDatum(NULL),
+ PointerGetDatum(NULL),
+ NIL,
+ PointerGetDatum(NULL),
+ 1,
+ 0);
+ }
+ }
+ else
+ inlineOid = InvalidOid;
+
/*
* Likewise for the validator, if required; but we don't care about
* its return type.
@@ -177,7 +218,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
false, /* isAgg */
false, /* isWindowFunc */
false, /* security_definer */
- false, /* isStrict */
+ true, /* isStrict */
PROVOLATILE_VOLATILE,
buildoidvector(funcargtypes, 1),
PointerGetDatum(NULL),
@@ -193,8 +234,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
valOid = InvalidOid;
/* ok, create it */
- create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
- pltemplate->tmpltrusted);
+ create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
+ valOid, pltemplate->tmpltrusted);
}
else
{
@@ -246,6 +287,16 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
NameListToString(stmt->plhandler))));
}
+ /* validate the inline function */
+ if (stmt->plinline)
+ {
+ funcargtypes[0] = INTERNALOID;
+ inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
+ /* return value is ignored, so we don't check the type */
+ }
+ else
+ inlineOid = InvalidOid;
+
/* validate the validator function */
if (stmt->plvalidator)
{
@@ -257,8 +308,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
valOid = InvalidOid;
/* ok, create it */
- create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
- stmt->pltrusted);
+ create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
+ valOid, stmt->pltrusted);
}
}
@@ -267,7 +318,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
*/
static void
create_proc_lang(const char *languageName,
- Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted)
+ Oid languageOwner, Oid handlerOid, Oid inlineOid,
+ Oid valOid, bool trusted)
{
Relation rel;
TupleDesc tupDesc;
@@ -293,6 +345,7 @@ create_proc_lang(const char *languageName,
values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
+ values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
nulls[Anum_pg_language_lanacl - 1] = true;
@@ -321,6 +374,15 @@ create_proc_lang(const char *languageName,
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ /* dependency on the inline handler function, if any */
+ if (OidIsValid(inlineOid))
+ {
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = inlineOid;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
+
/* dependency on the validator function, if any */
if (OidIsValid(valOid))
{
@@ -371,6 +433,11 @@ find_language_template(const char *languageName)
if (!isnull)
result->tmplhandler = TextDatumGetCString(datum);
+ datum = heap_getattr(tup, Anum_pg_pltemplate_tmplinline,
+ RelationGetDescr(rel), &isnull);
+ if (!isnull)
+ result->tmplinline = TextDatumGetCString(datum);
+
datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
RelationGetDescr(rel), &isnull);
if (!isnull)
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 48039b86cb9..5feff5d1691 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.437 2009/07/30 02:45:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.438 2009/09/22 23:43:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2561,6 +2561,16 @@ _copyRemoveFuncStmt(RemoveFuncStmt *from)
return newnode;
}
+static DoStmt *
+_copyDoStmt(DoStmt *from)
+{
+ DoStmt *newnode = makeNode(DoStmt);
+
+ COPY_NODE_FIELD(args);
+
+ return newnode;
+}
+
static RemoveOpClassStmt *
_copyRemoveOpClassStmt(RemoveOpClassStmt *from)
{
@@ -3104,6 +3114,7 @@ _copyCreatePLangStmt(CreatePLangStmt *from)
COPY_STRING_FIELD(plname);
COPY_NODE_FIELD(plhandler);
+ COPY_NODE_FIELD(plinline);
COPY_NODE_FIELD(plvalidator);
COPY_SCALAR_FIELD(pltrusted);
@@ -3797,6 +3808,9 @@ copyObject(void *from)
case T_RemoveFuncStmt:
retval = _copyRemoveFuncStmt(from);
break;
+ case T_DoStmt:
+ retval = _copyDoStmt(from);
+ break;
case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 6c75f2e2747..d7ed08cc68b 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.360 2009/07/30 02:45:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.361 2009/09/22 23:43:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1212,6 +1212,14 @@ _equalRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b)
return true;
}
+static bool
+_equalDoStmt(DoStmt *a, DoStmt *b)
+{
+ COMPARE_NODE_FIELD(args);
+
+ return true;
+}
+
static bool
_equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
{
@@ -1667,6 +1675,7 @@ _equalCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b)
{
COMPARE_STRING_FIELD(plname);
COMPARE_NODE_FIELD(plhandler);
+ COMPARE_NODE_FIELD(plinline);
COMPARE_NODE_FIELD(plvalidator);
COMPARE_SCALAR_FIELD(pltrusted);
@@ -2576,6 +2585,9 @@ equal(void *a, void *b)
case T_RemoveFuncStmt:
retval = _equalRemoveFuncStmt(a, b);
break;
+ case T_DoStmt:
+ retval = _equalDoStmt(a, b);
+ break;
case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b);
break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 81d57f65fb5..9a203a5a48d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.678 2009/09/21 20:10:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.679 2009/09/22 23:43:38 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -196,7 +196,7 @@ static TypeName *TableFuncTypeName(List *columns);
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
CreateUserStmt CreateUserMappingStmt CreateRoleStmt
- CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt
+ CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
@@ -246,7 +246,6 @@ static TypeName *TableFuncTypeName(List *columns);
%type OptSchemaEltList
%type TriggerActionTime TriggerForSpec opt_trusted opt_restart_seqs
-%type opt_lancompiler
%type TriggerEvents TriggerOneEvent
%type TriggerFuncArg
@@ -256,7 +255,7 @@ static TypeName *TableFuncTypeName(List *columns);
index_name name file_name cluster_index_specification
%type func_name handler_name qual_Op qual_all_Op subquery_Op
- opt_class opt_validator validator_clause
+ opt_class opt_inline_handler opt_validator validator_clause
%type qualified_name OptConstrFromTable
@@ -295,12 +294,12 @@ static TypeName *TableFuncTypeName(List *columns);
execute_param_clause using_clause returning_clause
enum_val_list table_func_column_list
create_generic_options alter_generic_options
- relation_expr_list
+ relation_expr_list dostmt_opt_list
%type OptTempTableName
%type into_clause create_as_target
-%type createfunc_opt_item common_func_opt_item
+%type createfunc_opt_item common_func_opt_item dostmt_opt_item
%type func_arg func_arg_with_default table_func_column
%type arg_class
%type func_return func_type
@@ -481,7 +480,7 @@ static TypeName *TableFuncTypeName(List *columns);
HANDLER HAVING HEADER_P HOLD HOUR_P
IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P
- INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY
+ INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
@@ -489,7 +488,7 @@ static TypeName *TableFuncTypeName(List *columns);
KEY
- LANCOMPILER LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
+ LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P
@@ -676,6 +675,7 @@ stmt :
| DefineStmt
| DeleteStmt
| DiscardStmt
+ | DoStmt
| DropAssertStmt
| DropCastStmt
| DropFdwStmt
@@ -2771,19 +2771,20 @@ CreatePLangStmt:
n->plname = $5;
/* parameters are all to be supplied by system */
n->plhandler = NIL;
+ n->plinline = NIL;
n->plvalidator = NIL;
n->pltrusted = false;
$$ = (Node *)n;
}
| CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
- HANDLER handler_name opt_validator opt_lancompiler
+ HANDLER handler_name opt_inline_handler opt_validator
{
CreatePLangStmt *n = makeNode(CreatePLangStmt);
n->plname = $5;
n->plhandler = $7;
- n->plvalidator = $8;
+ n->plinline = $8;
+ n->plvalidator = $9;
n->pltrusted = $2;
- /* LANCOMPILER is now ignored entirely */
$$ = (Node *)n;
}
;
@@ -2802,6 +2803,11 @@ handler_name:
| name attrs { $$ = lcons(makeString($1), $2); }
;
+opt_inline_handler:
+ INLINE_P handler_name { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
validator_clause:
VALIDATOR handler_name { $$ = $2; }
| NO VALIDATOR { $$ = NIL; }
@@ -2812,11 +2818,6 @@ opt_validator:
| /*EMPTY*/ { $$ = NIL; }
;
-opt_lancompiler:
- LANCOMPILER Sconst { $$ = $2; }
- | /*EMPTY*/ { $$ = NULL; }
- ;
-
DropPLangStmt:
DROP opt_procedural LANGUAGE ColId_or_Sconst opt_drop_behavior
{
@@ -5139,6 +5140,38 @@ any_operator:
{ $$ = lcons(makeString($1), $3); }
;
+/*****************************************************************************
+ *
+ * DO [ LANGUAGE language ]
+ *
+ * We use a DefElem list for future extensibility, and to allow flexibility
+ * in the clause order.
+ *
+ *****************************************************************************/
+
+DoStmt: DO dostmt_opt_list
+ {
+ DoStmt *n = makeNode(DoStmt);
+ n->args = $2;
+ $$ = (Node *)n;
+ }
+ ;
+
+dostmt_opt_list:
+ dostmt_opt_item { $$ = list_make1($1); }
+ | dostmt_opt_list dostmt_opt_item { $$ = lappend($1, $2); }
+ ;
+
+dostmt_opt_item:
+ Sconst
+ {
+ $$ = makeDefElem("as", (Node *)makeString($1));
+ }
+ | LANGUAGE ColId_or_Sconst
+ {
+ $$ = makeDefElem("language", (Node *)makeString($2));
+ }
+ ;
/*****************************************************************************
*
@@ -10362,6 +10395,7 @@ unreserved_keyword:
| INDEXES
| INHERIT
| INHERITS
+ | INLINE_P
| INPUT_P
| INSENSITIVE
| INSERT
@@ -10369,7 +10403,6 @@ unreserved_keyword:
| INVOKER
| ISOLATION
| KEY
- | LANCOMPILER
| LANGUAGE
| LARGE_P
| LAST_P
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index c6fefccfc6f..0d2079fc0aa 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.313 2009/07/29 20:56:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.314 2009/09/22 23:43:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -840,6 +840,10 @@ ProcessUtility(Node *parsetree,
}
break;
+ case T_DoStmt:
+ ExecuteDoStmt((DoStmt *) parsetree);
+ break;
+
case T_CreatedbStmt:
PreventTransactionChain(isTopLevel, "CREATE DATABASE");
createdb((CreatedbStmt *) parsetree);
@@ -1761,6 +1765,10 @@ CreateCommandTag(Node *parsetree)
}
break;
+ case T_DoStmt:
+ tag = "DO";
+ break;
+
case T_CreatedbStmt:
tag = "CREATE DATABASE";
break;
@@ -2276,6 +2284,10 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
+ case T_DoStmt:
+ lev = LOGSTMT_ALL;
+ break;
+
case T_CreatedbStmt:
lev = LOGSTMT_DDL;
break;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 17bbbd7cb4a..cb743bb55ef 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut .
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.518 2009/09/17 21:15:18 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.519 2009/09/22 23:43:38 tgl Exp $
*
*--------------------------------------------------------------------
*/
@@ -385,6 +385,8 @@ char *external_pid_file;
char *pgstat_temp_directory;
+char *default_do_language;
+
int tcp_keepalives_idle;
int tcp_keepalives_interval;
int tcp_keepalives_count;
@@ -2539,6 +2541,15 @@ static struct config_string ConfigureNamesString[] =
},
#endif /* USE_SSL */
+ {
+ {"default_do_language", PGC_USERSET, CLIENT_CONN_STATEMENT,
+ gettext_noop("Sets the language used in DO statement if LANGUAGE is not specified."),
+ NULL
+ },
+ &default_do_language,
+ "plpgsql", NULL, NULL
+ },
+
/* End-of-list marker */
{
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index b10775cc2df..d6cf7e21c73 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -422,6 +422,7 @@
#temp_tablespaces = '' # a list of tablespace names, '' uses
# only default tablespace
#check_function_bodies = on
+#default_do_language = 'plpgsql'
#default_transaction_isolation = 'read committed'
#default_transaction_read_only = off
#session_replication_role = 'origin'
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 5856dc7049a..34ebc27168d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.547 2009/09/11 19:17:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.548 2009/09/22 23:43:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -4445,6 +4445,7 @@ getProcLangs(int *numProcLangs)
int i_lanname;
int i_lanpltrusted;
int i_lanplcallfoid;
+ int i_laninline;
int i_lanvalidator;
int i_lanacl;
int i_lanowner;
@@ -4452,7 +4453,19 @@ getProcLangs(int *numProcLangs)
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
- if (g_fout->remoteVersion >= 80300)
+ if (g_fout->remoteVersion >= 80500)
+ {
+ /* pg_language has a laninline column */
+ appendPQExpBuffer(query, "SELECT tableoid, oid, "
+ "lanname, lanpltrusted, lanplcallfoid, "
+ "laninline, lanvalidator, lanacl, "
+ "(%s lanowner) AS lanowner "
+ "FROM pg_language "
+ "WHERE lanispl "
+ "ORDER BY oid",
+ username_subquery);
+ }
+ else if (g_fout->remoteVersion >= 80300)
{
/* pg_language has a lanowner column */
appendPQExpBuffer(query, "SELECT tableoid, oid, "
@@ -4515,6 +4528,7 @@ getProcLangs(int *numProcLangs)
i_lanpltrusted = PQfnumber(res, "lanpltrusted");
i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
/* these may fail and return -1: */
+ i_laninline = PQfnumber(res, "laninline");
i_lanvalidator = PQfnumber(res, "lanvalidator");
i_lanacl = PQfnumber(res, "lanacl");
i_lanowner = PQfnumber(res, "lanowner");
@@ -4529,6 +4543,10 @@ getProcLangs(int *numProcLangs)
planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
+ if (i_laninline >= 0)
+ planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
+ else
+ planginfo[i].laninline = InvalidOid;
if (i_lanvalidator >= 0)
planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
else
@@ -6994,6 +7012,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
char *qlanname;
char *lanschema;
FuncInfo *funcInfo;
+ FuncInfo *inlineInfo = NULL;
FuncInfo *validatorInfo = NULL;
if (dataOnly)
@@ -7011,6 +7030,13 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
if (funcInfo != NULL && !funcInfo->dobj.dump)
funcInfo = NULL; /* treat not-dumped same as not-found */
+ if (OidIsValid(plang->laninline))
+ {
+ inlineInfo = findFuncByOid(plang->laninline);
+ if (inlineInfo != NULL && !inlineInfo->dobj.dump)
+ inlineInfo = NULL;
+ }
+
if (OidIsValid(plang->lanvalidator))
{
validatorInfo = findFuncByOid(plang->lanvalidator);
@@ -7024,6 +7050,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
* dump it.
*/
useParams = (funcInfo != NULL &&
+ (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
(validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
if (!useParams && !shouldDumpProcLangs())
@@ -7054,6 +7081,16 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
{
appendPQExpBuffer(defqry, " HANDLER %s",
fmtId(funcInfo->dobj.name));
+ if (OidIsValid(plang->laninline))
+ {
+ appendPQExpBuffer(defqry, " INLINE ");
+ /* Cope with possibility that inline is in different schema */
+ if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
+ appendPQExpBuffer(defqry, "%s.",
+ fmtId(inlineInfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(defqry, "%s",
+ fmtId(inlineInfo->dobj.name));
+ }
if (OidIsValid(plang->lanvalidator))
{
appendPQExpBuffer(defqry, " VALIDATOR ");
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 6b84d59723d..beec160110c 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.156 2009/08/02 22:14:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.157 2009/09/22 23:43:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -357,6 +357,7 @@ typedef struct _procLangInfo
DumpableObject dobj;
bool lanpltrusted;
Oid lanplcallfoid;
+ Oid laninline;
Oid lanvalidator;
char *lanacl;
char *lanowner; /* name of owner, or empty string */
diff --git a/src/bin/scripts/droplang.c b/src/bin/scripts/droplang.c
index 7038e08b8af..16898e264a9 100644
--- a/src/bin/scripts/droplang.c
+++ b/src/bin/scripts/droplang.c
@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.31 2009/02/26 16:02:39 petere Exp $
+ * $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.32 2009/09/22 23:43:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,7 +38,6 @@ main(int argc, char *argv[])
const char *progname;
int optindex;
int c;
-
bool listlangs = false;
const char *dbname = NULL;
char *host = NULL;
@@ -47,19 +46,20 @@ main(int argc, char *argv[])
enum trivalue prompt_password = TRI_DEFAULT;
bool echo = false;
char *langname = NULL;
-
char *p;
Oid lanplcallfoid;
+ Oid laninline;
Oid lanvalidator;
char *handler;
+ char *inline_handler;
char *validator;
char *handler_ns;
+ char *inline_ns;
char *validator_ns;
bool keephandler;
+ bool keepinline;
bool keepvalidator;
-
PQExpBufferData sql;
-
PGconn *conn;
PGresult *result;
@@ -190,10 +190,10 @@ main(int argc, char *argv[])
executeCommand(conn, "SET search_path = pg_catalog;", progname, echo);
/*
- * Make sure the language is installed and find the OIDs of the handler
- * and validator functions
+ * Make sure the language is installed and find the OIDs of the
+ * language support functions
*/
- printfPQExpBuffer(&sql, "SELECT lanplcallfoid, lanvalidator "
+ printfPQExpBuffer(&sql, "SELECT lanplcallfoid, laninline, lanvalidator "
"FROM pg_language WHERE lanname = '%s' AND lanispl;",
langname);
result = executeQuery(conn, sql.data, progname, echo);
@@ -206,7 +206,8 @@ main(int argc, char *argv[])
exit(1);
}
lanplcallfoid = atooid(PQgetvalue(result, 0, 0));
- lanvalidator = atooid(PQgetvalue(result, 0, 1));
+ laninline = atooid(PQgetvalue(result, 0, 1));
+ lanvalidator = atooid(PQgetvalue(result, 0, 2));
PQclear(result);
/*
@@ -260,6 +261,44 @@ main(int argc, char *argv[])
handler_ns = NULL;
}
+ /*
+ * Check that the inline function isn't used by some other language
+ */
+ if (OidIsValid(laninline))
+ {
+ printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language "
+ "WHERE laninline = %u AND lanname <> '%s';",
+ laninline, langname);
+ result = executeQuery(conn, sql.data, progname, echo);
+ if (strcmp(PQgetvalue(result, 0, 0), "0") == 0)
+ keepinline = false;
+ else
+ keepinline = true;
+ PQclear(result);
+ }
+ else
+ keepinline = true; /* don't try to delete it */
+
+ /*
+ * Find the inline handler name
+ */
+ if (!keepinline)
+ {
+ printfPQExpBuffer(&sql, "SELECT proname, (SELECT nspname "
+ "FROM pg_namespace ns WHERE ns.oid = pronamespace) "
+ "AS prons FROM pg_proc WHERE oid = %u;",
+ laninline);
+ result = executeQuery(conn, sql.data, progname, echo);
+ inline_handler = strdup(PQgetvalue(result, 0, 0));
+ inline_ns = strdup(PQgetvalue(result, 0, 1));
+ PQclear(result);
+ }
+ else
+ {
+ inline_handler = NULL;
+ inline_ns = NULL;
+ }
+
/*
* Check that the validator function isn't used by some other language
*/
@@ -305,6 +344,9 @@ main(int argc, char *argv[])
if (!keephandler)
appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" ();\n",
handler_ns, handler);
+ if (!keepinline)
+ appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" (internal);\n",
+ inline_ns, inline_handler);
if (!keepvalidator)
appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" (oid);\n",
validator_ns, validator);
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index e162aa71076..5e0fc241549 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.538 2009/09/01 03:53:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.539 2009/09/22 23:43:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200908311
+#define CATALOG_VERSION_NO 200909221
#endif
diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h
index dd8d35e830d..dff946b4119 100644
--- a/src/include/catalog/pg_language.h
+++ b/src/include/catalog/pg_language.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_language.h,v 1.34 2009/01/01 17:23:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_language.h,v 1.35 2009/09/22 23:43:41 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -35,6 +35,7 @@ CATALOG(pg_language,2612)
bool lanispl; /* Is a procedural language */
bool lanpltrusted; /* PL is trusted */
Oid lanplcallfoid; /* Call handler for PL */
+ Oid laninline; /* Optional anonymous-block handler function */
Oid lanvalidator; /* Optional validation function */
aclitem lanacl[1]; /* Access privileges */
} FormData_pg_language;
@@ -50,27 +51,28 @@ typedef FormData_pg_language *Form_pg_language;
* compiler constants for pg_language
* ----------------
*/
-#define Natts_pg_language 7
+#define Natts_pg_language 8
#define Anum_pg_language_lanname 1
#define Anum_pg_language_lanowner 2
#define Anum_pg_language_lanispl 3
#define Anum_pg_language_lanpltrusted 4
#define Anum_pg_language_lanplcallfoid 5
-#define Anum_pg_language_lanvalidator 6
-#define Anum_pg_language_lanacl 7
+#define Anum_pg_language_laninline 6
+#define Anum_pg_language_lanvalidator 7
+#define Anum_pg_language_lanacl 8
/* ----------------
* initial contents of pg_language
* ----------------
*/
-DATA(insert OID = 12 ( "internal" PGUID f f 0 2246 _null_ ));
+DATA(insert OID = 12 ( "internal" PGUID f f 0 0 2246 _null_ ));
DESCR("built-in functions");
#define INTERNALlanguageId 12
-DATA(insert OID = 13 ( "c" PGUID f f 0 2247 _null_ ));
+DATA(insert OID = 13 ( "c" PGUID f f 0 0 2247 _null_ ));
DESCR("dynamically-loaded C functions");
#define ClanguageId 13
-DATA(insert OID = 14 ( "sql" PGUID f t 0 2248 _null_ ));
+DATA(insert OID = 14 ( "sql" PGUID f t 0 0 2248 _null_ ));
DESCR("SQL-language functions");
#define SQLlanguageId 14
diff --git a/src/include/catalog/pg_pltemplate.h b/src/include/catalog/pg_pltemplate.h
index 9775133ceb5..2065a5332bb 100644
--- a/src/include/catalog/pg_pltemplate.h
+++ b/src/include/catalog/pg_pltemplate.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.7 2009/01/01 17:23:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.8 2009/09/22 23:43:41 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -34,6 +34,7 @@ CATALOG(pg_pltemplate,1136) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
bool tmpltrusted; /* PL is trusted? */
bool tmpldbacreate; /* PL is installable by db owner? */
text tmplhandler; /* name of call handler function */
+ text tmplinline; /* name of anonymous-block handler, or NULL */
text tmplvalidator; /* name of validator function, or NULL */
text tmpllibrary; /* path of shared library */
aclitem tmplacl[1]; /* access privileges for template */
@@ -50,14 +51,15 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate;
* compiler constants for pg_pltemplate
* ----------------
*/
-#define Natts_pg_pltemplate 7
+#define Natts_pg_pltemplate 8
#define Anum_pg_pltemplate_tmplname 1
#define Anum_pg_pltemplate_tmpltrusted 2
#define Anum_pg_pltemplate_tmpldbacreate 3
#define Anum_pg_pltemplate_tmplhandler 4
-#define Anum_pg_pltemplate_tmplvalidator 5
-#define Anum_pg_pltemplate_tmpllibrary 6
-#define Anum_pg_pltemplate_tmplacl 7
+#define Anum_pg_pltemplate_tmplinline 5
+#define Anum_pg_pltemplate_tmplvalidator 6
+#define Anum_pg_pltemplate_tmpllibrary 7
+#define Anum_pg_pltemplate_tmplacl 8
/* ----------------
@@ -65,11 +67,11 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate;
* ----------------
*/
-DATA(insert ( "plpgsql" t t "plpgsql_call_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ ));
-DATA(insert ( "pltcl" t t "pltcl_call_handler" _null_ "$libdir/pltcl" _null_ ));
-DATA(insert ( "pltclu" f f "pltclu_call_handler" _null_ "$libdir/pltcl" _null_ ));
-DATA(insert ( "plperl" t t "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ ));
-DATA(insert ( "plperlu" f f "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ ));
-DATA(insert ( "plpythonu" f f "plpython_call_handler" _null_ "$libdir/plpython" _null_ ));
+DATA(insert ( "plpgsql" t t "plpgsql_call_handler" "plpgsql_inline_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ ));
+DATA(insert ( "pltcl" t t "pltcl_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
+DATA(insert ( "pltclu" f f "pltclu_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
+DATA(insert ( "plperl" t t "plperl_call_handler" _null_ "plperl_validator" "$libdir/plperl" _null_ ));
+DATA(insert ( "plperlu" f f "plperl_call_handler" _null_ "plperl_validator" "$libdir/plperl" _null_ ));
+DATA(insert ( "plpythonu" f f "plpython_call_handler" _null_ _null_ "$libdir/plpython" _null_ ));
#endif /* PG_PLTEMPLATE_H */
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 4396a497385..89bb227a90f 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.96 2009/07/29 20:56:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.97 2009/09/22 23:43:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -61,6 +61,7 @@ extern void DropCast(DropCastStmt *stmt);
extern void DropCastById(Oid castOid);
extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
const char *newschema);
+extern void ExecuteDoStmt(DoStmt *stmt);
/* commands/operatorcmds.c */
extern void DefineOperator(List *names, List *parameters);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 6be4bf39598..d842c9c3199 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.225 2009/09/17 20:49:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.226 2009/09/22 23:43:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -274,6 +274,7 @@ typedef enum NodeTag
T_CreateFunctionStmt,
T_AlterFunctionStmt,
T_RemoveFuncStmt,
+ T_DoStmt,
T_RenameStmt,
T_RuleStmt,
T_NotifyStmt,
@@ -388,7 +389,8 @@ typedef enum NodeTag
T_TriggerData = 950, /* in commands/trigger.h */
T_ReturnSetInfo, /* in nodes/execnodes.h */
T_WindowObjectData, /* private in nodeWindowAgg.c */
- T_TIDBitmap /* in nodes/tidbitmap.h */
+ T_TIDBitmap, /* in nodes/tidbitmap.h */
+ T_InlineCodeBlock /* in nodes/parsenodes.h */
} NodeTag;
/*
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index f0b3941abf8..1ce28b77541 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.401 2009/08/02 22:14:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.402 2009/09/22 23:43:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1570,6 +1570,7 @@ typedef struct CreatePLangStmt
NodeTag type;
char *plname; /* PL name */
List *plhandler; /* PL call handler function (qual. name) */
+ List *plinline; /* optional inline function (qual. name) */
List *plvalidator; /* optional validator function (qual. name) */
bool pltrusted; /* PL is trusted */
} CreatePLangStmt;
@@ -1922,6 +1923,25 @@ typedef struct RemoveFuncStmt
bool missing_ok; /* skip error if missing? */
} RemoveFuncStmt;
+/* ----------------------
+ * DO Statement
+ *
+ * DoStmt is the raw parser output, InlineCodeBlock is the execution-time API
+ * ----------------------
+ */
+typedef struct DoStmt
+{
+ NodeTag type;
+ List *args; /* List of DefElem nodes */
+} DoStmt;
+
+typedef struct InlineCodeBlock
+{
+ NodeTag type;
+ char *source_text; /* source text of anonymous code block */
+ Oid langOid; /* OID of selected language */
+} InlineCodeBlock;
+
/* ----------------------
* Drop Operator Class Statement
* ----------------------
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 23f5d87a7a6..d1fd91795b6 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.2 2009/04/06 08:42:53 heikki Exp $
+ * $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.3 2009/09/22 23:43:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -187,6 +187,7 @@ PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD)
PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD)
PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD)
PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
+PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
@@ -204,7 +205,6 @@ PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
-PG_KEYWORD("lancompiler", LANCOMPILER, UNRESERVED_KEYWORD)
PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 6f4acdef701..435a722aa0b 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -7,7 +7,7 @@
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
* Written by Peter Eisentraut .
*
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.104 2009/09/03 22:08:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.105 2009/09/22 23:43:41 tgl Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
@@ -178,6 +178,8 @@ extern char *HbaFileName;
extern char *IdentFileName;
extern char *external_pid_file;
+extern char *default_do_language;
+
extern int tcp_keepalives_idle;
extern int tcp_keepalives_interval;
extern int tcp_keepalives_count;
diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer
index 6040a4b012d..5eb43937ca8 100644
--- a/src/interfaces/ecpg/preproc/ecpg.trailer
+++ b/src/interfaces/ecpg/preproc/ecpg.trailer
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.11 2009/08/14 13:28:22 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.12 2009/09/22 23:43:42 tgl Exp $ */
statements: /*EMPTY*/
| statements statement
@@ -1614,12 +1614,12 @@ ECPGunreserved_con: ABORT_P { $$ = make_str("abort"); }
| INDEXES { $$ = make_str("indexes"); }
| INHERIT { $$ = make_str("inherit"); }
| INHERITS { $$ = make_str("inherits"); }
+ | INLINE_P { $$ = make_str("inline"); }
| INSENSITIVE { $$ = make_str("insensitive"); }
| INSERT { $$ = make_str("insert"); }
| INSTEAD { $$ = make_str("instead"); }
| ISOLATION { $$ = make_str("isolation"); }
| KEY { $$ = make_str("key"); }
- | LANCOMPILER { $$ = make_str("lancompiler"); }
| LANGUAGE { $$ = make_str("language"); }
| LARGE_P { $$ = make_str("large"); }
| LAST_P { $$ = make_str("last"); }
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index c589aa1994d..604b7dbf086 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.138 2009/09/20 01:53:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.139 2009/09/22 23:43:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -95,6 +95,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
PLpgSQL_function *function,
PLpgSQL_func_hashkey *hashkey,
bool forValidator);
+static void add_dummy_return(PLpgSQL_function *function);
static PLpgSQL_row *build_row_from_class(Oid classOid);
static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars);
static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
@@ -670,36 +671,11 @@ do_compile(FunctionCallInfo fcinfo,
* If it has OUT parameters or returns VOID or returns a set, we allow
* control to fall off the end without an explicit RETURN statement. The
* easiest way to implement this is to add a RETURN statement to the end
- * of the statement list during parsing. However, if the outer block has
- * an EXCEPTION clause, we need to make a new outer block, since the added
- * RETURN shouldn't act like it is inside the EXCEPTION clause.
+ * of the statement list during parsing.
*/
if (num_out_args > 0 || function->fn_rettype == VOIDOID ||
function->fn_retset)
- {
- if (function->action->exceptions != NULL)
- {
- PLpgSQL_stmt_block *new;
-
- new = palloc0(sizeof(PLpgSQL_stmt_block));
- new->cmd_type = PLPGSQL_STMT_BLOCK;
- new->body = list_make1(function->action);
-
- function->action = new;
- }
- if (function->action->body == NIL ||
- ((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
- {
- PLpgSQL_stmt_return *new;
-
- new = palloc0(sizeof(PLpgSQL_stmt_return));
- new->cmd_type = PLPGSQL_STMT_RETURN;
- new->expr = NULL;
- new->retvarno = function->out_param_varno;
-
- function->action->body = lappend(function->action->body, new);
- }
- }
+ add_dummy_return(function);
/*
* Complete the function's info
@@ -735,12 +711,150 @@ do_compile(FunctionCallInfo fcinfo,
return function;
}
+/* ----------
+ * plpgsql_compile_inline Make an execution tree for an anonymous code block.
+ *
+ * Note: this is generally parallel to do_compile(); is it worth trying to
+ * merge the two?
+ *
+ * Note: we assume the block will be thrown away so there is no need to build
+ * persistent data structures.
+ * ----------
+ */
+PLpgSQL_function *
+plpgsql_compile_inline(char *proc_source)
+{
+ char *func_name = "inline_code_block";
+ PLpgSQL_function *function;
+ ErrorContextCallback plerrcontext;
+ Oid typinput;
+ PLpgSQL_variable *var;
+ int parse_rc;
+ MemoryContext func_cxt;
+ int i;
+
+ /*
+ * Setup the scanner input and error info. We assume that this function
+ * cannot be invoked recursively, so there's no need to save and restore
+ * the static variables used here.
+ */
+ plpgsql_scanner_init(proc_source);
+
+ plpgsql_error_funcname = func_name;
+ plpgsql_error_lineno = 0;
+
+ /*
+ * Setup error traceback support for ereport()
+ */
+ plerrcontext.callback = plpgsql_compile_error_callback;
+ plerrcontext.arg = proc_source;
+ plerrcontext.previous = error_context_stack;
+ error_context_stack = &plerrcontext;
+
+ plpgsql_ns_init();
+ plpgsql_ns_push(func_name);
+ plpgsql_DumpExecTree = false;
+
+ datums_alloc = 128;
+ plpgsql_nDatums = 0;
+ plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
+ datums_last = 0;
+
+ /* Do extra syntax checking if check_function_bodies is on */
+ plpgsql_check_syntax = check_function_bodies;
+
+ /* Function struct does not live past current statement */
+ function = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function));
+
+ plpgsql_curr_compile = function;
+
+ /*
+ * All the rest of the compile-time storage (e.g. parse tree) is kept in
+ * its own memory context, so it can be reclaimed easily.
+ */
+ func_cxt = AllocSetContextCreate(CurrentMemoryContext,
+ "PL/PgSQL function context",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
+
+ function->fn_name = pstrdup(func_name);
+ function->fn_is_trigger = false;
+ function->fn_cxt = func_cxt;
+ function->out_param_varno = -1; /* set up for no OUT param */
+
+ /* Set up as though in a function returning VOID */
+ function->fn_rettype = VOIDOID;
+ function->fn_retset = false;
+ function->fn_retistuple = false;
+ /* a bit of hardwired knowledge about type VOID here */
+ function->fn_retbyval = true;
+ function->fn_rettyplen = sizeof(int32);
+ getTypeInputInfo(VOIDOID, &typinput, &function->fn_rettypioparam);
+ fmgr_info(typinput, &(function->fn_retinput));
+
+ /*
+ * Remember if function is STABLE/IMMUTABLE. XXX would it be better
+ * to set this TRUE inside a read-only transaction? Not clear.
+ */
+ function->fn_readonly = false;
+
+ /*
+ * Create the magic FOUND variable.
+ */
+ var = plpgsql_build_variable("found", 0,
+ plpgsql_build_datatype(BOOLOID, -1),
+ true);
+ function->found_varno = var->dno;
+
+ /*
+ * Now parse the function's text
+ */
+ parse_rc = plpgsql_yyparse();
+ if (parse_rc != 0)
+ elog(ERROR, "plpgsql parser returned %d", parse_rc);
+ function->action = plpgsql_yylval.program;
+
+ plpgsql_scanner_finish();
+
+ /*
+ * If it returns VOID (always true at the moment), we allow control to
+ * fall off the end without an explicit RETURN statement.
+ */
+ if (function->fn_rettype == VOIDOID)
+ add_dummy_return(function);
+
+ /*
+ * Complete the function's info
+ */
+ function->fn_nargs = 0;
+ function->ndatums = plpgsql_nDatums;
+ function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
+ for (i = 0; i < plpgsql_nDatums; i++)
+ function->datums[i] = plpgsql_Datums[i];
+
+ /*
+ * Pop the error context stack
+ */
+ error_context_stack = plerrcontext.previous;
+ plpgsql_error_funcname = NULL;
+ plpgsql_error_lineno = 0;
+
+ plpgsql_check_syntax = false;
+
+ MemoryContextSwitchTo(compile_tmp_cxt);
+ compile_tmp_cxt = NULL;
+ return function;
+}
+
/*
- * error context callback to let us supply a call-stack traceback. If
- * we are validating, the function source is passed as an
- * argument. This function is public only for the sake of an assertion
- * in gram.y
+ * error context callback to let us supply a call-stack traceback.
+ * If we are validating or executing an anonymous code block, the function
+ * source text is passed as an argument.
+ *
+ * This function is public only for the sake of an assertion in gram.y
*/
void
plpgsql_compile_error_callback(void *arg)
@@ -749,7 +863,7 @@ plpgsql_compile_error_callback(void *arg)
{
/*
* Try to convert syntax error position to reference text of original
- * CREATE FUNCTION command.
+ * CREATE FUNCTION or DO command.
*/
if (function_parse_error_transpose((const char *) arg))
return;
@@ -766,6 +880,42 @@ plpgsql_compile_error_callback(void *arg)
}
+/*
+ * Add a dummy RETURN statement to the given function's body
+ */
+static void
+add_dummy_return(PLpgSQL_function *function)
+{
+ /*
+ * If the outer block has an EXCEPTION clause, we need to make a new outer
+ * block, since the added RETURN shouldn't act like it is inside the
+ * EXCEPTION clause.
+ */
+ if (function->action->exceptions != NULL)
+ {
+ PLpgSQL_stmt_block *new;
+
+ new = palloc0(sizeof(PLpgSQL_stmt_block));
+ new->cmd_type = PLPGSQL_STMT_BLOCK;
+ new->body = list_make1(function->action);
+
+ function->action = new;
+ }
+ if (function->action->body == NIL ||
+ ((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
+ {
+ PLpgSQL_stmt_return *new;
+
+ new = palloc0(sizeof(PLpgSQL_stmt_return));
+ new->cmd_type = PLPGSQL_STMT_RETURN;
+ new->expr = NULL;
+ new->retvarno = function->out_param_varno;
+
+ function->action->body = lappend(function->action->body, new);
+ }
+}
+
+
/* ----------
* plpgsql_parse_word The scanner calls this to postparse
* any single word not found by a
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 2abe67c8526..4f506eb97ca 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.45 2009/08/04 21:22:46 alvherre Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.46 2009/09/22 23:43:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -114,6 +114,57 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
return retval;
}
+/* ----------
+ * plpgsql_inline_handler
+ *
+ * Called by PostgreSQL to execute an anonymous code block
+ * ----------
+ */
+PG_FUNCTION_INFO_V1(plpgsql_inline_handler);
+
+Datum
+plpgsql_inline_handler(PG_FUNCTION_ARGS)
+{
+ InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
+ PLpgSQL_function *func;
+ FunctionCallInfoData fake_fcinfo;
+ FmgrInfo flinfo;
+ Datum retval;
+ int rc;
+
+ Assert(IsA(codeblock, InlineCodeBlock));
+
+ /*
+ * Connect to SPI manager
+ */
+ if ((rc = SPI_connect()) != SPI_OK_CONNECT)
+ elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
+
+ /* Compile the anonymous code block */
+ func = plpgsql_compile_inline(codeblock->source_text);
+
+ /*
+ * Set up a fake fcinfo with just enough info to satisfy
+ * plpgsql_exec_function(). In particular note that this sets things up
+ * with no arguments passed.
+ */
+ MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
+ MemSet(&flinfo, 0, sizeof(flinfo));
+ fake_fcinfo.flinfo = &flinfo;
+ flinfo.fn_oid = InvalidOid;
+ flinfo.fn_mcxt = CurrentMemoryContext;
+
+ retval = plpgsql_exec_function(func, &fake_fcinfo);
+
+ /*
+ * Disconnect from SPI manager
+ */
+ if ((rc = SPI_finish()) != SPI_OK_FINISH)
+ elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
+
+ return retval;
+}
+
/* ----------
* plpgsql_validator
*
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 21c9edb52ca..fb627e7a898 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.115 2009/08/04 21:22:46 alvherre Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.116 2009/09/22 23:43:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -799,6 +799,7 @@ extern PLpgSQL_plugin **plugin_ptr;
*/
extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo,
bool forValidator);
+extern PLpgSQL_function *plpgsql_compile_inline(char *proc_source);
extern int plpgsql_parse_word(const char *word);
extern int plpgsql_parse_dblword(const char *word);
extern int plpgsql_parse_tripword(const char *word);
@@ -828,6 +829,7 @@ extern void plpgsql_compile_error_callback(void *arg);
*/
extern void _PG_init(void);
extern Datum plpgsql_call_handler(PG_FUNCTION_ARGS);
+extern Datum plpgsql_inline_handler(PG_FUNCTION_ARGS);
extern Datum plpgsql_validator(PG_FUNCTION_ARGS);
/* ----------
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 078c14d8158..ca4c9dc2331 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -3861,3 +3861,40 @@ NOTICE: foo\bar!baz
(1 row)
drop function strtest();
+-- Test anonymous code blocks.
+DO $$
+DECLARE r record;
+BEGIN
+ FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
+ LOOP
+ RAISE NOTICE '%, %', r.roomno, r.comment;
+ END LOOP;
+END$$ LANGUAGE plpgsql;
+NOTICE: 001, Entrance
+NOTICE: 002, Office
+NOTICE: 003, Office
+NOTICE: 004, Technical
+NOTICE: 101, Office
+NOTICE: 102, Conference
+NOTICE: 103, Restroom
+NOTICE: 104, Technical
+NOTICE: 105, Office
+NOTICE: 106, Office
+-- these are to check syntax error reporting
+DO LANGUAGE plpgsql $$begin return 1; end$$;
+ERROR: RETURN cannot have a parameter in function returning void at or near "1"
+LINE 1: DO LANGUAGE plpgsql $$begin return 1; end$$;
+ ^
+DO LANGUAGE plpgsql $$
+DECLARE r record;
+BEGIN
+ FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
+ LOOP
+ RAISE NOTICE '%, %', r.roomno, r.comment;
+ END LOOP;
+END$$;
+ERROR: column "foo" does not exist
+LINE 1: SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY room...
+ ^
+QUERY: SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
+CONTEXT: PL/pgSQL function "inline_code_block" line 3 at FOR over SELECT rows
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index da122118478..96f89144b77 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -3079,3 +3079,26 @@ $$ language plpgsql;
select strtest();
drop function strtest();
+
+-- Test anonymous code blocks.
+
+DO $$
+DECLARE r record;
+BEGIN
+ FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
+ LOOP
+ RAISE NOTICE '%, %', r.roomno, r.comment;
+ END LOOP;
+END$$ LANGUAGE plpgsql;
+
+-- these are to check syntax error reporting
+DO LANGUAGE plpgsql $$begin return 1; end$$;
+
+DO LANGUAGE plpgsql $$
+DECLARE r record;
+BEGIN
+ FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
+ LOOP
+ RAISE NOTICE '%, %', r.roomno, r.comment;
+ END LOOP;
+END$$;