|
22 | 22 | #include "access/sysattr.h"
|
23 | 23 | #include "catalog/indexing.h"
|
24 | 24 | #include "catalog/pg_constraint.h"
|
| 25 | +#include "catalog/pg_extension.h" |
25 | 26 | #include "catalog/pg_inherits.h"
|
26 | 27 | #include "catalog/pg_inherits_fn.h"
|
27 | 28 | #include "catalog/pg_type.h"
|
@@ -62,6 +63,7 @@ PathmanInitState pg_pathman_init_state;
|
62 | 63 | /* Shall we install new relcache callback? */
|
63 | 64 | static bool relcache_callback_needed = true;
|
64 | 65 |
|
| 66 | + |
65 | 67 | /* Functions for various local caches */
|
66 | 68 | static bool init_pathman_relation_oids(void);
|
67 | 69 | static void fini_pathman_relation_oids(void);
|
@@ -89,6 +91,11 @@ static bool read_opexpr_const(const OpExpr *opexpr,
|
89 | 91 | static int oid_cmp(const void *p1, const void *p2);
|
90 | 92 |
|
91 | 93 |
|
| 94 | +/* Validate SQL facade */ |
| 95 | +static uint32 build_sql_facade_version(char *version_cstr); |
| 96 | +static uint32 get_sql_facade_version(void); |
| 97 | +static void validate_sql_facade_version(uint32 ver); |
| 98 | + |
92 | 99 | /*
|
93 | 100 | * Save and restore main init state.
|
94 | 101 | */
|
@@ -167,6 +174,9 @@ load_config(void)
|
167 | 174 | if (!init_pathman_relation_oids())
|
168 | 175 | return false; /* remain 'uninitialized', exit before creating main caches */
|
169 | 176 |
|
| 177 | + /* Validate pg_pathman's Pl/PgSQL facade (might be outdated) */ |
| 178 | + validate_sql_facade_version(get_sql_facade_version()); |
| 179 | + |
170 | 180 | init_local_cache(); /* create 'partitioned_rels' hash table */
|
171 | 181 | read_pathman_config(); /* read PATHMAN_CONFIG table & fill cache */
|
172 | 182 |
|
@@ -1098,3 +1108,89 @@ oid_cmp(const void *p1, const void *p2)
|
1098 | 1108 | return 1;
|
1099 | 1109 | return 0;
|
1100 | 1110 | }
|
| 1111 | + |
| 1112 | + |
| 1113 | +/* Parse cstring and build uint32 representing the version */ |
| 1114 | +static uint32 |
| 1115 | +build_sql_facade_version(char *version_cstr) |
| 1116 | +{ |
| 1117 | + uint32 version; |
| 1118 | + |
| 1119 | + /* expect to see x+.y+.z+ */ |
| 1120 | + version = strtol(version_cstr, &version_cstr, 10) & 0xFF; |
| 1121 | + |
| 1122 | + version <<= 8; |
| 1123 | + if (strlen(version_cstr) > 1) |
| 1124 | + version |= (strtol(version_cstr + 1, &version_cstr, 10) & 0xFF); |
| 1125 | + |
| 1126 | + version <<= 8; |
| 1127 | + if (strlen(version_cstr) > 1) |
| 1128 | + version |= (strtol(version_cstr + 1, &version_cstr, 10) & 0xFF); |
| 1129 | + |
| 1130 | + return version; |
| 1131 | +} |
| 1132 | + |
| 1133 | +/* Get version of pg_pathman's facade written in Pl/PgSQL */ |
| 1134 | +static uint32 |
| 1135 | +get_sql_facade_version(void) |
| 1136 | +{ |
| 1137 | + Relation pg_extension_rel; |
| 1138 | + ScanKeyData skey; |
| 1139 | + SysScanDesc scan; |
| 1140 | + HeapTuple htup; |
| 1141 | + |
| 1142 | + Datum datum; |
| 1143 | + bool isnull; |
| 1144 | + char *version_cstr; |
| 1145 | + |
| 1146 | + /* Look up the extension */ |
| 1147 | + pg_extension_rel = heap_open(ExtensionRelationId, AccessShareLock); |
| 1148 | + |
| 1149 | + ScanKeyInit(&skey, |
| 1150 | + Anum_pg_extension_extname, |
| 1151 | + BTEqualStrategyNumber, F_NAMEEQ, |
| 1152 | + CStringGetDatum("pg_pathman")); |
| 1153 | + |
| 1154 | + scan = systable_beginscan(pg_extension_rel, |
| 1155 | + ExtensionNameIndexId, |
| 1156 | + true, NULL, 1, &skey); |
| 1157 | + |
| 1158 | + htup = systable_getnext(scan); |
| 1159 | + |
| 1160 | + /* Exit if pg_pathman's missing */ |
| 1161 | + if (!HeapTupleIsValid(htup)) |
| 1162 | + return 0; |
| 1163 | + |
| 1164 | + datum = heap_getattr(htup, Anum_pg_extension_extversion, |
| 1165 | + RelationGetDescr(pg_extension_rel), &isnull); |
| 1166 | + Assert(isnull == false); /* extversion should not be NULL */ |
| 1167 | + |
| 1168 | + /* Extract pg_pathman's version as cstring */ |
| 1169 | + version_cstr = text_to_cstring(DatumGetTextPP(datum)); |
| 1170 | + |
| 1171 | + systable_endscan(scan); |
| 1172 | + heap_close(pg_extension_rel, AccessShareLock); |
| 1173 | + |
| 1174 | + return build_sql_facade_version(version_cstr); |
| 1175 | +} |
| 1176 | + |
| 1177 | +/* Check that current Pl/PgSQL facade is compatible with internals */ |
| 1178 | +static void |
| 1179 | +validate_sql_facade_version(uint32 ver) |
| 1180 | +{ |
| 1181 | + Assert(ver > 0); |
| 1182 | + |
| 1183 | + /* Compare ver to 'lowest compatible frontend' version */ |
| 1184 | + if (ver < LOWEST_COMPATIBLE_FRONT) |
| 1185 | + { |
| 1186 | + elog(DEBUG1, "current version: %x, lowest compatible: %x", |
| 1187 | + ver, LOWEST_COMPATIBLE_FRONT); |
| 1188 | + |
| 1189 | + DisablePathman(); /* disable pg_pathman since config is broken */ |
| 1190 | + ereport(ERROR, |
| 1191 | + (errmsg("pg_pathman's Pl/PgSQL frontend is incompatible with " |
| 1192 | + "its shared library"), |
| 1193 | + errdetail("consider performing an update procedure"), |
| 1194 | + errhint(INIT_ERROR_HINT))); |
| 1195 | + } |
| 1196 | +} |
0 commit comments