|
35 | 35 | #include "utils/datetime.h" |
36 | 36 | #include "utils/fmgrprotos.h" |
37 | 37 | #include "utils/guc_hooks.h" |
| 38 | +#include "utils/guc_tables.h" |
38 | 39 | #include "utils/snapmgr.h" |
39 | 40 | #include "utils/syscache.h" |
40 | 41 | #include "utils/timestamp.h" |
@@ -1257,3 +1258,207 @@ check_ssl(bool *newval, void **extra, GucSource source) |
1257 | 1258 | #endif |
1258 | 1259 | return true; |
1259 | 1260 | } |
| 1261 | + |
| 1262 | +/* |
| 1263 | + * GUC check_hook for log_min_messages |
| 1264 | + * |
| 1265 | + * The parsing consists of a comma-separated list of BACKENDTYPENAME:LEVEL |
| 1266 | + * elements. BACKENDTYPENAME is log_min_messages_backend_types. LEVEL is |
| 1267 | + * server_message_level_options. A single LEVEL element should be part of this |
| 1268 | + * list and it is applied as a final step to the backend types that are not |
| 1269 | + * specified. For backward compatibility, the old syntax is still accepted and |
| 1270 | + * it means to apply the LEVEL for all backend types. |
| 1271 | + */ |
| 1272 | +bool |
| 1273 | +check_log_min_messages(char **newval, void **extra, GucSource source) |
| 1274 | +{ |
| 1275 | + char *rawstring; |
| 1276 | + List *elemlist; |
| 1277 | + ListCell *l; |
| 1278 | + int newlevel[BACKEND_NUM_TYPES]; |
| 1279 | + bool assigned[BACKEND_NUM_TYPES]; |
| 1280 | + int genericlevel = -1; /* -1 means not assigned */ |
| 1281 | + |
| 1282 | + /* Initialize the array. */ |
| 1283 | + memset(newlevel, WARNING, BACKEND_NUM_TYPES * sizeof(int)); |
| 1284 | + memset(assigned, false, BACKEND_NUM_TYPES * sizeof(bool)); |
| 1285 | + |
| 1286 | + /* Need a modifiable copy of string. */ |
| 1287 | + rawstring = guc_strdup(LOG, *newval); |
| 1288 | + |
| 1289 | + /* Parse string into list of identifiers. */ |
| 1290 | + if (!SplitGUCList(rawstring, ',', &elemlist)) |
| 1291 | + { |
| 1292 | + /* syntax error in list */ |
| 1293 | + GUC_check_errdetail("List syntax is invalid."); |
| 1294 | + guc_free(rawstring); |
| 1295 | + list_free(elemlist); |
| 1296 | + return false; |
| 1297 | + } |
| 1298 | + |
| 1299 | + /* Validate and assign log level and backend type. */ |
| 1300 | + foreach(l, elemlist) |
| 1301 | + { |
| 1302 | + char *tok = (char *) lfirst(l); |
| 1303 | + char *sep; |
| 1304 | + const struct config_enum_entry *entry; |
| 1305 | + |
| 1306 | + /* |
| 1307 | + * Check whether there is a backend type following the log level. If |
| 1308 | + * there is no separator, it means this is the generic log level. The |
| 1309 | + * generic log level will be assigned to the backend types that were |
| 1310 | + * not informed. |
| 1311 | + */ |
| 1312 | + sep = strchr(tok, ':'); |
| 1313 | + if (sep == NULL) |
| 1314 | + { |
| 1315 | + bool found = false; |
| 1316 | + |
| 1317 | + /* Reject duplicates for generic log level. */ |
| 1318 | + if (genericlevel != -1) |
| 1319 | + { |
| 1320 | + GUC_check_errdetail("Generic log level was already assigned."); |
| 1321 | + guc_free(rawstring); |
| 1322 | + list_free(elemlist); |
| 1323 | + return false; |
| 1324 | + } |
| 1325 | + |
| 1326 | + /* Is the log level valid? */ |
| 1327 | + for (entry = server_message_level_options; entry && entry->name; entry++) |
| 1328 | + { |
| 1329 | + if (pg_strcasecmp(entry->name, tok) == 0) |
| 1330 | + { |
| 1331 | + genericlevel = entry->val; |
| 1332 | + found = true; |
| 1333 | + break; |
| 1334 | + } |
| 1335 | + } |
| 1336 | + |
| 1337 | + if (!found) |
| 1338 | + { |
| 1339 | + GUC_check_errdetail("Unrecognized log level: \"%s\".", tok); |
| 1340 | + guc_free(rawstring); |
| 1341 | + list_free(elemlist); |
| 1342 | + return false; |
| 1343 | + } |
| 1344 | + } |
| 1345 | + else |
| 1346 | + { |
| 1347 | + char *loglevel; |
| 1348 | + char *btype; |
| 1349 | + bool found = false; |
| 1350 | + |
| 1351 | + btype = guc_malloc(LOG, (sep - tok) + 1); |
| 1352 | + if (!btype) |
| 1353 | + { |
| 1354 | + guc_free(rawstring); |
| 1355 | + list_free(elemlist); |
| 1356 | + return false; |
| 1357 | + } |
| 1358 | + memcpy(btype, tok, sep - tok); |
| 1359 | + btype[sep - tok] = '\0'; |
| 1360 | + loglevel = sep + 1; |
| 1361 | + |
| 1362 | + /* Is the log level valid? */ |
| 1363 | + for (entry = server_message_level_options; entry && entry->name; entry++) |
| 1364 | + { |
| 1365 | + if (pg_strcasecmp(entry->name, loglevel) == 0) |
| 1366 | + { |
| 1367 | + found = true; |
| 1368 | + break; |
| 1369 | + } |
| 1370 | + } |
| 1371 | + |
| 1372 | + if (!found) |
| 1373 | + { |
| 1374 | + GUC_check_errdetail("Unrecognized log level: \"%s\".", loglevel); |
| 1375 | + guc_free(btype); |
| 1376 | + guc_free(rawstring); |
| 1377 | + list_free(elemlist); |
| 1378 | + return false; |
| 1379 | + } |
| 1380 | + |
| 1381 | + /* |
| 1382 | + * Is the backend type name valid? There might be multiple entries |
| 1383 | + * per backend type, don't bail out because it can assign the |
| 1384 | + * value for multiple entries. |
| 1385 | + */ |
| 1386 | + found = false; |
| 1387 | + for (int i = 0; i < BACKEND_NUM_TYPES; i++) |
| 1388 | + { |
| 1389 | + if (pg_strcasecmp(log_min_messages_backend_types[i], btype) == 0) |
| 1390 | + { |
| 1391 | + /* Reject duplicates for a backend type. */ |
| 1392 | + if (assigned[i]) |
| 1393 | + { |
| 1394 | + GUC_check_errdetail("Backend type \"%s\" was already assigned.", btype); |
| 1395 | + guc_free(btype); |
| 1396 | + guc_free(rawstring); |
| 1397 | + list_free(elemlist); |
| 1398 | + return false; |
| 1399 | + } |
| 1400 | + |
| 1401 | + newlevel[i] = entry->val; |
| 1402 | + assigned[i] = true; |
| 1403 | + found = true; |
| 1404 | + } |
| 1405 | + } |
| 1406 | + |
| 1407 | + if (!found) |
| 1408 | + { |
| 1409 | + GUC_check_errdetail("Unrecognized backend type: \"%s\".", btype); |
| 1410 | + guc_free(btype); |
| 1411 | + guc_free(rawstring); |
| 1412 | + list_free(elemlist); |
| 1413 | + return false; |
| 1414 | + } |
| 1415 | + |
| 1416 | + guc_free(btype); |
| 1417 | + } |
| 1418 | + } |
| 1419 | + |
| 1420 | + /* |
| 1421 | + * The generic log level must be specified. It is the fallback value. |
| 1422 | + */ |
| 1423 | + if (genericlevel == -1) |
| 1424 | + { |
| 1425 | + GUC_check_errdetail("Generic log level was not defined."); |
| 1426 | + guc_free(rawstring); |
| 1427 | + list_free(elemlist); |
| 1428 | + return false; |
| 1429 | + } |
| 1430 | + |
| 1431 | + /* |
| 1432 | + * Apply the generic log level after all of the specific backend type have |
| 1433 | + * been assigned. Hence, it doesn't matter the order you specify the |
| 1434 | + * generic log level, the final result will be the same. |
| 1435 | + */ |
| 1436 | + for (int i = 0; i < BACKEND_NUM_TYPES; i++) |
| 1437 | + { |
| 1438 | + if (!assigned[i]) |
| 1439 | + newlevel[i] = genericlevel; |
| 1440 | + } |
| 1441 | + |
| 1442 | + guc_free(rawstring); |
| 1443 | + list_free(elemlist); |
| 1444 | + |
| 1445 | + /* |
| 1446 | + * Pass back data for assign_log_min_messages to use. |
| 1447 | + */ |
| 1448 | + *extra = guc_malloc(LOG, BACKEND_NUM_TYPES * sizeof(int)); |
| 1449 | + if (!*extra) |
| 1450 | + return false; |
| 1451 | + memcpy(*extra, newlevel, BACKEND_NUM_TYPES * sizeof(int)); |
| 1452 | + |
| 1453 | + return true; |
| 1454 | +} |
| 1455 | + |
| 1456 | +/* |
| 1457 | + * GUC assign_hook for log_min_messages |
| 1458 | + */ |
| 1459 | +void |
| 1460 | +assign_log_min_messages(const char *newval, void *extra) |
| 1461 | +{ |
| 1462 | + for (int i = 0; i < BACKEND_NUM_TYPES; i++) |
| 1463 | + log_min_messages[i] = ((int *) extra)[i]; |
| 1464 | +} |
0 commit comments