@ -100,14 +100,25 @@ typedef struct ExtensionVersionInfo
static List * find_update_path ( List * evi_list ,
ExtensionVersionInfo * evi_start ,
ExtensionVersionInfo * evi_target ,
bool reject_indirect ,
bool reinitialize ) ;
static Oid get_required_extension ( char * reqExtensionName ,
char * extensionName ,
char * origSchemaName ,
bool cascade ,
List * parents ,
bool is_create ) ;
static void get_available_versions_for_extension ( ExtensionControlFile * pcontrol ,
Tuplestorestate * tupstore ,
TupleDesc tupdesc ) ;
static Datum convert_requires_to_datum ( List * requires ) ;
static void ApplyExtensionUpdates ( Oid extensionOid ,
ExtensionControlFile * pcontrol ,
const char * initialVersion ,
List * updateVersions ) ;
List * updateVersions ,
char * origSchemaName ,
bool cascade ,
bool is_create ) ;
static char * read_whole_file ( const char * filename , int * length ) ;
@ -1071,7 +1082,7 @@ identify_update_path(ExtensionControlFile *control,
evi_target = get_ext_ver_info ( newVersion , & evi_list ) ;
/* Find shortest path */
result = find_update_path ( evi_list , evi_start , evi_target , false ) ;
result = find_update_path ( evi_list , evi_start , evi_target , false , false ) ;
if ( result = = NIL )
ereport ( ERROR ,
@ -1086,9 +1097,13 @@ identify_update_path(ExtensionControlFile *control,
* Apply Dijkstra ' s algorithm to find the shortest path from evi_start to
* evi_target .
*
* If reject_indirect is true , ignore paths that go through installable
* versions . This saves work when the caller will consider starting from
* all installable versions anyway .
*
* 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 .
* is still good . Otherwise , reinitialize all transient fields used here .
*
* Result is a List of names of versions to transition through ( the initial
* version is * not * included ) . Returns NIL if no such path .
@ -1097,6 +1112,7 @@ static List *
find_update_path ( List * evi_list ,
ExtensionVersionInfo * evi_start ,
ExtensionVersionInfo * evi_target ,
bool reject_indirect ,
bool reinitialize )
{
List * result ;
@ -1105,6 +1121,8 @@ find_update_path(List *evi_list,
/* Caller error if start == target */
Assert ( evi_start ! = evi_target ) ;
/* Caller error if reject_indirect and target is installable */
Assert ( ! ( reject_indirect & & evi_target - > installable ) ) ;
if ( reinitialize )
{
@ -1131,6 +1149,9 @@ find_update_path(List *evi_list,
ExtensionVersionInfo * evi2 = ( ExtensionVersionInfo * ) lfirst ( lc ) ;
int newdist ;
/* if reject_indirect, treat installable versions as unreachable */
if ( reject_indirect & & evi2 - > installable )
continue ;
newdist = evi - > distance + 1 ;
if ( newdist < evi2 - > distance )
{
@ -1166,6 +1187,67 @@ find_update_path(List *evi_list,
return result ;
}
/*
* Given a target version that is not directly installable , find the
* best installation sequence starting from a directly - installable version .
*
* evi_list : previously - collected version update graph
* evi_target : member of that list that we want to reach
*
* Returns the best starting - point version , or NULL if there is none .
* On success , * best_path is set to the path from the start point .
*
* If there ' s more than one possible start point , prefer shorter update paths ,
* and break any ties arbitrarily on the basis of strcmp ' ing the starting
* versions ' names .
*/
static ExtensionVersionInfo *
find_install_path ( List * evi_list , ExtensionVersionInfo * evi_target ,
List * * best_path )
{
ExtensionVersionInfo * evi_start = NULL ;
ListCell * lc ;
* best_path = NIL ;
/*
* We don ' t expect to be called for an installable target , but if we are ,
* the answer is easy : just start from there , with an empty update path .
*/
if ( evi_target - > installable )
return evi_target ;
/* Consider all installable versions as start points */
foreach ( lc , evi_list )
{
ExtensionVersionInfo * evi1 = ( ExtensionVersionInfo * ) lfirst ( lc ) ;
List * path ;
if ( ! evi1 - > installable )
continue ;
/*
* Find shortest path from evi1 to evi_target ; but no need to consider
* paths going through other installable versions .
*/
path = find_update_path ( evi_list , evi1 , evi_target , true , true ) ;
if ( path = = NIL )
continue ;
/* Remember best path */
if ( evi_start = = NULL | |
list_length ( path ) < list_length ( * best_path ) | |
( list_length ( path ) = = list_length ( * best_path ) & &
strcmp ( evi_start - > name , evi1 - > name ) < 0 ) )
{
evi_start = evi1 ;
* best_path = path ;
}
}
return evi_start ;
}
/*
* CREATE EXTENSION worker
*
@ -1175,17 +1257,16 @@ find_update_path(List *evi_list,
* installed , allowing us to error out if we recurse to one of those .
*/
static ObjectAddress
CreateExtensionInternal ( ParseState * pstate , CreateExtensionStmt * stmt , List * parents )
CreateExtensionInternal ( char * extensionName ,
char * schemaName ,
char * versionName ,
char * oldVersionName ,
bool cascade ,
List * parents ,
bool is_create )
{
DefElem * d_schema = NULL ;
DefElem * d_new_version = NULL ;
DefElem * d_old_version = NULL ;
DefElem * d_cascade = NULL ;
char * schemaName = NULL ;
char * origSchemaName = schemaName ;
Oid schemaOid = InvalidOid ;
char * versionName ;
char * oldVersionName ;
bool cascade = false ;
Oid extowner = GetUserId ( ) ;
ExtensionControlFile * pcontrol ;
ExtensionControlFile * control ;
@ -1193,87 +1274,43 @@ CreateExtensionInternal(ParseState *pstate, CreateExtensionStmt *stmt, List *par
List * requiredExtensions ;
List * requiredSchemas ;
Oid extensionOid ;
ListCell * lc ;
ObjectAddress address ;
ListCell * lc ;
/*
* Read the primary control file . Note we assume that it does not contain
* any non - ASCII data , so there is no need to worry about encoding at this
* point .
*/
pcontrol = read_extension_control_file ( stmt - > extname ) ;
/*
* Read the statement option list
*/
foreach ( lc , stmt - > options )
{
DefElem * defel = ( DefElem * ) lfirst ( lc ) ;
if ( strcmp ( defel - > defname , " schema " ) = = 0 )
{
if ( d_schema )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " conflicting or redundant options " ) ,
parser_errposition ( pstate , defel - > location ) ) ) ;
d_schema = defel ;
}
else if ( strcmp ( defel - > defname , " new_version " ) = = 0 )
{
if ( d_new_version )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " conflicting or redundant options " ) ,
parser_errposition ( pstate , defel - > location ) ) ) ;
d_new_version = defel ;
}
else if ( strcmp ( defel - > defname , " old_version " ) = = 0 )
{
if ( d_old_version )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " conflicting or redundant options " ) ,
parser_errposition ( pstate , defel - > location ) ) ) ;
d_old_version = defel ;
}
else if ( strcmp ( defel - > defname , " cascade " ) = = 0 )
{
if ( d_cascade )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " conflicting or redundant options " ) ,
parser_errposition ( pstate , defel - > location ) ) ) ;
d_cascade = defel ;
cascade = defGetBoolean ( d_cascade ) ;
}
else
elog ( ERROR , " unrecognized option: %s " , defel - > defname ) ;
}
pcontrol = read_extension_control_file ( extensionName ) ;
/*
* Determine the version to install
*/
if ( d_new_version & & d_new_version - > arg )
versionName = strVal ( d_new_version - > arg ) ;
else if ( pcontrol - > default_version )
versionName = pcontrol - > default_version ;
else
if ( versionName = = NULL )
{
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " version to install must be specified " ) ) ) ;
versionName = NULL ; /* keep compiler quiet */
if ( pcontrol - > default_version )
versionName = pcontrol - > default_version ;
else
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " version to install must be specified " ) ) ) ;
}
check_valid_version_name ( versionName ) ;
/*
* Determine the ( unpackaged ) version to update from , if any , and then
* figure out what sequence of update scripts we need to apply .
* Figure out which script ( s ) we need to run to install the desired
* version of the extension . If we do not have a script that directly
* does what is needed , we try to find a sequence of update scripts that
* will get us there .
*/
if ( d_old_version & & d_old_version - > arg )
if ( oldVersionName )
{
oldVersionName = strVal ( d_old_version - > arg ) ;
/*
* " FROM old_version " was specified , indicating that we ' re trying to
* update from some unpackaged version of the extension . Locate a
* series of update scripts that will do it .
*/
check_valid_version_name ( oldVersionName ) ;
if ( strcmp ( oldVersionName , versionName ) = = 0 )
@ -1308,8 +1345,48 @@ CreateExtensionInternal(ParseState *pstate, CreateExtensionStmt *stmt, List *par
}
else
{
/*
* No FROM , so we ' re installing from scratch . If there is an install
* script for the desired version , we only need to run that one .
*/
char * filename ;
struct stat fst ;
oldVersionName = NULL ;
updateVersions = NIL ;
filename = get_extension_script_filename ( pcontrol , NULL , versionName ) ;
if ( stat ( filename , & fst ) = = 0 )
{
/* Easy, no extra scripts */
updateVersions = NIL ;
}
else
{
/* Look for best way to install this version */
List * evi_list ;
ExtensionVersionInfo * evi_start ;
ExtensionVersionInfo * evi_target ;
/* Extract the version update graph from the script directory */
evi_list = get_ext_ver_list ( pcontrol ) ;
/* Identify the target version */
evi_target = get_ext_ver_info ( versionName , & evi_list ) ;
/* Identify best path to reach target */
evi_start = find_install_path ( evi_list , evi_target ,
& updateVersions ) ;
/* Fail if no path ... */
if ( evi_start = = NULL )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " extension \" %s \" has no installation script nor update path for version \" %s \" " ,
pcontrol - > name , versionName ) ) ) ;
/* Otherwise, install best starting point and then upgrade */
versionName = evi_start - > name ;
}
}
/*
@ -1320,13 +1397,8 @@ CreateExtensionInternal(ParseState *pstate, CreateExtensionStmt *stmt, List *par
/*
* Determine the target schema to install the extension into
*/
if ( d_schema & & d_schema - > arg )
if ( schemaName )
{
/*
* User given schema , CREATE EXTENSION . . . WITH SCHEMA . . .
*/
schemaName = strVal ( d_schema - > arg ) ;
/* If the user is giving us the schema name, it must exist already. */
schemaOid = get_namespace_oid ( schemaName , false ) ;
}
@ -1374,7 +1446,7 @@ CreateExtensionInternal(ParseState *pstate, CreateExtensionStmt *stmt, List *par
else if ( ! OidIsValid ( schemaOid ) )
{
/*
* Neither user nor author of the extension specified schema , use the
* Neither user nor author of the extension specified schema ; use the
* current default creation namespace , which is the first explicit
* entry in the search_path .
*/
@ -1415,66 +1487,12 @@ CreateExtensionInternal(ParseState *pstate, CreateExtensionStmt *stmt, List *par
Oid reqext ;
Oid reqschema ;
reqext = get_extension_oid ( curreq , true ) ;
if ( ! OidIsValid ( reqext ) )
{
if ( cascade )
{
/* Must install it. */
CreateExtensionStmt * ces ;
ListCell * lc2 ;
ObjectAddress addr ;
List * cascade_parents ;
/* Check extension name validity before trying to cascade. */
check_valid_extension_name ( curreq ) ;
/* Check for cyclic dependency between extensions. */
foreach ( lc2 , parents )
{
char * pname = ( char * ) lfirst ( lc2 ) ;
if ( strcmp ( pname , curreq ) = = 0 )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_RECURSION ) ,
errmsg ( " cyclic dependency detected between extensions \" %s \" and \" %s \" " ,
curreq , stmt - > extname ) ) ) ;
}
ereport ( NOTICE ,
( errmsg ( " installing required extension \" %s \" " ,
curreq ) ) ) ;
/* Build a CREATE EXTENSION statement to pass down. */
ces = makeNode ( CreateExtensionStmt ) ;
ces - > extname = curreq ;
ces - > if_not_exists = false ;
/* Propagate the CASCADE option. */
ces - > options = list_make1 ( d_cascade ) ;
/* Propagate the SCHEMA option if given. */
if ( d_schema & & d_schema - > arg )
ces - > options = lappend ( ces - > options , d_schema ) ;
/* Add current extension to list of parents to pass down. */
cascade_parents =
lappend ( list_copy ( parents ) , stmt - > extname ) ;
/* Create the required extension. */
addr = CreateExtensionInternal ( pstate , ces , cascade_parents ) ;
/* Get its newly-assigned OID. */
reqext = addr . objectId ;
}
else
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " required extension \" %s \" is not installed " ,
curreq ) ,
errhint ( " Use CREATE EXTENSION ... CASCADE to install required extensions too. " ) ) ) ;
}
reqext = get_required_extension ( curreq ,
extensionName ,
origSchemaName ,
cascade ,
parents ,
is_create ) ;
reqschema = get_extension_schema ( reqext ) ;
requiredExtensions = lappend_oid ( requiredExtensions , reqext ) ;
requiredSchemas = lappend_oid ( requiredSchemas , reqschema ) ;
@ -1510,17 +1528,100 @@ CreateExtensionInternal(ParseState *pstate, CreateExtensionStmt *stmt, List *par
* though a series of ALTER EXTENSION UPDATE commands were given
*/
ApplyExtensionUpdates ( extensionOid , pcontrol ,
versionName , updateVersions ) ;
versionName , updateVersions ,
origSchemaName , cascade , is_create ) ;
return address ;
}
/*
* Get the OID of an extension listed in " requires " , possibly creating it .
*/
static Oid
get_required_extension ( char * reqExtensionName ,
char * extensionName ,
char * origSchemaName ,
bool cascade ,
List * parents ,
bool is_create )
{
Oid reqExtensionOid ;
reqExtensionOid = get_extension_oid ( reqExtensionName , true ) ;
if ( ! OidIsValid ( reqExtensionOid ) )
{
if ( cascade )
{
/* Must install it. */
ObjectAddress addr ;
List * cascade_parents ;
ListCell * lc ;
/* Check extension name validity before trying to cascade. */
check_valid_extension_name ( reqExtensionName ) ;
/* Check for cyclic dependency between extensions. */
foreach ( lc , parents )
{
char * pname = ( char * ) lfirst ( lc ) ;
if ( strcmp ( pname , reqExtensionName ) = = 0 )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_RECURSION ) ,
errmsg ( " cyclic dependency detected between extensions \" %s \" and \" %s \" " ,
reqExtensionName , extensionName ) ) ) ;
}
ereport ( NOTICE ,
( errmsg ( " installing required extension \" %s \" " ,
reqExtensionName ) ) ) ;
/* Add current extension to list of parents to pass down. */
cascade_parents = lappend ( list_copy ( parents ) , extensionName ) ;
/*
* Create the required extension . We propagate the SCHEMA option
* if any , and CASCADE , but no other options .
*/
addr = CreateExtensionInternal ( reqExtensionName ,
origSchemaName ,
NULL ,
NULL ,
cascade ,
cascade_parents ,
is_create ) ;
/* Get its newly-assigned OID. */
reqExtensionOid = addr . objectId ;
}
else
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " required extension \" %s \" is not installed " ,
reqExtensionName ) ,
is_create ?
errhint ( " Use CREATE EXTENSION ... CASCADE to install required extensions too. " ) : 0 ) ) ;
}
return reqExtensionOid ;
}
/*
* CREATE EXTENSION
*/
ObjectAddress
CreateExtension ( ParseState * pstate , CreateExtensionStmt * stmt )
{
DefElem * d_schema = NULL ;
DefElem * d_new_version = NULL ;
DefElem * d_old_version = NULL ;
DefElem * d_cascade = NULL ;
char * schemaName = NULL ;
char * versionName = NULL ;
char * oldVersionName = NULL ;
bool cascade = false ;
ListCell * lc ;
/* Check extension name validity before any filesystem access */
check_valid_extension_name ( stmt - > extname ) ;
@ -1556,8 +1657,63 @@ CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " nested CREATE EXTENSION is not supported " ) ) ) ;
/* Finally create the extension. */
return CreateExtensionInternal ( pstate , stmt , NIL ) ;
/* Deconstruct the statement option list */
foreach ( lc , stmt - > options )
{
DefElem * defel = ( DefElem * ) lfirst ( lc ) ;
if ( strcmp ( defel - > defname , " schema " ) = = 0 )
{
if ( d_schema )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " conflicting or redundant options " ) ,
parser_errposition ( pstate , defel - > location ) ) ) ;
d_schema = defel ;
schemaName = defGetString ( d_schema ) ;
}
else if ( strcmp ( defel - > defname , " new_version " ) = = 0 )
{
if ( d_new_version )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " conflicting or redundant options " ) ,
parser_errposition ( pstate , defel - > location ) ) ) ;
d_new_version = defel ;
versionName = defGetString ( d_new_version ) ;
}
else if ( strcmp ( defel - > defname , " old_version " ) = = 0 )
{
if ( d_old_version )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " conflicting or redundant options " ) ,
parser_errposition ( pstate , defel - > location ) ) ) ;
d_old_version = defel ;
oldVersionName = defGetString ( d_old_version ) ;
}
else if ( strcmp ( defel - > defname , " cascade " ) = = 0 )
{
if ( d_cascade )
ereport ( ERROR ,
( errcode ( ERRCODE_SYNTAX_ERROR ) ,
errmsg ( " conflicting or redundant options " ) ,
parser_errposition ( pstate , defel - > location ) ) ) ;
d_cascade = defel ;
cascade = defGetBoolean ( d_cascade ) ;
}
else
elog ( ERROR , " unrecognized option: %s " , defel - > defname ) ;
}
/* Call CreateExtensionInternal to do the real work. */
return CreateExtensionInternal ( stmt - > extname ,
schemaName ,
versionName ,
oldVersionName ,
cascade ,
NIL ,
true ) ;
}
/*
@ -1914,43 +2070,28 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol,
Tuplestorestate * tupstore ,
TupleDesc tupdesc )
{
int extnamelen = strlen ( pcontrol - > name ) ;
char * location ;
DIR * dir ;
struct dirent * de ;
List * evi_list ;
ListCell * lc ;
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 )
/* Extract the version update graph from the script directory */
evi_list = get_ext_ver_list ( pcontrol ) ;
/* For each installable version ... */
foreach ( lc , evi_list )
{
ExtensionVersionInfo * evi = ( ExtensionVersionInfo * ) lfirst ( lc ) ;
ExtensionControlFile * control ;
char * vername ;
Datum values [ 7 ] ;
bool nulls [ 7 ] ;
ListCell * lc2 ;
/* 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 , " -- " ) )
if ( ! evi - > installable )
continue ;
/*
* Fetch parameters for specific version ( pcontrol is not changed )
*/
control = read_extension_aux_control_file ( pcontrol , ver name) ;
control = read_extension_aux_control_file ( pcontrol , evi - > name ) ;
memset ( values , 0 , sizeof ( values ) ) ;
memset ( nulls , 0 , sizeof ( nulls ) ) ;
@ -1959,7 +2100,7 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol,
values [ 0 ] = DirectFunctionCall1 ( namein ,
CStringGetDatum ( control - > name ) ) ;
/* version */
values [ 1 ] = CStringGetTextDatum ( ver name) ;
values [ 1 ] = CStringGetTextDatum ( evi - > name ) ;
/* superuser */
values [ 2 ] = BoolGetDatum ( control - > superuser ) ;
/* relocatable */
@ -1974,27 +2115,7 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol,
if ( control - > requires = = NIL )
nulls [ 5 ] = 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 [ 5 ] = PointerGetDatum ( a ) ;
}
values [ 5 ] = convert_requires_to_datum ( control - > requires ) ;
/* comment */
if ( control - > comment = = NULL )
nulls [ 6 ] = true ;
@ -2002,9 +2123,75 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol,
values [ 6 ] = CStringGetTextDatum ( control - > comment ) ;
tuplestore_putvalues ( tupstore , tupdesc , values , nulls ) ;
/*
* Find all non - directly - installable versions that would be installed
* starting from this version , and report them , inheriting the
* parameters that aren ' t changed in updates from this version .
*/
foreach ( lc2 , evi_list )
{
ExtensionVersionInfo * evi2 = ( ExtensionVersionInfo * ) lfirst ( lc2 ) ;
List * best_path ;
if ( evi2 - > installable )
continue ;
if ( find_install_path ( evi_list , evi2 , & best_path ) = = evi )
{
/*
* Fetch parameters for this version ( pcontrol is not changed )
*/
control = read_extension_aux_control_file ( pcontrol , evi2 - > name ) ;
/* name stays the same */
/* version */
values [ 1 ] = CStringGetTextDatum ( evi2 - > name ) ;
/* superuser */
values [ 2 ] = BoolGetDatum ( control - > superuser ) ;
/* relocatable */
values [ 3 ] = BoolGetDatum ( control - > relocatable ) ;
/* schema stays the same */
/* requires */
if ( control - > requires = = NIL )
nulls [ 5 ] = true ;
else
{
values [ 5 ] = convert_requires_to_datum ( control - > requires ) ;
nulls [ 5 ] = false ;
}
/* comment stays the same */
tuplestore_putvalues ( tupstore , tupdesc , values , nulls ) ;
}
}
}
}
FreeDir ( dir ) ;
/*
* Convert a list of extension names to a name [ ] Datum
*/
static Datum
convert_requires_to_datum ( List * requires )
{
Datum * datums ;
int ndatums ;
ArrayType * a ;
ListCell * lc ;
ndatums = list_length ( requires ) ;
datums = ( Datum * ) palloc ( ndatums * sizeof ( Datum ) ) ;
ndatums = 0 ;
foreach ( lc , requires )
{
char * curreq = ( char * ) lfirst ( lc ) ;
datums [ ndatums + + ] =
DirectFunctionCall1 ( namein , CStringGetDatum ( curreq ) ) ;
}
a = construct_array ( datums , ndatums ,
NAMEOID ,
NAMEDATALEN , false , ' c ' ) ;
return PointerGetDatum ( a ) ;
}
/*
@ -2076,7 +2263,7 @@ pg_extension_update_paths(PG_FUNCTION_ARGS)
continue ;
/* Find shortest path from evi1 to evi2 */
path = find_update_path ( evi_list , evi1 , evi2 , true ) ;
path = find_update_path ( evi_list , evi1 , evi2 , false , true ) ;
/* Emit result row */
memset ( values , 0 , sizeof ( values ) ) ;
@ -2808,7 +2995,8 @@ ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt)
* time
*/
ApplyExtensionUpdates ( extensionOid , control ,
oldVersionName , updateVersions ) ;
oldVersionName , updateVersions ,
NULL , false , false ) ;
ObjectAddressSet ( address , ExtensionRelationId , extensionOid ) ;
@ -2827,7 +3015,10 @@ static void
ApplyExtensionUpdates ( Oid extensionOid ,
ExtensionControlFile * pcontrol ,
const char * initialVersion ,
List * updateVersions )
List * updateVersions ,
char * origSchemaName ,
bool cascade ,
bool is_create )
{
const char * oldVersionName = initialVersion ;
ListCell * lcv ;
@ -2906,8 +3097,9 @@ ApplyExtensionUpdates(Oid extensionOid,
heap_close ( extRel , RowExclusiveLock ) ;
/*
* Look up the prerequisite extensions for this version , and build
* lists of their OIDs and the OIDs of their target schemas .
* Look up the prerequisite extensions for this version , install them
* if necessary , and build lists of their OIDs and the OIDs of their
* target schemas .
*/
requiredExtensions = NIL ;
requiredSchemas = NIL ;
@ -2917,16 +3109,12 @@ ApplyExtensionUpdates(Oid extensionOid,
Oid reqext ;
Oid reqschema ;
/*
* We intentionally don ' t use get_extension_oid ' s default error
* message here , because it would be confusing in this context .
*/
reqext = get_extension_oid ( curreq , true ) ;
if ( ! OidIsValid ( reqext ) )
ereport ( ERROR ,
( errcode ( ERRCODE_UNDEFINED_OBJECT ) ,
errmsg ( " required extension \" %s \" is not installed " ,
curreq ) ) ) ;
reqext = get_required_extension ( curreq ,
control - > name ,
origSchemaName ,
cascade ,
NIL ,
is_create ) ;
reqschema = get_extension_schema ( reqext ) ;
requiredExtensions = lappend_oid ( requiredExtensions , reqext ) ;
requiredSchemas = lappend_oid ( requiredSchemas , reqschema ) ;