Skip to content

Commit 6f68f31

Browse files
authored
Record dependency of default version sql func on the extension (#246)
1 parent 6bad5a6 commit 6f68f31

File tree

2 files changed

+197
-80
lines changed

2 files changed

+197
-80
lines changed

src/tleextension.c

Lines changed: 128 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,6 +1853,104 @@ find_install_path(List *evi_list, ExtensionVersionInfo *evi_target,
18531853
return evi_start;
18541854
}
18551855

1856+
/*
1857+
* Figures out which script(s) we need to run to install the desired
1858+
* version of the extension. If we do not have a script that directly
1859+
* does what is needed, we try to find a sequence of update scripts that
1860+
* will get us there.
1861+
*/
1862+
static List *
1863+
find_versions_to_apply(ExtensionControlFile *pcontrol, const char **versionName)
1864+
{
1865+
char *filename;
1866+
struct stat fst;
1867+
List *updateVersions;
1868+
List *evi_list;
1869+
ExtensionVersionInfo *evi_start;
1870+
ExtensionVersionInfo *evi_target;
1871+
1872+
filename = get_extension_script_filename(pcontrol, NULL, *versionName);
1873+
if (!tleext && stat(filename, &fst) == 0)
1874+
updateVersions = NIL; /* Easy, no extra scripts */
1875+
else if (tleext && funcstat(filename))
1876+
updateVersions = NIL; /* Also easy, no extra scripts */
1877+
else
1878+
{
1879+
/*
1880+
* Look for best way to install this version
1881+
*
1882+
* Extract the version update graph from the script directory
1883+
*/
1884+
evi_list = get_ext_ver_list(pcontrol);
1885+
1886+
/* Identify the target version */
1887+
evi_target = get_ext_ver_info(*versionName, &evi_list);
1888+
1889+
/* Identify best path to reach target */
1890+
evi_start = find_install_path(evi_list, evi_target,
1891+
&updateVersions);
1892+
1893+
/* Fail if no path ... */
1894+
if (evi_start == NULL)
1895+
ereport(ERROR,
1896+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1897+
errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
1898+
pcontrol->name, *versionName)));
1899+
1900+
/* Otherwise, install best starting point and then upgrade */
1901+
*versionName = evi_start->name;
1902+
}
1903+
1904+
return updateVersions;
1905+
}
1906+
1907+
static void
1908+
record_sql_function_dependencies(char *extensionName,
1909+
const char *versionName,
1910+
List *updateVersions,
1911+
ObjectAddress address)
1912+
{
1913+
char *sqlname;
1914+
Oid sqlfuncid;
1915+
ObjectAddress sqlfunc;
1916+
1917+
sqlname = psprintf("%s--%s.sql", extensionName, versionName);
1918+
sqlfuncid = get_tlefunc_oid_if_exists(sqlname);
1919+
1920+
/* If it exists, record dependencies on sql function for base version */
1921+
if (sqlfuncid != InvalidOid)
1922+
{
1923+
sqlfunc.classId = ProcedureRelationId;
1924+
sqlfunc.objectId = sqlfuncid;
1925+
sqlfunc.objectSubId = 0;
1926+
recordDependencyOn(&address, &sqlfunc, DEPENDENCY_NORMAL);
1927+
}
1928+
1929+
/*
1930+
* If necessary update scripts are found, record dependency on each script
1931+
*/
1932+
if (updateVersions != NULL)
1933+
{
1934+
const char *oldVersionName = versionName;
1935+
ListCell *lcv;
1936+
1937+
foreach(lcv, updateVersions)
1938+
{
1939+
ObjectAddress upgradesqlfunc;
1940+
1941+
versionName = (char *) lfirst(lcv);
1942+
sqlname = psprintf("%s--%s--%s.sql", extensionName, oldVersionName, versionName);
1943+
sqlfuncid = get_tlefunc_oid_if_exists(sqlname);
1944+
1945+
upgradesqlfunc.classId = ProcedureRelationId;
1946+
upgradesqlfunc.objectId = sqlfuncid;
1947+
upgradesqlfunc.objectSubId = 0;
1948+
1949+
recordDependencyOn(&address, &upgradesqlfunc, DEPENDENCY_NORMAL);
1950+
}
1951+
}
1952+
}
1953+
18561954
/*
18571955
* CREATE EXTENSION worker
18581956
*
@@ -1875,7 +1973,6 @@ CreateExtensionInternal(char *extensionName,
18751973
ExtensionControlFile *pcontrol;
18761974
ExtensionControlFile *control;
18771975
char *filename;
1878-
struct stat fst;
18791976
List *updateVersions;
18801977
List *requiredExtensions;
18811978
List *requiredSchemas;
@@ -1885,13 +1982,7 @@ CreateExtensionInternal(char *extensionName,
18851982
bool prevTLEState;
18861983
char *ctlname;
18871984
Oid ctlfuncid;
1888-
char *sqlname;
1889-
Oid sqlfuncid;
1890-
List *evi_list;
1891-
ExtensionVersionInfo *evi_start;
1892-
ExtensionVersionInfo *evi_target;
18931985
ObjectAddress ctlfunc;
1894-
ObjectAddress sqlfunc;
18951986

18961987
/*
18971988
* We have to do some state checking here if we are cascading through a
@@ -1926,43 +2017,7 @@ CreateExtensionInternal(char *extensionName,
19262017
}
19272018
check_valid_version_name(versionName);
19282019

1929-
/*
1930-
* Figure out which script(s) we need to run to install the desired
1931-
* version of the extension. If we do not have a script that directly
1932-
* does what is needed, we try to find a sequence of update scripts that
1933-
* will get us there.
1934-
*/
1935-
filename = get_extension_script_filename(pcontrol, NULL, versionName);
1936-
if (!tleext && stat(filename, &fst) == 0)
1937-
updateVersions = NIL; /* Easy, no extra scripts */
1938-
else if (tleext && funcstat(filename))
1939-
updateVersions = NIL; /* Also easy, no extra scripts */
1940-
else
1941-
{
1942-
/*
1943-
* Look for best way to install this version
1944-
*
1945-
* Extract the version update graph from the script directory
1946-
*/
1947-
evi_list = get_ext_ver_list(pcontrol);
1948-
1949-
/* Identify the target version */
1950-
evi_target = get_ext_ver_info(versionName, &evi_list);
1951-
1952-
/* Identify best path to reach target */
1953-
evi_start = find_install_path(evi_list, evi_target,
1954-
&updateVersions);
1955-
1956-
/* Fail if no path ... */
1957-
if (evi_start == NULL)
1958-
ereport(ERROR,
1959-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1960-
errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
1961-
pcontrol->name, versionName)));
1962-
1963-
/* Otherwise, install best starting point and then upgrade */
1964-
versionName = evi_start->name;
1965-
}
2020+
updateVersions = find_versions_to_apply(pcontrol, &versionName);
19662021

