Subversion Repositories DevTools

Rev

Rev 5919 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1038 dpurdie 1
########################################################################
2
# Copyright ( C ) 2006 ERG Limited, All rights reserved
3
#
4
# Module name   : jats.sh
5
# Module type   : Makefile system
6
# Compiler(s)   : n/a
7
# Environment(s): jats
8
#
9
# Description   : This package has been created to simplify the migration
10
#                 of the deployments scripts that use an DBI:ODBC interface
11
#                 to Release Manager, to a JDBC interface.
12
#
13
#                 The package provides suffient methods to trick the existing
14
#                 code into working. No More. No less.
15
#
16
# Usage:
17
#
18
# Version   Who      Date        Description
19
#
20
#......................................................................#
21
 
22
require 5.006_001;
23
use strict;
24
use warnings;
25
#use Data::Dumper;
26
use Cwd;
27
use IPC::Open2;
28
 
29
package DBI;
30
our $VERSION = '2.0.1';
31
 
32
 
33
use Exporter;
34
our @EXPORT = qw();
35
our @EXPORT_OK = (@EXPORT, qw());
36
our %EXPORT_TAGS = qw( );
37
our $verbose = $ENV{'GBE_DBI_VERBOSE'} || 0;
38
our $errstr = "No Error";
39
my  $appname = 'ReleaseManagerSelect.jar';
40
my $full_app;
41
 
42
#-------------------------------------------------------------------------------
43
# Function        : connect
44
#
45
# Description     : Connect to the SQL server
46
#
47
# Inputs          : $db                     - Database Name
48
#                   $user                   - User Name
49
#                   $passwd                 - PassWord
50
#
51
# Returns         : New connection
52
#                   undef if the required Java utility cannot be found
53
#
54
sub connect
55
{
56
    my $obclass = shift;
57
    my $class = ref($obclass) || $obclass;
58
 
59
    bless my $self = {
60
        DB          => $_[0],
61
        USER        => $_[1],
62
        PASSWORD    => $_[2],
63
        ATTRREF     => $_[3],
64
        ERROR       => 0,
65
        ECOUNT      => 0,
66
        FH_READ     => undef,
67
        FH_WRITE    => undef,
68
        PID         => 0,
69
    } => ( $class );
70
 
71
    if ( $self->{ATTRREF}->{verbose} )
72
    {
73
        $verbose = $self->{ATTRREF}->{verbose};
74
    }
75
 
76
    #
77
    #   Need to locate the path to the Java applet
78
    #   This can be in th "CLASSPATH", but that simply forces the problem of
79
    #   locating the utility into the configuration world
80
    #
81
    #   Look in Perls @INC list, as we expect to find the program within one of
82
    #   thePerl Libraries.
83
    #
84
    unless ( $full_app )
85
    {
86
        foreach my $dir ( @INC )
87
        {
88
            my $apppath = "$dir/$appname";
89
            next unless ( -f $apppath );
90
 
91
            $full_app = $apppath;
92
            last;
93
        }
94
 
95
        if ( ! $full_app )
96
        {
97
            $errstr = "Cannot find $appname in @INC path";
98
            return;
99
        }
100
    }
101
 
102
    $errstr = "OK";
103
 
104
    #
105
    #   Initiate the external application server
106
    #   This is slow and will only done once
107
    #
108
    #   Start up the Java based Oracle interface script
109
    #   Create it with both a read and a write handle as we will be pushing
110
    #   requests at it and pulling data from it.
111
    #
112
    #   Monitor the status of the server waiting for an indication that the
113
    #   connection is open, or that the connection link has terminated.
114
    #
115
    #
116
    my @cmd;
117
    push @cmd, "java";                      # Use form that will not invoke a shell
118
    push @cmd, "-jar";
119
    push @cmd, $full_app;
120
    push @cmd, $self->{DB};
121
    push @cmd, $self->{USER};
122
    push @cmd, $self->{PASSWORD};
123
 
124
    $self->{PID} = IPC::Open2::open2($self->{FH_READ}, $self->{FH_WRITE}, @cmd );
125
 
126
    $self->{ERROR} = 1;
127
    $errstr = "Failed to start server app";
128
    if ( $self->{PID} )
129
    {
130
        #
131
        #   Extract status and any error information
132
        #
133
        my $fh = $self->{FH_READ};
134
        while ( <$fh> )
135
        {
136
            chomp;
137
            print "[DBI] Connect: $_\n" if $verbose;
138
 
139
            if ( m/^ConnectionOpened:/ )
140
            {
141
                $self->{ERROR} = 0;
142
                $errstr = "OK";
143
                last;
144
            }
145
 
146
            if ( m/^Error:(.*?)\s*$/ )
147
            {
148
                $errstr = $1;
149
            }
150
 
151
        }
152
    }
153
 
154
    #
155
    #   Return class iff the connection has been established
156
    #
157
 
158
    return $self->{ERROR} ? undef : ($self);
159
}
160
 
