1 package DBIx::Class::Storage::DBI;
2 # -*- mode: cperl; cperl-indent-level: 2 -*-
4 use base 'DBIx::Class::Storage';
9 use SQL::Abstract::Limit;
10 use DBIx::Class::Storage::DBI::Cursor;
11 use DBIx::Class::Storage::Statistics;
13 use Carp::Clan qw/DBIx::Class/;
16 package DBIC::SQL::Abstract; # Would merge upstream, but nate doesn't reply :(
18 use base qw/SQL::Abstract::Limit/;
21 my ($self, $table, $fields, $where, $order, @rest) = @_;
22 $table = $self->_quote($table) unless ref($table);
23 @rest = (-1) unless defined $rest[0];
24 die "LIMIT 0 Does Not Compute" if $rest[0] == 0;
25 # and anyway, SQL::Abstract::Limit will cause a barf if we don't first
26 local $self->{having_bind} = [];
27 my ($sql, @ret) = $self->SUPER::select(
28 $table, $self->_recurse_fields($fields), $where, $order, @rest
30 return wantarray ? ($sql, @ret, @{$self->{having_bind}}) : $sql;
36 $table = $self->_quote($table) unless ref($table);
37 $self->SUPER::insert($table, @_);
43 $table = $self->_quote($table) unless ref($table);
44 $self->SUPER::update($table, @_);
50 $table = $self->_quote($table) unless ref($table);
51 $self->SUPER::delete($table, @_);
57 return $_[1].$self->_order_by($_[2]);
59 return $self->SUPER::_emulate_limit(@_);
64 my ($self, $fields) = @_;
65 my $ref = ref $fields;
66 return $self->_quote($fields) unless $ref;
67 return $$fields if $ref eq 'SCALAR';
69 if ($ref eq 'ARRAY') {
70 return join(', ', map { $self->_recurse_fields($_) } @$fields);
71 } elsif ($ref eq 'HASH') {
72 foreach my $func (keys %$fields) {
73 return $self->_sqlcase($func)
74 .'( '.$self->_recurse_fields($fields->{$func}).' )';
83 if (ref $_[0] eq 'HASH') {
84 if (defined $_[0]->{group_by}) {
85 $ret = $self->_sqlcase(' group by ')
86 .$self->_recurse_fields($_[0]->{group_by});
88 if (defined $_[0]->{having}) {
90 ($frag, @extra) = $self->_recurse_where($_[0]->{having});
91 push(@{$self->{having_bind}}, @extra);
92 $ret .= $self->_sqlcase(' having ').$frag;
94 if (defined $_[0]->{order_by}) {
95 $ret .= $self->SUPER::_order_by($_[0]->{order_by});
97 } elsif(ref $_[0] eq 'SCALAR') {
98 $ret = $self->_sqlcase(' order by ').${ $_[0] };
100 $ret = $self->SUPER::_order_by(@_);
105 sub _order_directions {
106 my ($self, $order) = @_;
107 $order = $order->{order_by} if ref $order eq 'HASH';
108 return $self->SUPER::_order_directions($order);
112 my ($self, $from) = @_;
113 if (ref $from eq 'ARRAY') {
114 return $self->_recurse_from(@$from);
115 } elsif (ref $from eq 'HASH') {
116 return $self->_make_as($from);
118 return $from; # would love to quote here but _table ends up getting called
119 # twice during an ->select without a limit clause due to
120 # the way S::A::Limit->select works. should maybe consider
121 # bypassing this and doing S::A::select($self, ...) in
122 # our select method above. meantime, quoting shims have
123 # been added to select/insert/update/delete here
128 my ($self, $from, @join) = @_;
130 push(@sqlf, $self->_make_as($from));
131 foreach my $j (@join) {
134 # check whether a join type exists
135 my $join_clause = '';
136 my $to_jt = ref($to) eq 'ARRAY' ? $to->[0] : $to;
137 if (ref($to_jt) eq 'HASH' and exists($to_jt->{-join_type})) {
138 $join_clause = ' '.uc($to_jt->{-join_type}).' JOIN ';
140 $join_clause = ' JOIN ';
142 push(@sqlf, $join_clause);
144 if (ref $to eq 'ARRAY') {
145 push(@sqlf, '(', $self->_recurse_from(@$to), ')');
147 push(@sqlf, $self->_make_as($to));
149 push(@sqlf, ' ON ', $self->_join_condition($on));
151 return join('', @sqlf);
155 my ($self, $from) = @_;
156 return join(' ', map { (ref $_ eq 'SCALAR' ? $$_ : $self->_quote($_)) }
157 reverse each %{$self->_skip_options($from)});
161 my ($self, $hash) = @_;
163 $clean_hash->{$_} = $hash->{$_}
164 for grep {!/^-/} keys %$hash;
168 sub _join_condition {
169 my ($self, $cond) = @_;
170 if (ref $cond eq 'HASH') {
173 my $x = '= '.$self->_quote($cond->{$_}); $j{$_} = \$x;
175 return $self->_recurse_where(\%j);
176 } elsif (ref $cond eq 'ARRAY') {
177 return join(' OR ', map { $self->_join_condition($_) } @$cond);
179 die "Can't handle this yet!";
184 my ($self, $label) = @_;
185 return '' unless defined $label;
186 return "*" if $label eq '*';
187 return $label unless $self->{quote_char};
188 if(ref $self->{quote_char} eq "ARRAY"){
189 return $self->{quote_char}->[0] . $label . $self->{quote_char}->[1]
190 if !defined $self->{name_sep};
191 my $sep = $self->{name_sep};
192 return join($self->{name_sep},
193 map { $self->{quote_char}->[0] . $_ . $self->{quote_char}->[1] }
194 split(/\Q$sep\E/,$label));
196 return $self->SUPER::_quote($label);
202 $_[0] =~ s/SELECT (.*?) FROM/
203 'SELECT '.join(', ', map { $_.' AS col'.++$c } split(', ', $1)).' FROM'/e;
204 $self->SUPER::_RowNum(@_);
209 $self->{limit_dialect} = shift if @_;
210 return $self->{limit_dialect};
215 $self->{quote_char} = shift if @_;
216 return $self->{quote_char};
221 $self->{name_sep} = shift if @_;
222 return $self->{name_sep};
225 } # End of BEGIN block
227 use base qw/DBIx::Class/;
229 __PACKAGE__->load_components(qw/AccessorGroup/);
231 __PACKAGE__->mk_group_accessors('simple' =>
232 qw/_connect_info _dbh _sql_maker _conn_pid _conn_tid debug debugobj
233 cursor on_connect_do transaction_depth/);
240 my $new = bless({}, ref $_[0] || $_[0]);
241 $new->cursor("DBIx::Class::Storage::DBI::Cursor");
242 $new->transaction_depth(0);
244 $new->debugobj(new DBIx::Class::Storage::Statistics());
247 if (defined($ENV{DBIX_CLASS_STORAGE_DBI_DEBUG}) &&
248 ($ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} =~ /=(.+)$/)) {
249 $fh = IO::File->new($1, 'w')
250 or $new->throw_exception("Cannot open trace file $1");
252 $fh = IO::File->new('>&STDERR');
255 $new->debug(1) if $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG};
259 =head2 throw_exception
261 Throws an exception - croaks.
265 sub throw_exception {
266 my ($self, $msg) = @_;
272 DBIx::Class::Storage::DBI - DBI storage handler
278 This class represents the connection to the database
286 The arguments of C<connect_info> are always a single array reference.
288 This is normally accessed via L<DBIx::Class::Schema/connection>, which
289 encapsulates its argument list in an arrayref before calling
290 C<connect_info> here.
292 The arrayref can either contain the same set of arguments one would
293 normally pass to L<DBI/connect>, or a lone code reference which returns
294 a connected database handle.
296 In either case, there is an optional final element within the arrayref
297 which can hold a hashref of connection-specific Storage::DBI options.
298 These include C<on_connect_do>, and the sql_maker options
299 C<limit_dialect>, C<quote_char>, and C<name_sep>. Examples:
301 ->connect_info([ 'dbi:SQLite:./foo.db' ]);
303 ->connect_info([ sub { DBI->connect(...) } ]);
311 { quote_char => q{`}, name_sep => q{@} },
317 sub { DBI->connect(...) },
318 { quote_char => q{`}, name_sep => q{@} },
324 Executes the sql statements given as a listref on every db connect.
326 This option can also be set via L</connect_info>.
330 Causes SQL trace information to be emitted on the C<debugobj> object.
331 (or C<STDERR> if C<debugobj> has not specifically been set).
335 Set or retrieve the filehandle used for trace/debug output. This should be
336 an IO::Handle compatible ojbect (only the C<print> method is used. Initially
337 set to be STDERR - although see information on the
338 L<DBIX_CLASS_STORAGE_DBI_DEBUG> environment variable.
345 if ($self->debugobj->can('debugfh')) {
346 return $self->debugobj->debugfh(@_);
352 Sets or retrieves the object used for metric collection. Defaults to an instance
353 of L<DBIx::Class::Storage::Statistics> that is campatible with the original
354 method of using a coderef as a callback. See the aforementioned Statistics
355 class for more information.
359 Sets a callback to be executed each time a statement is run; takes a sub
360 reference. Callback is executed as $sub->($op, $info) where $op is
361 SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed.
363 See L<debugobj> for a better way.
370 if ($self->debugobj->can('callback')) {
371 return $self->debugobj->callback(@_);
377 Disconnect the L<DBI> handle, performing a rollback first if the
378 database is not in C<AutoCommit> mode.
385 if( $self->connected ) {
386 $self->_dbh->rollback unless $self->_dbh->{AutoCommit};
387 $self->_dbh->disconnect;
394 Check if the L<DBI> handle is connected. Returns true if the handle
399 sub connected { my ($self) = @_;
401 if(my $dbh = $self->_dbh) {
402 if(defined $self->_conn_tid && $self->_conn_tid != threads->tid) {
403 $self->_sql_maker(undef);
404 return $self->_dbh(undef);
406 elsif($self->_conn_pid != $$) {
407 $self->_dbh->{InactiveDestroy} = 1;
408 $self->_sql_maker(undef);
409 return $self->_dbh(undef)
411 return ($dbh->FETCH('Active') && $dbh->ping);
417 =head2 ensure_connected
419 Check whether the database handle is connected - if not then make a
424 sub ensure_connected {
427 unless ($self->connected) {
428 $self->_populate_dbh;
434 Returns the dbh - a data base handle of class L<DBI>.
441 $self->ensure_connected;
445 sub _sql_maker_args {
448 return ( limit_dialect => $self->dbh );
453 Returns a C<sql_maker> object - normally an object of class
454 C<DBIC::SQL::Abstract>.
460 unless ($self->_sql_maker) {
461 $self->_sql_maker(new DBIC::SQL::Abstract( $self->_sql_maker_args ));
463 return $self->_sql_maker;
467 my ($self, $info_arg) = @_;
470 my $info = [ @$info_arg ]; # copy because we can alter it
471 my $last_info = $info->[-1];
472 if(ref $last_info eq 'HASH') {
474 if(my $on_connect_do = $last_info->{on_connect_do}) {
476 $self->on_connect_do($on_connect_do);
478 for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) {
479 if(my $opt_val = $last_info->{$sql_maker_opt}) {
481 $self->sql_maker->$sql_maker_opt($opt_val);
485 # remove our options hashref if it was there, to avoid confusing
486 # DBI in the case the user didn't use all 4 DBI options, as in:
487 # [ 'dbi:SQLite:foo.db', { quote_char => q{`} } ]
488 pop(@$info) if $used;
491 $self->_connect_info($info);
494 $self->_connect_info;
499 my @info = @{$self->_connect_info || []};
500 $self->_dbh($self->_connect(@info));
502 if(ref $self eq 'DBIx::Class::Storage::DBI') {
503 my $driver = $self->_dbh->{Driver}->{Name};
504 eval "require DBIx::Class::Storage::DBI::${driver}";
506 bless $self, "DBIx::Class::Storage::DBI::${driver}";
507 $self->_rebless() if $self->can('_rebless');
511 # if on-connect sql statements are given execute them
512 foreach my $sql_statement (@{$self->on_connect_do || []}) {
513 $self->debugobj->query_start($sql_statement) if $self->debug();
514 $self->_dbh->do($sql_statement);
515 $self->debugobj->query_end($sql_statement) if $self->debug();
518 $self->_conn_pid($$);
519 $self->_conn_tid(threads->tid) if $INC{'threads.pm'};
523 my ($self, @info) = @_;
525 $self->throw_exception("You failed to provide any connection info")
528 my ($old_connect_via, $dbh);
530 if ($INC{'Apache/DBI.pm'} && $ENV{MOD_PERL}) {
531 $old_connect_via = $DBI::connect_via;
532 $DBI::connect_via = 'connect';
536 $dbh = ref $info[0] eq 'CODE'
538 : DBI->connect(@info);
541 $DBI::connect_via = $old_connect_via if $old_connect_via;
544 $self->throw_exception("DBI Connection failed: " . ($@ || $DBI::errstr));
552 Calls begin_work on the current dbh.
554 See L<DBIx::Class::Schema> for the txn_do() method, which allows for
555 an entire code block to be executed transactionally.
561 if ($self->{transaction_depth}++ == 0) {
562 my $dbh = $self->dbh;
563 if ($dbh->{AutoCommit}) {
564 $self->debugobj->txn_begin()
573 Issues a commit against the current dbh.
579 my $dbh = $self->dbh;
580 if ($self->{transaction_depth} == 0) {
581 unless ($dbh->{AutoCommit}) {
582 $self->debugobj->txn_commit()
588 if (--$self->{transaction_depth} == 0) {
589 $self->debugobj->txn_commit()
598 Issues a rollback against the current dbh. A nested rollback will
599 throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
600 which allows the rollback to propagate to the outermost transaction.
608 my $dbh = $self->dbh;
609 if ($self->{transaction_depth} == 0) {
610 unless ($dbh->{AutoCommit}) {
611 $self->debugobj->txn_rollback()
617 if (--$self->{transaction_depth} == 0) {
618 $self->debugobj->txn_rollback()
623 die DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->new;
630 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
631 $error =~ /$exception_class/ and $self->throw_exception($error);
632 $self->{transaction_depth} = 0; # ensure that a failed rollback
633 $self->throw_exception($error); # resets the transaction depth
638 my ($self, $op, $extra_bind, $ident, @args) = @_;
639 my ($sql, @bind) = $self->sql_maker->$op($ident, @args);
640 unshift(@bind, @$extra_bind) if $extra_bind;
642 my @debug_bind = map { defined $_ ? qq{'$_'} : q{'NULL'} } @bind;
643 $self->debugobj->query_start($sql, @debug_bind);
645 my $sth = eval { $self->sth($sql,$op) };
648 $self->throw_exception(
649 'no sth generated via sql (' . ($@ || $self->_dbh->errstr) . "): $sql"
652 @bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
656 $rv = eval { $sth->execute(@bind) };
659 $self->throw_exception("Error executing '$sql': ".($@ || $sth->errstr));
662 $self->throw_exception("'$sql' did not generate a statement.");
665 my @debug_bind = map { defined $_ ? qq{`$_'} : q{`NULL'} } @bind;
666 $self->debugobj->query_end($sql, @debug_bind);
668 return (wantarray ? ($rv, $sth, @bind) : $rv);
672 my ($self, $ident, $to_insert) = @_;
673 $self->throw_exception(
674 "Couldn't insert ".join(', ',
675 map "$_ => $to_insert->{$_}", keys %$to_insert
677 ) unless ($self->_execute('insert' => [], $ident, $to_insert));
682 return shift->_execute('update' => [], @_);
686 return shift->_execute('delete' => [], @_);
690 my ($self, $ident, $select, $condition, $attrs) = @_;
691 my $order = $attrs->{order_by};
692 if (ref $condition eq 'SCALAR') {
693 $order = $1 if $$condition =~ s/ORDER BY (.*)$//i;
695 if (exists $attrs->{group_by} || $attrs->{having}) {
697 group_by => $attrs->{group_by},
698 having => $attrs->{having},
699 ($order ? (order_by => $order) : ())
702 my @args = ('select', $attrs->{bind}, $ident, $select, $condition, $order);
703 if ($attrs->{software_limit} ||
704 $self->sql_maker->_default_limit_syntax eq "GenericSubQ") {
705 $attrs->{software_limit} = 1;
707 $self->throw_exception("rows attribute must be positive if present")
708 if (defined($attrs->{rows}) && !($attrs->{rows} > 0));
709 push @args, $attrs->{rows}, $attrs->{offset};
711 return $self->_execute(@args);
716 Handle a SQL select statement.
722 my ($ident, $select, $condition, $attrs) = @_;
723 return $self->cursor->new($self, \@_, $attrs);
728 Performs a select, fetch and return of data - handles a single row
733 # Need to call finish() to work round broken DBDs
737 my ($rv, $sth, @bind) = $self->_select(@_);
738 my @row = $sth->fetchrow_array;
745 Returns a L<DBI> sth (statement handle) for the supplied SQL.
750 my ($self, $sql) = @_;
751 # 3 is the if_active parameter which avoids active sth re-use
752 return $self->dbh->prepare_cached($sql, {}, 3);
755 =head2 columns_info_for
757 Returns database type info for a given table columns.
761 sub columns_info_for {
762 my ($self, $table) = @_;
764 my $dbh = $self->dbh;
766 if ($dbh->can('column_info')) {
768 my $old_raise_err = $dbh->{RaiseError};
769 my $old_print_err = $dbh->{PrintError};
770 $dbh->{RaiseError} = 1;
771 $dbh->{PrintError} = 0;
773 my ($schema,$tab) = $table =~ /^(.+?)\.(.+)$/ ? ($1,$2) : (undef,$table);
774 my $sth = $dbh->column_info( undef,$schema, $tab, '%' );
776 while ( my $info = $sth->fetchrow_hashref() ){
778 $column_info{data_type} = $info->{TYPE_NAME};
779 $column_info{size} = $info->{COLUMN_SIZE};
780 $column_info{is_nullable} = $info->{NULLABLE} ? 1 : 0;
781 $column_info{default_value} = $info->{COLUMN_DEF};
782 my $col_name = $info->{COLUMN_NAME};
783 $col_name =~ s/^\"(.*)\"$/$1/;
785 $result{$col_name} = \%column_info;
788 $dbh->{RaiseError} = $old_raise_err;
789 $dbh->{PrintError} = $old_print_err;
790 return \%result if !$@;
794 my $sth = $dbh->prepare("SELECT * FROM $table WHERE 1=0");
796 my @columns = @{$sth->{NAME_lc}};
797 for my $i ( 0 .. $#columns ){
799 my $type_num = $sth->{TYPE}->[$i];
801 if(defined $type_num && $dbh->can('type_info')) {
802 my $type_info = $dbh->type_info($type_num);
803 $type_name = $type_info->{TYPE_NAME} if $type_info;
805 $column_info{data_type} = $type_name ? $type_name : $type_num;
806 $column_info{size} = $sth->{PRECISION}->[$i];
807 $column_info{is_nullable} = $sth->{NULLABLE}->[$i] ? 1 : 0;
809 if ($column_info{data_type} =~ m/^(.*?)\((.*?)\)$/) {
810 $column_info{data_type} = $1;
811 $column_info{size} = $2;
814 $result{$columns[$i]} = \%column_info;
820 =head2 last_insert_id
822 Return the row id of the last insert.
827 my ($self, $row) = @_;
829 return $self->dbh->func('last_insert_rowid');
835 Returns the database driver name.
839 sub sqlt_type { shift->dbh->{Driver}->{Name} }
841 =head2 create_ddl_dir (EXPERIMENTAL)
845 =item Arguments: $schema \@databases, $version, $directory, $sqlt_args
849 Creates an SQL file based on the Schema, for each of the specified
850 database types, in the given directory.
852 Note that this feature is currently EXPERIMENTAL and may not work correctly
853 across all databases, or fully handle complex relationships.
859 my ($self, $schema, $databases, $version, $dir, $sqltargs) = @_;
861 if(!$dir || !-d $dir)
863 warn "No directory given, using ./\n";
866 $databases ||= ['MySQL', 'SQLite', 'PostgreSQL'];
867 $databases = [ $databases ] if(ref($databases) ne 'ARRAY');
868 $version ||= $schema->VERSION || '1.x';
870 eval "use SQL::Translator";
871 $self->throw_exception("Can't deploy without SQL::Translator: $@") if $@;
873 my $sqlt = SQL::Translator->new({
877 foreach my $db (@$databases)
880 $sqlt->parser('SQL::Translator::Parser::DBIx::Class');
881 # $sqlt->parser_args({'DBIx::Class' => $schema);
882 $sqlt->data($schema);
883 $sqlt->producer($db);
886 my $filename = $schema->ddl_filename($db, $dir, $version);
889 $self->throw_exception("$filename already exists, skipping $db");
892 open($file, ">$filename")
893 or $self->throw_exception("Can't open $filename for writing ($!)");
894 my $output = $sqlt->translate;
896 # print join(":", keys %{$schema->source_registrations});
897 # print Dumper($sqlt->schema);
900 $self->throw_exception("Failed to translate to $db. (" . $sqlt->error . ")");
909 =head2 deployment_statements
911 Create the statements for L</deploy> and
912 L<DBIx::Class::Schema/deploy>.
916 sub deployment_statements {
917 my ($self, $schema, $type, $version, $dir, $sqltargs) = @_;
918 $type ||= $self->sqlt_type;
919 $version ||= $schema->VERSION || '1.x';
921 eval "use SQL::Translator";
924 eval "use SQL::Translator::Parser::DBIx::Class;";
925 $self->throw_exception($@) if $@;
926 eval "use SQL::Translator::Producer::${type};";
927 $self->throw_exception($@) if $@;
928 my $tr = SQL::Translator->new(%$sqltargs);
929 SQL::Translator::Parser::DBIx::Class::parse( $tr, $schema );
930 return "SQL::Translator::Producer::${type}"->can('produce')->($tr);
933 my $filename = $schema->ddl_filename($type, $dir, $version);
936 # $schema->create_ddl_dir([ $type ], $version, $dir, $sqltargs);
937 $self->throw_exception("No SQL::Translator, and no Schema file found, aborting deploy");
941 open($file, "<$filename")
942 or $self->throw_exception("Can't open $filename ($!)");
946 return join('', @rows);
952 Sends the appropriate statements to create or modify tables to the
953 db. This would normally be called through
954 L<DBIx::Class::Schema/deploy>.
959 my ($self, $schema, $type, $sqltargs) = @_;
960 foreach my $statement ( $self->deployment_statements($schema, $type, undef, undef, $sqltargs) ) {
961 for ( split(";\n", $statement)) {
962 next if($_ =~ /^--/);
964 # next if($_ =~ /^DROP/m);
965 next if($_ =~ /^BEGIN TRANSACTION/m);
966 next if($_ =~ /^COMMIT/m);
967 $self->debugobj->query_begin($_) if $self->debug;
968 $self->dbh->do($_) or warn "SQL was:\n $_";
969 $self->debugobj->query_end($_) if $self->debug;
974 =head2 datetime_parser
976 Returns the datetime parser class
980 sub datetime_parser {
982 return $self->{datetime_parser} ||= $self->build_datetime_parser(@_);
985 =head2 datetime_parser_type
987 Defines (returns) the datetime parser class - currently hardwired to
988 L<DateTime::Format::MySQL>
992 sub datetime_parser_type { "DateTime::Format::MySQL"; }
994 =head2 build_datetime_parser
996 See L</datetime_parser>
1000 sub build_datetime_parser {
1002 my $type = $self->datetime_parser_type(@_);
1004 $self->throw_exception("Couldn't load ${type}: $@") if $@;
1008 sub DESTROY { shift->disconnect }
1014 The module defines a set of methods within the DBIC::SQL::Abstract
1015 namespace. These build on L<SQL::Abstract::Limit> to provide the
1016 SQL query functions.
1018 The following methods are extended:-
1032 Accessor for setting limit dialect. This is useful
1033 for JDBC-bridge among others where the remote SQL-dialect cannot
1034 be determined by the name of the driver alone.
1036 This option can also be set via L</connect_info>.
1040 Specifies what characters to use to quote table and column names. If
1041 you use this you will want to specify L<name_sep> as well.
1043 quote_char expectes either a single character, in which case is it is placed
1044 on either side of the table/column, or an arrayref of length 2 in which case the
1045 table/column name is placed between the elements.
1047 For example under MySQL you'd use C<quote_char('`')>, and user SQL Server you'd
1048 use C<quote_char(qw/[ ]/)>.
1050 This option can also be set via L</connect_info>.
1054 This only needs to be used in conjunction with L<quote_char>, and is used to
1055 specify the charecter that seperates elements (schemas, tables, columns) from
1056 each other. In most cases this is simply a C<.>.
1058 This option can also be set via L</connect_info>.
1062 =head1 ENVIRONMENT VARIABLES
1064 =head2 DBIX_CLASS_STORAGE_DBI_DEBUG
1066 If C<DBIX_CLASS_STORAGE_DBI_DEBUG> is set then SQL trace information
1067 is produced (as when the L<debug> method is set).
1069 If the value is of the form C<1=/path/name> then the trace output is
1070 written to the file C</path/name>.
1072 This environment variable is checked when the storage object is first
1073 created (when you call connect on your schema). So, run-time changes
1074 to this environment variable will not take effect unless you also
1075 re-connect on your schema.
1079 Matt S. Trout <mst@shadowcatsystems.co.uk>
1081 Andy Grundman <andy@hybridized.org>
1085 You may distribute this code under the same terms as Perl itself.