#@ISA = qw(Exporter);
@ISA = ();
-$VERSION = "0.12";
+$VERSION = "0.13";
=head1 NAME
$DBIx_DBSchema_table_object = $schema->table("table_name");
- @sql = $schema->sql($dsn);
+ @sql = $schema->sql($dbh);
+ @sql = $schema->sql($dsn, $username, $password);
+ @sql = $schema->sql($dsn); #doesn't connect to database - less reliable
$perl_code = $schema->pretty_print;
%hash = eval $perl_code;
}
-=item new_odbc DATABASE_HANDLE || DATA_SOURCE USERNAME PASSWORD [ ATTR ]
+=item new_odbc DATABASE_HANDLE | DATA_SOURCE USERNAME PASSWORD [ ATTR ]
Creates a new DBIx::DBSchema object from an existing data source, which can be
specified by passing an open DBI database handle, or by passing the DBI data
);
}
-=item new_native DATABASE_HANDLE || DATA_SOURCE USERNAME PASSWORD [ ATTR ]
+=item new_native DATABASE_HANDLE | DATA_SOURCE USERNAME PASSWORD [ ATTR ]
Creates a new DBIx::DBSchema object from an existing data source, which can be
specified by passing an open DBI database handle, or by passing the DBI data
$self->{'tables'}->{$table};
}
-=item sql_string [ DATASRC ]
+=item sql [ DATABASE_HANDLE | DATA_SOURCE [ USERNAME PASSWORD [ ATTR ] ] ]
Returns a list of SQL `CREATE' statements for this schema.
-If passed a DBI data source such as `DBI:mysql:database' or
+The data source can be specified by passing an open DBI database handle, or by
+passing the DBI data source name, username and password.
+
+Although the username and password are optional, it is best to call this method
+with a database handle or data source including a valid username and password -
+a DBI connection will be opened and the quoting and type mapping will be more
+reliable.
+
+If passed a DBI data source (or handle) such as `DBI:mysql:database' or
`DBI:Pg:dbname=database', will use syntax specific to that database engine.
Currently supported databases are MySQL and PostgreSQL.
-If not passed a data source, or if there is no driver for the specified
-database, will attempt to use generic SQL syntax.
+If not passed a data source (or handle), or if there is no driver for the
+specified database, will attempt to use generic SQL syntax.
=cut
sub sql {
- my($self, $datasrc) = @_;
- map { $self->table($_)->sql_create_table($datasrc); } $self->tables;
+ my($self, $dbh) = (shift, shift);
+ $dbh = DBI->connect( $dbh, @_ ) or die $DBI::errstr
+ unless ref($dbh) || ! @_;
+ map { $self->table($_)->sql_create_table($dbh); } $self->tables;
}
=item pretty_print
$column = new DBIx::DBSchema::Column ( $name, $sql_type, 'NULL' );
$column = new DBIx::DBSchema::Column ( $name, $sql_type, '', $length );
$column = new DBIx::DBSchema::Column ( $name, $sql_type, 'NULL', $length );
- $column = new DBIx::DBSchema::Column ( $name, $sql_type, 'NULL', $length, $default, $local );
+
+ #named params with a hashref (preferred)
+ $column = new DBIx::DBSchema::Column ( {
+ 'name' => 'column_name',
+ 'type' => 'varchar'
+ 'null' => 'NOT NULL',
+ 'length' => 64,
+ 'default' => '
+ 'local' => '',
+ } );
+
+ #list
+ $column = new DBIx::DBSchema::Column ( $name, $sql_type, $nullability, $length, $default, $local );
+
$name = $column->name;
$column->name( 'name' );
=over 4
-=item new [ NAME [ , SQL_TYPE [ , NULL [ , LENGTH [ , DEFAULT [ , LOCAL ] ] ] ] ] ]
+=item new HASHREF
+
+=item new [ name [ , type [ , null [ , length [ , default [ , local ] ] ] ] ] ]
-Creates a new DBIx::DBSchema::Column object. NAME is the name of the column.
-SQL_TYPE is the SQL data type. NULL is the nullability of the column (the
-empty string is equivalent to `NOT NULL'). LENGTH is the SQL length of the
-column. DEFAULT is the default value of the column. LOCAL is reserved for
-database-specific information.
+Creates a new DBIx::DBSchema::Column object. Takes a hashref of named
+parameters, or a list. B<name> is the name of the column. B<type> is the SQL
+data type. B<null> is the nullability of the column (intrepreted using Perl's
+rules for truth, with one exception: `NOT NULL' is false). B<length> is the
+SQL length of the column. B<default> is the default value of the column.
+B<local> is reserved for database-specific information.
=cut
sub new {
- my($proto,$name,$type,$null,$length,$default,$local)=@_;
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
- #croak "Illegal name: $name" if grep $name eq $_, @reserved_words;
+ my $self;
+ if ( ref($_[0]) ) {
+ $self = shift;
+ } else {
+ $self = { map { $_ => shift } qw(name type null length default local) };
+ }
- $null =~ s/^NOT NULL$//i;
- $null = 'NULL' if $null;
+ #croak "Illegal name: ". $self->{'name'}
+ # if grep $self->{'name'} eq $_, @reserved_words;
- my $class = ref($proto) || $proto;
- my $self = {
- 'name' => $name,
- 'type' => $type,
- 'null' => $null,
- 'length' => $length,
- 'default' => $default,
- 'local' => $local,
- };
+ $self->{'null'} =~ s/^NOT NULL$//i;
+ $self->{'null'} = 'NULL' if $self->{'null'};
bless ($self, $class);
}
}
-=item line [ $datasrc ]
+=item line [ DATABASE_HANDLE | DATA_SOURCE [ USERNAME PASSWORD [ ATTR ] ] ]
Returns an SQL column definition.
-If passed a DBI data source such as `DBI:mysql:database' or
+The data source can be specified by passing an open DBI database handle, or by
+passing the DBI data source name, username and password.
+
+Although the username and password are optional, it is best to call this method
+with a database handle or data source including a valid username and password -
+a DBI connection will be opened and the quoting and type mapping will be more
+reliable.
+
+If passed a DBI data source (or handle) such as `DBI:mysql:database' or
`DBI:Pg:dbname=database', will use syntax specific to that database engine.
Currently supported databases are MySQL and PostgreSQL. Non-standard syntax
for other engines (if applicable) may also be supported in the future.
=cut
sub line {
- my($self,$datasrc)=@_;
+ my($self,$dbh)=@_;
- my $driver = DBIx::DBSchema::_load_driver($datasrc);
- my %typemap = eval "\%DBIx::DBSchema::DBD::${driver}::typemap";
+ my $driver = DBIx::DBSchema::_load_driver($dbh);
+ my %typemap;
+ %typemap = eval "\%DBIx::DBSchema::DBD::${driver}::typemap" if $driver;
my $type = defined( $typemap{uc($self->type)} )
? $typemap{uc($self->type)}
: $self->type;
- my($null)=$self->null;
+ my $null = $self->null;
+
+ my $default = $self->default;
+ if ( defined($default) && default ne ''
+ && ref($dbh)
+ # false laziness: nicked from FS::Record::_quote
+ && ( $default !~ /^\-?\d+(\.\d+)?$/
+ || $type =~ /(char|binary|blob|text)$/i
+ )
+ ) {
+ $default = $dbh->quote($self->default);
+ } else {
+ $default = $self->default;
+ }
- if ( $datasrc =~ /^dbi:mysql:/i ) { #yucky mysql hack
+ #this should be a callback into the driver
+ if ( $driver eq 'mysql' ) { #yucky mysql hack
$null ||= "NOT NULL"
- }
- if ( $datasrc =~ /^dbi:pg/i ) { #yucky Pg hack
+ } elsif ( $driver eq 'Pg' ) { #yucky Pg hack
$null ||= "NOT NULL";
$null =~ s/^NULL$//;
}
$self->name,
$type. ( $self->length ? '('.$self->length.')' : '' ),
$null,
- ( ( defined($self->default) && $self->default ne '' )
- ? 'DEFAULT '. $self->default
+ ( ( defined($default) && $default ne '' )
+ ? 'DEFAULT '. $default
: ''
),
- ( ( $datasrc =~ /^dbi:mysql:/i )
+ ( ( $driver eq 'mysql' )
? $self->local
: ''
),
$dbix_dbschema_column_object = $table->column("column");
- @sql_statements = $table->sql_create_table;
+ #preferred
+ @sql_statements = $table->sql_create_table $dbh;
+ @sql_statements = $table->sql_create_table $datasrc, $username, $password;
+
+ #possible problems
@sql_statements = $table->sql_create_table $datasrc;
+ @sql_statements = $table->sql_create_table;
=head1 DESCRIPTION
$self->{'columns'}->{$column};
}
-=item sql_create_table [ DATASRC ]
+=item sql_create_table [ DATABASE_HANDLE | DATA_SOURCE [ USERNAME PASSWORD [ ATTR ] ] ]
Returns a list of SQL statments to create this table.
-If passed a DBI data source such as `DBI:mysql:database', will use
+The data source can be specified by passing an open DBI database handle, or by
+passing the DBI data source name, username and password.
+
+Although the username and password are optional, it is best to call this method
+with a database handle or data source including a valid username and password -
+a DBI connection will be opened and the quoting and type mapping will be more
+reliable.
+
+If passed a DBI data source (or handle) such as `DBI:mysql:database', will use
MySQL-specific syntax. PostgreSQL is also supported (requires no special
syntax). Non-standard syntax for other engines (if applicable) may also be
supported in the future.
=cut
sub sql_create_table {
- my($self,$datasrc)=@_;
- my(@columns)=map { $self->column($_)->line($datasrc) } $self->columns;
+ my($self, $dbh) = (shift, shift);
+ $dbh = DBI->connect( $dbh, @_ ) or die $DBI::errstr
+ unless ref($dbh) || ! @_;
+
+ #false laziness: nicked from DBSchema::_load_driver
+ my $driver;
+ if ( ref($dbh) ) {
+ $driver = $dbh->{Driver}->{Name};
+ } else {
+ $dbh =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i #nicked from DBI->connect
+ or '' =~ /()/; # ensure $1 etc are empty if match fails
+ $driver = $1 or die "can't parse data source: $dbh";
+ }
+ #eofalse
+
+ my(@columns)=map { $self->column($_)->line($dbh) } $self->columns;
push @columns, "PRIMARY KEY (". $self->primary_key. ")"
if $self->primary_key;
- if ( $datasrc =~ /^dbi:mysql:/i ) { #yucky mysql hack
+ if ( $driver eq 'mysql' ) { #yucky mysql hack
push @columns, map "UNIQUE ($_)", $self->unique->sql_list;
push @columns, map "INDEX ($_)", $self->index->sql_list;
}