--- /dev/null
+.*.swp
+ChangeLog.bak
+postgresql_autodoc
+config.status
+config.mk
+config.log
--- /dev/null
+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.
+
--- /dev/null
+# $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)
--- /dev/null
+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@
--- /dev/null
+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
+])
--- /dev/null
+<?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>
--- /dev/null
+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">
+}
--- /dev/null
+<!-- $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> </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> </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> </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>♦</center><!-- /TMPL_IF name="select" --></td>
+ <td><!-- TMPL_IF name="insert" --><center>♦</center><!-- /TMPL_IF name="insert" --></td>
+ <td><!-- TMPL_IF name="update" --><center>♦</center><!-- /TMPL_IF name="update" --></td>
+ <td><!-- TMPL_IF name="delete" --><center>♦</center><!-- /TMPL_IF name="delete" --></td>
+ <td><!-- TMPL_IF name="references" --><center>♦</center><!-- /TMPL_IF name="references" --></td>
+ <td><!-- TMPL_IF name="rule" --><center>♦</center><!-- /TMPL_IF name="rule" --></td>
+ <td><!-- TMPL_IF name="trigger" --><center>♦</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>
--- /dev/null
+#!/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
--- /dev/null
+#!/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);)/&/g;
+ $string =~ s/</</g;
+ $string =~ s/>/>/g;
+ $string =~ s/'/'/g;
+ $string =~ s/"/"/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;
+}
--- /dev/null
+--
+-- $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;
--- /dev/null
+<!-- $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>
+
--- /dev/null
+<?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>