19672022
/*
19682023
* Fetch control parameters for installation target version
@@ -2122,47 +2177,24 @@ CreateExtensionInternal(char *extensionName,
21222177
if (ctlfuncid == InvalidOid)
21232178
elog(ERROR, "could not find control function %s for extension %s in schema %s", quote_identifier(ctlname), quote_identifier(extensionName), quote_identifier(PG_TLE_NSPNAME));
21242179

2125-
sqlname = psprintf("%s--%s.sql", extensionName, versionName);
2126-
sqlfuncid = get_tlefunc_oid_if_exists(sqlname);
2127-
21282180
/* Record dependencies on control function */
21292181
ctlfunc.classId = ProcedureRelationId;
21302182
ctlfunc.objectId = ctlfuncid;
21312183
ctlfunc.objectSubId = 0;
21322184
recordDependencyOn(&address, &ctlfunc, DEPENDENCY_NORMAL);
21332185

2134-
/* If it exists, record dependencies on sql function for base version */
2135-
if (sqlfuncid != InvalidOid)
2136-
{
2137-
sqlfunc.classId = ProcedureRelationId;
2138-
sqlfunc.objectId = sqlfuncid;
2139-
sqlfunc.objectSubId = 0;
2140-
recordDependencyOn(&address, &sqlfunc, DEPENDENCY_NORMAL);
2141-
}
2186+
record_sql_function_dependencies(extensionName, versionName, updateVersions, address);
21422187

