From b61a5e6a1f8d4d9e0bfe5d26bebfbb0687353c08 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 31 Aug 2019 13:37:10 -0400 Subject: [PATCH] Cosmetic improvements for options-handling code in ECPGconnect(). The comment describing the string format was a lie. Make it agree with reality, add/improve some other comments, fix coding style for loops with empty bodies. Also add an Assert that we counted parameters correctly, because the spread-out logic for that looks pretty fragile. No actual bugs fixed here, so no need to back-patch. Discussion: https://postgr.es/m/848B1649C8A6274AA527C4472CA11EDD5FC70CBE@G01JPEXMBYT02 --- src/interfaces/ecpg/ecpglib/connect.c | 33 +++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c index ec01f67b61..4f361510c3 100644 --- a/src/interfaces/ecpg/ecpglib/connect.c +++ b/src/interfaces/ecpg/ecpglib/connect.c @@ -516,9 +516,9 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p options ? "with options " : "", options ? options : "", (user && strlen(user) > 0) ? "for user " : "", user ? user : ""); + /* count options (this may produce an overestimate, it's ok) */ if (options) for (i = 0; options[i]; i++) - /* count options */ if (options[i] == '=') connect_params++; @@ -585,8 +585,12 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p { char *str; - /* options look like this "option1 = value1 option2 = value2 ... */ - /* we have to break up the string into single options */ + /* + * The options string contains "keyword=value" pairs separated by + * '&'s. We must break this up into keywords and values to pass to + * libpq (it's okay to scribble on the options string). We ignore + * spaces just before each keyword or value. + */ for (str = options; *str;) { int e, @@ -594,13 +598,21 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p char *token1, *token2; - for (token1 = str; *token1 && *token1 == ' '; token1++); - for (e = 0; token1[e] && token1[e] != '='; e++); + /* Skip spaces before keyword */ + for (token1 = str; *token1 == ' '; token1++) + /* skip */ ; + /* Find end of keyword */ + for (e = 0; token1[e] && token1[e] != '='; e++) + /* skip */ ; if (token1[e]) /* found "=" */ { token1[e] = '\0'; - for (token2 = token1 + e + 1; *token2 && *token2 == ' '; token2++); - for (a = 0; token2[a] && token2[a] != '&'; a++); + /* Skip spaces before value */ + for (token2 = token1 + e + 1; *token2 == ' '; token2++) + /* skip */ ; + /* Find end of value */ + for (a = 0; token2[a] && token2[a] != '&'; a++) + /* skip */ ; if (token2[a]) /* found "&" => another option follows */ { token2[a] = '\0'; @@ -614,11 +626,14 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p i++; } else - /* the parser should not be able to create this invalid option */ + { + /* Bogus options syntax ... ignore trailing garbage */ str = token1 + e; + } } - } + + Assert(i <= connect_params); conn_keywords[i] = NULL; /* terminator */ this->connection = PQconnectdbParams(conn_keywords, conn_values, 0); -- 2.40.0