> Patch includes only changes to backend, I will make pg_dump, ecpg and > documentation patches once this is completed and accepted by team.
I am ready to apply this patch. Would you make the additional changes you suggested? Is there any way to see the limits except to query pg_authid? --------------------------------------------------------------------------- Petr Jelinek wrote: > 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 \ -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073 ---------------------------(end of broadcast)--------------------------- TIP 3: Have you checked our extensive FAQ? http://www.postgresql.org/docs/faq