| 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; |