From fba6ed5589616edf70edb83ab7eb8b1945a94b37 Mon Sep 17 00:00:00 2001 From: "houzj.fnst" <63178771+sherlockcpp@users.noreply.github.com> Date: Fri, 24 Jul 2020 15:41:04 +0800 Subject: [PATCH 1/5] Update pool_relcache.c --- src/utils/pool_relcache.c | 154 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 142 insertions(+), 12 deletions(-) diff --git a/src/utils/pool_relcache.c b/src/utils/pool_relcache.c index c801b94..e4b995f 100644 --- a/src/utils/pool_relcache.c +++ b/src/utils/pool_relcache.c @@ -36,6 +36,7 @@ #include "utils/palloc.h" #include "utils/memutils.h" #include "utils/elog.h" +#include "parser/scansup.h" static void SearchRelCacheErrorCb(void *arg); static POOL_SELECT_RESULT *query_cache_to_relation_cache(char *data, size_t size); @@ -343,25 +344,154 @@ SearchRelCacheErrorCb(void *arg) } +/* + * SplitIdentifierString --- parse a string containing identifiers + * + * This is the guts of textToQualifiedNameList, and is exported for use in + * other situations such as parsing GUC variables. In the GUC case, it's + * important to avoid memory leaks, so the API is designed to minimize the + * amount of stuff that needs to be allocated and freed. + * + * Inputs: + * rawstring: the input string; must be overwritable! On return, it's + * been modified to contain the separated identifiers. + * separator: the separator punctuation expected between identifiers + * (typically '.' or ','). Whitespace may also appear around + * identifiers. + * Outputs: + * namelist: filled with a palloc'd list of pointers to identifiers within + * rawstring. Caller should list_free() this even on error return. + * + * Returns true if okay, false if there is a syntax error in the string. + * + * Note that an empty string is considered okay here, though not in + * textToQualifiedNameList. + */ +bool +SplitIdentifierString(char *rawstring, char separator, + Node **nlist) +{ + char *nextp = rawstring; + bool done = false; + List **namelist = (List **) nlist; + + *namelist = NIL; + + while (scanner_isspace(*nextp)) + nextp++; /* skip leading whitespace */ + + if (*nextp == '\0') + return true; /* allow empty string */ + + /* At the top of the loop, we are at start of a new identifier. */ + do + { + char *curname; + char *endp; + + if (*nextp == '"') + { + /* Quoted name --- collapse quote-quote pairs, no downcasing */ + curname = nextp + 1; + for (;;) + { + endp = strchr(nextp + 1, '"'); + if (endp == NULL) + return false; /* mismatched quotes */ + if (endp[1] != '"') + break; /* found end of quoted name */ + /* Collapse adjacent quotes into one quote, and look again */ + memmove(endp, endp + 1, strlen(endp)); + nextp = endp; + } + /* endp now points at the terminating quote */ + nextp = endp + 1; + } + else + { + /* Unquoted name --- extends to separator or whitespace */ + char *downname; + int len; + + curname = nextp; + while (*nextp && *nextp != separator && + !scanner_isspace(*nextp)) + nextp++; + endp = nextp; + if (curname == nextp) + return false; /* empty unquoted name not allowed */ + + /* + * Downcase the identifier, using same code as main lexer does. + * + * XXX because we want to overwrite the input in-place, we cannot + * support a downcasing transformation that increases the string + * length. This is not a problem given the current implementation + * of downcase_truncate_identifier, but we'll probably have to do + * something about this someday. + */ + len = endp - curname; + downname = downcase_truncate_identifier(curname, len, false); + Assert(strlen(downname) <= len); + strncpy(curname, downname, len); /* strncpy is required here */ + pfree(downname); + } + + while (scanner_isspace(*nextp)) + nextp++; /* skip trailing whitespace */ + + if (*nextp == separator) + { + nextp++; + while (scanner_isspace(*nextp)) + nextp++; /* skip leading whitespace for next */ + /* we expect another name, so done remains false */ + } + else if (*nextp == '\0') + done = true; + else + return false; /* invalid syntax */ + + /* Now safe to overwrite separator with a null */ + *endp = '\0'; + + /* Truncate name if it's overlength */ + truncate_identifier(curname, strlen(curname), false); + + /* + * Finished isolating current name --- add it to list + */ + *namelist = lappend(*namelist, curname); + + /* Loop back if we didn't reach end of string */ + } while (!done); + + return true; +} + char * remove_quotes_and_schema_from_relname(char *table) { static char rel[MAX_ITEM_LENGTH]; - char *p; - int i = 0; + char *rawstring; + List *names; - /* get rid of schema name */ - p = strchr(table, '.'); - if (p) - table = p + 1; - - /* get rid of quotation marks */ - for (i = 0; *table; table++) + rawstring = pstrdup(table); + if(SplitIdentifierString(rawstring, '.', (Node **) &names) && names != NIL) + { + /* + * Since table name is always the last one in the list, + * we use llast() to get table name. + */ + strlcpy(rel, llast(names), sizeof(rel)); + } + else { - if (*table != '"') - rel[i++] = *table; + rel[0] = '\0'; } - rel[i] = '\0'; + + pfree(rawstring); + list_free(names); return rel; } -- 1.8.3.1