Re: per user/database connections limit again - Mailing list pgsql-patches

From Petr Jelinek
Subject Re: per user/database connections limit again
Date
Msg-id 42C86FD5.8030700@parba.cz
Whole thread Raw
In response to Re: per user/database connections limit again  (Stephen Frost <sfrost@snowman.net>)
Responses Re: per user/database connections limit again  (Alvaro Herrera <alvherre@surnet.cl>)
Re: per user/database connections limit again  (Bruce Momjian <pgman@candle.pha.pa.us>)
Re: per user/database connections limit again  (Bruce Momjian <pgman@candle.pha.pa.us>)
Re: per user/database connections limit again  (Bruce Momjian <pgman@candle.pha.pa.us>)
List pgsql-patches
Stephen Frost wrote:

>This should almost certainly be a pg_database_ownercheck() call instead.
>
>
Right there wasn't pg_database_ownercheck at the time I was writing it,
fixed

>The rest needs to be updated for roles, but looks like it should be
>pretty easy to do.  Much of it just needs to be repatched, the parts
>that do need to be changed look to be pretty simple changes.
>
>
Done.

>I believe the use of SessionUserId is probably correct in this patch.
>This does mean that this patch will only be for canlogin roles, but that
>seems like it's probably correct.  Handling roles w/ members would
>require much more thought.
>
>
I don't think that having max connection for roles w/ members is doable
because you can have 5 roles which has 1 user as member and each role
has different number of max conections and there is no right way to
decide what to do.


New version which works with roles is attached (diffed against cvs),
everything else is mostly same.
I also had to readd roleid to flatfiles because I need it in
InitProcess() function.

--
Regards
Petr Jelinek (PJMODOS)


Index: src/backend/commands/dbcommands.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/dbcommands.c,v
retrieving revision 1.164
diff -c -r1.164 dbcommands.c
*** src/backend/commands/dbcommands.c    30 Jun 2005 00:00:50 -0000    1.164
--- src/backend/commands/dbcommands.c    3 Jul 2005 22:47:39 -0000
***************
*** 53,60 ****

  /* non-export function prototypes */
  static bool get_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP,
!             int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
!             Oid *dbLastSysOidP,
              TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
              Oid *dbTablespace);
  static bool have_createdb_privilege(void);
--- 53,60 ----

  /* non-export function prototypes */
  static bool get_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP,
!             int *encodingP, int *dbMaxConnP, bool *dbIsTemplateP,
!             bool *dbAllowConnP,    Oid *dbLastSysOidP,
              TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
              Oid *dbTablespace);
  static bool have_createdb_privilege(void);
***************
*** 74,79 ****
--- 74,80 ----
      int            src_encoding;
      bool        src_istemplate;
      bool        src_allowconn;
+     int            src_maxconn;
      Oid            src_lastsysoid;
      TransactionId src_vacuumxid;
      TransactionId src_frozenxid;
***************
*** 91,100 ****
--- 92,103 ----
      DefElem    *downer = NULL;
      DefElem    *dtemplate = NULL;
      DefElem    *dencoding = NULL;
+     DefElem    *dmaxconn = NULL;
      char       *dbname = stmt->dbname;
      char       *dbowner = NULL;
      const char *dbtemplate = NULL;
      int            encoding = -1;
+     int            dbmaxconn = -1;

  #ifndef WIN32
      char        buf[2 * MAXPGPATH + 100];
***************
*** 140,145 ****
--- 143,156 ----
                           errmsg("conflicting or redundant options")));
              dencoding = defel;
          }
