mirror of
https://github.com/postgres/postgres.git
synced 2025-06-29 10:41:53 +03:00
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.
This commit is contained in:
@ -6330,6 +6330,11 @@
|
|||||||
<entry>available extensions</entry>
|
<entry>available extensions</entry>
|
||||||
</row>
|
</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>
|
<row>
|
||||||
<entry><link linkend="view-pg-cursors"><structname>pg_cursors</structname></link></entry>
|
<entry><link linkend="view-pg-cursors"><structname>pg_cursors</structname></link></entry>
|
||||||
<entry>open cursors</entry>
|
<entry>open cursors</entry>
|
||||||
@ -6460,31 +6465,19 @@
|
|||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>version</structfield></entry>
|
<entry><structfield>default_version</structfield></entry>
|
||||||
<entry><type>text</type></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>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>installed</structfield></entry>
|
<entry><structfield>installed_version</structfield></entry>
|
||||||
<entry><type>text</type></entry>
|
<entry><type>text</type></entry>
|
||||||
<entry>Currently installed version of the extension,
|
<entry>Currently installed version of the extension,
|
||||||
or <literal>NULL</literal> if not installed</entry>
|
or <literal>NULL</literal> if not installed</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><structfield>schema</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>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry><structfield>relocatable</structfield></entry>
|
|
||||||
<entry><type>bool</type></entry>
|
|
||||||
<entry>True if extension can be relocated to another schema</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>comment</structfield></entry>
|
<entry><structfield>comment</structfield></entry>
|
||||||
<entry><type>text</type></entry>
|
<entry><type>text</type></entry>
|
||||||
@ -6497,7 +6490,88 @@
|
|||||||
<para>
|
<para>
|
||||||
The <structname>pg_available_extensions</structname> view is read only.
|
The <structname>pg_available_extensions</structname> view is read only.
|
||||||
</para>
|
</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>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>
|
||||||
|
<entry><structfield>relocatable</structfield></entry>
|
||||||
|
<entry><type>bool</type></entry>
|
||||||
|
<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>
|
||||||
|
<entry>Comment string from the extension's control file</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <structname>pg_available_extension_versions</structname> view is read
|
||||||
|
only.
|
||||||
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="view-pg-cursors">
|
<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
|
path than to move ahead one version at a time. If the downgrade script
|
||||||
drops any irreplaceable objects, this will yield undesirable results.
|
drops any irreplaceable objects, this will yield undesirable results.
|
||||||
</para>
|
</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>
|
||||||
|
|
||||||
<sect2>
|
<sect2>
|
||||||
|
@ -154,11 +154,17 @@ CREATE VIEW pg_cursors AS
|
|||||||
SELECT * FROM pg_cursor() AS C;
|
SELECT * FROM pg_cursor() AS C;
|
||||||
|
|
||||||
CREATE VIEW pg_available_extensions AS
|
CREATE VIEW pg_available_extensions AS
|
||||||
SELECT E.name, E.version, X.extversion AS installed,
|
SELECT E.name, E.default_version, X.extversion AS installed_version,
|
||||||
N.nspname AS schema, E.relocatable, E.comment
|
E.comment
|
||||||
FROM pg_available_extensions() AS E
|
FROM pg_available_extensions() AS E
|
||||||
LEFT JOIN pg_extension AS X ON E.name = X.extname
|
LEFT JOIN pg_extension AS X ON E.name = X.extname;
|
||||||
LEFT JOIN pg_namespace AS N on N.oid = X.extnamespace;
|
|
||||||
|
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
|
CREATE VIEW pg_prepared_xacts AS
|
||||||
SELECT P.transaction, P.gid, P.prepared,
|
SELECT P.transaction, P.gid, P.prepared,
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "access/sysattr.h"
|
#include "access/sysattr.h"
|
||||||
@ -80,6 +81,7 @@ typedef struct ExtensionVersionInfo
|
|||||||
{
|
{
|
||||||
char *name; /* name of the starting version */
|
char *name; /* name of the starting version */
|
||||||
List *reachable; /* List of ExtensionVersionInfo's */
|
List *reachable; /* List of ExtensionVersionInfo's */
|
||||||
|
bool installable; /* does this version have an install script? */
|
||||||
/* working state for Dijkstra's algorithm: */
|
/* working state for Dijkstra's algorithm: */
|
||||||
bool distance_known; /* is distance from start known yet? */
|
bool distance_known; /* is distance from start known yet? */
|
||||||
int distance; /* current worst-case distance estimate */
|
int distance; /* current worst-case distance estimate */
|
||||||
@ -87,6 +89,13 @@ typedef struct ExtensionVersionInfo
|
|||||||
} ExtensionVersionInfo;
|
} ExtensionVersionInfo;
|
||||||
|
|
||||||
/* Local functions */
|
/* 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,
|
static void ApplyExtensionUpdates(Oid extensionOid,
|
||||||
ExtensionControlFile *pcontrol,
|
ExtensionControlFile *pcontrol,
|
||||||
const char *initialVersion,
|
const char *initialVersion,
|
||||||
@ -909,6 +918,7 @@ get_ext_ver_info(const char *versionname, List **evi_list)
|
|||||||
evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
|
evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
|
||||||
evi->name = pstrdup(versionname);
|
evi->name = pstrdup(versionname);
|
||||||
evi->reachable = NIL;
|
evi->reachable = NIL;
|
||||||
|
evi->installable = false;
|
||||||
/* initialize for later application of Dijkstra's algorithm */
|
/* initialize for later application of Dijkstra's algorithm */
|
||||||
evi->distance_known = false;
|
evi->distance_known = false;
|
||||||
evi->distance = INT_MAX;
|
evi->distance = INT_MAX;
|
||||||
@ -981,15 +991,24 @@ get_ext_ver_list(ExtensionControlFile *control)
|
|||||||
de->d_name[extnamelen + 1] != '-')
|
de->d_name[extnamelen + 1] != '-')
|
||||||
continue;
|
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);
|
vername = pstrdup(de->d_name + extnamelen + 2);
|
||||||
*strrchr(vername, '.') = '\0';
|
*strrchr(vername, '.') = '\0';
|
||||||
vername2 = strstr(vername, "--");
|
vername2 = strstr(vername, "--");
|
||||||
if (!vername2)
|
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 = '\0'; /* terminate first version */
|
||||||
vername2 += 2; /* and point to second */
|
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 */
|
/* Create ExtensionVersionInfos and link them together */
|
||||||
evi = get_ext_ver_info(vername, &evi_list);
|
evi = get_ext_ver_info(vername, &evi_list);
|
||||||
evi2 = get_ext_ver_info(vername2, &evi_list);
|
evi2 = get_ext_ver_info(vername2, &evi_list);
|
||||||
@ -1015,7 +1034,6 @@ identify_update_path(ExtensionControlFile *control,
|
|||||||
List *evi_list;
|
List *evi_list;
|
||||||
ExtensionVersionInfo *evi_start;
|
ExtensionVersionInfo *evi_start;
|
||||||
ExtensionVersionInfo *evi_target;
|
ExtensionVersionInfo *evi_target;
|
||||||
ExtensionVersionInfo *evi;
|
|
||||||
|
|
||||||
if (strcmp(oldVersion, newVersion) == 0)
|
if (strcmp(oldVersion, newVersion) == 0)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -1029,12 +1047,57 @@ identify_update_path(ExtensionControlFile *control,
|
|||||||
evi_start = get_ext_ver_info(oldVersion, &evi_list);
|
evi_start = get_ext_ver_info(oldVersion, &evi_list);
|
||||||
evi_target = get_ext_ver_info(newVersion, &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;
|
evi_start->distance = 0;
|
||||||
|
|
||||||
while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
|
while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
|
||||||
{
|
{
|
||||||
ListCell *lc;
|
|
||||||
|
|
||||||
if (evi->distance == INT_MAX)
|
if (evi->distance == INT_MAX)
|
||||||
break; /* all remaining vertices are unreachable */
|
break; /* all remaining vertices are unreachable */
|
||||||
evi->distance_known = true;
|
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)
|
if (!evi_target->distance_known)
|
||||||
ereport(ERROR,
|
return NIL;
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
|
|
||||||
control->name, oldVersion, newVersion)));
|
|
||||||
|
|
||||||
/* Build and return list of version names representing the update path */
|
/* Build and return list of version names representing the update path */
|
||||||
result = NIL;
|
result = NIL;
|
||||||
@ -1553,9 +1614,9 @@ RemoveExtensionById(Oid extId)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function lists the extensions available in the control directory
|
* This function lists the available extensions (one row per primary control
|
||||||
* (each of which might or might not actually be installed). We parse each
|
* file in the control directory). We parse each control file and report the
|
||||||
* available control file and report the interesting fields.
|
* interesting fields.
|
||||||
*
|
*
|
||||||
* The system view pg_available_extensions provides a user interface to this
|
* The system view pg_available_extensions provides a user interface to this
|
||||||
* SRF, adding information about whether the extensions are installed in the
|
* 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)
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
||||||
elog(ERROR, "return type must be a row type");
|
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;
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
||||||
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||||
|
|
||||||
@ -1620,8 +1682,8 @@ pg_available_extensions(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
ExtensionControlFile *control;
|
ExtensionControlFile *control;
|
||||||
char *extname;
|
char *extname;
|
||||||
Datum values[4];
|
Datum values[3];
|
||||||
bool nulls[4];
|
bool nulls[3];
|
||||||
|
|
||||||
if (!is_extension_control_filename(de->d_name))
|
if (!is_extension_control_filename(de->d_name))
|
||||||
continue;
|
continue;
|
||||||
@ -1647,13 +1709,11 @@ pg_available_extensions(PG_FUNCTION_ARGS)
|
|||||||
nulls[1] = true;
|
nulls[1] = true;
|
||||||
else
|
else
|
||||||
values[1] = CStringGetTextDatum(control->default_version);
|
values[1] = CStringGetTextDatum(control->default_version);
|
||||||
/* relocatable */
|
|
||||||
values[2] = BoolGetDatum(control->relocatable);
|
|
||||||
/* comment */
|
/* comment */
|
||||||
if (control->comment == NULL)
|
if (control->comment == NULL)
|
||||||
nulls[3] = true;
|
nulls[2] = true;
|
||||||
else
|
else
|
||||||
values[3] = CStringGetTextDatum(control->comment);
|
values[2] = CStringGetTextDatum(control->comment);
|
||||||
|
|
||||||
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
||||||
}
|
}
|
||||||
@ -1667,6 +1727,319 @@ pg_available_extensions(PG_FUNCTION_ARGS)
|
|||||||
return (Datum) 0;
|
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[5] = true;
|
||||||
|
else
|
||||||
|
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 */
|
||||||
|
tuplestore_donestoring(tupstore);
|
||||||
|
|
||||||
|
return (Datum) 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pg_extension_config_dump
|
* pg_extension_config_dump
|
||||||
*
|
*
|
||||||
|
@ -586,7 +586,7 @@ static const SchemaQuery Query_for_list_of_views = {
|
|||||||
#define Query_for_list_of_available_extensions \
|
#define Query_for_list_of_available_extensions \
|
||||||
" SELECT pg_catalog.quote_ident(name) "\
|
" SELECT pg_catalog.quote_ident(name) "\
|
||||||
" FROM pg_catalog.pg_available_extensions "\
|
" 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
|
* This is a list of all "things" in Pgsql, which can show up after CREATE or
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201102121
|
#define CATALOG_VERSION_NO 201102141
|
||||||
|
|
||||||
#endif
|
#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");
|
DESCR("btree less-equal-greater");
|
||||||
|
|
||||||
/* Extensions */
|
/* 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");
|
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");
|
DESCR("flag an extension's table contents to be emitted by pg_dump");
|
||||||
|
|
||||||
/* SQL-spec window functions */
|
/* SQL-spec window functions */
|
||||||
|
@ -1067,6 +1067,8 @@ extern Datum unique_key_recheck(PG_FUNCTION_ARGS);
|
|||||||
|
|
||||||
/* commands/extension.c */
|
/* commands/extension.c */
|
||||||
extern Datum pg_available_extensions(PG_FUNCTION_ARGS);
|
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);
|
extern Datum pg_extension_config_dump(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
/* commands/prepare.c */
|
/* commands/prepare.c */
|
||||||
|
@ -1277,9 +1277,10 @@ drop table cchild;
|
|||||||
--
|
--
|
||||||
SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
|
SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
|
||||||
viewname | definition
|
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);
|
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_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_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_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))));
|
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);
|
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;
|
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
|
SELECT tablename, rulename, definition FROM pg_rules
|
||||||
ORDER BY tablename, rulename;
|
ORDER BY tablename, rulename;
|
||||||
|
Reference in New Issue
Block a user