161
 
162
#-------------------------------------------------------------------------------
163
# Function        : errstr
164
#
165
# Description     : Return the last open error
166
#
167
# Inputs          : None
168
#
169
# Returns         : String
170
#
171
sub errstr
172
{
173
    return $errstr;
174
}
175
 
176
#-------------------------------------------------------------------------------
177
# Function        : prepare
178
#
179
# Description     : Prepare an SQL statement for processing
180
#
181
# Inputs          : $self
182
#                   $statement
183
#
184
# Returns         : Reference to a class
185
#                   undefined on error
186
#
187
sub prepare
188
{
189
    my $self = shift;
190
    my $statement = shift;
191
 
192
    #
193
    #   Remove new-lines from the statement
194
    #   Must not send new-lines to the application - they don't make it
195
    #
196
    $statement =~ s~\n~ ~g;
197
 
198
    #
199
    #   Remove leading and trailing whitespace
200
    #
201
    $statement =~ s~^\s*~~;
202
    $statement =~ s~\s*$~~;
203
 
204
    print "[DBI] Prepare: $statement\n" if $verbose;
205
 
206
    #
207
    #   Create a new object to represent the SQL statement being prepared
208
    #
209
    my $class = "DBI_Prepare";
210
    bless my $new_self = {
211
        CONNECTION => $self,
212
        STATEMENT => $statement,
213
        ROWS_READ   => 0,
214
        ROWS        => 0,
215
        FH          => undef,
216
        ERRSTR      => 'OK',
217
    } => ( $class );
218
 
219
    $self->{ECOUNT}++;
220
    return $new_self;
221
}
222
 
223
#-------------------------------------------------------------------------------
224
# Function        : disconnect
225
#
226
# Description     : Close the connection
227
#
228
# Inputs          : None
229
#
230
# Returns         : Nothing
231
#
232
sub disconnect
233
{
234
    my $self = shift;
235
    print "[DBI] Disconnect\n" if $verbose;
236
 
237
    if ( $self->{PID} )
238
    {
239
        #
240
        #   Send out a zero-length query
241
        #   This will cause the helper application to close the connection
242
        #
243
 
244
        my $fhw = $self->{FH_WRITE};
245
        print $fhw "\n\n\n";
246
 
247
        #
248
        #   Now read in data until the pipe breaks
249
        #
250
        my $fhr = $self->{FH_READ};
251
        while ( <$fhr> )
252
        {
253
            chomp;
254
            print "[DBI] Disconnect: $_\n" if $verbose;
255
        }
256
 
257
        close( $self->{FH_READ} );
258
        close( $self->{FH_WRITE} );
259
 
260
        $self->{FH_READ} = undef;
261
        $self->{FH_WRITE} = undef;
262
 
263
        #
264
        #   Kill the server task.
265
        #   It will hang around forever if we don't do this
266
        #
267
#        kill 9, $self->{PID};
268
        $self->{PID} = 0;
269
    }
270
 
271
    return 1;
272
}
273
 
274
#-------------------------------------------------------------------------------
275
# Function        : DESTROY
276
#
277
# Description     : Called when the object is destroyed
278
#
279
# Inputs          :
280
#
281
# Returns         :
282
#
283
sub DESTROY
284
{
285
    my $self = shift;
286
    $self->disconnect();
287
    $self->dumpSelf() if $verbose > 1;
288
    print "[DBI] Connection destroyed\n" if $verbose;
289
}
290
 
291
#==============================================================================
292
#   dumpSelf, debugging member to dump selfs hash
293
#==============================================================================
294
sub dumpSelf
295
{
296
    use Data::Dumper;
297
 
298
    my $self = shift;
299
 
300
    print Data::Dumper->Dump([$self], [ref($self)]);
301
}   # dumpSelf
302
 
303
 
304
 
305
#-------------------------------------------------------------------------------
306
#
307
#   A new package to encapulate the actual SQL operations
308
#
309
package DBI_Prepare;
310
 