+         else if (strcmp(defel->defname, "maxconnections") == 0)
+         {
+             if (dmaxconn)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SYNTAX_ERROR),
+                          errmsg("conflicting or redundant options")));
+             dmaxconn = defel;
+         }
          else if (strcmp(defel->defname, "location") == 0)
          {
              ereport(WARNING,
***************
*** 185,190 ****
--- 196,203 ----
              elog(ERROR, "unrecognized node type: %d",
                   nodeTag(dencoding->arg));
      }
+     if (dmaxconn && dmaxconn->arg)
+         dbmaxconn = intVal(dmaxconn->arg);

      /* obtain OID of proposed owner */
      if (dbowner)
***************
*** 218,224 ****
       * idea, so accept possibility of race to create.  We will check again
       * after we grab the exclusive lock.
       */
!     if (get_db_info(dbname, NULL, NULL, NULL,
                      NULL, NULL, NULL, NULL, NULL, NULL))
          ereport(ERROR,
                  (errcode(ERRCODE_DUPLICATE_DATABASE),
--- 231,237 ----
       * idea, so accept possibility of race to create.  We will check again
       * after we grab the exclusive lock.
       */
!     if (get_db_info(dbname, NULL, NULL, NULL, NULL,
                      NULL, NULL, NULL, NULL, NULL, NULL))
          ereport(ERROR,
                  (errcode(ERRCODE_DUPLICATE_DATABASE),
***************
*** 231,238 ****
          dbtemplate = "template1";        /* Default template database name */

      if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
!                      &src_istemplate, &src_allowconn, &src_lastsysoid,
!                      &src_vacuumxid, &src_frozenxid, &src_deftablespace))
          ereport(ERROR,
                  (errcode(ERRCODE_UNDEFINED_DATABASE),
           errmsg("template database \"%s\" does not exist", dbtemplate)));
--- 244,252 ----
          dbtemplate = "template1";        /* Default template database name */

      if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
!                      &src_maxconn, &src_istemplate, &src_allowconn,
!                      &src_lastsysoid, &src_vacuumxid, &src_frozenxid,
!                      &src_deftablespace))
          ereport(ERROR,
                  (errcode(ERRCODE_UNDEFINED_DATABASE),
           errmsg("template database \"%s\" does not exist", dbtemplate)));
***************
*** 266,271 ****
--- 280,289 ----
      if (encoding < 0)
          encoding = src_encoding;

+     /* If dbmaxconn is defaulted, use source's dbmaxconn */
+     if (dbmaxconn < 0)
+         dbmaxconn = src_maxconn;
+
      /* Some encodings are client only */
      if (!PG_VALID_BE_ENCODING(encoding))
          ereport(ERROR,
***************
*** 461,467 ****
      pg_database_rel = heap_open(DatabaseRelationId, ExclusiveLock);

      /* Check to see if someone else created same DB name meanwhile. */
!     if (get_db_info(dbname, NULL, NULL, NULL,
                      NULL, NULL, NULL, NULL, NULL, NULL))
      {
          /* Don't hold lock while doing recursive remove */
--- 479,485 ----
      pg_database_rel = heap_open(DatabaseRelationId, ExclusiveLock);

      /* Check to see if someone else created same DB name meanwhile. */
!     if (get_db_info(dbname, NULL, NULL, NULL, NULL,
                      NULL, NULL, NULL, NULL, NULL, NULL))
      {
          /* Don't hold lock while doing recursive remove */
***************
*** 487,492 ****
--- 505,511 ----
      new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
      new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
      new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
+     new_record[Anum_pg_database_datmaxconn - 1] = Int32GetDatum(dbmaxconn);
      new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
      new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
      new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
***************
*** 587,593 ****
       */
      pgdbrel = heap_open(DatabaseRelationId, ExclusiveLock);

!     if (!get_db_info(dbname, &db_id, NULL, NULL,
                       &db_istemplate, NULL, NULL, NULL, NULL, NULL))
          ereport(ERROR,
                  (errcode(ERRCODE_UNDEFINED_DATABASE),
--- 606,612 ----
       */
      pgdbrel = heap_open(DatabaseRelationId, ExclusiveLock);

!     if (!get_db_info(dbname, &db_id, NULL, NULL, NULL,
                       &db_istemplate, NULL, NULL, NULL, NULL, NULL))
          ereport(ERROR,
                  (errcode(ERRCODE_UNDEFINED_DATABASE),
***************
*** 783,788 ****
--- 802,892 ----


  /*
+  * ALTER DATABASE name ...
+  */
+ void
+ AlterDatabase(AlterDatabaseStmt *stmt)
+ {
+     Datum        new_record[Natts_pg_database];
+     char        new_record_nulls[Natts_pg_database];
+     char        new_record_repl[Natts_pg_database];
+     Relation    rel;
+     HeapTuple    tuple,
+                 newtuple;
+     ScanKeyData scankey;
+     SysScanDesc scan;
+     ListCell   *option;
+     int            maxconn = -1;    /* Maximum connections allowed */
+
+     DefElem    *dmaxconn = NULL;
+
+     /* Extract options from the statement node tree */
+     foreach(option, stmt->options)
+     {
+         DefElem    *defel = (DefElem *) lfirst(option);
+
+         if (strcmp(defel->defname, "maxconnections") == 0)
+         {
+             if (dmaxconn)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SYNTAX_ERROR),
+                          errmsg("conflicting or redundant options")));
+             dmaxconn = defel;
+         }
+     }
+
+     if (dmaxconn)
+         maxconn = intVal(dmaxconn->arg);
+
+     /*
+      * We don't need ExclusiveLock since we aren't updating the
+      * flat file.
+      */
+     rel = heap_open(DatabaseRelationId, RowExclusiveLock);
+     ScanKeyInit(&scankey,
+                 Anum_pg_database_datname,
+                 BTEqualStrategyNumber, F_NAMEEQ,
+                 NameGetDatum(stmt->dbname));
+     scan = systable_beginscan(rel, DatabaseNameIndexId, true,
+                               SnapshotNow, 1, &scankey);
+     tuple = systable_getnext(scan);
+     if (!HeapTupleIsValid(tuple))
+         ereport(ERROR,
+                 (errcode(ERRCODE_UNDEFINED_DATABASE),
+                  errmsg("database \"%s\" does not exist", stmt->dbname)));
+
+     if (!have_createdb_privilege())
+         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+                        stmt->dbname);
+
+     /*
+      * Build an updated tuple, perusing the information just obtained
+      */
+     MemSet(new_record, 0, sizeof(new_record));
+     MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
+     MemSet(new_record_repl, ' ', sizeof(new_record_repl));
+
+     if (maxconn >= 0)
+     {
+         new_record[Anum_pg_database_datmaxconn - 1] = Int32GetDatum(maxconn);
+         new_record_repl[Anum_pg_database_datmaxconn - 1] = 'r';
+     }
+
+     newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), new_record,
+                                  new_record_nulls, new_record_repl);
+     simple_heap_update(rel, &tuple->t_self, newtuple);
+
+     /* Update indexes */
+     CatalogUpdateIndexes(rel, newtuple);
+
+     systable_endscan(scan);
+
+     /* Close pg_database, but keep lock till commit */
+     heap_close(rel, NoLock);
+ }
+
+
+ /*
   * ALTER DATABASE name SET ...
   */
  void
***************
*** 971,978 ****

  static bool
  get_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP,
!             int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
!             Oid *dbLastSysOidP,
              TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
              Oid *dbTablespace)
  {
--- 1075,1082 ----

  static bool
  get_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP,
!             int *encodingP, int *dbMaxConnP, bool *dbIsTemplateP,
!             bool *dbAllowConnP,    Oid *dbLastSysOidP,
              TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
              Oid *dbTablespace)
  {
***************
*** 1017,1022 ****
--- 1121,1129 ----
          /* allowing connections? */
          if (dbAllowConnP)
              *dbAllowConnP = dbform->datallowconn;
+         /* maximum connections */
+         if (dbMaxConnP)
+             *dbMaxConnP = dbform->datmaxconn;
          /* last system OID used in database */
          if (dbLastSysOidP)
              *dbLastSysOidP = dbform->datlastsysoid;
Index: src/backend/commands/user.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/user.c,v
retrieving revision 1.155
diff -c -r1.155 user.c
*** src/backend/commands/user.c    29 Jun 2005 20:34:13 -0000    1.155
--- src/backend/commands/user.c    3 Jul 2005 22:47:54 -0000
***************
*** 85,90 ****
--- 85,91 ----
      bool        createrole = false;        /* Can this user create roles? */
      bool        createdb = false;        /* Can the user create databases? */
      bool        canlogin = false;        /* Can this user login? */
+     int            maxconn = 0;            /* maximum connections allowed */
      List       *addroleto = NIL;        /* roles to make this a member of */
      List       *rolemembers = NIL;        /* roles to be members of this role */
      List       *adminmembers = NIL;        /* roles to be admins of this role */
***************
*** 94,99 ****
--- 95,101 ----
      DefElem    *dcreaterole = NULL;
      DefElem    *dcreatedb = NULL;
      DefElem    *dcanlogin = NULL;
+     DefElem    *dmaxconn = NULL;
      DefElem    *daddroleto = NULL;
      DefElem    *drolemembers = NULL;
      DefElem    *dadminmembers = NULL;
***************
*** 155,160 ****
--- 157,170 ----
                           errmsg("conflicting or redundant options")));
              dcanlogin = defel;
          }
