line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# DBIx::XMLMessage |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# Copyright (c) 2000-2001 Andrei Nossov. All rights reserved. |
5
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or |
6
|
|
|
|
|
|
|
# modify it under the same terms as Perl itself. |
7
|
|
|
|
|
|
|
# _________________________________________________________________________ |
8
|
|
|
|
|
|
|
# Modifications Log |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
# Version Date Author Notes |
11
|
|
|
|
|
|
|
# _________________________________________________________________________ |
12
|
|
|
|
|
|
|
# 0.04 3/01 Andrei Nossov Root compound key bug fixed |
13
|
|
|
|
|
|
|
# 0.03 11/00 Andrei Nossov Bug fixes, more documentation |
14
|
|
|
|
|
|
|
# 0.02 10/00 Andrei Nossov Documentation improved |
15
|
|
|
|
|
|
|
# 0.01 8/00 Andrei Nossov First cut |
16
|
|
|
|
|
|
|
# _________________________________________________________________________ |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
require 5.003; |
19
|
|
|
|
|
|
|
|
20
|
1
|
|
|
1
|
|
34802
|
use Exporter; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
40
|
|
21
|
1
|
|
|
1
|
|
818
|
use HTML::Entities (); |
|
1
|
|
|
|
|
6174
|
|
|
1
|
|
|
|
|
45
|
|
22
|
1
|
|
|
1
|
|
12634
|
use POSIX; |
|
1
|
|
|
|
|
12421
|
|
|
1
|
|
|
|
|
9
|
|
23
|
1
|
|
|
1
|
|
3212
|
use DBI; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
30
|
|
24
|
1
|
|
|
1
|
|
1071
|
use Data::Dumper; |
|
1
|
|
|
|
|
10537
|
|
|
1
|
|
|
|
|
89
|
|
25
|
1
|
|
|
1
|
|
11
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
51
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# _________________________________________________________________________ |
28
|
|
|
|
|
|
|
# XMLMessage: head package |
29
|
|
|
|
|
|
|
# |
30
|
|
|
|
|
|
|
package DBIx::XMLMessage; |
31
|
|
|
|
|
|
|
|
32
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
77
|
|
33
|
1
|
|
|
1
|
|
2878
|
use XML::Parser; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
use vars qw (@ISA %EXPORT_TAGS $TRACELEVEL $PACKAGE $VERSION); |
35
|
|
|
|
|
|
|
$PACKAGE = 'DBIx::XMLMessage'; |
36
|
|
|
|
|
|
|
$VERSION = '0.04'; |
37
|
|
|
|
|
|
|
$TRACELEVEL = 0; # Don't trace by default |
38
|
|
|
|
|
|
|
@ISA = qw ( Exporter ); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
%EXPORT_TAGS = ( 'elements' => ['VERSION', 'TRACELEVEL', '%TEMPLATE::', |
41
|
|
|
|
|
|
|
'%REFERENCE::', '%CHILD::', '%KEY::', '%COLUMN::', '%PARAMETER::']); |
42
|
|
|
|
|
|
|
Exporter::export_ok_tags ('elements'); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# _________________________________________________________________________ |
45
|
|
|
|
|
|
|
# Allow to create via 'new' |
46
|
|
|
|
|
|
|
# |
47
|
|
|
|
|
|
|
sub new { |
48
|
|
|
|
|
|
|
my ($class, %args) = @_; |
49
|
|
|
|
|
|
|
my $self = bless {}, $class; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Check if the external code references are correct |
52
|
|
|
|
|
|
|
# So far have: _OnError, _OnTrace |
53
|
|
|
|
|
|
|
foreach (keys %args) { |
54
|
|
|
|
|
|
|
if ( /^_On/ ) { # Should be a CODE reference |
55
|
|
|
|
|
|
|
if ( (ref $args{$_}) ne 'CODE' ) { |
56
|
|
|
|
|
|
|
$self->error ("Argument $_ should be a CODE reference"); |
57
|
|
|
|
|
|
|
} else { |
58
|
|
|
|
|
|
|
$self->{$_} = $args{$_}; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
} elsif ( /^Handlers$/ ) { |
61
|
|
|
|
|
|
|
$self->set_handlers ($self->{Handlers}); |
62
|
|
|
|
|
|
|
} elsif ( /^TemplateString$/ ) { |
63
|
|
|
|
|
|
|
$self->prepare_template ($args{TemplateString}); |
64
|
|
|
|
|
|
|
} elsif ( /^TemplateFile$/ ) { |
65
|
|
|
|
|
|
|
$self->prepare_template_from_file ($args{TemplateFile}); |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
return $self; |
69
|
|
|
|
|
|
|
} # -new |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# _________________________________________________________________________ |
72
|
|
|
|
|
|
|
# Set expat handlers |
73
|
|
|
|
|
|
|
# |
74
|
|
|
|
|
|
|
# This is needed as a separate function, as Handlers for input_xml and |
75
|
|
|
|
|
|
|
# prepare_template can be different |
76
|
|
|
|
|
|
|
# |
77
|
|
|
|
|
|
|
sub set_handlers { |
78
|
|
|
|
|
|
|
my $self = shift; |
79
|
|
|
|
|
|
|
my $handlers_ref = shift; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
my $old_handlers = $self->{Handlers}; |
82
|
|
|
|
|
|
|
# Check if Handlers is a hash referernce |
83
|
|
|
|
|
|
|
if ( $handlers_ref && (ref $handlers_ref) ne 'HASH' ) { |
84
|
|
|
|
|
|
|
$self->error ("Argument Handlers should be a HASH reference"); |
85
|
|
|
|
|
|
|
} else { |
86
|
|
|
|
|
|
|
$self->{Handlers} = $handlers_ref; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
return $old_handlers; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# _________________________________________________________________________ |
92
|
|
|
|
|
|
|
# Error method: invoke $self->{_OnError} and die, otherwise croak |
93
|
|
|
|
|
|
|
# |
94
|
|
|
|
|
|
|
sub error { |
95
|
|
|
|
|
|
|
my $self = shift; |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
if ( $self->{_OnError} ) { |
98
|
|
|
|
|
|
|
&{$self->{_OnError}} (@_); |
99
|
|
|
|
|
|
|
die; |
100
|
|
|
|
|
|
|
} else { |
101
|
|
|
|
|
|
|
croak (@_); |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
} # -error |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# _________________________________________________________________________ |
106
|
|
|
|
|
|
|
# trace method: invoke $self->{_OnTrace}, otherwise print to STDERR |
107
|
|
|
|
|
|
|
# |
108
|
|
|
|
|
|
|
sub trace { |
109
|
|
|
|
|
|
|
my $self = shift; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
if ( $TRACELEVEL || defined $self->{_OnTrace} ) { |
112
|
|
|
|
|
|
|
if ( $self->{_OnTrace} ) { |
113
|
|
|
|
|
|
|
&{$self->{_OnTrace}} (@_); |
114
|
|
|
|
|
|
|
} else { |
115
|
|
|
|
|
|
|
print STDERR @_; |
116
|
|
|
|
|
|
|
} } |
117
|
|
|
|
|
|
|
} # -trace |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# _________________________________________________________________________ |
120
|
|
|
|
|
|
|
# Prepare template for the message type |
121
|
|
|
|
|
|
|
# |
122
|
|
|
|
|
|
|
sub prepare_template { |
123
|
|
|
|
|
|
|
my $self = shift; |
124
|
|
|
|
|
|
|
my $tplcontents = shift; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
my $parser = new XML::Parser (Style => 'Objects', |
127
|
|
|
|
|
|
|
Pkg => $PACKAGE, Handlers => $self->{Handlers}); |
128
|
|
|
|
|
|
|
my $parsed; |
129
|
|
|
|
|
|
|
eval { $parsed = $parser->parse ($tplcontents) }; |
130
|
|
|
|
|
|
|
if ( $@ ) { |
131
|
|
|
|
|
|
|
$self->error ($@); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
$self->mk_refs ($parsed->[0]); |
134
|
|
|
|
|
|
|
$self->{_Template} = $parsed->[0]; |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
return $self->{_Template}; |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
} # -prepare_template |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# _________________________________________________________________________ |
141
|
|
|
|
|
|
|
# Prepare template for the message type |
142
|
|
|
|
|
|
|
# |
143
|
|
|
|
|
|
|
# If no filename given, try to derive it from the _MessageType set by the |
144
|
|
|
|
|
|
|
# input_xml and SQLM_TEMPLATE_DIR environment variable |
145
|
|
|
|
|
|
|
# |
146
|
|
|
|
|
|
|
sub prepare_template_from_file { |
147
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
148
|
|
|
|
|
|
|
my $fname = shift; # Template file name |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
if ( ! defined $fname ) { # Full filename expected |
151
|
|
|
|
|
|
|
# If there's no name, try to derive it from the message type. |
152
|
|
|
|
|
|
|
# This hopefully makes things a little bit more flexible |
153
|
|
|
|
|
|
|
$fname = $self->{_MessageType} . '.xml'; |
154
|
|
|
|
|
|
|
if ( $ENV{SQLM_TEMPLATE_DIR} ) { |
155
|
|
|
|
|
|
|
$fname = "$ENV{SQLM_TEMPLATE_DIR}/$fname"; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
$self->error ("Template file name not defined") unless -f $fname; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
my $parser = new XML::Parser (Style => 'Objects', |
160
|
|
|
|
|
|
|
Pkg => $PACKAGE, Handlers => $self->{Handlers}); |
161
|
|
|
|
|
|
|
my $parsed; |
162
|
|
|
|
|
|
|
eval { $parsed = $parser->parsefile ($fname) }; |
163
|
|
|
|
|
|
|
if ( $@ ) { |
164
|
|
|
|
|
|
|
$self->error ($@); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
$self->mk_refs ($parsed->[0]); |
167
|
|
|
|
|
|
|
$self->{_Template} = $parsed->[0]; |
168
|
|
|
|
|
|
|
return $self->{_Template}; |
169
|
|
|
|
|
|
|
} # -prepare_template_from_file |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
#__________________________________________________________________________ |
172
|
|
|
|
|
|
|
# Parse the input request |
173
|
|
|
|
|
|
|
# |
174
|
|
|
|
|
|
|
sub input_xml { |
175
|
|
|
|
|
|
|
my $self = shift; |
176
|
|
|
|
|
|
|
my $content = shift; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
my $p = new XML::Parser (Style => 'Tree', |
179
|
|
|
|
|
|
|
Handlers => $self->{Handlers}); |
180
|
|
|
|
|
|
|
$self->{_MessageTree} = $p->parse ($content); |
181
|
|
|
|
|
|
|
$self->{_MessageType} = undef; |
182
|
|
|
|
|
|
|
$self->{_MessageAttr} = undef; |
183
|
|
|
|
|
|
|
$self->{_MessageKids} = undef; |
184
|
|
|
|
|
|
|
foreach my $el (@{$self->{_MessageTree}}) { |
185
|
|
|
|
|
|
|
if ( (ref $el) =~ /HASH/ ) { |
186
|
|
|
|
|
|
|
$self->{_MessageAttr} = $el; |
187
|
|
|
|
|
|
|
} elsif ( (ref $el) =~ /ARRAY/ ) { |
188
|
|
|
|
|
|
|
$self->{_MessageKids} = $el; |
189
|
|
|
|
|
|
|
} elsif ( $el && !(ref $el) ) { |
190
|
|
|
|
|
|
|
$self->{_MessageType} = $el; |
191
|
|
|
|
|
|
|
} else { |
192
|
|
|
|
|
|
|
$self->error ("Unknown element type encountered: $el\n"); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
return $self->{_MessageType}; |
197
|
|
|
|
|
|
|
} ##input_xml |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
#__________________________________________________________________________ |
200
|
|
|
|
|
|
|
# Parse the input file |
201
|
|
|
|
|
|
|
# |
202
|
|
|
|
|
|
|
sub input_xml_file { |
203
|
|
|
|
|
|
|
my $self = shift; |
204
|
|
|
|
|
|
|
my $fname = shift; |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
my $p = new XML::Parser (Style => 'Tree', |
207
|
|
|
|
|
|
|
Handlers => $self->{Handlers}); |
208
|
|
|
|
|
|
|
$self->{_MessageTree} = $p->parsefile ($fname); |
209
|
|
|
|
|
|
|
$self->{_MessageType} = undef; |
210
|
|
|
|
|
|
|
$self->{_MessageAttr} = undef; |
211
|
|
|
|
|
|
|
$self->{_MessageKids} = undef; |
212
|
|
|
|
|
|
|
foreach my $el (@{$self->{_MessageTree}}) { |
213
|
|
|
|
|
|
|
if ( (ref $el) =~ /HASH/ ) { |
214
|
|
|
|
|
|
|
$self->{_MessageAttr} = $el; |
215
|
|
|
|
|
|
|
} elsif ( (ref $el) =~ /ARRAY/ ) { |
216
|
|
|
|
|
|
|
$self->{_MessageKids} = $el; |
217
|
|
|
|
|
|
|
} elsif ( $el && !(ref $el) ) { |
218
|
|
|
|
|
|
|
$self->{_MessageType} = $el; |
219
|
|
|
|
|
|
|
} else { |
220
|
|
|
|
|
|
|
$self->error ("Unknown element type encountered: $el\n"); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
return $self->{_MessageType}; |
224
|
|
|
|
|
|
|
} # -input_xml_file |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
#__________________________________________________________________________ |
227
|
|
|
|
|
|
|
# |
228
|
|
|
|
|
|
|
# Store the values in the according objects |
229
|
|
|
|
|
|
|
# |
230
|
|
|
|
|
|
|
# E.g.: |
231
|
|
|
|
|
|
|
# [ ServiceIncident, |
232
|
|
|
|
|
|
|
# [ {VERSION => "1.0"}, |
233
|
|
|
|
|
|
|
# Service, |
234
|
|
|
|
|
|
|
# [ {}, |
235
|
|
|
|
|
|
|
# 0, "", |
236
|
|
|
|
|
|
|
# Case, |
237
|
|
|
|
|
|
|
# [ {}, |
238
|
|
|
|
|
|
|
# 0, "", |
239
|
|
|
|
|
|
|
# ID, |
240
|
|
|
|
|
|
|
# [ {}, 0, "8014" |
241
|
|
|
|
|
|
|
# ], |
242
|
|
|
|
|
|
|
# 0, "" |
243
|
|
|
|
|
|
|
# ] |
244
|
|
|
|
|
|
|
# ], |
245
|
|
|
|
|
|
|
# 0, "" |
246
|
|
|
|
|
|
|
# ServiceTransaction, |
247
|
|
|
|
|
|
|
# [ {}, |
248
|
|
|
|
|
|
|
# 0, "", |
249
|
|
|
|
|
|
|
# DispStatus, |
250
|
|
|
|
|
|
|
# [ {}, 0, "In Progress" |
251
|
|
|
|
|
|
|
# ] |
252
|
|
|
|
|
|
|
# ] |
253
|
|
|
|
|
|
|
# 0, "" |
254
|
|
|
|
|
|
|
# ] |
255
|
|
|
|
|
|
|
# 0, "" |
256
|
|
|
|
|
|
|
# ] |
257
|
|
|
|
|
|
|
# |
258
|
|
|
|
|
|
|
# ------------------------------------------------------------------------ |
259
|
|
|
|
|
|
|
# |
260
|
|
|
|
|
|
|
# FIXME: Buggy.. |
261
|
|
|
|
|
|
|
# |
262
|
|
|
|
|
|
|
sub populate_objects { |
263
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
264
|
|
|
|
|
|
|
my $ghash = shift; # Global hash |
265
|
|
|
|
|
|
|
my $obj = shift; # The matching object for this tag |
266
|
|
|
|
|
|
|
my $tag = shift; # The tag name |
267
|
|
|
|
|
|
|
my $content = shift; # Reference to the array of kids, hash is attrs |
268
|
|
|
|
|
|
|
my $parix = shift || 0; # Parent input set index |
269
|
|
|
|
|
|
|
my ($el, $attr, $i, $text, $kid, $kidcont, $papa); |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# Initialize the first object from _Template |
272
|
|
|
|
|
|
|
if ( !defined $obj ) { |
273
|
|
|
|
|
|
|
if ( $self->{_Template} ) { |
274
|
|
|
|
|
|
|
$obj = $self->{_Template}; |
275
|
|
|
|
|
|
|
} else { |
276
|
|
|
|
|
|
|
$self->error ("Error: the template is empty" |
277
|
|
|
|
|
|
|
. " (have you run prepare_template?)"); |
278
|
|
|
|
|
|
|
} } |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# Initialize the first tag name from _MessageType and the |
281
|
|
|
|
|
|
|
# first content -- from the _MessageKids |
282
|
|
|
|
|
|
|
if ( ! defined $tag && ! defined $content ) { |
283
|
|
|
|
|
|
|
$tag = $self->{_MessageType}; |
284
|
|
|
|
|
|
|
$content = $self->{_MessageKids}; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
# Log the entry at this point.. Hopefully nothing will happen before.. |
287
|
|
|
|
|
|
|
$self->trace ("populate_objects: $tag, $parix\n"); |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# Figure out its own _INIX |
290
|
|
|
|
|
|
|
$obj->{_INIX} = (defined $obj->{_INIX}) ? ++$obj->{_INIX} : 0; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# Verify that the object matches w/ the tag |
293
|
|
|
|
|
|
|
if ( $tag ne $obj->{NAME} ) { |
294
|
|
|
|
|
|
|
croak "Error: $tag doesn't match with the template ($obj->{NAME})"; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
$text = undef; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
for ( $i=0; defined $content->[$i]; $i++ ) { |
299
|
|
|
|
|
|
|
# while ( defined ($kid = shift @$content) ) { |
300
|
|
|
|
|
|
|
$kid = $content->[$i]; |
301
|
|
|
|
|
|
|
if ( (ref $kid) =~ /HASH/ ) { # Attributes -- verify |
302
|
|
|
|
|
|
|
foreach $attr ( keys %$kid ) { |
303
|
|
|
|
|
|
|
if ( $obj->{$attr} && $kid->{$attr} ne $obj->{$attr} ) { |
304
|
|
|
|
|
|
|
$obj->error ("Error: $attr of the message $el->{$attr}" |
305
|
|
|
|
|
|
|
. " don't match with that of the template" |
306
|
|
|
|
|
|
|
. " ($obj->{$attr})"); |
307
|
|
|
|
|
|
|
} } |
308
|
|
|
|
|
|
|
} else { |
309
|
|
|
|
|
|
|
#<<<<<<<< |
310
|
|
|
|
|
|
|
$kidcont = $content->[++$i]; |
311
|
|
|
|
|
|
|
if ( ref $kid ) { # ?? Error |
312
|
|
|
|
|
|
|
$self->error ("Error: Unexpected reference $kid"); |
313
|
|
|
|
|
|
|
} elsif (!$kid) { # 0 -- text |
314
|
|
|
|
|
|
|
$kidcont =~ s/[\n\s]*$//; |
315
|
|
|
|
|
|
|
$text .= $kidcont; |
316
|
|
|
|
|
|
|
} else { # Not 0 -- tag |
317
|
|
|
|
|
|
|
undef $el; |
318
|
|
|
|
|
|
|
foreach my $typ (qw (CHI REF COL PAR KEY)) { |
319
|
|
|
|
|
|
|
if ( $obj->{"_$typ" . 'LIST'} && $obj->{"_$typ".'LIST'}->{$kid} ) { |
320
|
|
|
|
|
|
|
$el = $obj->{"_$typ" . 'LIST'}->{$kid}; |
321
|
|
|
|
|
|
|
last; |
322
|
|
|
|
|
|
|
} } |
323
|
|
|
|
|
|
|
if ( $el ) { # Found |
324
|
|
|
|
|
|
|
$self->populate_objects ($ghash,$el,$kid,$kidcont,$obj->{_INIX}); |
325
|
|
|
|
|
|
|
} else { |
326
|
|
|
|
|
|
|
# Kid not found -- see if we can dynamically create it.. |
327
|
|
|
|
|
|
|
if ( $obj->{TOLERANCE} && $obj->{TOLERANCE} =~ /^CREATE/ ) { |
328
|
|
|
|
|
|
|
# CREATE |
329
|
|
|
|
|
|
|
my $type = 'COLUMN'; |
330
|
|
|
|
|
|
|
if ( $obj->{TOLERANCE} =~ /^CREATE (.+)$/ ) { |
331
|
|
|
|
|
|
|
$type = $1; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
# Dynamic creation |
334
|
|
|
|
|
|
|
$el = new "$PACKAGE::$type"; |
335
|
|
|
|
|
|
|
$el->{NAME} = $kid; |
336
|
|
|
|
|
|
|
$el->{_PARENT_TAG} = $obj; |
337
|
|
|
|
|
|
|
push @{$obj->{Kids}}, $el; |
338
|
|
|
|
|
|
|
$obj->{_COLLIST}->{$kid} = $el; |
339
|
|
|
|
|
|
|
$self->populate_objects ($ghash,$el,$kid,$kidcont,$obj->{_INIX}); |
340
|
|
|
|
|
|
|
} elsif ( $obj->{TOLERANCE} |
341
|
|
|
|
|
|
|
&& $obj->{TOLERANCE} eq 'REJECT' ) {# REJECT |
342
|
|
|
|
|
|
|
$self->error ("$obj->{NAME} doesn't allow child $kid"); |
343
|
|
|
|
|
|
|
} else { # IGNORE |
344
|
|
|
|
|
|
|
$self->trace ("$kid kid not found in the template" |
345
|
|
|
|
|
|
|
. " for $obj->{NAME}, ignoring"); |
346
|
|
|
|
|
|
|
} } } } |
347
|
|
|
|
|
|
|
#<<<<<<<< |
348
|
|
|
|
|
|
|
} ## while kid |
349
|
|
|
|
|
|
|
# Tweak up the text if there's a built-in.. |
350
|
|
|
|
|
|
|
if ( $text && $obj->{BLTIN} ) { |
351
|
|
|
|
|
|
|
my $bltin = $obj->{BLTIN}; |
352
|
|
|
|
|
|
|
@_ = ($self,$obj,$text); |
353
|
|
|
|
|
|
|
my $cmd = '$text = &' . $bltin . ';'; |
354
|
|
|
|
|
|
|
eval $cmd || die "Error in BUILT-IN $bltin of $obj->{NAME}: $@"; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
# Figure out what to do w/ the text.. |
357
|
|
|
|
|
|
|
if ( (ref $obj) =~ /::COLUMN$/ || (ref $obj) =~ /::PARAMETER$/ |
358
|
|
|
|
|
|
|
|| (ref $obj) =~ /::KEY$/ ) { |
359
|
|
|
|
|
|
|
$papa = $obj->{_PARENT_TAG}; |
360
|
|
|
|
|
|
|
$papa->{_INVALUES}->[$parix]->{$tag} = $text; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
} # -populate_objects |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
#__________________________________________________________________________ |
366
|
|
|
|
|
|
|
# Debugging subroutine: Print the tree |
367
|
|
|
|
|
|
|
# |
368
|
|
|
|
|
|
|
sub pr_tree { |
369
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
370
|
|
|
|
|
|
|
my $ref = shift; # Root node of this subtree |
371
|
|
|
|
|
|
|
my $level = shift || 0; # Level of this root node |
372
|
|
|
|
|
|
|
my ($el, $i); |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
if ( (ref $ref) =~ /ARRAY/ ) { |
375
|
|
|
|
|
|
|
foreach $el (@$ref) { |
376
|
|
|
|
|
|
|
$self->pr_tree ($el, $level+1); |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
} elsif ( (ref $ref) =~ /HASH/ ) { |
379
|
|
|
|
|
|
|
# Attributes only |
380
|
|
|
|
|
|
|
foreach $el ( keys %$ref ) { |
381
|
|
|
|
|
|
|
for ($i=0; $i<$level; $i++) { $self->trace (" "); } |
382
|
|
|
|
|
|
|
$self->trace ("$el = $ref->$el\n"); |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
} else { |
385
|
|
|
|
|
|
|
if ( $ref ) { |
386
|
|
|
|
|
|
|
for ($i=0; $i<$level; $i++) { $self->trace (" "); } |
387
|
|
|
|
|
|
|
if ( $ref =~ /(.*)(\s+)$/ ) { |
388
|
|
|
|
|
|
|
$ref = $1; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
if ( $ref =~ /(.*)(\n+)$/ ) { |
391
|
|
|
|
|
|
|
$ref = $1; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
$self->trace ("$ref\n"); |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
} # -pr_tree |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
# _________________________________________________________________________ |
399
|
|
|
|
|
|
|
# Create the necessary internal structures |
400
|
|
|
|
|
|
|
# |
401
|
|
|
|
|
|
|
sub mk_refs { |
402
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
403
|
|
|
|
|
|
|
my $root = shift; # Element |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
foreach my $el (@{$root->{'Kids'}}) { |
406
|
|
|
|
|
|
|
if ( (ref $el) =~ /::(\w+)$/ && (ref $el) !~ /::Characters/ ) { |
407
|
|
|
|
|
|
|
# Create the parent references |
408
|
|
|
|
|
|
|
$el->{_PARENT_TAG} = $root; |
409
|
|
|
|
|
|
|
# Store the object type lists in hashes |
410
|
|
|
|
|
|
|
# Constructs: _COLLIST, _KEYLIST, _PARLIST, _REFLIST, _CHILIST |
411
|
|
|
|
|
|
|
# The assumption here is that the tag name within an object |
412
|
|
|
|
|
|
|
# type is unique (i.e. there couldn't be two COLUMNs with the |
413
|
|
|
|
|
|
|
# same name) |
414
|
|
|
|
|
|
|
my $listname = "_" . substr($1,0,3) . "LIST"; |
415
|
|
|
|
|
|
|
if ( $root->{$listname}->{$el->{NAME}} ) { |
416
|
|
|
|
|
|
|
$self->error ("$1 $el->{NAME} is defined more" |
417
|
|
|
|
|
|
|
. " than once under $root->{NAME}"); |
418
|
|
|
|
|
|
|
} else { |
419
|
|
|
|
|
|
|
$root->{$listname}->{$el->{NAME}} = $el; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
$self->mk_refs($el); |
422
|
|
|
|
|
|
|
} } |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
} # -mk_refs |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# _________________________________________________________________________ |
427
|
|
|
|
|
|
|
# Get the value from global hash (not a method!) |
428
|
|
|
|
|
|
|
# |
429
|
|
|
|
|
|
|
sub get_hashval { |
430
|
|
|
|
|
|
|
my $href = shift; # Hash reference |
431
|
|
|
|
|
|
|
my $name = shift; # Name to look for |
432
|
|
|
|
|
|
|
my $resix = shift || 0; # Index to look for |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# Note: This function doesn't have to have a $inix argument, as the only |
435
|
|
|
|
|
|
|
# linkage to the higher level is $resix. |
436
|
|
|
|
|
|
|
# |
437
|
|
|
|
|
|
|
my $val = undef; |
438
|
|
|
|
|
|
|
if ( $href && defined $href->{$name} ) { |
439
|
|
|
|
|
|
|
if ( (ref $href->{$name}) eq 'CODE' ) { |
440
|
|
|
|
|
|
|
$val = &{$href->{$name}}($resix); |
441
|
|
|
|
|
|
|
} elsif ( (ref $href->{$name}) eq 'ARRAY' ) { |
442
|
|
|
|
|
|
|
return $href->{$name}->[$resix]; |
443
|
|
|
|
|
|
|
} elsif ( !(ref $href->{$name}) && $resix == 0 ) { |
444
|
|
|
|
|
|
|
# Just a single value, only return if the index is 0 |
445
|
|
|
|
|
|
|
$val = $href->{$name}; |
446
|
|
|
|
|
|
|
} |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
return $val; |
449
|
|
|
|
|
|
|
} # -get_hashval |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# _________________________________________________________________________ |
452
|
|
|
|
|
|
|
# THESE ARE METHODS FOR THE ELEMENTS |
453
|
|
|
|
|
|
|
# |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# _________________________________________________________________________ |
456
|
|
|
|
|
|
|
# Get the *parent* result value #n |
457
|
|
|
|
|
|
|
# |
458
|
|
|
|
|
|
|
sub get_resval { |
459
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
460
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE | REFERENCE | CHILD |
461
|
|
|
|
|
|
|
my $name = shift; # (COLUMN) name |
462
|
|
|
|
|
|
|
my $resix = shift || 0; # Result set index |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
$self->trace (" get_resval ($node->{NAME},$name,$resix)\n"); |
465
|
|
|
|
|
|
|
my $papa = $node->{_PARENT_TAG} || return undef; |
466
|
|
|
|
|
|
|
my $rref = $papa->{_RESULTS} || return undef; |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
if ( (ref $rref) eq 'CODE' ) { |
469
|
|
|
|
|
|
|
# Should this work for global hash? |
470
|
|
|
|
|
|
|
return &{$rref}($resix); |
471
|
|
|
|
|
|
|
} elsif ( (ref $rref) eq 'ARRAY' ) { |
472
|
|
|
|
|
|
|
if ( $rref->[$resix] && defined $rref->[$resix]->{$name} ) { |
473
|
|
|
|
|
|
|
return $rref->[$resix]->{$name}; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
} elsif ( (ref $rref) eq 'HASH' && $rref->{$name} && $resix == 0 ) { |
476
|
|
|
|
|
|
|
# Should work for global hash as well? |
477
|
|
|
|
|
|
|
return $rref->{$name}; |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
return undef; |
480
|
|
|
|
|
|
|
} # -get_resval |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
# _________________________________________________________________________ |
483
|
|
|
|
|
|
|
# Get the parameter (input value) #n |
484
|
|
|
|
|
|
|
# |
485
|
|
|
|
|
|
|
sub get_inval { |
486
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
487
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
488
|
|
|
|
|
|
|
my $name = shift; # Name to look for |
489
|
|
|
|
|
|
|
my $ix = shift || 0; # Input value set index |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
$self->trace (" get_inval ($node->{NAME},$name,$ix)\n"); |
492
|
|
|
|
|
|
|
my $val = $node->{_INVALUES} |
493
|
|
|
|
|
|
|
? $node->{_INVALUES}->[$ix] |
494
|
|
|
|
|
|
|
? $node->{_INVALUES}->[$ix]->{$name} |
495
|
|
|
|
|
|
|
: undef |
496
|
|
|
|
|
|
|
: undef; |
497
|
|
|
|
|
|
|
return $val; |
498
|
|
|
|
|
|
|
} # -get_inval |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
#__________________________________________________________________________ |
501
|
|
|
|
|
|
|
# Get the key value #($inix,$resix) |
502
|
|
|
|
|
|
|
# |
503
|
|
|
|
|
|
|
sub get_keyval { |
504
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
505
|
|
|
|
|
|
|
my $node = shift; # Key reference |
506
|
|
|
|
|
|
|
my $href = shift; # External hash reference |
507
|
|
|
|
|
|
|
my $inix = shift || 0; # Input set index |
508
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
$self->trace (" get_keyval ($node->{NAME},$inix,$resix)\n"); |
511
|
|
|
|
|
|
|
my ($tag, $papa, $kname, $val); |
512
|
|
|
|
|
|
|
$tag = $node->{_PARENT_TAG}; |
513
|
|
|
|
|
|
|
# Any key should have a parent TEMPLATE|CHILD|REFERENCE |
514
|
|
|
|
|
|
|
if ( !$tag ) { |
515
|
|
|
|
|
|
|
$self->error ("Internal error: Key $node->{NAME} has no parent"); |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
# Find the corresponding name a level up |
518
|
|
|
|
|
|
|
$kname = $node->{PARENT_NAME} ? $node->{PARENT_NAME} : $node->{NAME}; |
519
|
|
|
|
|
|
|
# Check itself |
520
|
|
|
|
|
|
|
# Keys are stored in a 2-dimensional array: |
521
|
|
|
|
|
|
|
# _____________________________________________________________________ |
522
|
|
|
|
|
|
|
# resix 0 1 2 3 ... |
523
|
|
|
|
|
|
|
# inix |
524
|
|
|
|
|
|
|
# 0 A B C D |
525
|
|
|
|
|
|
|
# 1 E F |
526
|
|
|
|
|
|
|
# 2 G H I |
527
|
|
|
|
|
|
|
# ... |
528
|
|
|
|
|
|
|
# _____________________________________________________________________ |
529
|
|
|
|
|
|
|
# Thus, inix 0 should be always there and it's fake.. |
530
|
|
|
|
|
|
|
# |
531
|
|
|
|
|
|
|
if ( $tag->{_KEYS} && $tag->{_KEYS}->[$inix] |
532
|
|
|
|
|
|
|
&& defined $tag->{_KEYS}->[$inix]->[$resix] |
533
|
|
|
|
|
|
|
&& defined $tag->{_KEYS}->[$inix]->[$resix]->{$kname} ) { |
534
|
|
|
|
|
|
|
$val = $self->format_value ($node,$tag->{_KEYS}->[$inix]->[$resix]->{$kname}); |
535
|
|
|
|
|
|
|
$self->trace (" *get_keyval = $val\n"); |
536
|
|
|
|
|
|
|
return $val; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
# Find the tag's parent (all but TEMPLATE should have) |
539
|
|
|
|
|
|
|
if ( $tag->{_PARENT_TAG} ) { |
540
|
|
|
|
|
|
|
$papa = $tag->{_PARENT_TAG}; |
541
|
|
|
|
|
|
|
} elsif ( (ref $tag) !~ /::TEMPLATE$/ ) { |
542
|
|
|
|
|
|
|
$self->error ("Internal error: Tag $tag->{NAME} has no parent"); |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
# Try to get from input values and parent results |
545
|
|
|
|
|
|
|
my $val1 = $self->get_inval ($tag, $node->{NAME}, $inix); |
546
|
|
|
|
|
|
|
# Get the parent result |
547
|
|
|
|
|
|
|
my $val2 = $self->get_resval ($tag, $kname, $resix); |
548
|
|
|
|
|
|
|
# Compare values |
549
|
|
|
|
|
|
|
if ( defined $val1 ) { |
550
|
|
|
|
|
|
|
if ( defined $val2 && $val1 ne $val2 ) { |
551
|
|
|
|
|
|
|
$self->error ("Key $node->{NAME} values don't" |
552
|
|
|
|
|
|
|
. " match in parent result set and input"); |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
$val = $val1; |
555
|
|
|
|
|
|
|
} else { |
556
|
|
|
|
|
|
|
$val = $val2; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
# If still undefined, then try the global hash |
559
|
|
|
|
|
|
|
if ( !defined $val ) { |
560
|
|
|
|
|
|
|
# None defined -- try the global hash |
561
|
|
|
|
|
|
|
$val = &get_hashval ($href, $kname, $resix); |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
if ( defined $val ) { |
564
|
|
|
|
|
|
|
$tag->{_KEYS}->[$inix]->[$resix]->{$kname} = $val; |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
$val = (defined $val) ? $self->format_value($node,$val) : undef; |
567
|
|
|
|
|
|
|
$self->trace (" get_keyval = $val\n"); |
568
|
|
|
|
|
|
|
return $val; |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
# Should be able to have two references from two different columns |
571
|
|
|
|
|
|
|
# to the same table.. (I recall this idea seemed important..why?;^) |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
} # -get_keyval |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
#__________________________________________________________________________ |
576
|
|
|
|
|
|
|
# Get the parameter value #ix |
577
|
|
|
|
|
|
|
# |
578
|
|
|
|
|
|
|
sub get_parval { |
579
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
580
|
|
|
|
|
|
|
my $node = shift; # PARAMETER |
581
|
|
|
|
|
|
|
my $href = shift; # External hash reference |
582
|
|
|
|
|
|
|
my $inix = shift || 0; # Input value set index, real starts at 1 |
583
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
my $val = undef; |
586
|
|
|
|
|
|
|
my $tag = $node->{_PARENT_TAG}; # Parameter's tag |
587
|
|
|
|
|
|
|
if ( !$tag ) { |
588
|
|
|
|
|
|
|
$self->error ("Parameter $node->{NAME} has no parent tag"); |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
# Try to get from input values and parent results |
592
|
|
|
|
|
|
|
my $val1 = $self->get_inval ($tag, $node->{NAME}, $inix); |
593
|
|
|
|
|
|
|
# Find the corresponding name a level up |
594
|
|
|
|
|
|
|
my $pname = $node->{PARENT_NAME} ? $node->{PARENT_NAME} : $node->{NAME}; |
595
|
|
|
|
|
|
|
# Get the parent result |
596
|
|
|
|
|
|
|
my $val2 = $self->get_resval ($tag, $pname, $resix); |
597
|
|
|
|
|
|
|
# Compare values |
598
|
|
|
|
|
|
|
if ( defined $val1 ) { |
599
|
|
|
|
|
|
|
if ( defined $val2 && $val1 ne $val2 ) { |
600
|
|
|
|
|
|
|
$self->error ("Parameter $node->{NAME} values" |
601
|
|
|
|
|
|
|
. " don't match in parent result set and input"); |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
$val = $val1; |
604
|
|
|
|
|
|
|
} else { |
605
|
|
|
|
|
|
|
$val = $val2; |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
# If still undefined, then try the global hash |
608
|
|
|
|
|
|
|
if ( !defined $val ) { |
609
|
|
|
|
|
|
|
$val = &get_hashval ($href, $pname, $resix); |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
if ( defined $val ) { |
612
|
|
|
|
|
|
|
$val = $self->format_value($node,$val); |
613
|
|
|
|
|
|
|
} else { |
614
|
|
|
|
|
|
|
if ( !defined $val && defined $node->{DEFAULT} ) { |
615
|
|
|
|
|
|
|
$val = $self->{DEFAULT}; |
616
|
|
|
|
|
|
|
} } |
617
|
|
|
|
|
|
|
return $val; |
618
|
|
|
|
|
|
|
} ##get_parval |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
#__________________________________________________________________________ |
621
|
|
|
|
|
|
|
# Get and format the column value #($inix,$resix) |
622
|
|
|
|
|
|
|
# |
623
|
|
|
|
|
|
|
sub get_colval { |
624
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
625
|
|
|
|
|
|
|
my $node = shift; # COLUMN |
626
|
|
|
|
|
|
|
my $dbh = shift; # Database handle |
627
|
|
|
|
|
|
|
my $href = shift; # External hash reference |
628
|
|
|
|
|
|
|
my $inix = shift || 0; # Input value set index |
629
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
$self->trace (" get_colval ($node->{NAME},$inix,$resix)\n"); |
632
|
|
|
|
|
|
|
my $tag = $node->{_PARENT_TAG}; # Parameter's tag |
633
|
|
|
|
|
|
|
if ( !$tag ) { |
634
|
|
|
|
|
|
|
$self->error ("Internal error: Column $node->{NAME} has no parent"); |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
my $val = undef; |
637
|
|
|
|
|
|
|
# Find the tag's parent (all but TEMPLATE should have) |
638
|
|
|
|
|
|
|
my $papa; |
639
|
|
|
|
|
|
|
if ( $tag->{_PARENT_TAG} ) { |
640
|
|
|
|
|
|
|
$papa = $tag->{_PARENT_TAG}; |
641
|
|
|
|
|
|
|
} elsif ( (ref $tag) =~ /::TEMPLATE$/ ) { |
642
|
|
|
|
|
|
|
$papa = $href; |
643
|
|
|
|
|
|
|
} else { |
644
|
|
|
|
|
|
|
die ("Internal error: Tag $tag->{NAME} has no parent"); |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
# Look for the input value and parent result |
647
|
|
|
|
|
|
|
my $val1 = $self->get_inval ($tag, $node->{NAME}, $inix); |
648
|
|
|
|
|
|
|
my $val2 = $self->get_resval ($node, $node->{NAME}, $resix); |
649
|
|
|
|
|
|
|
$self->trace (" inval=" . (defined $val1 ? $val1 : "UNDEF") |
650
|
|
|
|
|
|
|
. ", resval=" . (defined $val2 ? $val2 : "UNDEF") . "\n"); |
651
|
|
|
|
|
|
|
if ( defined $val1 && length($val1) > 0 ) { |
652
|
|
|
|
|
|
|
if ( defined $val2 && length($val2) > 0 ) { |
653
|
|
|
|
|
|
|
if ( $val1 eq $val2 ) { |
654
|
|
|
|
|
|
|
$val = $val1 |
655
|
|
|
|
|
|
|
} else { |
656
|
|
|
|
|
|
|
die ("Internal error: $node->{NAME} column values don't " |
657
|
|
|
|
|
|
|
. "match in parent result set and input ($val1,$val2)"); |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
} else { |
660
|
|
|
|
|
|
|
$val = $val1; |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
} else { |
663
|
|
|
|
|
|
|
$val = $val2; |
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
# print " val=$val\n"; |
666
|
|
|
|
|
|
|
# Also try the keys with matching EXPR|NAME |
667
|
|
|
|
|
|
|
# as they might get pushed |
668
|
|
|
|
|
|
|
# from the lower levels (not anymore ;^)) |
669
|
|
|
|
|
|
|
if ( !defined $val ) { |
670
|
|
|
|
|
|
|
if ( $node->{EXPR} && $tag->{_KEYLIST}->{$node->{EXPR}} ) { |
671
|
|
|
|
|
|
|
my $key = $tag->{_KEYLIST}->{$node->{EXPR}}; |
672
|
|
|
|
|
|
|
$val = $self->get_keyval ($key,$href,$inix,$resix); |
673
|
|
|
|
|
|
|
} elsif ( $tag->{_KEYLIST}->{$node->{NAME}} ) { |
674
|
|
|
|
|
|
|
my $key = $tag->{_KEYLIST}->{$node->{NAME}}; |
675
|
|
|
|
|
|
|
$val = $self->get_keyval ($key,$href,$inix,$resix); |
676
|
|
|
|
|
|
|
} } |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
if ( $val ) { |
679
|
|
|
|
|
|
|
$val = $self->format_value ($node,$val); |
680
|
|
|
|
|
|
|
} elsif ( $node->{GENERATE_PK} ) { |
681
|
|
|
|
|
|
|
if ( $node->{GENERATE_PK} eq 'HASH' ) { |
682
|
|
|
|
|
|
|
$val = &get_hashval ($href,"$tag->{TABLE}",$inix,$resix); |
683
|
|
|
|
|
|
|
} else { |
684
|
|
|
|
|
|
|
# Should contain a SQL that selects 1 value |
685
|
|
|
|
|
|
|
if ( $dbh ) { |
686
|
|
|
|
|
|
|
my $idtab = $tag->{TABLE} . "_ID"; |
687
|
|
|
|
|
|
|
my $sql = $node->{GENERATE_PK}; |
688
|
|
|
|
|
|
|
my $sth = $dbh->prepare ($sql) || die $DBI::errstr; |
689
|
|
|
|
|
|
|
my $rc = $sth->execute() || die $DBI::errstr; |
690
|
|
|
|
|
|
|
$rc = $sth->fetchall_arrayref(); |
691
|
|
|
|
|
|
|
$val = $rc->[0]->[0]; |
692
|
|
|
|
|
|
|
$rc = $sth->finish(); |
693
|
|
|
|
|
|
|
} elsif ( $self->{NODBH} eq 'OK' ) { |
694
|
|
|
|
|
|
|
# No database handle: Try hash anyway |
695
|
|
|
|
|
|
|
$self->trace ("Trying to get PK without database handle"); |
696
|
|
|
|
|
|
|
$val = &get_hashval ($href,"$tag->{TABLE}",$inix,$resix); |
697
|
|
|
|
|
|
|
} else { |
698
|
|
|
|
|
|
|
$self->error ( |
699
|
|
|
|
|
|
|
"Can not generate primary key for table $tag->{TABLE}"); |
700
|
|
|
|
|
|
|
} } |
701
|
|
|
|
|
|
|
} elsif ( defined $node->{DEFAULT} ) { |
702
|
|
|
|
|
|
|
$val = $node->{DEFAULT}; # This goes as-is |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
return $val; |
705
|
|
|
|
|
|
|
} # -get_colval |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
#__________________________________________________________________________ |
708
|
|
|
|
|
|
|
# Format element value according to its datatype |
709
|
|
|
|
|
|
|
# |
710
|
|
|
|
|
|
|
sub format_value { |
711
|
|
|
|
|
|
|
my $self = shift; |
712
|
|
|
|
|
|
|
my $node = shift; |
713
|
|
|
|
|
|
|
my $val = shift; |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
# DATATYPE is CHAR by default |
716
|
|
|
|
|
|
|
if ( !$node->{DATATYPE} || $node->{DATATYPE} =~ /(CHAR|DATE|TIME)/ ) { |
717
|
|
|
|
|
|
|
if ( $val !~ /^\'(.*)\'$/ && $val !~ /^\"(.*)\"$/ ) { |
718
|
|
|
|
|
|
|
$val =~ s/\'/\'\'/g; |
719
|
|
|
|
|
|
|
$val = "'$val'"; |
720
|
|
|
|
|
|
|
} } |
721
|
|
|
|
|
|
|
return $val; |
722
|
|
|
|
|
|
|
} # -format_value |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
#__________________________________________________________________________ |
725
|
|
|
|
|
|
|
# Create the WHERE clause for SELECT/UPDATE |
726
|
|
|
|
|
|
|
# |
727
|
|
|
|
|
|
|
sub create_where { |
728
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
729
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
730
|
|
|
|
|
|
|
my $href = shift; # Global hash reference |
731
|
|
|
|
|
|
|
my $inix = shift || 0; # Key set index |
732
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
$self->trace (" create_where ($node->{NAME},$inix,$resix)\n"); |
735
|
|
|
|
|
|
|
my ($el, $where); |
736
|
|
|
|
|
|
|
# Construct WHERE clause |
737
|
|
|
|
|
|
|
foreach ( keys %{$node->{_KEYLIST}} ) { |
738
|
|
|
|
|
|
|
$el = $node->{_KEYLIST}->{$_}; |
739
|
|
|
|
|
|
|
my $val = $self->get_keyval ($el,$href,$inix,$resix); |
740
|
|
|
|
|
|
|
if ( !defined $val ) { |
741
|
|
|
|
|
|
|
$self->error ("$el->{NAME}: Key value #($inix,$resix) not found"); |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
$where .= " and "; |
744
|
|
|
|
|
|
|
if ( defined $el->{EXPR} ) { |
745
|
|
|
|
|
|
|
$where .= $el->{EXPR}; |
746
|
|
|
|
|
|
|
} else { |
747
|
|
|
|
|
|
|
$where .= $el->{NAME}; |
748
|
|
|
|
|
|
|
} |
749
|
|
|
|
|
|
|
if ( !$el->{DATATYPE} || $el->{DATATYPE} =~ /CHAR/ ) { |
750
|
|
|
|
|
|
|
$where .= " like "; |
751
|
|
|
|
|
|
|
} else { |
752
|
|
|
|
|
|
|
$where .= " = "; |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
$val = $self->format_value($el,$val); |
755
|
|
|
|
|
|
|
$where .= $val; |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
# Check if there is additional WHERE clause |
758
|
|
|
|
|
|
|
if ( $node->{'WHERE_CLAUSE'} ) { |
759
|
|
|
|
|
|
|
$where .= " and " if ( $where ); |
760
|
|
|
|
|
|
|
$where .= $node->{'WHERE_CLAUSE'}; |
761
|
|
|
|
|
|
|
} |
762
|
|
|
|
|
|
|
# Cut off the initial 'and' |
763
|
|
|
|
|
|
|
$where = substr ($where, 4) if ($where); |
764
|
|
|
|
|
|
|
return $where; |
765
|
|
|
|
|
|
|
} # -create_where |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
# _________________________________________________________________________ |
768
|
|
|
|
|
|
|
# Construct SELECT statement |
769
|
|
|
|
|
|
|
# |
770
|
|
|
|
|
|
|
sub create_select { |
771
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
772
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
773
|
|
|
|
|
|
|
my $dbh = shift; # Database handle |
774
|
|
|
|
|
|
|
my $href = shift; # Global hash reference |
775
|
|
|
|
|
|
|
my $inix = shift || 0; # Input value set index |
776
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
$self->trace (" create_select ($node->{NAME},$inix,$resix)\n"); |
779
|
|
|
|
|
|
|
my ($el, $colexpr, $sql); |
780
|
|
|
|
|
|
|
# Construct column list, possibly with aliases |
781
|
|
|
|
|
|
|
foreach ( keys %{$node->{_COLLIST}} ) { |
782
|
|
|
|
|
|
|
# $self->trace (" create_select: found column $_\n"); |
783
|
|
|
|
|
|
|
$el = $node->{_COLLIST}->{$_}; |
784
|
|
|
|
|
|
|
# Include expression if present |
785
|
|
|
|
|
|
|
if ( $el->{'EXPR'} ) { |
786
|
|
|
|
|
|
|
$colexpr = $el->{EXPR}; |
787
|
|
|
|
|
|
|
} else { |
788
|
|
|
|
|
|
|
$colexpr = $el->{NAME}; |
789
|
|
|
|
|
|
|
} |
790
|
|
|
|
|
|
|
# Include name if not the same |
791
|
|
|
|
|
|
|
if ( $el->{'NAME'} ne $colexpr ) { |
792
|
|
|
|
|
|
|
$colexpr .= " " if ($colexpr); |
793
|
|
|
|
|
|
|
$colexpr .= $el->{'NAME'}; |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
# Add to the SQL if not empty |
796
|
|
|
|
|
|
|
$sql .= "\n\t$colexpr," if ($colexpr); |
797
|
|
|
|
|
|
|
} |
798
|
|
|
|
|
|
|
if ( $sql ) { |
799
|
|
|
|
|
|
|
chop ($sql); # Chop the last comma |
800
|
|
|
|
|
|
|
$sql = "SELECT $sql"; |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
if ( $sql && $node->{TABLE} ) { |
803
|
|
|
|
|
|
|
$sql .= "\nFROM\n\t" . $node->{'TABLE'}; |
804
|
|
|
|
|
|
|
# WHERE clause doesn't make sence without FROM |
805
|
|
|
|
|
|
|
my $where = $self->create_where ($node, $href, $inix, $resix); |
806
|
|
|
|
|
|
|
$sql .= "\nWHERE $where"; |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
return $sql; |
809
|
|
|
|
|
|
|
} # -create_select |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
# _________________________________________________________________________ |
812
|
|
|
|
|
|
|
# Construct INSERT statement |
813
|
|
|
|
|
|
|
# |
814
|
|
|
|
|
|
|
sub create_insert { |
815
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
816
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
817
|
|
|
|
|
|
|
my $dbh = shift; # Database handle |
818
|
|
|
|
|
|
|
my $href = shift; # Global hash reference |
819
|
|
|
|
|
|
|
my $inix = shift || 0; # Input value set index |
820
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
my ($el, $colexpr, $colval, $sql, $sql1); |
823
|
|
|
|
|
|
|
$self->error ("$node->{NAME}: Cannot INSERT without TABLE") |
824
|
|
|
|
|
|
|
if(!$node->{TABLE}); |
825
|
|
|
|
|
|
|
# Construct the list of columns and list of values |
826
|
|
|
|
|
|
|
foreach ( keys %{$node->{_COLLIST}} ) { |
827
|
|
|
|
|
|
|
$el = $node->{_COLLIST}->{$_}; |
828
|
|
|
|
|
|
|
# Use EXPR if present |
829
|
|
|
|
|
|
|
if ( $el->{'EXPR'} ) { |
830
|
|
|
|
|
|
|
$colexpr = $el->{EXPR}; |
831
|
|
|
|
|
|
|
} else { |
832
|
|
|
|
|
|
|
$colexpr = $el->{NAME}; |
833
|
|
|
|
|
|
|
} |
834
|
|
|
|
|
|
|
$colval = $self->get_colval ($el, $dbh, $href, $inix, $resix); |
835
|
|
|
|
|
|
|
if ( defined $colval && $colval ne '' ) { |
836
|
|
|
|
|
|
|
# Add to the SQL if not empty |
837
|
|
|
|
|
|
|
$sql .= "\n\t$colexpr," if ($colexpr); |
838
|
|
|
|
|
|
|
$sql1 .= "\n\t$colval,"; |
839
|
|
|
|
|
|
|
} else { |
840
|
|
|
|
|
|
|
my $er = "Value #($inix,$resix) for col $colexpr not found"; |
841
|
|
|
|
|
|
|
# For INSERT all column values are required |
842
|
|
|
|
|
|
|
$self->trace ("* $er\n"); |
843
|
|
|
|
|
|
|
if ($node->{CARDINALITY} && $node->{CARDINALITY} eq 'OPTIONAL'){ |
844
|
|
|
|
|
|
|
return 1; |
845
|
|
|
|
|
|
|
} else { |
846
|
|
|
|
|
|
|
$self->error ("$er\n"); |
847
|
|
|
|
|
|
|
} } } |
848
|
|
|
|
|
|
|
if ( $sql ) { |
849
|
|
|
|
|
|
|
chop $sql; |
850
|
|
|
|
|
|
|
chop $sql1; |
851
|
|
|
|
|
|
|
$sql = "INSERT INTO $node->{TABLE} ($sql\n) VALUES ($sql1)"; |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
return $sql; |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
} # -create_insert |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
# _________________________________________________________________________ |
858
|
|
|
|
|
|
|
# Construct UPDATE statement |
859
|
|
|
|
|
|
|
# |
860
|
|
|
|
|
|
|
sub create_update { |
861
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
862
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
863
|
|
|
|
|
|
|
my $dbh = shift; # Database handle |
864
|
|
|
|
|
|
|
my $href = shift; # Global hash reference |
865
|
|
|
|
|
|
|
my $inix = shift || 0; # Input value set index |
866
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
$self->trace (" create_update ($node->{NAME},$inix,$resix)\n"); |
869
|
|
|
|
|
|
|
my ($el, $colexpr, $sql); |
870
|
|
|
|
|
|
|
$self->error ("$node->{NAME}: Cannot UPDATE without TABLE") |
871
|
|
|
|
|
|
|
if (!$node->{TABLE}); |
872
|
|
|
|
|
|
|
# Construct the list of columns with value assignments |
873
|
|
|
|
|
|
|
undef $sql; |
874
|
|
|
|
|
|
|
foreach ( keys %{$node->{_COLLIST}} ) { |
875
|
|
|
|
|
|
|
$el = $node->{_COLLIST}->{$_}; |
876
|
|
|
|
|
|
|
# print " -el = $el->{NAME}\n"; |
877
|
|
|
|
|
|
|
$colexpr = $self->get_colval ($el, $href, $dbh, $inix, $resix); |
878
|
|
|
|
|
|
|
# print " -colval = $colexpr\n"; |
879
|
|
|
|
|
|
|
if ( defined $colexpr && $colexpr ne "" ) { |
880
|
|
|
|
|
|
|
if ( $el->{EXPR} ) { |
881
|
|
|
|
|
|
|
$colexpr = "\n\t" . $el->{EXPR} . " = $colexpr,"; |
882
|
|
|
|
|
|
|
} else { |
883
|
|
|
|
|
|
|
$colexpr = "\n\t" . $el->{NAME} . " = $colexpr,"; |
884
|
|
|
|
|
|
|
} |
885
|
|
|
|
|
|
|
$sql .= $colexpr; |
886
|
|
|
|
|
|
|
# print " -sql = $sql\n"; |
887
|
|
|
|
|
|
|
} } |
888
|
|
|
|
|
|
|
# If anything was created |
889
|
|
|
|
|
|
|
if ( $sql ) { |
890
|
|
|
|
|
|
|
chop $sql; |
891
|
|
|
|
|
|
|
my $where = $self->create_where ($node, $href, $inix, $resix); |
892
|
|
|
|
|
|
|
$sql = "UPDATE $node->{TABLE} set $sql where $where"; |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
return $sql; |
895
|
|
|
|
|
|
|
} # -create_update |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
# _________________________________________________________________________ |
898
|
|
|
|
|
|
|
# Construct EXEC statement (only works with Sybase/SQL Server I suspect) |
899
|
|
|
|
|
|
|
# |
900
|
|
|
|
|
|
|
sub create_exec { |
901
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
902
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
903
|
|
|
|
|
|
|
my $dbh = shift; # Database handle |
904
|
|
|
|
|
|
|
my $href = shift; # Global hash reference |
905
|
|
|
|
|
|
|
my $inix = shift || 0; # Input value set index |
906
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
my ($el, $val, $sql, $dbdriver); |
909
|
|
|
|
|
|
|
if ( !defined $node->{PROC} ) { |
910
|
|
|
|
|
|
|
$self->error ("$node->{NAME}: PROC required where ACTION is EXEC"); |
911
|
|
|
|
|
|
|
} |
912
|
|
|
|
|
|
|
# Retrieve the driver name |
913
|
|
|
|
|
|
|
# $dbdriver = $dbh->{Driver}->{Name}; |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
# Collect the parameters |
916
|
|
|
|
|
|
|
foreach my $pname ( keys %{$node->{_PARLIST}} ) { |
917
|
|
|
|
|
|
|
my $el = $node->{_PARLIST}->{$pname}; |
918
|
|
|
|
|
|
|
my $val = $self->get_parval($el,$href,$inix,$resix); |
919
|
|
|
|
|
|
|
if ( !defined $val ) { |
920
|
|
|
|
|
|
|
if ($node->{CARDINALITY} && $node->{CARDINALITY} eq 'OPTIONAL'){ |
921
|
|
|
|
|
|
|
$self->trace ("Value #($inix,$resix) for $pname not found, " |
922
|
|
|
|
|
|
|
."but the tag is optional -- skipping"); |
923
|
|
|
|
|
|
|
return 1; |
924
|
|
|
|
|
|
|
} else { |
925
|
|
|
|
|
|
|
$self->error ( |
926
|
|
|
|
|
|
|
"$el->{NAME}: $pname value #($inix,$resix) not found"); |
927
|
|
|
|
|
|
|
} |
928
|
|
|
|
|
|
|
} else { |
929
|
|
|
|
|
|
|
$sql .= " \@$el->{NAME} = $val," |
930
|
|
|
|
|
|
|
} } |
931
|
|
|
|
|
|
|
if ( $sql ) { |
932
|
|
|
|
|
|
|
chop ($sql); |
933
|
|
|
|
|
|
|
} |
934
|
|
|
|
|
|
|
$sql = "EXEC $node->{PROC} $sql"; |
935
|
|
|
|
|
|
|
return $sql; |
936
|
|
|
|
|
|
|
} # -create_exec |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
#__________________________________________________________________________ |
939
|
|
|
|
|
|
|
# Execute the SQL for one index pair |
940
|
|
|
|
|
|
|
# |
941
|
|
|
|
|
|
|
sub execute_sql { |
942
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
943
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
944
|
|
|
|
|
|
|
my $dbh = shift; # Database handle |
945
|
|
|
|
|
|
|
my $href = shift; # External hash reference for parameters |
946
|
|
|
|
|
|
|
my $inix = shift || 0; # Input vector index |
947
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
my ($sql, $sth, $rc, $row); |
950
|
|
|
|
|
|
|
$self->trace (" execute_sql ($node->{NAME},$inix,$resix)\n"); |
951
|
|
|
|
|
|
|
# Verify that all key values are available |
952
|
|
|
|
|
|
|
foreach my $el ( keys %{$node->{_KEYLIST}} ) { |
953
|
|
|
|
|
|
|
my $val = $self->get_keyval ($node->{_KEYLIST}->{$el},$href,$inix,$resix); |
954
|
|
|
|
|
|
|
if ( !defined $val ) { |
955
|
|
|
|
|
|
|
if ($node->{CARDINALITY} && $node->{CARDINALITY} eq 'OPTIONAL'){ |
956
|
|
|
|
|
|
|
# Skipping the whole thing.. |
957
|
|
|
|
|
|
|
return 1; |
958
|
|
|
|
|
|
|
} else { |
959
|
|
|
|
|
|
|
$self->error ("$node->{NAME}: $el value #($inix,$resix) not found"); |
960
|
|
|
|
|
|
|
} } } |
961
|
|
|
|
|
|
|
# |
962
|
|
|
|
|
|
|
# Construct and execute SQL statement |
963
|
|
|
|
|
|
|
# |
964
|
|
|
|
|
|
|
# For different ACTIONs |
965
|
|
|
|
|
|
|
my $action = $node->{ACTION} ? $node->{ACTION} : 'SELECT'; |
966
|
|
|
|
|
|
|
for ( $action ) { |
967
|
|
|
|
|
|
|
if ( /INSERT/ ) { |
968
|
|
|
|
|
|
|
$sql = $self->create_insert ($node,$href,$dbh,$inix,$resix); |
969
|
|
|
|
|
|
|
$self->trace ("SQL = $sql\n"); |
970
|
|
|
|
|
|
|
$rc = $dbh->do ($sql) || croak ("$sql:\n" . $dbh->errstr); |
971
|
|
|
|
|
|
|
my %rowh = (); |
972
|
|
|
|
|
|
|
if ( $rc > 0 ) { |
973
|
|
|
|
|
|
|
$self->process_result($node,$dbh,\%rowh,$href,$inix,$resix); |
974
|
|
|
|
|
|
|
} |
975
|
|
|
|
|
|
|
} elsif ( /UPDATE/ ) { |
976
|
|
|
|
|
|
|
$sql = $self->create_update ($node,$href,$dbh,$inix,$resix); |
977
|
|
|
|
|
|
|
$self->trace ("SQL = $sql\n"); |
978
|
|
|
|
|
|
|
&{$self->{_OnPreDoSQL}} ($dbh) if ($self->{_OnPreDoSQL}); |
979
|
|
|
|
|
|
|
$rc = $dbh->do ($sql) || $self->error ("$sql\n".$dbh->errstr); |
980
|
|
|
|
|
|
|
&{$self->{_OnPostDoSQL}} ($dbh) if ($self->{_OnPostDoSQL}); |
981
|
|
|
|
|
|
|
my %rowh = (); |
982
|
|
|
|
|
|
|
if ( $rc > 0 ) { |
983
|
|
|
|
|
|
|
$self->process_result($node,$dbh,\%rowh,$href,$inix,$resix); |
984
|
|
|
|
|
|
|
} |
985
|
|
|
|
|
|
|
} elsif ( /SAVE/ ) { |
986
|
|
|
|
|
|
|
# Logic of the SAVE operation: update if found, insert if not |
987
|
|
|
|
|
|
|
$sql = $self->create_select ($node, $href, $dbh, $inix, $resix); |
988
|
|
|
|
|
|
|
$self->trace ("SQL = $sql\n"); |
989
|
|
|
|
|
|
|
$sth = $dbh->prepare ($sql) |
990
|
|
|
|
|
|
|
|| $self->error ("$sql\n".$dbh->errstr); |
991
|
|
|
|
|
|
|
$rc = $sth->execute() || croak ("$sql\n" . $dbh->errstr); |
992
|
|
|
|
|
|
|
if ( $row = $sth->fetchrow_hashref() ) { |
993
|
|
|
|
|
|
|
$sql = $self->create_update ($node,$href,$dbh,$inix,$resix); |
994
|
|
|
|
|
|
|
$self->trace ("SQL = $sql\n"); |
995
|
|
|
|
|
|
|
$rc = $dbh->do ($sql) |
996
|
|
|
|
|
|
|
|| $self->error("$sql\n".$dbh->errstr); |
997
|
|
|
|
|
|
|
} else { |
998
|
|
|
|
|
|
|
$sql = $self->create_insert ($node,$href,$dbh,$inix,$resix); |
999
|
|
|
|
|
|
|
$self->trace ("SQL = $sql\n"); |
1000
|
|
|
|
|
|
|
$rc = $dbh->do($sql) || $self->error("$sql\n".$dbh->errstr); |
1001
|
|
|
|
|
|
|
} |
1002
|
|
|
|
|
|
|
my %rowh = (); |
1003
|
|
|
|
|
|
|
if ( $rc > 0 ) { |
1004
|
|
|
|
|
|
|
$self->process_result($node,$dbh,\%rowh,$href,$inix,$resix); |
1005
|
|
|
|
|
|
|
} |
1006
|
|
|
|
|
|
|
} elsif ( /EXEC/ ) { |
1007
|
|
|
|
|
|
|
$sql = $self->create_exec ($node, $href, $dbh, $inix, $resix); |
1008
|
|
|
|
|
|
|
$self->trace ("SQL = $sql\n"); |
1009
|
|
|
|
|
|
|
$sth = $dbh->prepare ($sql) |
1010
|
|
|
|
|
|
|
|| $self->error ("$sql:\n" . $dbh->errstr); |
1011
|
|
|
|
|
|
|
# |
1012
|
|
|
|
|
|
|
# FIXME: we can analyze if the stored procedure does any selects |
1013
|
|
|
|
|
|
|
# and fetch only for those. If there are no selects, we probably |
1014
|
|
|
|
|
|
|
# should follow the INSERT/UPDATE schema and create one result |
1015
|
|
|
|
|
|
|
# row.. |
1016
|
|
|
|
|
|
|
# |
1017
|
|
|
|
|
|
|
$rc = $sth->execute() || $self->error ("$sql:\n".$dbh->errstr); |
1018
|
|
|
|
|
|
|
while ( $row = $sth->fetchrow_hashref() ) { |
1019
|
|
|
|
|
|
|
$self->process_result ($node,$dbh,$row,$href,$inix,$resix); |
1020
|
|
|
|
|
|
|
} |
1021
|
|
|
|
|
|
|
} elsif ( /SELECT/ || !defined $_ ) { |
1022
|
|
|
|
|
|
|
$sql = $self->create_select ($node, $href, $dbh, $inix, $resix); |
1023
|
|
|
|
|
|
|
$self->trace ("SQL = $sql\n"); |
1024
|
|
|
|
|
|
|
if ( !length $sql ) { |
1025
|
|
|
|
|
|
|
$self->error ("ERROR: Unable to create a SQL statement"); |
1026
|
|
|
|
|
|
|
} |
1027
|
|
|
|
|
|
|
$sth = $dbh->prepare ($sql) |
1028
|
|
|
|
|
|
|
|| $self->error ("$sql\n" . $dbh->errstr); |
1029
|
|
|
|
|
|
|
$rc = $sth->execute() |
1030
|
|
|
|
|
|
|
|| $self->error ("$sql\n" . $dbh->errstr); |
1031
|
|
|
|
|
|
|
while ( $row = $sth->fetchrow_hashref() ) { |
1032
|
|
|
|
|
|
|
$self->process_result ($node,$dbh,$row,$href,$inix,$resix); |
1033
|
|
|
|
|
|
|
} |
1034
|
|
|
|
|
|
|
} else { |
1035
|
|
|
|
|
|
|
$self->error ("$_: Unsupported action"); |
1036
|
|
|
|
|
|
|
} |
1037
|
|
|
|
|
|
|
} |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
} # -execute_sql |
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1042
|
|
|
|
|
|
|
# Function to be inoked per retrieved row |
1043
|
|
|
|
|
|
|
# Adds 2 pseudo-columns to the row: |
1044
|
|
|
|
|
|
|
# ->{_INIX} |
1045
|
|
|
|
|
|
|
# ->{_RESIX} |
1046
|
|
|
|
|
|
|
# |
1047
|
|
|
|
|
|
|
sub process_result { |
1048
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
1049
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
1050
|
|
|
|
|
|
|
my $dbh = shift; # DBI database handle |
1051
|
|
|
|
|
|
|
my $results = shift; # Result row hash reference |
1052
|
|
|
|
|
|
|
my $href = shift; # Global hash reference |
1053
|
|
|
|
|
|
|
my $inix = shift || 0; # Input value set index |
1054
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
1055
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
my ($colname, $val, $el); |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
# Collect the results on a per-colunm basis |
1059
|
|
|
|
|
|
|
foreach $colname ( keys %{$node->{_COLLIST}} ) { |
1060
|
|
|
|
|
|
|
$el = $node->{_COLLIST}->{$colname}; |
1061
|
|
|
|
|
|
|
if ( !defined $results->{$colname} ) { |
1062
|
|
|
|
|
|
|
$val = $self->get_colval ($el, $dbh, $href, $inix, $resix); |
1063
|
|
|
|
|
|
|
# De-format default values.. |
1064
|
|
|
|
|
|
|
if ( defined $val && $val =~ /^\'(.*)\'$/ ) { |
1065
|
|
|
|
|
|
|
$val = $1; |
1066
|
|
|
|
|
|
|
$val =~ s/\'\'/'/g; |
1067
|
|
|
|
|
|
|
} elsif ( defined $val && $val =~ /^\"(.*)\"$/ ) { |
1068
|
|
|
|
|
|
|
$val = $1; |
1069
|
|
|
|
|
|
|
$val =~ s/\"\"/"/g; |
1070
|
|
|
|
|
|
|
} |
1071
|
|
|
|
|
|
|
if ( 'NULL' eq uc($val) ) { |
1072
|
|
|
|
|
|
|
$val = undef; |
1073
|
|
|
|
|
|
|
} |
1074
|
|
|
|
|
|
|
$results->{$colname} = $val; |
1075
|
|
|
|
|
|
|
} } |
1076
|
|
|
|
|
|
|
# Now look from the results' perspective |
1077
|
|
|
|
|
|
|
foreach $colname ( keys %$results ) { |
1078
|
|
|
|
|
|
|
$results->{$colname} =~ s/\s*$// if (defined $results->{$colname}); |
1079
|
|
|
|
|
|
|
my $col = $node->{_COLLIST}->{$colname}; |
1080
|
|
|
|
|
|
|
if ( !$col ) { # Column does not exist |
1081
|
|
|
|
|
|
|
# Should we tolerate undefined results? |
1082
|
|
|
|
|
|
|
if ( $node->{TOLERANCE} && $node->{TOLERANCE} eq 'CREATE' |
1083
|
|
|
|
|
|
|
&& $colname !~ /^_/ ) { |
1084
|
|
|
|
|
|
|
$col = new "$PACKAGE::Element::COLUMN"; |
1085
|
|
|
|
|
|
|
$col->{NAME} = $colname; |
1086
|
|
|
|
|
|
|
$col->{_PARENT_TAG} = $node; |
1087
|
|
|
|
|
|
|
push @{$node->{Kids}}, $col; |
1088
|
|
|
|
|
|
|
$self->{_COLLIST}->{$colname} = $col; |
1089
|
|
|
|
|
|
|
} elsif ( $node->{TOLERANCE} && $node->{TOLERANCE} eq 'REJECT' ) { |
1090
|
|
|
|
|
|
|
$self->error ( |
1091
|
|
|
|
|
|
|
"ERROR: Unknown column $colname in the result set"); |
1092
|
|
|
|
|
|
|
# } elsif ( $self->{TOLERANCE} eq 'IGNORE' ) { |
1093
|
|
|
|
|
|
|
} else { # IGNORE by default |
1094
|
|
|
|
|
|
|
delete $$results{$colname}; |
1095
|
|
|
|
|
|
|
} } |
1096
|
|
|
|
|
|
|
} |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
# And push it into results array |
1099
|
|
|
|
|
|
|
# ... BUT COPY FIRST ... |
1100
|
|
|
|
|
|
|
my $rescopy; |
1101
|
|
|
|
|
|
|
foreach $colname ( keys %$results ) { |
1102
|
|
|
|
|
|
|
$rescopy->{$colname} = $results->{$colname}; |
1103
|
|
|
|
|
|
|
if ( $rescopy->{$colname} && |
1104
|
|
|
|
|
|
|
$node->{_COLLIST}->{$colname}->{BLTIN} ) { # Builtin |
1105
|
|
|
|
|
|
|
my $bltin = $node->{_COLLIST}->{$colname}->{BLTIN}; |
1106
|
|
|
|
|
|
|
$self->trace ("BUILTIN func: $bltin\n"); |
1107
|
|
|
|
|
|
|
my $cmd = '$rescopy->{$colname} = &' . $bltin . ';'; |
1108
|
|
|
|
|
|
|
@_ = ($self,$node,$rescopy->{$colname}); |
1109
|
|
|
|
|
|
|
$self->trace ("BUILTIN: $cmd\n"); |
1110
|
|
|
|
|
|
|
eval $cmd; |
1111
|
|
|
|
|
|
|
$self->error("Error in BUILT-IN $bltin of $colname: $@") if($@); |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
} |
1114
|
|
|
|
|
|
|
$rescopy->{_INIX} = $inix; |
1115
|
|
|
|
|
|
|
$rescopy->{_RESIX} = $resix; |
1116
|
|
|
|
|
|
|
push @{$node->{_RESULTS}}, $rescopy; |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
} # -process_result |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1121
|
|
|
|
|
|
|
# Execute the SQL for all parent results and input values |
1122
|
|
|
|
|
|
|
# |
1123
|
|
|
|
|
|
|
sub exec { |
1124
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
1125
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
1126
|
|
|
|
|
|
|
my $dbh = shift; # Database handle |
1127
|
|
|
|
|
|
|
my $href = shift; # External hash reference for parameters |
1128
|
|
|
|
|
|
|
|
1129
|
|
|
|
|
|
|
$self->trace ("\n exec $node->{NAME}\n"); |
1130
|
|
|
|
|
|
|
my $success = 1; |
1131
|
|
|
|
|
|
|
my $papa = $node->{_PARENT_TAG}; |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
my $nres; |
1134
|
|
|
|
|
|
|
if ( $papa ) { |
1135
|
|
|
|
|
|
|
$nres = $papa->{_RESULTS} ? scalar @{$papa->{_RESULTS}} : 0; |
1136
|
|
|
|
|
|
|
} else { |
1137
|
|
|
|
|
|
|
# No parent tag -- pick up the key #0 and count number of values. |
1138
|
|
|
|
|
|
|
my @keynames = defined $node->{_KEYLIST} |
1139
|
|
|
|
|
|
|
? keys %{$node->{_KEYLIST}} : (); |
1140
|
|
|
|
|
|
|
my $key0 = scalar @keynames |
1141
|
|
|
|
|
|
|
? $node->{_KEYLIST}->{$keynames[0]}->{PARENT_NAME} |
1142
|
|
|
|
|
|
|
? $node->{_KEYLIST}->{$keynames[0]}->{PARENT_NAME} |
1143
|
|
|
|
|
|
|
: $keynames[0] |
1144
|
|
|
|
|
|
|
: undef; |
1145
|
|
|
|
|
|
|
$nres = defined $key0 |
1146
|
|
|
|
|
|
|
? scalar @{$href->{$key0}} : 1; # No keys -- execute once |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
my $nval = $node->{_INVALUES} ? scalar @{$node->{_INVALUES}} : 0; |
1150
|
|
|
|
|
|
|
my $inix = 0; |
1151
|
|
|
|
|
|
|
$self->trace (" nval = $nval\n"); |
1152
|
|
|
|
|
|
|
do { # Execute once with no input values |
1153
|
|
|
|
|
|
|
for ( my $resix=0; $resix<$nres; $resix++ ) { |
1154
|
|
|
|
|
|
|
# But not without results |
1155
|
|
|
|
|
|
|
$success &= $self->execute_sql($node,$dbh,$href,$inix,$resix); |
1156
|
|
|
|
|
|
|
} |
1157
|
|
|
|
|
|
|
} while ( ++$inix < $nval ); |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
$success; |
1160
|
|
|
|
|
|
|
} # -exec |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1163
|
|
|
|
|
|
|
# Recursively execute SQL statements for all |
1164
|
|
|
|
|
|
|
# |
1165
|
|
|
|
|
|
|
sub rexec { |
1166
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
1167
|
|
|
|
|
|
|
my $dbh = shift; # database handle |
1168
|
|
|
|
|
|
|
my $href = shift; # External hash reference for parameters |
1169
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE|CHILD|REFERENCE |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
$node = $self->{_Template} if (!$node); |
1172
|
|
|
|
|
|
|
$self->trace ("\nrexec $node->{NAME}\n"); |
1173
|
|
|
|
|
|
|
my ($el, $success); |
1174
|
|
|
|
|
|
|
if ( !$dbh ) { |
1175
|
|
|
|
|
|
|
# |
1176
|
|
|
|
|
|
|
# FIXME: Allow for NODBH invocation |
1177
|
|
|
|
|
|
|
# |
1178
|
|
|
|
|
|
|
$self->error ("No database handle"); |
1179
|
|
|
|
|
|
|
} |
1180
|
|
|
|
|
|
|
# Execute for yourself |
1181
|
|
|
|
|
|
|
$success = $self->exec ($node, $dbh, $href); |
1182
|
|
|
|
|
|
|
foreach $el ( @{$node->{'Kids'}} ) { |
1183
|
|
|
|
|
|
|
if ( (ref $el) =~ /::REFERENCE$/ || (ref $el) =~ /::CHILD$/ ) { |
1184
|
|
|
|
|
|
|
$success &= $self->rexec ($dbh, $href, $el); |
1185
|
|
|
|
|
|
|
} } |
1186
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
$success; |
1188
|
|
|
|
|
|
|
} # -rexec |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1191
|
|
|
|
|
|
|
# Output the message |
1192
|
|
|
|
|
|
|
# |
1193
|
|
|
|
|
|
|
sub output_message { |
1194
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
#if ( $self->{TYPE} eq 'XML' ) { |
1197
|
|
|
|
|
|
|
return $self->output_xml(); |
1198
|
|
|
|
|
|
|
#} else { |
1199
|
|
|
|
|
|
|
# print $self->{TYPE} . ": not implemented\n" |
1200
|
|
|
|
|
|
|
#} |
1201
|
|
|
|
|
|
|
} |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1204
|
|
|
|
|
|
|
# Should have executed prior to this |
1205
|
|
|
|
|
|
|
# |
1206
|
|
|
|
|
|
|
# FIXME: Prints multuple childs |
1207
|
|
|
|
|
|
|
# |
1208
|
|
|
|
|
|
|
# |
1209
|
|
|
|
|
|
|
sub output_xml { |
1210
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
1211
|
|
|
|
|
|
|
my $level = shift || 0; # Level |
1212
|
|
|
|
|
|
|
my $resix = shift || 0; # Parent result set index |
1213
|
|
|
|
|
|
|
my $node = shift || $self->{_Template}; # TEMPLATE|CHILD|REFERENCE |
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
my ($r, $i, $j, $el, $el1, $res, $rref, $xml); |
1216
|
|
|
|
|
|
|
$xml = ""; # Target string |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
# see if there's anything to output |
1219
|
|
|
|
|
|
|
my $found = 0; |
1220
|
|
|
|
|
|
|
foreach (@{$node->{_RESULTS}}) { |
1221
|
|
|
|
|
|
|
if ( $_->{_RESIX} == $resix ) { |
1222
|
|
|
|
|
|
|
$found = 1; |
1223
|
|
|
|
|
|
|
} } |
1224
|
|
|
|
|
|
|
if ( !$found ) { |
1225
|
|
|
|
|
|
|
if ( (ref $node) =~ /::TEMPLATE$/ ) { # Always print the template |
1226
|
|
|
|
|
|
|
for ( $j=0;$j<$level;$j++ ) { $xml .= " "; } |
1227
|
|
|
|
|
|
|
$xml .= "<$node->{NAME} />\n"; |
1228
|
|
|
|
|
|
|
return $xml; |
1229
|
|
|
|
|
|
|
} else { # ... but nothing else! |
1230
|
|
|
|
|
|
|
return $xml; |
1231
|
|
|
|
|
|
|
} } |
1232
|
|
|
|
|
|
|
$i = 0; # Initial input value. The loop will execute once always |
1233
|
|
|
|
|
|
|
do { |
1234
|
|
|
|
|
|
|
for ( $r=0; $node->{_RESULTS}->[$r]; $r++ ) { # $r is resix for kids |
1235
|
|
|
|
|
|
|
# >>>>>>>>>> |
1236
|
|
|
|
|
|
|
$rref = $node->{_RESULTS}->[$r]; |
1237
|
|
|
|
|
|
|
if ( $rref->{_INIX} == $i && $rref->{_RESIX} == $resix |
1238
|
|
|
|
|
|
|
# FIXME: this is a hack... |
1239
|
|
|
|
|
|
|
&& !$rref->{_PRINTED} ) { |
1240
|
|
|
|
|
|
|
# Output the tag |
1241
|
|
|
|
|
|
|
for ( $j=0;$j<$level;$j++ ) { $xml .= " "; } |
1242
|
|
|
|
|
|
|
$xml .= "<$node->{NAME}"; |
1243
|
|
|
|
|
|
|
# Output columns with the face of 'ATTRIBUTE' as attributes |
1244
|
|
|
|
|
|
|
foreach my $elname ( keys %{$node->{_COLLIST}} ) { |
1245
|
|
|
|
|
|
|
$el = $node->{_COLLIST}->{$elname}; |
1246
|
|
|
|
|
|
|
if ( $el->{FACE} && $el->{FACE} eq 'ATTRIBUTE' ) { |
1247
|
|
|
|
|
|
|
if (defined $rref->{$el->{NAME}} && $rref->{$el->{NAME}} ne ''){ |
1248
|
|
|
|
|
|
|
$xml .= " $el->{'NAME'}=\"" . |
1249
|
|
|
|
|
|
|
HTML::Entities::encode($rref->{$el->{NAME}},'&<>"').'"'; |
1250
|
|
|
|
|
|
|
} } } |
1251
|
|
|
|
|
|
|
$xml .= ">\n"; |
1252
|
|
|
|
|
|
|
# Output the rest of the stuff |
1253
|
|
|
|
|
|
|
foreach $el ( @{$node->{'Kids'}} ) { |
1254
|
|
|
|
|
|
|
if ( (ref $el) =~ /::COLUMN$/ && |
1255
|
|
|
|
|
|
|
(!defined $el->{FACE} || $el->{FACE} eq 'TAG') ) { |
1256
|
|
|
|
|
|
|
if ( !$el->{'HIDDEN'} ) { |
1257
|
|
|
|
|
|
|
for ( $j=0;$j<$level+1;$j++ ) { $xml .= " "; } |
1258
|
|
|
|
|
|
|
if ( defined $rref->{$el->{NAME}} |
1259
|
|
|
|
|
|
|
&& $rref->{$el->{NAME}} ne '' ) { |
1260
|
|
|
|
|
|
|
$xml .= "<$el->{'NAME'}>" |
1261
|
|
|
|
|
|
|
. HTML::Entities::encode($rref->{$el->{NAME}},"&<>") |
1262
|
|
|
|
|
|
|
. "$el->{'NAME'}>\n"; |
1263
|
|
|
|
|
|
|
} else { |
1264
|
|
|
|
|
|
|
$xml .= "<$el->{'NAME'} />\n"; |
1265
|
|
|
|
|
|
|
} |
1266
|
|
|
|
|
|
|
} |
1267
|
|
|
|
|
|
|
} elsif ((ref $el)=~ /::REFERENCE$/ || (ref $el)=~ /::CHILD$/) { |
1268
|
|
|
|
|
|
|
my $niter = (defined $el->{_INVALUES}) |
1269
|
|
|
|
|
|
|
? scalar @{$el->{_INVALUES}} |
1270
|
|
|
|
|
|
|
: 0; |
1271
|
|
|
|
|
|
|
for ( $i=0; $i{_RESULTS}}; $i++ ) { |
1272
|
|
|
|
|
|
|
$j = 0; |
1273
|
|
|
|
|
|
|
do { |
1274
|
|
|
|
|
|
|
$xml .= $self->output_xml ($level+1,$r,$el); |
1275
|
|
|
|
|
|
|
} while ( $j++ < $niter ); |
1276
|
|
|
|
|
|
|
} |
1277
|
|
|
|
|
|
|
} |
1278
|
|
|
|
|
|
|
} |
1279
|
|
|
|
|
|
|
for ( $j=0;$j<$level;$j++ ) { $xml .= " "; } |
1280
|
|
|
|
|
|
|
$xml .= "$node->{'NAME'}>\n"; |
1281
|
|
|
|
|
|
|
# FIXME: this is the second part of the hack.. See above.. |
1282
|
|
|
|
|
|
|
$rref->{_PRINTED} = 1; |
1283
|
|
|
|
|
|
|
} |
1284
|
|
|
|
|
|
|
# >>>>>>>>>> |
1285
|
|
|
|
|
|
|
} ##for $r |
1286
|
|
|
|
|
|
|
} while ( $node->{_INVALUES}->[$i++] ); |
1287
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
return $xml; |
1289
|
|
|
|
|
|
|
} # -output_xml |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1292
|
|
|
|
|
|
|
# Test BUILT-IN |
1293
|
|
|
|
|
|
|
# |
1294
|
|
|
|
|
|
|
sub t_bltin { |
1295
|
|
|
|
|
|
|
print "t_bltin:"; |
1296
|
|
|
|
|
|
|
foreach (@_) { |
1297
|
|
|
|
|
|
|
print "\t$_\n"; |
1298
|
|
|
|
|
|
|
} |
1299
|
|
|
|
|
|
|
return "returned by t_bltin"; |
1300
|
|
|
|
|
|
|
} |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1303
|
|
|
|
|
|
|
# Fix the GMTIME values |
1304
|
|
|
|
|
|
|
# |
1305
|
|
|
|
|
|
|
sub fix_gmdatetime { |
1306
|
|
|
|
|
|
|
my $self = shift; # XMLMessage |
1307
|
|
|
|
|
|
|
my $node = shift; # TEMPLATE | CHILD | REFERENCE |
1308
|
|
|
|
|
|
|
my $val = shift || undef; |
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
if ( !defined $val ) { |
1311
|
|
|
|
|
|
|
return undef; |
1312
|
|
|
|
|
|
|
} |
1313
|
|
|
|
|
|
|
my $direction = $node->{_PARENT_TAG}->{ACTION} |
1314
|
|
|
|
|
|
|
? $node->{_PARENT_TAG}->{ACTION} eq 'SELECT' |
1315
|
|
|
|
|
|
|
? 'TOGMT' |
1316
|
|
|
|
|
|
|
: 'FROMGMT' |
1317
|
|
|
|
|
|
|
: 'TOGMT'; |
1318
|
|
|
|
|
|
|
my $curfmt = ''; |
1319
|
|
|
|
|
|
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); |
1320
|
|
|
|
|
|
|
my $hmon = { 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, |
1321
|
|
|
|
|
|
|
'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, |
1322
|
|
|
|
|
|
|
'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11 |
1323
|
|
|
|
|
|
|
}; |
1324
|
|
|
|
|
|
|
if ($val =~ /^\s*(\d{4})\/(\d{1,2})\/(\d{1,2})\s*(\d{1,2}):(\d{1,2})/ || |
1325
|
|
|
|
|
|
|
$val =~ /^\s*(\d{4})-(\d{1,2})-(\d{1,2})\s*(\d{1,2}):(\d{1,2})/ |
1326
|
|
|
|
|
|
|
) { |
1327
|
|
|
|
|
|
|
# E.g. 2000-3-21 12:05 |
1328
|
|
|
|
|
|
|
$curfmt = 'GMT'; # SES/SIS GMT |
1329
|
|
|
|
|
|
|
} elsif ( $val =~ /^\s*(\d{8})\s*(\d{4})/ ) { |
1330
|
|
|
|
|
|
|
# E.g. 20000321 1205 |
1331
|
|
|
|
|
|
|
$curfmt = 'GMTSHORT'; # Mark sends it like this.. |
1332
|
|
|
|
|
|
|
} elsif ( $val =~ |
1333
|
|
|
|
|
|
|
/^\s*(\D{3})\s*(\d{1,2})\s*(\d{4})\s*(\d{1,2}):(\d{2})(\D{2})/ |
1334
|
|
|
|
|
|
|
) { |
1335
|
|
|
|
|
|
|
# E.g. Mar 21 2000 12:05:46:350PM |
1336
|
|
|
|
|
|
|
$curfmt = 'SYBASE'; # As delivered by the Sybase DB engine |
1337
|
|
|
|
|
|
|
} |
1338
|
|
|
|
|
|
|
if ( $direction eq 'TOGMT' && $curfmt eq 'SYBASE' ) { |
1339
|
|
|
|
|
|
|
# - Transform from SYBASE to GMT |
1340
|
|
|
|
|
|
|
# This time is received from database and it's local, |
1341
|
|
|
|
|
|
|
# most probably according to the TZ environment variable |
1342
|
|
|
|
|
|
|
# - Calculate the time difference to GMT |
1343
|
|
|
|
|
|
|
my $ctime = time(); |
1344
|
|
|
|
|
|
|
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) |
1345
|
|
|
|
|
|
|
= gmtime($ctime); |
1346
|
|
|
|
|
|
|
my $time_t = POSIX::mktime ($sec,$min,$hour,$mday,$mon,$year); |
1347
|
|
|
|
|
|
|
my $tdiff = $ctime - $time_t; |
1348
|
|
|
|
|
|
|
($year,$mon,$mday,$hour,$min) = ($3, $1, $2, $4, $5); |
1349
|
|
|
|
|
|
|
$mon = $hmon->{$mon} ? $hmon->{$mon} : 0; |
1350
|
|
|
|
|
|
|
$hour += 12 if ( $6 && $6 eq 'PM' && $hour != 12 ); |
1351
|
|
|
|
|
|
|
$year -= 1900; |
1352
|
|
|
|
|
|
|
$time_t = POSIX::mktime (0,$min,$hour,$mday,$mon,$year); |
1353
|
|
|
|
|
|
|
$val = POSIX::strftime "%Y/%m/%d %H:%M", gmtime($time_t-$tdiff); |
1354
|
|
|
|
|
|
|
# print "Date = ", POSIX::ctime($time_t); |
1355
|
|
|
|
|
|
|
} elsif ( $direction eq 'FROMGMT' && $curfmt eq 'GMT' ) { |
1356
|
|
|
|
|
|
|
# - Transform from GMT to SYBASE |
1357
|
|
|
|
|
|
|
($year,$mon,$mday,$hour,$min) = ($1, $2, $3, $4, $5); |
1358
|
|
|
|
|
|
|
$mon--; |
1359
|
|
|
|
|
|
|
$year -= 1900; |
1360
|
|
|
|
|
|
|
my $time_t = POSIX::mktime (0,$min,$hour,$mday,$mon,$year); |
1361
|
|
|
|
|
|
|
if ( $node->{DATATYPE} eq 'DATE' ) { |
1362
|
|
|
|
|
|
|
$val = POSIX::strftime "%b %d %Y", localtime($time_t); |
1363
|
|
|
|
|
|
|
} elsif ( $node->{DATATYPE} eq 'TIME' ) { |
1364
|
|
|
|
|
|
|
$val = POSIX::strftime "%I:%M", localtime($time_t); |
1365
|
|
|
|
|
|
|
} else { |
1366
|
|
|
|
|
|
|
$val = POSIX::strftime "%b %d %Y %I:%M:00:000%p", |
1367
|
|
|
|
|
|
|
localtime($time_t); |
1368
|
|
|
|
|
|
|
} |
1369
|
|
|
|
|
|
|
} elsif ( $direction eq 'FROMGMT' && $curfmt eq 'GMTSHORT' ) { |
1370
|
|
|
|
|
|
|
# - Transform from GMTSHORT to SYBASE |
1371
|
|
|
|
|
|
|
my ($ymd,$hmi) = ($1,$2); |
1372
|
|
|
|
|
|
|
$year = substr ($ymd,0,4); |
1373
|
|
|
|
|
|
|
$mon = substr ($ymd,4,2); |
1374
|
|
|
|
|
|
|
$mday = substr ($ymd,6,2); |
1375
|
|
|
|
|
|
|
$hour = substr ($hmi,0,2); |
1376
|
|
|
|
|
|
|
$min = substr ($hmi,2,2); |
1377
|
|
|
|
|
|
|
$mon--; |
1378
|
|
|
|
|
|
|
$year -= 1900; |
1379
|
|
|
|
|
|
|
my $time_t = POSIX::mktime (0,$min,$hour,$mday,$mon,$year); |
1380
|
|
|
|
|
|
|
if ( $node->{DATATYPE} eq 'DATE' ) { |
1381
|
|
|
|
|
|
|
$val = POSIX::strftime "%b %d %Y", localtime($time_t); |
1382
|
|
|
|
|
|
|
} elsif ( $node->{DATATYPE} eq 'TIME' ) { |
1383
|
|
|
|
|
|
|
$val = POSIX::strftime "%I:%M:00:000%p", localtime($time_t); |
1384
|
|
|
|
|
|
|
} else { |
1385
|
|
|
|
|
|
|
$val = POSIX::strftime "%b %d %Y %I:%M:00:000%p", |
1386
|
|
|
|
|
|
|
localtime($time_t); |
1387
|
|
|
|
|
|
|
} |
1388
|
|
|
|
|
|
|
} # Otherwise don't touch |
1389
|
|
|
|
|
|
|
return $val; |
1390
|
|
|
|
|
|
|
} ##fix_gmdatetime |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
|
1393
|
|
|
|
|
|
|
|
1394
|
|
|
|
|
|
|
1; |
1395
|
|
|
|
|
|
|
# -package DBIx::XMLMessage; |
1396
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
|
1399
|
|
|
|
|
|
|
# _________________________________________________________________________ |
1400
|
|
|
|
|
|
|
# Tag Prototype |
1401
|
|
|
|
|
|
|
# |
1402
|
|
|
|
|
|
|
package DBIx::XMLMessage::Element; |
1403
|
|
|
|
|
|
|
|
1404
|
|
|
|
|
|
|
use strict; |
1405
|
|
|
|
|
|
|
use vars qw (@ISA %EXPORT_TAGS $VERSION @rattrs); |
1406
|
|
|
|
|
|
|
$VERSION = '0.01'; |
1407
|
|
|
|
|
|
|
@ISA = qw ( Exporter ); |
1408
|
|
|
|
|
|
|
%EXPORT_TAGS = ('elements' => [ 'VERSION', '%TEMPLATE::', |
1409
|
|
|
|
|
|
|
'%REFERENCE::', '%CHILD::', '%KEY::', '%COLUMN::', '%PARAMETER::']); |
1410
|
|
|
|
|
|
|
Exporter::export_ok_tags ('elements'); |
1411
|
|
|
|
|
|
|
@rattrs = qw (NAME); |
1412
|
|
|
|
|
|
|
1; |
1413
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1415
|
|
|
|
|
|
|
# Tag TEMPLATE |
1416
|
|
|
|
|
|
|
# |
1417
|
|
|
|
|
|
|
package DBIx::XMLMessage::TEMPLATE; |
1418
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
use vars qw (@ISA %EXPORT_TAGS @rattrs @oattrs @rkids @okids); |
1420
|
|
|
|
|
|
|
@ISA = qw (DBIx::XMLMessage::Element); |
1421
|
|
|
|
|
|
|
@rattrs = qw (NAME VERSION TYPE); |
1422
|
|
|
|
|
|
|
@oattrs = qw ( |
1423
|
|
|
|
|
|
|
ACTION |
1424
|
|
|
|
|
|
|
DEBUG |
1425
|
|
|
|
|
|
|
PROC |
1426
|
|
|
|
|
|
|
RTRIMTEXT |
1427
|
|
|
|
|
|
|
TABLE |
1428
|
|
|
|
|
|
|
TOLERANCE |
1429
|
|
|
|
|
|
|
_CHILIST |
1430
|
|
|
|
|
|
|
_COLLIST |
1431
|
|
|
|
|
|
|
_KEYLIST |
1432
|
|
|
|
|
|
|
_PARENT_TAG |
1433
|
|
|
|
|
|
|
_PARLIST |
1434
|
|
|
|
|
|
|
_REFLIST |
1435
|
|
|
|
|
|
|
); |
1436
|
|
|
|
|
|
|
@okids = qw (COLUMN REFERENCE CHILD PARAMETER KEY); |
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
sub new { |
1439
|
|
|
|
|
|
|
my ($class, %args) = @_; |
1440
|
|
|
|
|
|
|
return bless \%args, $class; |
1441
|
|
|
|
|
|
|
} |
1442
|
|
|
|
|
|
|
1; |
1443
|
|
|
|
|
|
|
|
1444
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1445
|
|
|
|
|
|
|
# Tag KEY |
1446
|
|
|
|
|
|
|
# |
1447
|
|
|
|
|
|
|
package DBIx::XMLMessage::KEY; |
1448
|
|
|
|
|
|
|
use vars qw (@ISA %EXPORT_TAGS @rattrs @oattrs @rkids @okids); |
1449
|
|
|
|
|
|
|
@ISA = qw (DBIx::XMLMessage::Element); |
1450
|
|
|
|
|
|
|
@rattrs = qw (NAME); |
1451
|
|
|
|
|
|
|
@oattrs = qw (_PARENT_TAG DATATYPE RTRIMTEXT DEFAULT PARENT_NAME); |
1452
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
sub new { |
1454
|
|
|
|
|
|
|
my ($class, %args) = @_; |
1455
|
|
|
|
|
|
|
return bless \%args, $class; |
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
1; |
1458
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1460
|
|
|
|
|
|
|
# Tag COLUMN |
1461
|
|
|
|
|
|
|
# |
1462
|
|
|
|
|
|
|
package DBIx::XMLMessage::COLUMN; |
1463
|
|
|
|
|
|
|
use vars qw (@ISA %EXPORT_TAGS @rattrs @oattrs @rkids @okids); |
1464
|
|
|
|
|
|
|
@ISA = qw (DBIx::XMLMessage::Element); |
1465
|
|
|
|
|
|
|
@rattrs = qw (NAME); |
1466
|
|
|
|
|
|
|
@oattrs = qw ( |
1467
|
|
|
|
|
|
|
ACTION |
1468
|
|
|
|
|
|
|
BLTIN |
1469
|
|
|
|
|
|
|
CARDINALITY |
1470
|
|
|
|
|
|
|
DATATYPE |
1471
|
|
|
|
|
|
|
DEBUG |
1472
|
|
|
|
|
|
|
DEFAULT |
1473
|
|
|
|
|
|
|
EXPR |
1474
|
|
|
|
|
|
|
FACE |
1475
|
|
|
|
|
|
|
GENERATE_PK |
1476
|
|
|
|
|
|
|
HIDDEN |
1477
|
|
|
|
|
|
|
RTRIMTEXT |
1478
|
|
|
|
|
|
|
TOLERANCE |
1479
|
|
|
|
|
|
|
_PARENT_TAG |
1480
|
|
|
|
|
|
|
); |
1481
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
sub new { |
1483
|
|
|
|
|
|
|
my ($class, %args) = @_; |
1484
|
|
|
|
|
|
|
return bless \%args, $class; |
1485
|
|
|
|
|
|
|
} |
1486
|
|
|
|
|
|
|
1; |
1487
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1489
|
|
|
|
|
|
|
# Tag REFERENCE |
1490
|
|
|
|
|
|
|
# |
1491
|
|
|
|
|
|
|
package DBIx::XMLMessage::REFERENCE; |
1492
|
|
|
|
|
|
|
use vars qw (@ISA %EXPORT_TAGS @rattrs @oattrs @rkids @okids); |
1493
|
|
|
|
|
|
|
@ISA = qw (DBIx::XMLMessage::Element); |
1494
|
|
|
|
|
|
|
@rattrs = qw (NAME); |
1495
|
|
|
|
|
|
|
@oattrs = qw ( |
1496
|
|
|
|
|
|
|
ACTION |
1497
|
|
|
|
|
|
|
CARDINALITY |
1498
|
|
|
|
|
|
|
DEBUG |
1499
|
|
|
|
|
|
|
PROC |
1500
|
|
|
|
|
|
|
RTRIMTEXT |
1501
|
|
|
|
|
|
|
TABLE |
1502
|
|
|
|
|
|
|
TOLERANCE |
1503
|
|
|
|
|
|
|
WHERE_CLAUSE |
1504
|
|
|
|
|
|
|
_CHILIST |
1505
|
|
|
|
|
|
|
_COLLIST |
1506
|
|
|
|
|
|
|
_KEYLIST |
1507
|
|
|
|
|
|
|
_PARENT_TAG |
1508
|
|
|
|
|
|
|
_PARLIST |
1509
|
|
|
|
|
|
|
_REFLIST |
1510
|
|
|
|
|
|
|
); |
1511
|
|
|
|
|
|
|
@okids = qw (COLUMN REFERENCE CHILD PARAMETER KEY); |
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
sub new { |
1514
|
|
|
|
|
|
|
my ($class, %args) = @_; |
1515
|
|
|
|
|
|
|
return bless \%args, $class; |
1516
|
|
|
|
|
|
|
} |
1517
|
|
|
|
|
|
|
1; |
1518
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1520
|
|
|
|
|
|
|
# Tag CHILD |
1521
|
|
|
|
|
|
|
# |
1522
|
|
|
|
|
|
|
package DBIx::XMLMessage::CHILD; |
1523
|
|
|
|
|
|
|
use vars qw (@ISA %EXPORT_TAGS @rattrs @oattrs @rkids @okids); |
1524
|
|
|
|
|
|
|
@ISA = qw (DBIx::XMLMessage::Element); |
1525
|
|
|
|
|
|
|
@rattrs = qw (NAME); |
1526
|
|
|
|
|
|
|
@oattrs = qw ( |
1527
|
|
|
|
|
|
|
ACTION |
1528
|
|
|
|
|
|
|
CARDINALITY |
1529
|
|
|
|
|
|
|
DEBUG |
1530
|
|
|
|
|
|
|
MAXROWS |
1531
|
|
|
|
|
|
|
PROC |
1532
|
|
|
|
|
|
|
RTRIMTEXT |
1533
|
|
|
|
|
|
|
TABLE |
1534
|
|
|
|
|
|
|
TOLERANCE |
1535
|
|
|
|
|
|
|
WHERE_CLAUSE |
1536
|
|
|
|
|
|
|
_CHILIST |
1537
|
|
|
|
|
|
|
_COLLIST |
1538
|
|
|
|
|
|
|
_KEYLIST |
1539
|
|
|
|
|
|
|
_PARENT_TAG |
1540
|
|
|
|
|
|
|
_PARLIST |
1541
|
|
|
|
|
|
|
_REFLIST |
1542
|
|
|
|
|
|
|
); |
1543
|
|
|
|
|
|
|
@okids = qw (COLUMN REFERENCE CHILD PARAMETER KEY); |
1544
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
sub new { |
1546
|
|
|
|
|
|
|
my ($class, %args) = @_; |
1547
|
|
|
|
|
|
|
return bless \%args, $class; |
1548
|
|
|
|
|
|
|
} |
1549
|
|
|
|
|
|
|
1; |
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
#__________________________________________________________________________ |
1552
|
|
|
|
|
|
|
# Tag PARAMETER |
1553
|
|
|
|
|
|
|
# |
1554
|
|
|
|
|
|
|
package DBIx::XMLMessage::PARAMETER; |
1555
|
|
|
|
|
|
|
use vars qw (@ISA %EXPORT_TAGS @rattrs @oattrs @rkids @okids); |
1556
|
|
|
|
|
|
|
@ISA = qw (DBIx::XMLMessage::Element); |
1557
|
|
|
|
|
|
|
@rattrs = qw (NAME); |
1558
|
|
|
|
|
|
|
@oattrs = qw ( |
1559
|
|
|
|
|
|
|
CARDINALITY |
1560
|
|
|
|
|
|
|
DATATYPE |
1561
|
|
|
|
|
|
|
DEFAULT |
1562
|
|
|
|
|
|
|
EXPR |
1563
|
|
|
|
|
|
|
RTRIMTEXT |
1564
|
|
|
|
|
|
|
_PARENT_TAG |
1565
|
|
|
|
|
|
|
); |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
sub new { |
1568
|
|
|
|
|
|
|
my ($class, %args) = @_; |
1569
|
|
|
|
|
|
|
return bless \%args, $class; |
1570
|
|
|
|
|
|
|
} |
1571
|
|
|
|
|
|
|
1; |
1572
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
__END__ |