diff --git a/src/test/modules/injection_points/expected/injection_points.out b/src/test/modules/injection_points/expected/injection_points.out index a3ccaee5472..cc50b547654 100644 --- a/src/test/modules/injection_points/expected/injection_points.out +++ b/src/test/modules/injection_points/expected/injection_points.out @@ -307,6 +307,49 @@ SELECT injection_points_detach('TestConditionLocal1'); (1 row) +-- String match +SELECT injection_points_attach('TestConditionString', 'notice', 'MyString'); + injection_points_attach +------------------------- + +(1 row) + +SELECT injection_points_run('TestConditionString', 'MyString'); -- notice +NOTICE: notice triggered for injection point TestConditionString (MyString) + injection_points_run +---------------------- + +(1 row) + +SELECT injection_points_run('TestConditionString', 'WrongString'); -- nothing + injection_points_run +---------------------- + +(1 row) + +SELECT injection_points_run('TestConditionString', NULL); -- nothing + injection_points_run +---------------------- + +(1 row) + +SELECT injection_points_detach('TestConditionString'); + injection_points_detach +------------------------- + +(1 row) + +-- string too long for attach +SELECT injection_points_attach('TestConditionTooLong', 'error', repeat('a', 256)); +ERROR: injection point condition string too long (maximum of 255 characters) +-- empty condition string +SELECT injection_points_attach('TestConditionEmpty', 'error', ''); +ERROR: injection point condition string must not be empty +-- NULL name or action (strictness) +SELECT injection_points_attach(NULL, 'error', 'MyString'); +ERROR: injection point name must not be null +SELECT injection_points_attach('TestConditionNull', NULL, 'MyString'); +ERROR: injection point action must not be null -- Function variant for attach. SELECT injection_points_attach(repeat('a', 64), 'injection_points', 'injection_notice', NULL); diff --git a/src/test/modules/injection_points/injection_points--1.0.sql b/src/test/modules/injection_points/injection_points--1.0.sql index 861c7355d4e..2efb307f5bf 100644 --- a/src/test/modules/injection_points/injection_points--1.0.sql +++ b/src/test/modules/injection_points/injection_points--1.0.sql @@ -9,10 +9,11 @@ -- Attaches the action to the given injection point. -- CREATE FUNCTION injection_points_attach(IN point_name TEXT, - IN action text) + IN action text, + IN condition_string text DEFAULT NULL) RETURNS void AS 'MODULE_PATHNAME', 'injection_points_attach' -LANGUAGE C STRICT PARALLEL UNSAFE; +LANGUAGE C PARALLEL UNSAFE; -- -- injection_points_attach() diff --git a/src/test/modules/injection_points/injection_points.c b/src/test/modules/injection_points/injection_points.c index 0ed1dc7c8a7..66d8158d0c2 100644 --- a/src/test/modules/injection_points/injection_points.c +++ b/src/test/modules/injection_points/injection_points.c @@ -151,21 +151,20 @@ injection_init_shmem(void) * otherwise. */ static bool -injection_point_allowed(const InjectionPointCondition *condition) +injection_point_allowed(const InjectionPointCondition *condition, + const char *arg) { - bool result = true; + /* Does not match the condition PID? */ + if ((condition->type & INJ_CONDITION_PID) && + MyProcPid != condition->pid) + return false; - switch (condition->type) - { - case INJ_CONDITION_PID: - if (MyProcPid != condition->pid) - result = false; - break; - case INJ_CONDITION_ALWAYS: - break; - } + /* Does not match the condition string? */ + if ((condition->type & INJ_CONDITION_STRING) && + (arg == NULL || strcmp(condition->str, arg) != 0)) + return false; - return result; + return true; } /* @@ -197,7 +196,7 @@ injection_error(const char *name, const void *private_data, void *arg) const InjectionPointCondition *condition = private_data; char *argstr = arg; - if (!injection_point_allowed(condition)) + if (!injection_point_allowed(condition, argstr)) return; if (argstr) @@ -213,7 +212,7 @@ injection_notice(const char *name, const void *private_data, void *arg) const InjectionPointCondition *condition = private_data; char *argstr = arg; - if (!injection_point_allowed(condition)) + if (!injection_point_allowed(condition, argstr)) return; if (argstr) @@ -244,12 +243,13 @@ injection_wait(const char *name, const void *private_data, void *arg) int index = -1; uint32 injection_wait_event = 0; const InjectionPointCondition *condition = private_data; + char *argstr = arg; int delay_us = 0; if (inj_state == NULL) injection_init_shmem(); - if (!injection_point_allowed(condition)) + if (!injection_point_allowed(condition, argstr)) return; /* @@ -312,11 +312,23 @@ PG_FUNCTION_INFO_V1(injection_points_attach); Datum injection_points_attach(PG_FUNCTION_ARGS) { - char *name = text_to_cstring(PG_GETARG_TEXT_PP(0)); - char *action = text_to_cstring(PG_GETARG_TEXT_PP(1)); + char *name; + char *action; + char *str; char *function; InjectionPointCondition condition = {0}; + if (PG_ARGISNULL(0)) + elog(ERROR, "injection point name must not be null"); + + if (PG_ARGISNULL(1)) + elog(ERROR, "injection point action must not be null"); + + name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + action = text_to_cstring(PG_GETARG_TEXT_PP(1)); + str = PG_ARGISNULL(2) ? NULL + : text_to_cstring(PG_GETARG_TEXT_PP(2)); + if (strcmp(action, "error") == 0) function = "injection_error"; else if (strcmp(action, "notice") == 0) @@ -328,10 +340,21 @@ injection_points_attach(PG_FUNCTION_ARGS) if (injection_point_local) { - condition.type = INJ_CONDITION_PID; + condition.type |= INJ_CONDITION_PID; condition.pid = MyProcPid; } + if (str) + { + if (str[0] == '\0') + elog(ERROR, "injection point condition string must not be empty"); + if (strlen(str) >= INJ_DATA_MAXLEN) + elog(ERROR, "injection point condition string too long (maximum of %d characters)", + INJ_DATA_MAXLEN - 1); + condition.type |= INJ_CONDITION_STRING; + strlcpy(condition.str, str, INJ_DATA_MAXLEN); + } + InjectionPointAttach(name, "injection_points", function, &condition, sizeof(InjectionPointCondition)); diff --git a/src/test/modules/injection_points/injection_points.h b/src/test/modules/injection_points/injection_points.h index caabc4ffb32..1f02642b492 100644 --- a/src/test/modules/injection_points/injection_points.h +++ b/src/test/modules/injection_points/injection_points.h @@ -15,10 +15,14 @@ #ifndef INJECTION_POINTS_H #define INJECTION_POINTS_H +/* Maximum length for an injection point condition string */ +#define INJ_DATA_MAXLEN 256 + typedef enum InjectionPointConditionType { - INJ_CONDITION_ALWAYS = 0, /* always run */ - INJ_CONDITION_PID, /* PID restriction */ + INJ_CONDITION_NONE = 0, /* no restrictions to apply */ + INJ_CONDITION_PID = 1 << 0, /* PID restriction */ + INJ_CONDITION_STRING = 1 << 1, /* string to compare with arg */ } InjectionPointConditionType; typedef struct InjectionPointCondition @@ -28,6 +32,9 @@ typedef struct InjectionPointCondition /* ID of the process where the injection point is allowed to run */ int pid; + + /* String to compare with an argument at runtime */ + char str[INJ_DATA_MAXLEN]; } InjectionPointCondition; #endif /* INJECTION_POINTS_H */ diff --git a/src/test/modules/injection_points/sql/injection_points.sql b/src/test/modules/injection_points/sql/injection_points.sql index ba14df706ef..f9cc93b514b 100644 --- a/src/test/modules/injection_points/sql/injection_points.sql +++ b/src/test/modules/injection_points/sql/injection_points.sql @@ -88,6 +88,20 @@ SELECT injection_points_detach('TestConditionError'); SELECT injection_points_attach('TestConditionLocal1', 'error'); SELECT injection_points_detach('TestConditionLocal1'); +-- String match +SELECT injection_points_attach('TestConditionString', 'notice', 'MyString'); +SELECT injection_points_run('TestConditionString', 'MyString'); -- notice +SELECT injection_points_run('TestConditionString', 'WrongString'); -- nothing +SELECT injection_points_run('TestConditionString', NULL); -- nothing +SELECT injection_points_detach('TestConditionString'); +-- string too long for attach +SELECT injection_points_attach('TestConditionTooLong', 'error', repeat('a', 256)); +-- empty condition string +SELECT injection_points_attach('TestConditionEmpty', 'error', ''); +-- NULL name or action (strictness) +SELECT injection_points_attach(NULL, 'error', 'MyString'); +SELECT injection_points_attach('TestConditionNull', NULL, 'MyString'); + -- Function variant for attach. SELECT injection_points_attach(repeat('a', 64), 'injection_points', 'injection_notice', NULL);