+         else if (strcmp(defel->defname, "maxconnections") == 0)
+         {
+             if (dmaxconn)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SYNTAX_ERROR),
+                          errmsg("conflicting or redundant options")));
+             dmaxconn = defel;
+         }
          else if (strcmp(defel->defname, "addroleto") == 0)
          {
              if (daddroleto)
***************
*** 202,207 ****
--- 212,230 ----
          createdb = intVal(dcreatedb->arg) != 0;
      if (dcanlogin)
          canlogin = intVal(dcanlogin->arg) != 0;
+     if (dmaxconn)
+     {
+         maxconn = intVal(dmaxconn->arg);
+         if (maxconn < 0)
+             ereport(ERROR,
+                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                      errmsg("MAX CONNECTIONS must not be negative")));
+
+         if (!canlogin && maxconn > 0)
+             ereport(ERROR,
+                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                      errmsg("MAX CONNECTIONS can be specified only for roles which can login")));
+     }
      if (daddroleto)
          addroleto = (List *) daddroleto->arg;
      if (drolemembers)
***************
*** 265,270 ****
--- 288,294 ----
      /* superuser gets catupdate right by default */
      new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
      new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
+     new_record[Anum_pg_authid_rolmaxconn - 1] = Int32GetDatum(maxconn);

      if (password)
      {
***************
*** 369,374 ****
--- 393,399 ----
      int            createrole = -1;        /* Can this user create roles? */
      int            createdb = -1;            /* Can the user create databases? */
      int            canlogin = -1;            /* Can this user login? */
+     int            maxconn = -1;            /* maximum connections allowed */
      List       *rolemembers = NIL;        /* roles to be added/removed */
      char       *validUntil = NULL;        /* time the login is valid until */
      DefElem    *dpassword = NULL;
***************
*** 376,381 ****
--- 401,407 ----
      DefElem    *dcreaterole = NULL;
      DefElem    *dcreatedb = NULL;
      DefElem    *dcanlogin = NULL;
+     DefElem    *dmaxconn = NULL;
      DefElem    *drolemembers = NULL;
      DefElem    *dvalidUntil = NULL;
      Oid            roleid;
***************
*** 431,436 ****
--- 457,470 ----
                           errmsg("conflicting or redundant options")));
              dcanlogin = defel;
          }
+         else if (strcmp(defel->defname, "maxconnections") == 0)
+         {
+             if (dmaxconn)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_SYNTAX_ERROR),
+                          errmsg("conflicting or redundant options")));
+             dmaxconn = defel;
+         }
          else if (strcmp(defel->defname, "rolemembers") == 0 &&
                   stmt->action != 0)
          {
***************
*** 463,468 ****
--- 497,515 ----
          createdb = intVal(dcreatedb->arg);
      if (dcanlogin)
          canlogin = intVal(dcanlogin->arg);
+     if (dmaxconn)
+     {
+         maxconn = intVal(dmaxconn->arg);
+         if (maxconn < 0)
+             ereport(ERROR,
+                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                      errmsg("MAX CONNECTIONS must not be negative")));
+
+         if (canlogin == 0 && maxconn > 0)
+             ereport(ERROR,
+                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                      errmsg("MAX CONNECTIONS can be specified only for roles which can login")));
+     }
      if (drolemembers)
          rolemembers = (List *) drolemembers->arg;
      if (dvalidUntil)
***************
*** 502,507 ****
--- 549,555 ----
              !(createrole < 0 &&
                createdb < 0 &&
                canlogin < 0 &&
+               maxconn < 0 &&
                !rolemembers &&
                !validUntil &&
                password &&
***************
*** 553,558 ****
--- 601,612 ----
          new_record_repl[Anum_pg_authid_rolcanlogin - 1] = 'r';
      }