21432188
/*
2144-
* If necessary update scripts are found, record dependency on each
2145-
* script
2189+
* Record dependencies such that default version can be installed
2190+
* after a pg_dump
21462191
*/
2147-
if (updateVersions != NULL)
2192+
if (pcontrol->default_version)
21482193
{
2149-
const char *oldVersionName = versionName;
2150-
ListCell *lcv;
2151-
2152-
foreach(lcv, updateVersions)
2153-
{
2154-
ObjectAddress upgradesqlfunc;
2155-
2156-
versionName = (char *) lfirst(lcv);
2157-
sqlname = psprintf("%s--%s--%s.sql", extensionName, oldVersionName, versionName);
2158-
sqlfuncid = get_tlefunc_oid_if_exists(sqlname);
2194+
const char *defaultVersion = pcontrol->default_version;
21592195

2160-
upgradesqlfunc.classId = ProcedureRelationId;
2161-
upgradesqlfunc.objectId = sqlfuncid;
2162-
upgradesqlfunc.objectSubId = 0;
2163-
2164-
recordDependencyOn(&address, &upgradesqlfunc, DEPENDENCY_NORMAL);
2165-
}
2196+
updateVersions = find_versions_to_apply(pcontrol, &defaultVersion);
2197+
record_sql_function_dependencies(extensionName, defaultVersion, updateVersions, address);
21662198
}
21672199
}
21682200

@@ -4876,6 +4908,9 @@ pg_tle_set_default_version(PG_FUNCTION_ARGS)
48764908
char *ctlsql;
48774909
ExtensionControlFile *control;
48784910
char *filename;
4911+
List *updateVersions;
4912+
Oid extensionOid;
4913+
ObjectAddress extAddress;
48794914

