Here are the rest. Most of it was pretty straightforward, with the main exception of jsonpath_scan.c, which is not quite finished. That one passes tests but still has one compiler warning. I'm unsure how much of what is there already is really necessary or was cargo-culted from elsewhere without explanation. For starters, I'm not sure why the grammar has a forward declaration of "union YYSTYPE". It's noteworthy that it used to compile standalone, but with a bit more stuff, and that was reverted in 550b9d26f80fa30. I can hack on it some more later but I ran out of steam today.
Other questions thus far: - "BISONFLAGS += -d" is now in every make file with a .y file -- can we just force that everywhere? - Include order seems to matter for the grammar's .h file. I didn't test if that was the case every time, and after a few miscompiles just always made it the last inclusion, but I'm wondering if we should keep those inclusions outside %top{} and put it at the start of the next %{} ? - contrib/cubeparse.y now has a global variable -- not terrific, but I wanted to get something working first. - I'm actually okay with guc-file.c now, but I'll still welcome comments on that. -- John Naylor EDB: http://www.enterprisedb.com
From da2b610b8608e6759f5ed9cc32b487ea8e750ce4 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Fri, 12 Aug 2022 17:09:45 +0700 Subject: [PATCH v201 3/9] Build repl_scanner.c standalone --- src/backend/replication/Makefile | 11 +++++++++-- src/backend/replication/repl_gram.y | 2 -- src/backend/replication/repl_scanner.l | 27 +++++++++++++++----------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/backend/replication/Makefile b/src/backend/replication/Makefile index 2bffac58c0..bc8170418f 100644 --- a/src/backend/replication/Makefile +++ b/src/backend/replication/Makefile @@ -16,6 +16,7 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) OBJS = \ repl_gram.o \ + repl_scanner.o \ slot.o \ slotfuncs.o \ syncrep.o \ @@ -28,8 +29,14 @@ SUBDIRS = logical include $(top_srcdir)/src/backend/common.mk -# repl_scanner is compiled as part of repl_gram -repl_gram.o: repl_scanner.c +# See notes in src/backend/parser/Makefile about the following two rules +repl_gram.h: repl_gram.c + touch $@ + +repl_gram.c: BISONFLAGS += -d + +# Force these dependencies to be known even without dependency info built: +repl_gram.o repl_scanner.o: repl_gram.h # syncrep_scanner is compiled as part of syncrep_gram syncrep_gram.o: syncrep_scanner.c diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index 4cf087e602..b343f108d3 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -416,5 +416,3 @@ ident_or_keyword: ; %% - -#include "repl_scanner.c" diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l index 586f0d3a5c..95a933c9a8 100644 --- a/src/backend/replication/repl_scanner.l +++ b/src/backend/replication/repl_scanner.l @@ -1,4 +1,4 @@ -%{ +%top{ /*------------------------------------------------------------------------- * * repl_scanner.l @@ -17,7 +17,12 @@ #include "utils/builtins.h" #include "parser/scansup.h" +#include "replication/walsender_private.h" + +#include "repl_gram.h" +} +%{ /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */ #undef fprintf #define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg) @@ -130,7 +135,7 @@ WAIT { return K_WAIT; } {space}+ { /* do nothing */ } {digit}+ { - yylval.uintval = strtoul(yytext, NULL, 10); + replication_yylval.uintval = strtoul(yytext, NULL, 10); return UCONST; } @@ -138,8 +143,8 @@ WAIT { return K_WAIT; } uint32 hi, lo; if (sscanf(yytext, "%X/%X", &hi, &lo) != 2) - yyerror("invalid streaming start location"); - yylval.recptr = ((uint64) hi) << 32 | lo; + replication_yyerror("invalid streaming start location"); + replication_yylval.recptr = ((uint64) hi) << 32 | lo; return RECPTR; } @@ -151,7 +156,7 @@ WAIT { return K_WAIT; } <xq>{quotestop} { yyless(1); BEGIN(INITIAL); - yylval.str = litbufdup(); + replication_yylval.str = litbufdup(); return SCONST; } @@ -173,9 +178,9 @@ WAIT { return K_WAIT; } yyless(1); BEGIN(INITIAL); - yylval.str = litbufdup(); - len = strlen(yylval.str); - truncate_identifier(yylval.str, len, true); + replication_yylval.str = litbufdup(); + len = strlen(replication_yylval.str); + truncate_identifier(replication_yylval.str, len, true); return IDENT; } @@ -186,7 +191,7 @@ WAIT { return K_WAIT; } {identifier} { int len = strlen(yytext); - yylval.str = downcase_truncate_identifier(yytext, len, true); + replication_yylval.str = downcase_truncate_identifier(yytext, len, true); return IDENT; } @@ -195,7 +200,7 @@ WAIT { return K_WAIT; } return yytext[0]; } -<xq,xd><<EOF>> { yyerror("unterminated quoted string"); } +<xq,xd><<EOF>> { replication_yyerror("unterminated quoted string"); } <<EOF>> { @@ -231,7 +236,7 @@ addlitchar(unsigned char ychar) } void -yyerror(const char *message) +replication_yyerror(const char *message) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), -- 2.36.1
From d723ba14acf56fd432e9e263db937fcc13fc0355 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Thu, 11 Aug 2022 19:38:37 +0700 Subject: [PATCH v201 1/9] Build guc-file.c standalone The proposed Meson build system will need a way to ignore certain generated files in order to coexist with the autoconf build system, and #include'd C files generated by Flex make this more difficult. Build guc-file.c separately from guc.c, as was done in 72b1e3a21. TODO: other Flex-generated files Discussion: https://www.postgresql.org/message-id/20220810171935.7k5zgnjwqzalzmtm%40awork3.anarazel.de --- src/backend/utils/misc/Makefile | 5 +- src/backend/utils/misc/guc-file.l | 367 +----------------------------- src/backend/utils/misc/guc.c | 362 ++++++++++++++++++++++++++++- src/include/utils/guc.h | 9 + 4 files changed, 370 insertions(+), 373 deletions(-) diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index 1d5327cf64..cf7ce9bc83 100644 --- a/src/backend/utils/misc/Makefile +++ b/src/backend/utils/misc/Makefile @@ -16,6 +16,7 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) OBJS = \ guc.o \ + guc-file.o \ help_config.o \ pg_config.o \ pg_controldata.o \ @@ -37,10 +38,6 @@ endif include $(top_srcdir)/src/backend/common.mk -# guc-file is compiled as part of guc -guc.o: guc-file.c - # Note: guc-file.c is not deleted by 'make clean', # since we want to ship it in distribution tarballs. clean: - @rm -f lex.yy.c diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index ce5633844c..08adb454de 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -7,7 +7,7 @@ * src/backend/utils/misc/guc-file.l */ -%{ +%top{ #include "postgres.h" @@ -17,9 +17,12 @@ #include "mb/pg_wchar.h" #include "miscadmin.h" #include "storage/fd.h" +#include <sys/stat.h> #include "utils/guc.h" +#include "utils/memutils.h" +} - +%{ /* * flex emits a yy_fatal_error() function that it calls in response to * critical errors like malloc failure, file I/O errors, and detection of @@ -48,12 +51,6 @@ static sigjmp_buf *GUC_flex_fatal_jmp; static void FreeConfigVariable(ConfigVariable *item); -static void record_config_file_error(const char *errmsg, - const char *config_file, - int lineno, - ConfigVariable **head_p, - ConfigVariable **tail_p); - static int GUC_flex_fatal(const char *msg); /* LCOV_EXCL_START */ @@ -159,358 +156,6 @@ ProcessConfigFile(GucContext context) MemoryContextDelete(config_cxt); } -/* - * This function handles both actual config file (re)loads and execution of - * show_all_file_settings() (i.e., the pg_file_settings view). In the latter - * case we don't apply any of the settings, but we make all the usual validity - * checks, and we return the ConfigVariable list so that it can be printed out - * by show_all_file_settings(). - */ -static ConfigVariable * -ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel) -{ - bool error = false; - bool applying = false; - const char *ConfFileWithError; - ConfigVariable *item, - *head, - *tail; - int i; - - /* Parse the main config file into a list of option names and values */ - ConfFileWithError = ConfigFileName; - head = tail = NULL; - - if (!ParseConfigFile(ConfigFileName, true, - NULL, 0, 0, elevel, - &head, &tail)) - { - /* Syntax error(s) detected in the file, so bail out */ - error = true; - goto bail_out; - } - - /* - * Parse the PG_AUTOCONF_FILENAME file, if present, after the main file to - * replace any parameters set by ALTER SYSTEM command. Because this file - * is in the data directory, we can't read it until the DataDir has been - * set. - */ - if (DataDir) - { - if (!ParseConfigFile(PG_AUTOCONF_FILENAME, false, - NULL, 0, 0, elevel, - &head, &tail)) - { - /* Syntax error(s) detected in the file, so bail out */ - error = true; - ConfFileWithError = PG_AUTOCONF_FILENAME; - goto bail_out; - } - } - else - { - /* - * If DataDir is not set, the PG_AUTOCONF_FILENAME file cannot be - * read. In this case, we don't want to accept any settings but - * data_directory from postgresql.conf, because they might be - * overwritten with settings in the PG_AUTOCONF_FILENAME file which - * will be read later. OTOH, since data_directory isn't allowed in the - * PG_AUTOCONF_FILENAME file, it will never be overwritten later. - */ - ConfigVariable *newlist = NULL; - - /* - * Prune all items except the last "data_directory" from the list. - */ - for (item = head; item; item = item->next) - { - if (!item->ignore && - strcmp(item->name, "data_directory") == 0) - newlist = item; - } - - if (newlist) - newlist->next = NULL; - head = tail = newlist; - - /* - * Quick exit if data_directory is not present in file. - * - * We need not do any further processing, in particular we don't set - * PgReloadTime; that will be set soon by subsequent full loading of - * the config file. - */ - if (head == NULL) - goto bail_out; - } - - /* - * Mark all extant GUC variables as not present in the config file. We - * need this so that we can tell below which ones have been removed from - * the file since we last processed it. - */ - for (i = 0; i < num_guc_variables; i++) - { - struct config_generic *gconf = guc_variables[i]; - - gconf->status &= ~GUC_IS_IN_FILE; - } - - /* - * Check if all the supplied option names are valid, as an additional - * quasi-syntactic check on the validity of the config file. It is - * important that the postmaster and all backends agree on the results of - * this phase, else we will have strange inconsistencies about which - * processes accept a config file update and which don't. Hence, unknown - * custom variable names have to be accepted without complaint. For the - * same reason, we don't attempt to validate the options' values here. - * - * In addition, the GUC_IS_IN_FILE flag is set on each existing GUC - * variable mentioned in the file; and we detect duplicate entries in the - * file and mark the earlier occurrences as ignorable. - */ - for (item = head; item; item = item->next) - { - struct config_generic *record; - - /* Ignore anything already marked as ignorable */ - if (item->ignore) - continue; - - /* - * Try to find the variable; but do not create a custom placeholder if - * it's not there already. - */ - record = find_option(item->name, false, true, elevel); - - if (record) - { - /* If it's already marked, then this is a duplicate entry */ - if (record->status & GUC_IS_IN_FILE) - { - /* - * Mark the earlier occurrence(s) as dead/ignorable. We could - * avoid the O(N^2) behavior here with some additional state, - * but it seems unlikely to be worth the trouble. - */ - ConfigVariable *pitem; - - for (pitem = head; pitem != item; pitem = pitem->next) - { - if (!pitem->ignore && - strcmp(pitem->name, item->name) == 0) - pitem->ignore = true; - } - } - /* Now mark it as present in file */ - record->status |= GUC_IS_IN_FILE; - } - else if (!valid_custom_variable_name(item->name)) - { - /* Invalid non-custom variable, so complain */ - ereport(elevel, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %d", - item->name, - item->filename, item->sourceline))); - item->errmsg = pstrdup("unrecognized configuration parameter"); - error = true; - ConfFileWithError = item->filename; - } - } - - /* - * If we've detected any errors so far, we don't want to risk applying any - * changes. - */ - if (error) - goto bail_out; - - /* Otherwise, set flag that we're beginning to apply changes */ - applying = true; - - /* - * Check for variables having been removed from the config file, and - * revert their reset values (and perhaps also effective values) to the - * boot-time defaults. If such a variable can't be changed after startup, - * report that and continue. - */ - for (i = 0; i < num_guc_variables; i++) - { - struct config_generic *gconf = guc_variables[i]; - GucStack *stack; - - if (gconf->reset_source != PGC_S_FILE || - (gconf->status & GUC_IS_IN_FILE)) - continue; - if (gconf->context < PGC_SIGHUP) - { - /* The removal can't be effective without a restart */ - gconf->status |= GUC_PENDING_RESTART; - ereport(elevel, - (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), - errmsg("parameter \"%s\" cannot be changed without restarting the server", - gconf->name))); - record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server", - gconf->name), - NULL, 0, - &head, &tail); - error = true; - continue; - } - - /* No more to do if we're just doing show_all_file_settings() */ - if (!applySettings) - continue; - - /* - * Reset any "file" sources to "default", else set_config_option will - * not override those settings. - */ - if (gconf->reset_source == PGC_S_FILE) - gconf->reset_source = PGC_S_DEFAULT; - if (gconf->source == PGC_S_FILE) - gconf->source = PGC_S_DEFAULT; - for (stack = gconf->stack; stack; stack = stack->prev) - { - if (stack->source == PGC_S_FILE) - stack->source = PGC_S_DEFAULT; - } - - /* Now we can re-apply the wired-in default (i.e., the boot_val) */ - if (set_config_option(gconf->name, NULL, - context, PGC_S_DEFAULT, - GUC_ACTION_SET, true, 0, false) > 0) - { - /* Log the change if appropriate */ - if (context == PGC_SIGHUP) - ereport(elevel, - (errmsg("parameter \"%s\" removed from configuration file, reset to default", - gconf->name))); - } - } - - /* - * Restore any variables determined by environment variables or - * dynamically-computed defaults. This is a no-op except in the case - * where one of these had been in the config file and is now removed. - * - * In particular, we *must not* do this during the postmaster's initial - * loading of the file, since the timezone functions in particular should - * be run only after initialization is complete. - * - * XXX this is an unmaintainable crock, because we have to know how to set - * (or at least what to call to set) every non-PGC_INTERNAL variable that - * could potentially have PGC_S_DYNAMIC_DEFAULT or PGC_S_ENV_VAR source. - */ - if (context == PGC_SIGHUP && applySettings) - { - InitializeGUCOptionsFromEnvironment(); - pg_timezone_abbrev_initialize(); - /* this selects SQL_ASCII in processes not connected to a database */ - SetConfigOption("client_encoding", GetDatabaseEncodingName(), - PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT); - } - - /* - * Now apply the values from the config file. - */ - for (item = head; item; item = item->next) - { - char *pre_value = NULL; - int scres; - - /* Ignore anything marked as ignorable */ - if (item->ignore) - continue; - - /* In SIGHUP cases in the postmaster, we want to report changes */ - if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster) - { - const char *preval = GetConfigOption(item->name, true, false); - - /* If option doesn't exist yet or is NULL, treat as empty string */ - if (!preval) - preval = ""; - /* must dup, else might have dangling pointer below */ - pre_value = pstrdup(preval); - } - - scres = set_config_option(item->name, item->value, - context, PGC_S_FILE, - GUC_ACTION_SET, applySettings, 0, false); - if (scres > 0) - { - /* variable was updated, so log the change if appropriate */ - if (pre_value) - { - const char *post_value = GetConfigOption(item->name, true, false); - - if (!post_value) - post_value = ""; - if (strcmp(pre_value, post_value) != 0) - ereport(elevel, - (errmsg("parameter \"%s\" changed to \"%s\"", - item->name, item->value))); - } - item->applied = true; - } - else if (scres == 0) - { - error = true; - item->errmsg = pstrdup("setting could not be applied"); - ConfFileWithError = item->filename; - } - else - { - /* no error, but variable's active value was not changed */ - item->applied = true; - } - - /* - * We should update source location unless there was an error, since - * even if the active value didn't change, the reset value might have. - * (In the postmaster, there won't be a difference, but it does matter - * in backends.) - */ - if (scres != 0 && applySettings) - set_config_sourcefile(item->name, item->filename, - item->sourceline); - - if (pre_value) - pfree(pre_value); - } - - /* Remember when we last successfully loaded the config file. */ - if (applySettings) - PgReloadTime = GetCurrentTimestamp(); - -bail_out: - if (error && applySettings) - { - /* During postmaster startup, any error is fatal */ - if (context == PGC_POSTMASTER) - ereport(ERROR, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("configuration file \"%s\" contains errors", - ConfFileWithError))); - else if (applying) - ereport(elevel, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("configuration file \"%s\" contains errors; unaffected changes were applied", - ConfFileWithError))); - else - ereport(elevel, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("configuration file \"%s\" contains errors; no changes were applied", - ConfFileWithError))); - } - - /* Successful or otherwise, return the collected data list */ - return head; -} - /* * Given a configuration file or directory location that may be a relative * path, return an absolute one. We consider the location to be relative to @@ -659,7 +304,7 @@ cleanup: * Capture an error message in the ConfigVariable list returned by * config file parsing. */ -static void +void record_config_file_error(const char *errmsg, const char *config_file, int lineno, diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 5db5df6285..e4a00f1205 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -243,10 +243,6 @@ static void assign_recovery_target_lsn(const char *newval, void *extra); static bool check_primary_slot_name(char **newval, void **extra, GucSource source); static bool check_default_with_oids(bool *newval, void **extra, GucSource source); -/* Private functions in guc-file.l that need to be called from guc.c */ -static ConfigVariable *ProcessConfigFileInternal(GucContext context, - bool applySettings, int elevel); - /* * Track whether there were any deferred checks for custom resource managers * specified in wal_consistency_checking. @@ -5164,8 +5160,8 @@ static bool report_needed; /* true if any GUC_REPORT reports are needed */ static int GUCNestLevel = 0; /* 1 when in main transaction */ +static struct config_generic *find_option(const char *name, bool create_placeholders, bool skip_errors, int elevel); static int guc_var_compare(const void *a, const void *b); -static int guc_name_compare(const char *namea, const char *nameb); static void InitializeGUCOptionsFromEnvironment(void); static void InitializeOneGUCOption(struct config_generic *gconf); static void push_old_value(struct config_generic *gconf, GucAction action); @@ -5184,7 +5180,359 @@ static bool validate_option_array_item(const char *name, const char *value, static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head_p); static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p, const char *name, const char *value); +static bool valid_custom_variable_name(const char *name); + +/* + * This function handles both actual config file (re)loads and execution of + * show_all_file_settings() (i.e., the pg_file_settings view). In the latter + * case we don't apply any of the settings, but we make all the usual validity + * checks, and we return the ConfigVariable list so that it can be printed out + * by show_all_file_settings(). + */ +ConfigVariable * +ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel) +{ + bool error = false; + bool applying = false; + const char *ConfFileWithError; + ConfigVariable *item, + *head, + *tail; + int i; + + /* Parse the main config file into a list of option names and values */ + ConfFileWithError = ConfigFileName; + head = tail = NULL; + + if (!ParseConfigFile(ConfigFileName, true, + NULL, 0, 0, elevel, + &head, &tail)) + { + /* Syntax error(s) detected in the file, so bail out */ + error = true; + goto bail_out; + } + + /* + * Parse the PG_AUTOCONF_FILENAME file, if present, after the main file to + * replace any parameters set by ALTER SYSTEM command. Because this file + * is in the data directory, we can't read it until the DataDir has been + * set. + */ + if (DataDir) + { + if (!ParseConfigFile(PG_AUTOCONF_FILENAME, false, + NULL, 0, 0, elevel, + &head, &tail)) + { + /* Syntax error(s) detected in the file, so bail out */ + error = true; + ConfFileWithError = PG_AUTOCONF_FILENAME; + goto bail_out; + } + } + else + { + /* + * If DataDir is not set, the PG_AUTOCONF_FILENAME file cannot be + * read. In this case, we don't want to accept any settings but + * data_directory from postgresql.conf, because they might be + * overwritten with settings in the PG_AUTOCONF_FILENAME file which + * will be read later. OTOH, since data_directory isn't allowed in the + * PG_AUTOCONF_FILENAME file, it will never be overwritten later. + */ + ConfigVariable *newlist = NULL; + + /* + * Prune all items except the last "data_directory" from the list. + */ + for (item = head; item; item = item->next) + { + if (!item->ignore && + strcmp(item->name, "data_directory") == 0) + newlist = item; + } + + if (newlist) + newlist->next = NULL; + head = tail = newlist; + + /* + * Quick exit if data_directory is not present in file. + * + * We need not do any further processing, in particular we don't set + * PgReloadTime; that will be set soon by subsequent full loading of + * the config file. + */ + if (head == NULL) + goto bail_out; + } + + /* + * Mark all extant GUC variables as not present in the config file. We + * need this so that we can tell below which ones have been removed from + * the file since we last processed it. + */ + for (i = 0; i < num_guc_variables; i++) + { + struct config_generic *gconf = guc_variables[i]; + + gconf->status &= ~GUC_IS_IN_FILE; + } + + /* + * Check if all the supplied option names are valid, as an additional + * quasi-syntactic check on the validity of the config file. It is + * important that the postmaster and all backends agree on the results of + * this phase, else we will have strange inconsistencies about which + * processes accept a config file update and which don't. Hence, unknown + * custom variable names have to be accepted without complaint. For the + * same reason, we don't attempt to validate the options' values here. + * + * In addition, the GUC_IS_IN_FILE flag is set on each existing GUC + * variable mentioned in the file; and we detect duplicate entries in the + * file and mark the earlier occurrences as ignorable. + */ + for (item = head; item; item = item->next) + { + struct config_generic *record; + + /* Ignore anything already marked as ignorable */ + if (item->ignore) + continue; + + /* + * Try to find the variable; but do not create a custom placeholder if + * it's not there already. + */ + record = find_option(item->name, false, true, elevel); + + if (record) + { + /* If it's already marked, then this is a duplicate entry */ + if (record->status & GUC_IS_IN_FILE) + { + /* + * Mark the earlier occurrence(s) as dead/ignorable. We could + * avoid the O(N^2) behavior here with some additional state, + * but it seems unlikely to be worth the trouble. + */ + ConfigVariable *pitem; + + for (pitem = head; pitem != item; pitem = pitem->next) + { + if (!pitem->ignore && + strcmp(pitem->name, item->name) == 0) + pitem->ignore = true; + } + } + /* Now mark it as present in file */ + record->status |= GUC_IS_IN_FILE; + } + else if (!valid_custom_variable_name(item->name)) + { + /* Invalid non-custom variable, so complain */ + ereport(elevel, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %d", + item->name, + item->filename, item->sourceline))); + item->errmsg = pstrdup("unrecognized configuration parameter"); + error = true; + ConfFileWithError = item->filename; + } + } + + /* + * If we've detected any errors so far, we don't want to risk applying any + * changes. + */ + if (error) + goto bail_out; + + /* Otherwise, set flag that we're beginning to apply changes */ + applying = true; + + /* + * Check for variables having been removed from the config file, and + * revert their reset values (and perhaps also effective values) to the + * boot-time defaults. If such a variable can't be changed after startup, + * report that and continue. + */ + for (i = 0; i < num_guc_variables; i++) + { + struct config_generic *gconf = guc_variables[i]; + GucStack *stack; + + if (gconf->reset_source != PGC_S_FILE || + (gconf->status & GUC_IS_IN_FILE)) + continue; + if (gconf->context < PGC_SIGHUP) + { + /* The removal can't be effective without a restart */ + gconf->status |= GUC_PENDING_RESTART; + ereport(elevel, + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed without restarting the server", + gconf->name))); + record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server", + gconf->name), + NULL, 0, + &head, &tail); + error = true; + continue; + } + + /* No more to do if we're just doing show_all_file_settings() */ + if (!applySettings) + continue; + + /* + * Reset any "file" sources to "default", else set_config_option will + * not override those settings. + */ + if (gconf->reset_source == PGC_S_FILE) + gconf->reset_source = PGC_S_DEFAULT; + if (gconf->source == PGC_S_FILE) + gconf->source = PGC_S_DEFAULT; + for (stack = gconf->stack; stack; stack = stack->prev) + { + if (stack->source == PGC_S_FILE) + stack->source = PGC_S_DEFAULT; + } + + /* Now we can re-apply the wired-in default (i.e., the boot_val) */ + if (set_config_option(gconf->name, NULL, + context, PGC_S_DEFAULT, + GUC_ACTION_SET, true, 0, false) > 0) + { + /* Log the change if appropriate */ + if (context == PGC_SIGHUP) + ereport(elevel, + (errmsg("parameter \"%s\" removed from configuration file, reset to default", + gconf->name))); + } + } + + /* + * Restore any variables determined by environment variables or + * dynamically-computed defaults. This is a no-op except in the case + * where one of these had been in the config file and is now removed. + * + * In particular, we *must not* do this during the postmaster's initial + * loading of the file, since the timezone functions in particular should + * be run only after initialization is complete. + * + * XXX this is an unmaintainable crock, because we have to know how to set + * (or at least what to call to set) every non-PGC_INTERNAL variable that + * could potentially have PGC_S_DYNAMIC_DEFAULT or PGC_S_ENV_VAR source. + */ + if (context == PGC_SIGHUP && applySettings) + { + InitializeGUCOptionsFromEnvironment(); + pg_timezone_abbrev_initialize(); + /* this selects SQL_ASCII in processes not connected to a database */ + SetConfigOption("client_encoding", GetDatabaseEncodingName(), + PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT); + } + /* + * Now apply the values from the config file. + */ + for (item = head; item; item = item->next) + { + char *pre_value = NULL; + int scres; + + /* Ignore anything marked as ignorable */ + if (item->ignore) + continue; + + /* In SIGHUP cases in the postmaster, we want to report changes */ + if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster) + { + const char *preval = GetConfigOption(item->name, true, false); + + /* If option doesn't exist yet or is NULL, treat as empty string */ + if (!preval) + preval = ""; + /* must dup, else might have dangling pointer below */ + pre_value = pstrdup(preval); + } + + scres = set_config_option(item->name, item->value, + context, PGC_S_FILE, + GUC_ACTION_SET, applySettings, 0, false); + if (scres > 0) + { + /* variable was updated, so log the change if appropriate */ + if (pre_value) + { + const char *post_value = GetConfigOption(item->name, true, false); + + if (!post_value) + post_value = ""; + if (strcmp(pre_value, post_value) != 0) + ereport(elevel, + (errmsg("parameter \"%s\" changed to \"%s\"", + item->name, item->value))); + } + item->applied = true; + } + else if (scres == 0) + { + error = true; + item->errmsg = pstrdup("setting could not be applied"); + ConfFileWithError = item->filename; + } + else + { + /* no error, but variable's active value was not changed */ + item->applied = true; + } + + /* + * We should update source location unless there was an error, since + * even if the active value didn't change, the reset value might have. + * (In the postmaster, there won't be a difference, but it does matter + * in backends.) + */ + if (scres != 0 && applySettings) + set_config_sourcefile(item->name, item->filename, + item->sourceline); + + if (pre_value) + pfree(pre_value); + } + + /* Remember when we last successfully loaded the config file. */ + if (applySettings) + PgReloadTime = GetCurrentTimestamp(); + +bail_out: + if (error && applySettings) + { + /* During postmaster startup, any error is fatal */ + if (context == PGC_POSTMASTER) + ereport(ERROR, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("configuration file \"%s\" contains errors", + ConfFileWithError))); + else if (applying) + ereport(elevel, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("configuration file \"%s\" contains errors; unaffected changes were applied", + ConfFileWithError))); + else + ereport(elevel, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("configuration file \"%s\" contains errors; no changes were applied", + ConfFileWithError))); + } + + /* Successful or otherwise, return the collected data list */ + return head; +} /* * Some infrastructure for checking malloc/strdup/realloc calls @@ -5741,7 +6089,7 @@ guc_var_compare(const void *a, const void *b) /* * the bare comparison function for GUC names */ -static int +int guc_name_compare(const char *namea, const char *nameb) { /* @@ -12988,5 +13336,3 @@ check_default_with_oids(bool *newval, void **extra, GucSource source) return true; } - -#include "guc-file.c" diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index e734493a48..aae071cd82 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -442,6 +442,15 @@ extern void GUC_check_errcode(int sqlerrcode); pre_format_elog_string(errno, TEXTDOMAIN), \ GUC_check_errhint_string = format_elog_string +/* functions shared between guc.c and guc-file.l */ +extern int guc_name_compare(const char *namea, const char *nameb); +extern ConfigVariable *ProcessConfigFileInternal(GucContext context, + bool applySettings, int elevel); +extern void record_config_file_error(const char *errmsg, + const char *config_file, + int lineno, + ConfigVariable **head_p, + ConfigVariable **tail_p); /* * The following functions are not in guc.c, but are declared here to avoid -- 2.36.1
From 4c105b7b415f0937e7fa42e8313c9452a8db1ad4 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Sat, 13 Aug 2022 09:34:17 +0700 Subject: [PATCH v201 5/9] Build specscanner.c standalone --- src/test/isolation/.gitignore | 1 + src/test/isolation/Makefile | 15 +++++++++++---- src/test/isolation/specparse.y | 2 -- src/test/isolation/specscanner.l | 25 ++++++++++++++++--------- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/test/isolation/.gitignore b/src/test/isolation/.gitignore index 870dac4d28..2c13b4bf98 100644 --- a/src/test/isolation/.gitignore +++ b/src/test/isolation/.gitignore @@ -3,6 +3,7 @@ /pg_isolation_regress # Local generated source files +/specparse.h /specparse.c /specscanner.c diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile index 0d452c89d4..b8738b7c1b 100644 --- a/src/test/isolation/Makefile +++ b/src/test/isolation/Makefile @@ -15,7 +15,8 @@ override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) \ OBJS = \ $(WIN32RES) \ isolationtester.o \ - specparse.o + specparse.o \ + specscanner.o all: isolationtester$(X) pg_isolation_regress$(X) @@ -44,8 +45,14 @@ isolationtester$(X): $(OBJS) | submake-libpq submake-libpgport distprep: specparse.c specscanner.c -# specscanner is compiled as part of specparse -specparse.o: specscanner.c +# See notes in src/backend/parser/Makefile about the following two rules +specparse.h: specparse.c + touch $@ + +specparse.c: BISONFLAGS += -d + +# Force these dependencies to be known even without dependency info built: +specparse.o specscanner.o: specparse.h # specparse.c and specscanner.c are in the distribution tarball, # so do not clean them here @@ -55,7 +62,7 @@ clean distclean: rm -rf $(pg_regress_clean_files) maintainer-clean: distclean - rm -f specparse.c specscanner.c + rm -f specparse.h specparse.c specscanner.c installcheck: all $(pg_isolation_regress_installcheck) --schedule=$(srcdir)/isolation_schedule diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y index eb368184b8..657285cc23 100644 --- a/src/test/isolation/specparse.y +++ b/src/test/isolation/specparse.y @@ -276,5 +276,3 @@ blocker: ; %% - -#include "specscanner.c" diff --git a/src/test/isolation/specscanner.l b/src/test/isolation/specscanner.l index aa6e89268e..2dc292c21d 100644 --- a/src/test/isolation/specscanner.l +++ b/src/test/isolation/specscanner.l @@ -1,4 +1,4 @@ -%{ +%top{ /*------------------------------------------------------------------------- * * specscanner.l @@ -9,7 +9,14 @@ * *------------------------------------------------------------------------- */ +#include "postgres_fe.h" + +#include "isolationtester.h" +#include "specparse.h" +} + +%{ static int yyline = 1; /* line number for error reporting */ #define LITBUF_INIT 1024 /* initial size of litbuf */ @@ -75,7 +82,7 @@ teardown { return TEARDOWN; } /* Plain identifiers */ {identifier} { - yylval.str = pg_strdup(yytext); + spec_yylval.str = pg_strdup(yytext); return(identifier); } @@ -87,13 +94,13 @@ teardown { return TEARDOWN; } <qident>\"\" { addlitchar(yytext[0]); } <qident>\" { litbuf[litbufpos] = '\0'; - yylval.str = pg_strdup(litbuf); + spec_yylval.str = pg_strdup(litbuf); BEGIN(INITIAL); return(identifier); } <qident>. { addlitchar(yytext[0]); } -<qident>\n { yyerror("unexpected newline in quoted identifier"); } -<qident><<EOF>> { yyerror("unterminated quoted identifier"); } +<qident>\n { spec_yyerror("unexpected newline in quoted identifier"); } +<qident><<EOF>> { spec_yyerror("unterminated quoted identifier"); } /* SQL blocks: { UPDATE ... } */ /* We trim leading/trailing whitespace, otherwise they're unprocessed */ @@ -104,7 +111,7 @@ teardown { return TEARDOWN; } } <sql>{space}*"}" { litbuf[litbufpos] = '\0'; - yylval.str = pg_strdup(litbuf); + spec_yylval.str = pg_strdup(litbuf); BEGIN(INITIAL); return(sqlblock); } @@ -116,12 +123,12 @@ teardown { return TEARDOWN; } addlitchar(yytext[0]); } <sql><<EOF>> { - yyerror("unterminated sql block"); + spec_yyerror("unterminated sql block"); } /* Numbers and punctuation */ {digit}+ { - yylval.integer = atoi(yytext); + spec_yylval.integer = atoi(yytext); return INTEGER; } @@ -150,7 +157,7 @@ addlitchar(char c) } void -yyerror(const char *message) +spec_yyerror(const char *message) { fprintf(stderr, "%s at line %d\n", message, yyline); exit(1); -- 2.36.1
From 92d48ac8354bce8bb57a43e01448835e1cd75871 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Fri, 12 Aug 2022 18:27:39 +0700 Subject: [PATCH v201 4/9] Build syncrep_scanner.c standalone --- src/backend/replication/.gitignore | 1 + src/backend/replication/Makefile | 11 +++++++++-- src/backend/replication/syncrep_gram.y | 2 -- src/backend/replication/syncrep_scanner.l | 17 +++++++++++------ 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/backend/replication/.gitignore b/src/backend/replication/.gitignore index d1df6147bd..ad138c0c98 100644 --- a/src/backend/replication/.gitignore +++ b/src/backend/replication/.gitignore @@ -1,4 +1,5 @@ /repl_gram.c /repl_scanner.c +/syncrep_gram.h /syncrep_gram.c /syncrep_scanner.c diff --git a/src/backend/replication/Makefile b/src/backend/replication/Makefile index bc8170418f..23f29ba545 100644 --- a/src/backend/replication/Makefile +++ b/src/backend/replication/Makefile @@ -21,6 +21,7 @@ OBJS = \ slotfuncs.o \ syncrep.o \ syncrep_gram.o \ + syncrep_scanner.o \ walreceiver.o \ walreceiverfuncs.o \ walsender.o @@ -38,8 +39,14 @@ repl_gram.c: BISONFLAGS += -d # Force these dependencies to be known even without dependency info built: repl_gram.o repl_scanner.o: repl_gram.h -# syncrep_scanner is compiled as part of syncrep_gram -syncrep_gram.o: syncrep_scanner.c +# See notes in src/backend/parser/Makefile about the following two rules +syncrep_gram.h: syncrep_gram.c + touch $@ + +syncrep_gram.c: BISONFLAGS += -d + +# Force these dependencies to be known even without dependency info built: +syncrep_gram.o syncrep_scanner.o: syncrep_gram.h # repl_gram.c, repl_scanner.c, syncrep_gram.c and syncrep_scanner.c # are in the distribution tarball, so they are not cleaned here. diff --git a/src/backend/replication/syncrep_gram.y b/src/backend/replication/syncrep_gram.y index d932f2cda3..4fc3647da1 100644 --- a/src/backend/replication/syncrep_gram.y +++ b/src/backend/replication/syncrep_gram.y @@ -112,5 +112,3 @@ create_syncrep_config(const char *num_sync, List *members, uint8 syncrep_method) return config; } - -#include "syncrep_scanner.c" diff --git a/src/backend/replication/syncrep_scanner.l b/src/backend/replication/syncrep_scanner.l index 1952c8c6e0..8f38cb4613 100644 --- a/src/backend/replication/syncrep_scanner.l +++ b/src/backend/replication/syncrep_scanner.l @@ -1,4 +1,4 @@ -%{ +%top{ /*------------------------------------------------------------------------- * * syncrep_scanner.l @@ -16,7 +16,12 @@ #include "postgres.h" #include "lib/stringinfo.h" +#include "replication/syncrep.h" + +#include "syncrep_gram.h" +} +%{ /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */ #undef fprintf #define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg) @@ -82,28 +87,28 @@ xdinside [^"]+ appendStringInfoString(&xdbuf, yytext); } <xd>{xdstop} { - yylval.str = xdbuf.data; + syncrep_yylval.str = xdbuf.data; xdbuf.data = NULL; BEGIN(INITIAL); return NAME; } <xd><<EOF>> { - yyerror("unterminated quoted identifier"); + syncrep_yyerror("unterminated quoted identifier"); return JUNK; } {identifier} { - yylval.str = pstrdup(yytext); + syncrep_yylval.str = pstrdup(yytext); return NAME; } {digit}+ { - yylval.str = pstrdup(yytext); + syncrep_yylval.str = pstrdup(yytext); return NUM; } "*" { - yylval.str = "*"; + syncrep_yylval.str = "*"; return NAME; } -- 2.36.1
From 7d4ecfcb3e91f3b45e94b9e64c7c40f1bbd22aa8 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Fri, 12 Aug 2022 15:45:24 +0700 Subject: [PATCH v201 2/9] Build booscanner.c standalone --- src/backend/bootstrap/.gitignore | 1 + src/backend/bootstrap/Makefile | 11 +++++- src/backend/bootstrap/bootparse.y | 2 - src/backend/bootstrap/bootscanner.l | 57 +++++++++++++++-------------- 4 files changed, 40 insertions(+), 31 deletions(-) diff --git a/src/backend/bootstrap/.gitignore b/src/backend/bootstrap/.gitignore index 1ffe8ca39e..6351b920fd 100644 --- a/src/backend/bootstrap/.gitignore +++ b/src/backend/bootstrap/.gitignore @@ -1,2 +1,3 @@ +/bootparse.h /bootparse.c /bootscanner.c diff --git a/src/backend/bootstrap/Makefile b/src/backend/bootstrap/Makefile index 6421efb227..c39eb7089c 100644 --- a/src/backend/bootstrap/Makefile +++ b/src/backend/bootstrap/Makefile @@ -14,12 +14,19 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) OBJS = \ bootparse.o \ + bootscanner.o \ bootstrap.o include $(top_srcdir)/src/backend/common.mk -# bootscanner is compiled as part of bootparse -bootparse.o: bootscanner.c +# See notes in src/backend/parser/Makefile about the following two rules +bootparse.h: bootparse.c + touch $@ + +bootparse.c: BISONFLAGS += -d + +# Force these dependencies to be known even without dependency info built: +bootparse.o bootscan.o: bootparse.h # bootparse.c and bootscanner.c are in the distribution tarball, so # they are not cleaned here. diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 7d7655d295..c45ddde67f 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -488,5 +488,3 @@ boot_ident: | XNULL { $$ = pstrdup($1); } ; %% - -#include "bootscanner.c" diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l index 3094ccb93f..3f916fbb93 100644 --- a/src/backend/bootstrap/bootscanner.l +++ b/src/backend/bootstrap/bootscanner.l @@ -1,4 +1,4 @@ -%{ +%top{ /*------------------------------------------------------------------------- * * bootscanner.l @@ -18,8 +18,11 @@ #include "bootstrap/bootstrap.h" #include "utils/guc.h" -/* Not needed now that this file is compiled as part of bootparse. */ -/* #include "bootparse.h" */ +/* XXX must be included after bootstrap.h */ +#include "bootparse.h" +} + +%{ /* LCOV_EXCL_START */ @@ -52,7 +55,7 @@ id [-A-Za-z0-9_]+ sid \'([^']|\'\')*\' /* - * Keyword tokens return the keyword text (as a constant string) in yylval.kw, + * Keyword tokens return the keyword text (as a constant string) in boot_yylval.kw, * just in case that's needed because we want to treat the keyword as an * unreserved identifier. Note that _null_ is not treated as a keyword * for this purpose; it's the one "reserved word" in the bootstrap syntax. @@ -60,23 +63,23 @@ sid \'([^']|\'\')*\' * Notice that all the keywords are case-sensitive, and for historical * reasons some must be upper case. * - * String tokens return a palloc'd string in yylval.str. + * String tokens return a palloc'd string in boot_yylval.str. */ %% -open { yylval.kw = "open"; return OPEN; } +open { boot_yylval.kw = "open"; return OPEN; } -close { yylval.kw = "close"; return XCLOSE; } +close { boot_yylval.kw = "close"; return XCLOSE; } -create { yylval.kw = "create"; return XCREATE; } +create { boot_yylval.kw = "create"; return XCREATE; } -OID { yylval.kw = "OID"; return OBJ_ID; } -bootstrap { yylval.kw = "bootstrap"; return XBOOTSTRAP; } -shared_relation { yylval.kw = "shared_relation"; return XSHARED_RELATION; } -rowtype_oid { yylval.kw = "rowtype_oid"; return XROWTYPE_OID; } +OID { boot_yylval.kw = "OID"; return OBJ_ID; } +bootstrap { boot_yylval.kw = "bootstrap"; return XBOOTSTRAP; } +shared_relation { boot_yylval.kw = "shared_relation"; return XSHARED_RELATION; } +rowtype_oid { boot_yylval.kw = "rowtype_oid"; return XROWTYPE_OID; } -insert { yylval.kw = "insert"; return INSERT_TUPLE; } +insert { boot_yylval.kw = "insert"; return INSERT_TUPLE; } _null_ { return NULLVAL; } @@ -90,25 +93,25 @@ _null_ { return NULLVAL; } ^\#[^\n]* ; /* drop everything after "#" for comments */ -declare { yylval.kw = "declare"; return XDECLARE; } -build { yylval.kw = "build"; return XBUILD; } -indices { yylval.kw = "indices"; return INDICES; } -unique { yylval.kw = "unique"; return UNIQUE; } -index { yylval.kw = "index"; return INDEX; } -on { yylval.kw = "on"; return ON; } -using { yylval.kw = "using"; return USING; } -toast { yylval.kw = "toast"; return XTOAST; } -FORCE { yylval.kw = "FORCE"; return XFORCE; } -NOT { yylval.kw = "NOT"; return XNOT; } -NULL { yylval.kw = "NULL"; return XNULL; } +declare { boot_yylval.kw = "declare"; return XDECLARE; } +build { boot_yylval.kw = "build"; return XBUILD; } +indices { boot_yylval.kw = "indices"; return INDICES; } +unique { boot_yylval.kw = "unique"; return UNIQUE; } +index { boot_yylval.kw = "index"; return INDEX; } +on { boot_yylval.kw = "on"; return ON; } +using { boot_yylval.kw = "using"; return USING; } +toast { boot_yylval.kw = "toast"; return XTOAST; } +FORCE { boot_yylval.kw = "FORCE"; return XFORCE; } +NOT { boot_yylval.kw = "NOT"; return XNOT; } +NULL { boot_yylval.kw = "NULL"; return XNULL; } {id} { - yylval.str = pstrdup(yytext); + boot_yylval.str = pstrdup(yytext); return ID; } {sid} { /* strip quotes and escapes */ - yylval.str = DeescapeQuotedString(yytext); + boot_yylval.str = DeescapeQuotedString(yytext); return ID; } @@ -121,7 +124,7 @@ NULL { yylval.kw = "NULL"; return XNULL; } /* LCOV_EXCL_STOP */ void -yyerror(const char *message) +boot_yyerror(const char *message) { elog(ERROR, "%s at line %d", message, yyline); } -- 2.36.1
From 75168640fbd4e2a23f2765b2918cd6a0676d0f74 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Sat, 13 Aug 2022 11:18:06 +0700 Subject: [PATCH v201 6/9] Build cubescan.c standalone --- contrib/cube/.gitignore | 1 + contrib/cube/Makefile | 16 ++++++++++------ contrib/cube/cubedata.h | 4 ++++ contrib/cube/cubeparse.y | 9 ++------- contrib/cube/cubescan.l | 33 +++++++++++++++++++-------------- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/contrib/cube/.gitignore b/contrib/cube/.gitignore index cb4c989fff..f788440c79 100644 --- a/contrib/cube/.gitignore +++ b/contrib/cube/.gitignore @@ -1,3 +1,4 @@ +/cubeparse.h /cubeparse.c /cubescan.c # Generated subdirectories diff --git a/contrib/cube/Makefile b/contrib/cube/Makefile index cf195506c7..4fd19aac35 100644 --- a/contrib/cube/Makefile +++ b/contrib/cube/Makefile @@ -4,7 +4,8 @@ MODULE_big = cube OBJS = \ $(WIN32RES) \ cube.o \ - cubeparse.o + cubeparse.o \ + cubescan.o EXTENSION = cube DATA = cube--1.2.sql cube--1.2--1.3.sql cube--1.3--1.4.sql cube--1.4--1.5.sql \ @@ -15,8 +16,6 @@ HEADERS = cubedata.h REGRESS = cube cube_sci -EXTRA_CLEAN = y.tab.c y.tab.h - SHLIB_LINK += $(filter -lm, $(LIBS)) ifdef USE_PGXS @@ -30,11 +29,16 @@ include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif +# See notes in src/backend/parser/Makefile about the following two rules +cubeparse.h: cubeparse.c + touch $@ + +cubeparse.c: BISONFLAGS += -d -# cubescan is compiled as part of cubeparse -cubeparse.o: cubescan.c +# Force these dependencies to be known even without dependency info built: +cubeparse.o cubescan.o: cubeparse.h distprep: cubeparse.c cubescan.c maintainer-clean: - rm -f cubeparse.c cubescan.c + rm -f cubeparse.h cubeparse.c cubescan.c diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h index dbe7d4f742..0b373048b5 100644 --- a/contrib/cube/cubedata.h +++ b/contrib/cube/cubedata.h @@ -67,3 +67,7 @@ extern void cube_scanner_finish(void); /* in cubeparse.y */ extern int cube_yyparse(NDBOX **result); + +/* All grammar constructs return strings */ +#define YYSTYPE char * +extern int scanbuflen; diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y index 7577c4515c..d3fd1fb475 100644 --- a/contrib/cube/cubeparse.y +++ b/contrib/cube/cubeparse.y @@ -9,9 +9,6 @@ #include "cubedata.h" #include "utils/float.h" -/* All grammar constructs return strings */ -#define YYSTYPE char * - /* * Bison doesn't allocate anything that needs to live across parser calls, * so we can easily have it use palloc instead of malloc. This prevents @@ -23,8 +20,8 @@ #define YYMALLOC palloc #define YYFREE pfree -static char *scanbuf; -static int scanbuflen; +// TODO: get rid of global var +int scanbuflen; static int item_count(const char *s, char delim); static NDBOX *write_box(int dim, char *str1, char *str2); @@ -265,5 +262,3 @@ write_point_as_box(int dim, char *str) return bp; } - -#include "cubescan.c" diff --git a/contrib/cube/cubescan.l b/contrib/cube/cubescan.l index bd400e3684..b7d35c6f78 100644 --- a/contrib/cube/cubescan.l +++ b/contrib/cube/cubescan.l @@ -1,9 +1,16 @@ -%{ +%top{ /* * A scanner for EMP-style numeric ranges * contrib/cube/cubescan.l */ +#include "postgres.h" +#include "cubedata.h" + +#include "cubeparse.h" +} + +%{ /* LCOV_EXCL_START */ /* No reason to constrain amount of data slurped */ @@ -21,9 +28,7 @@ fprintf_to_ereport(const char *fmt, const char *msg) /* Handles to the buffer that the lexer uses internally */ static YY_BUFFER_STATE scanbufhandle; -/* this is now declared in cubeparse.y: */ -/* static char *scanbuf; */ -/* static int scanbuflen; */ +static char *scanbuf; %} %option 8bit @@ -45,14 +50,14 @@ NaN [nN][aA][nN] %% -{float} yylval = yytext; return CUBEFLOAT; -{infinity} yylval = yytext; return CUBEFLOAT; -{NaN} yylval = yytext; return CUBEFLOAT; -\[ yylval = "("; return O_BRACKET; -\] yylval = ")"; return C_BRACKET; -\( yylval = "("; return O_PAREN; -\) yylval = ")"; return C_PAREN; -\, yylval = ","; return COMMA; +{float} cube_yylval = yytext; return CUBEFLOAT; +{infinity} cube_yylval = yytext; return CUBEFLOAT; +{NaN} cube_yylval = yytext; return CUBEFLOAT; +\[ cube_yylval = "("; return O_BRACKET; +\] cube_yylval = ")"; return C_BRACKET; +\( cube_yylval = "("; return O_PAREN; +\) cube_yylval = ")"; return C_PAREN; +\, cube_yylval = ","; return COMMA; [ \t\n\r\f]+ /* discard spaces */ . return yytext[0]; /* alert parser of the garbage */ @@ -62,7 +67,7 @@ NaN [nN][aA][nN] /* result is not used, but Bison expects this signature */ void -yyerror(NDBOX **result, const char *message) +cube_yyerror(NDBOX **result, const char *message) { if (*yytext == YY_END_OF_BUFFER_CHAR) { @@ -89,7 +94,7 @@ yyerror(NDBOX **result, const char *message) void cube_scanner_init(const char *str) { - Size slen = strlen(str); + Size slen = strlen(str); /* * Might be left over after ereport() -- 2.36.1
From 5170d8fac8bbb9e101e10f18ed280e446b305e26 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Sat, 13 Aug 2022 12:00:33 +0700 Subject: [PATCH v201 7/9] Build segscan.c standalone --- contrib/seg/.gitignore | 1 + contrib/seg/Makefile | 15 +++++++++++---- contrib/seg/segparse.y | 3 --- contrib/seg/segscan.l | 25 +++++++++++++++---------- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/contrib/seg/.gitignore b/contrib/seg/.gitignore index 69e73d2096..fa247a4e67 100644 --- a/contrib/seg/.gitignore +++ b/contrib/seg/.gitignore @@ -1,3 +1,4 @@ +/segparse.h /segparse.c /segscan.c # Generated subdirectories diff --git a/contrib/seg/Makefile b/contrib/seg/Makefile index bb63e83506..c6c134b8f1 100644 --- a/contrib/seg/Makefile +++ b/contrib/seg/Makefile @@ -4,7 +4,8 @@ MODULE_big = seg OBJS = \ $(WIN32RES) \ seg.o \ - segparse.o + segparse.o \ + segscan.o EXTENSION = seg DATA = seg--1.1.sql seg--1.1--1.2.sql seg--1.2--1.3.sql seg--1.3--1.4.sql \ @@ -29,10 +30,16 @@ include $(top_srcdir)/contrib/contrib-global.mk endif -# segscan is compiled as part of segparse -segparse.o: segscan.c +# See notes in src/backend/parser/Makefile about the following two rules +segparse.h: segparse.c + touch $@ + +segparse.c: BISONFLAGS += -d + +# Force these dependencies to be known even without dependency info built: +segparse.o segscan.o: segparse.h distprep: segparse.c segscan.c maintainer-clean: - rm -f segparse.c segscan.c + rm -f segparse.h segparse.c segscan.c diff --git a/contrib/seg/segparse.y b/contrib/seg/segparse.y index 33e3a9f35f..637eacd1a6 100644 --- a/contrib/seg/segparse.y +++ b/contrib/seg/segparse.y @@ -160,6 +160,3 @@ seg_atof(const char *value) datum = DirectFunctionCall1(float4in, CStringGetDatum(value)); return DatumGetFloat4(datum); } - - -#include "segscan.c" diff --git a/contrib/seg/segscan.l b/contrib/seg/segscan.l index 5f6595e9eb..db0db1aa70 100644 --- a/contrib/seg/segscan.l +++ b/contrib/seg/segscan.l @@ -1,8 +1,15 @@ -%{ +%top{ /* * A scanner for EMP-style numeric ranges */ +#include "postgres.h" + +#include "segdata.h" +#include "segparse.h" +} + +%{ /* LCOV_EXCL_START */ /* No reason to constrain amount of data slurped */ @@ -21,7 +28,6 @@ fprintf_to_ereport(const char *fmt, const char *msg) /* Handles to the buffer that the lexer uses internally */ static YY_BUFFER_STATE scanbufhandle; static char *scanbuf; -static int scanbuflen; %} %option 8bit @@ -42,12 +48,12 @@ float ({integer}|{real})([eE]{integer})? %% -{range} yylval.text = yytext; return RANGE; -{plumin} yylval.text = yytext; return PLUMIN; -{float} yylval.text = yytext; return SEGFLOAT; -\< yylval.text = "<"; return EXTENSION; -\> yylval.text = ">"; return EXTENSION; -\~ yylval.text = "~"; return EXTENSION; +{range} seg_yylval.text = yytext; return RANGE; +{plumin} seg_yylval.text = yytext; return PLUMIN; +{float} seg_yylval.text = yytext; return SEGFLOAT; +\< seg_yylval.text = "<"; return EXTENSION; +\> seg_yylval.text = ">"; return EXTENSION; +\~ seg_yylval.text = "~"; return EXTENSION; [ \t\n\r\f]+ /* discard spaces */ . return yytext[0]; /* alert parser of the garbage */ @@ -56,7 +62,7 @@ float ({integer}|{real})([eE]{integer})? /* LCOV_EXCL_STOP */ void -yyerror(SEG *result, const char *message) +seg_yyerror(SEG *result, const char *message) { if (*yytext == YY_END_OF_BUFFER_CHAR) { @@ -94,7 +100,6 @@ seg_scanner_init(const char *str) /* * Make a scan buffer with special termination needed by flex. */ - scanbuflen = slen; scanbuf = palloc(slen + 2); memcpy(scanbuf, str, slen); scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; -- 2.36.1
From 4d16b395978e8bc830e91d363cf9cadda0c00365 Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Sat, 13 Aug 2022 12:35:55 +0700 Subject: [PATCH v201 8/9] Build jsonpath_scan.c standalone XXX: warnings about missing jsonpath_yylex --- src/backend/utils/adt/.gitignore | 1 + src/backend/utils/adt/Makefile | 11 +++++++++-- src/backend/utils/adt/jsonpath_gram.y | 23 ----------------------- src/backend/utils/adt/jsonpath_scan.l | 25 +++++++++++++++---------- src/include/utils/jsonpath.h | 13 +++++++++++++ 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/backend/utils/adt/.gitignore b/src/backend/utils/adt/.gitignore index 48cf941a52..7fab054407 100644 --- a/src/backend/utils/adt/.gitignore +++ b/src/backend/utils/adt/.gitignore @@ -1,2 +1,3 @@ +/jsonpath_gram.h /jsonpath_gram.c /jsonpath_scan.c diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 7c722ea2ce..d03f897478 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -57,6 +57,7 @@ OBJS = \ jsonpath.o \ jsonpath_exec.o \ jsonpath_gram.o \ + jsonpath_scan.o \ like.o \ like_support.o \ lockfuncs.o \ @@ -119,11 +120,17 @@ OBJS = \ xid8funcs.o \ xml.o +# See notes in src/backend/parser/Makefile about the following two rules +jsonpath_gram.h: jsonpath_gram.c + touch $@ + +jsonpath_gram.c: BISONFLAGS += -d + jsonpath_scan.c: FLEXFLAGS = -CF -p -p jsonpath_scan.c: FLEX_NO_BACKUP=yes -# jsonpath_scan is compiled as part of jsonpath_gram -jsonpath_gram.o: jsonpath_scan.c +# Force these dependencies to be known even without dependency info built: +jsonpath_gram.o jsonpath_gram.o jsonpath_parser.o: jsonpath_gram.h # jsonpath_gram.c and jsonpath_scan.c are in the distribution tarball, # so they are not cleaned here. diff --git a/src/backend/utils/adt/jsonpath_gram.y b/src/backend/utils/adt/jsonpath_gram.y index f903dba3e3..a7557d325e 100644 --- a/src/backend/utils/adt/jsonpath_gram.y +++ b/src/backend/utils/adt/jsonpath_gram.y @@ -24,21 +24,8 @@ #include "utils/builtins.h" #include "utils/jsonpath.h" -/* struct JsonPathString is shared between scan and gram */ -typedef struct JsonPathString -{ - char *val; - int len; - int total; -} JsonPathString; - union YYSTYPE; -/* flex 2.5.4 doesn't bother with a decl for this */ -int jsonpath_yylex(union YYSTYPE *yylval_param); -int jsonpath_yyparse(JsonPathParseResult **result); -void jsonpath_yyerror(JsonPathParseResult **result, const char *message); - static JsonPathParseItem *makeItemType(JsonPathItemType type); static JsonPathParseItem *makeItemString(JsonPathString *s); static JsonPathParseItem *makeItemVariable(JsonPathString *s); @@ -593,13 +580,3 @@ jspConvertRegexFlags(uint32 xflags) return cflags; } - -/* - * jsonpath_scan.l is compiled as part of jsonpath_gram.y. Currently, this is - * unavoidable because jsonpath_gram does not create a .h file to export its - * token symbols. If these files ever grow large enough to be worth compiling - * separately, that could be fixed; but for now it seems like useless - * complication. - */ - -#include "jsonpath_scan.c" diff --git a/src/backend/utils/adt/jsonpath_scan.l b/src/backend/utils/adt/jsonpath_scan.l index 4351f6ec98..edd9d1c706 100644 --- a/src/backend/utils/adt/jsonpath_scan.l +++ b/src/backend/utils/adt/jsonpath_scan.l @@ -1,4 +1,4 @@ -%{ +%top{ /*------------------------------------------------------------------------- * * jsonpath_scan.l @@ -17,9 +17,14 @@ #include "postgres.h" +#include "utils/jsonpath.h" #include "mb/pg_wchar.h" #include "nodes/pg_list.h" +#include "jsonpath_gram.h" +} + +%{ static JsonPathString scanstring; /* Handles to the buffer that the lexer uses internally */ @@ -142,9 +147,9 @@ hex_fail \\x{hex_dig}{0,1} <xnq,xq,xvq>{hex_char} { parseHexChar(yytext); } -<xnq,xq,xvq>{unicode}*{unicodefail} { yyerror(NULL, "invalid unicode sequence"); } +<xnq,xq,xvq>{unicode}*{unicodefail} { jsonpath_yyerror(NULL, "invalid unicode sequence"); } -<xnq,xq,xvq>{hex_fail} { yyerror(NULL, "invalid hex character sequence"); } +<xnq,xq,xvq>{hex_fail} { jsonpath_yyerror(NULL, "invalid hex character sequence"); } <xnq,xq,xvq>{unicode}+\\ { /* throw back the \\, and treat as unicode */ @@ -154,9 +159,9 @@ hex_fail \\x{hex_dig}{0,1} <xnq,xq,xvq>\\. { addchar(false, yytext[1]); } -<xnq,xq,xvq>\\ { yyerror(NULL, "unexpected end after backslash"); } +<xnq,xq,xvq>\\ { jsonpath_yyerror(NULL, "unexpected end after backslash"); } -<xq,xvq><<EOF>> { yyerror(NULL, "unexpected end of quoted string"); } +<xq,xvq><<EOF>> { jsonpath_yyerror(NULL, "unexpected end of quoted string"); } <xq>\" { yylval->str = scanstring; @@ -178,7 +183,7 @@ hex_fail \\x{hex_dig}{0,1} <xc>\* { } -<xc><<EOF>> { yyerror(NULL, "unexpected end of comment"); } +<xc><<EOF>> { jsonpath_yyerror(NULL, "unexpected end of comment"); } \&\& { return AND_P; } @@ -244,10 +249,10 @@ hex_fail \\x{hex_dig}{0,1} return INT_P; } -{realfail} { yyerror(NULL, "invalid numeric literal"); } -{integer_junk} { yyerror(NULL, "trailing junk after numeric literal"); } -{decimal_junk} { yyerror(NULL, "trailing junk after numeric literal"); } -{real_junk} { yyerror(NULL, "trailing junk after numeric literal"); } +{realfail} { jsonpath_yyerror(NULL, "invalid numeric literal"); } +{integer_junk} { jsonpath_yyerror(NULL, "trailing junk after numeric literal"); } +{decimal_junk} { jsonpath_yyerror(NULL, "trailing junk after numeric literal"); } +{real_junk} { jsonpath_yyerror(NULL, "trailing junk after numeric literal"); } \" { addchar(true, '\0'); diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h index 8e79b8dc9f..b9b56209b2 100644 --- a/src/include/utils/jsonpath.h +++ b/src/include/utils/jsonpath.h @@ -21,6 +21,14 @@ #include "utils/jsonb.h" #include "utils/jsonfuncs.h" +/* struct JsonPathString is shared between scan and gram */ +typedef struct JsonPathString +{ + char *val; + int len; + int total; +} JsonPathString; + typedef struct { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -250,6 +258,11 @@ typedef struct JsonPathParseResult extern JsonPathParseResult *parsejsonpath(const char *str, int len); +/* flex 2.5.4 doesn't bother with a decl for this */ +//int jsonpath_yylex(union YYSTYPE *yylval_param); +//int jsonpath_yyparse(JsonPathParseResult **result); +void jsonpath_yyerror(JsonPathParseResult **result, const char *message); + extern int jspConvertRegexFlags(uint32 xflags); /* -- 2.36.1
From cae4dccc5aaee93e0ed258448f60d4178163ec1c Mon Sep 17 00:00:00 2001 From: John Naylor <john.nay...@postgresql.org> Date: Sat, 13 Aug 2022 13:35:14 +0700 Subject: [PATCH v201 9/9] Build exprscan.c standalone --- src/bin/pgbench/.gitignore | 1 + src/bin/pgbench/Makefile | 13 ++++++++++--- src/bin/pgbench/exprparse.y | 15 --------------- src/bin/pgbench/exprscan.l | 9 ++++++++- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/bin/pgbench/.gitignore b/src/bin/pgbench/.gitignore index 983a3cd7a6..07492a993c 100644 --- a/src/bin/pgbench/.gitignore +++ b/src/bin/pgbench/.gitignore @@ -1,3 +1,4 @@ +/exprparse.h /exprparse.c /exprscan.c /pgbench diff --git a/src/bin/pgbench/Makefile b/src/bin/pgbench/Makefile index f402fe7b91..6647c9fe97 100644 --- a/src/bin/pgbench/Makefile +++ b/src/bin/pgbench/Makefile @@ -10,6 +10,7 @@ include $(top_builddir)/src/Makefile.global OBJS = \ $(WIN32RES) \ exprparse.o \ + exprscan.o \ pgbench.o override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS) @@ -26,8 +27,14 @@ all: pgbench pgbench: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) -# exprscan is compiled as part of exprparse -exprparse.o: exprscan.c +# See notes in src/backend/parser/Makefile about the following two rules +exprparse.h: exprparse.c + touch $@ + +exprparse.c: BISONFLAGS += -d + +# Force these dependencies to be known even without dependency info built: +exprparse.o exprscan.o: exprparse.h distprep: exprparse.c exprscan.c @@ -45,7 +52,7 @@ clean distclean: rm -rf tmp_check maintainer-clean: distclean - rm -f exprparse.c exprscan.c + rm -f exprparse.h exprparse.c exprscan.c check: $(prove_check) diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index b5592d4b97..ade2ecdaab 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -526,18 +526,3 @@ make_case(yyscan_t yyscanner, PgBenchExprList *when_then_list, PgBenchExpr *else find_func(yyscanner, "!case_end"), make_elist(else_part, when_then_list)); } - -/* - * exprscan.l is compiled as part of exprparse.y. Currently, this is - * unavoidable because exprparse does not create a .h file to export - * its token symbols. If these files ever grow large enough to be - * worth compiling separately, that could be fixed; but for now it - * seems like useless complication. - */ - -/* First, get rid of "#define yyscan_t" from pgbench.h */ -#undef yyscan_t -/* ... and the yylval macro, which flex will have its own definition for */ -#undef yylval - -#include "exprscan.c" diff --git a/src/bin/pgbench/exprscan.l b/src/bin/pgbench/exprscan.l index 4f63818606..6e9d949dcf 100644 --- a/src/bin/pgbench/exprscan.l +++ b/src/bin/pgbench/exprscan.l @@ -1,4 +1,4 @@ -%{ +%top{ /*------------------------------------------------------------------------- * * exprscan.l @@ -23,8 +23,15 @@ *------------------------------------------------------------------------- */ +#include "postgres_fe.h" + #include "fe_utils/psqlscan_int.h" +#include "pgbench.h" +#include "exprparse.h" +} + +%{ /* context information for reporting errors in expressions */ static const char *expr_source = NULL; static int expr_lineno = 0; -- 2.36.1