Commit 555353c0 authored by Tom Lane's avatar Tom Lane

Rearrange extension-related views as per recent discussion.

The original design of pg_available_extensions did not consider the
possibility of version-specific control files.  Split it into two views:
pg_available_extensions shows information that is generic about an
extension, while pg_available_extension_versions shows all available
versions together with information that could be version-dependent.
Also, add an SRF pg_extension_update_paths() to assist in checking that
a collection of update scripts provide sane update path sequences.
parent cee103da
......@@ -6330,6 +6330,11 @@
<entry>available extensions</entry>
</row>
<row>
<entry><link linkend="view-pg-available-extension-versions"><structname>pg_available_extension_versions</structname></link></entry>
<entry>available versions of extensions</entry>
</row>
<row>
<entry><link linkend="view-pg-cursors"><structname>pg_cursors</structname></link></entry>
<entry>open cursors</entry>
......@@ -6460,23 +6465,78 @@
</row>
<row>
<entry><structfield>version</structfield></entry>
<entry><structfield>default_version</structfield></entry>
<entry><type>text</type></entry>
<entry>Version string from the extension's control file</entry>
<entry>Name of default version, or <literal>NULL</literal> if none is
specified</entry>
</row>
<row>
<entry><structfield>installed</structfield></entry>
<entry><structfield>installed_version</structfield></entry>
<entry><type>text</type></entry>
<entry>Currently installed version of the extension,
or <literal>NULL</literal> if not installed</entry>
</row>
<row>
<entry><structfield>schema</structfield></entry>
<entry><structfield>comment</structfield></entry>
<entry><type>text</type></entry>
<entry>Comment string from the extension's control file</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
The <structname>pg_available_extensions</structname> view is read only.
</para>
</sect1>
<sect1 id="view-pg-available-extension-versions">
<title><structname>pg_available_extension_versions</structname></title>
<indexterm zone="view-pg-available-extension-versions">
<primary>pg_available_extension_versions</primary>
</indexterm>
<para>
The <structname>pg_available_extension_versions</structname> view lists the
specific extension versions that are available for installation. This view
can only be read by superusers. See also the <link
linkend="catalog-pg-extension"><structname>pg_extension</structname></link>
catalog, which shows the extensions currently installed.
</para>
<table>
<title><structname>pg_available_extension_versions</> Columns</title>
<tgroup cols="3">
<thead>
<row>
<entry>Name</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>name</structfield></entry>
<entry><type>name</type></entry>
<entry>Name of the schema where the extension is installed,
or <literal>NULL</literal> if not installed</entry>
<entry>Extension name</entry>
</row>
<row>
<entry><structfield>version</structfield></entry>
<entry><type>text</type></entry>
<entry>Version name</entry>
</row>
<row>
<entry><structfield>installed</structfield></entry>
<entry><type>bool</type></entry>
<entry>True if this version of this extension is currently
installed</entry>
</row>
<row>
......@@ -6485,6 +6545,20 @@
<entry>True if extension can be relocated to another schema</entry>
</row>
<row>
<entry><structfield>schema</structfield></entry>
<entry><type>name</type></entry>
<entry>Name of the schema that the extension must be installed into,
or <literal>NULL</literal> if partially or fully relocatable</entry>
</row>
<row>
<entry><structfield>requires</structfield></entry>
<entry><type>name[]</type></entry>
<entry>Names of prerequisite extensions,
or <literal>NULL</literal> if none</entry>
</row>
<row>
<entry><structfield>comment</structfield></entry>
<entry><type>text</type></entry>
......@@ -6495,9 +6569,9 @@
</table>
<para>
The <structname>pg_available_extensions</structname> view is read only.
The <structname>pg_available_extension_versions</structname> view is read
only.
</para>
</sect1>
<sect1 id="view-pg-cursors">
......
......@@ -765,6 +765,20 @@ SELECT pg_catalog.pg_extension_config_dump('my_config', 'WHERE NOT standard_entr
path than to move ahead one version at a time. If the downgrade script
drops any irreplaceable objects, this will yield undesirable results.
</para>
<para>
To check for unexpected update paths, use this command:
<programlisting>
SELECT * FROM pg_extension_update_paths('<replaceable>extension_name</>');
</programlisting>
This shows each pair of distinct known version names for the specified
extension, together with the update path sequence that would be taken to
get from the source version to the target version, or <literal>NULL</> if
there is no available update path. The path is shown in textual form
with <literal>--</> separators. You can use
<literal>regexp_split_to_array(path,'--')</> if you prefer an array
format.
</para>
</sect2>
<sect2>
......
......@@ -154,11 +154,17 @@ CREATE VIEW pg_cursors AS
SELECT * FROM pg_cursor() AS C;
CREATE VIEW pg_available_extensions AS
SELECT E.name, E.version, X.extversion AS installed,
N.nspname AS schema, E.relocatable, E.comment
SELECT E.name, E.default_version, X.extversion AS installed_version,
E.comment
FROM pg_available_extensions() AS E
LEFT JOIN pg_extension AS X ON E.name = X.extname
LEFT JOIN pg_namespace AS N on N.oid = X.extnamespace;
LEFT JOIN pg_extension AS X ON E.name = X.extname;
CREATE VIEW pg_available_extension_versions AS
SELECT E.name, E.version, (X.extname IS NOT NULL) AS installed,
E.relocatable, E.schema, E.requires, E.comment
FROM pg_available_extension_versions() AS E
LEFT JOIN pg_extension AS X
ON E.name = X.extname AND E.version = X.extversion;
CREATE VIEW pg_prepared_xacts AS
SELECT P.transaction, P.gid, P.prepared,
......
......@@ -24,6 +24,7 @@
#include "postgres.h"
#include <dirent.h>
#include <limits.h>
#include <unistd.h>
#include "access/sysattr.h"
......@@ -80,6 +81,7 @@ typedef struct ExtensionVersionInfo
{
char *name; /* name of the starting version */
List *reachable; /* List of ExtensionVersionInfo's */
bool installable; /* does this version have an install script? */
/* working state for Dijkstra's algorithm: */
bool distance_known; /* is distance from start known yet? */
int distance; /* current worst-case distance estimate */
......@@ -87,6 +89,13 @@ typedef struct ExtensionVersionInfo
} ExtensionVersionInfo;
/* Local functions */
static List *find_update_path(List *evi_list,
ExtensionVersionInfo *evi_start,
ExtensionVersionInfo *evi_target,
bool reinitialize);
static void get_available_versions_for_extension(ExtensionControlFile *pcontrol,
Tuplestorestate *tupstore,
TupleDesc tupdesc);
static void ApplyExtensionUpdates(Oid extensionOid,
ExtensionControlFile *pcontrol,
const char *initialVersion,
......@@ -909,6 +918,7 @@ get_ext_ver_info(const char *versionname, List **evi_list)
evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
evi->name = pstrdup(versionname);
evi->reachable = NIL;
evi->installable = false;
/* initialize for later application of Dijkstra's algorithm */
evi->distance_known = false;
evi->distance = INT_MAX;
......@@ -981,15 +991,24 @@ get_ext_ver_list(ExtensionControlFile *control)
de->d_name[extnamelen + 1] != '-')
continue;
/* extract version names from 'extname--something.sql' filename */
/* extract version name(s) from 'extname--something.sql' filename */
vername = pstrdup(de->d_name + extnamelen + 2);
*strrchr(vername, '.') = '\0';
vername2 = strstr(vername, "--");
if (!vername2)
continue; /* it's not an update script */
{
/* It's an install, not update, script; record its version name */
evi = get_ext_ver_info(vername, &evi_list);
evi->installable = true;
continue;
}
*vername2 = '\0'; /* terminate first version */
vername2 += 2; /* and point to second */
/* if there's a third --, it's bogus, ignore it */
if (strstr(vername2, "--"))
continue;
/* Create ExtensionVersionInfos and link them together */
evi = get_ext_ver_info(vername, &evi_list);
evi2 = get_ext_ver_info(vername2, &evi_list);
......@@ -1015,7 +1034,6 @@ identify_update_path(ExtensionControlFile *control,
List *evi_list;
ExtensionVersionInfo *evi_start;
ExtensionVersionInfo *evi_target;
ExtensionVersionInfo *evi;
if (strcmp(oldVersion, newVersion) == 0)
ereport(ERROR,
......@@ -1029,12 +1047,57 @@ identify_update_path(ExtensionControlFile *control,
evi_start = get_ext_ver_info(oldVersion, &evi_list);
evi_target = get_ext_ver_info(newVersion, &evi_list);
/* Find shortest path */
result = find_update_path(evi_list, evi_start, evi_target, false);
if (result == NIL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
control->name, oldVersion, newVersion)));
return result;
}
/*
* Apply Dijkstra's algorithm to find the shortest path from evi_start to
* evi_target.
*
* If reinitialize is false, assume the ExtensionVersionInfo list has not
* been used for this before, and the initialization done by get_ext_ver_info
* is still good.
*
* Result is a List of names of versions to transition through (the initial
* version is *not* included). Returns NIL if no such path.
*/
static List *
find_update_path(List *evi_list,
ExtensionVersionInfo *evi_start,
ExtensionVersionInfo *evi_target,
bool reinitialize)
{
List *result;
ExtensionVersionInfo *evi;
ListCell *lc;
/* Caller error if start == target */
Assert(evi_start != evi_target);
if (reinitialize)
{
foreach(lc, evi_list)
{
evi = (ExtensionVersionInfo *) lfirst(lc);
evi->distance_known = false;
evi->distance = INT_MAX;
evi->previous = NULL;
}
}
evi_start->distance = 0;
while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
{
ListCell *lc;
if (evi->distance == INT_MAX)
break; /* all remaining vertices are unreachable */
evi->distance_known = true;
......@@ -1068,11 +1131,9 @@ identify_update_path(ExtensionControlFile *control,
}
}
/* Return NIL if target is not reachable from start */
if (!evi_target->distance_known)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
control->name, oldVersion, newVersion)));
return NIL;
/* Build and return list of version names representing the update path */
result = NIL;
......@@ -1553,9 +1614,9 @@ RemoveExtensionById(Oid extId)
}
/*
* This function lists the extensions available in the control directory
* (each of which might or might not actually be installed). We parse each
* available control file and report the interesting fields.
* This function lists the available extensions (one row per primary control
* file in the control directory). We parse each control file and report the
* interesting fields.
*
* The system view pg_available_extensions provides a user interface to this
* SRF, adding information about whether the extensions are installed in the
......@@ -1593,6 +1654,7 @@ pg_available_extensions(PG_FUNCTION_ARGS)
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
/* Build tuplestore to hold the result rows */
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
......@@ -1620,8 +1682,8 @@ pg_available_extensions(PG_FUNCTION_ARGS)
{
ExtensionControlFile *control;
char *extname;
Datum values[4];
bool nulls[4];
Datum values[3];
bool nulls[3];
if (!is_extension_control_filename(de->d_name))
continue;
......@@ -1647,18 +1709,329 @@ pg_available_extensions(PG_FUNCTION_ARGS)
nulls[1] = true;
else
values[1] = CStringGetTextDatum(control->default_version);
/* comment */
if (control->comment == NULL)
nulls[2] = true;
else
values[2] = CStringGetTextDatum(control->comment);
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
FreeDir(dir);
}
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
return (Datum) 0;
}
/*
* This function lists the available extension versions (one row per
* extension installation script). For each version, we parse the related
* control file(s) and report the interesting fields.
*
* The system view pg_available_extension_versions provides a user interface
* to this SRF, adding information about which versions are installed in the
* current DB.
*/
Datum
pg_available_extension_versions(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
Tuplestorestate *tupstore;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
char *location;
DIR *dir;
struct dirent *de;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to list available extensions"))));
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not " \
"allowed in this context")));
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
/* Build tuplestore to hold the result rows */
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
tupstore = tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
MemoryContextSwitchTo(oldcontext);
location = get_extension_control_directory();
dir = AllocateDir(location);
/*
* If the control directory doesn't exist, we want to silently return
* an empty set. Any other error will be reported by ReadDir.
*/
if (dir == NULL && errno == ENOENT)
{
/* do nothing */
}
else
{
while ((de = ReadDir(dir, location)) != NULL)
{
ExtensionControlFile *control;
char *extname;
if (!is_extension_control_filename(de->d_name))
continue;
/* extract extension name from 'name.control' filename */
extname = pstrdup(de->d_name);
*strrchr(extname, '.') = '\0';
/* ignore it if it's an auxiliary control file */
if (strstr(extname, "--"))
continue;
/* read the control file */
control = read_extension_control_file(extname);
/* scan extension's script directory for install scripts */
get_available_versions_for_extension(control, tupstore, tupdesc);
}
FreeDir(dir);
}
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
return (Datum) 0;
}
/*
* Inner loop for pg_available_extension_versions:
* read versions of one extension, add rows to tupstore
*/
static void
get_available_versions_for_extension(ExtensionControlFile *pcontrol,
Tuplestorestate *tupstore,
TupleDesc tupdesc)
{
int extnamelen = strlen(pcontrol->name);
char *location;
DIR *dir;
struct dirent *de;
location = get_extension_script_directory(pcontrol);
dir = AllocateDir(location);
/* Note this will fail if script directory doesn't exist */
while ((de = ReadDir(dir, location)) != NULL)
{
ExtensionControlFile *control;
char *vername;
Datum values[6];
bool nulls[6];
/* must be a .sql file ... */
if (!is_extension_script_filename(de->d_name))
continue;
/* ... matching extension name followed by separator */
if (strncmp(de->d_name, pcontrol->name, extnamelen) != 0 ||
de->d_name[extnamelen] != '-' ||
de->d_name[extnamelen + 1] != '-')
continue;
/* extract version name from 'extname--something.sql' filename */
vername = pstrdup(de->d_name + extnamelen + 2);
*strrchr(vername, '.') = '\0';
/* ignore it if it's an update script */
if (strstr(vername, "--"))
continue;
/*
* Fetch parameters for specific version (pcontrol is not changed)
*/
control = read_extension_aux_control_file(pcontrol, vername);
memset(values, 0, sizeof(values));
memset(nulls, 0, sizeof(nulls));
/* name */
values[0] = DirectFunctionCall1(namein,
CStringGetDatum(control->name));
/* version */
values[1] = CStringGetTextDatum(vername);
/* relocatable */
values[2] = BoolGetDatum(control->relocatable);
/* schema */
if (control->schema == NULL)
nulls[3] = true;
else
values[3] = DirectFunctionCall1(namein,
CStringGetDatum(control->schema));
/* requires */
if (control->requires == NIL)
nulls[4] = true;
else
{
Datum *datums;
int ndatums;
ArrayType *a;
ListCell *lc;
ndatums = list_length(control->requires);
datums = (Datum *) palloc(ndatums * sizeof(Datum));
ndatums = 0;
foreach(lc, control->requires)
{
char *curreq = (char *) lfirst(lc);
datums[ndatums++] =
DirectFunctionCall1(namein, CStringGetDatum(curreq));
}
a = construct_array(datums, ndatums,
NAMEOID,
NAMEDATALEN, false, 'c');
values[4] = PointerGetDatum(a);
}
/* comment */
if (control->comment == NULL)
nulls[3] = true;
nulls[5] = true;
else
values[3] = CStringGetTextDatum(control->comment);
values[5] = CStringGetTextDatum(control->comment);
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
FreeDir(dir);
}
/*
* This function reports the version update paths that exist for the
* specified extension.
*/
Datum
pg_extension_update_paths(PG_FUNCTION_ARGS)
{
Name extname = PG_GETARG_NAME(0);
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
Tuplestorestate *tupstore;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
List *evi_list;
ExtensionControlFile *control;
ListCell *lc1;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to list extension update paths"))));
/* Check extension name validity before any filesystem access */
check_valid_extension_name(NameStr(*extname));
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not " \
"allowed in this context")));
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
/* Build tuplestore to hold the result rows */
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
tupstore = tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
MemoryContextSwitchTo(oldcontext);
/* Read the extension's control file */
control = read_extension_control_file(NameStr(*extname));
/* Extract the version update graph from the script directory */
evi_list = get_ext_ver_list(control);
/* Iterate over all pairs of versions */
foreach(lc1, evi_list)
{
ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc1);
ListCell *lc2;
foreach(lc2, evi_list)
{
ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
List *path;
Datum values[3];
bool nulls[3];
if (evi1 == evi2)
continue;
/* Find shortest path from evi1 to evi2 */
path = find_update_path(evi_list, evi1, evi2, true);
/* Emit result row */
memset(values, 0, sizeof(values));
memset(nulls, 0, sizeof(nulls));
/* source */
values[0] = CStringGetTextDatum(evi1->name);
/* target */
values[1] = CStringGetTextDatum(evi2->name);
/* path */
if (path == NIL)
nulls[2] = true;
else
{
StringInfoData pathbuf;
ListCell *lcv;
initStringInfo(&pathbuf);
/* The path doesn't include start vertex, but show it */
appendStringInfoString(&pathbuf, evi1->name);
foreach(lcv, path)
{
char *versionName = (char *) lfirst(lcv);
appendStringInfoString(&pathbuf, "--");
appendStringInfoString(&pathbuf, versionName);
}
values[2] = CStringGetTextDatum(pathbuf.data);
pfree(pathbuf.data);
}
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
}
/* clean up and return the tuplestore */
......
......@@ -586,7 +586,7 @@ static const SchemaQuery Query_for_list_of_views = {
#define Query_for_list_of_available_extensions \
" SELECT pg_catalog.quote_ident(name) "\
" FROM pg_catalog.pg_available_extensions "\
" WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed IS NULL"
" WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
/*
* This is a list of all "things" in Pgsql, which can show up after CREATE or
......
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201102121
#define CATALOG_VERSION_NO 201102141
#endif
......@@ -4878,9 +4878,13 @@ DATA(insert OID = 2987 ( btrecordcmp PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23
DESCR("btree less-equal-greater");
/* Extensions */
DATA(insert OID = 3082 ( pg_available_extensions PGNSP PGUID 12 10 100 0 f f f t t s 0 0 2249 "" "{19,25,16,25}" "{o,o,o,o}" "{name,version,relocatable,comment}" _null_ pg_available_extensions _null_ _null_ _null_ ));
DATA(insert OID = 3082 ( pg_available_extensions PGNSP PGUID 12 10 100 0 f f f t t s 0 0 2249 "" "{19,25,25}" "{o,o,o}" "{name,default_version,comment}" _null_ pg_available_extensions _null_ _null_ _null_ ));
DESCR("list available extensions");
DATA(insert OID = 3083 ( pg_extension_config_dump PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "2205 25" _null_ _null_ _null_ _null_ pg_extension_config_dump _null_ _null_ _null_ ));
DATA(insert OID = 3083 ( pg_available_extension_versions PGNSP PGUID 12 10 100 0 f f f t t s 0 0 2249 "" "{19,25,16,19,1003,25}" "{o,o,o,o,o,o}" "{name,version,relocatable,schema,requires,comment}" _null_ pg_available_extension_versions _null_ _null_ _null_ ));
DESCR("list available extension versions");
DATA(insert OID = 3084 ( pg_extension_update_paths PGNSP PGUID 12 10 100 0 f f f t t s 1 0 2249 "19" "{19,25,25,25}" "{i,o,o,o}" "{name,source,target,path}" _null_ pg_extension_update_paths _null_ _null_ _null_ ));
DESCR("list an extension's version update paths");
DATA(insert OID = 3086 ( pg_extension_config_dump PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "2205 25" _null_ _null_ _null_ _null_ pg_extension_config_dump _null_ _null_ _null_ ));
DESCR("flag an extension's table contents to be emitted by pg_dump");
/* SQL-spec window functions */
......
......@@ -1067,6 +1067,8 @@ extern Datum unique_key_recheck(PG_FUNCTION_ARGS);
/* commands/extension.c */
extern Datum pg_available_extensions(PG_FUNCTION_ARGS);
extern Datum pg_available_extension_versions(PG_FUNCTION_ARGS);
extern Datum pg_extension_update_paths(PG_FUNCTION_ARGS);
extern Datum pg_extension_config_dump(PG_FUNCTION_ARGS);
/* commands/prepare.c */
......
......@@ -1277,9 +1277,10 @@ drop table cchild;
--
SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
viewname | definition
-----------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
pg_available_extensions | SELECT e.name, e.version, x.extversion AS installed, n.nspname AS schema, e.relocatable, e.comment FROM ((pg_available_extensions() e(name, version, relocatable, comment) LEFT JOIN pg_extension x ON ((e.name = x.extname))) LEFT JOIN pg_namespace n ON ((n.oid = x.extnamespace)));
pg_available_extension_versions | SELECT e.name, e.version, (x.extname IS NOT NULL) AS installed, e.relocatable, e.schema, e.requires, e.comment FROM (pg_available_extension_versions() e(name, version, relocatable, schema, requires, comment) LEFT JOIN pg_extension x ON (((e.name = x.extname) AND (e.version = x.extversion))));
pg_available_extensions | SELECT e.name, e.default_version, x.extversion AS installed_version, e.comment FROM (pg_available_extensions() e(name, default_version, comment) LEFT JOIN pg_extension x ON ((e.name = x.extname)));
pg_cursors | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
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"));
......@@ -1337,7 +1338,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
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;
(59 rows)
(60 rows)
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment