1;

__END__

=head1 NAME

GT::SQL::Driver::Types - Column types supported by GT::SQL

=head1 SYNOPSIS

    my $c = $DB->creator('new_table');
    $c->cols({
        column_name => { type => 'INT', default => 42, not_null => 1, unsigned => 1 }
        # ... more columns ...
    });

    my $e = $DB->editor('table_name');
    $e->add_col(column_name2 => { type => 'CHAR', size => 10, default => 'abc' });

=head1 DESCRIPTION

This module should not be used directly, however the documentation here
describes the different types support by GT::SQL and any caveats associated
with those types.

=head1 ATTRIBUTES

All types are specified as a C<column_name =E<gt> { column definition }> pair,
where the column definition should contain at least a C<type> key containing
one of the L</"TYPES"> outlined below.  Commonly accepted attributes are:

=over 4

=item not_null

Used to specify that a column should not be allowed to contain NULL values.
Note that for character/string data types, a 0-character string (and, for
C<CHAR>/C<VARCHAR> columns, strings containing only spaces), B<are> considered
NULL values are are not permitted if the column is specified as C<not_null>.
The value passed to not_null should be true.

=item default

Used to specify a default value to be used for the column when no explicit
value is provided when a row is inserted.  The default value is also used for
the value in existing rows when adding a not_null column to an existing table -
in such a case, the C<default> is B<required>.

Also see the L<C<TEXT>|/TEXT> section regarding caveats and limitations of
using C<default>'s for C<TEXT> types.

=back

Other column attributes are supported as outlined below.  In addition to
attributes mentioned in this document, various attributes are available that
influence automatically-generated forms displayed by GT::SQL::Admin - see
L<GT::SQL::Creator> for details on these attributes.

=head1 TYPES

=head2 Integer types

=over 4

=item TINYINT

The C<TINYINT> type specifies an 8-bit integer able to handle values from -128
to 127.  Some databases will allow larger values due to not supporting an
appropriate data type.  The C<unsigned> column attribute I<may> turn this into
an unsigned value supporting values from 0 to 255; due to this type being
implemented as a larger integer type in some databases (which, incidentally,
coincide with the databases not supporting an unsigned 8-bit C<TINYINT>) using
an C<unsigned> TINYINT type will result in a column able to store any value
from 0-255, unlike most of the larger integer types below.

=item SMALLINT

The C<SMALLINT> type specifies a 16-bit integer able to handle values from
-32768 to 32767.  The C<unsigned> column attribute I<may> turn this into an
unsigned value supporting values from 0 to 65535, however this is B<not>
guaranteed.  If you need to store values in the 32768-65535 range, a larger
type is recommended.

=item MEDIUMINT

The C<MEDIUMINT> type (only natively supported by MySQL) specifies a 24-bit
integer type able to hold values from -8388608 to 8388607.  If the C<unsigned>
column attribute is specified, this allows values from 0 to 16777215.  Due to
this being supported with the C<unsigned> attribute, or implemented as a larger
data type, an C<unsigned> C<MEDIUMINT> will always supported values up to
16777215.

=item INT, INTEGER

The C<INT> type specifies a 32-bit integer able to hold values from -2147483648
to 2147483647.  If the C<unsigned> column attribute is specified, the column
I<may> support values from 0 to 4294967295, however this is B<not> guaranteed.
If values larger than 2147483647 are needed, using the C<BIGINT> type below is
recommended.  C<INTEGER> is an alias for C<INT>.

=item BIGINT

The largest integral type, C<BIGINT> specifies a 64-bit integer value able to
hold values from -9223372036854775808 to 9223372036854775807.  If specified as
C<unsigned>, the column I<may> support values from 0 to 18446744073709551616,
but this is B<not> guaranteed.  If larger values are needed, use the C<DECIMAL>
type with a C<scale> value of C<0>.

=back

=head2 Float-point types

=over 4

=item REAL, FLOAT

