diff --git a/contrib/pg_stash_advice/stashpersist.c b/contrib/pg_stash_advice/stashpersist.c index ccdd13872b5..2b23ba969f5 100644 --- a/contrib/pg_stash_advice/stashpersist.c +++ b/contrib/pg_stash_advice/stashpersist.c @@ -368,7 +368,7 @@ pgsa_read_from_disk(void) PGSA_DUMP_FILE, lineno))); /* No further fields are expected. */ - if (*cursor != '\0') + if (cursor != NULL) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("syntax error in file \"%s\" line %u: expected end of line", @@ -423,7 +423,7 @@ pgsa_read_from_disk(void) PGSA_DUMP_FILE, lineno))); /* No further fields are expected. */ - if (*cursor != '\0') + if (cursor != NULL) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg("syntax error in file \"%s\" line %u: expected end of line", @@ -603,25 +603,34 @@ pgsa_append_tsv_escaped_string(StringInfo buf, const char *str) /* * Extract the next tab-delimited field from *cursor. * - * The tab delimiter is replaced with '\0' and *cursor is advanced past it. - * If *cursor already points to '\0' (no more fields), returns NULL. + * Returns a pointer to the field data; when there are no remaining fields, + * returns NULL. For fields other than the last, the tab that terminates the + * field is replaced by \0, so that the caller can always interpret the return + * value as a C string. + * + * When this function is first called for a given line of text, *cursor should + * point to the beginning of the line. On return, *cursor will have been + * advanced past the tab that terminates the current field, or set to NULL if + * we just returned the last field. */ static char * pgsa_next_tsv_field(char **cursor) { char *start = *cursor; - char *p = start; + char *p; - if (*p == '\0') + if (start == NULL) return NULL; - while (*p != '\0' && *p != '\t') - p++; + p = strchr(start, '\t'); + if (p != NULL) + { + *p = '\0'; + *cursor = p + 1; + } + else + *cursor = NULL; - if (*p == '\t') - *p++ = '\0'; - - *cursor = p; return start; } diff --git a/contrib/pg_stash_advice/t/001_persist.pl b/contrib/pg_stash_advice/t/001_persist.pl index 83e98889f93..89347fb35bf 100644 --- a/contrib/pg_stash_advice/t/001_persist.pl +++ b/contrib/pg_stash_advice/t/001_persist.pl @@ -20,12 +20,13 @@ $node->start; $node->safe_psql("postgres", "CREATE EXTENSION pg_stash_advice;\n"); -# Create two stashes: one with 2 entries, one with 1 entry. +# Create two stashes: one with 3 entries, one with just 1 entry. $node->safe_psql( "postgres", qq{ SELECT pg_create_advice_stash('stash_a'); SELECT pg_set_stashed_advice('stash_a', 1001, 'IndexScan(t)'); SELECT pg_set_stashed_advice('stash_a', 1002, E'line1\\nline2\\ttab\\\\backslash'); + SELECT pg_set_stashed_advice('stash_a', 1003, ''); SELECT pg_create_advice_stash('stash_b'); SELECT pg_set_stashed_advice('stash_b', 2001, 'SeqScan(t)'); }); @@ -34,23 +35,24 @@ $node->safe_psql( my $result = $node->safe_psql("postgres", "SELECT stash_name, num_entries FROM pg_get_advice_stashes() ORDER BY stash_name" ); -is($result, "stash_a|2\nstash_b|1", 'stashes present before restart'); +is($result, "stash_a|3\nstash_b|1", 'stashes present before restart'); # Restart and verify the data survived. $node->restart; -$node->wait_for_log("loaded 2 advice stashes and 3 entries"); +$node->wait_for_log("loaded 2 advice stashes and 4 entries"); $result = $node->safe_psql("postgres", "SELECT stash_name, num_entries FROM pg_get_advice_stashes() ORDER BY stash_name" ); -is($result, "stash_a|2\nstash_b|1", 'stashes survived restart'); +is($result, "stash_a|3\nstash_b|1", 'stashes survived restart'); -# Verify entry contents, including the one with special characters. +# Verify entry contents, including the one with special characters and the +# one with an empty advice string. $result = $node->safe_psql("postgres", "SELECT stash_name, query_id, advice_string FROM pg_get_advice_stash_contents(NULL) ORDER BY stash_name, query_id" ); is( $result, - "stash_a|1001|IndexScan(t)\nstash_a|1002|line1\nline2\ttab\\backslash\nstash_b|2001|SeqScan(t)", + "stash_a|1001|IndexScan(t)\nstash_a|1002|line1\nline2\ttab\\backslash\nstash_a|1003|\nstash_b|2001|SeqScan(t)", 'entry contents survived restart with special characters intact'); # Add a third stash with 0 entries. @@ -61,13 +63,13 @@ $node->safe_psql( # Restart again and verify all three stashes are present. $node->restart; -$node->wait_for_log("loaded 3 advice stashes and 3 entries"); +$node->wait_for_log("loaded 3 advice stashes and 4 entries"); $result = $node->safe_psql("postgres", "SELECT stash_name, num_entries FROM pg_get_advice_stashes() ORDER BY stash_name" ); is( $result, - "stash_a|2\nstash_b|1\nstash_c|0", + "stash_a|3\nstash_b|1\nstash_c|0", 'all three stashes survived second restart'); # Drop all stashes and verify the dump file is removed after restart.