=head1 NAME

SQL::SyntaxModel::DataDictionary - Describe a database suitable for storing SQL::SyntaxModels.

=head1 COPYRIGHT AND LICENSE

This file is part of the SQL::SyntaxModel library (libSQLSM).

SQL::SyntaxModel is Copyright (c) 1999-2003, Darren R. Duncan.  All rights
reserved.  Address comments, suggestions, and bug reports to
B<perl@DarrenDuncan.net>, or visit "http://www.DarrenDuncan.net" for more
information.

SQL::SyntaxModel is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License (GPL) version 2 as published
by the Free Software Foundation (http://www.fsf.org/).  You should have
received a copy of the GPL as part of the SQL::SyntaxModel distribution, in the
file named "LICENSE"; if not, write to the Free Software Foundation, Inc., 59
Temple Place, Suite 330, Boston, MA 02111-1307 USA.

Any versions of SQL::SyntaxModel that you modify and distribute must carry
prominent notices stating that you changed the files and the date of any
changes, in addition to preserving this original copyright notice and other
credits. SQL::SyntaxModel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GPL for more details.

Linking SQL::SyntaxModel statically or dynamically with other modules is making
a combined work based on SQL::SyntaxModel.  Thus, the terms and conditions of
the GPL cover the whole combination.

As a special exception, the copyright holders of SQL::SyntaxModel give you
permission to link SQL::SyntaxModel with independent modules that are
interfaces to or implementations of databases, regardless of the license terms
of these independent modules, and to copy and distribute the resulting combined
work under terms of your choice, provided that every copy of the combined work
is accompanied by a complete copy of the source code of SQL::SyntaxModel (the
version of SQL::SyntaxModel used to produce the combined work), being
distributed under the terms of the GPL plus this exception.  An independent
module is a module which is not derived from or based on SQL::SyntaxModel, and
which is fully useable when not linked to SQL::SyntaxModel in any form.

Note that people who make modified versions of SQL::SyntaxModel are not
obligated to grant this special exception for their modified versions; it is
their choice whether to do so.  The GPL gives permission to release a modified
version without this exception; this exception also makes it possible to
release a modified version which carries forward this exception.

While it is by no means required, the copyright holders of SQL::SyntaxModel
would appreciate being informed any time you create a modified version of
SQL::SyntaxModel that you are willing to distribute, because that is a
practical way of suggesting improvements to the standard version.

=head1 DESCRIPTION

All concepts in a SQL::SyntaxModel can be represented by a data dictionary.
Such a data dictionary can be a linked in-memory set of objects (or serialized
version thereof), or they can be represented by records in database tables
having specific columns and constraints.  This documentation will attempt to
explain the components of a SQL::SyntaxModel data dictionary and how they
relate.  Since SQL::SyntaxModel doesn't actually use any database tables
internally, and that it is your application (or other third party modules)
which would map such database tables to SQL::SyntaxModel objects, you are free
to modify this schema to your liking. However, it is recommended that you
mainly just add columns, such as for adding user visible text descriptions of
each record, rather than changing or removing the suggested columns.

=head1 STRUCTURE

Here is a set of diagrams that show visually how the various tables relate.  The 
structure of the individual tables themselves are explained in other sections 
further below.  All of the relationships are either many-to-one or one to one; 
most are optional, but for simplicity all lines are solid below.

Every table shown here has a single-column primary key so that it is easy to
convert their records into in-memory structs/objects, and their relationships
into normal scalar references each pointing from one struct to another. 
Likewise, the records can be easily converted into XML nodes, where each node
has a single-value unique id, and individual attributes in one XML node can 
refer to such on another.  There are two main kinds of tables.

The tables whose names start with "cct_" have program-defined values and are
not meant to be changed; they are "constant".  Each of those tables represents
an enumeration, and their primary keys are all short strings of lowercased
latin letters and sometimes numbers.  All of these primary keys are on a field
named 'code'.  It is quite possible that these don't need to exist as tables at
all, if the database in use supports column constraints by enumerated list,
rather than just by foreign key.

All of the other tables, which do not start with "cct_", are "normal" tables,
and you can put all of your own records in them.  Each of these tables has a
non-content-descriptive integer for a primary key, which is an intentional
choice; this makes it easy for you to change values which would otherwise be
part of your primary key, without having to worry about updating other copies
to preserve relational integrity; it also saves on memory usage.  All of these
primary keys are on a field named 'id'.

=head2 Data Types

	cct_basic_data_type
	    |
	   /|\
	data_type=>---+---cct_str_latin_case
	   \|/        |
	    |         |
	cct_str_enc   cct_datetime_calendar

=head2 Databases and Name Spaces

	   user
	   \|/
	    |
	 database   view(named)
	    |       \|/
	   /|\       |
	namespace----+-<=block(named)
	    |        |
	   /|\      /|\
	  table   sequence

=head2 Tables

	 trigger      data_type
	   \|/            |
	    |            /|\
	  table------<=table_col=>----sequence
	    |(2)          |(2)
	   /|\           /|\
	table_ind--<=table_ind_col
	   \|/
	    |
	cct_index_type

=head2 Views

	 data_type   cct_view_type
	     |           |
	    /|\         /|\                     cct_view_part;cct_basic_expr_type;view;
	 view_col=>----view  cct_rs_merge_type  cct_standard_func;block(user_func)
	     |           |     |                   |
	    /|\         /|\   /|\                 /|\
	view_col_def=>--view_rowset---<=view_part_def;=>---view_src_col
	    \|/             \|/         view_hierarchy         |(2)
	     |               |                                /|\
	view_src_col=>----view_src----<=view_join---<=view_join_col
	                    \|/   (2)     |
	                     |           /|\
	                 table;view  cct_rs_join_type

=head2 Sequences

	sequence

=head2 Blocks

	 table   cct_block_type   data_type
	   |            |             |
	  /|\          /|\           /|\
	trigger-------block-----<=block_var=>---cct_basic_var_type
	                |   -------|  |
	               /|\ /|\       /|\
	            block_stmt--<=block_expr=>---cct_basic_expr_type;view;
	            \|/    \|/                   cct_standard_func;block(user_func)
	             |      ----------|
	cct_basic_stmt_type   cct_standard_proc

=head2 Users

	user---<=privilege

=head2 Applications, Commands and Results

	cct_command_type   command_var (bind variables passed from application)
	      |                \|/
	     /|\ |---------------
	   command=>---application
	    |  \|/ (a command can be executed multiple times for multiple results)
	   /|\  |  (a result can be used as input or context for multiple commands)
	   result
	     \|/
	      |
	cct_result_type

=head1 CONSTANT CODE TABLES

These tables correspond to basic concepts that are hard-coded into SQL::SyntaxModel and
they are intended to be read-only.  The table contents are meant for two main
uses, one being for foreign key constraints on enumerated type columns in other
tables, and the other being for a source of picklist values on forms that users
define SQL::SyntaxModels with.

The values in these tables are stored in code by the SQL::SyntaxModel::Codes
class.  You can get the values for these tables from that class, and don't have
to code them yourself.  The other SQL::SyntaxModel classes use the Codes class
internally for when they need to know this information, and hence are not
susceptible to security risks from someone altering the following tables in the
database.

=head2 cct_basic_var_type

This table enumerates the basic variable or container types that block
variables or arguments or return types can be, or which functions can
take or return, or that intermediate values for expressions are stored
in.  Some types can contain single distinct values, such as scalars, and some 
can have multiple distinct values, such as records.  The type of a table column 
is usually just one value.

Column List:

	code - str,req - name of the base data type
	is_ref - bool,req - if true, var stores reference to var type otherwise desc here
	is_scalar - bool,req - true when variable can only hold a single distinct value at once
	is_record - bool,req - true when var holds multiple distinct values, each keyed by a str/name
	is_array - bool,req - true when var holds ordered list of sca/rec elems, accessible in any order
	is_cursor - bool,req - true when var holds a SQL-select definition; rec only acc sequentially
	can_use_in_table - bool,req - true when may be used for a table column

Index List:

	primary - unique - [code]

Record List:

	|code  |rf|sc|re|ar|cu|ta|
	|------|--|--|--|--|--|--|
	|scalar|0 |1 |0 |0 |0 |1 | - a single value
	|record|0 |0 |1 |0 |0 |0 | - a list of scalars (can differ in type), keyed by a string/column-name
	|array |0 |0 |0 |1 |0 |0 | - an ordered list of elements/records, all same type, can be read in any order
	|cursor|0 |0 |0 |0 |1 |0 | - an ordered list of elements/records, can only/usually be read in sequential order
	|ref   |1 |0 |0 |1 |0 |1 | - reference to a record, such as in object-relational databases

=head2 cct_basic_data_type

This table enumerates the basic scalar data value types that table
columns or view columns or block variables or arguments can be.

Column List:

	code - str,req - name of the base data type
	size_undefined - bool,req - true when user can't customize space used by data type
	size_is_bytes - bool,req - true when can customize type to a size measured in bytes
	size_is_chars - bool,req - true when can customize type to a size measured in chars
	size_is_digits - bool,req - true when can customize type to a size measured in digits
	typ_min_size - uint - suggested typical minimum size to customize to (in any above unit)
	typ_max_size - uint - suggested typical maximum size to customize to (in any above unit)

Index List:

	primary - unique - [code]

Record List:

	|code    |un|by|ch|di|min|       max|
	|--------|--|--|--|--|---|----------|
	|bin     |0 |1 |0 |0 |  1|4294967295| - stores anything as binary data
	|str     |0 |1 |1 |0 |  1|4294967295| - stores character data
	|num     |0 |1 |1 |1 |  1|       255| - a number, either integral or fractional
	|bool    |1 |0 |0 |0 |   |          | - a boolean; only 2 values of false or true
	|datetime|1 |0 |0 |0 |   |          | - a date or time or both (may be split up)

	Geographical types are expected to be added as well.  Maybe enumerated or set types also.

=head2 cct_str_enc

This table enumerates the set of known character string encodings that can be
used by character data, with Unicode being the recommended one to use when
possible, and with Ascii being the most common legacy encoding.  Encodings are 
only applicable to data which is measured in characters.

Column List:

	code - str,req - name of the character encoding
	is_var_len_enc - bool,req - true when char encoding is variable length, false when fixed length
	min_bytes_per_char - uint,req - minimum num bytes used to store each character; typically 1
	max_bytes_per_char - uint,req - maximum bytes per char, same as minimum when fixed length
	has_latin_chars - bool,req - true when operations like upper/lowercase have any meaning

Index List:

	primary - unique - [code]

Record List:

	|cod|vle|nbpc|xbpc|lat|
	|---|---|----|----|---|
	|u8 |1  |   1|   6|1  | - UTF-8 (always byte-order; no big/little endian; typ 1 byte or 3 byte)
	|u16|1  |   2|  ?4|1  | - UTF-16 (has big/little endian versions)
	|u32|0  |   4|   4|1  | - UTF-32 (has big/little endian versions)
	|asc|0  |   1|   1|1  | - ascii
	|ebs|0  |   1|   1|1  | - ebsdic

	Note that some of these examples may be wrong for practical use and be changed later.

=head2 cct_str_latin_case

This table enumerates a set of options for normalizing the case of latin
characters in strings, so that they can be matched reliably with case-sensitive
(normal) string operations, even if they are conceptually case-insensitive.
When this attribute is used with table columns, for example, it may cause data
to be upper/lowercased prior to insertion, losing knowledge of the old case.

One place that this is helpful is when dealing with database systems that are
both case-insensitive and case-sensitive with the same data depending on how
you access it.  For example, Oracle table and column names when declared as
barewords, the normal SQL way, will match in a case-insensitive fashion with
other barewords, but will match case-sensitive full-uppercase only when
matching either with double-quoted strings or when looking in the special
'user_tables' et al Oracle views.  (As if that paragraph is helpful?)

Note that this table's function may be expanded later (with rename) to handle 
things like whitespace trimming et al, or maybe it won't.

Column List:

	code - str,req - name of the latin case normalization type
	uc_latin - bool,req - uppercase everything prior to writing, no change on reading
	lc_latin - bool,req - lowercase everything prior to writing, no change on reading

Index List:

	primary - unique - [code]

Record List:

	|co|uc|lc|
	|--|--|--|
	|pr|0 |0 | - preserve - everything is case-sensitive, no transformation is done (default)
	|uc|1 |0 | - toupper  - uppercase everything prior to writing, no change on reading
	|lc|0 |1 | - tolower  - lowercase everything prior to writing, no change on reading

=head2 cct_datetime_calendar

This table enumerates the set of known calendars which a date and time can be
relative to and counted with.  For each, year zero could be at a different
event, and other differences like what months or other yearly divisions there 
are would also distinguish the calendars.  Use "absolute" if you don't want to 
pick any calendar in particular.

Column List:

	code - str,req - name of the calendar

Index List:

	primary - unique - [code]

Record List:

	|cod|
	|---|
	|abs| - "absolute", for non-calendar-specific dates and times
	|gre| - the Gregorian calendar
	|jul| - the Julian/Roman calendar
	|chi| - the Chinese calendar
	|heb| - the Hebrew calendar
	|isl| - the Islamic calendar
	|jpn| - the Japanese calendar

	Note that some of these examples may be wrong for practical use and be changed later.

=head2 cct_index_type

This table enumerates the basic index types that database tables can have
applied to them; each instance of these can apply to multiple columns at once.  
All indexes are intended to make accessing table data faster, but some also 
will impose constraints on what data can be put in the columns.

Column List:

	code - str,req - name of the table index type
	is_unique - bool,req - true if index imposes a unique key constraint
	is_foreign - bool,req - true if index imposes a foreign key constraint

Index List:

	primary - unique - [code]

Record List:

	|code    |uk|fk|
	|--------|--|--|
	|noconstr|0 |0 | - index is simply to make db faster, no constraints are imposed
	|unique  |1 |0 | - index imposes a unique key constraint on a set of columns
	|foreign |0 |1 | - index imposes a many-to-one foreign key constraint on a set of columns
	|uforeign|1 |1 | - index imposes a one-to-one foreign key (assuming target is a unique key)

=head2 cct_view_type

This table enumerates the basic types that a view can be, since SQL::SyntaxModel "views"
have a broader meaning than in classic SQL.  There are 4 main types.

First, the "classic" type of view is stored in a database schema as a schema
object, and it has a name, like a table; these views can not usually have
variables in their definitions, and so will always return the same thing if
their source tables are unchanged.

The second type of "view" corresponds to a SQL "select" statement which an
application executes against a database, but it is not part of the database
schema, and do not have names; these views can have variables anywhere in their
definitions.

The third type of "view" corresponds to a "cursor" definition in a SQL
"procedure"; while these do have names, they are only known by those names
inside a SQL procedure or other SQL block; they can usually take variables.

The fourth type of "view" corresponds to a "subquery" or "subselect" declared
inside any other view (types 1-4); these never have names (they are "part" of
the parent view), except for when they are in the SQL-From, in which case they
can have aliases local to the parent view, and they can take variables if and
only if their parent views can.

Column List:

	code - str,req - name of the view type
	inherit_props - bool,req - true when view declared inside another, inherits parent attrs
	can_have_vars - bool,req - true when view can or might have variables

Index List:

	primary - unique - [code]

Record List:

	|code  |inh|var|
	|------|---|---|
	|object|0  |0  | - a named schema object, the classic "view"
	|caller|0  |1  | - declared by a caller application and doesn't persist
	|cursor|0  |1  | - a cursor declared inside a block
	|inside|1  |1  | - a subquery inside another view

=head2 cct_rs_merge_type

This table enumerates the standard ways that multiple compatible view row sets
can be merged into a single row set, where all of the input row sets have the
same set of columns as the the output row set, and each single output row
matches a distinct input row.  A union is the most common such operation.  

Column List:

	code - str,req - name of the view row set merge type
	max_inputs - uint,req - number of input sets that this set merge operator can take; 0 = unlimited
	keeps_all - bool,req - true if all input rows are always returned, false if some may not be
	is_unique - bool,req - true if all returned rows are distinct, false if duplicates may occur

Index List:

	primary - unique - [code]

Record List:

	|cod|max|all|unq|
	|---|---|---|---|
	|dis|  1|0  |1  | - distinct - all distinct rows from a single input set, like a "select distinct ..."
	|all|  0|1  |0  | - all - all input rows are returned, like a "union all" (the default)
	|uni|  0|0  |1  | - union - all distinct rows that are each in at least one input set
	|int|  0|0  |1  | - intersect - all distinct rows that are each in every input set
	|exc|  0|0  |1  | - exclusive - all distinct rows that are each in exactly one input set (exclusive or)
	|min| ?2|0  |1  | - minus - all distinct rows from one input set that are not in the others

=head2 cct_rs_join_type

This table enumerates the standard ways that columns from two tables or views
can be joined side by side into a single row set, where all values in each
output column are from exactly one input, and values in columns from separate
sources are aligned into common rows on related row values.  This is the most
common way of "relating" data in relational databases.

Column List:

	code - str,req - name of the table or view join type
	outer_join - bool,req - when true all rows from one source kept even if not matched in the other

Index List:

	primary - unique - [code]

Record List:

	|code |out|
	|-----|---|
	|equal|  0| - an equal-join; only rows with related entries in both sources are kept
	|left |  1| - a left-join; all rows from first source kept even if not matched in second

	A right-join may also be added, but its value is dubious at the moment.  
	Also, there is no concept of a "natural" join at this level of activity.
	Full outer join may also be added.

=head2 cct_view_part

This table enumerates the standard parts of a view definition which exist in 
the SQL following the "from" part.  See "view_part_def" for an explanation.

Column List:

	code - str,req - name of the view part

Index List:

	primary - unique - [code]

Record List:

	|code |
	|-----|
	|where| - the SQL "where" part
	|group| - the SQL "group by" part
	|havin| - the SQL "having" part
	|order| - the SQL "order by" part

=head2 cct_basic_expr_type

This table enumerates the basic expression types that views or blocks can contain.  An 
expression is conceptually like a function which takes zero or more arguments and 
returns a value; each argument is also an expression.  This is recursive until the 
expression is one that either takes no arguments (includes constant values or names of 
variables or columns).

Column List:

	code - str,req - name of the basic expression type
	is_lit - bool,req - true when expression is a literal value such as a quoted string or number
	is_var - bool,req - true when expression is a variable name, such as in a block or app call
	is_col - bool,req - true when expression is a column name, such as in a view, or cursor in block
	is_view - bool,req - true when expression is a view declaration, such as a subquery or cursor def
	is_sfunc - bool,req - true when expression is a call to a standard built-in function
	is_ufunc - bool,req - true when expression is a call to a user-defined stored function (block)
	can_have_args - bool,req - true when expression might have child expressions

Index List:

	primary - unique - [code]

Record List:

	|code |li|va|co|vw|sf|uf|ha|
	|-----|--|--|--|--|--|--|--|
	|lit  |1 |0 |0 |0 |0 |0 |0 | - a literal value, such as number or string
	|var  |0 |1 |0 |0 |0 |0 |0 | - a variable name, such as stored block or app bind var
	|col  |0 |0 |1 |0 |0 |0 |0 | - a column name, such as in a view or cursor in block
	|view |0 |0 |0 |1 |0 |0 |0 | - a view declaration, such as a subquery or a cursor
	|sfunc|0 |0 |0 |0 |1 |0 |1 | - a standard built-in function; one of cct_standard_func
	|ufunc|0 |0 |0 |0 |0 |1 |1 | - a user defined stored function (block)

=head2 cct_standard_func

This table enumerates a list of the standard built in functions that can be used
as parts of view definitions or code blocks like stored procedures or functions
or triggers.

Column List:

	code - str,req - name of the standard function
	can_have_args - bool,req - true when function can have any arguments
	req_min_args - uint,req - minimum num of args function must have, whether unlimited or not
	req_arg_mult - uint - all args over minimum must be supplied in this multiple (default=1)
	unlim_args - bool,req - true when function can take any number of arguments over minimum
	req_max_args - uint - count of maximum args function can have when not unlimited
	can_use_in_column - bool,req - true when func type may be used in view column def, [having/order]
	can_use_in_filter - bool,req - true when func type may be used in view filter (where)
	can_use_in_block - bool,req - true when func type may be used in a block (eg: stored proc)
	is_aggregate_func - bool,req - true when is an aggregate func (a grouping func, like 'count')
	data_type - enum - basic data type that function returns

Index List:

	primary - unique - [code]
	fk_data_type - foreign - [data_type]->[cct_basic_data_type]:[code]

Record List:

	|code   |ha|mn|ml|ul|mx|cc|cf|cb|ag|datatype|
	|-------|--|--|--|--|--|--|--|--|--|--------|
	|to_str |1 | 1|  |0 | 1|1 |1 |1 |0 |str     | - cast arg as string (might take more args)
	|to_num |1 | 1|  |0 | 1|1 |1 |1 |0 |num     | - cast arg as numeric (might take more args)
	|to_int |1 | 1|  |0 | 1|1 |1 |1 |0 |num     | - cast arg as integer (might take more args)
	|to_bool|1 | 1|  |0 | 1|1 |1 |1 |0 |bool    | - cast arg as boolean (might take more args)
	|to_date|1 | 1|  |0 | 1|1 |1 |1 |0 |datetime| - cast arg as datetime (might take more args)
	|not    |1 | 1|  |0 | 1|1 |1 |1 |0 |bool    | - a logical 'not', true iif lone arg is false
	|and    |1 | 2| 1|1 |  |1 |1 |1 |0 |bool    | - a logical 'and', true iif every arg is true
	|or     |1 | 2| 1|1 |  |1 |1 |1 |0 |bool    | - a logical 'or', true iif at least one arg is true
	|xor    |1 | 2| 1|1 |  |1 |1 |1 |0 |bool    | - a logical 'xor', true iif 1+ arg true and 1+ arg false
	|eq     |1 | 2|  |0 | 2|1 |1 |1 |0 |bool    | - true if both args are equal (both args cast same tp)
	|ne     |1 | 2|  |0 | 2|1 |1 |1 |0 |bool    | - true if both args are unequal (when same data type)
	|lt     |1 | 2|  |0 | 2|1 |1 |1 |0 |bool    | - true if first arg is less than second
	|gt     |1 | 2|  |0 | 2|1 |1 |1 |0 |bool    | - true if first arg is greater than second
	|le     |1 | 2|  |0 | 2|1 |1 |1 |0 |bool    | - true if first arg is less than or equal to second
	|ge     |1 | 2|  |0 | 2|1 |1 |1 |0 |bool    | - true if first arg is greater than or equal to second
	|is_null|1 | 1|  |0 | 1|1 |1 |1 |0 |bool    | - true if only arg is a null value
	|nvl    |1 | 2|  |0 | 2|1 |1 |1 |0 |        | - returns arg 1 if it is not null, else arg 2
	|switch |1 | 2| 2|1 |  |1 |1 |1 |0 |        | - a logical switch-case expr (like Oracle 'decode')
	|like   |1 | 2| 1|0 | 4|1 |1 |1 |0 |bool    | - true if first arg contains second; args 3,4 are flags
	|add    |1 | 2| 1|1 |  |1 |1 |1 |0 |num     | - result of adding all args as numbers
	|sub    |1 | 2| 1|1 |  |1 |1 |1 |0 |num     | - result of subtracting all subsequent args from first
	|mul    |1 | 2| 1|1 |  |1 |1 |1 |0 |num     | - result of multiplying all arguments
	|div    |1 | 2|  |0 | 2|1 |1 |1 |0 |num     | - result of dividing first argument by second
	|divi   |1 | 2|  |0 | 2|1 |1 |1 |0 |num     | - integral division of first arg by second
	|mod    |1 | 2|  |0 | 2|1 |1 |1 |0 |num     | - modulus of integral division of first arg by second
	|round  |1 | 1| 1|0 | 2|1 |1 |1 |0 |num     | - rounds first arg to N dec places; N is second arg or 0
	|exp    |1 | 2| 1|0 | 2|1 |1 |1 |0 |num     | - raises first arg to the power of the second
	|log    |1 | 2| 1|0 | 2|1 |1 |1 |0 |num     | - logarithm of the first arg on the base of second
	|min    |1 | 1| 1|1 |  |1 |1 |1 |0 |num     | - minimum arg value of all arguments
	|max    |1 | 1| 1|1 |  |1 |1 |1 |0 |num     | - maximum arg value of all arguments
	|avg    |1 | 1| 1|1 |  |1 |1 |1 |0 |num     | - average value of all arguments
	|sconcat|1 | 1| 1|1 |  |1 |1 |1 |0 |str     | - str concat of all arguments
	|slength|1 | 1|  |0 | 1|1 |1 |1 |0 |num     | - length of input string in characters
	|sindex |1 | 2| 1|0 | 3|1 |1 |1 |0 |num     | - pos in arg 1 of arg 2 if present, start at arg 3
	|substr |1 | 2| 1|0 | 3|1 |1 |1 |0 |str     | - substr in arg 1 starting pos arg 2 of length arg 3
	|srepeat|1 | 1| 1|0 | 2|1 |1 |1 |0 |str     | - str concat arg 1 to self repeated by arg 2 instances
	|strim  |1 | 1|  |0 | 1|1 |1 |1 |0 |str     | - trims leading and trailing whitespace from arg 1
	|spad   |1 | 2| 1|0 | 3|1 |1 |1 |0 |str     | - lengthens arg 1 to length of arg 2 using arg 3 or space
	|spadl  |1 | 2| 1|0 | 3|1 |1 |1 |0 |str     | - like spad but add filler on left rather than right
	|lc     |1 | 1|  |0 | 1|1 |1 |1 |0 |str     | - lowercases latin chars in a string
	|uc     |1 | 1|  |0 | 1|1 |1 |1 |0 |str     | - uppercases latin chars in a string
	|gcount |0 | 0|  |0 | 0|1 |0 |0 |1 |num     | - count of rows a view/cursor can see
	|gmin   |1 | 1|  |0 | 1|1 |0 |0 |1 |num     | - minimum of values in all records in one view col
	|gmax   |1 | 1|  |0 | 1|1 |0 |0 |1 |num     | - maximum of values in all records in one view col
	|gsum   |1 | 1|  |0 | 1|1 |0 |0 |1 |num     | - sum of values in all records in one view col
	|gavg   |1 | 1|  |0 | 1|1 |0 |0 |1 |num     | - average of values in all records in one view col
	|gconcat|1 | 1|  |0 | 1|1 |0 |0 |1 |str     | - str concat of values in all records in one view col
	|gevery |1 | 1|  |0 | 1|1 |0 |0 |1 |bool    | - is true when all rec values in one col are true
	|gany   |1 | 1|  |0 | 1|1 |0 |0 |1 |bool    | - is true when at least one rec value in one col is true
	|gsome  |1 | 1|  |0 | 1|1 |0 |0 |1 |bool    | - is true when some rec values are true
	|crowid |0 | 0|  |0 | 0|1 |0 |0 |0 |str     | - unique database-generated row id of returned row (=rowid?)
	|crownum|0 | 0|  |0 | 0|1 |0 |0 |0 |num     | - row number of returned row, before sorting (eg:Oracle)
	|clevel |0 | 0|  |0 | 0|1 |0 |0 |0 |num     | - when using st-wi-cn-by, what hierarchy level row is in (eg:Oracle)

	Note that the function list is incomplete and will grow over time.  It does not currently 
	mention functions for working with view/cursor subqueries, such as "in" (field in subquery), 
	and also doesn't include any list operators, such as for comparing a list of field names to 
	a subquery that returns multiple columns (as I suspect MySQL 4.1 supports).

=head2 cct_block_type

This table enumerates the basic types that a blocks can be, since SQL::SyntaxModel
"blocks" are generic enough that each of the following can be represented by
them: stored procedures and functions, triggers, and packages containing stored
procedures and functions; all of the previous can also have nested stored
procedures and functions; all of the previous can have nested un-named blocks
as well.  

All block types (except packages?) can incorporate a series of commands plus
conditionals or iterators, and all kinds can declare or use local variables,
and they can all contain other blocks of certain types.  As such, blocks
arranged in a hierarchy of parents and children, where a root block is one that
is not contained in another.  All block types can take arguments of some sort,
but your choice of type can severely limit what kinds of arguments you can
take.  Only some block types, functions mainly, can return a value.  Only some
block types have names.

Column List:

	code - str,req - name of the block type
	is_unnamed - bool,req - true when block has no name; it is a scope inside a larger block
	has_ret_val - bool,req - true when block is like a function and should return a value
	is_package - bool,req - true when child blocks are publically visible in schema
	is_trigger - bool,req - true when block is the root of a trigger on a table

Index List:

	primary - unique - [code]

Record List:

	|code|unn|ret|pkg|trg|
	|----|---|---|---|---|
	|pack|0  |0  |1  |0  | - an Oracle package; a namespace for related funcs and procs
	|trig|0  |0  |0  |1  | - a trigger on a table
	|proc|0  |0  |0  |0  | - a named stored procedure, plain or nested or in package
	|func|0  |1  |0  |0  | - a named stored function, plain or nested or in package
	|loop|1  |0  |0  |0  | - a loop/iterator context inside a block, such as a 'foreach'
	|cond|1  |0  |0  |0  | - a conditional context inside a block, such as an 'if'

	This list is probably missing some items.

=head2 cct_basic_stmt_type

This table enumerates the basic statement types that blocks can contain.  
Examples of statements are calls to stored procedures or some kinds of program 
logic control operations or value assignment operations.

Column List:

	code - str,req - name of the basic statement type
	is_sproc - bool,req - true when statement is a procedure call to a standard procedure
	is_uproc - bool,req - true when statement is a procedure call to a user-defined procedure
	is_assign - bool,req - true when statement involves assigning an expression value to a variable
	is_logic - bool,req - true when stmt is logic control like if/else or return or other

Index List:

	primary - unique - [code]

Record List:

	|code |sp|up|as|lo|
	|-----|--|--|--|--|
	|sproc|1 |0 |0 |0 | - a call to a standard built-in procedure; one of cct_standard_proc
	|uproc|0 |1 |0 |0 | - a call to a user defined stored procedure (block)
	|assig|0 |0 |1 |0 | - an assignment of an expression value to a variable
	|logic|0 |0 |0 |1 | - some control-flow logic operation ...

	To add: any view related operations like select/insert/update/delete.
	Where allowed, also to add user related operations or commit/rollback, etc.

=head2 cct_standard_proc

This table enumerates a list of the standard built in procedures that can be
called from blocks.

Column List:

	code - str,req - name of the standard function
	can_have_args - bool,req - true when function can have any arguments
	req_min_args - uint,req - minimum num of args function must have, whether unlimited or not
	req_arg_mult - uint - all args over minimum must be supplied in this multiple (default=1)
	unlim_args - bool,req - true when function can take any number of arguments over minimum
	req_max_args - uint - count of maximum args function can have when not unlimited

Index List:

	primary - unique - [code]

Record List:

	|code   |ha|mn|ml|ul|mx|
	|-------|--|--|--|--|--|
	|assign |1 | 2|  |0 | 2| - an assignment to a variable of the result of an expression

	line types: block,assignment,call,return,throw,declare-cursor,use-cursor

	block types: plain,throw,try,catch,if,elseif,else,switch,case,otherwise,foreach,
	for,while,until,map,grep,function,procedure,trigger,regexp

=head2 cct_command_type

This table enumerates the basic types of SQL::SyntaxModel Commands that an application 
can execute against a database or other Result context.  Note that in many cases 
"db" can mean either "database" or "data source"; "ds" may be used instead.

Column List:

	code - str,req - name of the command type
	can_rd_db - bool,req - true when command may open/close db connection or confirm its existence
	can_wr_db - bool,req - true when command may create/delete/move/copy db (what about expl save?)
	can_rd_user - bool,req - true when command may confirm presence/details of database users
	can_wr_user - bool,req - true when command may create/remove users or alter privileges
	can_rd_sch - bool,req - true when command may confirm presence/details of table/view/block
	can_wr_sch - bool,req - true when command may create/alter/delete tables/views/blocks/etc
	can_rd_rec - bool,req - true when command may fetch/count table records, by any means
	can_wr_rec - bool,req - true when command may insert or update or delete table records

Index List:

	primary - unique - [code]

Record List:

	|code        |rd|wd|ru|wu|rs|ws|rr|wr|
	|------------|--|--|--|--|--|--|--|--|
	|db_list     |1 |0 |0 |0 |0 |0 |0 |0 | - fetches a list of auto-detectable database instances
	|db_info     |1 |0 |0 |0 |0 |0 |0 |0 | - fetches some detailed info about a database instance
	|db_verify   |1 |0 |0 |0 |0 |0 |0 |0 | - compares a provided db spec to an actual database
	|db_open     |1 |0 |0 |0 |0 |0 |0 |0 | - opens a connection between app and a database instance
	|db_close    |1 |0 |0 |0 |0 |0 |0 |0 | - closes a connection between app and a database instance
	|db_ping     |1 |0 |0 |0 |0 |0 |0 |0 | - verifies that a db connection is still open
	|db_create   |0 |1 |0 |0 |0 |0 |0 |0 | - creates a new database instance
	|db_delete   |0 |1 |0 |0 |0 |0 |0 |0 | - deletes a database instance
	|db_clone    |1 |1 |0 |0 |0 |0 |0 |0 | - makes a clone of a db instance in another storage loc
	|db_move     |1 |1 |0 |0 |0 |0 |0 |0 | - moves a db inst from one storage location to another
	|user_list   |0 |0 |1 |0 |0 |0 |0 |0 | - fetches a list of users in open db instance
	|user_info   |0 |0 |1 |0 |0 |0 |0 |0 | - fetches some detailed info about a database user
	|user_verify |0 |0 |1 |0 |0 |0 |0 |0 | - compares a provided user spec to an actual user
	|user_create |0 |0 |0 |1 |0 |0 |0 |0 | - creates new db user one can auth db_open with (if privs)
	|user_delete |0 |0 |0 |1 |0 |0 |0 |0 | - deletes db user (as well as all schema it owns, if applic)
	|user_clone  |0 |0 |1 |1 |0 |0 |0 |0 | - creates a clone of an existing user with different name
	|user_update |0 |0 |0 |1 |0 |0 |0 |0 | - alters some details for a database user
	|user_grant  |0 |0 |0 |1 |0 |0 |0 |0 | - grants a db privilege to a db user
	|user_revoke |0 |0 |0 |1 |0 |0 |0 |0 | - revokes a db privilege from a db user
	|table_list  |0 |0 |0 |0 |1 |0 |0 |0 | - fetches a list of tables in schema of open db instance
	|table_info  |0 |0 |0 |0 |1 |0 |0 |0 | - fetches some detailed info about a database instance
	|table_verify|0 |0 |0 |0 |1 |0 |0 |0 | - compares a provided table spec to an actual table
	|table_create|0 |0 |0 |0 |0 |1 |0 |0 | - creates a new table in schema of open db inst
	|table_delete|0 |0 |0 |0 |0 |1 |0 |0 | - deletes an existing table in open db inst (if it can)
	|table_clone |0 |0 |0 |0 |1 |1 |0 |0 | - creates a clone of an existing table with different name
	|table_update|0 |0 |0 |0 |0 |1 |0 |0 | - alters schema for an existing table
	|view_list   |0 |0 |0 |0 |1 |0 |0 |0 | - fetches a list of views in schema of open db instance
	|view_info   |0 |0 |0 |0 |1 |0 |0 |0 | - fetches some detailed info about a database instance
	|view_verify |0 |0 |0 |0 |1 |0 |0 |0 | - compares a provided view spec to an actual view
	|view_create |0 |0 |0 |0 |0 |1 |0 |0 | - creates a new view in schema of open db inst
	|view_delete |0 |0 |0 |0 |0 |1 |0 |0 | - deletes an existing view in open db inst (if it can)
	|view_clone  |0 |0 |0 |0 |1 |1 |0 |0 | - creates a clone of an existing view with different name
	|view_update |0 |0 |0 |0 |0 |1 |0 |0 | - alters schema for an existing view
	|block_list  |0 |0 |0 |0 |1 |0 |0 |0 | - fetches a list of blocks/procs/funcs of open db instance
	|block_info  |0 |0 |0 |0 |1 |0 |0 |0 | - fetches some detailed info about a database instance
	|block_verify|0 |0 |0 |0 |1 |0 |0 |0 | - compares a provided block spec to an actual block
	|block_create|0 |0 |0 |0 |0 |1 |0 |0 | - creates a new block in schema of open db inst
	|block_delete|0 |0 |0 |0 |0 |1 |0 |0 | - deletes an existing block in open db inst (if it can)
	|block_clone |0 |0 |0 |0 |1 |1 |0 |0 | - creates a clone of an existing block with different name
	|block_update|0 |0 |0 |0 |0 |1 |0 |0 | - alters schema for an existing block
	|rec_fetch   |0 |0 |0 |0 |0 |0 |1 |0 | - fetches records from a table or view of multiple tables
	|rec_verify  |0 |0 |0 |0 |0 |0 |1 |0 | - compares a provided set of records to stored ones
	|rec_insert  |0 |0 |0 |0 |0 |0 |0 |1 | - inserts new recs into a table or view of multiple tables
	|rec_update  |0 |0 |0 |0 |0 |0 |0 |1 | - updates exist recs in a table or view of multiple tables
	|rec_c_update|0 |0 |0 |0 |0 |0 |0 |1 | - ? updates exist recs with calculation rather than value list
	|rec_delete  |0 |0 |0 |0 |0 |0 |0 |1 | - deletes exist recs from a table or view of multiple tables
	|rec_replace |0 |0 |0 |0 |0 |0 |0 |1 | - either updates or inserts recs if they exist or not
	|rec_clone   |0 |0 |0 |0 |0 |0 |0 |1 | - creates a clone of a record in same table/view (if possible)
	|rec_lock    |0 |0 |0 |0 |0 |0 |1 |1 | - places a lock on recs for a consistant read plus update
	|rec_unlock  |0 |0 |0 |0 |0 |0 |1 |1 | - releases an existing lock on recs
	|tra_start   |0 |0 |0 |0 |0 |0 |0 |1 | - starts a new transactional context for later commands
	|tra_commit  |0 |0 |0 |0 |0 |0 |0 |1 | - commits outstanding rec commands, releases locks
	|tra_rollback|0 |0 |0 |0 |0 |0 |0 |1 | - rolls back outstanding rec commands, releases locks
	|call_proc   |0 |0 |1 |1 |0 |0 |1 |1 | - calls a stored procedure to do some predefined task
	|call_func   |0 |0 |1 |1 |0 |0 |1 |1 | - calls a stored function to do some predefined task

	Note that the above list isn't technically true when certain types of databases are used, 
	but this exception is something that would be abstracted away by the driver, so isn't part 
	of the normal RNI.  The exception is with certain small RDBMS products which maintain their 
	database entirely in RAM with periodic flushes to disk, such as with certain small scale 
	products.  What happens is that all parts of the database are stored in a single file on 
	disk, which is read fully into RAM by the 'db_open' command, and written fully to disk 
	either on 'db_close' or other times.  Most databases by contrast save any changes to their 
	state to disk immediately.  For those databases, 'wd' could be true for any command type.

=head2 cct_result_type

This table enumerates the basic types of Results that SQL::SyntaxModel can return from executing a 
Command against a database or other Result context.

Column List:

	code - str,req - name of the command type
	is_error - bool,req - true when result is an error condition
	is_conn - bool,req - true when result is a database connection handle
	is_trans - bool,req - true when result is a database transaction handle
	is_curs - bool,req - true when result is a database record fetch cursor handle
	is_rec - bool,req - true when result is a database row returned by a cursor
	is_var - bool,req - true when result is a variable bound to a db command arg or large result
	is_lit - bool,req - true when result is a literal value (may be multidimensional)

Index List:

	primary - unique - [code]

Record List:

	|code |er|co|tr|cu|re|va|li|
	|-----|--|--|--|--|--|--|--|
	|error|1 |0 |0 |0 |0 |0 |0 | - an error message
	|conn |0 |1 |0 |0 |0 |0 |0 | - a database connection handle
	|trans|0 |0 |1 |0 |0 |0 |0 | - a database transaction handle
	|curs |0 |0 |0 |1 |0 |0 |0 | - a database record fetch cursor handle
	|rec  |0 |0 |0 |0 |1 |0 |0 | - a database row returned by a cursor
	|var  |0 |0 |0 |0 |0 |1 |0 | - a variable bound to a db command arg or large result
	|lit  |0 |0 |0 |0 |0 |0 |1 | - a literal value (may be multidimensional)

=head1 DATA TYPES

This table is for storing "user" definitions of data types.  Each of these
would correspond to a basic type that is recognized in code by SQL::SyntaxModel, and
allows the users to customize details such as the type names or in some cases
their scale or precision or certain other constraints.

For example, the user may decide to create a custom data type called
"currency", which is a decimal number of scale 15 and a precision of 2.  Or,
they may want to have an "ip address" type, which is a string that can hold 15
characters (how ips are normally displayed to humans).  Or, they may want a
custom SIN or telephone-no or person-name type.  They can then refer to these
custom types everywhere as if they were types built-in to the database.

Because all of the records in these tables are user defined, the provided 
record list is simply some example or "synopsis" data; none of it corresponds 
to anything in the SQL::SyntaxModel code.

=head2 data_type

This table describes custom user-defined data types, which can be used in 
table column definitions, view column definitions, and block variables.

Column List:

	id - uint,req - unique identifier for this data type
	name - str,req - name of the user customized data type
	basic_type - enum,req - name of the basic data type this is customized from: bin, str, num, bool, datetime
	size_in_bytes - uint - maximum size in bytes data can be
	size_in_chars - uint - maximum size in chars data can be
	size_in_digits - uint - maximum size in digits data can be (aka num_scale)
	store_fixed - bool - when true then try to reserve max size on disk even if not all used
	str_encoding - enum - which character encoding to use when data type is a string
	str_trim_white - bool - when true then trim lead/trailing whitespace on save into field/var
	str_latin_case - enum - when str has latin chars do we upper/lowercase them on save
	str_pad_char - str - when store_fixed is true then pad actual value with this to max size on save
	str_trim_pad - bool - when store_fixed is true then trim padding on read from field/var
	num_unsigned - bool - when basic_type is 'num', true means only >= 0 may be stored
	num_precision - uint - when basic_type is 'num', num digits of fractional precision we allowed
	datetime_calendar - enum - when basic_type is 'datetime', what calendar the date and time is in

Undecided Possible Extra Columns:

	num_min_val - uint - when type is numerical, what the allowed minimum value is
	num_max_val - uint - when type is numerical, what the allowed maximum value is
	datetime_min_val - datetime - when type is datetime, what the allowed earliest value is
	datetime_max_val - datetime - when type is datetime, what the allowed latest value is

Index List:

	primary - unique - [id]
	ak_name - unique - [name]
	fk_basic_type - foreign - [basic_type]->[cct_basic_data_type]:[code]
	fk_str_encoding - foreign - [str_encoding]->[cct_str_enc]:[code]
	fk_str_latin_case - foreign - [str_latin_case]->[cct_str_latin_case]:[code]
	fk_datetime_calendar - foreign - [datetime_calendar]->[cct_datetime_calendar]:[code]

Example Record List:

	|id|name    |base    |bytes|char|dig|fx|enc|tw|la|pc|tp|u|p|cal|
	|--|--------|--------|-----|----|---|--|---|--|--|--|--|-|-|---|
	| 1|bin1k   |bin     | 1000|    |   |  |   |  |  |  |  | | |   | - a hunk of binary data of maximum 1000 bytes
	| 2|bin32k  |bin     |32000|    |   |  |   |  |  |  |  | | |   | - a hunk of binary data of maximum 32000 bytes
	| 3|str4    |str     |     |   4|   | 1|asc| 1|uc|20|1 | | |   | - a fix-w 4 char ascii str, uppercased, spc-pad
	| 4|str10   |str     |     |  10|   | 1|asc| 1|pr|20|1 | | |   | - a fix-w 10 char ascii str, case-preserve, spc-pad
	| 5|str30   |str     |     |  30|   |  |asc| 1|  |  |  | | |   | - a var-w 30 char ascii str, case-preserving
	| 6|str2k   |str     |     |2000|   |  |u16|  |  |  |  | | |   | - a var-w 2000 char unicode str, case-preserving
	| 7|byte    |num     |    1|    |   |  |   |  |  |  |  | |0|   | - a precise int btwn           -128 and           +127
	| 8|short   |num     |    2|    |   |  |   |  |  |  |  | |0|   | - a precise int btwn        -32,768 and        +32,767
	| 9|int     |num     |    4|    |   |  |   |  |  |  |  | |0|   | - a precise int btwn -2,147,483,648 and +2,147,483,647
	|10|long    |num     |    8|    |   |  |   |  |  |  |  | |0|   | - a precise int btwn        -(2^63) and      +(2^63)-1
	|11|ubyte   |num     |    1|    |   |  |   |  |  |  |  |1|0|   | - a precise integer between 0 and           +255
	|12|ushort  |num     |    2|    |   |  |   |  |  |  |  |1|0|   | - a precise integer between 0 and        +65,535
	|13|uint    |num     |    4|    |   |  |   |  |  |  |  |1|0|   | - a precise integer between 0 and +4,294,967,295
	|14|ulong   |num     |    8|    |   |  |   |  |  |  |  |1|0|   | - a precise integer between 0 and      +(2^64)-1
	|15|float   |num     |    4|    |   |  |   |  |  |  |  | | |   | - a 32-bit imprecise fractional number
	|16|double  |num     |    8|    |   |  |   |  |  |  |  | | |   | - a 64-bit imprecise fractional number
	|17|dec10p2 |num     |     |    | 10|  |   |  |  |  |  | |2|   | - a precise 10-digit num with hundredths precision
	|18|dec255  |num     |     |    |255|  |   |  |  |  |  | | |   | - a precise 255-digit num with arbitrary precision
	|19|boolean |bool    |     |    |   |  |   |  |  |  |  | | |   | - a boolean; only 2 values of false or true
	|20|datetime|datetime|     |    |   |  |   |  |  |  |  | | |abs| - a date or time or both, non-calendar specific
	|21|dtchines|datetime|     |    |   |  |   |  |  |  |  | | |chi| - a date or time or both, in the Chinese calendar
	|22|str1    |str     |     |   1|   |  |   |  |  |  |  | | |   | - a 1-char string
	|23|str20   |str     |     |  20|   |  |   |  |  |  |  | | |   | - a 20-char string
	|24|str100  |str     |     | 100|   |  |   |  |  |  |  | | |   | - a 100-char string
	|25|str250  |str     |     | 250|   |  |   |  |  |  |  | | |   | - a 250-char string
	|26|entitynm|str     |     |  30|   |  |   |  |  |  |  | | |   | - a short string suitable for naming things
	|27|generic |str     |     | 250|   |  |   |  |  |  |  | | |   | - a longer string that most kinds of data will fit in

=head1 DATABASES AND NAME SPACES

SQL::SyntaxModel data dictionaries can be and are used to describe both things
that are stored in a database schema and things which are not stored
there, but are used in connection with database schema by applications.
Items which are stored in a database can be accessed by other items
stored in a database, like named stored procedures or packages, and they
can not directly bind to application variables.  Items not stored in a
database can be bound and customized to application variables, such as
normal 'select' SQL.  There are two root tables in SQL::SyntaxModel data
dictioaries, into which almost everything else is grouped.  'database'
groups what can be stored in a database, and 'application' groups what
can not be.  The current version of DataDictionary.pod does not 
explicitely describe 'application' or what is under it.

=head2 database

Each record in this table corresponds to a distinct "database" or
"data source" or "database instance" or "server" or "host" which contains
everything else, both schema and users.  This is what an application
"connects to" when it will use a database.  Usually this will contain just 
one record, if you are only using one database.  The rationale for being able 
to describe multiple databases in the same data dictionary is, for example, 
when one database wants to talk directly to another.

Column List:

	id - uint,req - unique identifier for this database
	name - str - corresponds to Oracle "Data Source" (for one db instance querying another)

Index List:

	primary - unique - [id]
	ak_name - unique - [name]

Example Record List:

	|id|name|
	|--|----|
	| 1|    | - a default database, usually just used if it is the only database
	| 2|site| - a multi-namespace genealogy database that you manage
	| 3|dist| - a similar database that someone else manages

=head2 namespace

Each record in this table corresponds to a "name space" into which your schema
objects can be collected.  Some database products support multiple name spaces
(in Oracle each one is called a "Schema" and is associated with a database
user), and other databases do not support multiple name spaces (most?).  In 
many cases this table only ever contains one record, where all schema objects 
share the same (or only) namespace.

SQL::SyntaxModel will let you define your schema objects (tables, views, procedures,
etc) as if multiple namespaces were supported natively, and if you are
deploying to a database that doesn't, then SQL::SyntaxModel can put a common name prefix
in front of all the schema objects (the namespace name), to simulate the
lacking functionality.  That said, it is better for you to design your schemas 
so different namespaces don't contain same-named objects anyway, if practical.

Because all of the records in these tables are user defined, the provided 
record list is simply some example or "synopsis" data; none of it corresponds 
to anything in the SQL::SyntaxModel code.

Column List:

	id - uint,req - unique identifier for this namespace
	database - uint,req - the database that this namespace is in
	name - str - the name this namespace is identified by; corresponds to Oracle "Schema"

Index List:

	primary - unique - [id]
	ak_name - unique - [database,name]
	fk_database - foreign - [database]->[database]:[id]

Example Record List:

	|id|db|name|
	|--|--|----|
	| 1| 1|    | - a default namespace, usually just used if it is the only namespace
	| 2| 2|gene| - store all the normal app data that constitutes a genealogy database
	| 3| 2|dd  | - store a data dictionary describing an application for editing gene data
	| 4| 3|gene| - in case we want to access genealogy data collected by someone else

Note: it may not be practical in real life to have databases directly querying
each other, but for when you do want to, some database engines do support it.

=head1 TABLES

These tables are for storing user definitions of database tables, which are
what actually store their data.  Each table has one or more columns and one or
more indexes or constraints.

All tables are uniquely identified here by an "id", which is different from the
table name that is stored in the database schema; the actual name in the schema
may change depending on what the implementing database is.

Because all of the records in these tables are user defined, the provided 
record list is simply some example or "synopsis" data; none of it corresponds 
to anything in the SQL::SyntaxModel code.

=head2 table

Each record in this table uniquely corresponds to one database table, and has
some core details.

Column List:

	id - uint,req - unique identifier for this table
	namespace - uint,req - the namespace that this table is in
	name - str,req - the name this table is identified by
	order - uint,req - to explicitely define what order tables are declared in
	public_syn - str - a name for the table outside of any namespace; Oracle public synonym
	storage_file - str - where applicable, explicitely say where to store table (aka, "tablespace")

Undecided Possible Extra Column:

	is_temporary - bool - does table even go in the schema, or just a connection-specific place

Index List:

	primary - unique - [id]
	ak_name - unique - [namespace,name]
	ak_order - unique - [namespace,order]
	ak_public - unique - [public_syn]
	fk_namespace - foreign - [namespace]->[namespace]:[id]

Example Record List:

	|id|ns|name        |ord|public_syn  |file  |
	|--|--|------------|---|------------|------|
	| 1| 1|user_auth   |  1|user_auth   |user  | - authentication related details for application users
	| 2| 1|user_profile|  2|user_profile|user  | - public personal details for application users
	| 3| 1|user_pref   |  3|user_pref   |user  | - application preference values for users
	| 4| 1|person      |  4|person      |person| - core data node in a genealogical program

=head2 table_col

Each record in this table uniquely corresponds to a single table column, and has 
details that are specific to that column.

Column List:

	id - uint,req - unique identifier for this table column
	table - uint,req - unique identifier for this table
	name - str,req - unique identifier for column within table
	order - uint,req - what order columns are declared in (and by default returned in)
	data_type - uint,req - the user-customized data type for this column
	required_val - bool,req - true when col value is required (not null), false when not (null)
	default_val - str - an optional default value for the column, or starting val for auto_inc
	auto_inc - bool - when true, col val defaults from a special auto-incrementing sequence

Undecided Possible Extra Columns:

	default_seq - uint - when set, the column defaults to a value from this user defined sequence

Index List:

	primary - unique - [id]
	ak_name - unique - [table,name]
	ak_order - unique - [table,order]
	fk_table - foreign - [table]->[table]:[id]
	fk_data_type - foreign - [data_type]->[data_type]:[id]

Undecided Possible Extra Indexes:

	fk_sequence - foreign - [default_seq]->[sequence]:[id]

Example Record List:

	|id|tb|name         |ord|ty|req|def|inc|
	|--|--|-------------|---|--|---|---|---|
	| 1| 1|user_id      |  1| 9|1  |1  |1  | - unique internal id for user, not changeable
	| 2| 1|login_name   |  2|23|1  |   |   | - who user authenticates into app as
	| 3| 1|login_pass   |  3|23|1  |   |   | - also used with authentication
	| 4| 1|private_name |  4|24|1  |   |   | - real name that app service provider can know
	| 5| 1|private_email|  5|24|1  |   |   | - email that service provider can contact user with
	| 6| 1|may_login    |  6|19|1  |   |   | - true when user may use app at all
	| 7| 1|max_sessions |  7| 7|1  |3  |   | - max concurrent app logins user may have
	| 8| 2|user_id      |  1| 9|1  |   |   | - unique internal id for user, not changeable
	| 9| 2|public_name  |  2|25|1  |   |   | - public name or pen name or public alias
	|10| 2|public_email |  3|25|0  |   |   | - email address the public may use for contact
	|11| 2|web_url      |  4|25|0  |   |   | - personal/business website address of user
	|12| 2|contact_net  |  5|25|0  |   |   | - info like ICQ number or other internet handles
	|13| 2|contact_phy  |  6|25|0  |   |   | - physical address or city or telephone number
	|14| 2|bio          |  7|25|0  |   |   | - brief description of the person
	|15| 2|plan         |  8|25|0  |   |   | - what the person plans to do next
	|16| 2|comments     |  9|25|0  |   |   | - other comments
	|17| 3|user_id      |  1| 9|1  |   |   | - unique internal id for user, not changeable
	|18| 3|pref_name    |  2|26|1  |   |   | - app-specific preference name
	|19| 3|pref_value   |  3|27|0  |   |   | - preference value for this user
	|20| 4|person_id    |  1| 9|1  |1  |1  | - unique actual id for person, not changeable
	|21| 4|alternate_id |  2|23|0  |   |   | - user's own way of ident people, if wanted
	|22| 4|name         |  3|24|1  |   |   | - actual name of the person they are called by
	|23| 4|sex          |  4|22|0  |   |   | - sex of the person, if known
	|24| 4|father_id    |  5| 9|0  |   |   | - person_id of this person's father, if known
	|25| 4|mother_id    |  6| 9|0  |   |   | - person_id of this person's mother, if known

=head2 table_ind

Each record in this table uniquely corresponds to a single table index, and has
details that are specific to that index.

Note that the primary key for a table is defined to be the first (by order)
unique index where all of the index columns are required.  If no table indexes 
qualify then the table has no primary key.

Note that this data dictionary design assumes that database products will only 
enforce foreign key constraints if the columns in question are populated.  
That is, a constrained column may be empty even if the foreign column never is.

Column List:

	id - uint,req - unique identifier for this table index
	table - uint,req - unique identifier for this table
	name - str,req - unique identifier for index within table
	order - uint,req - what order indexes are declared in
	ind_type - enum,req - what type of index this is (eg: unique, foreign)
	f_table - uint - when the index type is a foreign key, this is the constraining table

Index List:

	primary - unique - [id]
	ak_name - unique - [table,name]
	ak_order - unique - [table,order]
	fk_table - foreign - [table]->[table]:[id]
	fk_ind_type - foreign - [ind_type]->[cct_index_type]:[code]
	fk_f_table - foreign - [f_table]->[table]:[id]

Example Record List:

	|id|tb|name            |ord|type   |ftbl|
	|--|--|----------------|---|-------|----|
	| 1| 1|primary         |  1|unique |    | - ensure all [user_id] are unique
	| 2| 1|ak_login_name   |  2|unique |    | - ensure all [login_name] are unique
	| 3| 1|ak_private_email|  3|unique |    | - ensure all [private_email] are unique
	| 4| 2|primary         |  1|unique |    | - ensure all [user_id] are unique
	| 5| 2|ak_public_name  |  2|unique |    | - ensure all [public_name] are unique
	| 6| 2|fk_user         |  3|foreign|   1| - ensure user_profile matches user_auth
	| 7| 3|primary         |  1|unique |    | - ensure all [user_id,pref_name] are unique
	| 8| 3|fk_user         |  2|foreign|   1| - ensure user_pref matches user_auth
	| 9| 4|primary         |  1|unique |    | - ensure all [person_id] are unique
	|10| 4|ak_alternate_id |  2|unique |    | - ensure all [alternate_id] are unique
	|11| 4|fk_father       |  3|foreign|   4| - link child to father
	|12| 4|fk_mother       |  4|foreign|   4| - link child to mother

=head2 table_ind_col

This is an intersection table between table_ind and table_col; it says which table 
columns are involved in each table index.

Column List:

	id - uint,req - unique identifier for this table index column
	table_ind - uint,req - unique identifier for index within table
	table_col - uint,req - unique identifier for column within table
	order - uint,req - order of the columns within the index
	f_table_col - uint - when the index type is a foreign key, this is the constraining column

	table - uint,req - unique identifier for this table
	f_table - uint - when the index type is a foreign key, this is the constraining table

Index List:

	primary - unique - [id]
	ak_table_col - unique - [table_ind,table_col]
	ak_order - unique - [table_ind,order]
	fk_table_ind - foreign - [table_ind,table]->[table_ind]:[id,table]
	fk_table_col - foreign - [table_col,table]->[table_col]:[id,table]
	fk_f_table_col - foreign - [f_table_col]->[table_col]:[id]

Example Record List:

	|id|ind|col|ord|fcol|tbl|ftbl|
	|--|---|---|---|----|---|----|
	| 1|  1|  1|  1|    |  1|    | - ensure all [user_id] are unique
	| 2|  2|  2|  1|    |  1|    | - ensure all [login_name] are unique
	| 3|  3|  5|  1|    |  1|    | - ensure all [private_email] are unique
	| 4|  4|  8|  1|    |  2|    | - ensure all [user_id] are unique
	| 5|  5|  9|  1|    |  2|    | - ensure all [login_name] are unique
	| 6|  6|  8|  1|   1|  2|   1| - ensure user_profile matches user_auth
	| 7|  7| 17|  1|    |  3|    | - ensure all [user_id,pref_name] are unique
	| 8|  7| 18|  2|    |  3|    | - ensure all [user_id,pref_name] are unique
	| 9|  8| 17|  1|   1|  3|   1| - ensure user_pref matches user_auth
	|10|  9| 20|  1|    |  4|    | - ensure all [person_id] are unique
	|11| 10| 21|  1|    |  4|    | - ensure all [alternate_id] are unique
	|12| 11| 24|  1|  20|  4|   4| - link child to father
	|13| 12| 25|  1|  20|  4|   4| - link child to mother

=head2 trigger

This table is basically an intersection table between a table and a block,
except that each block can only be used in one trigger.  Each record in this
table uniquely corresponds to a single trigger, which is a special unnamed
block that is associated with a table and which executes automatically when
certain kinds of DML activity happen to the table.  Triggers can be set to run
before or after said activity, either once per SQL statement execution or once
per each row worked on; they can run on inserts and/or updates and/or deletes.

Column List:

	id - uint,req - unique identifier for this trigger
	table - uint,req - unique identifier for the table to watch
	block - uint,req - unique identifier for the block to execute, only 1 trig can use a block
	run_before - bool,req - true when the block should execute before attempted change is made
	run_after - bool,req - true when the block should execute after attempted change is made
	on_insert - bool,req - true when block should execute when a record insert is attempted
	on_update - bool,req - true when block should execute when a record update is attempted
	on_delete - bool,req - true when block should execute when a record delete is attempted
	for_each_row - bool,req - true when block is re-executed for each row affected; false is once

Index List:

	primary - unique - [id]
	ak_block - unique - [block]
	fk_table - foreign - [table]->[table]:[id]
	fk_block - foreign - [block]->[block]:[id]

=head1 VIEWS

These tables are for storing user definitions of database views, which are
interfaces to one or more tables that are related in a specific way.  Each view
looks outwardly like a table, in that it has rows or columns, but it does not
describe how data is stored, but mainly just how it is retrieved.  SQL::SyntaxModel
"views" are used for more types of things than SQL views are; see the
cct_view_type table description above for details.

All views are uniquely identified here by an "id", which is different from the
view name that is stored in the database schema (where applicable); the actual
name in the schema may change depending on what the implementing database is.

Because all of the records in these tables are user defined, the provided 
record list is simply some example or "synopsis" data; none of it corresponds 
to anything in the SQL::SyntaxModel code.

=head2 view

Each record in this table uniquely corresponds to one database view, and has
some core details.

Views are often fully defined using a set of multiple records in various
view/_* tables, which makes them fully customizable.  However, a short-cut is
available which allows a view to be defined entirely with just one record in
"view", through the optional match_table field.  When this is populated with a
table id, the view will exactly match the interface of that table, with no
further customization being allowed (except, perhaps, row paging).  This short
cut is mainly for use when we want to simulate full direct table access, which
is needed for mass back-ups or restores of tables, or when implementing a
utility that lets users make direct changes to a table.

Since the ability to change database records is more complicated than simply
viewing records, and usually requires more information to be available (such as
primary keys for rows being updated), SQL::SyntaxModel allows you to store a hint with a
view, called "may_write", that says whether or not you will even try to make
updates against a view, so we will know in advance and save ourselves
unnecessary work or complexity.  The flag defaults to false.

Column List:

	id - uint,req - unique identifier for this view
	view_type - enum,req - what kind of view this is; eg: object, caller, cursor, inside
	p_view - uint - parent view of this one, if any; empty if this is the root view
	namespace - uint - the namespace that this view is in, if any
	name - str - the name this view is identified by, if any
	order - uint - to explicitely define what order views are declared in, if named
	public_syn - str - a name for the view outside of any namespace, if named; Oracle public synonym
	may_write - bool,req - true when we should at least try allowing updates through the view
	match_table - uint - when set, the view matches exactly the interface for one table

Undecided Possible Extra Columns:

	p_view_order - uint,req - order of this view among its siblings; 1 if no siblings
	page_rows - bool,req - true when we should page the resulting rows so only some are returned
	maxr_lit_val - uint - if paging, this literal value says maximum rows to be returned
	maxr_block_var - uint - if paging, get max rows from this containing block variable
	maxr_command_var - uint - if paging, get max rows from this caller bind variable
	skipr_lit_val - uint - if paging, this literal value says rows to skip before returning any
	skipr_block_var - uint - if paging, get skip rows from this containing block variable
	skipr_command_var - uint - if paging, get skip rows from this caller bind variable

Index List:

	primary - unique - [id]
	ak_name - unique - [namespace,name]
	ak_order - unique - [namespace,order]
	ak_public - unique - [public_syn]
	fk_view_type - foreign - [view_type]->[cct_view_type]:[code]
	fk_namespace - foreign - [namespace]->[namespace]:[id]
	fk_match_table - foreign - [match_table]->[table]:[id]

Undecided Possible Extra Indexes:

	fk_maxr_block_var - foreign - [maxr_block_var]->[block_var]:[id]
	fk_maxr_command_var - foreign - [maxr_command_var]->[command_var]:[id]
	fk_skipr_block_var - foreign - [skipr_block_var]->[block_var]:[id]
	fk_skipr_command_var - foreign - [skipr_command_var]->[command_var]:[id]

Example Record List:

	|id|type  |pvw|ns|name|ord|pub|wr|match|
	|--|------|---|--|----|---|---|--|-----|
	| 1|caller|   |  |    |   |   |1 |     | - user - joins the "user_auth" and "user_profile" tables
	| 2|caller|   |  |    |   |   |0 |     | - person_with_parents - joins the "person" table with itself twice
	| 3|caller|   |  |    |   |   |0 |     | - user_theme - shows how many users use each theme pref value
	| 4|caller|   |  |    |   |   |1 |    4| - person - simply the "person" table

=head2 view_col

Each record in this table uniquely corresponds to a single view column public
interface, and has details that are specific to that column; the view column
implementation (where the data comes from or goes to) is not described here.

Column List:

	id - uint,req - unique identifier for this view column
	view - uint,req - unique identifier for this view
	name - str,req - unique identifier for column within view
	order - uint,req - what order columns are declared in (and by default returned in)
	data_type - uint,req - the user-customized data type for this column
	sort_priority - uint - if valued, priority for final result rows (after rs merges) to be sorted by this column

Undecided Possible Extra Columns:

	is_writeable - bool - true when enough info is known to write changes to this column
	is_required - bool - true when corresponding value must always be populated
	is_key - bool - true when this column is a part of unique id for source table or for view row

Index List:

	primary - unique - [id]
	ak_name - unique - [view,name]
	ak_order - unique - [view,order]
	fk_view - foreign - [view]->[view]:[id]
	fk_data_type - foreign - [data_type]->[data_type]:[id]

Example Record List:

	|id|vw|col_name     |ord|ty|so|
	|--|--|-------------|---|--|--|
	| 1| 1|user_id      |  1| 9|  | - unique internal id for user, not changeable
	| 2| 1|login_name   |  2|23| 1| - who user authenticates into app as
	| 3| 1|login_pass   |  3|23|  | - also used with authentication
	| 4| 1|private_name |  4|24|  | - real name that app service provider can know
	| 5| 1|private_email|  5|24|  | - email that service provider can contact user with
	| 6| 1|may_login    |  6|19|  | - true when user may use app at all
	| 7| 1|max_sessions |  7| 7|  | - max concurrent app logins user may have
	| 8| 1|public_name  |  8|25|  | - public name or pen name or public alias
	| 9| 1|public_email |  9|25|  | - email address the public may use for contact
	|10| 1|web_url      | 10|25|  | - personal/business website address of user
	|11| 1|contact_net  | 11|25|  | - info like ICQ number or other internet handles
	|12| 1|contact_phy  | 12|25|  | - physical address or city or telephone number
	|13| 1|bio          | 13|25|  | - brief description of the person
	|14| 1|plan         | 14|25|  | - what the person plans to do next
	|15| 1|comments     | 15|25|  | - other comments
	|16| 2|self_id      |  1| 9|  | - unique actual id for person, not changeable
	|17| 2|self_name    |  2|24| 1| - actual name of the person they are called by
	|18| 2|father_id    |  3| 9|  | - person_id of this person's father, if known
	|19| 2|father_name  |  4|24| 2| - actual name of the person's father
	|20| 2|mother_id    |  5| 9|  | - person_id of this person's mother, if known
	|21| 2|mother_name  |  6|24| 3| - actual name of the person's mother
	|22| 3|theme_name   |  1|27| 2| - name of a user theme
	|23| 3|theme_count  |  2| 9| 1| - count of users that use this theme

=head2 view_rowset

Each record in this table uniquely corresponds to a rowset definition which is
part of a view definition.  Normally there is only one rowset in a view, but if
the view contains operations like "union" or "intersect" then there would be
more than one rowset which are, for example, being unioned to produce the final
result set.  Each rowset in a view has its own view definition, except that all
rowsets in a view share the same view_col records, and possibly view_order.  

The view_rowset records are arranged into a hierarchy whose root is the view, so 
that the merging operations (eg: the unions) are done in the correct order.

Column List:

	id - uint,req - unique identifier for this view rowset
	view - uint,req - unique identifier for this view
	p_rowset - uint - parent rowset of this one, if any; empty if this is the root rowset
	p_rowset_order - uint,req - order of this rowset among its siblings; 1 if no siblings
	c_merge_type - enum - how to merge any child rowsets of this one together, if any

Index List:

	primary - unique - [id]
	ak_order - unique - [p_rowset,p_rowset_order]
	fk_view - foreign - [view]->[view]:[id]
	fk_merge_type - foreign - [c_merge_type]->[cct_rs_merge_type]:[code]

Example Record List:

	|id|vw|pri|pro|mtp|
	|--|--|---|---|---|
	| 1| 1|   |  1|   | - user
	| 2| 2|   |  1|   | - person_with_parents
	| 3| 3|   |  1|   | - user_theme

=head2 view_src

Each record in this table uniquely corresponds to a source table or view that
is used by this view (one copy per view rowset if applicable).  Specifically it
applies only to the "from" clause in the generated SQL, where applicable.  A
table or view may be used for multiple sources, each of which would be a unique
alias for it.

Column List:

	id - uint,req - unique identifier for this view source
	rowset - uint,req - unique identifier for rowset within view
	name - str,req - unique "alias" identifier for source within view rowset
	order - uint,req - what order sources are declared in (and by default joined)
	match_table - uint - if set, the source is a table (and match_view must not be set)
	match_view - uint - if set, the source is another view (and match_table must not be set)

Index List:

	primary - unique - [id]
	ak_name - unique - [rowset,name]
	ak_order - unique - [rowset,order]
	fk_rowset - foreign - [rowset]->[view_rowset]:[id]
	fk_match_table - foreign - [match_table]->[table]:[id]
	fk_match_view - foreign - [match_view]->[view]:[id]

Example Record List:

	|id|rs|name        |ord|mtb|mvw|
	|--|--|------------|---|---|---|
	| 1| 1|user_auth   |  1|  1|   | - match "user_auth" table
	| 2| 1|user_profile|  2|  2|   | - match "user_profile" table
	| 3| 2|self        |  1|  4|   | - match "person" table
	| 4| 2|father      |  2|  4|   | - match "person" table
	| 5| 2|mother      |  3|  4|   | - match "person" table
	| 6| 3|user_pref   |  1|  3|   | - match "user_pref" table

=head2 view_src_col

Each record in this table uniquely represents a column in a source table or
view that is used by this view, as specified in the view_src table.

Note that with databases that require all used columns to be populated in order
to enforce a unique key or foreign key constraint, a trigger or other mechanism
may be needed for some of the below items.

Column List:

	id - uint,req - unique identifier for this view source column
	src - uint,req - which view source this column is associated with
	match_table_col - uint - which column from the source table is represented, if applicable
	match_view_col - uint - which column from the source view is represented, if applicable

	rowset - uint,req - unique identifier for rowset within view (for fk to col table)
	match_table - uint - if set, the source is a table (and match_view must not be set)
	match_view - uint - if set, the source is another view (and match_table must not be set)

Index List:

	primary - unique - [id]
	fk_view_src - foreign - [src,rowset]->[view_src]:[id,rowset]
	fk_match_table - foreign - [src,match_table]->[view_src]:[id,match_table]
	fk_match_view - foreign - [src,match_view]->[view_src]:[id,match_view]
	fk_match_table_col - foreign - [match_table,match_table_col]->[table_col]:[id,table]
	fk_match_view_col - foreign - [match_view,match_view_col]->[view_col]:[id,view]

Example Record List:

	|id|vs|mtb|mtc|mvw|mvc|ri|
	|--|--|---|---|---|---|--|
	| 1| 1|  1|  1|   |   | 1| - "user_auth"."user_id"
	| 2| 1|  1|  2|   |   | 1| - "user_auth"."login_name"
	| 3| 1|  1|  3|   |   | 1| - "user_auth"."login_pass"
	| 4| 1|  1|  4|   |   | 1| - "user_auth"."private_name"
	| 5| 1|  1|  5|   |   | 1| - "user_auth"."private_email"
	| 6| 1|  1|  6|   |   | 1| - "user_auth"."may_login"
	| 7| 1|  1|  7|   |   | 1| - "user_auth"."max_sessions"
	| 8| 2|  2|  8|   |   | 1| - "user_profile"."user_id"
	| 9| 2|  2|  9|   |   | 1| - "user_profile"."public_name"
	|10| 2|  2| 10|   |   | 1| - "user_profile"."public_email"
	|11| 2|  2| 11|   |   | 1| - "user_profile"."web_url"
	|12| 2|  2| 12|   |   | 1| - "user_profile"."contact_net"
	|13| 2|  2| 13|   |   | 1| - "user_profile"."contact_phy"
	|14| 2|  2| 14|   |   | 1| - "user_profile"."bio"
	|15| 2|  2| 15|   |   | 1| - "user_profile"."plan"
	|16| 2|  2| 16|   |   | 1| - "user_profile"."comments"
	|17| 3|  4| 20|   |   | 2| - "self"."person_id"
	|18| 3|  4| 22|   |   | 2| - "self"."name"
	|19| 4|  4| 20|   |   | 2| - "father"."person_id"
	|20| 4|  4| 22|   |   | 2| - "father"."name"
	|21| 5|  4| 20|   |   | 2| - "mother"."person_id"
	|22| 5|  4| 22|   |   | 2| - "mother"."name"
	|23| 6|  3| 18|   |   | 3| - "user_pref"."pref_name"
	|24| 6|  3| 19|   |   | 3| - "user_pref"."pref_value"
	|25| 3|  4| 24|   |   | 2| - "self"."father_id"
	|26| 3|  4| 25|   |   | 2| - "self"."mother_id"

=head2 view_join

Each record in this table uniquely corresponds to a join operation being done 
between two sources (each a table or a view), both in the same view rowset.  
There are usually just two types of joins used, "equal" and "left".

Note that there can only be one join between the same two sources.  Also the
same source can never be on the right side of more than one join (?).  The fact
that there is no "right" join in the suggested data dictionary should help
prevent the same source from being outer joined to more than one other source,
which in many databases is illegal.

Column List:

	id - uint,req - unique identifier for this view join
	rowset - uint,req - unique identifier for rowset within view
	lhs_src - uint,req - which view source is on the left side of the join
	rhs_src - uint,req - which view source is on the right side of the join
	join_type - enum,req - what kind of table/view join is being done

Index List:

	primary - unique - [id]
	ak_join - unique - [lhs_src,rhs_src]
	ak_limit_one - unique - [rhs_src]
	fk_lhs_src - foreign - [lhs_src,rowset]->[view_src]:[id,rowset]
	fk_rhs_src - foreign - [rhs_src,rowset]->[view_src]:[id,rowset]
	fk_join_type - foreign - [join_type]->[cct_rs_join_type]:[code]

Example Record List:

	|id|rs|lhs|rhs|type|
	|--|--|---|---|----|
	| 1| 1|  1|  2|left| - "user_auth" left join "user_profile"
	| 2| 2|  3|  4|left| - "self" left join "father"
	| 3| 2|  3|  5|left| - "self" left join "mother"

=head2 view_join_col

This is an intersection table between view_join and either table_col or
view_col; it says which table or view columns are involved in each view join.

Each record in this table uniquely corresponds to part of a join operation
being done between two sources (each a table or a view), both in the same view
rowset.  There is one record for each pair of source columns (one from each
source) that are being matched.

Column List:

	id - uint,req - unique identifier for this view join column
	join - uint,req - which view join this column is associated with
	lhs_src_col - uint,req - which column from the left source is being matched on
	rhs_src_col - uint,req - which column from the right source is being matched on

	lhs_src - uint,req - which view source is on the left side of the join
	rhs_src - uint,req - which view source is on the right side of the join

Index List:

	primary - unique - [id]
	ak_join - unique - [lhs_src,rhs_src,lhs_src_col]
	fk_join - foreign - [join,lhs_src,rhs_src]->[view_join]:[id,lhs_src,rhs_src]
	fk_lhs_src_col - foreign - [lhs_src_col,lhs_src]->[view_src_col]:[id,src]
	fk_rhs_src_col - foreign - [rhs_src_col,rhs_src]->[view_src_col]:[id,src]

Example Record List:

	|id|vj|lhs|lhc|rhs|rhc|
	|--|--|---|---|---|---|
	| 1| 1|  1|  1|  2|  8| - on "user_profile"."user_id" = "user_auth"."user_id"
	| 2| 2|  3| 25|  4| 19| - on "father"."person_id" = "self"."father_id"
	| 3| 3|  3| 26|  5| 21| - on "mother"."person_id" = "self"."mother_id"

=head2 view_hierarchy

Each record in this table can define an n-level hierarchical self-join-union to
be part of a view rowset definition (similar to Oracle's start-with-connect-by
feature).  Only one is allowed per view rowset, and it is probably evaluated
between the SQL "where" and "group by", where applicable.

Note: Apparently SQL99 allows recursive queries with "WITH clause" which is
a standard way of doing the same thing as Oracle's CONNECT BY.

Column List:

	id - uint,req - unique identifier for this view hierarchy
	rowset - uint,req - unique identifier for rowset within view
	start_src_col - uint,req - which source column is checked against to determine the root of the hierarchy
	start_lit_val - str - if start_src_col is being compared to a literal, then store the literal value here
	start_block_var - uint - if start_src_col is being compared to a containing block variable
	start_command_var - uint - if start_src_col is being compared to a caller bind variable
	conn_src_col - uint,req - which source column contains a record's own identifier against which children match
	p_conn_src_col - uint,req - which source column contains the value of a parent identifier

	src - uint,req - which view source is being hierarchically joined to itself

Index List:

	primary - unique - [id]
	ak_rowset - unique - [rowset]
	fk_rowset - foreign - [rowset]->[view_rowset]:[id]
	fk_src - foreign - [src,rowset]->[view_src]:[id,rowset]
	fk_start_src_col - foreign - [start_src_col,src]->[view_src_col]:[id,src]
	fk_start_block_var - foreign - [start_block_var]->[block_var]:[id]
	fk_start_command_var - foreign - [start_command_var]->[command_var]:[id]
	fk_conn_src_col - foreign - [conn_src_col,src]->[view_src_col]:[id,src]
	fk_p_conn_src_col - foreign - [p_conn_src_col,src]->[view_src_col]:[id,src]

Note that the current structure only allows queries like "... start with
[start_src_col] = [start_[lit_val/[block/command]_var]] connect by prior
[conn_src_col] = [p_conn_src_col] ...", but this probably isn't adequate for
all uses, and will be improved.  We may eliminate this table in favor of
view_part_def.

=head2 view_col_def

Each record in this table uniquely corresponds to a sub-expression that is part
of an interface/output column definition in a view; this is an intersection 
table between view_col and view_rowset; there needs to be one full
expression for every view_col/view_rowset record combination in a view.  These
expressions are used in the first part of the SQL "where" clause, before
"from"; these are not intended to affect how many columns or rows the view
returns, but only what the exact content of each column is.  All of these
sub-expressions form a hierarchy where children are "arguments" to their parent
expressions; the root expression is supposed to return the same type of value
as the data_type specified in the view_col record.

Column List:

	id - uint,req - unique identifier for this view column def sub-expression
	view_col - uint,req - unique identifier for interface/output column within view
	rowset - uint,req - unique identifier for rowset within view
	p_expr - uint - parent expression of this one, if any; empty if this is the root expression
	p_expr_order - uint,req - order of this expression among its siblings; 1 if no siblings
	expr_type - enum,req - what type of expression this is; eg: literal, variable, column, view, function
	lit_val - str - if expr_type is 'lit', then store the literal value here
	block_var - uint - if expr_type is 'var', then use this containing block variable
	command_var - uint - if expr_type is 'var', then use this caller bind variable
	src_col - uint - if expr_type is 'col', then use this source table/view column
	f_view - uint - if expr_type is 'view', then put the view/subquery id here
	sfunc - enum - if expr_type is 'sfunc', then put the standard built-in function name/code here
	ufunc - uint - if expr_type is 'ufunc', then put the user-defined stored function (block) id here

	view - uint,req - unique identifier for this view

Index List:

	primary - unique - [id]
	ak_order - unique - [view_col,rowset,p_expr,p_expr_order]
	fk_view_col - foreign - [view_col,view]->[view_col]:[id,view]
	fk_rowset - foreign - [rowset,view]->[view_rowset]:[id,view]
	fk_expr_type - foreign - [c_expr_type]->[cct_basic_expr_type]:[code]
	fk_block_var - foreign - [block_var]->[block_var]:[id]
	fk_command_var - foreign - [command_var]->[command_var]:[id]
	fk_src_col - foreign - [src_col,rowset]->[view_src_col]:[id,rowset]
	fk_f_view - foreign - [f_view]->[view]:[id]
	fk_sfunc - foreign - [sfunc]->[cct_standard_func]:[code]
	fk_ufunc - foreign - [ufunc]->[block]:[id]

Example Record List:

	|id|ci|ri|pe|peo|type |lit|blv|cmv|src|fvw|sf    |uf|vw|
	|--|--|--|--|---|-----|---|---|---|---|---|------|--|--|
	| 1| 1| 1|  |  1|col  |   |   |   |  1|   |      |  | 1|
	| 2| 2| 1|  |  1|col  |   |   |   |  2|   |      |  | 1|
	| 3| 3| 1|  |  1|col  |   |   |   |  3|   |      |  | 1|
	| 4| 4| 1|  |  1|col  |   |   |   |  4|   |      |  | 1|
	| 5| 5| 1|  |  1|col  |   |   |   |  5|   |      |  | 1|
	| 6| 6| 1|  |  1|col  |   |   |   |  6|   |      |  | 1|
	| 7| 7| 1|  |  1|col  |   |   |   |  7|   |      |  | 1|
	| 8| 8| 1|  |  1|col  |   |   |   |  9|   |      |  | 1|
	| 9| 9| 1|  |  1|col  |   |   |   | 10|   |      |  | 1|
	|10|10| 1|  |  1|col  |   |   |   | 11|   |      |  | 1|
	|11|11| 1|  |  1|col  |   |   |   | 12|   |      |  | 1|
	|12|12| 1|  |  1|col  |   |   |   | 13|   |      |  | 1|
	|13|13| 1|  |  1|col  |   |   |   | 14|   |      |  | 1|
	|14|14| 1|  |  1|col  |   |   |   | 15|   |      |  | 1|
	|15|15| 1|  |  1|col  |   |   |   | 16|   |      |  | 1|
	|16|16| 2|  |  1|col  |   |   |   | 17|   |      |  | 2|
	|17|17| 2|  |  1|col  |   |   |   | 18|   |      |  | 2|
	|18|18| 2|  |  1|col  |   |   |   | 19|   |      |  | 2|
	|19|19| 2|  |  1|col  |   |   |   | 20|   |      |  | 2|
	|20|20| 2|  |  1|col  |   |   |   | 21|   |      |  | 2|
	|21|21| 2|  |  1|col  |   |   |   | 22|   |      |  | 2|
	|22|22| 3|  |  1|col  |   |   |   | 24|   |      |  | 3|
	|23|23| 3|  |  1|sfunc|   |   |   |   |   |gcount|  | 3|
	|24|23| 3|23|  1|col  |   |   |   | 24|   |      |  | 3|

=head2 view_part_def

The records in this table are intended to describe most of the parts of a SQL
"select" which is the basis for a view rowset definition.  The parts described
here correspond to these SQL terms: "where", "group by", "having", "order by".
All of these parts are optional, and often mutually exclusive.  However,
"having" can only be used with "group by".

The main parts that are not described here are the column list definitions that
start a "select", and the "from" (includes join definitions), and any "union"
or similar operations.  See the other view_* tables for those.  

The "order by" described by this table is applied prior to any rowset merge
operations; since those operations tend to change the order of rows, it would
only make sense to use this when your view only has one source rowset.  If you
have multiple rowsets, or you only want to sort by output columns, then use the
sort_priority field in view_col to sort instead, which has much simpler syntax, 
and is evaluated after all rowset merging is done.

Each record in this table uniquely corresponds to a sub-expression that is part
of one of several optional main/root expressions in a view rowset definition. 
All of these sub-expressions form a hierarchy where children are "arguments" to
their parent expressions.  There can only be one root expression for a "where"
and a "having" part, and that is expected to return a boolean value.  The
"group by" and "order by" parts can each have multiple root expressions, each
of which is part of an ordered list of "columns" arranged in the priority that
they are applied.  The "start with" and "connect by" can only have one root
expression each.

Column List:

	id - uint,req - unique identifier for this view part def sub-expression
	rowset - uint,req - unique identifier for rowset within view
	view_part - enum,req - what "part" of a view definition this is defining
	p_expr - uint - parent expression of this one, if any; empty if this is the root expression
	p_expr_order - uint,req - order of this expression among its siblings; 1 if no siblings
	expr_type - enum,req - what type of expression this is; eg: literal, variable, column, view, function
	lit_val - str - if expr_type is 'lit', then store the literal value here
	block_var - uint - if expr_type is 'var', then use this containing block variable
	command_var - uint - if expr_type is 'var', then use this caller bind variable
	src_col - uint - if expr_type is 'col', then use this source table/view column
	f_view - uint - if expr_type is 'view', then put the view/subquery id here
	sfunc - enum - if expr_type is 'sfunc', then put the standard built-in function name/code here
	ufunc - uint - if expr_type is 'ufunc', then put the user-defined stored function (block) id here

Index List:

	primary - unique - [id]
	ak_order - unique - [rowset,view_part,p_expr,p_expr_order]
	fk_rowset - foreign - [rowset]->[view_rowset]:[id]
	fk_view_part - foreign - [view_part]->[cct_view_part]:[code]
	fk_expr_type - foreign - [c_expr_type]->[cct_basic_expr_type]:[code]
	fk_block_var - foreign - [block_var]->[block_var]:[id]
	fk_command_var - foreign - [command_var]->[command_var]:[id]
	fk_src_col - foreign - [src_col,rowset]->[view_src_col]:[id,rowset]
	fk_f_view - foreign - [f_view]->[view]:[id]
	fk_sfunc - foreign - [sfunc]->[cct_standard_func]:[code]
	fk_ufunc - foreign - [ufunc]->[block]:[id]

Example Record List:

	|id|ri|part |pe|peo|type |lit  |blv|cmv     |src|fvw|sf    |uf|
	|--|--|-----|--|---|-----|-----|---|--------|---|---|------|--|
	| 1| 1|where|  |  1|sfunc|     |   |        |   |   |eq    |  | - standard function of "eq(a,b)"
	| 2| 1|where| 1|  1|col  |     |   |        |  1|   |      |  | - match column "user_auth"."user_id"
	| 3| 1|where| 1|  2|var  |     |   |curr_uid|   |   |      |  | - value of bind var "curr_uid"
	| 4| 2|where|  |  1|sfunc|     |   |        |   |   |and   |  | - standard function of "and(a,b)"
	| 5| 2|where| 4|  1|sfunc|     |   |        |   |   |like  |  | - standard function of "like(a,b)"
	| 6| 2|where| 5|  1|col  |     |   |        | 20|   |      |  | - match column "father"."name"
	| 7| 2|where| 5|  2|var  |     |   |srchw_fa|   |   |      |  | - value of bind var "srchw_fa"
	| 8| 2|where| 4|  1|sfunc|     |   |        |   |   |like  |  | - standard function of "like(a,b)"
	| 9| 2|where| 8|  1|col  |     |   |        | 22|   |      |  | - match column "mother"."name"
	|10| 2|where| 8|  2|var  |     |   |srchw_mo|   |   |      |  | - value of bind var "srchw_mo"
	|11| 3|where|  |  1|sfunc|     |   |        |   |   |eq    |  | - standard function of "eq(a,b)"
	|12| 3|where|11|  1|col  |     |   |        | 23|   |      |  | - match column "user_pref"."pref_name"
	|13| 3|where|11|  2|lit  |theme|   |        |   |   |      |  | - match literal value of "theme"
	|14| 3|group|  |  1|col  |     |   |        | 24|   |      |  | - group by "user_pref"."pref_value"
	|15| 3|havin|  |  1|sfunc|     |   |        |   |   |gt    |  | - standard function of "gt(a,b)"
	|16| 3|havin|15|  1|sfunc|     |   |        |   |   |gcount|  | - standard function of "gcount(col)"
	|17| 3|havin|15|  2|lit  |    1|   |        |   |   |      |  | - match literal value of "theme"

	Notes: In Oracle notation: the first view says match where
	"user_auth.user_id = :curr_uid", the second says match where "father.name
	like '%'||:srchw_fa||'%' and mother.name like '%'||:srchw_mo||'%'", the
	third says match where "user_pref.pref_name = 'theme'".

	Notes: In Oracle notation: the third view says match having "count(*) > 1" ("gcount" has no args).

	Notes: The example 'command_var' values are actually incorrect and will be changed to id numbers.

=head2 Had there been separate tables for the above, here are their descriptions

view_src_filter: Each record in this table uniquely corresponds to a
sub-expression that is part of a filter definition in a view rowset.  This
filter definition is run against the rows in the view sources just after or
while they are being joined, and it is supposed to eliminate most or all of the
source rows that we don't want to keep.  In other words, the whole expression
becomes the "where" clause in the generated SQL, where applicable (it runs
prior to the SQL "group by").  All of these sub-expressions form a hierarchy
where children are "arguments" to their parent expressions; the root expression
is supposed to return a boolean value.

view_grp: When any records in this table exist for a particular view rowset,
each one matches a source column, and the rows returned by the view rowset will
be grouped (self-merged) so that each row has a unique permutation of values in
the columns being grouped on.  Also, when any view_grp records are used, that
view rowset may only use the columns being grouped on in its output column
definition.  Certain standard functions can only be used when grouping.

view_grp_filter: Each record in this table uniquely corresponds to a
sub-expression that is part of a filter definition in a view rowset.  This
filter definition is run against the rows after they have been grouped; it is
supposed to do additional filtering that could only be done after grouping,
such as when the sub-expression uses standard functions that only work in a
grouping SQL select. This whole expression becomes the "having" clause in the
generated SQL, where applicable.  All of these sub-expressions form a hierarchy
where children are "arguments" to their parent expressions; the root expression
is supposed to return a boolean value.

view_order: The records in this table say what order to return the rows for a
view rowset or entire view in; there is one record for each solumn that is
being sorted by. They correspond to the SQL "order by".  Also, when any
view_grp records are used, that view rowset may only use the columns being
grouped on in its output column definition.  Certain standard functions can
only be used when grouping.

=head1 SEQUENCES

This section still needs to be written.

Because all of the records in these tables are user defined, the provided 
record list is simply some example or "synopsis" data; none of it corresponds 
to anything in the SQL::SyntaxModel code.

To be added: sequence.

=head1 BLOCKS

These tables are for storing user definitions of code blocks, which are
composed of a series of commands plus conditionals and iterations.  Types of
blocks include stored procedures and functions, triggers, and packages
containing stored procedures and functions; all of the previous can also have
nested stored procedures and functions; all of the previous can have nested
un-named blocks as well.

All blocks are uniquely identified here by an "id", which is different from the
view name that is stored in the database schema (where applicable); the actual
name in the schema may change depending on what the implementing database is.

Because all of the records in these tables are user defined, the provided 
record list is simply some example or "synopsis" data; none of it corresponds 
to anything in the SQL::SyntaxModel code.

=head2 block

Each record in this table uniquely corresponds to one database block, and has
some core details.

Column List:

	id - uint,req - unique identifier for this block
	block_type - enum,req - what kind of block this is; eg: object, caller, cursor, inside
	p_block - uint - parent block of this one, if any; empty if this is the root block
	namespace - uint - the namespace that this block is in, if any
	name - str - the name this block is identified by, if any
	order - uint - to explicitely define what order blocks are declared in, if named
	public_syn - str - a name for the block outside of any namespace, if named; Oracle public synonym

Undecided Possible Extra Columns:

	p_block_order - uint,req - order of this block among its siblings; 1 if no siblings
	return_type - str,req - if this block returns a value, this is its data type

Index List:

	primary - unique - [id]
	ak_name - unique - [namespace,name]
	ak_order - unique - [namespace,order]
	ak_public - unique - [public_syn]
	fk_block_type - foreign - [block_type]->[cct_block_type]:[code]
	fk_namespace - foreign - [namespace]->[namespace]:[id]

Undecided Possible Extra Indexes:

	fk_return_type - foreign - [return_type]->[data_type]:[name]

=head2 block_var

Each record in this table is for declaring a variable within the scope of a
block; it can be used by that block and by any child blocks, where applicable.  
If the current block is a package, these are package-level variables.

A variable could also be an input and/or output argument to the block, which is 
determined by its type.

Column List:

	id - uint,req - unique identifier for this block var
	block - uint,req - what block this variable is in
	name - str,req - unique identifier for variable within view
	order - uint,req - what order variables are declared in
	var_type - enum,req - what basic variable type the variable is
	is_argument - bool,req - true if this variable is a block argument (needs fleshing out)
	data_type - uint - if the var type is 'scalar', this is its user customized data type
	init_lit_val - str - if var type is 'scalar', an initial value for var can go here
	c_view - uint - if var type is 'cursor', then put the view defining it here

Undecided Possible Extra Columns:

	is_constant - bool - if the var type is 'scalar', this says its value may not be changed

Index List:

	primary - unique - [id]
	ak_name - unique - [block,name]
	ak_order - unique - [block,order]
	fk_block - foreign - [block]->[block]:[id]
	fk_var_type - foreign - [var_type]->[cct_basic_var_type]:[code]
	fk_data_type - foreign - [data_type]->[data_type]:[id]
	fk_c_view - foreign - [c_view]->[view]:[id]

=head2 block_stmt

Each record in this table represents a command or statement or line within a
block, which includes such operations as variable assignment or reading a
cursor or executing a DML operation.  In the case of an assignment, it is the
block_expr record(s) which refer to the block_stmt record.  If this statement
is something which opens a new unnamed block context, the block record is 
referred to by the block_stmt record.

Column List:

	id - uint,req - unique identifier for this block statement
	block - uint,req - what block this statement is in
	order - uint,req - what order a statement executes in
	stmt_type - str,req - what type of stmt this is; eg: assignment, condit, call, loop, dml, return
	dest_var - uint - if the stmt type is 'assign', this var is where the expression result goes
	sproc - enum - if expr_type is 'sproc', then this is the standard built-in procedure to call
	uproc - uint - if expr_type is 'uproc', then this is the user-defined stored function (block) to call
	c_block - uint - if the stmt type starts an unnamed block context, this is the child block id

Index List:

	primary - unique - [id]
	ak_order - unique - [block,order]
	fk_block - foreign - [block]->[block]:[id]
	fk_dest_var - foreign - [dest_var]->[block_var]:[id]
	fk_sproc - foreign - [sproc]->[cct_standard_proc]:[code]
	fk_uproc - foreign - [uproc]->[block]:[id]
	fk_c_block - foreign - [c_block]->[block]:[id]

=head2 block_expr

Each record in this table uniquely corresponds to a sub-expression that is part
of a main/root expression which is the right hand side of a variable assignment
statement in a block.  All of these sub-expressions form a hierarchy where
children are "arguments" to their parent expressions.  The root expression is
expected to return a value that can be stored in the block variable on the left
side of the statement.

Column List:

	id - uint,req - unique identifier for this block statement sub-expression
	stmt - uint,req - unique identifier for block statement this expression is part of
	p_expr - uint - parent expression of this one, if any; empty if this is the root expression
	p_expr_order - uint,req - order of this expression among its siblings; 1 if no siblings
	expr_type - enum,req - what type of expression this is; eg: literal, variable, column, function
	lit_val - str - if expr_type is 'lit', then store the literal value here
	src_var - uint - if expr_type is 'var', then use this containing block variable
	sfunc - enum - if expr_type is 'sfunc', then put the standard built-in function name/code here
	ufunc - uint - if expr_type is 'ufunc', then put the user-defined stored function (block) id here

Index List:

	primary - unique - [id]
	ak_order - unique - [stmt,p_expr,p_expr_order]
	fk_stmt - foreign - [stmt]->[block_stmt]:[id]
	fk_expr_type - foreign - [c_expr_type]->[cct_basic_expr_type]:[code]
	fk_src_var - foreign - [src_var]->[block_var]:[id]
	fk_sfunc - foreign - [sfunc]->[cct_standard_func]:[code]
	fk_ufunc - foreign - [ufunc]->[block]:[id]

=head1 USERS

This section still needs to be written.

Because all of the records in these tables are user defined, the provided 
record list is simply some example or "synopsis" data; none of it corresponds 
to anything in the SQL::SyntaxModel code.

To be added: user, privilege.

=head1 APPLICATIONS, COMMANDS AND RESULTS

This section still needs to be written.

Because all of the records in these tables are user defined, the provided 
record list is simply some example or "synopsis" data; none of it corresponds 
to anything in the SQL::SyntaxModel code.

To be added: application, command, command_var, result.

=head1 SEE ALSO

perl(1), SQL::SyntaxModel, SQL::SyntaxModel::XMLSchema, Rosetta,
Rosetta::Framework.

=cut