The C<REAL> type specifies a 32-bit floating-point (i.e.  fractional) number,
accurate to 23 binary digits (which works out to I<approximately> 6 decimal
digits).  The values may be signed, and can range from at least as small as
10^-37 to at least as large as 10^37.  For more precise values, the C<DOUBLE>
type is recommended.  For exact precision (i.e. for monetary values), the
(often slower) C<DECIMAL> type is recommended.  C<FLOAT> is an alias for
C<REAL>.

=item DOUBLE

The C<DOUBLE> type specifies a 64-bit floating-point (i.e. fractional) number,
accurate to 52 binary digits (I<approximately> 15 decimal digits).  The values
may be signed, and can range from at least as small as 10^-307 to at least as
large as 10^308 (except under Oracle - see below).  For exact precision (i.e.
for monetary values), the (often slower) C<DECIMAL> type is recommended.

Take note that Oracle doesn't properly support the full range supported by
other databases' C<DOUBLE> types - the smallest number supported (assuming
precision to digits) is 10^-113 - specifically, the number of digits after the
decimal place may not exceed 128 - so 1.2345678901e-117 is acceptable, while
1.23456789012e-117 is not.  The larger number Oracle supports is just less than
1e+126 (i.e. 9.999...e+125), as opposed to other databases' 1e+307.  If you
need to store numbers larger or smaller than this amount, you'll have to find
some other way to store your numbers (i.e. Math::BigFloat with a C<VARCHAR>).

=back

=head2 Aribtrary precision numbers

=over 4

=item DECIMAL

The C<DECIMAL> type is provided to support numbers of arbitrary precision.  It
requires two attributes, C<scale> and C<precision>, where C<scale> specifies
the number of decimal places, and precision specifies the number of overall
digits.  For example, C<123.45> has a C<precision> of 5, and a C<scale> of 2.
C<42> has a C<precision> or 2, and a C<scale> of 0.  C<scale> must be less than
C<precision>, and C<precision> must not exceed 38.  Also, although the value
stored and retrieved is completely accurate within it's given precision and
scale range, the accuracy available for comparisons (i.e. column = number) is
only reliably accurate to approximately the same level as DOUBLE's - that is,
about 15 digits.

=back

=head2 Character types

=over 4

=item CHAR

The C<CHAR> type is used to specify a string of characters from 1 to 255
characters long.  It takes a C<size> attribute which must be 255 or less, and
specifies the size of the column values - if not specified, 255 will be used.
This implementation's C<CHAR> type, for historic reasons, B<will not> pad
inserted values with spaces, but B<may> trim trailing spaces when retrieving
and/or comparing values.  Note that this is B<not> SQL compliant C<CHAR>
behaviour - SQL-compliant C<CHAR>'s are padded with spaces up to their size.

