Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# It doesn't use CFLAGS in compiling, it uses some postgres magic instead :(
CFLAGS := ${CFLAGS} -Wall -Werror
override CFLAGS = -Wall -Wmissing-prototypes -Wpointer-arith -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-unused-but-set-variable -Wno-address -Wno-format-truncation -Wno-stringop-truncation -g -ggdb -std=gnu99 -Werror=uninitialized -Werror=implicit-function-declaration -DGPBUILD

EXTENSION = query_tag
EXTVERSION = $(shell grep default_version $(EXTENSION).control | \
Expand Down
5 changes: 3 additions & 2 deletions sql/query_tag--1.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ CREATE FUNCTION CURRENT_RESGROUP() RETURNS text
AS 'query_tag', 'current_resgroup'
LANGUAGE C STRICT VOLATILE;

CREATE OR REPLACE FUNCTION is_tag_in_guc(query_tag text)
CREATE FUNCTION is_tag_in_guc(text)
RETURNS boolean
AS 'query_tag', 'is_tag_in_guc'
LANGUAGE C STRICT VOLATILE;
Expand All @@ -32,7 +32,8 @@ CREATE TABLE wlm_rules (
spill_file_mb int,
cpuskew_percent int,
cpuskew_duration_sec int,
order_id int not null
order_id int not null,
kill_rule boolean
);

CREATE TABLE gpcc_wlm_log_history (
Expand Down
220 changes: 58 additions & 162 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,188 +4,84 @@
#include "utils/builtins.h"
#include "c.h"
#include <locale.h>
#include "utils/memutils.h"

static bool good_char(char c) {
return (isalnum(c) || c == '=' || c == ';' || c == '_');
}

bool parse_tags(const char *guc, List **parsed) {
*parsed = NIL;
bool is_in_key = true;
bool is_empty = true;
const char *substr_ptr_start;
const char *substr_ptr_end;
char *key_tag = NULL, *value_tag = NULL;
if (!guc || *guc == '\0') {
return true;
static void free_double_list(List **double_list) {
ListCell *current_cell;
foreach(current_cell, *double_list) {
list_free(lfirst(current_cell));
}
substr_ptr_start = guc;
const char *cur;
for (cur = guc;; ++cur) {
if (*cur == '\0') {
if (is_in_key) {
return false;
}
if (is_empty) {
return true;
}
substr_ptr_end = cur;
value_tag = copy_substr(substr_ptr_start, substr_ptr_end);
substr_ptr_start = cur + 1;

tag_pair *tpair;
tpair = malloc(sizeof(tpair));
tpair->key = key_tag;
tpair->value = value_tag;
*parsed = lappend(*parsed, tpair);
break;
}
if (!good_char(*cur)) {
return false;
}
if (*cur == '=') {
if (is_empty) {
return false;
}
if (is_in_key) {
is_in_key = false;
is_empty = true;
} else {
return false;
}
}
if (*cur == ';') {
if (is_empty) {
return false;
}
if (is_in_key) {
return false;
} else {
is_in_key = true;
is_empty = true;
}
}
if (isalpha(*cur) || *cur == '_') {
is_empty = false;
}
if (*cur == '=') {
substr_ptr_end = cur;
key_tag = copy_substr(substr_ptr_start, substr_ptr_end);
substr_ptr_start = cur + 1;
}
if (*cur == ';') {
substr_ptr_end = cur;
value_tag = copy_substr(substr_ptr_start, substr_ptr_end);
substr_ptr_start = cur + 1;

tag_pair *tpair;
tpair = malloc(sizeof(tpair));
tpair->key = key_tag;
tpair->value = value_tag;
*parsed = lappend(*parsed, tpair);
}
}

return true;
list_free(*double_list);
*double_list = NIL;
}

void tag_list_free(List **tag_list) {
ListCell *cell;
foreach (cell, *tag_list) {
tag_pair *tpair = lfirst(cell);
free(tpair->key);
free(tpair->value);
free(tpair);
bool split_tags(const char *tags, ParsedTags **parsed) {
if (!tags) {
Comment thread
Lepip marked this conversation as resolved.
elog(ERROR, "QUERY_TAG: there's a NULL query_tag somewhere.");
}
list_free(*tag_list);
*tag_list = NIL;
}

bool is_safe(const char *guc) {
if (!guc)
MemoryContext oldctx = MemoryContextSwitchTo(TopMemoryContext);
*parsed = palloc(sizeof(**parsed));
char *tags_mutable = pstrdup(tags);
List *tag_pairs = NIL;
bool ok = SplitIdentifierString(tags_mutable, ';', &tag_pairs);
if (!ok) {
pfree(*parsed);
*parsed = NULL;
pfree(tags_mutable);
list_free(tag_pairs);
MemoryContextSwitchTo(oldctx);
return false;
if (*guc == '\0')
return true;
bool is_in_key = true;
bool is_empty = true;
for (const char *cur = guc; *cur != '\0'; ++cur) {
if (!good_char(*cur)) {
elog(INFO, "GUHed char: %c", *cur);
}
ListCell *current_tag;
List *parsed_tags = NIL;
foreach(current_tag, tag_pairs) {
List *parsed_current_tag = NIL;
ok = SplitIdentifierString(lfirst(current_tag), '=', &parsed_current_tag);
if (!ok || list_length(parsed_current_tag) != 2) {
list_free(parsed_current_tag);
free_double_list(&parsed_tags);
pfree(*parsed);
*parsed = NULL;
pfree(tags_mutable);
list_free(tag_pairs);
MemoryContextSwitchTo(oldctx);
return false;
}
if (*cur == '=') {
if (is_empty) {
return false;
}
if (is_in_key) {
is_in_key = false;
is_empty = true;
} else {
return false;
}
}
if (*cur == ';') {
if (is_empty) {
return false;
}
if (is_in_key) {
return false;
} else {
is_in_key = true;
is_empty = true;
}
}
if (isalnum(*cur) || *cur == '_') {
is_empty = false;
}
parsed_tags = lappend(parsed_tags, parsed_current_tag);
}
if (is_in_key && !is_empty)
return false;
return true;
}

char *copy_substr(const char *start, const char *end) {
int len = end - start;
char *ret = calloc(len + 1, sizeof(char));
memcpy(ret, start, len);
ret[len] = '\0';
return ret;
(*parsed)->tags_mutable = tags_mutable;
(*parsed)->parsed_tags = parsed_tags;
MemoryContextSwitchTo(oldctx);
return true;
}

bool is_tag_in_guc_ctype(const char *tag, const char *guc) {
List *parsed_guc = NIL;
List *parsed_tag = NIL;

bool ok = parse_tags(guc, &parsed_guc);
if (!ok) {
tag_list_free(&parsed_guc);
return false;
}

ok = parse_tags(tag, &parsed_tag);
if (!ok) {
tag_list_free(&parsed_tag);
return false;
}
ListCell *guc_pair_cell, *tag_pair_cell;
foreach (tag_pair_cell, parsed_tag) {
tag_pair *cur_tag = lfirst(tag_pair_cell);
bool is_parsed_rule_in_parsed_guc(ParsedTags *rule_tags, ParsedTags *guc_tags) {
ListCell *guc_cell, *tag_cell;
foreach (tag_cell, rule_tags->parsed_tags) {
List *tag_pair = lfirst(tag_cell);
bool found = false;
foreach (guc_pair_cell, parsed_guc) {
tag_pair *cur_guc = lfirst(guc_pair_cell);
if (strcmp(cur_tag->key, cur_guc->key) == 0 &&
strcmp(cur_tag->value, cur_guc->value) == 0) {
foreach (guc_cell, guc_tags->parsed_tags) {
List *guc_pair = lfirst(guc_cell);
if (strcmp(linitial(guc_pair), linitial(tag_pair)) == 0 &&
strcmp(lsecond(guc_pair), lsecond(tag_pair)) == 0) {
found = true;
break;
}
}
if (!found) {
tag_list_free(&parsed_guc);
tag_list_free(&parsed_tag);
return false;
}
}
tag_list_free(&parsed_guc);
tag_list_free(&parsed_tag);
return true;
}

void free_parsed_tags(ParsedTags **parsed) {
if (*parsed) {
free_double_list(&(*parsed)->parsed_tags);
if ((*parsed)->tags_mutable)
pfree((*parsed)->tags_mutable);
pfree(*parsed);
*parsed = NULL;
}
}
16 changes: 7 additions & 9 deletions src/parser.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
#include "nodes/pg_list.h"

typedef struct tpair{
char *key;
char *value;
} tag_pair;
typedef struct ParsedTags {
char *tags_mutable;
List *parsed_tags;
} ParsedTags;

bool is_safe(const char *guc);
bool parse_tags(const char *guc, List **parsed);
void tag_list_free(List **tag_list);
char *copy_substr(const char *start, const char *end);
bool is_tag_in_guc_ctype(const char *tag, const char *guc);
bool split_tags(const char *tags, ParsedTags **parsed);
bool is_parsed_rule_in_parsed_guc(ParsedTags *parsed_rule, ParsedTags *parsed_guc);
void free_parsed_tags(ParsedTags **parsed);
Loading