311
#-------------------------------------------------------------------------------
312
# Function        : execute
313
#
314
# Description     : Execute the SQL statement
315
#
316
# Inputs          : A list of substitution arguments
317
#                   These will be repalced within the SELECT statement;
318
#
319
# Returns         : True: Execution was good
320
#
321
sub execute
322
{
323
    my $self = shift;
324
    my @args = @_;
325
    my @rows;
326
 
327
    my $statement = $self->{STATEMENT};
328
 
329
 
330
    #
331
    #   The users query may contain '?' characters
332
    #   These are replaced with arguments passed in to the 'execute'
333
    #
334
    if ( @args )
335
    {
336
        foreach my $arg ( @args )
337
        {
338
            $statement =~ s~\?~'$arg'~;
339
        }
340
    }
341
 
342
    #
343
    #   Write the select statement to the helper server task on the writer pipe
344
    #   The server will execute the task on our behalf and return the results
345
    #   on our reader handle
346
    #
347
    $self->{ERRSTR} = 'None';
348
    my $fhw = $self->{CONNECTION}{FH_WRITE};
349
    print $fhw "$statement\n";
350
 
351
    #
352
    #   Extract ALL the data from the link
353
    #   This will allow for nested calls
354
    #
355
    #   Assume that we have an error, until we see the start of data marker
356
    #
357
    $self->{ERROR} = 1;
358
    my $fhr = $self->{CONNECTION}{FH_READ};
359
    while ( <$fhr> )
360
    {
361
        chomp;
362
 
363
        if ( m/Data:(.*)/ )
364
        {
365
            push @rows, $1;
366
            print "[DBI] Execute: $_\n" if $verbose > 2;
367
        }
368
        else
369
        {
370
            print "[DBI] Execute: $_\n" if $verbose;
371
        }
372
 
373
 
374
        if ( m/^DataStart:/ )
375
        {
376
            $self->{ERROR} = 0;
377
        }
378
 
379
        if ( m/^DataEnd:/ )
380
        {
381
            last;
382
        }
383
 
384
        if ( m/^Warning:(.*?)\s*$/ )
385
        {
386
            $self->{ERROR} = 1;
387
            $self->{ERRSTR} = $1;
388
        }
389
 
390
    }
391
 
392
    $self->{ROWS} = \@rows;
393
 
394
    return ! $self->{ERROR};
395
}
396
 
397
#-------------------------------------------------------------------------------
398
# Function        : errstr
399
#
400
# Description     : Return the last execute error
401
#
402
# Inputs          : None
403
#
404
# Returns         : String
405
#
406
sub errstr
407
{
408
    my $self = shift;
409
    return $self->{ERRSTR};
410
}
411
 
412
#-------------------------------------------------------------------------------
413
# Function        : rows
414
#
415
# Description     : Return the number of rows extracted in the query
416
#
417
# Inputs          : None
418
#
419
# Returns         : -1, because we don't know
420
#
421
sub rows
422
{
423
    my $self = shift;
424
    my $row_count = 1 + $#{$self->{ROWS}};
425
    print "[DBI] Rows: $row_count\n" if $verbose > 1;
426
    return $row_count;
427
}
428
 
429
#-------------------------------------------------------------------------------
430
# Function        : fetchrow_array
431
#
432
# Description     : Return the next row of data
433
#
434
# Inputs          : None
435
#
436
# Returns         : The next row of data
437
#                   undef on end of data
438
#
439
sub fetchrow_array
440
{
441
    my $self = shift;
442
    my $rowref = $self->{ROWS};
443
    my $data = pop @$rowref;
444
 
445
    return () unless ( $data );
446
    $data =~ s~\s+$~~;
447
 
448
    my @row;
449
    foreach my $item ( split (',', $data ) )
450
    {
451
        push @row, pack( 'H*', $item);
452
    }
453
 
454
    print "[DBI] RawData: ". join(',', @row)."\n" if $verbose > 1;
455
#   print "[DBI] RawData: ". join(',', @row)."\n";
456
    $self->{ROWS_READ}++;
457
    return @row;
458
}
459
 
460
#-------------------------------------------------------------------------------
461
# Function        : finish
462
#
463
# Description     : Finish the 'execute'
464
#
465
# Inputs          : None
466
#
467
# Returns         : Nothing
468
#
469
sub finish
470
{
471
    my $self = shift;
472
}
473
 
474
#-------------------------------------------------------------------------------
475
# Function        : DESTROY
476
#
477
# Description     : Called when the object is destroyed
478
#
479
# Inputs          :
480
#
481
# Returns         :
482
#
483
sub DESTROY
484
{
485
    my $self = shift;
486
    $self->dumpSelf() if $verbose > 1;
487
    print "[DBI] Query destroyed\n" if $verbose;
488
}
489
 
490
#==============================================================================
491
#   dumpSelf, debugging member to dump selfs hash
492
#==============================================================================
493
sub dumpSelf
494
{
495
    use Data::Dumper;
496
 
497
    my $self = shift;
498
 
499
    print Data::Dumper->Dump([$self], [ref($self)]);
500
}   # dumpSelf
501
 
502
 
503
1;
504