What this ends up meaning is that for everything except MySQL, C<CHAR> columns
will be mapped to C<VARCHAR> columns.  Note that even MySQL, which is the only
database for which C<CHAR>'s are not automatically mapped into C<VARCHAR>'s,
will I<transparently> convert C<CHAR> columns to C<VARCHAR> columns if any
non-fixed-size datatype (anything other than a C<CHAR> or numeric types) is
used in or added to the table.  As a general rule, C<VARCHAR> is preferred over
C<CHAR> except when dealing with columns whose values don't vary significantly
in length B<and> are in a table that only contains fixed-size data types
(C<CHAR>'s and numeric types).  Everywhere else, use C<VARCHAR>'s, since that's
what you'll be getting anyway.

A C<binary> attribute is supported, which I<may> indicates that comparisons
with this field should be case-sensitive.  Note that this only works on
databases that actually have a case-sensitive C<CHAR> field - currently, only
MySQL.

=item VARCHAR

The C<VARCHAR> type is identical to the above C<CHAR> type B<except> as
follows.  Unlike a C<CHAR>, a C<VARCHAR> column does not take up C<size> bytes
of storage space - typically the storage space is only slightly larger
(typically 1 byte) than the size of the value stored.  As such, C<VARCHAR>'s
are almost always preferred over columns, except for nearly-constant sized
data, or tables with all fixed-width data types (C<CHAR>'s, C<INT>'s, and
non-C<DECIMAL> numeric types).  C<VARCHAR> columns will not be padded with
whitespace up to C<size>, however trailing whitespace C<may> be trimmed from
values.

As with C<CHAR>, the C<binary> attribute I<may> make the C<VARCHAR> values
case-sensitive for the matching purposes.

=item TEXT

The C<TEXT> type is similar to C<VARCHAR> types, except that they are always
case-insensitive for matching/equality, and can contain longer values.  The
C<TEXT> type takes a C<size> attribute which contains the length required - if
not provided, a value of approximately 2 billion is used.  Note that the
maximum size of the column will usually be larger than the value you specify to
C<size> - it simply indicates to the driver to use a field capable of at least
the size specified.  The values of C<TEXT> fields are case-insensitive in terms
of matches and equality.  The maximum C<size> value, and the default, is
approximately 2 billion.

Certain aliases are provided with implicit size defaults - C<TINYTEXT>,
C<SMALLTEXT>, C<MEDIUMTEXT>, and C<LONGTEXT>, which are equivelant to C<TEXT>
with C<size> values of 255, 65535, 16777215, and 2147483647, respectively.

Depending on the C<size> value, certain databases _may_ use different
underlying types.  MySQL, for example, uses the smallest possible type between
its native C<TINYTEXT>, C<TEXT>, C<MEDIUMTEXT>, and C<LONGTEXT> types.  As
such, it is recommended that you use a sufficiently large C<size> value unless
absolutely sure that you will never need a larger value.

Also note that C<TEXT> types B<do not> support normal equality operations - in
fact, the only portable things that can be done with C<TEXT> columns is C<IS
NULL> tests (in GT::SQL this means "=" C<undef>) and C<LIKE> comparisons - but,
for portability with all supported databases, the argument of a C<LIKE> may not
exceed 4000 characters.

Also note that the C<default> value will be ignored by MySQL, which does not
support having default values on C<TEXT> columns.  Everything else, however,
will properly support this, and the default will still be used when inserting
with GT::SQL even when using MySQL.  Also note that the default value of
C<TEXT> types B<must not> exceed 3998 characters, due to limits imposed by some
databases.  Longer indexes may work in some cases, but are not guaranteed - for
example, a table resync on MSSQL will not work.

=item ENUM

The C<ENUM> type is a MySQL-only type that supports certain fixed string
values.  On non-MySQL databases, it is simply mapped to a C<VARCHAR> column.
It requires a C<values> option which should have a value of an array reference
of string values that the ENUM should permit.  The C<ENUM> type is generally
discouraged in favour of a C<CHAR>, C<VARCHAR>, or an
L<integral type|/"Integer types"> column, all of which provide more flexibility
(i.e. if you want to add a new possible value) and are not a single
database-specific type.

=back

=head2 Date/time types

All of the date/time types support by MySQL will be handled by GT::SQL, for
compatibility reasons.  However, all types other than DATE and C<DATETIME>
should be considered deprecated as cross-database compatibility is not possible
using these types.  In particular, C<TIMESTAMP> will work exactly like a
C<DATETIME> on every non-MySQL database; C<TIME> and C<DATE> will work in
Postgres just like they do in MySQL; under everything else, C<TIME> won't work
at all, and C<DATE> will work like C<DATETIME>.

GT::SQL users are urged to at least consider using an INT column, designed to
contain Perl's time() value, in lieu of any of the Date/time types as it avoids
many problems typically associated with storing local times - such as time zone
issues and non-local databases.  That said, if you are certain you want a
Date/time type, a DATETIME is preferred as it will work (almost) the same
everywhere.

=over 4

=item DATETIME

A date field, which stores values in C<YYYY-MM-DD HH:MM:SS> format (where
C<'HH'> is a 24-hour hour).  Inserted values may omit the seconds
(C<YYYY-MM-DD HH:MM>), or time (C<YYYY-MM-DD>) portions of the value.  Omitted
values will default to C<0>.

Note that C<DATETIME> values returned from a database I<may> include
fractional-second precision values such as C<2004-01-01 12:00:07.123>.
Currently MSSQL and Postgres exhibit this behaviour.  MSSQL's C<DATETIME> type
always includes exactly three decimal digits, while Postgres' C<TIMESTAMP> type,
used for GT::SQL C<DATETIME>'s, stores times with 6 decimal-digit precision.
Unlike MSSQL, however, Postgres will only display decimal digits if a
significant decimal value has been stored in the database.  This happens with
the C<time_check> option, below, and when an explicit fractional second value
has been inserted into the database.

A C<time_check> attribute may be passed with a true value; if set, any update
to the row that doesn't explicitly set the column will have the column updated
to the B<database's> current local time.  Due to issues with times and/or
timezones, this option should be considered deprecated and discouraged - it is
recommended instead that you update the value yourself using a value that
I<your script> thinks is local time (or, better yet, use an C<INT> column with
unix time values (i.e. time() in Perl), which are timezone-independent to begin
with), rather than trying to depend on a database having the same time and time
zone as your script.

=item DATE

Just like C<DATETIME>, except (under MySQL and Postgres) it only stores and
returns the C<YYYY-MM-DD> portion of the value.  Note that when using this
type, care must be taken to extract only the desired portion of the output as
databases other than MySQL and Postgres map this to a C<DATETIME> above, which
returns 'YYYY-MM-DD HH:MM:SS' values (with a possible fractional seconds value,
in the case of MSSQL/Postgres).  Using a C<DATETIME> or C<INT> field is
generally preferred, but this type may be slightly more effecient and take
slightly less space (4 bytes instead of 8 bytes) on MySQL and Postgres
databases.

Like C<DATETIME>, this handles a C<time_check> field, with the same caveats
described in the the C<DATETIME> C<time_check> description.

=back

The alternate, deprecated date/time types supported are listed in the
L</Deprecated types> section below.

=head2 Deprecated types

=over 4

=item BLOB

Limited C<BLOB> support (C<TINYBLOB>, C<BLOB>, C<MEDIUMBLOB>, and C<LONGBLOB>)
existed in older versions of GT::SQL, however the support, where it existed at
all, was partial and incomplete.  Additionally, only certain drivers (MySQL and
Oracle) supported C<BLOB> types at all.  As such, the limited C<BLOB> support
present in old GT::SQL versions is still supported under MySQL and Oracle, but
any new development should avoid them.  If you really need to store binary
data, it is strongly recommended that you use files, and simply store
fileI<names> in the database.

=item TIMESTAMP

This extremely odd MySQL data type, depending on the version of MySQL, stores
times in either the format described in C<DATETIME> (MySQL 4.1+) or an
extremely MySQL-specific C<YYYYMMDDhhmmss> format.  Another MySQL-specific of
this data type is that the first - and ONLY the first - C<TIMESTAMP> column in
a row will be automatically updated to the current local timezone-dependent
date and time.  Use a C<DATETIME> (possibly with the C<time_check> option)
instead.

=item TIME

A MySQL and Postgres-specific type that stores only the time-of-day in
C<HH:MM:SS> format.  Deprecated due to non-portability and incompatibility on
other databases.  If you really want to store just the time of day, either use
an C<INT> to store the minutes or seconds since midnight, or use a C<CHAR>
which you update with the C<HH:MM:SS> value.  Causes a fatal error on databases
which don't have an appropriate native type.

=item YEAR

A particularly useless MySQL-specific data type that stores only the year
portion of a date.  Use a C<SMALLINT> instead.  Causes a fatal error on
anything other than MySQL.

=back

=head1 SEE ALSO

L<GT::SQL>

L<GT::SQL::Creator>

=head1 MAINTAINER

Jason Rhinelander

=head1 COPYRIGHT

Copyright (c) 2004 Gossamer Threads Inc.  All Rights Reserved.
http://www.gossamer-threads.com/

=head1 VERSION

Revision: $Id: Types.pm,v 1.3 2006/05/26 21:56:31 brewt Exp $

=cut
