On Tue, 2006-01-03 at 18:00 -0500, Neil Conway wrote: > Anyway, if there was a reasonably cheap way to present the query strings > of protocol-level and SQL prepared statements in the same manner, I > think we should definitely do so. Since there doesn't appear to be one, > I'm content to just use the query string as sent by the user. I'll post > a revised patch that does that soon.
Attached is the patch I applied to HEAD that uses the query string supplied by the client, without any rewriting. -Neil
============================================================ *** doc/src/sgml/catalogs.sgml 29fbade056e00ee4a48ba6a3f686627f62a103cf --- doc/src/sgml/catalogs.sgml f265188b9a381a6c2e67f94290b56f9dc993f5d1 *************** *** 4373,4378 **** --- 4373,4383 ---- </row> <row> + <entry><link linkend="view-pg-prepared-statements"><structname>pg_prepared_statements</structname></link></entry> + <entry>current prepared statements</entry> + </row> + + <row> <entry><link linkend="view-pg-prepared-xacts"><structname>pg_prepared_xacts</structname></link></entry> <entry>currently prepared transactions</entry> </row> *************** *** 4778,4783 **** --- 4783,4883 ---- </sect1> + <sect1 id="view-pg-prepared-statements"> + <title><structname>pg_prepared_statements</structname></title> + + <indexterm zone="view-pg-prepared-statements"> + <primary>pg_prepared_statements</primary> + </indexterm> + + <para> + The <structname>pg_prepared_statements</structname> view displays + all the prepared statements that are available in the current + session. See <xref linkend="sql-prepare" + endterm="sql-prepare-title"> for more information about prepared + statements. + </para> + + <para> + <structname>pg_prepared_statements</structname> contains one row + for each prepared statement. Rows are added to the view when a new + prepared statement is created, and removed when a prepared + statement is released (for example, via the <xref + linkend="sql-deallocate" endterm="sql-deallocate-title"> + command). + </para> + + <table> + <title><structname>pg_prepared_statements</> Columns</title> + + <tgroup cols=4> + <thead> + <row> + <entry>Name</entry> + <entry>Type</entry> + <entry>References</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry><structfield>name</structfield></entry> + <entry><type>text</type></entry> + <entry></entry> + <entry> + The identifier of the prepared statement. + </entry> + </row> + <row> + <entry><structfield>statement</structfield></entry> + <entry><type>text</type></entry> + <entry></entry> + <entry> + The query string submitted by the client to create this + prepared statement. For prepared statements created via SQL, + this is the <command>PREPARE</command> statement submitted by + the client. For prepared statements created via the + frontend/backend protocol, this is the text of the prepared + statement itself. + </entry> + </row> + <row> + <entry><structfield>prepare_time</structfield></entry> + <entry><type>timestamptz</type></entry> + <entry></entry> + <entry> + The time at which the prepared statement was created. + </entry> + </row> + <row> + <entry><structfield>parameter_types</structfield></entry> + <entry><type>oid[]</type></entry> + <entry></entry> + <entry> + The expected parameter types for the prepared statement in the form of + an array of type OIDs. + </entry> + </row> + <row> + <entry><structfield>from_sql</structfield></entry> + <entry><type>boolean</type></entry> + <entry></entry> + <entry> + <literal>true</literal> if the prepared statement was created + via the <command>PREPARE</command> SQL statement; + <literal>false</literal> if the statement was prepared via the + frontend/backend protocol. + </entry> + </row> + </tbody> + </tgroup> + </table> + + <para> + The <structname>pg_prepared_statements</structname> view is read only. + </para> + </sect1> + <sect1 id="view-pg-prepared-xacts"> <title><structname>pg_prepared_xacts</structname></title> ============================================================ *** doc/src/sgml/ref/prepare.sgml 17fce269c43549b6ffa7bf3d5770da9fbdf18896 --- doc/src/sgml/ref/prepare.sgml 98824b3ad9ac4ffa50677f3b8ac821f8a1c84e16 *************** *** 145,150 **** --- 145,155 ---- the <xref linkend="sql-analyze" endterm="sql-analyze-title"> documentation. </para> + + <para> + You can see all available prepared statements of a session by querying the + <structname>pg_prepared_statements</> system view. + </para> </refsect1> <refsect1 id="sql-prepare-examples"> ============================================================ *** src/backend/catalog/system_views.sql 307260ff7bc30a48c0c60a40d4130f70310ebff2 --- src/backend/catalog/system_views.sql 7b92550bbcaf9d0ee99c12527f7785385cfeefe7 *************** *** 156,161 **** --- 156,167 ---- LEFT JOIN pg_authid U ON P.ownerid = U.oid LEFT JOIN pg_database D ON P.dbid = D.oid; + CREATE VIEW pg_prepared_statements AS + SELECT P.name, P.statement, P.prepare_time, P.parameter_types, P.from_sql + FROM pg_prepared_statement() AS P + (name text, statement text, prepare_time timestamptz, + parameter_types oid[], from_sql boolean); + CREATE VIEW pg_settings AS SELECT * FROM pg_show_all_settings() AS A ============================================================ *** src/backend/commands/prepare.c 3c1a8b677a84566407472a0b7b85b4cb86587956 --- src/backend/commands/prepare.c dc237de8d42ca2cd72d75e3b9bf64b8786702e5a *************** *** 16,30 **** */ #include "postgres.h" #include "commands/explain.h" #include "commands/prepare.h" #include "executor/executor.h" ! #include "utils/guc.h" #include "optimizer/planner.h" #include "rewrite/rewriteHandler.h" #include "tcop/pquery.h" #include "tcop/tcopprot.h" #include "tcop/utility.h" #include "utils/hsearch.h" #include "utils/memutils.h" --- 16,35 ---- */ #include "postgres.h" + #include "access/heapam.h" + #include "catalog/pg_type.h" #include "commands/explain.h" #include "commands/prepare.h" #include "executor/executor.h" ! #include "funcapi.h" ! #include "parser/parsetree.h" #include "optimizer/planner.h" #include "rewrite/rewriteHandler.h" #include "tcop/pquery.h" #include "tcop/tcopprot.h" #include "tcop/utility.h" + #include "utils/builtins.h" + #include "utils/guc.h" #include "utils/hsearch.h" #include "utils/memutils.h" *************** *** 40,45 **** --- 45,51 ---- static void InitQueryHashTable(void); static ParamListInfo EvaluateParams(EState *estate, List *params, List *argtypes); + static Datum build_oid_array(List *oid_list); /* * Implements the 'PREPARE' utility statement. *************** *** 114,120 **** commandTag, query_list, plan_list, ! stmt->argtype_oids); } /* --- 120,127 ---- commandTag, query_list, plan_list, ! stmt->argtype_oids, ! true); } /* *************** *** 298,304 **** const char *commandTag, List *query_list, List *plan_list, ! List *argtype_list) { PreparedStatement *entry; MemoryContext oldcxt, --- 305,312 ---- const char *commandTag, List *query_list, List *plan_list, ! List *argtype_list, ! bool from_sql) { PreparedStatement *entry; MemoryContext oldcxt, *************** *** 361,366 **** --- 369,376 ---- entry->plan_list = plan_list; entry->argtype_list = argtype_list; entry->context = entrycxt; + entry->prepare_time = GetCurrentTimestamp(); + entry->from_sql = from_sql; MemoryContextSwitchTo(oldcxt); } *************** *** 383,389 **** { /* * We can't just use the statement name as supplied by the user: the ! * hash package is picky enough that it needs to be NULL-padded out to * the appropriate length to work correctly. */ StrNCpy(key, stmt_name, sizeof(key)); --- 393,399 ---- { /* * We can't just use the statement name as supplied by the user: the ! * hash package is picky enough that it needs to be NUL-padded out to * the appropriate length to work correctly. */ StrNCpy(key, stmt_name, sizeof(key)); *************** *** 661,663 **** --- 671,795 ---- if (estate) FreeExecutorState(estate); } + + /* + * This set returning function reads all the prepared statements and + * returns a set of (name, statement, prepare_time, param_types). + */ + Datum + pg_prepared_statement(PG_FUNCTION_ARGS) + { + FuncCallContext *funcctx; + HASH_SEQ_STATUS *hash_seq; + PreparedStatement *prep_stmt; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + TupleDesc tupdesc; + MemoryContext oldcontext; + + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + /* + * switch to memory context appropriate for multiple function + * calls + */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* allocate memory for user context */ + if (prepared_queries) + { + hash_seq = (HASH_SEQ_STATUS *) palloc(sizeof(HASH_SEQ_STATUS)); + hash_seq_init(hash_seq, prepared_queries); + funcctx->user_fctx = (void *) hash_seq; + } + else + funcctx->user_fctx = NULL; + + /* + * build tupdesc for result tuples. This must match the + * definition of the pg_prepared_statements view in + * system_views.sql + */ + tupdesc = CreateTemplateTupleDesc(5, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time", + TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types", + OIDARRAYOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql", + BOOLOID, -1, 0); + + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + MemoryContextSwitchTo(oldcontext); + } + + /* stuff done on every call of the function */ + funcctx = SRF_PERCALL_SETUP(); + hash_seq = (HASH_SEQ_STATUS *) funcctx->user_fctx; + + /* if the hash table is uninitialized, we're done */ + if (hash_seq == NULL) + SRF_RETURN_DONE(funcctx); + + prep_stmt = hash_seq_search(hash_seq); + if (prep_stmt) + { + Datum result; + HeapTuple tuple; + Datum values[5]; + bool nulls[5]; + + MemSet(nulls, 0, sizeof(nulls)); + + values[0] = DirectFunctionCall1(textin, + CStringGetDatum(prep_stmt->stmt_name)); + + if (prep_stmt->query_string == NULL) + nulls[1] = true; + else + values[1] = DirectFunctionCall1(textin, + CStringGetDatum(prep_stmt->query_string)); + + values[2] = TimestampTzGetDatum(prep_stmt->prepare_time); + values[3] = build_oid_array(prep_stmt->argtype_list); + values[4] = BoolGetDatum(prep_stmt->from_sql); + + tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + result = HeapTupleGetDatum(tuple); + SRF_RETURN_NEXT(funcctx, result); + } + + SRF_RETURN_DONE(funcctx); + } + + /* + * This utility function takes a List of Oids, and returns a Datum + * pointing to a Postgres array containing those OIDs. The empty list + * is returned as a zero-element array, not NULL. + */ + static Datum + build_oid_array(List *oid_list) + { + ListCell *lc; + int len; + int i; + Datum *tmp_ary; + ArrayType *ary; + + len = list_length(oid_list); + tmp_ary = (Datum *) palloc(len * sizeof(Datum)); + + i = 0; + foreach(lc, oid_list) + tmp_ary[i++] = ObjectIdGetDatum(lfirst_oid(lc)); + + /* XXX: this hardcodes assumptions about the OID type... */ + ary = construct_array(tmp_ary, len, OIDOID, sizeof(Oid), true, 'i'); + return PointerGetDatum(ary); + } ============================================================ *** src/backend/tcop/postgres.c f7e0f0dfaefca6014bb740974b51674d9856af52 --- src/backend/tcop/postgres.c 7e0c12bb20c7c728cb3c75a3b9fa3216cbb930c4 *************** *** 55,60 **** --- 55,61 ---- #include "tcop/pquery.h" #include "tcop/tcopprot.h" #include "tcop/utility.h" + #include "utils/builtins.h" #include "utils/flatfiles.h" #include "utils/guc.h" #include "utils/lsyscache.h" *************** *** 1308,1314 **** commandTag, querytree_list, plantree_list, ! param_list); } else { --- 1309,1316 ---- commandTag, querytree_list, plantree_list, ! param_list, ! false); } else { *************** *** 1322,1327 **** --- 1324,1330 ---- pstmt->query_list = querytree_list; pstmt->plan_list = plantree_list; pstmt->argtype_list = param_list; + pstmt->from_sql = false; pstmt->context = unnamed_stmt_context; /* Now the unnamed statement is complete and valid */ unnamed_stmt_pstmt = pstmt; ============================================================ *** src/include/catalog/catversion.h a927f31e147ee53ba1556ece5c1274ad51d3ac90 --- src/include/catalog/catversion.h ec1699040aae8697aac9fca28606a491e794bead *************** *** 53,58 **** */ /* yyyymmddN */ ! #define CATALOG_VERSION_NO 200512271 #endif --- 53,58 ---- */ /* yyyymmddN */ ! #define CATALOG_VERSION_NO 200601081 #endif ============================================================ *** src/include/catalog/pg_proc.h cf6670bbb53ec82df8cef94c7816568e84f76649 --- src/include/catalog/pg_proc.h 30a03ca195666dbb6c2ce4c9276c59c85bf733a3 *************** *** 3617,3622 **** --- 3617,3624 ---- DESCR("constraint description with pretty-print option"); DATA(insert OID = 2509 ( pg_get_expr PGNSP PGUID 12 f f t f s 3 25 "25 26 16" _null_ _null_ _null_ pg_get_expr_ext - _null_ )); DESCR("deparse an encoded expression with pretty-print option"); + DATA(insert OID = 2510 ( pg_prepared_statement PGNSP PGUID 12 f f t t s 0 2249 "" _null_ _null_ _null_ pg_prepared_statement - _null_ )); + DESCR("get the prepared statements for this session"); /* non-persistent series generator */ DATA(insert OID = 1066 ( generate_series PGNSP PGUID 12 f f t t v 3 23 "23 23 23" _null_ _null_ _null_ generate_series_step_int4 - _null_ )); ============================================================ *** src/include/catalog/pg_type.h 8ec7dd1d4090cf8d0e42e8e942be80a242663181 --- src/include/catalog/pg_type.h b2c605634dd3fff9823efc37bffdc3df638c5e4d *************** *** 406,411 **** --- 406,412 ---- DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b t \054 0 24 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b t \054 0 25 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b t \054 0 26 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); + #define OIDARRAYOID 1028 DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b t \054 0 27 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b t \054 0 28 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b t \054 0 29 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); ============================================================ *** src/include/commands/prepare.h 6efc9215b98662a9c339ca3c4e00565039d6d1af --- src/include/commands/prepare.h 0edc3f720309bfdedcd06ea718a04e76a46479d0 *************** *** 30,42 **** typedef struct { /* dynahash.c requires key to be first field */ ! char stmt_name[NAMEDATALEN]; ! char *query_string; /* text of query, or NULL */ ! const char *commandTag; /* command tag (a constant!), or NULL */ ! List *query_list; /* list of queries */ ! List *plan_list; /* list of plans */ ! List *argtype_list; /* list of parameter type OIDs */ ! MemoryContext context; /* context containing this query */ } PreparedStatement; --- 30,45 ---- typedef struct { /* dynahash.c requires key to be first field */ ! char stmt_name[NAMEDATALEN]; ! char *query_string; /* text of query, or NULL */ ! const char *commandTag; /* command tag (a constant!), or NULL */ ! List *query_list; /* list of queries, rewritten */ ! List *plan_list; /* list of plans */ ! List *argtype_list; /* list of parameter type OIDs */ ! TimestampTz prepare_time; /* the time when the stmt was prepared */ ! bool from_sql; /* stmt prepared via SQL, not ! * FE/BE protocol? */ ! MemoryContext context; /* context containing this query */ } PreparedStatement; *************** *** 54,60 **** const char *commandTag, List *query_list, List *plan_list, ! List *argtype_list); extern PreparedStatement *FetchPreparedStatement(const char *stmt_name, bool throwError); extern void DropPreparedStatement(const char *stmt_name, bool showError); --- 57,64 ---- const char *commandTag, List *query_list, List *plan_list, ! List *argtype_list, ! bool from_sql); extern PreparedStatement *FetchPreparedStatement(const char *stmt_name, bool throwError); extern void DropPreparedStatement(const char *stmt_name, bool showError); ============================================================ *** src/include/utils/builtins.h 59e351f3d080f64a8f9c60208697d98be3a74cc0 --- src/include/utils/builtins.h 435078a846fa3528c3f72253440c25979e4f90cc *************** *** 861,864 **** --- 861,867 ---- /* catalog/pg_conversion.c */ extern Datum pg_convert_using(PG_FUNCTION_ARGS); + /* commands/prepare.c */ + extern Datum pg_prepared_statement(PG_FUNCTION_ARGS); + #endif /* BUILTINS_H */ ============================================================ *** src/test/regress/expected/prepare.out 65183ee54b3fae638559a548c5326f0ad3f7ad17 --- src/test/regress/expected/prepare.out ac00879338b4a595a7115ff49820258b9fea4556 *************** *** 1,11 **** ! -- Regression tests for prepareable statements ! PREPARE q1 AS SELECT 1; EXECUTE q1; ! ?column? ! ---------- ! 1 (1 row) -- should fail PREPARE q1 AS SELECT 2; ERROR: prepared statement "q1" already exists --- 1,24 ---- ! -- Regression tests for prepareable statements. We query the content ! -- of the pg_prepared_statements view as prepared statements are ! -- created and removed. ! SELECT name, statement, parameter_types FROM pg_prepared_statements; ! name | statement | parameter_types ! ------+-----------+----------------- ! (0 rows) ! ! PREPARE q1 AS SELECT 1 AS a; EXECUTE q1; ! a ! --- ! 1 (1 row) + SELECT name, statement, parameter_types FROM pg_prepared_statements; + name | statement | parameter_types + ------+------------------------------+----------------- + q1 | PREPARE q1 AS SELECT 1 AS a; | {} + (1 row) + -- should fail PREPARE q1 AS SELECT 2; ERROR: prepared statement "q1" already exists *************** *** 18,29 **** --- 31,71 ---- 2 (1 row) + PREPARE q2 AS SELECT 2 AS b; + SELECT name, statement, parameter_types FROM pg_prepared_statements; + name | statement | parameter_types + ------+------------------------------+----------------- + q1 | PREPARE q1 AS SELECT 2; | {} + q2 | PREPARE q2 AS SELECT 2 AS b; | {} + (2 rows) + -- sql92 syntax DEALLOCATE PREPARE q1; + SELECT name, statement, parameter_types FROM pg_prepared_statements; + name | statement | parameter_types + ------+------------------------------+----------------- + q2 | PREPARE q2 AS SELECT 2 AS b; | {} + (1 row) + + DEALLOCATE PREPARE q2; + -- the view should return the empty set again + SELECT name, statement, parameter_types FROM pg_prepared_statements; + name | statement | parameter_types + ------+-----------+----------------- + (0 rows) + -- parameterized queries PREPARE q2(text) AS SELECT datname, datistemplate, datallowconn FROM pg_database WHERE datname = $1; + SELECT name, statement, parameter_types FROM pg_prepared_statements; + name | statement | parameter_types + ------+--------------------------------------------------------------------------------------------------------+----------------- + q2 | PREPARE q2(text) AS + SELECT datname, datistemplate, datallowconn + FROM pg_database WHERE datname = $1; | {25} + (1 row) + EXECUTE q2('regression'); datname | datistemplate | datallowconn ------------+---------------+-------------- *************** *** 33,38 **** --- 75,91 ---- PREPARE q3(text, int, float, boolean, oid, smallint) AS SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR ten = $3::bigint OR true = $4 OR oid = $5 OR odd = $6::int); + SELECT name, statement, parameter_types FROM pg_prepared_statements; + name | statement | parameter_types + ------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------- + q2 | PREPARE q2(text) AS + SELECT datname, datistemplate, datallowconn + FROM pg_database WHERE datname = $1; | {25} + q3 | PREPARE q3(text, int, float, boolean, oid, smallint) AS + SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR + ten = $3::bigint OR true = $4 OR oid = $5 OR odd = $6::int); | {25,23,701,16,26,21} + (2 rows) + EXECUTE q3('AAAAxx', 5::smallint, 10.5::float, false, 500::oid, 4::bigint); unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- ============================================================ *** src/test/regress/expected/rules.out 50f1bbe53e81493d4e3ecd6f38ffedfdf78ba115 --- src/test/regress/expected/rules.out d2b7b350c3d01bd98ee6ceaa0e92acb34c2380f6 *************** *** 1280,1285 **** --- 1280,1286 ---- pg_group | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin); pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS "tablespace", pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char")); pg_locks | SELECT l.locktype, l."database", l.relation, l.page, l.tuple, l.transactionid, l.classid, l.objid, l.objsubid, l."transaction", l.pid, l."mode", l."granted" FROM pg_lock_status() l(locktype text, "database" oid, relation oid, page integer, tuple smallint, transactionid xid, classid oid, objid oid, objsubid smallint, "transaction" xid, pid integer, "mode" text, "granted" boolean); + pg_prepared_statements | SELECT p.name, p."statement", p.prepare_time, p.parameter_types, p.from_sql FROM pg_prepared_statement() p(name text, "statement" text, prepare_time timestamp with time zone, parameter_types oid[], from_sql boolean); pg_prepared_xacts | SELECT p."transaction", p.gid, p."prepared", u.rolname AS "owner", d.datname AS "database" FROM ((pg_prepared_xact() p("transaction" xid, gid text, "prepared" timestamp with time zone, ownerid oid, dbid oid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid))); pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig, pg_authid.oid FROM pg_authid; pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name); *************** *** 1320,1326 **** shoelace_obsolete | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color)))); street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath); toyemp | SELECT emp.name, emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp; ! (44 rows) SELECT tablename, rulename, definition FROM pg_rules ORDER BY tablename, rulename; --- 1321,1327 ---- shoelace_obsolete | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color)))); street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath); toyemp | SELECT emp.name, emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp; ! (45 rows) SELECT tablename, rulename, definition FROM pg_rules ORDER BY tablename, rulename; ============================================================ *** src/test/regress/sql/prepare.sql 77e19c33d5c686ea3013cefc80d4df7b997cc7b2 --- src/test/regress/sql/prepare.sql 90bc73b518b0d7ef0c1ede82d5ae088392ea3910 *************** *** 1,8 **** ! -- Regression tests for prepareable statements ! PREPARE q1 AS SELECT 1; EXECUTE q1; -- should fail PREPARE q1 AS SELECT 2; --- 1,14 ---- ! -- Regression tests for prepareable statements. We query the content ! -- of the pg_prepared_statements view as prepared statements are ! -- created and removed. ! SELECT name, statement, parameter_types FROM pg_prepared_statements; ! ! PREPARE q1 AS SELECT 1 AS a; EXECUTE q1; + SELECT name, statement, parameter_types FROM pg_prepared_statements; + -- should fail PREPARE q1 AS SELECT 2; *************** *** 11,29 **** --- 17,49 ---- PREPARE q1 AS SELECT 2; EXECUTE q1; + PREPARE q2 AS SELECT 2 AS b; + SELECT name, statement, parameter_types FROM pg_prepared_statements; + -- sql92 syntax DEALLOCATE PREPARE q1; + SELECT name, statement, parameter_types FROM pg_prepared_statements; + + DEALLOCATE PREPARE q2; + -- the view should return the empty set again + SELECT name, statement, parameter_types FROM pg_prepared_statements; + -- parameterized queries PREPARE q2(text) AS SELECT datname, datistemplate, datallowconn FROM pg_database WHERE datname = $1; + + SELECT name, statement, parameter_types FROM pg_prepared_statements; + EXECUTE q2('regression'); PREPARE q3(text, int, float, boolean, oid, smallint) AS SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR ten = $3::bigint OR true = $4 OR oid = $5 OR odd = $6::int); + SELECT name, statement, parameter_types FROM pg_prepared_statements; + EXECUTE q3('AAAAxx', 5::smallint, 10.5::float, false, 500::oid, 4::bigint); -- too few params
---------------------------(end of broadcast)--------------------------- TIP 9: In versions below 8.0, the planner will ignore your desire to choose an index scan if your joining column's datatypes do not match