57
57
bool creating_extension = false;
58
58
Oid CurrentExtensionObject = InvalidOid ;
59
59
60
- /* Character that separates extension & version names in a script filename */
61
- #define EXT_VERSION_SEP '-'
62
-
63
60
/*
64
61
* Internal data structure to hold the results of parsing a control file
65
62
*/
@@ -225,9 +222,42 @@ get_extension_schema(Oid ext_oid)
225
222
static void
226
223
check_valid_extension_name (const char * extensionname )
227
224
{
225
+ int namelen = strlen (extensionname );
226
+
228
227
/*
229
- * No directory separators (this is sufficient to prevent ".." style
230
- * attacks).
228
+ * Disallow empty names (the parser rejects empty identifiers anyway,
229
+ * but let's check).
230
+ */
231
+ if (namelen == 0 )
232
+ ereport (ERROR ,
233
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
234
+ errmsg ("invalid extension name: \"%s\"" , extensionname ),
235
+ errdetail ("Extension names must not be empty." )));
236
+
237
+ /*
238
+ * No double dashes, since that would make script filenames ambiguous.
239
+ */
240
+ if (strstr (extensionname , "--" ))
241
+ ereport (ERROR ,
242
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
243
+ errmsg ("invalid extension name: \"%s\"" , extensionname ),
244
+ errdetail ("Extension names must not contain \"--\"." )));
245
+
246
+ /*
247
+ * No leading or trailing dash either. (We could probably allow this,
248
+ * but it would require much care in filename parsing and would make
249
+ * filenames visually if not formally ambiguous. Since there's no
250
+ * real-world use case, let's just forbid it.)
251
+ */
252
+ if (extensionname [0 ] == '-' || extensionname [namelen - 1 ] == '-' )
253
+ ereport (ERROR ,
254
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
255
+ errmsg ("invalid extension name: \"%s\"" , extensionname ),
256
+ errdetail ("Extension names must not begin or end with \"-\"." )));
257
+
258
+ /*
259
+ * No directory separators either (this is sufficient to prevent ".."
260
+ * style attacks).
231
261
*/
232
262
if (first_dir_separator (extensionname ) != NULL )
233
263
ereport (ERROR ,
@@ -239,16 +269,39 @@ check_valid_extension_name(const char *extensionname)
239
269
static void
240
270
check_valid_version_name (const char * versionname )
241
271
{
242
- /* No separators --- would risk confusion of install vs update scripts */
243
- if (strchr (versionname , EXT_VERSION_SEP ))
272
+ int namelen = strlen (versionname );
273
+
274
+ /*
275
+ * Disallow empty names (we could possibly allow this, but there seems
276
+ * little point).
277
+ */
278
+ if (namelen == 0 )
279
+ ereport (ERROR ,
280
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
281
+ errmsg ("invalid extension version name: \"%s\"" , versionname ),
282
+ errdetail ("Version names must not be empty." )));
283
+
284
+ /*
285
+ * No double dashes, since that would make script filenames ambiguous.
286
+ */
287
+ if (strstr (versionname , "--" ))
288
+ ereport (ERROR ,
289
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
290
+ errmsg ("invalid extension version name: \"%s\"" , versionname ),
291
+ errdetail ("Version names must not contain \"--\"." )));
292
+
293
+ /*
294
+ * No leading or trailing dash either.
295
+ */
296
+ if (versionname [0 ] == '-' || versionname [namelen - 1 ] == '-' )
244
297
ereport (ERROR ,
245
298
(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
246
299
errmsg ("invalid extension version name: \"%s\"" , versionname ),
247
- errdetail ("Version names must not contain the character \"%c \"." ,
248
- EXT_VERSION_SEP )));
300
+ errdetail ("Version names must not begin or end with \"- \"." )));
301
+
249
302
/*
250
- * No directory separators (this is sufficient to prevent ".." style
251
- * attacks).
303
+ * No directory separators either (this is sufficient to prevent ".."
304
+ * style attacks).
252
305
*/
253
306
if (first_dir_separator (versionname ) != NULL )
254
307
ereport (ERROR ,
@@ -336,8 +389,8 @@ get_extension_aux_control_filename(ExtensionControlFile *control,
336
389
scriptdir = get_extension_script_directory (control );
337
390
338
391
result = (char * ) palloc (MAXPGPATH );
339
- snprintf (result , MAXPGPATH , "%s/%s%c %s.control" ,
340
- scriptdir , control -> name , EXT_VERSION_SEP , version );
392
+ snprintf (result , MAXPGPATH , "%s/%s-- %s.control" ,
393
+ scriptdir , control -> name , version );
341
394
342
395
pfree (scriptdir );
343
396
@@ -355,12 +408,11 @@ get_extension_script_filename(ExtensionControlFile *control,
355
408
356
409
result = (char * ) palloc (MAXPGPATH );
357
410
if (from_version )
358
- snprintf (result , MAXPGPATH , "%s/%s%c%s%c%s.sql" ,
359
- scriptdir , control -> name , EXT_VERSION_SEP , from_version ,
360
- EXT_VERSION_SEP , version );
411
+ snprintf (result , MAXPGPATH , "%s/%s--%s--%s.sql" ,
412
+ scriptdir , control -> name , from_version , version );
361
413
else
362
- snprintf (result , MAXPGPATH , "%s/%s%c %s.sql" ,
363
- scriptdir , control -> name , EXT_VERSION_SEP , version );
414
+ snprintf (result , MAXPGPATH , "%s/%s-- %s.sql" ,
415
+ scriptdir , control -> name , version );
364
416
365
417
pfree (scriptdir );
366
418
@@ -426,7 +478,7 @@ parse_extension_control_file(ExtensionControlFile *control,
426
478
if (version )
427
479
ereport (ERROR ,
428
480
(errcode (ERRCODE_SYNTAX_ERROR ),
429
- errmsg ("parameter \"%s\" cannot be set in a per-version extension control file" ,
481
+ errmsg ("parameter \"%s\" cannot be set in a secondary extension control file" ,
430
482
item -> name )));
431
483
432
484
control -> directory = pstrdup (item -> value );
@@ -436,7 +488,7 @@ parse_extension_control_file(ExtensionControlFile *control,
436
488
if (version )
437
489
ereport (ERROR ,
438
490
(errcode (ERRCODE_SYNTAX_ERROR ),
439
- errmsg ("parameter \"%s\" cannot be set in a per-version extension control file" ,
491
+ errmsg ("parameter \"%s\" cannot be set in a secondary extension control file" ,
440
492
item -> name )));
441
493
442
494
control -> default_version = pstrdup (item -> value );
@@ -907,16 +959,18 @@ get_ext_ver_list(ExtensionControlFile *control)
907
959
908
960
/* ... matching extension name followed by separator */
909
961
if (strncmp (de -> d_name , control -> name , extnamelen ) != 0 ||
910
- de -> d_name [extnamelen ] != EXT_VERSION_SEP )
962
+ de -> d_name [extnamelen ] != '-' ||
963
+ de -> d_name [extnamelen + 1 ] != '-' )
911
964
continue ;
912
965
913
- /* extract version names from 'extname-something.sql' filename */
914
- vername = pstrdup (de -> d_name + extnamelen + 1 );
966
+ /* extract version names from 'extname-- something.sql' filename */
967
+ vername = pstrdup (de -> d_name + extnamelen + 2 );
915
968
* strrchr (vername , '.' ) = '\0' ;
916
- vername2 = strchr (vername , EXT_VERSION_SEP );
969
+ vername2 = strstr (vername , "--" );
917
970
if (!vername2 )
918
971
continue ; /* it's not an update script */
919
- * vername2 ++ = '\0' ;
972
+ * vername2 = '\0' ; /* terminate first version */
973
+ vername2 += 2 ; /* and point to second */
920
974
921
975
/* Create ExtensionVersionInfos and link them together */
922
976
evi = get_ext_ver_info (vername , & evi_list );
@@ -979,6 +1033,20 @@ identify_update_path(ExtensionControlFile *control,
979
1033
evi2 -> distance = newdist ;
980
1034
evi2 -> previous = evi ;
981
1035
}
1036
+ else if (newdist == evi2 -> distance &&
1037
+ evi2 -> previous != NULL &&
1038
+ strcmp (evi -> name , evi2 -> previous -> name ) < 0 )
1039
+ {
1040
+ /*
1041
+ * Break ties in favor of the version name that comes first
1042
+ * according to strcmp(). This behavior is undocumented and
1043
+ * users shouldn't rely on it. We do it just to ensure that
1044
+ * if there is a tie, the update path that is chosen does not
1045
+ * depend on random factors like the order in which directory
1046
+ * entries get visited.
1047
+ */
1048
+ evi2 -> previous = evi ;
1049
+ }
982
1050
}
983
1051
}
984
1052
@@ -1251,7 +1319,7 @@ CreateExtension(CreateExtensionStmt *stmt)
1251
1319
requiredExtensions );
1252
1320
1253
1321
/*
1254
- * Apply any comment on extension
1322
+ * Apply any control-file comment on extension
1255
1323
*/
1256
1324
if (control -> comment != NULL )
1257
1325
CreateComments (extensionOid , ExtensionRelationId , 0 , control -> comment );
@@ -1544,6 +1612,10 @@ pg_available_extensions(PG_FUNCTION_ARGS)
1544
1612
extname = pstrdup (de -> d_name );
1545
1613
* strrchr (extname , '.' ) = '\0' ;
1546
1614
1615
+ /* ignore it if it's an auxiliary control file */
1616
+ if (strstr (extname , "--" ))
1617
+ continue ;
1618
+
1547
1619
control = read_extension_control_file (extname );
1548
1620
1549
1621
memset (values , 0 , sizeof (values ));
0 commit comments