48804915
if (PG_ARGISNULL(0))
48814916
ereport(ERROR,
@@ -4974,6 +5009,25 @@ pg_tle_set_default_version(PG_FUNCTION_ARGS)
49745009
if (SPI_finish() != SPI_OK_FINISH)
49755010
elog(ERROR, "SPI_finish failed");
49765011

5012+
/*
5013+
* When default version is updated we update the dependencies so that
5014+
* pg_dump can maintain the correct order.
5015+
*/
5016+
extensionOid = get_extension_oid(extname, true);
5017+
if (extensionOid != InvalidOid)
5018+
{
5019+
const char *defaultVersion = control->default_version;
5020+
5021+
extAddress.classId = ExtensionRelationId;
5022+
extAddress.objectId = extensionOid;
5023+
extAddress.objectSubId = 0;
5024+
5025+
SET_TLEEXT;
5026+
updateVersions = find_versions_to_apply(control, &defaultVersion);
5027+
UNSET_TLEEXT;
5028+
record_sql_function_dependencies(extname, defaultVersion, updateVersions, extAddress);
5029+
}
5030+
49775031
/* flag that we are done manipulating pg_tle artifacts */
49785032
UNSET_TLEART;
49795033

test/t/002_pg_tle_dump_restore.pl

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
# 1. Install and create a regular TLE
1818
# 2. Install and create a TLE with an indirect version upgrade path
1919
# 3. Install and create a TLE that depends on another TLE with an indirect version
20-
# 4. Create a custom data type
21-
# 5. Create a custom operator
20+
# 4. Install two versions of a TLE and create the non-default version
21+
# 5. Create a custom data type
22+
# 6. Create a custom operator
2223

2324
use strict;
2425
use warnings;
@@ -208,7 +209,56 @@
208209
$node->psql($testdb, 'SELECT test_cascade_dependency_func_2()', stdout => \$stdout, stderr => \$stderr);
209210
like ($stdout, qr/-1/, 'select_tle_function');
210211

211-
# 4. Create a custom data type
212+
# 4. Install two versions of a TLE and create the non-default version
213+
214+
$node->psql(
215+
$testdb, qq[
216+
SELECT pgtle.install_extension
217+
(
218+
'test_non_default_version',
219+
'1.0',
220+
'Test TLE Functions',
221+
\$_pgtle_\$
222+
CREATE OR REPLACE FUNCTION test_non_default_version()
223+
RETURNS INT AS \$\$
224+
(
225+
SELECT 1
226+
)\$\$ LANGUAGE sql;
227+
\$_pgtle_\$
228+
);
229+
], stdout => \$stdout, stderr => \$stderr);
230+
like ($stderr, qr//, 'install_tle');
231+
232+
$node->psql(
233+
$testdb, qq[
234+
SELECT pgtle.install_extension_version_sql
235+
(
236+
'test_non_default_version',
237+
'1.1',
238+
\$_pgtle_\$
239+
CREATE OR REPLACE FUNCTION test_non_default_version()
240+
RETURNS INT AS \$\$
241+
(
242+
SELECT 2
243+
)\$\$ LANGUAGE sql;
244+
\$_pgtle_\$
245+
);
246+
], stdout => \$stdout, stderr => \$stderr);
247+
like ($stderr, qr//, 'install_tle_update_path');
248+
249+
$node->psql(
250+
$testdb, qq[
251+
SELECT default_version FROM pgtle.available_extensions() WHERE name = 'test_non_default_version';
252+
], stdout => \$stdout, stderr => \$stderr);
253+
like ($stdout, qr/1.0/, 'verify default version');
254+
255+
$node->psql($testdb, "CREATE EXTENSION test_non_default_version VERSION '1.1'", stdout => \$stdout, stderr => \$stderr);
256+
like ($stderr, qr//, 'create_tle');
257+
$node->psql($testdb, 'SELECT test_non_default_version()', stdout => \$stdout, stderr => \$stderr);
258+
like ($stdout, qr/2/, 'select_tle_function');
259+
260+
261+
# 5. Create a custom data type
212262

213263
$node->psql($testdb, 'SELECT pgtle.create_shell_type(\'public\', \'test_citext\')', stdout => \$stdout, stderr => \$stderr);
214264
like ($stderr, qr//, 'create_shell_type');
@@ -239,7 +289,7 @@
239289
$node->psql($testdb, 'SELECT * FROM test_dt;', stdout => \$stdout, stderr => \$stderr);
240290
like ($stdout, qr/TEST/, 'select_custom_data_type');
241291

242-
# 5. Create a custom data operator
292+
# 6. Create a custom data operator
243293

244294
$node->psql($testdb, qq[CREATE FUNCTION public.test_citext_cmp(l bytea, r bytea) RETURNS int AS
245295
\$\$
@@ -321,12 +371,25 @@
321371
$node->psql($restored_db, 'SELECT test_cascade_dependency_func_2()', stdout => \$stdout, stderr => \$stderr);
322372
like ($stdout, qr/-1/, 'select_tle_function_from_restored_db_3');
323373

324-
# 4. Verify custom data type
374+
# 4. Verify non-default version TLE installed (the default version should be restored)
375+
376+
$node->psql($restored_db,
377+
"SELECT count(*) FROM pgtle.available_extension_versions() WHERE name = 'test_non_default_version'",
378+
stdout => \$stdout, stderr => \$stderr);
379+
like ($stdout, qr/2/, 'number_of_available_extension_versions');
380+
$node->psql($restored_db,
381+
"SELECT version FROM pgtle.available_extension_versions() WHERE name = 'test_non_default_version' ORDER BY version",
382+
stdout => \$stdout, stderr => \$stderr);
383+
like ($stdout, qr/1\.0\n1\.1/, 'available_extension_versions');
384+
$node->psql($restored_db, 'SELECT test_non_default_version()', stdout => \$stdout, stderr => \$stderr);
385+
like ($stdout, qr/1/, 'select_tle_function');
386+
387+
# 5. Verify custom data type
325388

326389
$node->psql($restored_db, 'SELECT * FROM test_dt;', stdout => \$stdout, stderr => \$stderr);
327390
like ($stdout, qr/TEST/, 'select_custom_data_type_from_restored_db');
328391

329-
# 5. Verify custom data operator
392+
# 6. Verify custom data operator
330393

331394
$node->psql($restored_db, 'SELECT (c1 = c1) as c2 from test_dt', stdout => \$stdout, stderr => \$stderr);
332395
like ($stdout, qr/t/, 'operator_from_restored_db');

0 commit comments

Comments
 (0)