2222 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
2323 * Portions Copyright (c) 1994, Regents of the University of California
2424 *
25- * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.1 2005/02/2002:22:00 tgl Exp $
25+ * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.2 2005/02/2004:45:59 tgl Exp $
2626 *
2727 *-------------------------------------------------------------------------
2828 */
@@ -278,7 +278,7 @@ write_database_file(Relation drel)
278278}
279279
280280/*
281- *File format is: "dbname" oid frozenxid
281+ *The file format is: "dbname" oid frozenxid
282282 *
283283 * The xid is not needed for backend startup, but may be of use
284284 * for forensic purposes.
@@ -317,13 +317,6 @@ write_database_file(Relation drel)
317317
318318/*
319319 * write_group_file: update the flat group file
320- *
321- * XXX this will never be able to work during system bootstrap: we don't
322- * have either TOAST support or SysCache support. Need to redefine both
323- * the catalog and file contents to fix this completely. In the short term
324- * we can handle everything except an out-of-line-toasted grolist, if we
325- * change the flat file definition to store numeric sysids instead of
326- * user names.
327320 */
328321static void
329322write_group_file (Relation grel )
@@ -335,7 +328,6 @@ write_group_file(Relation grel)
335328mode_t oumask ;
336329HeapScanDesc scan ;
337330HeapTuple tuple ;
338- TupleDesc dsc = RelationGetDescr (grel );
339331
340332/*
341333 * Create a temporary filename to be renamed later. This prevents the
@@ -364,22 +356,19 @@ write_group_file(Relation grel)
364356scan = heap_beginscan (grel ,SnapshotSelf ,0 ,NULL );
365357while ((tuple = heap_getnext (scan ,ForwardScanDirection ))!= NULL )
366358{
367- Datum datum ,
368- grolist_datum ;
369- bool isnull ;
359+ Form_pg_group grpform = (Form_pg_group )GETSTRUCT (tuple );
360+ HeapTupleHeader tup = tuple -> t_data ;
361+ char * tp ;/* ptr to tuple data */
362+ long off ;/* offset in tuple data */
363+ bits8 * bp = tup -> t_bits ;/* ptr to null bitmask in tuple */
364+ Datum datum ;
370365char * groname ;
371366IdList * grolist_p ;
372367AclId * aidp ;
373368int i ,
374369num ;
375- char * usename ;
376- bool first_user = true;
377370
378- datum = heap_getattr (tuple ,Anum_pg_group_groname ,dsc ,& isnull );
379- /* ignore NULL groupnames --- shouldn't happen */
380- if (isnull )
381- continue ;
382- groname = NameStr (* DatumGetName (datum ));
371+ groname = NameStr (grpform -> groname );
383372
384373/*
385374 * Check for illegal characters in the group name.
@@ -391,57 +380,58 @@ write_group_file(Relation grel)
391380continue ;
392381}
393382
394- grolist_datum = heap_getattr (tuple ,Anum_pg_group_grolist ,dsc ,& isnull );
395- /* Ignore NULL group lists */
396- if (isnull )
383+ /*
384+ * We can't use heap_getattr() here because during startup we will
385+ * not have any tupdesc for pg_group. Fortunately it's not too
386+ * hard to work around this. grolist is the first possibly-null
387+ * field so we can compute its offset directly.
388+ */
389+ tp = (char * )tup + tup -> t_hoff ;
390+ off = offsetof(FormData_pg_group ,grolist );
391+
392+ if (HeapTupleHasNulls (tuple )&&
393+ att_isnull (Anum_pg_group_grolist - 1 ,bp ))
394+ {
395+ /* grolist is null, so we can ignore this group */
396+ continue ;
397+ }
398+
399+ /* assume grolist is pass-by-ref */
400+ datum = PointerGetDatum (tp + off );
401+
402+ /*
403+ * We can't currently support out-of-line toasted group lists in
404+ * startup mode (the tuptoaster won't work). This sucks, but it
405+ * should be something of a corner case. Live with it until we
406+ * can redesign pg_group.
407+ *
408+ * Detect startup mode by noting whether we got a tupdesc.
409+ */
410+ if (VARATT_IS_EXTERNAL (DatumGetPointer (datum ))&&
411+ RelationGetDescr (grel )== NULL )
397412continue ;
398413
399414/* be sure the IdList is not toasted */
400- grolist_p = DatumGetIdListP (grolist_datum );
415+ grolist_p = DatumGetIdListP (datum );
401416
402- /* scan grolist */
403- num = IDLIST_NUM (grolist_p );
417+ /*
418+ * The file format is: "groupname" usesysid1 usesysid2 ...
419+ *
420+ * We ignore groups that have no members.
421+ */
404422aidp = IDLIST_DAT (grolist_p );
405- for (i = 0 ;i < num ;++ i )
423+ num = IDLIST_NUM (grolist_p );
424+ if (num > 0 )
406425{
407- tuple = SearchSysCache (SHADOWSYSID ,
408- PointerGetDatum (aidp [i ]),
409- 0 ,0 ,0 );
410- if (HeapTupleIsValid (tuple ))
411- {
412- usename = NameStr (((Form_pg_shadow )GETSTRUCT (tuple ))-> usename );
413-
414- /*
415- * Check for illegal characters in the user name.
416- */
417- if (!name_okay (usename ))
418- {
419- ereport (LOG ,
420- (errmsg ("invalid user name \"%s\"" ,usename )));
421- continue ;
422- }
423-
424- /*
425- * File format is: "groupname" "user1" "user2" "user3"
426- */
427- if (first_user )
428- {
429- fputs_quote (groname ,fp );
430- fputs ("\t" ,fp );
431- first_user = false;
432- }
433- else
434- fputs (" " ,fp );
435-
436- fputs_quote (usename ,fp );
437-
438- ReleaseSysCache (tuple );
439- }
440- }
441- if (!first_user )
426+ fputs_quote (groname ,fp );
427+ fprintf (fp ,"\t%u" ,aidp [0 ]);
428+ for (i = 1 ;i < num ;++ i )
429+ fprintf (fp ," %u" ,aidp [i ]);
442430fputs ("\n" ,fp );
431+ }
432+
443433/* if IdList was toasted, free detoasted copy */
444- if ((Pointer )grolist_p != DatumGetPointer (grolist_datum ))
434+ if ((Pointer )grolist_p != DatumGetPointer (datum ))
445435pfree (grolist_p );
446436}
447437heap_endscan (scan );
@@ -517,8 +507,10 @@ write_user_file(Relation urel)
517507char * usename ,
518508* passwd ,
519509* valuntil ;
510+ AclId usesysid ;
520511
521512usename = NameStr (pwform -> usename );
513+ usesysid = pwform -> usesysid ;
522514
523515/*
524516 * We can't use heap_getattr() here because during startup we will
@@ -532,30 +524,26 @@ write_user_file(Relation urel)
532524if (HeapTupleHasNulls (tuple )&&
533525att_isnull (Anum_pg_shadow_passwd - 1 ,bp ))
534526{
535- /*
536- * It can be argued that people having a null password shouldn't
537- * be allowed to connect under password authentication, because
538- * they need to have a password set up first. If you think
539- * assuming an empty password in that case is better, change this
540- * logic to look something like the code for valuntil.
541- */
542- continue ;
527+ /* passwd is null, emit as an empty string */
528+ passwd = pstrdup ("" );
543529}
530+ else
531+ {
532+ /* assume passwd is pass-by-ref */
533+ datum = PointerGetDatum (tp + off );
544534
545- /* assume passwd is pass-by-ref */
546- datum = PointerGetDatum (tp + off );
547-
548- /*
549- * The password probably shouldn't ever be out-of-line toasted;
550- * if it is, ignore it, since we can't handle that in startup mode.
551- */
552- if (VARATT_IS_EXTERNAL (DatumGetPointer (datum )))
553- continue ;
554-
555- passwd = DatumGetCString (DirectFunctionCall1 (textout ,datum ));
535+ /*
536+ * The password probably shouldn't ever be out-of-line toasted;
537+ * if it is, ignore it, since we can't handle that in startup mode.
538+ */
539+ if (VARATT_IS_EXTERNAL (DatumGetPointer (datum )))
540+ passwd = pstrdup ("" );
541+ else
542+ passwd = DatumGetCString (DirectFunctionCall1 (textout ,datum ));
556543
557- /* assume passwd has attlen -1 */
558- off = att_addlength (off ,-1 ,tp + off );
544+ /* assume passwd has attlen -1 */
545+ off = att_addlength (off ,-1 ,tp + off );
546+ }
559547
560548if (HeapTupleHasNulls (tuple )&&
561549att_isnull (Anum_pg_shadow_valuntil - 1 ,bp ))
@@ -588,8 +576,11 @@ write_user_file(Relation urel)
588576continue ;
589577}
590578
579+ /*
580+ * The file format is: "usename" usesysid "passwd" "valuntil"
581+ */
591582fputs_quote (usename ,fp );
592- fputs ( " " ,fp );
583+ fprintf ( fp , " %u " ,usesysid );
593584fputs_quote (passwd ,fp );
594585fputs (" " ,fp );
595586fputs_quote (valuntil ,fp );
@@ -664,17 +655,13 @@ BuildFlatFiles(bool database_only)
664655
665656if (!database_only )
666657{
667- #ifdef NOT_YET
668- /* XXX doesn't work yet for reasons stated above */
669-
670658/* hard-wired path to pg_group */
671659rnode .spcNode = GLOBALTABLESPACE_OID ;
672660rnode .dbNode = 0 ;
673661rnode .relNode = RelOid_pg_group ;
674662
675663rel = XLogOpenRelation (true,0 ,rnode );
676664write_group_file (rel );
677- #endif
678665
679666/* hard-wired path to pg_shadow */
680667rnode .spcNode = GLOBALTABLESPACE_OID ;