line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
1
|
|
|
1
|
|
80298
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
43
|
|
2
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
46
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Class::DBI::MSSQL; |
5
|
1
|
|
|
1
|
|
5
|
use base qw(Class::DBI); |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1464
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.122'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Class::DBI::MSSQL - Class::DBI for MSSQL |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 VERSION |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
version 0.122 |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
$Id: /my/cs/projects/cdbi-mssql/trunk/lib/Class/DBI/MSSQL.pm 27829 2006-11-11T04:02:42.956483Z rjbs $ |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 SYNOPSIS |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
use base qw(Class::DBI::MSSQL); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# lots of normal-looking CDBI code |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 DESCRIPTION |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
This is just a simple subclass of Class::DBI; it makes Class::DBI play nicely |
28
|
|
|
|
|
|
|
with MSSQL, at least if DBD::ODBC is providing the connection. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
Here are the things it changes: |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=over 4 |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=item * use C |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=item * use C for C |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=back |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
It also implements some metadata methods, described below. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=cut |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub _auto_increment_value { |
45
|
0
|
|
|
0
|
|
|
my $self = shift; |
46
|
0
|
|
|
|
|
|
my $dbh = $self->db_Main; |
47
|
|
|
|
|
|
|
|
48
|
0
|
|
|
|
|
|
my ($id) = $dbh->selectrow_array('SELECT @@IDENTITY'); |
49
|
0
|
0
|
|
|
|
|
$self->_croak("Can't get last insert id") unless defined $id; |
50
|
0
|
|
|
|
|
|
return $id; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub _insert_row { |
54
|
0
|
|
|
0
|
|
|
my $self = shift; |
55
|
0
|
|
|
|
|
|
my $data = shift; |
56
|
0
|
0
|
|
|
|
|
if (keys %$data) { |
57
|
0
|
|
|
|
|
|
return $self->SUPER::_insert_row($data); |
58
|
|
|
|
|
|
|
} else { |
59
|
0
|
|
|
|
|
|
eval { |
60
|
0
|
|
|
|
|
|
my $sth = $self->sql_MakeNewEmptyObj(); |
61
|
0
|
|
|
|
|
|
$sth->execute; |
62
|
0
|
|
|
|
|
|
my @primary_columns = $self->primary_columns; |
63
|
0
|
0
|
0
|
|
|
|
$data->{ $primary_columns[0] } = $self->_auto_increment_value |
64
|
|
|
|
|
|
|
if @primary_columns == 1 |
65
|
|
|
|
|
|
|
&& !defined $data->{ $primary_columns[0] }; |
66
|
|
|
|
|
|
|
}; |
67
|
0
|
0
|
|
|
|
|
if ($@) { |
68
|
0
|
|
|
|
|
|
my $class = ref $self; |
69
|
0
|
|
|
|
|
|
return $self->_croak( |
70
|
|
|
|
|
|
|
"Can't insert new $class: $@", |
71
|
|
|
|
|
|
|
err => $@, |
72
|
|
|
|
|
|
|
method => 'create' |
73
|
|
|
|
|
|
|
); |
74
|
|
|
|
|
|
|
} |
75
|
0
|
|
|
|
|
|
return 1; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
__PACKAGE__->set_sql(MakeNewEmptyObj => 'INSERT INTO __TABLE__ DEFAULT VALUES'); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head1 METHODS |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head2 C<< set_up_table($table_name) >> |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
This method sets up the columns from the named table by querying MSSQL's |
86
|
|
|
|
|
|
|
C metadata tables. It will set up the key(s) as Primary |
87
|
|
|
|
|
|
|
and all other columns as Essential. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=cut |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
__PACKAGE__->set_sql(desc_table => <<'SQL'); |
92
|
|
|
|
|
|
|
SELECT col.table_name, col.column_name, col.data_type, ccu.constraint_name |
93
|
|
|
|
|
|
|
FROM information_schema.columns col |
94
|
|
|
|
|
|
|
LEFT JOIN information_schema.constraint_column_usage ccu |
95
|
|
|
|
|
|
|
ON col.table_catalog = ccu.table_catalog |
96
|
|
|
|
|
|
|
AND col.table_schema = ccu.table_schema |
97
|
|
|
|
|
|
|
AND col.table_name = ccu.table_name |
98
|
|
|
|
|
|
|
AND col.column_name = ccu.column_name |
99
|
|
|
|
|
|
|
WHERE (col.table_name = '__TABLE__') |
100
|
|
|
|
|
|
|
SQL |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub set_up_table { |
103
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
104
|
0
|
|
0
|
|
|
|
$class->table(shift || $class->table); |
105
|
0
|
|
|
|
|
|
(my $sth = $class->sql_desc_table)->execute; |
106
|
0
|
|
|
|
|
|
my (@cols, @pri); |
107
|
0
|
|
|
|
|
|
while (my $hash = $sth->fetch_hash) { |
108
|
0
|
|
|
|
|
|
my ($col) = $hash->{column_name} =~ /(\w+)/; |
109
|
0
|
0
|
|
|
|
|
if($hash->{constraint_name} =~ /^PK_/) { |
110
|
0
|
|
|
|
|
|
push @pri, $col; |
111
|
|
|
|
|
|
|
} else { |
112
|
0
|
|
|
|
|
|
push @cols, $col; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
0
|
0
|
|
|
|
|
$class->_croak($class->table, " has no primary key") unless @pri; |
116
|
0
|
|
|
|
|
|
$class->columns(Primary => @pri); |
117
|
0
|
|
|
|
|
|
$class->columns(Essential => @cols); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head2 C<< column_type($column_name) >> |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
This returns the named column's datatype. |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=cut |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub _column_info { |
127
|
0
|
|
|
0
|
|
|
my $self = shift; |
128
|
0
|
|
|
|
|
|
my $dbh = $self->db_Main; |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
(my $sth = $self->sql_desc_table)->execute; |
131
|
0
|
|
|
|
|
|
return { map { $_->{column_name} => $_ } $sth->fetchall_hash }; |
|
0
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub column_type { |
135
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
136
|
0
|
0
|
|
|
|
|
my $col = shift or Carp::croak "Need a column for column_type"; |
137
|
0
|
|
|
|
|
|
return $class->_column_info->{$col}->{data_type}; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=head2 C<< autoinflate($type => $class) >> |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
This will automatically set up has_a() relationships for all columns of |
143
|
|
|
|
|
|
|
the specified type to the given class. If the type is "dates" it will apply to |
144
|
|
|
|
|
|
|
both datetime and smalldatetime columns. If the class is Time::Piece, |
145
|
|
|
|
|
|
|
Time::Piece::MSSQL will be required. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
We currently assume that all classess passed will be able to inflate |
148
|
|
|
|
|
|
|
and deflate without needing extra has_a arguments. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=cut |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub autoinflate { |
153
|
0
|
|
|
0
|
1
|
|
my ($class, %how) = @_; |
154
|
0
|
|
0
|
|
|
|
$how{$_} ||= $how{dates} for qw/datetime smalldatetime/; |
155
|
0
|
|
|
|
|
|
my $info = $class->_column_info; |
156
|
0
|
|
|
|
|
|
foreach my $col (keys %$info) { |
157
|
0
|
|
|
|
|
|
(my $type = $info->{$col}->{type}) =~ s/\W.*//; |
158
|
0
|
0
|
|
|
|
|
next unless $how{$type}; |
159
|
0
|
|
|
|
|
|
my %args; |
160
|
0
|
0
|
|
|
|
|
if ($how{$type} eq "Time::Piece") { |
161
|
0
|
|
|
|
|
|
eval "use Time::Piece::MSSQL"; |
162
|
0
|
0
|
|
|
|
|
$class->_croak($@) if $@; |
163
|
0
|
|
|
|
|
|
$args{inflate} = "from_mssql_$type"; |
164
|
0
|
|
|
|
|
|
$args{deflate} = "mssql_$type"; |
165
|
|
|
|
|
|
|
} |
166
|
0
|
|
|
|
|
|
$class->has_a($col => $how{$type}, %args); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head1 WARNINGS |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
For one thing, there are no useful tests in this distribution. I'll take care |
174
|
|
|
|
|
|
|
of that, but right now this is all taken care of in the tests I've written for |
175
|
|
|
|
|
|
|
subclasses of this class, and I don't have a lot of motivation to write new |
176
|
|
|
|
|
|
|
tests just for this package. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
Class::DBI's C<_init> sub has a line that reads as follows: |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
if (@primary_columns == grep defined, @{$data}{@primary_columns}) { |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
This will cause the primary key columns to autovivify as I, which will |
183
|
|
|
|
|
|
|
make inserts fail under MSSQL. You should change that line to the following, |
184
|
|
|
|
|
|
|
which will fix the behavior. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
if (@$data{@primary_columns} |
187
|
|
|
|
|
|
|
and @primary_columns == grep defined, @{$data}{@primary_columns} |
188
|
|
|
|
|
|
|
) { |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
I can't easily subclass that routine, as it relies on lexical variables above |
191
|
|
|
|
|
|
|
its scope. I've sent a patch to Tony, which I expect to be in the next |
192
|
|
|
|
|
|
|
Class::DBI release. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head1 THANKS |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
...to James O'Sullivan, for graciously sending me his own solution to this |
197
|
|
|
|
|
|
|
problem, which I've happily included. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
...to Michael Schwern and Tony Bowden for creating and maintaining, |
200
|
|
|
|
|
|
|
respectively, the excellent Class::DBI system. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
...to Casey West, for his crash course on Class::DBI at OSCON '04, which |
203
|
|
|
|
|
|
|
finally convinced me to just use the darn thing. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head1 AUTHOR |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Ricardo SIGNES, > |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
C and C from James O'Sullivan. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head1 COPYRIGHT |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
(C) 2004-2006, Ricardo SIGNES. Class::DBI::MSSQL is available under the same |
214
|
|
|
|
|
|
|
terms as Perl itself. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=cut |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
1; |