]> granicus.if.org Git - postgresql-autodoc/commitdiff
Initial revision
authorrbt <rbt>
Wed, 12 May 2004 16:00:32 +0000 (16:00 +0000)
committerrbt <rbt>
Wed, 12 May 2004 16:00:32 +0000 (16:00 +0000)
13 files changed:
.cvsignore [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile [new file with mode: 0644]
config.mk.in [new file with mode: 0644]
configure.ac [new file with mode: 0644]
dia.tmpl [new file with mode: 0644]
dot.tmpl [new file with mode: 0644]
html.tmpl [new file with mode: 0644]
install-sh [new file with mode: 0755]
postgresql_autodoc.pl [new file with mode: 0755]
regressdatabase.sql [new file with mode: 0644]
xml.tmpl [new file with mode: 0644]
zigzag.dia.tmpl [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..1075296
--- /dev/null
@@ -0,0 +1,6 @@
+.*.swp
+ChangeLog.bak
+postgresql_autodoc
+config.status
+config.mk
+config.log
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..8e8b8c1
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,1065 @@
+2004-02-15 08:30  rtaylor02
+
+       * dot.tmpl, postgresql_autodoc.pl: Escape the variables for .dot
+         files which may include quotes.
+
+2004-02-14 15:37  rtaylor02
+
+       * postgresql_autodoc.pl: Last commit (bug fix) reported by
+
+         Adrian Head Bytecomm P/L
+
+2004-02-14 15:29  rtaylor02
+
+       * postgresql_autodoc.pl: Remove quote_ident() calls that caused
+         postgresql keywords to be quoted. These were quite ugly and
+         actually broke the .dot output.
+
+2003-12-07 16:09  rtaylor02
+
+       * Makefile, zigzag.dia.tmpl: New template for dia
+
+         In databases with many tables and foreign keys dia diagram
+         doesn't look very nice because uml-constraint is just a line (not
+         zigzagline). Attached is a patch to dia.tmpl which uses
+         dependancies instead of constraints. On the diagram they look in
+         the same way, but it is possible to have more segments.It is
+         tested on linux Suse 8.2, Postgresql 7.3.2, postgresql_autodoc
+         1.20, Dia 0.90.
+
+         Submitted by: Atanas Karashenski
+
+2003-12-02 09:11  rtaylor02
+
+       * postgresql_autodoc.pl: Fix permissions. They were picking up
+         characters in the granting users name.
+
+2003-11-28 19:07  rtaylor02
+
+       * ChangeLog: 1.21 release
+
+2003-11-14 09:28  rtaylor02
+
+       * ChangeLog: Sorry, 1.21 release
+
+2003-11-14 09:28  rtaylor02
+
+       * ChangeLog: Update Changelog for 1.20 changes
+
+2003-11-13 21:58  rtaylor02
+
+       * postgresql_autodoc.pl: Correct a bug with Indexes query for
+         databases we do not support indexes for (7.2 and prior).
+
+2003-11-07 21:15  rtaylor02
+
+       * configure: Goes with last commit..
+
+2003-11-07 21:14  rtaylor02
+
+       * configure.ac: Do perl module test using the form [ ! ( expression
+         ) ] as the current test could fail on some versions of bash.
+
+         Reported by: Chantal Ackermann
+
+2003-11-07 21:12  rtaylor02
+
+       * regressdatabase.sql: quantity_idx to become quantity_index for
+         spellcheck reasons.
+
+2003-11-02 17:33  rtaylor02
+
+       * ChangeLog: Changelogs for 1.20
+
+2003-11-01 18:19  rtaylor02
+
+       * postgresql_autodoc.pl: Remove usage of upper() in favour of uc()
+
+2003-11-01 18:08  rtaylor02
+
+       * postgresql_autodoc.pl: Add the necessary ~ to upper (don't want
+         character count, want a character exchange)
+
+         Bump version number to 1.20
+
+2003-11-01 17:11  rtaylor02
+
+       * postgresql_autodoc.pl, xml.tmpl: Minor cleanups for spellchecker
+
+2003-10-28 17:58  rtaylor02
+
+       * regressdatabase.sql: Regress the index.
+
+2003-10-28 17:57  rtaylor02
+
+       * postgresql_autodoc.pl, xml.tmpl: Quick and dirty Index
+         documentation for Docbook.
+
+2003-08-25 23:35  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Rearrange / format help
+
+         Correct a number of hrefs within the template to use the prepared
+         _sgmlid identifiers.
+
+2003-08-25 23:16  rtaylor02
+
+       * Makefile, html.tmpl, postgresql_autodoc.pl, xml.tmpl: Here's
+         another patch. This has a small addition to the makefile to make
+         the binary executable (useful in development). It also has code
+         to get the function data and display it in the HTML template. You
+         might think this needs more work. I have no knowledge of the dot
+         and dia forms, and not very much knowledge of docbook, so I
+         didn't do anything in those templates. Also, I have no knowledge
+         of what is required for earlier versions of Postgres, so I left
+         that alone.
+
+         Andrew Dunstan
+
+         Includes a correction of most HTML links, completes the above
+         function elements (pre 7.3, docbook).
+
+         Rod Taylor
+
+2003-08-18 09:30  rtaylor02
+
+       * xml.tmpl: Add View: and Table: prefixes much like HTML output.
+
+2003-08-18 09:24  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Here's a first patch with 3
+         things: 1. "View" heading for views in HTML 2. option to specify
+         template location (useful in development, for example) 3. option
+         to specify what sort of output you want, instead of  getting them
+         all.
+
+         Andrew Dunstan
+
+2003-08-12 10:03  rtaylor02
+
+       * Makefile, postgresql_autodoc.pl: Ensure that a single tmpl file
+         will be converted without an error.
+
+         Change the make file to install a single template file at a time.
+
+2003-08-11 18:01  rtaylor02
+
+       * ChangeLog: Add release notes for 1.12 to ChangeLog
+
+2003-08-11 17:56  rtaylor02
+
+       * html.tmpl: Add a note about where the documentation originated
+         from
+
+2003-08-11 17:52  rtaylor02
+
+       * postgresql_autodoc.pl: Bump version to 1.12
+
+2003-08-11 17:50  rtaylor02
+
+       * postgresql_autodoc.pl: Complain if the template files cannot be
+         found.
+
+2003-08-11 17:47  rtaylor02
+
+       * html.tmpl: Formatting corrections for compliance.
+
+2003-08-11 17:46  rtaylor02
+
+       * regressdatabase.sql: Add a couple of small functions.
+
+2003-08-01 20:49  rtaylor02
+
+       * ChangeLog, Makefile: Commit notes for 1.11
+
+2003-08-01 20:48  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Rename various variables for
+         consistency -- discovered while documenting.
+
+2003-07-27 20:54  rtaylor02
+
+       * postgresql_autodoc.pl: Remove docbook markup for plain numbers.
+
+2003-07-26 15:04  rtaylor02
+
+       * .cvsignore: Ignore ChangeLog.bak
+
+2003-07-26 15:03  rtaylor02
+
+       * ChangeLog: Introduction of the changelog.
+
+2003-07-26 15:03  rtaylor02
+
+       * sgml.tmpl: Not as useful as xml.tmpl
+
+2003-07-26 14:58  rtaylor02
+
+       * dot.tmpl, html.tmpl, postgresql_autodoc.pl, sgml.tmpl, xml.tmpl:
+         Rename table_description to table_comment Skip views in GraphViz
+         output Rename column_null to column_constraint_notnull Reorder
+         column items to be alphabetical Rename column_description to
+         column_comment Remove tables.type
+
+         Clean whitespace
+
+2003-07-19 20:57  rtaylor02
+
+       * regressdatabase.sql: 2 field CHECK constraint and a simple view.
+
+2003-07-19 19:38  rtaylor02
+
+       * xml.tmpl: Copy of sgml.tmpl
+
+         The SGML version is no longer going to be maintained (by me
+         anyway), as the XML based version is much more useful.
+
+2003-07-18 20:10  rtaylor02
+
+       * .cvsignore: Ignore generated files.
+
+2003-07-18 20:09  rtaylor02
+
+       * regressdatabase.sql: A very simple regression database.
+
+2003-06-27 09:41  rtaylor02
+
+       * postgresql_autodoc.pl: Version bump
+
+2003-06-27 09:41  rtaylor02
+
+       * sgml.tmpl: Remove the schema prefix of the function title.
+
+2003-06-13 14:52  rtaylor02
+
+       * postgresql_autodoc.pl: Improve statistics message
+
+2003-06-13 14:44  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Clean up the statistics code to
+         function as expected.
+
+2003-06-13 14:11  rtaylor02
+
+       * Makefile: Add distclean target, short for distribution-clean
+
+2003-05-31 13:46  rtaylor02
+
+       * postgresql_autodoc.pl: Reformat help using spaces rather than
+         tabs.
+
+         Inform the user on what to fix when --statistics is attempted on
+         old DB versions.
+
+2003-05-31 00:03  rtaylor02
+
+       * dot.tmpl, postgresql_autodoc.pl: Fix inter-schema connections in
+         the .dot output.
+
+2003-05-30 09:56  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Add back schema comments.
+
+2003-05-25 22:23  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Prototype most functions.
+
+         Add triggerError function (prints error and exits)
+
+         Change statistics to use pgstattuple in PostgreSQL 7.4 Add
+         --statistics flag to enable them.
+
+2003-05-25 21:35  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: When creating the list of Fkeys
+         referencing the current table, be sure to compare the schema,
+         table and column, not just the table and column.
+
+         Noticed By:     Arthur Ward
+
+2003-05-21 12:21  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Rudementry stats.
+
+2003-05-20 13:57  rtaylor02
+
+       * postgresql_autodoc.pl, sgml.tmpl: Correct the schema prefix to
+         function names.
+
+2003-05-20 13:34  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl, sgml.tmpl: Treat NOT NULL
+         properly.
+
+         It wasn't showing in the standard case -- but we still wanted to
+         hide it in the primary key case.
+
+2003-05-20 11:40  rtaylor02
+
+       * sgml.tmpl: Re-shuffle statements.
+
+2003-05-20 11:30  rtaylor02
+
+       * sgml.tmpl: Ensure we test for foreign keys WITHIN the constraint
+         loop!
+
+2003-05-14 16:17  rtaylor02
+
+       * postgresql_autodoc.pl: Ensure we escape $'s in queries that
+         aren't a part of variables.
+
+         Noticed By: Mike Stok
+
+2003-05-14 09:07  rtaylor02
+
+       * configure, configure.ac: Redirect PERL test output with 2>&1
+         rather than >&.  For some reason this messed up non-cli based
+         configures.
+
+2003-05-14 08:34  rtaylor02
+
+       * configure, configure.ac: Use ${PERL} rather than relying on the
+         paths.
+
+2003-05-12 15:31  rtaylor02
+
+       * Makefile: Fix up release creation.
+
+         Fix up installation (depends on all, create directories first)
+
+2003-05-12 14:58  rtaylor02
+
+       * Makefile: Include $(RELEASE_FILES) in the release target (doH!)
+
+2003-05-12 14:57  rtaylor02
+
+       * Makefile: Add a simple make target for release that ensure
+         everything is all cleaned up and ready to go.
+
+2003-05-10 10:03  rtaylor02
+
+       * postgresql_autodoc.pl: Clean up comments, touch of formatting,
+         and remove some unneeded (commented out) debug code.
+
+2003-05-10 00:04  rtaylor02
+
+       * postgresql_autodoc.pl: Ensure we don't pull out the constraint
+         name if it has been auto-generated by postgresql.  The $N style
+         naming doesn't have any useful information, per Arthur.
+
+         UCASE() the various SQL keywords in queries, notably AS.
+
+2003-05-09 23:29  rtaylor02
+
+       * configure, configure.ac: Silence perls loud errors by redirecting
+         the 'if' tests output to /dev/null
+
+2003-05-09 22:45  rtaylor02
+
+       * configure.ac: Bump comment on perl modules tested
+
+2003-05-09 22:44  rtaylor02
+
+       * configure, configure.ac: Add tests for perl modules
+
+2003-05-09 22:42  rtaylor02
+
+       * postgresql_autodoc.pl: Comment out the Data::Dumper file.  It's
+         unneeded.
+
+2003-05-09 20:50  rtaylor02
+
+       * Makefile: Don't be so secretive.
+
+2003-05-09 20:49  rtaylor02
+
+       * Makefile: Add distribution-clean, which should be good enough to
+         setup tarball.
+
+         The difference between it and maintainer-clean, is that
+         distribution-clean will leave the configure file.
+
+2003-05-09 20:41  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Add the column name to the
+         foreign key link.
+
+         Ignore the plpgsql_call_handler() function in >= Pg73
+
+         Ensure we show schemas (set number_of_schemas variable) for
+         column constraints.
+
+2003-05-09 20:39  rtaylor02
+
+       * sgml.tmpl: Correct spelling of REFERENCS
+
+         Add a . between schema and table names in the section xreflabel
+
+2003-05-09 16:00  rtaylor02
+
+       * Makefile: Install with privileges
+
+2003-05-09 16:00  rtaylor02
+
+       * configure: Minor changes to header notes
+
+2003-05-09 15:59  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Fix column descriptions.
+
+         Noticed by: Arthur Ward
+
+2003-05-09 15:23  rtaylor02
+
+       * Makefile, config.mk.in, configure, configure.ac, install-sh,
+         postgresql_autodoc.pl: Generate a make structure with
+         installation support.
+
+2003-05-09 10:23  rtaylor02
+
+       * postgresql_autodoc.pl: Ensure that 7.2 (and hopefully 7.1)
+         multikey foreign keys work the same as the newer versions of
+         PostgreSQL.
+
+         Fiddle with the code in that area to reduce the amount of
+         duplication.
+
+2003-05-09 08:17  rtaylor02
+
+       * dot.tmpl, postgresql_autodoc.pl: Escape the foreign key name in
+         GraphViz .dot files.
+
+2003-05-09 07:20  rtaylor02
+
+       * dot.tmpl: Add a connection point to the table, and re-use \N for
+         the name of the node.
+
+2003-05-09 06:51  rtaylor02
+
+       * dot.tmpl: Replace \N with the $table name.
+
+         Submitted By: rp at raphinou.com
+
+2003-05-09 06:44  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl, sgml.tmpl: Change foreign key
+         structure over to allow multi-key and single-key keys to work the
+         same way.
+
+         This in turn allows them to be shown with #'s attached to them
+         (like UNIQUE).
+
+         Suggested By (with reference patch): Arthur Ward
+
+         Replace 4 leading spaces with a tab for indenting.
+
+2003-05-06 13:06  rtaylor02
+
+       * dia.tmpl: The leading comment broke Dia.
+
+2003-05-06 10:12  rtaylor02
+
+       * sgml.tmpl: Fix up the sgml output to deal with multiple
+         multi-column unique constraints.
+
+         Used HTML output as reference.
+
+2003-05-05 23:18  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Rearrange constraints so that a
+         multi-key unique constraint can be associated with a group
+         number.
+
+         That is, multikey unique constraints are referred to as UNIQUE#1,
+         UNQIUE#2, etc.
+
+         Like #N's are a part of the same constraint.
+
+         Suggested by: Arthur Ward
+
+2003-05-05 20:48  rtaylor02
+
+       * postgresql_autodoc.pl: Sprinkle comments.
+
+         Ensure that the Information_Schema in 7.4 is NOT documented.
+
+2003-05-01 09:57  rtaylor02
+
+       * dia.tmpl, dot.tmpl, html.tmpl, sgml.tmpl: Toss in $Header: /cvsroot/autodoc/autodoc/ChangeLog,v 1.1 2004/05/12 16:00:33 rbt Exp $ where
+         appropriate
+
+         Remove <!--   --> style entities from dot.tmpl.  It's not a
+         flavour of SGML.
+
+2003-05-01 09:53  rtaylor02
+
+       * postgresql_autodoc.pl, sgml.tmpl: Ensure schemas are references
+         in the permission block for sgml template.
+
+         Add user variables ass required for html output.
+
+2003-04-30 15:53  rtaylor02
+
+       * postgresql_autodoc.pl: Final round on permissions.  Show all
+         permissions a user has, not just the first.
+
+2003-04-30 15:39  rtaylor02
+
+       * postgresql_autodoc.pl: Fix permissions to list off all
+         permissions in sgml output.
+
+         Add a lower() function to convert strings to lowercase
+
+         Change more spaces to tabs where appropriate.
+
+2003-04-30 15:07  rtaylor02
+
+       * postgresql_autodoc.pl: Toss the table and usernames into the
+         permission block.
+
+2003-04-30 14:46  rtaylor02
+
+       * postgresql_autodoc.pl: Spaces to tabs..
+
+2003-04-30 14:40  rtaylor02
+
+       * postgresql_autodoc.pl: permisions -> permissions
+
+2003-04-29 15:53  rtaylor02
+
+       * sgml.tmpl: Close the literal earlier...  Literals aren't variable
+         (duh!)
+
+2003-04-29 15:36  rtaylor02
+
+       * sgml.tmpl: Gotta use a prepared id for the ID attribute.
+
+2003-04-29 15:29  rtaylor02
+
+       * sgml.tmpl: Toss the View definition into a figure.
+
+         Fix the function title ID definition.
+
+2003-04-29 14:13  rtaylor02
+
+       * sgml.tmpl: Chapter needs to be closed.
+
+2003-04-29 14:04  rtaylor02
+
+       * sgml.tmpl: Toss the book header onto a single line.
+
+         It makes it easier for me to munge (oh well).
+
+2003-04-29 10:03  rtaylor02
+
+       * postgresql_autodoc.pl: Fix -f (bump ARGV)
+
+2003-04-24 11:49  rtaylor02
+
+       * sgml.tmpl: Loops are plural... schemas, tables, etc.
+
+2003-04-24 11:40  rtaylor02
+
+       * postgresql_autodoc.pl: Queries exist now.  Drop the comments.
+
+2003-04-24 10:28  rtaylor02
+
+       * postgresql_autodoc.pl: Simplify cross table foreign key links
+         (use database provided schema rather than first matching table --
+         fixes problems with linking to wrote schema too).
+
+         Rename element FK to FKTABLE (better meaning) to match FKSCHEMA.
+
+2003-04-24 10:15  rtaylor02
+
+       * postgresql_autodoc.pl: Ensure that the table of referenced tables
+         (foreign key links) are only displayed once per table and not
+         once per key.
+
+2003-04-24 09:57  rtaylor02
+
+       * postgresql_autodoc.pl: Track multi-key indicies and single-key
+         indicies using a common method.  Let the templates work it out.
+
+2003-04-24 09:56  rtaylor02
+
+       * html.tmpl: If a column is a primary key, don't bother marking as
+         NOT NULL as well.
+
+2003-04-23 14:47  rtaylor02
+
+       * dot.tmpl: Change the ratio to be 'auto' rather than 1.0.
+
+         This helps prepare for multi-key primary and foreign keys
+
+         Submitted by: Arthur Ward
+
+2003-04-23 12:42  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Fix Foreign key references
+         where multiple schemas are involved (schema prefix was missing)
+
+2003-04-23 12:33  rtaylor02
+
+       * html.tmpl: ESCAPE="???" rather than ESCAPE=???
+
+         Toss in a . between schema and table in permission blocks.
+
+2003-04-23 12:29  rtaylor02
+
+       * html.tmpl: Ensure the permissions segment is treated the same as
+         the others when a schema prefix is required.
+
+2003-04-23 12:20  rtaylor02
+
+       * postgresql_autodoc.pl: Correct ID links.  object_id needed to be
+         incremented prior to recording the value -- not after (duh).
+
+2003-04-23 11:44  rtaylor02
+
+       * postgresql_autodoc.pl: Clean up a slew of formatting (spaces ->
+         tabs)
+
+2003-04-23 11:34  rtaylor02
+
+       * postgresql_autodoc.pl: Slight stylistic improvements and updated
+         (or added) comments.
+
+2003-04-23 11:24  rtaylor02
+
+       * postgresql_autodoc.pl: Alphabetize fk_links
+
+2003-04-23 11:17  rtaylor02
+
+       * dia.tmpl: Ensure all TMPL_VAR entries are escaped properly.
+
+2003-04-23 10:59  rtaylor02
+
+       * html.tmpl: Fix up the HTML template for formatting.
+
+2003-04-22 13:07  rtaylor02
+
+       * postgresql_autodoc.pl: Better mark the debug segment
+         (Data::Dumper) and clean up trailing tabs on some lines
+
+2003-04-22 12:08  rtaylor02
+
+       * sgml.tmpl: SGML cleanups for consistency.
+
+2003-04-22 12:07  rtaylor02
+
+       * html.tmpl: Remove second ESCAPE=HTML
+
+2003-04-22 11:43  rtaylor02
+
+       * dia.tmpl, html.tmpl, postgresql_autodoc.pl, sgml.tmpl: Clean up
+         formatting of dia.tmpl, html.tmpl.  Ensure ESCAPE=? properties
+         are applied where appropriate
+
+         Remove the sgml (docbook) code from postgresql_autodoc.pl, and
+         toss it into a template.
+
+         Clean up help (add single schema note).
+
+2003-04-17 17:14  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Have HTML output deal with
+         schemas properly
+
+         Use schema.table for links and references when multiple schemas
+         exist -- or where otherwise hidden from the user.
+
+2003-04-17 14:39  rtaylor02
+
+       * postgresql_autodoc.pl: Allow dumping the structure of a single
+         schema rather than the entire system.
+
+2003-04-16 14:34  rtaylor02
+
+       * dia.tmpl, dot.tmpl, html.tmpl, postgresql_autodoc.pl: Make dia
+         templates actually work -- used to crash Dia.
+
+         Clean up formatting of HTML template (ucase tmpl commands).
+
+         Fix postgresql_autodoc to drop the asxml items.  Rely on ENCODING
+         by HTML::Template instead.
+
+2003-04-15 12:53  rtaylor02
+
+       * dia.tmpl, dot.tmpl, postgresql_autodoc.pl: Give proper connection
+         numbers for dot file -- dia is special, so rename those.
+
+         DOT template now functions...
+
+2003-04-15 10:17  rtaylor02
+
+       * dia.tmpl, dot.tmpl, postgresql_autodoc.pl: pk_fk_links ->
+         fk_links
+
+         Clean up dot template to insert less new lines.
+
+2003-04-15 10:01  rtaylor02
+
+       * postgresql_autodoc.pl: Array values must be separated by ,'s
+
+2003-04-14 20:48  rtaylor02
+
+       * postgresql_autodoc.pl: Clean .dot file support out of autodoc.
+         Template is the preferred method.
+
+2003-04-14 20:47  rtaylor02
+
+       * dia.tmpl: Stylistic improvements.
+
+2003-04-14 20:44  rtaylor02
+
+       * dot.tmpl: Dot file -- untested.
+
+2003-04-14 15:54  rtaylor02
+
+       * dia.tmpl: Beautification
+
+2003-04-13 17:04  rtaylor02
+
+       * .cvsignore: Ignore .swp files
+
+2003-04-13 17:00  rtaylor02
+
+       * dia.tmpl, html.tmpl, new.dia.tmpl, postgresql_autodoc.pl: Remove
+         the new.dia.tmpl file. Add dia.tmpl in its place.
+
+         Update autodoc to generate dia via the templated method only (has
+         problems for dia).
+
+         Fix html template for multiple schemas.
+
+2002-10-28 09:41  rtaylor02
+
+       * postgresql_autodoc.pl: Correct a bug in the sql_Columns query for
+         7.1 databases.  It was inappropriately attempting to use a
+         namespace.
+
+2002-09-18 10:40  rtaylor02
+
+       * postgresql_autodoc.pl: Clean up dirname / basename generation to
+         handle ./
+
+         Clean up template munging to manage templates in a different
+         directory than the executable.
+
+2002-09-18 10:26  rtaylor02
+
+       * postgresql_autodoc.pl: Add blank fields to Dia output to prevent
+         Dia from crashing.
+
+2002-09-17 16:58  rtaylor02
+
+       * postgresql_autodoc.pl: Wrap the table and column headers in the
+         sgml portion in <structname> and <structfield> respectively.
+
+         These could be replaced with database fields, but it doesn't seem
+         to buy anything.
+
+2002-09-16 16:52  rtaylor02
+
+       * postgresql_autodoc.pl: Add a few \n's
+
+         Just prettyprint SQL stuff once.
+
+2002-09-16 15:45  rtaylor02
+
+       * postgresql_autodoc.pl: Add in titleabbrev.
+
+         Give title and titleabbrev ids.
+
+         Use 'join' where possible to generate names.
+
+2002-09-16 14:40  rtaylor02
+
+       * postgresql_autodoc.pl: Fix the default depth and indent values to
+         make things nicer for SGML output.
+
+2002-09-16 14:21  rtaylor02
+
+       * postgresql_autodoc.pl: Pretty Print the View definition for SGML
+         output as well.
+
+2002-09-16 14:10  rtaylor02
+
+       * html.tmpl, postgresql_autodoc.pl: Simple view support.
+
+2002-09-08 14:57  orangepeel
+
+       * postgresql_autodoc.pl: change options that were index specific
+         (no-index etc) to no_templates set first object_id to 0 instead
+         of undef
+
+2002-09-08 08:58  orangepeel
+
+       * new.dia.tmpl, postgresql_autodoc.pl: beginings of dia template
+         called new.dia.tmpl so as not to overwrite the standard dia
+         output file added object id and primary key to foriegn key for
+         connections in dia
+
+2002-09-06 10:46  orangepeel
+
+       * html.tmpl, postgresql_autodoc.pl: use HTML::Template template for
+         html added write_index_structure replaced with version using html
+         template
+
+2002-09-05 23:22  rtaylor02
+
+       * postgresql_autodoc.pl: /usr/bin/env perl
+
+         rather than
+
+         /usr/bin/perl
+
+2002-09-05 23:10  rtaylor02
+
+       * postgresql_autodoc.pl: sgml, not xml for default docbook
+         extension.
+
+2002-09-03 12:24  rtaylor02
+
+       * postgresql_autodoc.pl: Whack load of changes to simplify, and
+         increase the exactness of the queries used.
+
+2002-08-30 19:56  rtaylor02
+
+       * postgresql_autodoc.pl: Nicer note about the website.
+
+2002-08-30 15:03  rtaylor02
+
+       * postgresql_autodoc.pl: Make hte sgml output filename sgml.
+
+         Make the docbook output fully sgml (suggest sx to convert to
+         XML).
+
+         Add the database commect above the Index.
+
+         Add the date of the output to the HTML documentation.
+
+         Correct a number of formatting issues.
+
+2002-08-29 19:54  rtaylor02
+
+       * postgresql_autodoc.pl: Output SGML rather than XML.
+
+2002-08-28 10:24  rtaylor02
+
+       * postgresql_autodoc.pl: Ran the file through perltidy, which has
+         helped clean it up quite a bit.
+
+2002-08-28 10:17  rtaylor02
+
+       * README.dia, postgresql_autodoc.pl: Clean up title printing for
+         docbook book titles.
+
+         Clean up a few error messages.
+
+         Drop README.dia as silly.
+
+2002-08-23 21:39  rtaylor02
+
+       * postgresql_autodoc.pl: Correct some formatting issues.
+
+2002-08-23 21:13  rtaylor02
+
+       * postgresql_autodoc.pl: Only display the schema for dia output if
+         there is more than one.
+
+         Remove a good chunk of Dia XML which overrode user defaults.
+         v0.90 doesn't crash on these.
+
+2002-08-23 20:44  rtaylor02
+
+       * postgresql_autodoc.pl: Clean up internal docs.
+
+         Don't group in Dia unless there is more than one schema.
+
+2002-08-23 17:07  rtaylor02
+
+       * postgresql_autodoc.pl: Fix the binary name in the help file.
+
+         Remove references of --filelist.
+
+2002-08-23 11:08  rtaylor02
+
+       * postgresql_autodoc.pl: Remove the docbook DTD declaration.
+         Assume that the user will include these in their sgml buildlines.
+
+2002-08-23 09:18  rtaylor02
+
+       * postgresql_autodoc.pl: Correct the namespace field name.
+
+2002-08-22 16:43  rtaylor02
+
+       * postgresql_autodoc.pl: Ignore system schemas by variable, incase
+         they change in the future.
+
+2002-08-16 16:19  rtaylor02
+
+       * postgresql_autodoc.pl: Correct the spelling of structure.
+
+2002-08-12 14:30  rtaylor02
+
+       * postgresql_autodoc.pl: Block quotes from the sgml identifiers.
+
+         Enable pulling non-system functions from the db in 7.2 or prior.
+
+2002-07-25 19:23  rtaylor02
+
+       * postgresql_autodoc.pl: Fix a few docbook tags.  Remove the old
+         style tagfix stuff.  Add an optional inclusiong of 'filelist.xml'
+         for docbook.
+
+2002-07-22 10:04  rtaylor02
+
+       * postgresql_autodoc.pl: Lets make our XRef labels a little more
+         consistent.
+
+2002-07-21 21:02  rtaylor02
+
+       * postgresql_autodoc.pl: Record Hans's name in the right place.
+
+         Add database comments to the docbook output.
+
+2002-07-21 10:56  rtaylor02
+
+       * postgresql_autodoc.pl: Clean up our management of id tags.
+         Remove the database name -- as that is too easily changed.
+
+         Drop -'s from the end of an id as well, to make it easier to
+         create xref's
+
+2002-07-20 23:37  rtaylor02
+
+       * postgresql_autodoc.pl: To prevent array and non-array types from
+         conflicting, sgml_safe_id will trade [] for ARRAY- rather than
+         --.
+
+2002-07-20 22:43  rtaylor02
+
+       * postgresql_autodoc.pl: Ensure to replace multiple --'s with a
+         single - in the sgml id.
+
+2002-07-20 14:47  rtaylor02
+
+       * postgresql_autodoc.pl: - Refactor docbook output to use lists
+         rather than tables.  This removes warnings about columns being
+         too wide (as there are no columns).  Looks better anyway.
+
+         - Change permissions to list off the available perms for a user,
+         rather than a check.
+
+         - Update column output in 7.3 to use format_type().
+
+         - Allow overriding tag cleanup by prepending the comment with
+         @DOCBOOK.  Autodoc will remove the @DOCBOOK portion and use the
+         string as is.  Otherwise it will replace <, >, &, etc. with SGML
+         safe characters.
+
+2002-07-19 15:17  rtaylor02
+
+       * postgresql_autodoc.pl: Allow users to enforce that special
+         characters in comment blocks are not escapted.  The reason for
+         this is to allow custom markups in the comments (HTML or
+         DocBook).
+
+2002-07-18 22:47  rtaylor02
+
+       * postgresql_autodoc.pl: Clean up the Docbook output mechanism to
+         output a book (rather than an appendix).
+
+         Docbook format outputs functions.
+
+         Docbook format uses hardcoded system URI rather than public due
+         to openjade no longer using URLs.
+
+2002-07-17 14:35  rtaylor02
+
+       * postgresql_autodoc.pl: Center permission headers in HTML output.
+
+2002-07-17 14:20  rtaylor02
+
+       * postgresql_autodoc.pl: Be somewhat more cautious with variables.
+         Test whether they're defined before trying to pull a value.
+
+         Setup 7.2 and prior DBs to create teh FKGROUP entries as
+         $system_schema.
+
+2002-07-17 10:25  rtaylor02
+
+       * postgresql_autodoc.pl: Make files overwrite instead of
+         complaining.
+
+         Display basics about user created functions (HTML output only).
+
+         Fix display of permissions and constraints.
+
+         Ensure full 7.3 compatibility (at this point).
+
+2002-07-16 10:23  rtaylor02
+
+       * postgresql_autodoc.pl: Apply stylesheet and HTML fixes as
+         supplied by Hans Schou.
+
+2002-07-13 22:14  rtaylor02
+
+       * postgresql_autodoc.pl: Add rudementry support for pulling out the
+         API of a function set.
+
+2002-07-10 10:36  rtaylor02
+
+       * postgresql_autodoc.pl: Update the script to use schemas instead
+         of the previous grouping method.
+
+         For pre 7.3 versions use 'public' as the schema, as this would be
+         what they upgrade to.
+
+2002-06-05 09:29  rtaylor02
+
+       * postgresql_autodoc.pl: Ensure we catch the trigger permission as
+         well as user PUBLIC when no other user or group was provided.
+
+2002-06-04 16:31  rtaylor02
+
+       * postgresql_autodoc.pl: Improved job of handling old DBD modules
+         which don't return bytea values -- but rather return strings in
+         their place.
+
+         Basically means escaping the \ in \000 or not.
+
+2002-06-03 11:08  rtaylor02
+
+       * postgresql_autodoc.pl: Escape the backslash before NULL (\000)
+         for regular expression parsing.
+
+         Appears in perl 5.6 it comes out as a string rather than as an
+         expression
+
+2002-04-23 11:15  rtaylor02
+
+       * postgresql_autodoc.pl: Use postgresql environment variables.
+
+2002-04-23 09:44  rtaylor02
+
+       * README.dia: Brief explanation about the usage of the .dia format.
+
+2002-04-23 09:38  rtaylor02
+
+       * postgresql_autodoc.pl: Fix -u to work like -U
+
+         Bug reported by Neil Prockter
+
+2002-04-18 16:24  iggie
+
+       * postgresql_autodoc.pl: Added directed graph output in the 'dot'
+         language used by GraphViz.  Changed connections in Dia to connect
+         primary/foreign key columns rather than just tables.
+
+2002-04-03 15:32  rtaylor02
+
+       * postgresql_autodoc.pl: Initial import of the original.
+
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..7047ba8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,95 @@
+# $Header: /cvsroot/autodoc/autodoc/Makefile,v 1.1 2004/05/12 16:00:34 rbt Exp $
+
+TEMPLATES = dia.tmpl dot.tmpl html.tmpl xml.tmpl zigzag.dia.tmpl
+BINARY = postgresql_autodoc
+CONFIGFILE = config.mk
+
+RELEASE_FILES = Makefile config.mk.in configure \
+                               configure.ac $(TEMPLATES) install-sh \
+                               postgresql_autodoc.pl
+
+cur-dir   := $(shell basename ${PWD})
+REAL_RELEASE_FILES = $(addprefix $(cur-dir)/,$(RELEASE_FILES))
+
+# Global dependencies
+ALWAYS_DEPEND = Makefile configure $(CONFIGFILE)
+
+
+####
+# Test to see if $(CONFIGFILE) has been generated.  If so, include it. Otherwise we assume
+# it will be created for us.
+has_configmk := $(wildcard $(CONFIGFILE))
+
+ifeq ($(has_configmk),$(CONFIGFILE))
+include $(CONFIGFILE)
+endif
+
+####
+# ALL
+.PHONY: all
+all: $(ALWAYS_DEPEND) $(BINARY)
+
+####
+# Replace the /usr/bin/env perl with the supplied path
+# chmod to make testing easier
+$(BINARY): postgresql_autodoc.pl $(CONFIGFILE)
+       $(SED) -e "s,/usr/bin/env perl,$(PERL)," \
+                       -e "s,@@TEMPLATE-DIR@@,$(datadir)," \
+                postgresql_autodoc.pl > $(BINARY)
+       -chmod +x $(BINARY)
+
+####
+# INSTALL Target
+.PHONY: install
+install: all $(ALWAYS_DEPEND)
+       $(INSTALL_SCRIPT) -d $(bindir)
+       $(INSTALL_SCRIPT) -d $(datadir)
+       $(INSTALL_SCRIPT) -m 755 $(BINARY) $(bindir)
+       for entry in $(TEMPLATES) ; \
+               do $(INSTALL_SCRIPT) -m 644 $${entry} $(datadir) ; \
+       done
+
+####
+# CLEAN / DISTRIBUTION-CLEAN / MAINTAINER-CLEAN Targets
+.PHONY: clean
+clean: $(ALWAYS_DEPEND)
+       $(RM) $(BINARY)
+
+.PHONY: distribution-clean distclean
+distribution-clean distclean: clean
+       $(RM) $(CONFIGFILE) config.log config.status
+       $(RM) -r autom4te.cache
+       $(RM) $(patsubst %.tmpl,*.%,$(wildcard *.tmpl))
+
+.PHONY: maintainer-clean
+maintainer-clean: distribution-clean
+       $(RM) configure
+
+####
+# Build a release
+#
+#      Clean
+#      Ensure configure is up to date
+#      Commit any pending elements
+#      Tar up the results
+.PHONY: release
+release: distribution-clean configure $(RELEASE_FILES)
+       @if [ -z ${VERSION} ] ; then \
+               echo "-------------------------------------------"; \
+               echo "VERSION needs to be specified for a release"; \
+               echo "-------------------------------------------"; \
+               false; \
+       fi
+       cvs2cl
+       -cvs commit
+       cd ../ && tar -czvf postgresql_autodoc-${VERSION}.tar.gz $(REAL_RELEASE_FILES)
+
+####
+# Build and Run configure files when configure or a template is updated.
+configure: configure.ac
+       autoconf
+
+# Fix my makefile, then execute myself
+$(CONFIGFILE) : config.mk.in configure
+       ./configure
+       $(MAKE) $(MAKEFLAGS)
diff --git a/config.mk.in b/config.mk.in
new file mode 100644 (file)
index 0000000..ddfc225
--- /dev/null
@@ -0,0 +1,13 @@
+SHELL = /bin/sh
+VPATH = @srcdir@
+
+# Configure replacements
+INSTALL_SCRIPT = @INSTALL@
+PERL = @PERL@
+SED = @SED@
+
+# installation directories
+prefix = @prefix@
+exec_prefix= @exec_prefix@
+bindir = @bindir@
+datadir = @datadir@
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..c5a3436
--- /dev/null
@@ -0,0 +1,55 @@
+AC_PREREQ(2.53)
+AC_REVISION($Header: /cvsroot/autodoc/autodoc/Attic/configure.ac,v 1.1 2004/05/12 16:00:34 rbt Exp $)
+AC_INIT(postgresql_autodoc.pl)
+
+
+# Programs
+AC_PROG_INSTALL
+
+AC_PATH_PROGS([SED], [sed], ,
+             [$PATH:/bin:/usr/bin])
+
+# Check for Perl
+AC_ARG_WITH(perl-prefix,
+       [  --with-perl-prefix      Location of Perl],
+       PERLPATH=$withval,
+       PERLPATH="")
+
+if ( test -n "$PERLPATH" -a "`echo $PERLPATH | cut -c-3`" = "../" ); then
+       PERLPATH="$PWD/$PERLPATH"
+fi
+
+PERL=""
+if ( test -n "$PERLPATH" ); then
+       AC_CHECK_FILE("$PERLPATH/bin/perl",PERL="$PERLPATH/bin/perl")
+else
+       AC_PATH_PROGS([PERL], [perl], ,
+                 [$PATH:/usr/bin:/usr/local/bin:/usr/pkg/bin:/usr/local/perl/bin:/opt/sfw/bin])
+fi
+if ( test -z "$PERL" ); then
+       AC_MSG_ERROR("Perl is required")
+fi
+AC_SUBST(PERL)
+
+
+# Check that Perl Libraries are available:
+#      DBI
+#      DBD::Pg
+#      Fcntl
+#      HTML::Template
+#
+# Output of if test redirected to /dev/null to keep quiet
+for module in DBI DBD::Pg Fcntl HTML::Template ; do
+       AC_MSG_CHECKING(${module})
+       if [ ! (${PERL} -e "use ${module}" 2>&1 /dev/null ) ]; then
+               AC_MSG_RESULT(no)
+               AC_MSG_ERROR(Perl module ${module} is required)
+       else
+               AC_MSG_RESULT(yes)
+       fi
+done
+
+
+AC_OUTPUT([
+config.mk
+])
diff --git a/dia.tmpl b/dia.tmpl
new file mode 100644 (file)
index 0000000..8c8ea6f
--- /dev/null
+++ b/dia.tmpl
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+  <dia:layer name="Background" visible="true">
+<!-- TMPL_LOOP name="schemas" -->
+<!-- TMPL_IF name="number_of_schemas" -->
+    <dia:group>
+<!-- /TMPL_IF name="number_of_schemas" -->
+<!-- TMPL_LOOP name="tables" -->
+    <dia:object type="UML - Class" version="0" id="O<!-- TMPL_VAR ESCAPE="HTML" name="object_id" -->">
+      <dia:attribute name="name">
+        <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="table" -->#</dia:string>
+      </dia:attribute>
+<!-- TMPL_IF name="number_of_schemas" -->
+      <dia:attribute name="stereotype">
+        <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="schema" -->#</dia:string>
+      </dia:attribute>
+<!-- /TMPL_IF name="number_of_schemas" -->
+      <dia:attribute name="abstract">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="suppress_attributes">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="suppress_operations">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="visible_attributes">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="attributes">
+<!-- TMPL_LOOP name="columns" -->
+        <dia:composite type="umlattribute">
+          <dia:attribute name="name">
+            <dia:string>#<!-- TMPL_IF name="column_primary_key" -->PK<!-- TMPL_ELSE name="column_primary_key" -->  <!-- /TMPL_IF name="column_primary_key" --><!-- TMPL_VAR ESCAPE="HTML" name="column" -->#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="type">
+            <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="column_type" -->#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="value">
+<!-- TMPL_IF name="column_default_short" -->
+            <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="column_default_short" -->#</dia:string>
+<!-- TMPL_ELSE name="column_default_short" -->
+            <dia:string/>
+<!-- /TMPL_IF name="column_default_short" -->
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="3"/>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+        </dia:composite>
+<!-- /TMPL_LOOP name="columns" -->
+      </dia:attribute>
+<!-- TMPL_IF name="constraints" -->
+      <dia:attribute name="visible_operations">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="operations">
+<!-- TMPL_LOOP name="constraints" -->
+        <dia:composite type="umloperation">
+          <dia:attribute name="name">
+            <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="constraint_name" -->#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="3"/>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="parameters">
+            <dia:composite type="umlparameter">
+              <dia:attribute name="name">
+                <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="constraint_short" -->#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="type">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="value">
+                <dia:string/>
+              </dia:attribute>
+              <dia:attribute name="kind">
+                <dia:enum val="0"/>
+              </dia:attribute>
+            </dia:composite>
+          </dia:attribute>
+        </dia:composite>
+<!-- /TMPL_LOOP name="constraints" -->
+      </dia:attribute>
+<!-- TMPL_ELSE name="constraints" -->
+      <dia:attribute name="visible_operations">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="operations"/>
+<!-- /TMPL_IF name="constraints" -->
+      <dia:attribute name="template">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="templates"/>
+    </dia:object>
+<!-- /TMPL_LOOP name="tables" -->
+<!-- TMPL_IF name="number_of_schemas" -->
+    </dia:group>
+<!-- /TMPL_IF name="number_of_schemas" -->
+<!-- /TMPL_LOOP name="schemas" -->
+<!-- TMPL_LOOP name="fk_links" -->
+    <dia:object type="UML - Constraint" version="0" id="O<!-- TMPL_VAR ESCAPE="HTML" name="object_id" -->">
+      <dia:attribute name="constraint">
+        <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="fk_link_name" -->#</dia:string>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O<!-- TMPL_VAR ESCAPE="HTML" name="handle0_to" -->" connection="<!-- TMPL_VAR ESCAPE="HTML" name="handle0_connection_dia" -->"/>
+        <dia:connection handle="1" to="O<!-- TMPL_VAR ESCAPE="HTML" name="handle1_to" -->" connection="<!-- TMPL_VAR ESCAPE="HTML" name="handle1_connection_dia" -->"/>
+      </dia:connections>
+    </dia:object>
+<!-- /TMPL_LOOP name="fk_links" -->
+  </dia:layer>
+</dia:diagram>
diff --git a/dot.tmpl b/dot.tmpl
new file mode 100644 (file)
index 0000000..6723622
--- /dev/null
+++ b/dot.tmpl
@@ -0,0 +1,18 @@
+digraph g {
+graph [
+rankdir = "LR",
+concentrate = true,
+ratio = auto
+];
+node [
+fontsize = "10",
+shape = record
+];
+edge [
+];
+<TMPL_LOOP name="schemas"><TMPL_LOOP name="tables"><TMPL_UNLESS name="view_definition">
+"<TMPL_IF name="number_of_schemas"><TMPL_VAR name="schema_dot">.</TMPL_IF name="number_of_schemas"><TMPL_VAR name="table_dot">" [shape = record, label = "<col0> \N | <TMPL_LOOP name="columns"> <TMPL_VAR name="column_dot">:  <TMPL_VAR name="column_type">\l</TMPL_LOOP name="columns">" ];
+</TMPL_UNLESS name="view_definition"></TMPL_LOOP name="tables"></TMPL_LOOP name="schemas">
+<TMPL_LOOP name="fk_links">
+"<TMPL_IF name="number_of_schemas"><TMPL_VAR name="handle0_schema">.</TMPL_IF name="number_of_schemas"><TMPL_VAR name="handle0_name">" -> "<TMPL_IF name="number_of_schemas"><TMPL_VAR name="handle1_schema">.</TMPL_IF name="number_of_schemas"><TMPL_VAR name="handle1_name">" [label="<TMPL_VAR name="fk_link_name_dot">"];</TMPL_LOOP name="fk_links">
+}
diff --git a/html.tmpl b/html.tmpl
new file mode 100644 (file)
index 0000000..f5fe161
--- /dev/null
+++ b/html.tmpl
@@ -0,0 +1,292 @@
+<!-- $Header: /cvsroot/autodoc/autodoc/html.tmpl,v 1.1 2004/05/12 16:00:34 rbt Exp $ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+   "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+  <head>
+    <title>Index for <!-- TMPL_VAR ESCAPE="HTML" name="database" --></title>
+    <style type="text/css">
+       BODY {
+               color:  #000000; 
+               background-color: #FFFFFF;
+               font-family: Helvetica, sans-serif; 
+       }
+
+       P {
+               margin-top: 5px;
+               margin-bottom: 5px;
+       }
+
+       P.w3ref {
+               font-size: 8pt;
+               font-style: italic;
+               text-align: right;
+       }
+
+       P.detail {
+               font-size: 10pt;
+       }
+
+       .error {
+               color: #FFFFFF;
+               background-color: #FF0000;
+       }
+
+       H1, H2, H3, H4, H5, H6 {
+       }
+
+       OL {
+               list-style-type: upper-alpha;
+       }
+
+       UL.topic {
+               list-style-type: upper-alpha;
+       }
+
+       LI.topic {
+               font-weight : bold;
+       }
+
+       HR {
+               color: #00FF00;
+               background-color: #808080;
+       }
+
+       TABLE {
+               border-width: medium;
+               padding: 3px;
+               background-color: #000000;
+               width: 90%;
+       }
+
+       CAPTION {
+               text-transform: capitalize;
+               font-weight : bold;
+               font-size: 14pt;
+       }
+
+       TH {
+               color: #FFFFFF;
+               background-color: #000000;
+               text-align: left;
+       }
+
+       TR {
+               color: #000000;
+               background-color: #000000;
+               vertical-align: top;
+       }
+
+       TR.tr0 {
+               background-color: #F0F0F0;
+       }
+
+       TR.tr1 {
+               background-color: #D8D8D8;
+       }
+
+       TD {
+               font-size: 12pt;
+       }
+
+       TD.col0 {
+               font-weight : bold;
+               width: 20%;
+       }
+
+       TD.col1 {
+               font-style: italic;
+               width: 15%;
+       }
+
+       TD.col2 {
+               font-size: 12px;
+       }
+    </style>
+    <link rel="stylesheet" type="text/css" media="all" href="all.css">
+    <link rel="stylesheet" type="text/css" media="screen" href="screen.css">
+    <link rel="stylesheet" type="text/css" media="print" href="print.css">
+    <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+  </head>
+  <body>
+
+    <!-- Primary Index -->
+       <p><!-- TMPL_VAR ESCAPE="HTML" name="database_comment" --><br><br>Dumped on <!-- TMPL_VAR ESCAPE="HTML" name="dumped_on" --></p>
+<h1><a name="index">Index of database - <!-- TMPL_VAR ESCAPE="HTML" name="database" --></a></h1>
+<ul>
+    <!-- TMPL_LOOP name="schemas" -->
+    <li><a name="<!-- TMPL_VAR ESCAPE="HTML" name="schema_sgmlid" -->"><!-- TMPL_VAR ESCAPE="HTML" name="schema" --></a></li><ul>
+       <!-- TMPL_LOOP name="tables" --><li><a href="#<!-- TMPL_VAR ESCAPE="URL" name="table_sgmlid" -->"><!-- TMPL_VAR ESCAPE="HTML" name="table" --></a></li><!-- /TMPL_LOOP name="tables" -->
+       <!-- TMPL_LOOP name="functions" --><li><a href="#<!-- TMPL_VAR ESCAPE="URL" name="function_sgmlid" -->"><!-- TMPL_VAR ESCAPE="HTML" name="function" --></a></li><!-- /TMPL_LOOP name="functions" -->
+    </ul>
+    <!-- /TMPL_LOOP name="schemas" -->
+</ul>
+
+    <!-- Schema Creation -->
+    <!-- TMPL_LOOP name="schemas" --><!-- <!-- TMPL_VAR ESCAPE="HTML" name="schema" --><!-- TMPL_VAR ESCAPE="HTML" name="schema" --> -->
+
+               <!-- TMPL_IF name="number_of_schemas" -->
+               <hr>
+               <h1>Schema <!-- TMPL_VAR ESCAPE="HTML" name="schema" --></h1>
+               <!-- TMPL_IF name="schema_comment" -->
+                       <p><!-- TMPL_VAR name="schema_comment" --></p>
+               <!-- /TMPL_IF name="schema_comment" -->
+
+               <!-- /TMPL_IF name="number_of_schemas" -->
+               <!-- TMPL_LOOP name="tables" -->
+        <hr>
+               <h2><!-- TMPL_IF name="view_definition" -->View:<!-- TMPL_ELSE -->Table:<!-- /TMPL_IF -->
+                       <!-- TMPL_IF name="number_of_schemas" -->
+                       <a href="#<!-- TMPL_VAR ESCAPE="URL" name="schema_sgmlid" -->"><!-- TMPL_VAR ESCAPE="HTML" name="schema" --></a>.<!-- /TMPL_IF name="number_of_schemas" --><a name="<!-- TMPL_VAR ESCAPE="URL" name="table_sgmlid" -->"><!-- TMPL_VAR ESCAPE="HTML" name="table" --></a>
+               </h2>
+        <!-- TMPL_IF name="table_comment" -->
+         <p><!-- TMPL_VAR ESCAPE="HTML" name="table_comment" --></p>
+        <!-- /TMPL_IF name="table_comment" -->
+
+
+        <table width="100%" cellspacing="0" cellpadding="3">
+                <caption><!-- TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="schema" -->.<!-- /TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="table" --> Structure</caption>
+                <tr>
+                <th>F-Key</th>
+                <th>Name</th>
+                <th>Type</th>
+                <th>Description</th>
+                </tr>
+            <!-- TMPL_LOOP name="columns" -->
+            <tr class="<!-- TMPL_IF name="__odd__" -->tr0<!-- tmpl_else name="__odd__" -->tr1<!-- /TMPL_IF name="__odd__" -->">
+                               <td>
+                <!-- TMPL_LOOP name="column_constraints" -->
+                  <!-- TMPL_IF name="column_fk" -->
+                  <a href="#<!-- TMPL_VAR ESCAPE="URL" name="column_fk_sgmlid" -->"><!-- TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="column_fk_schema" -->.<!-- /TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="column_fk_table" -->.<!-- TMPL_VAR ESCAPE="HTML" name="column_fk_colnum" --><!-- TMPL_IF name="column_fk_keygroup" -->#<!-- TMPL_VAR name="column_fk_keygroup" --><!-- /TMPL_IF name="column_fk_keygroup" --></a>
+                  <!-- /TMPL_IF name="column_fk" -->
+                <!-- /TMPL_LOOP name="column_constraints" -->
+                </td>
+               <td><!-- TMPL_VAR ESCAPE="HTML" name="column" --></td>
+               <td><!-- TMPL_VAR ESCAPE="HTML" name="column_type" --></td>
+                <td><i>
+                               <!-- TMPL_LOOP name="column_constraints" -->
+                                       <!-- TMPL_IF name="column_primary_key" -->PRIMARY KEY
+                                       <!-- /TMPL_IF name="column_primary_key" -->
+
+                                       <!-- TMPL_IF name="column_unique" -->
+                       UNIQUE<!-- TMPL_IF name="column_unique_keygroup" -->#<!-- TMPL_VAR name="column_unique_keygroup" --><!-- /TMPL_IF name="column_unique_keygroup" -->
+                    <!-- /TMPL_IF name="column_unique" -->
+                               <!-- /TMPL_LOOP name="column_constraints" -->
+
+                               <!-- TMPL_IF name="column_constraint_notnull" -->NOT NULL<!-- /TMPL_IF name="column_constraint_notnull" -->
+                               <!-- TMPL_IF name="column_default" -->DEFAULT <!-- TMPL_VAR ESCAPE="HTML" name="column_default" --><!-- /TMPL_IF name="column_default" -->
+                               </i>
+                               <!-- TMPL_IF name="column_comment" --><br><br><!-- TMPL_VAR ESCAPE="HTML" name="column_comment" --><!-- /TMPL_IF name="column_comment" -->
+                               </td>
+                        </tr>
+            <!-- /TMPL_LOOP name="columns" -->
+        </table>
+
+               <!-- TMPL_UNLESS name="view_definition" -->
+               <!-- TMPL_IF name="stats_enabled" -->
+        <p>&nbsp;</p>
+        <table width="100%" cellspacing="0" cellpadding="3">
+         <caption>Statistics</caption>
+         <tr>
+          <th>Total Space (disk usage)</th>
+          <th>Tuple Count</th>
+          <th>Active Space</th>
+          <th>Dead Space</th>
+          <th>Free Space</th>
+         </tr>
+         <tr class="tr0">
+          <td><!-- TMPL_VAR ESCAPE="HTML" name="stats_table_bytes" --></td>
+          <td><!-- TMPL_VAR ESCAPE="HTML" name="stats_tuple_count" --></td>
+          <td><!-- TMPL_VAR ESCAPE="HTML" name="stats_tuple_bytes" --></td>
+          <td><!-- TMPL_VAR ESCAPE="HTML" name="stats_dead_bytes" --></td>
+          <td><!-- TMPL_VAR ESCAPE="HTML" name="stats_free_bytes" --></td>
+         </tr>
+        </table>
+               <!-- /TMPL_IF name="stats_enabled" -->
+               <!-- /TMPL_UNLESS name="view_definition" -->
+
+        <!-- Constraint List -->
+               <!-- TMPL_IF name="constraints" -->
+        <p>&nbsp;</p>
+               <table width="100%" cellspacing="0" cellpadding="3">
+            <caption><!-- TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="schema" -->.<!-- /TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="table" --> Constraints</caption>
+            <tr>
+               <th>Name</th>
+               <th>Constraint</th>
+            </tr>
+                       <!-- TMPL_LOOP name="constraints" -->
+            <tr class="<!-- TMPL_IF name="__odd__" -->tr0<!-- TMPL_ELSE name="__odd__" -->tr1<!-- /TMPL_IF name="__odd__" -->">
+                               <td><!-- TMPL_VAR ESCAPE="HTML" name="constraint_name" --></td>
+                <td><!-- TMPL_VAR ESCAPE="HTML" name="constraint" --></td>
+            </tr>
+                       <!-- /TMPL_LOOP name="constraints" -->
+               </table>
+               <!-- /TMPL_IF name="constraints" -->
+
+        <!-- Foreign Key Discovery -->
+               <!-- TMPL_IF name="fk_schemas" -->
+                       <p>Tables referencing this one via Foreign Key Constraints:</p>
+               <!-- TMPL_LOOP name="fk_schemas" -->
+                       <ul>    
+                               <li><a href="#<!-- TMPL_VAR ESCAPE="URL" name="fk_sgmlid" -->"><!-- TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="fk_schema" -->.<!-- /TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="fk_table" --></a></li>
+                       </ul>
+               <!-- /TMPL_LOOP name="fk_schemas" -->
+               <!-- /TMPL_IF name="fk_schemas" -->
+
+       <!-- View Definition -->
+       <!-- TMPL_IF name="view_definition" -->
+       <pre><!-- TMPL_VAR ESCAPE="HTML" name="view_definition" --></pre>
+       <!-- /TMPL_IF name="view_definition" -->
+
+       <!-- List off permissions -->
+       <!-- TMPL_IF name="permissions" -->
+       <p>&nbsp;</p>
+       <table width="100%" cellspacing="0" cellpadding="3">
+       <caption>Permissions which apply to <!-- TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="schema" -->.<!-- /TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="table" --></caption>
+       <tr>
+               <th>User</th>
+               <th><center>Select</center></th>
+               <th><center>Insert</center></th>
+               <th><center>Update</center></th>
+               <th><center>Delete</center></th>
+               <th><center>Reference</center></th>
+               <th><center>Rule</center></th>
+               <th><center>Trigger</center></th>
+       </tr>
+               <!-- TMPL_LOOP name="permissions" -->
+               <tr class="<!-- TMPL_IF name="__odd__" -->tr0<!-- tmpl_else name="__odd__" -->tr1<!-- /TMPL_IF name="__odd__" -->">
+                       <td><!-- TMPL_VAR ESCAPE="HTML" name="user" --></td>
+                       <td><!-- TMPL_IF name="select" --><center>&diams;</center><!-- /TMPL_IF name="select" --></td>
+                       <td><!-- TMPL_IF name="insert" --><center>&diams;</center><!-- /TMPL_IF name="insert" --></td>
+                       <td><!-- TMPL_IF name="update" --><center>&diams;</center><!-- /TMPL_IF name="update" --></td>
+                       <td><!-- TMPL_IF name="delete" --><center>&diams;</center><!-- /TMPL_IF name="delete" --></td>
+                       <td><!-- TMPL_IF name="references" --><center>&diams;</center><!-- /TMPL_IF name="references" --></td>
+                       <td><!-- TMPL_IF name="rule" --><center>&diams;</center><!-- /TMPL_IF name="rule" --></td>
+                       <td><!-- TMPL_IF name="trigger" --><center>&diams;</center><!-- /TMPL_IF name="trigger" --></td>
+               </tr>
+               <!-- /TMPL_LOOP name="permissions" -->
+       </table>
+       <!-- /TMPL_IF name="permissions" -->
+
+       <p>
+               <a href="#index">Index</a> -
+               <a href="#<!-- TMPL_VAR ESCAPE="URL" name="schema_sgmlid" -->">Schema <!-- TMPL_VAR ESCAPE="HTML" name="schema" --></a>
+    </p>
+       <!-- /TMPL_LOOP name="tables" -->
+
+       <!-- We've gone through the table structure, now lets take a look at user functions -->
+       <!-- TMPL_LOOP name="functions" -->
+               <hr>
+               <h2>Function: 
+                       <a href="#<!-- TMPL_VAR ESCAPE="HTML" name="schema_sgmlid" -->"><!-- TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="schema" --></a>.<!-- /TMPL_IF name="number_of_schemas" --><a name="<!-- TMPL_VAR ESCAPE="URL" name="function_sgmlid" -->"><!-- TMPL_VAR ESCAPE="HTML" name="function" --></a>
+               </h2>
+<h3>Returns: <!-- TMPL_VAR ESCAPE="HTML" name="function_returns" --></h3>
+<h3>Language: <!-- TMPL_VAR ESCAPE="HTML" name="function_language" --></h3>
+        <!-- TMPL_IF name="function_comment" --><p><!-- TMPL_VAR ESCAPE="HTML" name="function_comment" --></p><!-- /TMPL_IF name="function_comment" -->
+        <pre><!-- TMPL_IF name="function_source" --><!-- TMPL_VAR ESCAPE="HTML" name="function_source" --><!-- /TMPL_IF name="function_source" --></pre>
+       <!-- /TMPL_LOOP name="functions" -->
+
+<!-- /TMPL_LOOP name="schemas" -->
+<p class="w3ref">Generated by <a href="http://www.rbt.ca/autodoc/">PostgreSQL Autodoc</a></p>
+<p class="w3ref"><a href="http://validator.w3.org/check/referer">W3C HTML 4.01 Strict</a></p>
+</body></html>
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..398a88e
--- /dev/null
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       :
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=$mkdirprog
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               :
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               :
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               :
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+       '
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               :
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               :
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/postgresql_autodoc.pl b/postgresql_autodoc.pl
new file mode 100755 (executable)
index 0000000..18fc9ac
--- /dev/null
@@ -0,0 +1,1763 @@
+#!/usr/bin/env perl
+# -- # -*- Perl -*-w
+# $Header: /cvsroot/autodoc/autodoc/postgresql_autodoc.pl,v 1.1 2004/05/12 16:00:36 rbt Exp $
+#  Imported 1.22 2002/02/08 17:09:48 into sourceforge
+
+# Postgres Auto-Doc Version 1.22
+
+# License
+# -------
+# Copyright (c) 2001, Rod Taylor
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1.   Redistributions of source code must retain the above copyright
+#      notice, this list of conditions and the following disclaimer.
+#
+# 2.   Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials provided
+#      with the distribution.
+#
+# 3.   Neither the name of the InQuent Technologies Inc. nor the names
+#      of its contributors may be used to endorse or promote products
+#      derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD
+# PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# About Project
+# -------------
+# Various details about the project and related items can be found at 
+# the website
+#
+# http://www.rbt.ca/autodoc/
+
+use DBI;
+use strict;
+
+# Allows file locking
+use Fcntl;
+
+## Useful for debugging ##
+#use Data::Dumper;
+
+# Allows file templates
+use HTML::Template;
+
+# The templates path
+# @@TEMPLATE-DIR@@ will be replaced by make in the build phase
+my $template_path = '@@TEMPLATE-DIR@@';
+
+# Setup the default connection variables based on the environment
+my $dbuser = $ENV{'PGUSER'};
+$dbuser ||= $ENV{'USER'};
+
+my $database = $ENV{'PGDATABASE'};
+$database ||= $dbuser;
+
+my $dbhost = $ENV{'PGHOST'};
+$dbhost ||= "";
+
+my $dbport = $ENV{'PGPORT'};
+$dbport ||= "";
+
+my $dbpass = "";
+my $output_filename_base = $database;
+
+# Tracking variables
+my $dbisset = 0;
+my $fileisset = 0;
+
+my $only_schema;
+
+my $wanted_output = undef; # means all types
+
+my $statistics = 0;
+
+# Fetch base and dirnames.  Useful for Usage()
+my $basename = $0;
+my $dirname = $0;
+$basename =~ s|^.*/([^/]+)$|$1|;
+$dirname =~ s|^(.*)/[^/]+$|$1|;
+
+# If template_path isn't defined, lets set it ourselves
+$template_path = $dirname if (!defined($template_path));
+
+for ( my $i = 0 ; $i <= $#ARGV ; $i++ ) {
+  ARGPARSE: for ( $ARGV[$i] ) {
+               # Set the database
+               /^-d$/ && do {
+                       $database = $ARGV[ ++$i ];
+                       $dbisset  = 1;
+                       if ( !$fileisset ) {
+                               $output_filename_base = $database;
+                       }
+                       last;
+               };
+
+               # Set the user
+               /^-[uU]$/ && do {
+                       $dbuser = $ARGV[ ++$i ];
+                       if ( !$dbisset ) {
+                               $database = $dbuser;
+                               if ( !$fileisset ) {
+                                       $output_filename_base = $database;
+                               }
+                       }
+                       last;
+               };
+
+               # Set the hostname
+               /^-h$/ && do { $dbhost = $ARGV[ ++$i ]; last; };
+
+               # Set the Port
+               /^-p$/ && do { $dbport = $ARGV[ ++$i ]; last; };
+
+               # Set the users password
+               /^--password=/ && do {
+                       $dbpass = $ARGV[$i];
+                       $dbpass =~ s/^--password=//g;
+                       last;
+               };
+
+               # Set the base of the filename.  The extensions pulled from the templates
+               # will be appended to this name
+               /^-f$/ && do {
+                       $output_filename_base = $ARGV[++$i];
+                       $fileisset        = 1;
+                       last;
+               };
+
+               # Set the template directory explicitly
+               /^(-l|--library)$/ && do {
+                       $template_path = $ARGV[++$i];
+                       last;
+               };
+
+               # Set the output type
+               /^(-t|--type)$/ && do {
+                       $wanted_output = $ARGV[++$i];
+                       last;
+               };
+
+               # User has requested a single schema dump and provided a pattern
+               /^(-s|--schema)$/ && do {
+                       $only_schema = $ARGV[++$i];
+                       last;
+               };
+
+               # Check to see if Statistics have been requested
+               /^--statistics$/ && do {
+                       $statistics = 1;
+                       last;
+               };
+
+               # Help is wanted, redirect user to usage()
+               /^-\?$/ && do { usage(); last; };
+               /^--help$/ && do { usage(); last; };
+       }
+}
+
+# If no arguments have been provided, connect to the database anyway but
+# inform the user of what we're doing.
+if ( $#ARGV <= 0 ) {
+       print <<Msg
+No arguments set.  Use '$basename --help' for help
+
+Connecting to database '$database' as user '$dbuser'
+Msg
+;
+}
+
+
+# Database Connection
+my $dsn = "dbi:Pg:dbname=$database";
+$dsn .= ";host=$dbhost" if ( "$dbhost" ne "" );
+$dsn .= ";port=$dbport" if ( "$dbport" ne "" );
+my $dbh = DBI->connect( $dsn, $dbuser, $dbpass );
+
+# Always disconnect from the database if a database handle is setup
+END {
+       $dbh->disconnect() if $dbh;
+}
+
+# PostgreSQL's version is used to determine what queries are required
+# to retrieve a given information set.
+my $sql_GetVersion = qq{
+  SELECT cast(substr(version(), 12, 1) as integer) * 10000
+                + cast(substr(version(), 14, 1) as integer) * 100
+                as version;
+};
+
+my $sth_GetVersion = $dbh->prepare($sql_GetVersion);
+$sth_GetVersion->execute();
+my $version   = $sth_GetVersion->fetchrow_hashref;
+my $pgversion = $version->{'version'};
+
+# Ensure we only get information for the requested schemas.
+#
+# system_schema             -> The primary system schema for a database.
+#                       Public is used for verions prior to 7.3
+#
+# system_schema_list -> The list of schemas which we are not supposed
+#                       to gather information for.
+#                        TODO: Merge with system_schema in array form.
+#
+# schemapattern      -> The schema the user provided as a command
+#                       line option.
+my $schemapattern = '^';
+my $system_schema;
+my $system_schema_list;
+if ( $pgversion >= 70300 ) {
+       $system_schema = 'pg_catalog';
+       $system_schema_list = 'pg_catalog|information_schema';
+       if (defined($only_schema)) {
+               $schemapattern = '^'. $only_schema .'$';
+       }
+}
+else {
+       $system_schema = 'public';
+       $system_schema_list = $system_schema;
+}
+
+#
+# List of queries which are used to gather information from the
+# database. The queries differ based on version but should 
+# provide similar output. At some point it should be safe to remove
+# support for older database versions.
+#
+my $sql_Columns;
+my $sql_Constraint;
+my $sql_Database;
+my $sql_Foreign_Keys;
+my $sql_Foreign_Key_Arg;
+my $sql_Function;
+my $sql_FunctionArg;
+my $sql_Indexes;
+my $sql_Primary_Keys;
+my $sql_Schema;
+my $sql_Tables;
+my $sql_Table_Statistics;
+
+# Pull out a list of tables, views and special structures. 
+if ( $pgversion >= 70300 ) {
+       $sql_Tables = qq{
+       SELECT nspname as namespace
+                , relname as tablename
+                , pg_catalog.pg_get_userbyid(relowner) AS tableowner
+                , relhasindex as hasindexes
+                , relhasrules as hasrules
+                , reltriggers as hastriggers
+                , pg_class.oid
+                , pg_catalog.obj_description(pg_class.oid, 'pg_class') as table_description
+                , relacl
+                , CASE
+                  WHEN relkind = 'r' THEN
+                        'table'
+                  WHEN relkind = 's' THEN
+                        'special'
+                  ELSE
+                        'view'
+                  END as reltype
+                , CASE
+                  WHEN relkind = 'v' THEN
+                        pg_get_viewdef(pg_class.oid)
+                  ELSE
+                        NULL
+                  END as view_definition
+         FROM pg_catalog.pg_class
+         JOIN pg_catalog.pg_namespace ON (relnamespace = pg_namespace.oid)
+        WHERE relkind IN ('r', 's', 'v')
+          AND nspname !~ '$system_schema_list'
+          AND nspname ~ '$schemapattern';
+       };
+
+       # - uses pg_class.oid
+       $sql_Columns = qq{
+       SELECT attname as column_name
+                , attlen as column_length
+                , CASE
+                  WHEN pg_type.typname = 'int4'
+                               AND EXISTS (SELECT TRUE
+                                                         FROM pg_catalog.pg_depend
+                                                         JOIN pg_catalog.pg_class ON (pg_class.oid = objid)
+                                                        WHERE refobjsubid = attnum
+                                                          AND refobjid = attrelid
+                                                          AND relkind = 'S') THEN
+                        'serial'
+                  WHEN pg_type.typname = 'int8'
+                               AND EXISTS (SELECT TRUE
+                                                         FROM pg_catalog.pg_depend
+                                                         JOIN pg_catalog.pg_class ON (pg_class.oid = objid)
+                                                        WHERE refobjsubid = attnum
+                                                          AND refobjid = attrelid
+                                                          AND relkind = 'S') THEN
+                        'bigserial'
+                  ELSE
+                        pg_catalog.format_type(atttypid, atttypmod)
+                  END as column_type
+                , CASE
+                  WHEN attnotnull THEN
+                        cast('NOT NULL' as text)
+                  ELSE
+                        cast('' as text)
+                  END as column_null
+                , CASE
+                  WHEN pg_type.typname IN ('int4', 'int8')
+                               AND EXISTS (SELECT TRUE
+                                                         FROM pg_catalog.pg_depend
+                                                         JOIN pg_catalog.pg_class ON (pg_class.oid = objid)
+                                                        WHERE refobjsubid = attnum
+                                                          AND refobjid = attrelid
+                                                          AND relkind = 'S') THEN
+                        NULL
+                  ELSE
+                        adsrc
+                  END as column_default
+                , pg_catalog.col_description(attrelid, attnum) as column_description
+                , attnum
+         FROM pg_catalog.pg_attribute 
+                                JOIN pg_catalog.pg_type ON (pg_type.oid = atttypid) 
+         LEFT OUTER JOIN pg_catalog.pg_attrdef ON (   attrelid = adrelid 
+                                                                                          AND attnum = adnum)
+        WHERE attnum > 0
+          AND attisdropped IS FALSE
+          AND attrelid = ?;
+       };
+
+}
+elsif ( $pgversion >= 70200 ) {
+       $sql_Tables = qq{
+       SELECT 'public' as namespace
+                , relname as tablename
+                , pg_get_userbyid(relowner) AS tableowner
+                , relhasindex as hasindexes
+                , relhasrules as hasrules
+                , reltriggers as hastriggers
+                , pg_class.oid
+                , obj_description(pg_class.oid, 'pg_class') as table_description
+                , relacl
+                , CASE
+                  WHEN relkind = 'r' THEN
+                        'table'
+                  WHEN relkind = 's' THEN
+                        'special'
+                  ELSE
+                        'view'
+                  END as reltype
+                , CASE
+                  WHEN relkind = 'v' THEN
+                        pg_get_viewdef(pg_class.relname)
+                  ELSE
+                        NULL
+                  END as view_definition
+         FROM pg_class
+        WHERE relkind in ('r', 's', 'v')
+          AND relname NOT LIKE 'pg_%';
+       };
+
+       # - uses pg_class.oid
+       $sql_Columns = qq{
+       SELECT attname as column_name
+                , attlen as column_length
+                , CASE
+                  WHEN pg_type.typname = 'int4'
+                               AND adsrc LIKE 'nextval(%' THEN
+                        'serial'
+                  WHEN pg_type.typname = 'int8'
+                               AND adsrc LIKE 'nextval(%' THEN
+                        'bigserial'
+                  ELSE
+                        format_type(atttypid, atttypmod)
+                  END as column_type
+                , CASE
+                  WHEN attnotnull IS TRUE THEN
+                        'NOT NULL'::text
+                  ELSE
+                        ''::text
+                  END as column_null
+                , CASE
+                  WHEN pg_type.typname in ('int4', 'int8')
+                               AND adsrc LIKE 'nextval(%' THEN
+                        NULL
+                  ELSE
+                        adsrc
+                  END as column_default
+                , col_description(attrelid, attnum) as column_description
+                , attnum
+         FROM pg_attribute 
+                                JOIN pg_type ON (pg_type.oid = pg_attribute.atttypid) 
+         LEFT OUTER JOIN pg_attrdef ON (   pg_attribute.attrelid = pg_attrdef.adrelid 
+                                                                       AND pg_attribute.attnum = pg_attrdef.adnum)
+        WHERE attnum > 0
+          AND attrelid = ?;
+       };
+
+}
+else {
+       # 7.1 or earlier has a different description structure
+
+       $sql_Tables = qq{
+       SELECT 'public' as namespace
+                , relname as tablename
+                , pg_get_userbyid(relowner) AS tableowner
+                , relhasindex as hasindexes
+                , relhasrules as hasrules
+                , reltriggers as hastriggers
+                , pg_class.oid
+                , obj_description(pg_class.oid) as table_description
+                , 'table' as reltype
+                , NULL as view_definition
+         FROM pg_class
+        WHERE relkind IN ('r', 's')
+          AND relname NOT LIKE 'pg_%';
+       };
+
+       # - uses pg_class.oid
+       $sql_Columns = qq{
+       SELECT attname as column_name
+                , attlen as column_length
+                , CASE
+                  WHEN pg_type.typname = 'int4'
+                               AND adsrc LIKE 'nextval(%' THEN
+                        'serial'
+                  WHEN pg_type.typname = 'int8'
+                               AND adsrc LIKE 'nextval(%' THEN
+                        'bigserial'
+                  ELSE
+                        format_type(atttypid, atttypmod)
+                  END as column_type
+                , CASE
+                  WHEN attnotnull IS TRUE THEN
+                        'NOT NULL'::text
+                  ELSE
+                        ''::text
+                  END as column_null
+                , CASE
+                  WHEN pg_type.typname in ('int4', 'int8')
+                               AND adsrc LIKE 'nextval(%' THEN
+                        NULL
+                  ELSE
+                        adsrc
+                  END as column_default
+                , description as column_description
+                , attnum
+         FROM pg_attribute 
+                                JOIN pg_type ON (pg_type.oid = pg_attribute.atttypid) 
+         LEFT OUTER JOIN pg_attrdef ON (   pg_attribute.attrelid = pg_attrdef.adrelid 
+                                                                       AND pg_attribute.attnum = pg_attrdef.adnum)
+         LEFT OUTER JOIN pg_description ON (pg_description.objoid = pg_attribute.oid)
+        WHERE attnum > 0
+          AND attrelid = ?;
+       };
+}
+
+if ($statistics == 1)
+{
+       if ($pgversion <= 70300) {
+               triggerError("Table statistics supported on PostgreSQL 7.4 and later.\nRemove --statistics flag and try again.");
+       }
+
+       $sql_Table_Statistics = qq{
+               SELECT table_len
+                    , tuple_count
+                    , tuple_len
+                    , CAST(tuple_percent AS numeric(20,2)) AS tuple_percent
+                    , dead_tuple_count
+                    , dead_tuple_len
+                    , CAST(dead_tuple_percent AS numeric(20,2)) AS dead_tuple_percent
+                    , CAST(free_space AS numeric(20,2)) AS free_space
+                    , CAST(free_percent AS numeric(20,2)) AS free_percent
+                 FROM pgstattuple(CAST(? AS oid));
+       };
+}
+
+if ($pgversion >= 70300)
+{
+       $sql_Indexes = qq{
+       SELECT schemaname
+            , tablename
+            , indexname
+            , substring(    indexdef
+                       FROM position('(' IN indexdef) + 1
+                     FOR length(indexdef) - position('(' IN indexdef) - 1
+                    ) AS indexdef
+      FROM pg_catalog.pg_indexes
+        WHERE substring(indexdef FROM 8 FOR 6) != 'UNIQUE'
+          AND schemaname = ?
+          AND tablename = ?;
+       };
+} else {
+       $sql_Indexes = qq{
+       SELECT NULL AS schemaname
+            , NULL AS tablename
+            , NULL AS indexname
+            , NULL AS indexdef
+        WHERE TRUE = FALSE AND ? = ?;
+       };
+}
+
+
+# Fetch the list of PRIMARY and UNIQUE keys
+if ($pgversion >= 70300)
+{
+       $sql_Primary_Keys = qq{
+       SELECT conname AS constraint_name
+                , pg_catalog.pg_get_indexdef(d.objid) AS constraint_definition
+                , CASE
+                  WHEN contype = 'p' THEN
+                        'PRIMARY KEY'
+                  ELSE
+                        'UNIQUE'
+                  END as constraint_type
+         FROM pg_catalog.pg_constraint AS c
+         JOIN pg_catalog.pg_depend AS d ON (d.refobjid = c.oid)
+        WHERE contype IN ('p', 'u')
+          AND deptype = 'i'
+          AND conrelid = ?;
+       };
+
+} else {
+       # - uses pg_class.oid
+       $sql_Primary_Keys = qq{
+       SELECT i.relname AS constraint_name
+                , pg_get_indexdef(pg_index.indexrelid) AS constraint_definition
+                , CASE
+                  WHEN indisprimary THEN
+                        'PRIMARY KEY'
+                  ELSE
+                        'UNIQUE'
+                  END as constraint_type
+         FROM pg_index
+                , pg_class as i 
+        WHERE i.oid = pg_index.indexrelid
+          AND pg_index.indisunique
+          AND pg_index.indrelid = ?;
+       };
+}
+
+# FOREIGN KEY fetch
+#
+# Don't return the constraint name if it was automatically generated by
+# PostgreSQL.  The $N (where N is an integer) is not a descriptive enough
+# piece of information to be worth while including in the various outputs.
+if ( $pgversion >= 70300 ) {
+       $sql_Foreign_Keys = qq{
+       SELECT pg_constraint.oid
+                , pg_namespace.nspname AS namespace
+                , CASE WHEN substring(pg_constraint.conname FROM 1 FOR 1) = '\$' THEN ''
+                  ELSE pg_constraint.conname
+                  END AS constraint_name
+                , conkey AS constraint_key
+                , confkey AS constraint_fkey
+                , confrelid AS foreignrelid
+         FROM pg_catalog.pg_constraint
+         JOIN pg_catalog.pg_class ON (pg_class.oid = conrelid)
+         JOIN pg_catalog.pg_class AS pc ON (pc.oid = confrelid)
+         JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid)
+         JOIN pg_catalog.pg_namespace AS pn ON (pn.oid = pc.relnamespace)
+        WHERE contype = 'f'
+          AND conrelid = ?
+          AND pg_namespace.nspname ~ '$schemapattern'
+          AND pn.nspname ~ '$schemapattern';
+       };
+
+       $sql_Foreign_Key_Arg = qq{
+        SELECT attname AS attribute_name
+                 , relname AS relation_name
+                 , nspname AS namespace
+          FROM pg_catalog.pg_attribute
+          JOIN pg_catalog.pg_class ON (pg_class.oid = attrelid)
+          JOIN pg_catalog.pg_namespace ON (relnamespace = pg_namespace.oid)
+         WHERE attrelid = ?
+               AND attnum = ?;
+       };
+}
+else {
+       # - uses pg_class.oid
+       $sql_Foreign_Keys = q{
+       SELECT oid
+                , 'public' AS namespace
+                , CASE WHEN substring(tgname from 1 for 1) = '$' THEN ''
+                  ELSE tgname
+                  END AS constraint_name
+                , tgnargs AS number_args
+                , tgargs AS args
+         FROM pg_trigger
+        WHERE tgisconstraint = TRUE
+          AND tgtype = 21
+          AND tgrelid = ?;
+       };
+
+       $sql_Foreign_Key_Arg = qq{SELECT TRUE WHERE ? = 0 and ? = 0;};
+}
+
+# Fetch CHECK constraints
+if ( $pgversion >= 70300 ) {
+       $sql_Constraint = qq{
+       SELECT 'CHECK ' || pg_catalog.substr(consrc, 2, length(consrc) - 2) AS constraint_source
+                , conname AS constraint_name
+         FROM pg_constraint
+        WHERE conrelid = ?
+          AND contype = 'c';
+       };
+}
+else {
+       $sql_Constraint = qq{
+       SELECT 'CHECK ' || substr(rcsrc, 2, length(rcsrc) - 2) AS constraint_source
+                , rcname AS constraint_name
+         FROM pg_relcheck
+        WHERE rcrelid = ?;
+       };
+}
+
+# Query for function information
+if ( $pgversion >= 70300 ) {
+       $sql_Function = qq{
+         SELECT proname AS function_name
+                  , nspname AS namespace
+                  , lanname AS language_name
+                  , pg_catalog.obj_description(pg_proc.oid, 'pg_proc') AS comment
+                  , proargtypes AS function_args
+                  , prosrc AS source_code
+                  , proretset AS returns_set
+                  , prorettype AS return_type
+               FROM pg_catalog.pg_proc
+               JOIN pg_catalog.pg_language ON (pg_language.oid = prolang)
+               JOIN pg_catalog.pg_namespace ON (pronamespace = pg_namespace.oid)
+               JOIN pg_catalog.pg_type ON (prorettype = pg_type.oid)
+          WHERE pg_namespace.nspname !~ '$system_schema_list'
+                AND pg_namespace.nspname ~ '$schemapattern'
+            AND proname != 'plpgsql_call_handler';
+       };
+
+       $sql_FunctionArg = qq{
+         SELECT nspname AS namespace
+                  , pg_catalog.format_type(pg_type.oid, typtypmod) AS type_name
+               FROM pg_catalog.pg_type
+               JOIN pg_catalog.pg_namespace ON (pg_namespace.oid = typnamespace)
+          WHERE pg_type.oid = ?;
+       };
+}
+else {
+       $sql_Function = qq{
+       SELECT proname AS function_name
+                , 'public' AS namespace
+                , lanname AS language_name
+                , description AS comment
+                , proargtypes AS function_args
+                , prosrc AS source_code
+                , proretset AS returns_set
+                , prorettype AS return_type
+         FROM pg_proc
+         JOIN pg_language ON (pg_language.oid = prolang)
+         LEFT OUTER JOIN pg_description ON (objoid = pg_proc.oid)
+        WHERE pg_proc.oid > 16000
+          AND proname != 'plpgsql_call_handler';
+        };
+
+       $sql_FunctionArg = qq{
+       SELECT 'public' AS namespace
+                , format_type(pg_type.oid, typtypmod) AS type_name
+         FROM pg_type
+        WHERE pg_type.oid = ?;
+       };
+}
+
+# Fetch schema information.
+if ( $pgversion >= 70300 ) {
+       $sql_Schema = qq{
+       SELECT pg_catalog.obj_description(oid, 'pg_namespace') AS comment
+                , nspname as namespace
+         FROM pg_catalog.pg_namespace;
+       };
+}
+else {
+       # In PostgreSQL 7.2 and prior, schemas were not a part of the system.
+       # Dummy query returns no rows to prevent added logic later on.
+       $sql_Schema = qq{SELECT TRUE WHERE TRUE = FALSE;};
+}
+
+# Fetch the description of the database
+if ($pgversion >= 70300) {
+       $sql_Database = qq{
+       SELECT pg_catalog.obj_description(oid, 'pg_database') as comment
+         FROM pg_catalog.pg_database
+        WHERE datname = '$database';
+       };
+}
+elsif ($pgversion == 70200) {
+       $sql_Database = qq{
+       SELECT obj_description(oid, 'pg_database') as comment
+         FROM pg_database
+        WHERE datname = '$database';
+       };
+}
+else {
+       # In PostgreSQL 7.1, the database did not have comment support
+       $sql_Database = qq{ SELECT TRUE as comment WHERE TRUE = FALSE;};
+}
+
+my $sth_Columns                        = $dbh->prepare($sql_Columns);
+my $sth_Constraint             = $dbh->prepare($sql_Constraint);
+my $sth_Database               = $dbh->prepare($sql_Database);
+my $sth_Foreign_Keys   = $dbh->prepare($sql_Foreign_Keys);
+my $sth_Foreign_Key_Arg        = $dbh->prepare($sql_Foreign_Key_Arg);
+my $sth_Function               = $dbh->prepare($sql_Function);
+my $sth_FunctionArg            = $dbh->prepare($sql_FunctionArg);
+my $sth_Indexes                        = $dbh->prepare($sql_Indexes);
+my $sth_Primary_Keys   = $dbh->prepare($sql_Primary_Keys);
+my $sth_Schema                 = $dbh->prepare($sql_Schema);
+my $sth_Tables                 = $dbh->prepare($sql_Tables);
+my $sth_Table_Statistics = $dbh->prepare($sql_Table_Statistics);
+
+my %structure;
+my %struct;
+
+# Fetch Database info
+$sth_Database->execute();
+my $dbinfo = $sth_Database->fetchrow_hashref;
+if ( defined($dbinfo) ) {
+       $struct{'DATABASE'}{$database}{'COMMENT'} = $dbinfo->{'comment'};
+}
+
+# Fetch tables and all things bound to tables
+$sth_Tables->execute();
+while ( my $tables = $sth_Tables->fetchrow_hashref ) {
+       my $reloid  = $tables->{'oid'};
+       my $relname = $tables->{'tablename'};
+
+       my $group = $tables->{'namespace'};
+
+       EXPRESSIONFOUND:
+
+       # Store permissions
+       my $acl = $tables->{'relacl'};
+
+       # Empty acl groups cause serious issues.
+       $acl ||= '';
+       
+       # Strip array forming 'junk'.
+       $acl =~ s/^{//g;
+       $acl =~ s/}$//g;
+       $acl =~ s/"//g;
+
+       # Foreach acl
+       foreach ( split ( /\,/, $acl ) ) {
+               my ( $user, $raw_permissions ) = split ( /=/, $_ );
+
+               if ( defined($raw_permissions) ) {
+                       if ( $user eq '' ) {
+                               $user = 'PUBLIC';
+                       }
+
+                       # The section after the / is the user who granted the permissions
+                       my ( $permissions, $granting_user) = split ( /\//, $raw_permissions );
+
+                       # Break down permissions to individual flags
+                       if ( $permissions =~ /a/ ) {
+                               $structure{$group}{$relname}{'ACL'}{$user}{'INSERT'} = 1;
+                       }
+
+                       if ( $permissions =~ /r/ ) {
+                               $structure{$group}{$relname}{'ACL'}{$user}{'SELECT'} = 1;
+                       }
+
+                       if ( $permissions =~ /w/ ) {
+                               $structure{$group}{$relname}{'ACL'}{$user}{'UPDATE'} = 1;
+                       }
+
+                       if ( $permissions =~ /d/ ) {
+                               $structure{$group}{$relname}{'ACL'}{$user}{'DELETE'} = 1;
+                       }
+
+                       if ( $permissions =~ /R/ ) {
+                               $structure{$group}{$relname}{'ACL'}{$user}{'RULE'} = 1;
+                       }
+
+                       if ( $permissions =~ /x/ ) {
+                               $structure{$group}{$relname}{'ACL'}{$user}{'REFERENCES'} = 1;
+                       }
+
+                       if ( $permissions =~ /t/ ) {
+                               $structure{$group}{$relname}{'ACL'}{$user}{'TRIGGER'} = 1;
+                       }
+               }
+       }
+
+       # Primitive Stats, but only if requested
+       if ($statistics == 1)
+       {
+               $sth_Table_Statistics->execute($reloid);
+
+               my $stats = $sth_Table_Statistics->fetchrow_hashref;
+
+               $structure{$group}{$relname}{'TABLELEN'} = $stats->{'table_len'};
+               $structure{$group}{$relname}{'TUPLECOUNT'} = $stats->{'tuple_count'};
+               $structure{$group}{$relname}{'TUPLELEN'} = $stats->{'tuple_len'};
+               $structure{$group}{$relname}{'DEADTUPLELEN'} = $stats->{'dead_tuple_len'};
+               $structure{$group}{$relname}{'FREELEN'} = $stats->{'free_space'};
+       }
+
+       # Store the relation type
+       $structure{$group}{$relname}{'TYPE'} = $tables->{'reltype'};
+
+       # Store table description
+       $structure{$group}{$relname}{'DESCRIPTION'} = $tables->{'table_description'};
+
+       # Store the view definition
+       $structure{$group}{$relname}{'VIEW_DEF'} = $tables->{'view_definition'};
+
+       # Store constraints
+       $sth_Constraint->execute($reloid);
+       while ( my $cols = $sth_Constraint->fetchrow_hashref ) {
+               my $constraint_name = $cols->{'constraint_name'};
+               $structure{$group}{$relname}{'CONSTRAINT'}{$constraint_name} =
+                 $cols->{'constraint_source'};
+       }
+
+       $sth_Columns->execute($reloid);
+       my $i = 1;
+       while ( my $cols = $sth_Columns->fetchrow_hashref ) {
+               my $column_name = $cols->{'column_name'};
+               $structure{$group}{$relname}{'COLUMN'}{$column_name}{'ORDER'} =
+                 $cols->{'attnum'};
+               $structure{$group}{$relname}{'COLUMN'}{$column_name}{'PRIMARY KEY'} =
+                 0;
+               $structure{$group}{$relname}{'COLUMN'}{$column_name}{'FKTABLE'}   = '';
+               $structure{$group}{$relname}{'COLUMN'}{$column_name}{'TYPE'} =
+                 $cols->{'column_type'};
+               $structure{$group}{$relname}{'COLUMN'}{$column_name}{'NULL'} =
+                 $cols->{'column_null'};
+               $structure{$group}{$relname}{'COLUMN'}{$column_name}{'DESCRIPTION'} =
+                 $cols->{'column_description'};
+               $structure{$group}{$relname}{'COLUMN'}{$column_name}{'DEFAULT'} =
+                 $cols->{'column_default'};
+       }
+
+       # Pull out both PRIMARY and UNIQUE keys based on the supplied query
+       # and the relation OID.
+       #
+       # Since there may be multiple UNIQUE indexes on a table, we append a
+       # number to the end of the the UNIQUE keyword which shows that they
+       # are a part of a related definition.  I.e UNIQUE_1 goes with UNIQUE_1
+       #
+       $sth_Primary_Keys->execute($reloid);
+       my $unqgroup = 0;
+       while ( my $pricols = $sth_Primary_Keys->fetchrow_hashref ) {
+               my $index_type = $pricols->{'constraint_type'};
+               my $con         = $pricols->{'constraint_name'};
+               my $indexdef   = $pricols->{'constraint_definition'};
+
+               # Fetch the column list
+               my $column_list = $indexdef;
+               $column_list =~ s/.*\(([^)]+)\).*/$1/g;
+
+               # Split our column list and deal with all PRIMARY KEY fields
+               my @collist = split(',', $column_list);
+
+               # Store the column number in the indextype field.  Anything > 0 indicates
+               # the column has this type of constraint applied to it.
+               my $column;
+               my $currentcol = $#collist + 1;
+               my $numcols = $#collist + 1;
+
+               # Bump group number if there are two or more columns
+               if ($numcols >= 2 && $index_type eq 'UNIQUE') {
+                       $unqgroup++;
+               }
+
+               # Record the data to the structure.
+               while ($column = pop(@collist) ) {
+                       $column =~ s/\s$//;
+                       $column =~ s/^\s//;
+
+                       $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'TYPE'} = $index_type;
+
+                       $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'COLNUM'} = $currentcol--;
+
+                       # Record group number only when a multi-column constraint is involved
+                       if ($numcols >= 2 && $index_type eq 'UNIQUE') {
+                               $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'KEYGROUP'} = $unqgroup;
+                       }
+               }
+       }
+
+       # FOREIGN KEYS like UNIQUE indexes can appear several times in a table in multi-column
+       # format. We use the same trick to record a numeric association to the foreign key
+       # reference.
+       #
+       $sth_Foreign_Keys->execute($reloid);
+       my $fkgroup = 0;
+       while (my $forcols = $sth_Foreign_Keys->fetchrow_hashref)
+       {
+               my $column_oid    = $forcols->{'oid'};
+               my $con = $forcols->{'constraint_name'};
+
+               # Declare variables for dataload
+               my @keylist;
+               my @fkeylist;
+               my $fgroup;
+               my $ftable;
+
+               if ($pgversion >= 70300) {
+                       my $fkey   = $forcols->{'constraint_fkey'};
+                       my $keys   = $forcols->{'constraint_key'};
+                       my $frelid = $forcols->{'foreignrelid'};
+
+                       # Since decent array support was not added to 7.4, and we want to support
+                       # 7.3 as well, we parse the text version of the array by hand rather than
+                       # combining this and Foreign_Key_Arg query into a single query.
+                       $fkey =~ s/^{//g;
+                       $fkey =~ s/}$//g;
+                       $fkey =~ s/"//g;
+
+                       $keys =~ s/^{//g;
+                       $keys =~ s/}$//g;
+                       $keys =~ s/"//g;
+
+                       my @keyset  = split (/,/, $keys);
+                       my @fkeyset = split (/,/, $fkey);
+
+                       # Convert the list of column numbers into column names for the
+                       # local side.
+                       foreach my $k (@keyset)
+                       {
+                               $sth_Foreign_Key_Arg->execute($reloid, $k);
+
+                               my $row = $sth_Foreign_Key_Arg->fetchrow_hashref;
+
+                               push(@keylist, $row->{'attribute_name'});
+                       }
+
+                       # Convert the list of columns numbers into column names for the
+                       # referenced side. Grab the table and namespace while we're here.
+                       foreach my $k (@fkeyset)
+                       {
+                               $sth_Foreign_Key_Arg->execute($frelid, $k);
+
+                               my $row = $sth_Foreign_Key_Arg->fetchrow_hashref;
+
+                               push(@fkeylist, $row->{'attribute_name'});
+                               $fgroup = $row->{'namespace'};
+                               $ftable = $row->{'relation_name'};
+                       }
+
+                       # Deal with common catalog issues.
+                       die "FKEY $con Broken -- fix your PostgreSQL installation" if $#keylist != $#fkeylist;
+               }
+               else {
+                       my $keyname;            # Throw away
+                       my $table;                      # Throw away
+                       my $unspecified;        # Throw away
+                       my @columns;
+
+                       my $nargs = $forcols->{'number_args'};
+                       my $args  = $forcols->{'args'};
+
+                       # This database doesn't support namespaces, so use the default
+                       $fgroup = $system_schema;
+
+                       ($keyname, $table, $ftable, $unspecified, @columns) = split(/\000/, $args);
+
+                       # Account for old versions which don't handle NULL but instead return a string
+                       # of the escape sequence
+                       if (!defined($ftable)) {
+                               ($keyname, $table, $ftable, $unspecified, @columns) = split (/\\000/, $args);
+                       }
+
+                       # Push the column list stored into @columns into the key and fkey lists
+                       while (my $column = pop (@columns)
+                               and my $fcolumn = pop (@columns))
+                       {
+                               push(@keylist, $column);
+                               push(@fkeylist, $fcolumn);
+                       }
+               }
+
+               #
+               # Load up the array based on the information discovered using the information
+               # retrieval methods above.
+               #
+               my $numcols = $#keylist + 1;
+               my $currentcol = $#keylist + 1;
+
+               # Bump group number if there are two or more columns involved
+               if ($numcols >= 2) {
+                       $fkgroup++;
+               }
+
+               # Record the foreign key to structure
+               while (my $column = pop(@keylist)
+                       and my $fkey = pop(@fkeylist))
+               {
+                       $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'TYPE'} = 'FOREIGN KEY';
+       
+                       $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'COLNUM'} = $currentcol--;
+
+                       $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'FKTABLE'} = $ftable;
+                       $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'FKSCHEMA'} = $fgroup;
+                       $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'FK-COL NAME'} = $fkey;
+
+                       # Record group number only when a multi-column constraint is involved
+                       if ($numcols >= 2) {
+                               $structure{$group}{$relname}{'COLUMN'}{$column}{'CON'}{$con}{'KEYGROUP'} = $fkgroup;
+                       }
+               }
+       }
+
+       # Pull out index information
+       $sth_Indexes->execute($group, $relname);
+       while (my $idx = $sth_Indexes->fetchrow_hashref)
+       {
+               $structure{$group}{$relname}{'INDEX'}{$idx->{'indexname'}} = $idx->{'indexdef'};
+       }
+}
+
+# Function Handling
+$sth_Function->execute();
+while ( my $functions = $sth_Function->fetchrow_hashref ) {
+       my $functionname = $functions->{'function_name'} . '( ';
+       my $group               = $functions->{'namespace'};
+       my $comment       = $functions->{'comment'};
+       my $functionargs = $functions->{'function_args'};
+
+       my @types = split ( ' ', $functionargs );
+       my $count = 0;
+
+       foreach my $type (@types) {
+               $sth_FunctionArg->execute($type);
+
+               my $hash = $sth_FunctionArg->fetchrow_hashref;
+
+               if ( $count > 0 ) {
+                       $functionname .= ', ';
+               }
+
+               if ( $hash->{'namespace'} ne $system_schema ) {
+                       $functionname .= $hash->{'namespace'} . '.';
+               }
+               $functionname .= $hash->{'type_name'};
+               $count++;
+       }
+       $functionname .= ' )';
+
+       my $ret_type = $functions->{'returns_set'} ? 'SET OF ' : '';
+       $sth_FunctionArg->execute($functions->{'return_type'});
+       my $rhash = $sth_FunctionArg->fetchrow_hashref;
+       $ret_type .= $rhash->{'type_name'};
+
+       $struct{'FUNCTION'}{$group}{$functionname}{'COMMENT'} = $comment;
+       $struct{'FUNCTION'}{$group}{$functionname}{'SOURCE'} = $functions->{'source_code'};
+       $struct{'FUNCTION'}{$group}{$functionname}{'LANGUAGE'} = $functions->{'language_name'};
+       $struct{'FUNCTION'}{$group}{$functionname}{'RETURNS'} = $ret_type;
+}
+
+# Deal with the Schema
+$sth_Schema->execute();
+while ( my $schema = $sth_Schema->fetchrow_hashref ) {
+       my $comment   = $schema->{'comment'};
+       my $namespace = $schema->{'namespace'};
+
+       $struct{'SCHEMA'}{$namespace}{'COMMENT'} = $comment;
+}
+
+# Write out *ALL* templates
+&write_using_templates();
+
+
+#####
+# write_using_templates
+#      Generate structure that HTML::Template requires out of the
+#      $structure for table related information, and $struct for
+#      the schema and function information
+#
+#      TODO: Finish conversion of $structure format into $struct
+sub write_using_templates
+{
+       my @schemas;
+       # Start at 0, increment to 1 prior to use.
+       my $object_id = 0;
+       my %tableids;
+       foreach my $schema ( sort keys %structure ) {
+               my @tables;
+               foreach my $table ( sort keys %{ $structure{$schema} } ) {
+                       # Column List
+                       my @columns;
+                       foreach my $column (
+                               sort {
+                                       $structure{$schema}{$table}{'COLUMN'}{$a}{'ORDER'} <=>
+                                       $structure{$schema}{$table}{'COLUMN'}{$b}{'ORDER'}
+                               } keys %{ $structure{$schema}{$table}{'COLUMN'} }
+                         )
+                       {
+                               my $inferrednotnull = 0;
+
+                               # Have a shorter default for places that require it
+                               my $shortdefault = $structure{$schema}{$table}{'COLUMN'}{$column}{'DEFAULT'};
+                               $shortdefault =~ s/^(.{17}).{5,}(.{5})$/$1 ... $2/g;
+
+                               # Deal with column constraints
+                               my @colconstraints;
+                               foreach my $con
+                                       ( sort keys %{ $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'} })
+                               {
+                                       if ($structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'TYPE'} eq 'UNIQUE') {
+                                               my $unq = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'TYPE'};
+                                               my $unqcol = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'COLNUM'};
+                                               my $unqgroup = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'KEYGROUP'};
+
+                                               push @colconstraints, {
+                                                       column_unique => $unq,
+                                                       column_unique_colnum => $unqcol,
+                                                       column_unique_keygroup => $unqgroup,
+                                               };
+                                       } elsif ($structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'TYPE'} eq 'PRIMARY KEY') {
+                                               $inferrednotnull = 1;
+                                               push @colconstraints, {
+                                                       column_primary_key => 'PRIMARY KEY',
+                                               };
+                                       } elsif ($structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'TYPE'} eq 'FOREIGN KEY') {
+                                               my $fksgmlid = sgml_safe_id(
+                                                       join('.'
+                                                               , $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'FKSCHEMA'}
+                                                               , $structure{$schema}{$table}{'TYPE'} 
+                                                               , $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'FKTABLE'}));
+
+                                               my $fkgroup = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'KEYGROUP'};
+                                               my $fktable = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'FKTABLE'};
+                                               my $fkcol = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'FK-COL NAME'};
+                                               my $fkschema = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'FKSCHEMA'};
+
+                                               push @colconstraints, {
+                                                       column_fk => 'FOREIGN KEY',
+                                                       column_fk_colnum => $fkcol,
+                                                       column_fk_keygroup => $fkgroup,
+                                                       column_fk_schema => $fkschema,
+                                                       column_fk_schema_dbk => docbook($fkschema),
+                                                       column_fk_schema_dot => graphviz($fkschema),
+                                                       column_fk_sgmlid => $fksgmlid,
+                                                       column_fk_table => $fktable,
+                                                       column_fk_table_dbk => docbook($fktable),
+                                               };
+
+                                               # only have the count if there is more than 1 schema
+                                               if (scalar(keys %structure) > 1) {
+                                                       $colconstraints[-1]{"number_of_schemas"} = scalar(keys %structure);
+                                               }
+                                       }
+                               }
+
+
+                               # Generate the Column array
+                               push @columns, {
+                                       column => $column,
+                                       column_dbk => docbook($column),
+                                       column_dot => graphviz($column),
+                                       column_default => $structure{$schema}{$table}{'COLUMN'}{$column}{'DEFAULT'},
+                                       column_default_dbk => docbook($structure{$schema}{$table}{'COLUMN'}{$column}{'DEFAULT'}),
+                                       column_default_short => $shortdefault,
+                                       column_default_short_dbk => docbook($shortdefault),
+
+                                       column_comment => $structure{$schema}{$table}{'COLUMN'}{$column}{'DESCRIPTION'},
+                                       column_comment_dbk => docbook($structure{$schema}{$table}{'COLUMN'}{$column}{'DESCRIPTION'}),
+
+                                       column_number => $structure{$schema}{$table}{'COLUMN'}{$column}{'ORDER'},
+
+                                       column_type => $structure{$schema}{$table}{'COLUMN'}{$column}{'TYPE'},
+                                       column_type_dbk => docbook($structure{$schema}{$table}{'COLUMN'}{$column}{'TYPE'}),
+
+                                       column_constraints => \@colconstraints,
+                               };
+
+                               if ($inferrednotnull == 0) {
+                                       $columns[-1]{"column_constraint_notnull"} =
+                                               $structure{$schema}{$table}{'COLUMN'}{$column}{'NULL'};
+                               }
+                       }
+
+                       # Constraint List
+                       my @constraints;
+                       foreach my $constraint (sort keys %{$structure{$schema}{$table}{'CONSTRAINT'}}) {
+                               my $shortcon = $structure{$schema}{$table}{'CONSTRAINT'}{$constraint};
+                               $shortcon =~ s/^(.{30}).{5,}(.{5})$/$1 ... $2/g;
+                               push @constraints, {
+                                       constraint => $structure{$schema}{$table}{'CONSTRAINT'}{$constraint},
+                                       constraint_dbk => docbook($structure{$schema}{$table}{'CONSTRAINT'}{$constraint}),
+                                       constraint_name => $constraint,
+                                       constraint_name_dbk => docbook($constraint),
+                                       constraint_short => $shortcon,
+                                       constraint_short_dbk => docbook($shortcon),
+                                       table => $table,
+                                       table_dbk => docbook($table),
+                                       table_dot => graphviz($table),
+                               };
+                       }
+
+                       # Index List
+                       my @indexes;
+                       foreach my $index (sort keys %{$structure{$schema}{$table}{'INDEX'}}) { 
+                               push @indexes, {
+                                       index_definition => $structure{$schema}{$table}{'INDEX'}{$index},
+                                       index_definition_dbk => docbook($structure{$schema}{$table}{'INDEX'}{$index}),
+                                       index_name => $index,
+                                       index_name_dbk => docbook($index),
+                                       table => $table,
+                                       table_dbk => docbook($table),
+                                       table_dot => graphviz($table),
+                                       schema => $schema,
+                                       schema_dbk => docbook($schema),
+                                       schema_dot => graphviz($schema),
+                               };
+                       }
+
+                       # Foreign Key Discovery
+                       #
+                       # $lastmatch is used to ensure that we only supply a result a single time and not once
+                       # for each link found.  Since the loops are sorted, we only need to track the last
+                       # element, and not all supplied elements.
+                       my @fk_schemas;
+                       my $lastmatch = '';
+                       foreach my $fk_schema ( sort keys %structure ) {
+                               foreach my $fk_table ( sort keys %{ $structure{$fk_schema} } ) {
+                                       foreach my $fk_column (
+                                               sort keys %{ $structure{$fk_schema}{$fk_table}{'COLUMN'} } )
+                                       {
+                                               foreach my $con (
+                                                       sort keys %{$structure{$fk_schema}{$fk_table}{'COLUMN'}{$fk_column}{'CON'}}
+                                               ) {
+                                                       if (
+                                                               $structure{$fk_schema}{$fk_table}{'COLUMN'}{$fk_column}{'CON'}{$con}{'TYPE'} eq 'FOREIGN KEY'
+                                                               && $structure{$fk_schema}{$fk_table}{'COLUMN'}{$fk_column}{'CON'}{$con}{'FKTABLE'} eq $table
+                                                               && $structure{$fk_schema}{$fk_table}{'COLUMN'}{$fk_column}{'CON'}{$con}{'FKSCHEMA'} eq $schema
+                                                               && $lastmatch ne "$fk_schema$fk_table"
+                                                               )
+                                                       {
+                                                               my $fksgmlid = sgml_safe_id(
+                                                                                                       join('.',$fk_schema
+                                                                                                                       , $structure{$fk_schema}{$fk_table}{'TYPE'}
+                                                                                                                       , $fk_table));
+                                                               push @fk_schemas, {
+                                                                       fk_column_number => $structure{$fk_schema}{$fk_table}{'COLUMN'}{$fk_column}{'ORDER'},
+                                                                       fk_sgmlid => $fksgmlid,
+                                                                       fk_schema => $fk_schema,
+                                                                       fk_schema_dbk => docbook($fk_schema),
+                                                                       fk_schema_dot => graphviz($fk_schema),
+                                                                       fk_table => $fk_table,
+                                                                       fk_table_dbk => docbook($fk_table),
+                                                                       fk_table_dot => graphviz($fk_table),
+                                                               };
+
+                                                               # only have the count if there is more than 1 schema
+                                                               if (scalar(keys %structure) > 1) {
+                                                                       $fk_schemas[-1]{"number_of_schemas"} = scalar(keys %structure);
+                                                               }
+
+                                                               $lastmatch = "$fk_schema$fk_table";
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       # List off permissions
+                       my @permissions;
+                       foreach my $user ( sort keys %{ $structure{$schema}{$table}{'ACL'} } ) {
+                               push @permissions, {
+                                       schema => $schema,
+                                       schema_dbk => docbook($schema),
+                                       schema_dot => graphviz($schema),
+                                       table => $table,
+                                       table_dbk => docbook($table),
+                                       table_dot => graphviz($table),
+                                       user => $user,
+                                       user_dbk => docbook($user),
+                               };
+
+                               # only have the count if there is more than 1 schema
+                               if (scalar(keys %structure) > 1) {
+                                       $permissions[-1]{"number_of_schemas"} = scalar(keys %structure);
+                               }
+
+                               foreach my $perm ( keys %{ $structure{$schema}{$table}{'ACL'}{$user} } ) {
+                                       if ( $structure{$schema}{$table}{'ACL'}{$user}{$perm} == 1 ) {
+                                               $permissions[-1]{lower($perm)} = 1; 
+                                       }
+                               }
+
+                       }
+
+                       # Increment and record the object ID
+                       $tableids{"$schema$table"} = ++$object_id;
+                       my $viewdef = sql_prettyprint($structure{$schema}{$table}{'VIEW_DEF'});
+
+                       push @tables, {
+                               object_id => $object_id,
+                               object_id_dbk => docbook($object_id),
+
+                               schema => $schema,
+                               schema_dbk => docbook($schema),
+                               schema_dot => graphviz($schema),
+                               schema_sgmlid => sgml_safe_id($schema.".schema"),
+
+                               # Statistics
+                               stats_enabled => $statistics,
+                               stats_dead_bytes => useUnits($structure{$schema}{$table}{'DEADTUPLELEN'}),
+                               stats_dead_bytes_dbk => docbook(useUnits($structure{$schema}{$table}{'DEADTUPLELEN'})),
+                               stats_free_bytes => useUnits($structure{$schema}{$table}{'FREELEN'}),
+                               stats_free_bytes_dbk => docbook(useUnits($structure{$schema}{$table}{'FREELEN'})),
+                               stats_table_bytes => useUnits($structure{$schema}{$table}{'TABLELEN'}),
+                               stats_table_bytes_dbk => docbook(useUnits($structure{$schema}{$table}{'TABLELEN'})),
+                               stats_tuple_count => $structure{$schema}{$table}{'TUPLECOUNT'},
+                               stats_tuple_count_dbk => docbook($structure{$schema}{$table}{'TUPLECOUNT'}),
+                               stats_tuple_bytes => useUnits($structure{$schema}{$table}{'TUPLELEN'}),
+                               stats_tuple_bytes_dbk => docbook(useUnits($structure{$schema}{$table}{'TUPLELEN'})),
+
+                               table => $table,
+                               table_dbk => docbook($table),
+                               table_dot => graphviz($table),
+                               table_sgmlid => sgml_safe_id(join('.', $schema, $structure{$schema}{$table}{'TYPE'}, $table)),
+                               table_comment => $structure{$schema}{$table}{'DESCRIPTION'},
+                               table_comment_dbk => docbook($structure{$schema}{$table}{'DESCRIPTION'}),
+                               view_definition => $viewdef,
+                               view_definition_dbk => docbook($viewdef),
+                               columns => \@columns,
+                               constraints => \@constraints,
+                               fk_schemas => \@fk_schemas,
+                               indexes => \@indexes,
+                               permissions => \@permissions,
+                       };
+
+                       # only have the count if there is more than 1 schema
+                       if (scalar(keys %structure) > 1) {
+                               $tables[-1]{"number_of_schemas"} = scalar(keys %structure);
+                       }
+               }
+
+               # Dump out list of functions
+               my @functions;
+               foreach my $function ( sort keys %{ $struct{'FUNCTION'}{$schema} } ) {
+                       push @functions, {
+                               function => $function,
+                               function_dbk => docbook($function),
+                               function_sgmlid => sgml_safe_id(join('.', $schema, 'function', $function)),
+                               function_comment => $struct{'FUNCTION'}{$schema}{$function}{'COMMENT'},
+                               function_comment_dbk => docbook($struct{'FUNCTION'}{$schema}{$function}{'COMMENT'}),
+                               function_language => uc($struct{'FUNCTION'}{$schema}{$function}{'LANGUAGE'}),
+                               function_returns => $struct{'FUNCTION'}{$schema}{$function}{'RETURNS'},
+                               function_source => $struct{'FUNCTION'}{$schema}{$function}{'SOURCE'},
+                               schema => $schema,
+                               schema_dbk => docbook($schema),
+                               schema_dot => graphviz($schema),
+                               schema_sgmlid => sgml_safe_id($schema.".schema"),
+                       };
+
+                       # only have the count if there is more than 1 schema
+                       if (scalar(keys %structure) > 1) {
+                               $functions[-1]{"number_of_schemas"} = scalar(keys %structure);
+                       }
+               }
+
+               push @schemas, {
+                       schema => $schema,
+                       schema_dbk => docbook($schema),
+                       schema_dot => graphviz($schema),
+                       schema_sgmlid => sgml_safe_id($schema.".schema"),
+                       schema_comment => $struct{'SCHEMA'}{$schema}{'COMMENT'},
+                       schema_comment_dbk => docbook($struct{'SCHEMA'}{$schema}{'COMMENT'}),
+                       functions => \@functions,
+                       tables => \@tables,
+               };
+
+               # Build the array of schemas
+               if (scalar(keys %structure) > 1) {
+                       $schemas[-1]{"number_of_schemas"} = scalar(keys %structure);
+               }
+       }
+
+       # Link the various components together via the template.
+       my @fk_links;
+       my @fkeys;
+       foreach my $schema ( sort keys %structure ) {
+               foreach my $table ( sort keys %{ $structure{$schema} } ) {
+                       foreach my $column (
+                               sort {
+                                       $structure{$schema}{$table}{'COLUMN'}{$a}{'ORDER'} <=>
+                                       $structure{$schema}{$table}{'COLUMN'}{$b}{'ORDER'}
+                               }
+                               keys %{ $structure{$schema}{$table}{'COLUMN'} }
+                       ) {
+                               foreach my $con (
+                                       sort keys %{$structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}}
+                               ) {
+                                       # To prevent a multi-column foreign key from appearing several times, we've opted
+                                       # to simply display the first column of any given key.  Since column numbering
+                                       # always starts at 1 for foreign keys.
+                                       if ( $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'TYPE'}
+                                                       eq 'FOREIGN KEY' 
+                                               && $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'COLNUM'}
+                                                       == 1 )
+                                       {
+                                               # Pull out some of the longer keys
+                                               my $ref_table = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'FKTABLE'};
+                                               my $ref_schema = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'FKSCHEMA'};
+                                               my $ref_column = $structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'FK-COL NAME'};
+
+                                               # Default values cause these elements to attach to the bottom in Dia
+                                               #
+                                               # If a KEYGROUP is not defined, it's a single column.  Modify the ref_con
+                                               # and key_con variables to attach the to the columns connection point
+                                               # directly.
+                                               my $ref_con = 0;
+                                               my $key_con = 0;
+                                               my $keycon_offset = 0;
+                                               if (!defined($structure{$schema}{$table}{'COLUMN'}{$column}{'CON'}{$con}{'KEYGROUP'})) {
+                                                       $ref_con = $structure{$ref_schema}{$ref_table}{'COLUMN'}{$ref_column}{'ORDER'};
+                                                       $key_con = $structure{$schema}{$table}{'COLUMN'}{$column}{'ORDER'};
+                                                       $keycon_offset = 1;
+                                               }
+                                       
+                                               # Bump object_id
+                                               $object_id++;
+
+                                               push @fk_links, {
+                                                       fk_link_name => $con,
+                                                       fk_link_name_dbk => docbook($con),
+                                                       fk_link_name_dot => graphviz($con),
+                                                       handle0_connection => $key_con,
+                                                       handle0_connection_dbk => docbook($key_con),
+                                                       handle0_connection_dia => 6 + ($key_con * 2),
+                                                       handle0_name => $table,
+                                                       handle0_name_dbk => docbook($table),
+                                                       handle0_schema => $schema,
+                                                       handle0_to => $tableids{"$schema$table"},
+                                                       handle0_to_dbk => docbook($tableids{"$schema$table"}),
+                                                       handle1_connection => $ref_con,
+                                                       handle1_connection_dbk => docbook($ref_con),
+                                                       handle1_connection_dia => 6 + ($ref_con * 2) + $keycon_offset,
+                                                       handle1_name => $ref_table,
+                                                       handle1_name_dbk => docbook($ref_table),
+                                                       handle1_schema => $ref_schema,
+                                                       handle1_to => $tableids{"$ref_schema$ref_table"},
+                                                       handle1_to_dbk => docbook($tableids{"$ref_schema$ref_table"}),
+                                                       object_id => $object_id,
+                                                       object_id_dbk => docbook($object_id),
+                                               };
+
+                                               # Build the array of schemas
+                                               if (scalar(keys %structure) > 1) {
+                                                       $fk_links[-1]{"number_of_schemas"} = scalar(keys %structure);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+### FOR DEBUGGING ###
+# print Data::Dumper->Dump(\@schemas);
+
+       # Make database level comment information
+       my @timestamp = localtime();
+       my $dumped_on = sprintf("%04d-%02d-%02d", $timestamp[5]+1900, $timestamp[4]+1, $timestamp[3]);
+       my $database_comment = $struct{'DATABASE'}{$database}{'COMMENT'};
+
+       # Loop through each template found in the supplied path. Output the results of the template
+       # as <filename>.<extension> into the current working directory.
+       my @template_files = glob($template_path .'/*.tmpl');
+
+       # Ensure we've told the user if we don't find any files.
+       triggerError("Templates files not found in $template_path")
+               if ($#template_files < 0);
+
+       # Process all found templates.
+       foreach my $template_file (@template_files) {
+               (my $file_extension = $template_file) =~ s/^(?:.*\/|)([^\/]+)\.tmpl$/$1/;
+               next if (defined($wanted_output) && $file_extension ne $wanted_output);
+               my $output_filename = "$output_filename_base.$file_extension";
+               print "Producing $output_filename from $template_file\n";
+
+               my $template = HTML::Template->new(
+                       filename => $template_file,
+                       die_on_bad_params => 0,
+                       global_vars => 0,
+                       strict => 1,
+                       loop_context_vars => 1
+               );
+
+               $template->param(
+                       database => $database,
+                       database_dbk => docbook($database),
+                       database_sgmlid => sgml_safe_id($database),
+                       database_comment => $database_comment,
+                       database_comment_dbk => docbook($database_comment),
+                       dumped_on => $dumped_on,
+                       dumped_on_dbk => docbook($dumped_on),
+                       fk_links => \@fk_links,
+                       schemas => \@schemas,
+               );
+
+               sysopen( FH, $output_filename, O_WRONLY | O_TRUNC | O_CREAT, 0644 )
+                 or die "Can't open $output_filename: $!";
+               print FH $template->output();
+       }
+}
+
+
+######
+# sgml_safe_id
+#   Safe SGML ID Character replacement
+sub sgml_safe_id($) {
+       my $string = shift;
+
+       # Lets use the keyword ARRAY in place of the square brackets
+       # to prevent duplicating a non-array equivelent
+       $string =~ s/\[\]/ARRAY-/g;
+
+       # Brackets, spaces, commads, underscores are not valid 'id' characters
+       # replace with as few -'s as possible.
+       $string =~ s/[ "',)(_-]+/-/g;
+
+       # Don't want a - at the end either.  It looks silly.
+       $string =~ s/-$//g;
+
+       return ($string);
+}
+
+#####
+# lower
+#      LowerCase the string
+sub lower($) {
+       my $string = shift;
+
+       $string =~ tr/A-Z/a-z/;
+
+       return ($string);
+}
+
+#####
+# useUnits
+#      Tack on base 2 metric units
+sub useUnits($) {
+       my $value = shift;
+
+       my @units = ('Bytes', 'KiBytes', 'MiBytes', 'GiBytes', 'TiBytes');
+       my $loop = 0;
+
+       while ($value >= 1024)
+       {
+               $loop++;
+
+               $value = $value / 1024;
+       }
+
+       return(sprintf("%.2f %s", $value, $units[$loop]));
+}
+
+#####
+# docbook
+#      Docbook output is special in that we may or may not want to escape
+#      the characters inside the string depending on a string prefix.
+sub docbook($) {
+       my $string = shift;
+
+       if ( defined($string) ) {
+               if ( $string =~ /^\@DOCBOOK/ ) {
+                       $string =~ s/^\@DOCBOOK//;
+               }
+               else {
+                       $string =~ s/&(?!(amp|lt|gr|apos|quot);)/&amp;/g;
+                       $string =~ s/</&lt;/g;
+                       $string =~ s/>/&gt;/g;
+                       $string =~ s/'/&apos;/g;
+                       $string =~ s/"/&quot;/g;
+               }
+       }
+       else {
+               # Return an empty string when all else fails
+               $string = '';
+       }
+
+       return ($string);
+}
+
+#####
+# graphviz
+#      GraphViz output requires that special characters (like " and whitespace) must be preceeded
+#      by a \ when a part of a lable.
+sub graphviz($) {
+       my $string = shift;
+
+       # Ensure we don't return an least a empty string
+       $string = '' if (!defined($string));
+
+       $string =~ s/([\s"'])/\\$1/g;
+
+       return ($string);
+}
+
+
+#####
+# sql_prettyprint
+#      Clean up SQL into something presentable
+sub sql_prettyprint($)
+{
+       my $string = shift;
+
+       # If nothing has been sent in, return an empty string
+       if (!defined($string))
+       {
+               return '';
+       }
+
+       # Initialize Result string
+       my $result = '';
+
+       # List of tokens to split on 
+       my $tok = "SELECT|FROM|WHERE|HAVING|GROUP BY|ORDER BY|OR|AND|LEFT JOIN|RIGHT JOIN".
+                               "|LEFT OUTER JOIN|LEFT INNER JOIN|INNER JOIN|RIGHT OUTER JOIN|RIGHT INNER JOIN".
+                               "|JOIN|UNION ALL|UNION|EXCEPT|USING|ON|CAST|[\(\),]";
+
+       my $key = 0;
+       my $bracket = 0;
+       my $depth = 0;
+       my $indent = 6;
+
+       # XXX: Split is wrong -- match would do
+       foreach my $elem (split(/(\"[^\"]*\"|'[^']*'|$tok)/, $string))
+       {
+               my $format;
+
+               # Skip junk tokens
+               if ($elem =~ /^[\s]?$/)
+               {
+                       next;
+               }
+
+               # NOTE: Should we drop leading spaces?
+               #       $elem =~ s/^\s//;
+
+               # Close brackets are special
+               # Bring depth in a level
+               if ($elem =~ /\)/)
+               {
+                       $depth = $depth - $indent;
+                       if ($key == 1 or $bracket == 1)
+                       {
+                               $format = "%s%s";
+                       } else
+                       {
+                               $format = "%s\n%". $depth ."s";
+                       }
+
+                       $key = 0;
+                       $bracket = 0;
+               }
+               # Open brackets are special
+               # Bump depth out a level
+               elsif ($elem =~ /\(/)
+               {
+                       if ($key == 1)
+                       {
+                               $format = "%s %s";
+                       } else
+                       {
+                               $format = "%s\n%". $depth ."s";
+                       }
+                       $depth = $depth + $indent;
+                       $bracket = 1;
+                       $key = 0;
+               }
+               # Key element
+               # Token from our list -- format on left hand side of the equation
+               # when appropriate.
+               elsif ($elem =~ /$tok/)
+               {
+                       if ($key == 1)
+                       {
+                               $format = "%s%s";
+                       } else
+                       {
+                               $format = "%s\n%". $depth ."s";
+                       }
+
+                       $key = 1;
+                       $bracket = 0;
+               }
+               # Value
+               # Format for right hand side of the equation
+               else {
+                       $format = "%s%s";               
+
+                       $key = 0;
+               }
+
+               # Add the new format string to the result
+               $result = sprintf($format, $result, $elem);
+       }
+
+       return $result;
+}
+
+##
+# triggerError
+#      Print out a supplied error message and exit the script.
+sub triggerError($)
+{
+       my $error = shift;
+
+       # Test error
+       if (!defined($error) || $error eq '')
+       {
+               triggerError("triggerError: Unknown error");
+       }
+       printf("\n\n%s\n", $error);
+
+       exit 2;
+}
+
+#####
+# usage
+#   Usage
+sub usage() {
+       print <<USAGE
+Usage:
+  $basename [options] [dbname [username]]
+
+Options:
+  -d <dbname>     Specify database name to connect to (default: $database)
+  -f <file>       Specify output file prefix (default: $database)
+  -h <host>       Specify database server host (default: localhost)
+  -p <port>       Specify database server port (default: 5432)
+  -u <username>   Specify database username (default: $dbuser)
+  --password=<pw> Specify database password (default: blank)
+
+  -l <path>       Path to the templates (default: @@TEMPLATE-DIR@@)
+  -t <output>     Type of output wanted (default: All in template library)
+
+  -s <schema>    Specify a specific schema to match. Technically this is a regular
+                  expression but anything other than a specific name may have unusual
+                  results.
+
+  --statistics    In 7.4 and later, with the contrib module pgstattuple installed we
+                  can gather statistics on the tables in the database 
+                  (average size, free space, disk space used, dead tuple counts, etc.)
+                  This is disk intensive on large databases as all pages must be visited.
+USAGE
+       ;
+       exit 1;
+}
diff --git a/regressdatabase.sql b/regressdatabase.sql
new file mode 100644 (file)
index 0000000..8d5890f
--- /dev/null
@@ -0,0 +1,115 @@
+--
+-- $Id: regressdatabase.sql,v 1.1 2004/05/12 16:00:37 rbt Exp $
+--
+
+BEGIN;
+--
+-- Foreign key'd structure, check constraints, primary keys
+-- and duplicate table names in different schemas
+--
+CREATE SCHEMA product
+ CREATE TABLE product
+ ( product_id SERIAL PRIMARY KEY
+ , product_code text NOT NULL UNIQUE 
+                     CHECK(product_code = upper(product_code))
+ , product_description text
+ );
+
+CREATE SCHEMA store
+ CREATE TABLE store
+ ( store_id SERIAL PRIMARY KEY
+ , store_code text NOT NULL UNIQUE
+                   CHECK(store_code = upper(store_code))
+ , store_description text
+ )
+
+ CREATE TABLE inventory
+ ( store_id integer REFERENCES store
+                       ON UPDATE CASCADE ON DELETE RESTRICT
+ , product_id integer REFERENCES product.product
+                        ON UPDATE CASCADE ON DELETE RESTRICT
+ , PRIMARY KEY(store_id, product_id)
+ , quantity integer NOT NULL CHECK(quantity > 0)
+ );
+
+--
+-- Another schema with 
+--
+CREATE SCHEMA warehouse
+ CREATE TABLE warehouse
+ ( warehouse_id SERIAL PRIMARY KEY
+ , warehouse_code text NOT NULL UNIQUE
+                       CHECK(warehouse_code = upper(warehouse_code))
+ , warehouse_manager text NOT NULL
+ , warehouse_supervisor text UNIQUE
+ , warehouse_description text
+ , CHECK (upper(warehouse_manager) != upper(warehouse_supervisor))
+ )
+ CREATE TABLE inventory
+ ( warehouse_id integer REFERENCES warehouse 
+                          ON UPDATE CASCADE
+                          ON DELETE RESTRICT
+ , product_id integer REFERENCES product.product
+                        ON UPDATE CASCADE
+                        ON DELETE RESTRICT
+ , PRIMARY KEY(warehouse_id, product_id)
+ , quantity integer NOT NULL
+                    CHECK(quantity > 0)
+ )
+ CREATE VIEW products AS
+   SELECT DISTINCT product.*
+     FROM inventory
+     JOIN product.product USING (product_id);
+
+-- Sample index
+CREATE INDEX quantity_index ON warehouse.inventory (quantity);
+
+--
+-- Simple text comments
+--
+--COMMENT ON DATABASE IS
+--'This database has been created for the purpose of simple
+-- tests on PostgreSQL Autodoc.';
+
+COMMENT ON SCHEMA product IS
+'This schema stores a list of products and information
+ about the product';
+
+COMMENT ON SCHEMA warehouse IS
+'A list of warehouses and information on warehouses';
+
+COMMENT ON TABLE warehouse.inventory IS
+'Warehouse inventory';
+
+COMMENT ON TABLE store.inventory IS
+'Store inventory';
+
+COMMENT ON COLUMN warehouse.warehouse.warehouse_code IS
+'Internal code which represents warehouses for
+ invoice purposes';
+
+COMMENT ON COLUMN warehouse.warehouse.warehouse_supervisor IS
+'Supervisors name for a warehouse when one
+ has been assigned.  The same supervisor may not
+ be assigned to more than one warehouse, per company
+ policy XYZ.';
+
+COMMENT ON COLUMN warehouse.warehouse.warehouse_manager IS
+'Name of Warehouse Manager';
+
+--
+-- A few simple functions
+--
+CREATE FUNCTION product.worker(integer, integer) RETURNS integer AS
+'SELECT $1 + $1;' LANGUAGE sql;
+
+CREATE FUNCTION warehouse.worker(integer, integer) RETURNS integer AS
+'SELECT $1 * $1;' LANGUAGE sql;
+
+COMMENT ON FUNCTION product.worker(integer, integer) IS
+'Worker function appropriate for products';
+
+COMMENT ON FUNCTION warehouse.worker(integer, integer) IS
+'Worker function appropriate for warehouses.';
+
+END;
diff --git a/xml.tmpl b/xml.tmpl
new file mode 100644 (file)
index 0000000..13d0188
--- /dev/null
+++ b/xml.tmpl
@@ -0,0 +1,203 @@
+<!-- $Header: /cvsroot/autodoc/autodoc/xml.tmpl,v 1.1 2004/05/12 16:00:37 rbt Exp $ -->
+
+<book id="database.<!-- TMPL_VAR name="database_sgmlid" -->" xreflabel="<!-- TMPL_VAR name="database_dbk" --> database schema"><title><!-- TMPL_VAR name="database_dbk" --> Model</title>
+
+<!-- TMPL_IF name="database_comment" -->
+<!-- TMPL_VAR name="database_comment_dbk" -->
+<!-- /TMPL_IF name="database_comment" -->
+
+<!-- TMPL_LOOP name="schemas" -->
+  <chapter id="<!-- TMPL_VAR name="schema_sgmlid" -->"
+           xreflabel="<!-- TMPL_VAR name="schema_dbk" -->">
+    <title>Schema <!-- TMPL_VAR name="schema_dbk" --></title>
+    <para><!-- TMPL_VAR name="schema_comment_dbk" --></para>
+
+<!-- TMPL_LOOP name="tables" -->
+      <section id="<!-- TMPL_VAR name="table_sgmlid" -->"
+               xreflabel="<!-- TMPL_VAR name="schema_dbk" -->.<!-- TMPL_VAR name="table_dbk" -->">
+        <title id="<!-- TMPL_VAR name="table_sgmlid" -->-title">
+         <!-- TMPL_IF name="view_definition" -->View:
+         <!-- TMPL_ELSE -->Table:
+         <!-- /TMPL_IF name="view_definition" -->
+         <structname><!-- TMPL_VAR name="table_dbk" --></structname>
+        </title>
+<!-- TMPL_IF name="table_comment" -->
+        <para>
+          <!-- TMPL_VAR name="table_comment_dbk" -->
+        </para>
+<!-- /TMPL_IF name="table_comment" -->
+
+        <para>
+          <variablelist>
+            <title>
+              Structure of <structname><!-- TMPL_VAR name="table_dbk" --></structname>
+            </title>
+
+<!-- TMPL_LOOP name="columns" -->
+            <varlistentry>
+              <term><structfield><!-- TMPL_VAR name="column_dbk" --></structfield></term>
+              <listitem><para>
+                <type><!-- TMPL_VAR name="column_type_dbk" --></type>
+<!-- TMPL_LOOP name="column_constraints" -->
+<!-- TMPL_IF name="column_primary_key" -->
+                <literal>PRIMARY KEY</literal>
+
+<!-- /TMPL_IF name="column_primary_key" -->
+
+<!-- TMPL_IF name="column_unique" -->
+                      <literal>UNIQUE<!-- TMPL_IF name="column_unique_keygroup" -->#<!-- TMPL_VAR name="column_unique_keygroup" --><!-- /TMPL_IF name="column_unique_keygroup" --></literal>
+<!-- /TMPL_IF name="column_unique" -->
+<!-- /TMPL_LOOP name="column_constraints" -->
+
+<!-- TMPL_IF name="column_constraint_notnull" -->
+                <literal>NOT NULL</literal>
+<!-- /TMPL_IF name="column_constraint_notnull" -->
+
+<!-- TMPL_IF name="column_default" -->
+                <literal>DEFAULT <!-- TMPL_VAR name="column_default_dbk" --></literal>
+<!-- /TMPL_IF name="column_default" -->
+
+<!-- TMPL_LOOP name="column_constraints" -->
+<!-- TMPL_IF name="column_fk" -->
+                <literal>REFERENCES</literal> <xref linkend="<!-- TMPL_VAR name="column_fk_sgmlid" -->"/>
+<!-- /TMPL_IF name="column_fk" -->
+<!-- /TMPL_LOOP name="column_constraints" -->
+              </para>
+<!-- TMPL_IF name="column_comment" -->
+              <para>
+                <!-- TMPL_VAR name="column_comment_dbk" -->
+              </para>
+<!-- /TMPL_IF name="column_comment" -->
+            </listitem>
+          </varlistentry>
+<!-- /TMPL_LOOP name="columns" -->
+        </variablelist>
+
+<!-- TMPL_LOOP name="constraints" -->
+<!-- TMPL_IF name="__FIRST__" -->
+        <variablelist>
+          <title>Constraints on <!-- TMPL_VAR name="table_dbk" --></title>
+<!-- /TMPL_IF name="__FIRST__" -->
+          <varlistentry>
+            <term><!-- TMPL_VAR name="constraint_name_dbk" --></term>
+            <listitem><para><!-- TMPL_VAR name="constraint_dbk" --></para></listitem>
+          </varlistentry>
+<!-- TMPL_IF name="__LAST__" -->
+        </variablelist>
+<!-- /TMPL_IF name="__LAST__" -->
+<!-- /TMPL_LOOP name="constraints" -->
+
+<!-- TMPL_LOOP name="indexes" -->
+<!-- TMPL_IF name="__FIRST__" -->
+        <variablelist>
+          <title>Indexes on <!-- TMPL_VAR name="table_dbk" --></title>
+<!-- /TMPL_IF name="__FIRST__" -->
+          <varlistentry>
+            <term><!-- TMPL_VAR name="index_name_dbk" --></term>
+            <listitem><para><!-- TMPL_VAR name="index_definition_dbk" --></para></listitem>
+          </varlistentry>
+<!-- TMPL_IF name="__LAST__" -->
+        </variablelist>
+<!-- /TMPL_IF name="__LAST__" -->
+<!-- /TMPL_LOOP name="indexes" -->
+
+<!-- TMPL_LOOP name="fk_schemas" -->
+<!-- TMPL_IF name="__FIRST__" -->
+        <itemizedlist>
+          <title>
+            Tables referencing <!-- TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="fk_schema_dbk" -->.<!-- /TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="fk_table_dbk" --> via Foreign Key Constraints
+          </title>
+<!-- /TMPL_IF name="__FIRST__" -->
+          <listitem>
+            <para>
+              <xref linkend="<!-- TMPL_VAR name="fk_sgmlid" -->"/>
+            </para>
+          </listitem>
+<!-- TMPL_IF name="__LAST__" -->
+        </itemizedlist>
+<!-- /TMPL_IF name="__LAST__" -->
+<!-- /TMPL_LOOP name="fk_schemas" -->
+
+<!-- TMPL_IF name="view_definition" -->
+        <figure>
+         <title>Definition of view <!-- TMPL_VAR name="table_dbk" --></title>
+         <programlisting><!-- TMPL_VAR name="view_definition_dbk" --></programlisting>
+        </figure>
+<!-- /TMPL_IF name="view_definition" -->
+<!-- TMPL_LOOP name="permissions" -->
+<!-- TMPL_IF name="__FIRST__" -->
+        <variablelist>
+          <title>Permissions on <!-- TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR ESCAPE="HTML" name="schema" -->.<!-- /TMPL_IF name="number_of_schemas" --><!-- TMPL_VAR name="table_dbk" --></title>
+<!-- /TMPL_IF name="__FIRST__" -->
+          <varlistentry>
+            <term><!-- TMPL_VAR name="user_dbk" --></term>
+            <listitem>
+              <para>
+                <simplelist type="inline">
+<!-- TMPL_IF name="select" -->
+                  <member>Select</member>
+<!-- /TMPL_IF name="select" -->
+<!-- TMPL_IF name="insert" -->
+                  <member>Insert</member>
+<!-- /TMPL_IF name="insert" -->
+<!-- TMPL_IF name="update" -->
+                  <member>Update</member>
+<!-- /TMPL_IF name="update" -->
+<!-- TMPL_IF name="delete" -->
+                  <member>Delete</member>
+<!-- /TMPL_IF name="delete" -->
+<!-- TMPL_IF name="rule" -->
+                  <member>Rule</member>
+<!-- /TMPL_IF name="rule" -->
+<!-- TMPL_IF name="references" -->
+                  <member>References</member>
+<!-- /TMPL_IF name="references" -->
+<!-- TMPL_IF name="trigger" -->
+                  <member>Trigger</member>
+<!-- /TMPL_IF name="trigger" -->
+                </simplelist>
+              </para>
+            </listitem>
+          </varlistentry>
+<!-- TMPL_IF name="__LAST__" -->
+        </variablelist>
+<!-- /TMPL_IF name="__LAST__" -->
+<!-- /TMPL_LOOP name="permissions" -->
+
+      </para>
+    </section>
+<!-- /TMPL_LOOP name="tables" -->
+
+<!-- TMPL_LOOP name="functions" -->
+<!-- Function <!-- TMPL_VAR NAME="function" --> -->
+    <section id="<!-- TMPL_VAR NAME="function_sgmlid" -->"
+             xreflabel="<!-- TMPL_VAR NAME="schema_dbk" --><!-- TMPL_VAR NAME="function_dbk"-->">
+      <title id="<!-- TMPL_VAR NAME="function_sgmlid" -->-title">
+       <!-- TMPL_VAR name="function_dbk" -->
+      </title>
+      <titleabbrev id="<!-- TMPL_VAR NAME="function_sgmlid" -->-titleabbrev">
+       <!-- TMPL_VAR name="function_dbk" -->
+      </titleabbrev>
+
+      <para>
+       <segmentedlist>
+        <title>Function Properties</title>
+        <?dbhtml list-presentation="list"?>
+        <segtitle>Language</segtitle>
+        <segtitle>Return Type</segtitle>
+        <seglistitem>
+         <seg><!-- TMPL_VAR ESCAPE="HTML" name="function_language" --></seg>
+         <seg><!-- TMPL_VAR ESCAPE="HTML" name="function_returns" --></seg>
+        </seglistitem>
+       </segmentedlist>
+       <!-- TMPL_VAR name="function_comment_dbk" -->
+        <programlisting><!-- TMPL_IF name="function_source" --><!-- TMPL_VAR ESCAPE="HTML" name="function_source" --><!-- /TMPL_IF name="function_source" --></programlisting>
+      </para>
+    </section>
+<!-- /TMPL_LOOP name="functions" -->
+  </chapter>
+<!-- /TMPL_LOOP name="schemas" -->
+</book>
+
diff --git a/zigzag.dia.tmpl b/zigzag.dia.tmpl
new file mode 100644 (file)
index 0000000..70327aa
--- /dev/null
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+  <dia:layer name="Background" visible="true">
+<!-- TMPL_LOOP name="schemas" -->
+<!-- TMPL_IF name="number_of_schemas" -->
+    <dia:group>
+<!-- /TMPL_IF name="number_of_schemas" -->
+<!-- TMPL_LOOP name="tables" -->
+    <dia:object type="UML - Class" version="0" id="O<!-- TMPL_VAR ESCAPE="HTML" name="object_id" -->">
+      <dia:attribute name="name">
+        <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="table" -->#</dia:string>
+      </dia:attribute>
+<!-- TMPL_IF name="number_of_schemas" -->
+      <dia:attribute name="stereotype">
+        <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="schema" -->#</dia:string>
+      </dia:attribute>
+<!-- /TMPL_IF name="number_of_schemas" -->
+      <dia:attribute name="abstract">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="suppress_attributes">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="suppress_operations">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="visible_attributes">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="attributes">
+<!-- TMPL_LOOP name="columns" -->
+        <dia:composite type="umlattribute">
+          <dia:attribute name="name">
+            <dia:string>#<!-- TMPL_IF name="column_primary_key" -->PK<!-- TMPL_ELSE name="column_primary_key" -->  <!-- /TMPL_IF name="column_primary_key" --><!-- TMPL_VAR ESCAPE="HTML" name="column" -->#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="type">
+            <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="column_type" -->#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="value">
+<!-- TMPL_IF name="column_default_short" -->
+            <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="column_default_short" -->#</dia:string>
+<!-- TMPL_ELSE name="column_default_short" -->
+            <dia:string/>
+<!-- /TMPL_IF name="column_default_short" -->
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="3"/>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+        </dia:composite>
+<!-- /TMPL_LOOP name="columns" -->
+      </dia:attribute>
+<!-- TMPL_IF name="constraints" -->
+      <dia:attribute name="visible_operations">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="operations">
+<!-- TMPL_LOOP name="constraints" -->
+        <dia:composite type="umloperation">
+          <dia:attribute name="name">
+            <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="constraint_name" -->#</dia:string>
+          </dia:attribute>
+          <dia:attribute name="visibility">
+            <dia:enum val="3"/>
+          </dia:attribute>
+          <dia:attribute name="abstract">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="class_scope">
+            <dia:boolean val="false"/>
+          </dia:attribute>
+          <dia:attribute name="parameters">
+            <dia:composite type="umlparameter">
+              <dia:attribute name="name">
+                <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="constraint_short" -->#</dia:string>
+              </dia:attribute>
+              <dia:attribute name="type">
+                <dia:string>##</dia:string>
+              </dia:attribute>
+              <dia:attribute name="value">
+                <dia:string/>
+              </dia:attribute>
+              <dia:attribute name="kind">
+                <dia:enum val="0"/>
+              </dia:attribute>
+            </dia:composite>
+          </dia:attribute>
+        </dia:composite>
+<!-- /TMPL_LOOP name="constraints" -->
+      </dia:attribute>
+<!-- TMPL_ELSE name="constraints" -->
+      <dia:attribute name="visible_operations">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="operations"/>
+<!-- /TMPL_IF name="constraints" -->
+      <dia:attribute name="template">
+        <dia:boolean val="false"/>
+      </dia:attribute>
+      <dia:attribute name="templates"/>
+    </dia:object>
+<!-- /TMPL_LOOP name="tables" -->
+<!-- TMPL_IF name="number_of_schemas" -->
+    </dia:group>
+<!-- /TMPL_IF name="number_of_schemas" -->
+<!-- /TMPL_LOOP name="schemas" -->
+<!-- TMPL_LOOP name="fk_links" -->
+    <dia:object type="UML - Dependency" version="0" id="O<!-- TMPL_VAR ESCAPE="HTML" name="object_id" -->">
+      <dia:attribute name="obj_pos">
+        <dia:point val="0.0,0.0"/>
+      </dia:attribute>
+       <dia:attribute name="obj_bb">
+        <dia:rectangle val="0.0,0.0;0.0,0.0"/>
+      </dia:attribute>
+      <dia:attribute name="orth_points">
+        <dia:point val="0.0,0.0"/>
+        <dia:point val="0.0,0.0"/>
+        <dia:point val="0.0,0.0"/>
+        <dia:point val="0.0,0.0"/>
+      </dia:attribute>
+      <dia:attribute name="orth_orient">
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+        <dia:enum val="0"/>
+      </dia:attribute>
+      <dia:attribute name="orth_autoroute">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:attribute name="name">
+        <dia:string>#<!-- TMPL_VAR ESCAPE="HTML" name="fk_link_name" -->#</dia:string>
+      </dia:attribute>
+      <dia:attribute name="stereotype">
+        <dia:string>##</dia:string>
+      </dia:attribute>
+      <dia:attribute name="draw_arrow">
+        <dia:boolean val="true"/>
+      </dia:attribute>
+      <dia:connections>
+        <dia:connection handle="0" to="O<!-- TMPL_VAR ESCAPE="HTML" name="handle0_to" -->" connection="<!-- TMPL_VAR ESCAPE="HTML" name="handle0_connection_dia" -->"/>
+        <dia:connection handle="1" to="O<!-- TMPL_VAR ESCAPE="HTML" name="handle1_to" -->" connection="<!-- TMPL_VAR ESCAPE="HTML" name="handle1_connection_dia" -->"/>
+      </dia:connections>
+    </dia:object>
+<!-- /TMPL_LOOP name="fk_links" -->
+  </dia:layer>
+</dia:diagram>