+     if (maxconn >= 0)
+     {
+         new_record[Anum_pg_authid_rolmaxconn - 1] = Int32GetDatum(maxconn);
+         new_record_repl[Anum_pg_authid_rolmaxconn - 1] = 'r';
+     }
+
      /* password */
      if (password)
      {
Index: src/backend/libpq/crypt.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/libpq/crypt.c,v
retrieving revision 1.64
diff -c -r1.64 crypt.c
*** src/backend/libpq/crypt.c    29 Jun 2005 22:51:54 -0000    1.64
--- src/backend/libpq/crypt.c    3 Jul 2005 22:47:57 -0000
***************
*** 42,52 ****
      if ((line = get_role_line(role)) == NULL)
          return STATUS_ERROR;

!     /* Skip over rolename */
      token = list_head(*line);
      if (token)
          token = lnext(token);
      if (token)
      {
          shadow_pass = (char *) lfirst(token);
          token = lnext(token);
--- 42,54 ----
      if ((line = get_role_line(role)) == NULL)
          return STATUS_ERROR;

!     /* Skip over rolename and roleid */
      token = list_head(*line);
      if (token)
          token = lnext(token);
      if (token)
+         token = lnext(token);
+     if (token)
      {
          shadow_pass = (char *) lfirst(token);
          token = lnext(token);
Index: src/backend/libpq/hba.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/libpq/hba.c,v
retrieving revision 1.144
diff -c -r1.144 hba.c
*** src/backend/libpq/hba.c    28 Jun 2005 22:16:45 -0000    1.144
--- src/backend/libpq/hba.c    3 Jul 2005 22:48:12 -0000
***************
*** 494,505 ****
          return true;

      /*
!      * skip over the role name, password, valuntil, examine all the
       * membership entries
       */
!     if (list_length(*line) < 4)
          return false;
!     for_each_cell(line_item, lnext(lnext(lnext(list_head(*line)))))
      {
          if (strcmp((char *) lfirst(line_item), role) == 0)
              return true;
--- 494,505 ----
          return true;

      /*
!      * skip over the role name, id, password, valuntil, examine all the
       * membership entries
       */
!     if (list_length(*line) < 5)
          return false;
!     for_each_cell(line_item, lnext(lnext(lnext(lnext(list_head(*line))))))
      {
          if (strcmp((char *) lfirst(line_item), role) == 0)
              return true;
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.311
diff -c -r1.311 copyfuncs.c
*** src/backend/nodes/copyfuncs.c    2 Jul 2005 23:00:39 -0000    1.311
--- src/backend/nodes/copyfuncs.c    3 Jul 2005 22:48:36 -0000
***************
*** 2204,2209 ****
--- 2204,2220 ----
      return newnode;
  }

+ static AlterDatabaseStmt *
+ _copyAlterDatabaseStmt(AlterDatabaseStmt *from)
+ {
+     AlterDatabaseStmt *newnode = makeNode(AlterDatabaseStmt);
+
+     COPY_STRING_FIELD(dbname);
+     COPY_NODE_FIELD(options);
+
+     return newnode;
+ }
+
  static AlterDatabaseSetStmt *
  _copyAlterDatabaseSetStmt(AlterDatabaseSetStmt *from)
  {
***************
*** 3010,3015 ****
--- 3021,3029 ----
          case T_CreatedbStmt:
              retval = _copyCreatedbStmt(from);
              break;
+         case T_AlterDatabaseStmt:
+             retval = _copyAlterDatabaseStmt(from);
+             break;
          case T_AlterDatabaseSetStmt:
              retval = _copyAlterDatabaseSetStmt(from);
              break;
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.248
diff -c -r1.248 equalfuncs.c
*** src/backend/nodes/equalfuncs.c    2 Jul 2005 23:00:39 -0000    1.248
--- src/backend/nodes/equalfuncs.c    3 Jul 2005 22:48:53 -0000
***************
*** 1152,1157 ****
--- 1152,1166 ----
  }

  static bool
+ _equalAlterDatabaseStmt(AlterDatabaseStmt *a, AlterDatabaseStmt *b)
+ {
+     COMPARE_STRING_FIELD(dbname);
+     COMPARE_NODE_FIELD(options);
+
+     return true;
+ }
+
+ static bool
  _equalAlterDatabaseSetStmt(AlterDatabaseSetStmt *a, AlterDatabaseSetStmt *b)
  {
      COMPARE_STRING_FIELD(dbname);
***************
*** 2058,2063 ****
--- 2067,2075 ----
          case T_CreatedbStmt:
              retval = _equalCreatedbStmt(a, b);
              break;
+         case T_AlterDatabaseStmt:
+             retval = _equalAlterDatabaseStmt(a, b);
+             break;
          case T_AlterDatabaseSetStmt:
              retval = _equalAlterDatabaseSetStmt(a, b);
              break;
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.501
diff -c -r2.501 gram.y
*** src/backend/parser/gram.y    29 Jun 2005 20:34:13 -0000    2.501
--- src/backend/parser/gram.y    3 Jul 2005 22:50:20 -0000
***************
*** 131,139 ****
  }

  %type <node>    stmt schema_stmt
!         AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt AlterOwnerStmt
!         AlterSeqStmt AlterTableStmt AlterUserStmt AlterUserSetStmt
!         AlterRoleStmt AlterRoleSetStmt
          AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
          ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
          CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt
--- 131,139 ----
  }

  %type <node>    stmt schema_stmt
!         AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt
!         AlterOwnerStmt AlterSeqStmt AlterTableStmt
!         AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
          AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
          ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
          CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt
***************
*** 165,172 ****

  %type <dbehavior>    opt_drop_behavior

! %type <list>    createdb_opt_list copy_opt_list transaction_mode_list
! %type <defelt>    createdb_opt_item copy_opt_item transaction_mode_item

  %type <ival>    opt_lock lock_type cast_context
  %type <boolean>    opt_force opt_or_replace
--- 165,174 ----

  %type <dbehavior>    opt_drop_behavior

! %type <list>    createdb_opt_list alterdb_opt_list copy_opt_list
!                 transaction_mode_list
! %type <defelt>    createdb_opt_item alterdb_opt_item copy_opt_item
!                 transaction_mode_item

  %type <ival>    opt_lock lock_type cast_context
  %type <boolean>    opt_force opt_or_replace
***************
*** 342,348 ****
      CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P
      CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
      CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
!     COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
      CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
      CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE

--- 344,350 ----
      CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P
      CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
      CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
!     COMMITTED CONNECTIONS CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
      CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
      CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE

***************
*** 373,379 ****
      LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
      LOCK_P LOGIN_P

!     MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE

      NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
      NOCREATEROLE NOCREATEUSER NOLOGIN_P NONE NOSUPERUSER NOT NOTHING NOTIFY
--- 375,381 ----
      LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
      LOCK_P LOGIN_P

!     MATCH MAX MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE

      NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
      NOCREATEROLE NOCREATEUSER NOLOGIN_P NONE NOSUPERUSER NOT NOTHING NOTIFY
***************
*** 486,492 ****
          ;

  stmt :
!             AlterDatabaseSetStmt
              | AlterDomainStmt
              | AlterFunctionStmt
              | AlterGroupStmt
--- 488,495 ----
          ;

  stmt :
!             AlterDatabaseStmt
!             | AlterDatabaseSetStmt
              | AlterDomainStmt
              | AlterFunctionStmt
              | AlterGroupStmt
***************
*** 663,668 ****
--- 666,675 ----
                  {
                      $$ = makeDefElem("canlogin", (Node *)makeInteger(FALSE));
                  }
+             | MAX CONNECTIONS Iconst
+                 {
+                     $$ = makeDefElem("maxconnections", (Node *)makeInteger($3));
+                 }
              | IN_P ROLE name_list
                  {
                      $$ = makeDefElem("addroleto", (Node *)$3);
***************
*** 4455,4460 ****
--- 4462,4471 ----
                  {
                      $$ = makeDefElem("encoding", NULL);
                  }
+             | MAX CONNECTIONS opt_equal Iconst
+                 {
+                     $$ = makeDefElem("maxconnections", (Node *)makeInteger($4));
+                 }
              | OWNER opt_equal name
                  {
                      $$ = makeDefElem("owner", (Node *)makeString($3));
***************
*** 4481,4486 ****
--- 4492,4507 ----
   *
   *****************************************************************************/

+ AlterDatabaseStmt:
+              ALTER DATABASE database_name opt_with alterdb_opt_list
+                  {
+                     AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
+                     n->dbname = $3;
+                     n->options = $5;
+                     $$ = (Node *)n;
+                  }
+         ;
+
  AlterDatabaseSetStmt:
              ALTER DATABASE database_name SET set_rest
                  {
***************
*** 4501,4506 ****
--- 4522,4540 ----
          ;


+ alterdb_opt_list:
+             alterdb_opt_list alterdb_opt_item        { $$ = lappend($1, $2); }
+             | /* EMPTY */                            { $$ = NIL; }
+         ;
+
+ alterdb_opt_item:
+             MAX CONNECTIONS opt_equal Iconst
+                 {
+                     $$ = makeDefElem("maxconnections", (Node *)makeInteger($4));
+                 }
+         ;
+
+
  /*****************************************************************************
   *
   *        DROP DATABASE
***************
*** 7941,7946 ****
--- 7975,7981 ----
              | COMMENT
              | COMMIT
              | COMMITTED
+             | CONNECTIONS
              | CONSTRAINTS
              | CONVERSION_P
              | COPY
***************
*** 8009,8014 ****
--- 8044,8050 ----
              | LOCK_P
              | LOGIN_P
              | MATCH
+             | MAX
              | MAXVALUE
              | MINUTE_P
              | MINVALUE
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.162
diff -c -r1.162 keywords.c
*** src/backend/parser/keywords.c    29 Jun 2005 20:34:14 -0000    1.162
--- src/backend/parser/keywords.c    3 Jul 2005 22:50:24 -0000
***************
*** 83,88 ****
--- 83,89 ----
      {"comment", COMMENT},
      {"commit", COMMIT},
      {"committed", COMMITTED},
+     {"connections", CONNECTIONS},
      {"constraint", CONSTRAINT},
      {"constraints", CONSTRAINTS},
      {"conversion", CONVERSION_P},
***************
*** 203,208 ****
--- 204,210 ----
      {"lock", LOCK_P},
      {"login", LOGIN_P},
      {"match", MATCH},
+     {"max", MAX},
      {"maxvalue", MAXVALUE},
      {"minute", MINUTE_P},
      {"minvalue", MINVALUE},
Index: src/backend/storage/ipc/procarray.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/storage/ipc/procarray.c,v
retrieving revision 1.3
diff -c -r1.3 procarray.c
*** src/backend/storage/ipc/procarray.c    17 Jun 2005 22:32:45 -0000    1.3
--- src/backend/storage/ipc/procarray.c    3 Jul 2005 22:50:36 -0000
***************
*** 734,739 ****
--- 734,790 ----
  }


+ /*
+  * CountDBBackends --- count backends that are using specified database
+  */
+ int
+ CountDBBackends(Oid databaseid)
+ {
+     ProcArrayStruct *arrayP = procArray;
+     int            count = 0;
+     int            index;
+
+     LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+     for (index = 0; index < arrayP->numProcs; index++)
+     {
+         PGPROC       *proc = arrayP->procs[index];
+
+         if (proc->pid != 0 && proc->databaseId == databaseid)
+             count++;
+     }
+
+     LWLockRelease(ProcArrayLock);
+
+     return count;
+ }
+
+ /*
+  * CountUserBackends --- count backends that are used by specified user
+  */
+ int
+ CountUserBackends(Oid roleid)
+ {
+     ProcArrayStruct *arrayP = procArray;
+     int            count = 0;
+     int            index;
+
+     LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+     for (index = 0; index < arrayP->numProcs; index++)
+     {
+         PGPROC       *proc = arrayP->procs[index];
+
+         if (proc->pid != 0 && proc->roleId == roleid)
+             count++;
+     }
+
+     LWLockRelease(ProcArrayLock);
+
+     return count;
+ }
+
+
  #define XidCacheRemove(i) \
      do { \
          MyProc->subxids.xids[i] = MyProc->subxids.xids[MyProc->subxids.nxids - 1]; \
Index: src/backend/storage/lmgr/proc.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v
retrieving revision 1.160
diff -c -r1.160 proc.c
*** src/backend/storage/lmgr/proc.c    17 Jun 2005 22:32:45 -0000    1.160
--- src/backend/storage/lmgr/proc.c    3 Jul 2005 22:50:51 -0000
***************
*** 254,259 ****
--- 254,260 ----
      MyProc->xmin = InvalidTransactionId;
      MyProc->pid = MyProcPid;
      MyProc->databaseId = MyDatabaseId;
+     MyProc->roleId = GetSessionUserId();
      MyProc->lwWaiting = false;
      MyProc->lwExclusive = false;
      MyProc->lwWaitLink = NULL;
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.240
diff -c -r1.240 utility.c
*** src/backend/tcop/utility.c    30 Jun 2005 00:00:51 -0000    1.240
--- src/backend/tcop/utility.c    3 Jul 2005 22:51:06 -0000
***************
*** 275,280 ****
--- 275,281 ----

      switch (nodeTag(parsetree))
      {
+         case T_AlterDatabaseStmt:
          case T_AlterDatabaseSetStmt:
          case T_AlterDomainStmt:
          case T_AlterFunctionStmt:
***************
*** 788,793 ****
--- 789,798 ----
              createdb((CreatedbStmt *) parsetree);
              break;

+         case T_AlterDatabaseStmt:
+             AlterDatabase((AlterDatabaseStmt *) parsetree);
+             break;
+
          case T_AlterDatabaseSetStmt:
              AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
              break;
***************
*** 1504,1509 ****
--- 1509,1518 ----
              tag = "CREATE DATABASE";
              break;

+         case T_AlterDatabaseStmt:
+             tag = "ALTER DATABASE";
+             break;
+
          case T_AlterDatabaseSetStmt:
              tag = "ALTER DATABASE";
              break;
Index: src/backend/utils/init/flatfiles.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/flatfiles.c,v
retrieving revision 1.11
diff -c -r1.11 flatfiles.c
*** src/backend/utils/init/flatfiles.c    29 Jun 2005 20:34:15 -0000    1.11
--- src/backend/utils/init/flatfiles.c    3 Jul 2005 22:51:18 -0000
***************
*** 629,635 ****
              ListCell *mem;

              fputs_quote(arole->rolname, fp);
!             fputs(" ", fp);
              fputs_quote(arole->rolpassword, fp);
              fputs(" ", fp);
              fputs_quote(arole->rolvaliduntil, fp);
--- 629,635 ----
              ListCell *mem;

              fputs_quote(arole->rolname, fp);
!             fprintf(fp, " %u ", arole->roleid);
              fputs_quote(arole->rolpassword, fp);
              fputs(" ", fp);
              fputs_quote(arole->rolvaliduntil, fp);
Index: src/backend/utils/init/miscinit.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/miscinit.c,v
retrieving revision 1.144
diff -c -r1.144 miscinit.c
*** src/backend/utils/init/miscinit.c    28 Jun 2005 22:16:45 -0000    1.144
--- src/backend/utils/init/miscinit.c    3 Jul 2005 22:51:29 -0000
***************
*** 39,44 ****
--- 39,45 ----
  #include "utils/guc.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
+ #include "storage/procarray.h"


  ProcessingMode Mode = InitProcessing;
***************
*** 347,352 ****
--- 348,365 ----

      SetSessionUserId(roleid);    /* sets CurrentUserId too */

+     /*
+      * Check connection limit for user
+      */
+     if (rform->rolmaxconn > 0 && !AuthenticatedUserIsSuperuser &&
+             CountUserBackends(AuthenticatedUserId) > rform->rolmaxconn)
+     {
+         ereport(FATAL,
+             (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
+          errmsg("sorry, too many clients already for role \"%s\"",
+             rolename)));
+     }
+
      /* Record username and superuser status as GUC settings too */
      SetConfigOption("session_authorization", rolename,
                      PGC_BACKEND, PGC_S_OVERRIDE);
Index: src/backend/utils/init/postinit.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.151
diff -c -r1.151 postinit.c
*** src/backend/utils/init/postinit.c    28 Jun 2005 19:51:23 -0000    1.151
--- src/backend/utils/init/postinit.c    3 Jul 2005 22:51:37 -0000
***************
*** 47,52 ****
--- 47,53 ----


  static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
+ static bool FindMyRole(const char *name, Oid *role_id);
  static void ReverifyMyDatabase(const char *name);
  static void InitCommunication(void);
  static void ShutdownPostgres(int code, Datum arg);
***************
*** 101,106 ****
--- 102,136 ----
  }

  /*
+  * Get roleid from flatfiles
+  *
+  * We need this because we need to know userid before
+  * InitProcess() is called
+  */
+ static bool
+ FindMyRole(const char *name, Oid *role_id)
+ {
+     List      **line;
+     ListCell   *token;
+
+     if ((line = get_role_line(name)) == NULL)
+         ereport(FATAL,
+                 (ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION,
+                  errmsg("could not find role \"%s\"", name)));
+
+     token = list_head(*line);
+     if (token)
+         token = lnext(token);
+     if (token)
+     {
+         *role_id = atoi((char*)lfirst(token));
+         return true;
+     }
+
+     return false;
+ }
+
+ /*
   * ReverifyMyDatabase -- recheck info obtained by FindMyDatabase
   *
   * Since FindMyDatabase cannot lock pg_database, the information it read
***************
*** 166,182 ****
                          name, MyDatabaseId)));
      }

-     /*
-      * Also check that the database is currently allowing connections.
-      * (We do not enforce this in standalone mode, however, so that there is
-      * a way to recover from "UPDATE pg_database SET datallowconn = false;")
-      */
      dbform = (Form_pg_database) GETSTRUCT(tup);
!     if (IsUnderPostmaster && !dbform->datallowconn)
!         ereport(FATAL,
!                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
!          errmsg("database \"%s\" is not currently accepting connections",
                  name)));

      /*
       * OK, we're golden.  Next to-do item is to save the encoding
--- 196,230 ----
                          name, MyDatabaseId)));
      }

      dbform = (Form_pg_database) GETSTRUCT(tup);
!     if (IsUnderPostmaster)
!     {
!         /*
!          * Also check that the database is currently allowing connections.
!          * (We do not enforce this in standalone mode, however, so that there is
!          * a way to recover from "UPDATE pg_database SET datallowconn = false;")
!          */
!         if (!dbform->datallowconn)
!         {
!             ereport(FATAL,
!                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
!              errmsg("database \"%s\" is not currently accepting connections",
!                     name)));
!         }
!
!         /*
!          * Here we check cxonenction limit for this database
!          */
!         if (dbform->datmaxconn > 0 && !superuser() &&
!                 CountDBBackends(MyDatabaseId) > dbform->datmaxconn)
!         {
!             ereport(FATAL,
!                 (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
!              errmsg("sorry, too many clients already for database \"%s\"",
                  name)));
+         }
+     }
+

      /*
       * OK, we're golden.  Next to-do item is to save the encoding
***************
*** 352,357 ****
--- 400,424 ----
       */

      /*
+      * We need to know roleid in InitProcess() so we have read it from
+      * flatfile, real user inicialization is done later
+      */
+     if (IsUnderPostmaster)
+     {
+         Oid roleid;
+
+         if (!FindMyRole(username, &roleid))
+             ereport(FATAL,
+                     (ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION,
+                      errmsg("role \"%s\" does not exist",
+                             username)));
+
+         SetSessionUserId(roleid);
+     }
+     else
+         SetSessionUserId(BOOTSTRAP_SUPERUSERID);
+
+     /*
       * Set up my per-backend PGPROC struct in shared memory.    (We need
       * to know MyDatabaseId before we can do this, since it's entered into
       * the PGPROC struct.)
Index: src/include/catalog/pg_authid.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_authid.h,v
retrieving revision 1.1
diff -c -r1.1 pg_authid.h
*** src/include/catalog/pg_authid.h    28 Jun 2005 05:09:05 -0000    1.1
--- src/include/catalog/pg_authid.h    3 Jul 2005 22:51:50 -0000
***************
*** 48,53 ****
--- 48,54 ----
      bool        rolcreatedb;    /* allowed to create databases? */
      bool        rolcatupdate;    /* allowed to alter catalogs manually? */
      bool        rolcanlogin;    /* allowed to log in as session user? */
+     int4        rolmaxconn;        /* maximum connections allowed */

      /* remaining fields may be null; use heap_getattr to read them! */
      text        rolpassword;    /* password, if any */
***************
*** 69,84 ****
   *        compiler constants for pg_authid
   * ----------------
   */
! #define Natts_pg_authid                    9
  #define Anum_pg_authid_rolname            1
  #define Anum_pg_authid_rolsuper            2
  #define Anum_pg_authid_rolcreaterole    3
  #define Anum_pg_authid_rolcreatedb        4
  #define Anum_pg_authid_rolcatupdate        5
  #define Anum_pg_authid_rolcanlogin        6
! #define Anum_pg_authid_rolpassword        7
! #define Anum_pg_authid_rolvaliduntil    8
! #define Anum_pg_authid_rolconfig        9

  /* ----------------
   *        initial contents of pg_authid
--- 70,86 ----
   *        compiler constants for pg_authid
   * ----------------
   */
! #define Natts_pg_authid                    10
  #define Anum_pg_authid_rolname            1
  #define Anum_pg_authid_rolsuper            2
  #define Anum_pg_authid_rolcreaterole    3
  #define Anum_pg_authid_rolcreatedb        4
  #define Anum_pg_authid_rolcatupdate        5
  #define Anum_pg_authid_rolcanlogin        6
! #define Anum_pg_authid_rolmaxconn        7
! #define Anum_pg_authid_rolpassword        8
! #define Anum_pg_authid_rolvaliduntil    9
! #define Anum_pg_authid_rolconfig        10

  /* ----------------
   *        initial contents of pg_authid
***************
*** 87,93 ****
   * user choices.
   * ----------------
   */
! DATA(insert OID = 10 ( "POSTGRES" t t t t t _null_ _null_ _null_ ));

  #define BOOTSTRAP_SUPERUSERID 10

--- 89,95 ----
   * user choices.
   * ----------------
   */
! DATA(insert OID = 10 ( "POSTGRES" t t t t t 0 _null_ _null_ _null_ ));

  #define BOOTSTRAP_SUPERUSERID 10

Index: src/include/catalog/pg_database.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_database.h,v
retrieving revision 1.36
diff -c -r1.36 pg_database.h
*** src/include/catalog/pg_database.h    28 Jun 2005 05:09:06 -0000    1.36
--- src/include/catalog/pg_database.h    3 Jul 2005 22:51:51 -0000
***************
*** 40,45 ****
--- 40,46 ----
      int4        encoding;        /* character encoding */
      bool        datistemplate;    /* allowed as CREATE DATABASE template? */
      bool        datallowconn;    /* new connections allowed? */
+     int4        datmaxconn;        /* maximum connections allowed */
      Oid            datlastsysoid;    /* highest OID to consider a system OID */
      TransactionId datvacuumxid; /* all XIDs before this are vacuumed */
      TransactionId datfrozenxid; /* all XIDs before this are frozen */
***************
*** 59,78 ****
   *        compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database                11
  #define Anum_pg_database_datname        1
  #define Anum_pg_database_datdba            2
  #define Anum_pg_database_encoding        3
  #define Anum_pg_database_datistemplate    4
  #define Anum_pg_database_datallowconn    5
! #define Anum_pg_database_datlastsysoid    6
! #define Anum_pg_database_datvacuumxid    7
! #define Anum_pg_database_datfrozenxid    8
! #define Anum_pg_database_dattablespace    9
! #define Anum_pg_database_datconfig        10
! #define Anum_pg_database_datacl            11

! DATA(insert OID = 1 (  template1 PGUID ENCODING t t 0 0 0 1663 _null_ _null_ ));
  DESCR("Default template database");
  #define TemplateDbOid            1

--- 60,80 ----
   *        compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database                12
  #define Anum_pg_database_datname        1
  #define Anum_pg_database_datdba            2
  #define Anum_pg_database_encoding        3
  #define Anum_pg_database_datistemplate    4
  #define Anum_pg_database_datallowconn    5
! #define Anum_pg_database_datmaxconn        6
! #define Anum_pg_database_datlastsysoid    7
! #define Anum_pg_database_datvacuumxid    8
! #define Anum_pg_database_datfrozenxid    9
! #define Anum_pg_database_dattablespace    10
! #define Anum_pg_database_datconfig        11
! #define Anum_pg_database_datacl            12

! DATA(insert OID = 1 (  template1 PGUID ENCODING t t 0 0 0 0 1663 _null_ _null_ ));
  DESCR("Default template database");
  #define TemplateDbOid            1

Index: src/include/commands/dbcommands.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/dbcommands.h,v
retrieving revision 1.39
diff -c -r1.39 dbcommands.h
*** src/include/commands/dbcommands.h    28 Jun 2005 05:09:12 -0000    1.39
--- src/include/commands/dbcommands.h    3 Jul 2005 22:51:53 -0000
***************
*** 64,69 ****
--- 64,70 ----
  extern void createdb(const CreatedbStmt *stmt);
  extern void dropdb(const char *dbname);
  extern void RenameDatabase(const char *oldname, const char *newname);
+ extern void AlterDatabase(AlterDatabaseStmt *stmt);
  extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
  extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId);

Index: src/include/nodes/nodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.172
diff -c -r1.172 nodes.h
*** src/include/nodes/nodes.h    28 Jun 2005 05:09:13 -0000    1.172
--- src/include/nodes/nodes.h    3 Jul 2005 22:52:00 -0000
***************
*** 270,275 ****
--- 270,276 ----
      T_ReindexStmt,
      T_CheckPointStmt,
      T_CreateSchemaStmt,
+     T_AlterDatabaseStmt,
      T_AlterDatabaseSetStmt,
      T_AlterRoleSetStmt,
      T_CreateConversionStmt,
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.285
diff -c -r1.285 parsenodes.h
*** src/include/nodes/parsenodes.h    28 Jun 2005 19:51:24 -0000    1.285
--- src/include/nodes/parsenodes.h    3 Jul 2005 22:52:25 -0000
***************
*** 1611,1616 ****
--- 1611,1623 ----
   *    Alter Database
   * ----------------------
   */
+ typedef struct AlterDatabaseStmt
+ {
+     NodeTag        type;
+     char       *dbname;            /* name of database to alter */
+     List       *options;        /* List of DefElem nodes */
+ } AlterDatabaseStmt;
+
  typedef struct AlterDatabaseSetStmt
  {
      NodeTag        type;
Index: src/include/storage/proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/storage/proc.h,v
retrieving revision 1.79
diff -c -r1.79 proc.h
*** src/include/storage/proc.h    17 Jun 2005 22:32:50 -0000    1.79
--- src/include/storage/proc.h    3 Jul 2005 22:52:29 -0000
***************
*** 71,76 ****
--- 71,77 ----

      int            pid;            /* This backend's process id, or 0 */
      Oid            databaseId;        /* OID of database this backend is using */
+     Oid            roleId;            /* OID of role using conencted to backend */

      /* Info about LWLock the process is currently waiting for, if any. */
      bool        lwWaiting;        /* true if waiting for an LW lock */
Index: src/include/storage/procarray.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/storage/procarray.h,v
retrieving revision 1.2
diff -c -r1.2 procarray.h
*** src/include/storage/procarray.h    17 Jun 2005 22:32:50 -0000    1.2
--- src/include/storage/procarray.h    3 Jul 2005 22:52:30 -0000
***************
*** 31,36 ****
--- 31,38 ----
  extern bool DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself);

  extern int    CountActiveBackends(void);
+ extern int    CountDBBackends(Oid databaseid);
+ extern int    CountUserBackends(Oid roleid);

  extern void XidCacheRemoveRunningXids(TransactionId xid,
                            int nxids, TransactionId *xids);
Index: src/tools/pgindent/pgindent
===================================================================
RCS file: /projects/cvsroot/pgsql/src/tools/pgindent/pgindent,v
retrieving revision 1.75
diff -c -r1.75 pgindent
*** src/tools/pgindent/pgindent    28 Jun 2005 23:55:30 -0000    1.75
--- src/tools/pgindent/pgindent    3 Jul 2005 22:53:03 -0000
***************
*** 177,182 ****
--- 177,183 ----
  -TAllocSetContext \
  -TAllocateDesc \
  -TAllocateDescKind \
+ -TAlterDatabaseStmt \
  -TAlterDatabaseSetStmt \
  -TAlterDomainStmt \
  -TAlterFunctionStmt \

pgsql-patches by date:

Previous
From: Simon Riggs
Date:
Subject: Re: Constraint Exclusion (Partitioning) - Initial Review
Next
From: Euler Taveira de Oliveira
Date:
Subject: reindexdb into scripts