Using a single standalone-backend run in initdb (was Re: Bootstrap DATA is a pita)

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Using a single standalone-backend run in initdb (was Re: Bootstrap DATA is a pita)
Дата
Msg-id 2098.1449959509@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: Bootstrap DATA is a pita  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: Using a single standalone-backend run in initdb (was Re: Bootstrap DATA is a pita)  (Andres Freund <andres@anarazel.de>)
Re: Using a single standalone-backend run in initdb (was Re: Bootstrap DATA is a pita)  (Joe Conway <mail@joeconway.com>)
Re: Using a single standalone-backend run in initdb (was Re: Bootstrap DATA is a pita)  (Craig Ringer <craig@2ndquadrant.com>)
Список pgsql-hackers
I wrote:
> BTW, there's another thing I'd like to see improved in this area, which is
> a problem already but will get a lot worse if we push more work into the
> post-bootstrap phase of initdb.  That is that the post-bootstrap phase is
> both inefficient and impossible to debug.  If you've ever had a failure
> there, you'll have seen that the backend spits out an entire SQL script
> and says there's an error in it somewhere; that's because it gets the
> whole per-stage script as one submission.  (Try introducing a syntax error
> somewhere in information_schema.sql, and you'll see what I mean.)
> Breaking the stage scripts down further would help, but that is
> unattractive because each one requires a fresh backend startup/shutdown,
> including a full checkpoint.  I'd like to see things rejiggered so that
> there's only one post-bootstrap standalone backend session that performs
> all the steps, but initdb feeds it just one SQL command at a time so that
> errors are better localized.  That should both speed up initdb noticeably
> and make debugging easier.

I thought this sounded like a nice lazy-Saturday project, so I started
poking at it, and attached is a WIP patch.  The core issue that has to
be dealt with is that standalone-backend mode currently has just two
rules for deciding when to stop collecting input and execute the command
buffer, and they both suck:

1. By default, execute after every newline.  (Actually, you can quote
a newline with a backslash, but we don't use that ability anywhere.)

2. With -j, slurp the entire input until EOF, and execute it as one
giant multicommand string.

We're doing #2 to handle information_schema.sql and the other large
SQL scripts that initdb runs, which is why the response to an error in
those scripts is so yucky.

After some experimentation, I came up with the idea of executing any
time that a semicolon followed by two newlines is seen.  This nicely
breaks up input like information_schema.sql.  There are probably some
residual places where more than one command is executed in a single
string, but we could fix that with some more newlines.  Obviously,
this rule is capable of being fooled if you have a newline followed by
a blank line in a comment or quoted literal --- but it turns out that
no such case exists anywhere in initdb's data.

I'm not particularly wedded to this rule.  In principle we could go so
far as to import psql's code that parses commands and figures out which
semicolons are command terminators --- but that is a pretty large chunk
of code, and I think it'd really be overkill considering that initdb
deals only with fixed input scripts.  But if anyone has another simple
rule for breaking SQL into commands, we can certainly discuss
alternatives.

Anyway, the attached patch tweaks postgres.c to follow that rule instead
of slurp-to-EOF when -j is given.  I doubt that being non-backwards-
compatible is a problem here; in fact, I'm tempted to rip out the -j
switch altogether and just have standalone mode always parse input the
same way.  Does anyone know of people using standalone mode other than
for initdb?

The other part of the patch modifies initdb to do all its post-bootstrap
steps using a single standalone backend session.  I had to remove the
code that currently prints out progress markers for individual phases
of that processing, so that now you get output that looks like

creating directory /home/postgres/testversion/data ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
creating template1 database in /home/postgres/testversion/data/base/1 ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

Since initdb is just printing to the backend in an open-loop fashion,
it doesn't really know whether each command succeeds; in fact it is
usually pretty far ahead of the backend, until it does pclose() which
waits for the subprocess to exit.  So we can't readily keep the old
progress markers.  I don't think we'll miss them though.  The whole
"post-bootstrap initialization" step only takes a second or so on my
main dev machine, so breaking down the progress more finely isn't that
useful anymore.

I had to change ;\n to ;\n\n in a few places in initdb's internal
scripts, to ensure that VACUUM commands were executed by themselves
(otherwise you get "VACUUM can't run in a transaction block" type
failures).  I wasn't very thorough about that though, pending a
decision on exactly what the new command-boundary rule will be.

The upshot of these changes is that initdb runs about 10% faster overall
(more in -N mode), which is a useful savings.  Also, the response to a
syntax error in information_schema.sql now looks like this:

creating template1 database in /home/postgres/testversion/data/base/1 ... ok
performing post-bootstrap initialization ... FATAL:  column "routzine_schema" does not exist at character 243
HINT:  Perhaps you meant to reference the column "routine_privileges.routine_schema".
STATEMENT:
    /*
     * 5.42
     * ROLE_ROUTINE_GRANTS view
     */

    CREATE VIEW role_routine_grants AS
        SELECT grantor,
               grantee,
               specific_catalog,
               specific_schema,
               specific_name,
               routine_catalog,
               routzine_schema,
               routine_name,
               privilege_type,
               is_grantable
        FROM routine_privileges
        WHERE grantor IN (SELECT role_name FROM enabled_roles)
              OR grantee IN (SELECT role_name FROM enabled_roles);

child process exited with exit code 1
initdb: removing data directory "/home/postgres/testversion/data"

which is a *huge* improvement over what you got before.

What remains to be done before this'd be committable is updating
the documentation around the -j switch (or removing it altogether),
and going through initdb and its input scripts to ensure there's
a double newline after every nontrivial SQL command.  I don't see
much point in finishing that detail work until we have consensus on
whether to use this or another command-boundary rule.

Thoughts?

            regards, tom lane

diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 1dc2eb0..1cb0cd9 100644
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
*************** static int
*** 219,226 ****
  InteractiveBackend(StringInfo inBuf)
  {
      int            c;                /* character read from getc() */
-     bool        end = false;    /* end-of-input flag */
-     bool        backslashSeen = false;    /* have we seen a \ ? */

      /*
       * display a prompt and obtain input from the user
--- 219,224 ----
*************** InteractiveBackend(StringInfo inBuf)
*** 230,284 ****

      resetStringInfo(inBuf);

!     if (UseNewLine)
      {
!         /*
!          * if we are using \n as a delimiter, then read characters until the
!          * \n.
!          */
!         while ((c = interactive_getc()) != EOF)
          {
!             if (c == '\n')
              {
!                 if (backslashSeen)
                  {
                      /* discard backslash from inBuf */
                      inBuf->data[--inBuf->len] = '\0';
-                     backslashSeen = false;
                      continue;
                  }
                  else
                  {
!                     /* keep the newline character */
                      appendStringInfoChar(inBuf, '\n');
                      break;
                  }
              }
-             else if (c == '\\')
-                 backslashSeen = true;
              else
!                 backslashSeen = false;
!
!             appendStringInfoChar(inBuf, (char) c);
          }

!         if (c == EOF)
!             end = true;
!     }
!     else
!     {
!         /*
!          * otherwise read characters until EOF.
!          */
!         while ((c = interactive_getc()) != EOF)
!             appendStringInfoChar(inBuf, (char) c);
!
!         /* No input before EOF signal means time to quit. */
!         if (inBuf->len == 0)
!             end = true;
      }

!     if (end)
          return EOF;

      /*
--- 228,282 ----

      resetStringInfo(inBuf);

!     /*
!      * Read characters until EOF or the appropriate delimiter is seen.
!      */
!     while ((c = interactive_getc()) != EOF)
      {
!         if (c == '\n')
          {
!             if (UseNewLine)
              {
!                 /*
!                  * In newline mode, newline is delimiter unless preceded by
!                  * backslash.
!                  */
!                 if (inBuf->len > 0 &&
!                     inBuf->data[inBuf->len - 1] == '\\')
                  {
                      /* discard backslash from inBuf */
                      inBuf->data[--inBuf->len] = '\0';
                      continue;
                  }
                  else
                  {
!                     /* keep the newline character, but end the command */
                      appendStringInfoChar(inBuf, '\n');
                      break;
                  }
              }
              else
!             {
!                 /*
!                  * In -j mode, semicolon followed by two newlines ends the
!                  * command; otherwise treat newline as regular character.
!                  */
!                 if (inBuf->len > 1 &&
!                     inBuf->data[inBuf->len - 1] == '\n' &&
!                     inBuf->data[inBuf->len - 2] == ';')
!                 {
!                     /* might as well drop the second newline */
!                     break;
!                 }
!             }
          }

!         /* Not newline, or newline treated as regular character */
!         appendStringInfoChar(inBuf, (char) c);
      }

!     /* No input before EOF signal means time to quit. */
!     if (c == EOF && inBuf->len == 0)
          return EOF;

      /*
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index feeff9e..b056639 100644
*** a/src/bin/initdb/initdb.c
--- b/src/bin/initdb/initdb.c
*************** static void set_null_conf(void);
*** 244,264 ****
  static void test_config_settings(void);
  static void setup_config(void);
  static void bootstrap_template1(void);
! static void setup_auth(void);
! static void get_set_pwd(void);
! static void setup_depend(void);
! static void setup_sysviews(void);
! static void setup_description(void);
! static void setup_collation(void);
! static void setup_conversion(void);
! static void setup_dictionary(void);
! static void setup_privileges(void);
  static void set_info_version(void);
! static void setup_schema(void);
! static void load_plpgsql(void);
! static void vacuum_db(void);
! static void make_template0(void);
! static void make_postgres(void);
  static void fsync_pgdata(void);
  static void trapsig(int signum);
  static void check_ok(void);
--- 244,264 ----
  static void test_config_settings(void);
  static void setup_config(void);
  static void bootstrap_template1(void);
! static void setup_auth(FILE *cmdfd);
! static void get_set_pwd(FILE *cmdfd);
! static void setup_depend(FILE *cmdfd);
! static void setup_sysviews(FILE *cmdfd);
! static void setup_description(FILE *cmdfd);
! static void setup_collation(FILE *cmdfd);
! static void setup_conversion(FILE *cmdfd);
! static void setup_dictionary(FILE *cmdfd);
! static void setup_privileges(FILE *cmdfd);
  static void set_info_version(void);
! static void setup_schema(FILE *cmdfd);
! static void load_plpgsql(FILE *cmdfd);
! static void vacuum_db(FILE *cmdfd);
! static void make_template0(FILE *cmdfd);
! static void make_postgres(FILE *cmdfd);
  static void fsync_pgdata(void);
  static void trapsig(int signum);
  static void check_ok(void);
*************** bootstrap_template1(void)
*** 1545,1553 ****
   * set up the shadow password table
   */
  static void
! setup_auth(void)
  {
-     PG_CMD_DECL;
      const char **line;
      static const char *pg_authid_setup[] = {
          /*
--- 1545,1552 ----
   * set up the shadow password table
   */
  static void
! setup_auth(FILE *cmdfd)
  {
      const char **line;
      static const char *pg_authid_setup[] = {
          /*
*************** setup_auth(void)
*** 1558,1589 ****
          NULL
      };

-     fputs(_("initializing pg_authid ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      for (line = pg_authid_setup; *line != NULL; line++)
          PG_CMD_PUTS(*line);
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
   * get the superuser password if required, and call postgres to set it
   */
  static void
! get_set_pwd(void)
  {
-     PG_CMD_DECL;
-
      char       *pwd1,
                 *pwd2;

--- 1557,1572 ----
          NULL
      };

      for (line = pg_authid_setup; *line != NULL; line++)
          PG_CMD_PUTS(*line);
  }

  /*
   * get the superuser password if required, and call postgres to set it
   */
  static void
! get_set_pwd(FILE *cmdfd)
  {
      char       *pwd1,
                 *pwd2;

*************** get_set_pwd(void)
*** 1640,1673 ****
          pwd1 = pg_strdup(pwdbuf);

      }
-     printf(_("setting password ... "));
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;

      PG_CMD_PRINTF2("ALTER USER \"%s\" WITH PASSWORD E'%s';\n",
                     username, escape_quotes(pwd1));

-     /* MM: pwd1 is no longer needed, freeing it */
      free(pwd1);
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
   * set up pg_depend
   */
  static void
! setup_depend(void)
  {
-     PG_CMD_DECL;
      const char **line;
      static const char *pg_depend_setup[] = {
          /*
--- 1623,1641 ----
          pwd1 = pg_strdup(pwdbuf);

      }

      PG_CMD_PRINTF2("ALTER USER \"%s\" WITH PASSWORD E'%s';\n",
                     username, escape_quotes(pwd1));

      free(pwd1);
  }

  /*
   * set up pg_depend
   */
  static void
! setup_depend(FILE *cmdfd)
  {
      const char **line;
      static const char *pg_depend_setup[] = {
          /*
*************** setup_depend(void)
*** 1684,1693 ****
           * First delete any already-made entries; PINs override all else, and
           * must be the only entries for their objects.
           */
!         "DELETE FROM pg_depend;\n",
!         "VACUUM pg_depend;\n",
!         "DELETE FROM pg_shdepend;\n",
!         "VACUUM pg_shdepend;\n",

          "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
          " FROM pg_class;\n",
--- 1652,1661 ----
           * First delete any already-made entries; PINs override all else, and
           * must be the only entries for their objects.
           */
!         "DELETE FROM pg_depend;\n\n",
!         "VACUUM pg_depend;\n\n",
!         "DELETE FROM pg_shdepend;\n\n",
!         "VACUUM pg_shdepend;\n\n",

          "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
          " FROM pg_class;\n",
*************** setup_depend(void)
*** 1740,1819 ****
          NULL
      };

-     fputs(_("initializing dependencies ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      for (line = pg_depend_setup; *line != NULL; line++)
          PG_CMD_PUTS(*line);
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
   * set up system views
   */
  static void
! setup_sysviews(void)
  {
-     PG_CMD_DECL;
      char      **line;
      char      **sysviews_setup;

-     fputs(_("creating system views ... "), stdout);
-     fflush(stdout);
-
      sysviews_setup = readfile(system_views_file);

-     /*
-      * We use -j here to avoid backslashing stuff in system_views.sql
-      */
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s -j template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      for (line = sysviews_setup; *line != NULL; line++)
      {
          PG_CMD_PUTS(*line);
          free(*line);
      }

-     PG_CMD_CLOSE;
-
      free(sysviews_setup);
-
-     check_ok();
  }

  /*
   * load description data
   */
  static void
! setup_description(void)
  {
-     PG_CMD_DECL;
-
-     fputs(_("loading system objects' descriptions ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_description ( "
                  "    objoid oid, "
                  "    classname name, "
--- 1708,1743 ----
          NULL
      };

      for (line = pg_depend_setup; *line != NULL; line++)
          PG_CMD_PUTS(*line);
  }

  /*
   * set up system views
   */
  static void
! setup_sysviews(FILE *cmdfd)
  {
      char      **line;
      char      **sysviews_setup;

      sysviews_setup = readfile(system_views_file);

      for (line = sysviews_setup; *line != NULL; line++)
      {
          PG_CMD_PUTS(*line);
          free(*line);
      }

      free(sysviews_setup);
  }

  /*
   * load description data
   */
  static void
! setup_description(FILE *cmdfd)
  {
      PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_description ( "
                  "    objoid oid, "
                  "    classname name, "
*************** setup_description(void)
*** 1853,1862 ****
                  "  WHERE opdesc NOT LIKE 'deprecated%' AND "
                  "  NOT EXISTS (SELECT 1 FROM pg_description "
            "    WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass);\n");
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  #ifdef HAVE_LOCALE_T
--- 1777,1782 ----
*************** normalize_locale_name(char *new, const c
*** 1899,1905 ****
   * populate pg_collation
   */
  static void
! setup_collation(void)
  {
  #if defined(HAVE_LOCALE_T) && !defined(WIN32)
      int            i;
--- 1819,1825 ----
   * populate pg_collation
   */
  static void
! setup_collation(FILE *cmdfd)
  {
  #if defined(HAVE_LOCALE_T) && !defined(WIN32)
      int            i;
*************** setup_collation(void)
*** 1907,1930 ****
      char        localebuf[NAMEDATALEN]; /* we assume ASCII so this is fine */
      int            count = 0;

-     PG_CMD_DECL;
- #endif
-
-     fputs(_("creating collations ... "), stdout);
-     fflush(stdout);
-
- #if defined(HAVE_LOCALE_T) && !defined(WIN32)
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
      locale_a_handle = popen_check("locale -a", "r");
      if (!locale_a_handle)
          return;                    /* complaint already printed */

-     PG_CMD_OPEN;
-
      PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_collation ( "
                  "    collname name, "
                  "    locale name, "
--- 1827,1836 ----
*************** setup_collation(void)
*** 2032,2048 ****
         "  ORDER BY collname, encoding, (collname = locale) DESC, locale;\n");

      pclose(locale_a_handle);
-     PG_CMD_CLOSE;

-     check_ok();
      if (count == 0 && !debug)
      {
          printf(_("No usable system locales were found.\n"));
          printf(_("Use the option \"--debug\" to see details.\n"));
      }
- #else                            /* not HAVE_LOCALE_T && not WIN32 */
-     printf(_("not supported on this platform\n"));
-     fflush(stdout);
  #endif   /* not HAVE_LOCALE_T  && not WIN32 */
  }

--- 1938,1949 ----
*************** setup_collation(void)
*** 2050,2071 ****
   * load conversion functions
   */
  static void
! setup_conversion(void)
  {
-     PG_CMD_DECL;
      char      **line;
      char      **conv_lines;

-     fputs(_("creating conversions ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      conv_lines = readfile(conversion_file);
      for (line = conv_lines; *line != NULL; line++)
      {
--- 1951,1961 ----
   * load conversion functions
   */
  static void
! setup_conversion(FILE *cmdfd)
  {
      char      **line;
      char      **conv_lines;

      conv_lines = readfile(conversion_file);
      for (line = conv_lines; *line != NULL; line++)
      {
*************** setup_conversion(void)
*** 2075,2109 ****
      }

      free(conv_lines);
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
   * load extra dictionaries (Snowball stemmers)
   */
  static void
! setup_dictionary(void)
  {
-     PG_CMD_DECL;
      char      **line;
      char      **conv_lines;

-     fputs(_("creating dictionaries ... "), stdout);
-     fflush(stdout);
-
-     /*
-      * We use -j here to avoid backslashing stuff
-      */
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s -j template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      conv_lines = readfile(dictionary_file);
      for (line = conv_lines; *line != NULL; line++)
      {
--- 1965,1981 ----
      }

      free(conv_lines);
  }

  /*
   * load extra dictionaries (Snowball stemmers)
   */
  static void
! setup_dictionary(FILE *cmdfd)
  {
      char      **line;
      char      **conv_lines;

      conv_lines = readfile(dictionary_file);
      for (line = conv_lines; *line != NULL; line++)
      {
*************** setup_dictionary(void)
*** 2112,2121 ****
      }

      free(conv_lines);
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
--- 1984,1989 ----
*************** setup_dictionary(void)
*** 2130,2138 ****
   * set (NOT NULL).
   */
  static void
! setup_privileges(void)
  {
-     PG_CMD_DECL;
      char      **line;
      char      **priv_lines;
      static char *privileges_setup[] = {
--- 1998,2005 ----
   * set (NOT NULL).
   */
  static void
! setup_privileges(FILE *cmdfd)
  {
      char      **line;
      char      **priv_lines;
      static char *privileges_setup[] = {
*************** setup_privileges(void)
*** 2145,2168 ****
          NULL
      };

-     fputs(_("setting privileges on built-in objects ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      priv_lines = replace_token(privileges_setup, "$POSTGRES_SUPERUSERNAME",
                                 escape_quotes(username));
      for (line = priv_lines; *line != NULL; line++)
          PG_CMD_PUTS(*line);
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
--- 2012,2021 ----
*************** set_info_version(void)
*** 2197,2223 ****
   * load info schema and populate from features file
   */
  static void
! setup_schema(void)
  {
-     PG_CMD_DECL;
      char      **line;
      char      **lines;

-     fputs(_("creating information schema ... "), stdout);
-     fflush(stdout);
-
      lines = readfile(info_schema_file);

-     /*
-      * We use -j here to avoid backslashing stuff in information_schema.sql
-      */
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s -j template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      for (line = lines; *line != NULL; line++)
      {
          PG_CMD_PUTS(*line);
--- 2050,2062 ----
   * load info schema and populate from features file
   */
  static void
! setup_schema(FILE *cmdfd)
  {
      char      **line;
      char      **lines;

      lines = readfile(info_schema_file);

      for (line = lines; *line != NULL; line++)
      {
          PG_CMD_PUTS(*line);
*************** setup_schema(void)
*** 2226,2240 ****

      free(lines);

-     PG_CMD_CLOSE;
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      PG_CMD_PRINTF1("UPDATE information_schema.sql_implementation_info "
                     "  SET character_value = '%s' "
                     "  WHERE implementation_info_name = 'DBMS VERSION';\n",
--- 2065,2070 ----
*************** setup_schema(void)
*** 2245,2390 ****
                     "  sub_feature_name, is_supported, comments) "
                     " FROM E'%s';\n",
                     escape_quotes(features_file));
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
   * load PL/pgsql server-side language
   */
  static void
! load_plpgsql(void)
  {
-     PG_CMD_DECL;
-
-     fputs(_("loading PL/pgSQL server-side language ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n");
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
   * clean everything up in template1
   */
  static void
! vacuum_db(void)
  {
-     PG_CMD_DECL;
-
-     fputs(_("vacuuming database template1 ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      /* Run analyze before VACUUM so the statistics are frozen. */
!     PG_CMD_PUTS("ANALYZE;\nVACUUM FREEZE;\n");
!
!     PG_CMD_CLOSE;
!
!     check_ok();
  }

  /*
   * copy template1 to template0
   */
  static void
! make_template0(void)
  {
-     PG_CMD_DECL;
      const char **line;
      static const char *template0_setup[] = {
!         "CREATE DATABASE template0 IS_TEMPLATE = true ALLOW_CONNECTIONS = false;\n",

          /*
           * We use the OID of template0 to determine lastsysoid
           */
          "UPDATE pg_database SET datlastsysoid = "
          "    (SELECT oid FROM pg_database "
!         "    WHERE datname = 'template0');\n",

          /*
           * Explicitly revoke public create-schema and create-temp-table
           * privileges in template1 and template0; else the latter would be on
           * by default
           */
!         "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n",
!         "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n",

!         "COMMENT ON DATABASE template0 IS 'unmodifiable empty database';\n",

          /*
           * Finally vacuum to clean up dead rows in pg_database
           */
!         "VACUUM FULL pg_database;\n",
          NULL
      };

-     fputs(_("copying template1 to template0 ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      for (line = template0_setup; *line; line++)
          PG_CMD_PUTS(*line);
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
   * copy template1 to postgres
   */
  static void
! make_postgres(void)
  {
-     PG_CMD_DECL;
      const char **line;
      static const char *postgres_setup[] = {
!         "CREATE DATABASE postgres;\n",
!         "COMMENT ON DATABASE postgres IS 'default administrative connection database';\n",
          NULL
      };

-     fputs(_("copying template1 to postgres ... "), stdout);
-     fflush(stdout);
-
-     snprintf(cmd, sizeof(cmd),
-              "\"%s\" %s template1 >%s",
-              backend_exec, backend_options,
-              DEVNULL);
-
-     PG_CMD_OPEN;
-
      for (line = postgres_setup; *line; line++)
          PG_CMD_PUTS(*line);
-
-     PG_CMD_CLOSE;
-
-     check_ok();
  }

  /*
--- 2075,2154 ----
                     "  sub_feature_name, is_supported, comments) "
                     " FROM E'%s';\n",
                     escape_quotes(features_file));
  }

  /*
   * load PL/pgsql server-side language
   */
  static void
! load_plpgsql(FILE *cmdfd)
  {
      PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n");
  }

  /*
   * clean everything up in template1
   */
  static void
! vacuum_db(FILE *cmdfd)
  {
      /* Run analyze before VACUUM so the statistics are frozen. */
!     PG_CMD_PUTS("ANALYZE;\n\nVACUUM FREEZE;\n\n");
  }

  /*
   * copy template1 to template0
   */
  static void
! make_template0(FILE *cmdfd)
  {
      const char **line;
      static const char *template0_setup[] = {
!         "CREATE DATABASE template0 IS_TEMPLATE = true ALLOW_CONNECTIONS = false;\n\n",

          /*
           * We use the OID of template0 to determine lastsysoid
           */
          "UPDATE pg_database SET datlastsysoid = "
          "    (SELECT oid FROM pg_database "
!         "    WHERE datname = 'template0');\n\n",

          /*
           * Explicitly revoke public create-schema and create-temp-table
           * privileges in template1 and template0; else the latter would be on
           * by default
           */
!         "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n\n",
!         "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n\n",

!         "COMMENT ON DATABASE template0 IS 'unmodifiable empty database';\n\n",

          /*
           * Finally vacuum to clean up dead rows in pg_database
           */
!         "VACUUM FULL pg_database;\n\n",
          NULL
      };

      for (line = template0_setup; *line; line++)
          PG_CMD_PUTS(*line);
  }

  /*
   * copy template1 to postgres
   */
  static void
! make_postgres(FILE *cmdfd)
  {
      const char **line;
      static const char *postgres_setup[] = {
!         "CREATE DATABASE postgres;\n\n",
!         "COMMENT ON DATABASE postgres IS 'default administrative connection database';\n\n",
          NULL
      };

      for (line = postgres_setup; *line; line++)
          PG_CMD_PUTS(*line);
  }

  /*
*************** warn_on_mount_point(int error)
*** 3303,3308 ****
--- 3067,3073 ----
  void
  initialize_data_directory(void)
  {
+     PG_CMD_DECL;
      int            i;

      setup_signals();
*************** initialize_data_directory(void)
*** 3343,3377 ****
       */
      write_version_file("base/1");

!     /* Create the stuff we don't need to use bootstrap mode for */

!     setup_auth();
      if (pwprompt || pwfilename)
!         get_set_pwd();

!     setup_depend();

!     setup_sysviews();

!     setup_description();

!     setup_collation();

!     setup_conversion();

!     setup_dictionary();

!     setup_privileges();

!     setup_schema();

!     load_plpgsql();

!     vacuum_db();

!     make_template0();

!     make_postgres();
  }


--- 3108,3158 ----
       */
      write_version_file("base/1");

!     /*
!      * Create the stuff we don't need to use bootstrap mode for, using a
!      * backend running in simple standalone mode.
!      */
!     fputs(_("performing post-bootstrap initialization ... "), stdout);
!     fflush(stdout);

!     snprintf(cmd, sizeof(cmd),
!              "\"%s\" %s -j template1 >%s",
!              backend_exec, backend_options,
!              DEVNULL);
!
!     PG_CMD_OPEN;
!
!     setup_auth(cmdfd);
      if (pwprompt || pwfilename)
!         get_set_pwd(cmdfd);

!     setup_depend(cmdfd);

!     setup_sysviews(cmdfd);

!     setup_description(cmdfd);

!     setup_collation(cmdfd);

!     setup_conversion(cmdfd);

!     setup_dictionary(cmdfd);

!     setup_privileges(cmdfd);

!     setup_schema(cmdfd);

!     load_plpgsql(cmdfd);

!     vacuum_db(cmdfd);

!     make_template0(cmdfd);

!     make_postgres(cmdfd);
!
!     PG_CMD_CLOSE;
!
!     check_ok();
  }



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Peter Geoghegan
Дата:
Сообщение: Re: Using quicksort for every external sort run
Следующее
От: Andres Freund
Дата:
Сообщение: Re: PATCH: track last known XLOG segment in control file