Subversion Repositories DevTools

Rev

Rev 5919 | Rev 6776 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1038 dpurdie 1
########################################################################
5919 dpurdie 2
# Copyright (c) VIX TECHNOLOGY (AUST) LTD
1038 dpurdie 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
        {
5923 dpurdie 136
            chomp;
1038 dpurdie 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
 
5919 dpurdie 151
            if ( m/^Status:ConnectionClosed$/ )
152
            {
153
                $self->{PID} = 0;
154
            }
1038 dpurdie 155
        }
156
    }
157
 
158
    #
159
    #   Return class iff the connection has been established
160
    #
161
 
162
    return $self->{ERROR} ? undef : ($self);
163
}
164
 
165
 
166
#-------------------------------------------------------------------------------
167
# Function        : errstr
168
#
169
# Description     : Return the last open error
170
#
171
# Inputs          : None
172
#
173
# Returns         : String
174
#
175
sub errstr
176
{
177
    return $errstr;
178
}
179
 
180
#-------------------------------------------------------------------------------
181
# Function        : prepare
182
#
183
# Description     : Prepare an SQL statement for processing
184
#
185
# Inputs          : $self
186
#                   $statement
187
#
188
# Returns         : Reference to a class
189
#                   undefined on error
190
#
191
sub prepare
192
{
193
    my $self = shift;
194
    my $statement = shift;
195
 
196
    #
197
    #   Remove new-lines from the statement
198
    #   Must not send new-lines to the application - they don't make it
199
    #
200
    $statement =~ s~\n~ ~g;
201
 
202
    #
203
    #   Remove leading and trailing whitespace
204
    #
205
    $statement =~ s~^\s*~~;
206
    $statement =~ s~\s*$~~;
207
 
208
    print "[DBI] Prepare: $statement\n" if $verbose;
209
 
210
    #
211
    #   Create a new object to represent the SQL statement being prepared
212
    #
213
    my $class = "DBI_Prepare";
214
    bless my $new_self = {
215
        CONNECTION => $self,
216
        STATEMENT => $statement,
217
        ROWS_READ   => 0,
218
        ROWS        => 0,
219
        FH          => undef,
220
        ERRSTR      => 'OK',
221
    } => ( $class );
222
 
223
    $self->{ECOUNT}++;
224
    return $new_self;
225
}
226
 
227
#-------------------------------------------------------------------------------
228
# Function        : disconnect
229
#
230
# Description     : Close the connection
231
#
232
# Inputs          : None
233
#
234
# Returns         : Nothing
235
#
236
sub disconnect
237
{
238
    my $self = shift;
239
    print "[DBI] Disconnect\n" if $verbose;
240
 
241
    if ( $self->{PID} )
242
    {
243
        #
244
        #   Send out a zero-length query
245
        #   This will cause the helper application to close the connection
246
        #
247
 
248
        my $fhw = $self->{FH_WRITE};
249
        print $fhw "\n\n\n";
250
 
251
        #
252
        #   Now read in data until the pipe breaks
253
        #
254
        my $fhr = $self->{FH_READ};
255
        while ( <$fhr> )
256
        {
257
            chomp;
258
            print "[DBI] Disconnect: $_\n" if $verbose;
259
        }
260
 
261
        close( $self->{FH_READ} );
262
        close( $self->{FH_WRITE} );
263
 
264
        $self->{FH_READ} = undef;
265
        $self->{FH_WRITE} = undef;
266
 
267
        #
268
        #   Kill the server task.
269
        #   It will hang around forever if we don't do this
270
        #
271
#        kill 9, $self->{PID};
272
        $self->{PID} = 0;
273
    }
274
 
275
    return 1;
276
}
277
 
278
#-------------------------------------------------------------------------------
279
# Function        : DESTROY
280
#
281
# Description     : Called when the object is destroyed
282
#
283
# Inputs          :
284
#
285
# Returns         :
286
#
287
sub DESTROY
288
{
289
    my $self = shift;
290
    $self->disconnect();
291
    $self->dumpSelf() if $verbose > 1;
292
    print "[DBI] Connection destroyed\n" if $verbose;
293
}
294
 
295
#==============================================================================
296
#   dumpSelf, debugging member to dump selfs hash
297
#==============================================================================
298
sub dumpSelf
299
{
300
    use Data::Dumper;
301
 
302
    my $self = shift;
303
 
304
    print Data::Dumper->Dump([$self], [ref($self)]);
305
}   # dumpSelf
306
 
307
 
308
 
309
#-------------------------------------------------------------------------------
310
#
311
#   A new package to encapulate the actual SQL operations
312
#
313
package DBI_Prepare;
314
 
315
#-------------------------------------------------------------------------------
316
# Function        : execute
317
#
318
# Description     : Execute the SQL statement
319
#
320
# Inputs          : A list of substitution arguments
321
#                   These will be repalced within the SELECT statement;
322
#
323
# Returns         : True: Execution was good
324
#
325
sub execute
326
{
327
    my $self = shift;
328
    my @args = @_;
329
    my @rows;
330
 
331
    my $statement = $self->{STATEMENT};
332
 
333
 
334
    #
335
    #   The users query may contain '?' characters
336
    #   These are replaced with arguments passed in to the 'execute'
337
    #
338
    if ( @args )
339
    {
340
        foreach my $arg ( @args )
341
        {
342
            $statement =~ s~\?~'$arg'~;
343
        }
344
    }
345
 
346
    #
347
    #   Write the select statement to the helper server task on the writer pipe
348
    #   The server will execute the task on our behalf and return the results
349
    #   on our reader handle
350
    #
351
    $self->{ERRSTR} = 'None';
352
    my $fhw = $self->{CONNECTION}{FH_WRITE};
353
    print $fhw "$statement\n";
354
 
355
    #
356
    #   Extract ALL the data from the link
357
    #   This will allow for nested calls
358
    #
359
    #   Assume that we have an error, until we see the start of data marker
360
    #
361
    $self->{ERROR} = 1;
362
    my $fhr = $self->{CONNECTION}{FH_READ};
363
    while ( <$fhr> )
364
    {
365
        chomp;
366
 
367
        if ( m/Data:(.*)/ )
368
        {
369
            push @rows, $1;
370
            print "[DBI] Execute: $_\n" if $verbose > 2;
371
        }
372
        else
373
        {
374
            print "[DBI] Execute: $_\n" if $verbose;
375
        }
376
 
377
 
378
        if ( m/^DataStart:/ )
379
        {
380
            $self->{ERROR} = 0;
381
        }
382
 
383
        if ( m/^DataEnd:/ )
384
        {
385
            last;
386
        }
387
 
388
        if ( m/^Warning:(.*?)\s*$/ )
389
        {
390
            $self->{ERROR} = 1;
391
            $self->{ERRSTR} = $1;
392
        }
393
 
394
    }
395
 
396
    $self->{ROWS} = \@rows;
397
 
398
    return ! $self->{ERROR};
399
}
400
 
401
#-------------------------------------------------------------------------------
402
# Function        : errstr
403
#
404
# Description     : Return the last execute error
405
#
406
# Inputs          : None
407
#
408
# Returns         : String
409
#
410
sub errstr
411
{
412
    my $self = shift;
413
    return $self->{ERRSTR};
414
}
415
 
416
#-------------------------------------------------------------------------------
417
# Function        : rows
418
#
419
# Description     : Return the number of rows extracted in the query
420
#
421
# Inputs          : None
422
#
423
# Returns         : -1, because we don't know
424
#
425
sub rows
426
{
427
    my $self = shift;
428
    my $row_count = 1 + $#{$self->{ROWS}};
429
    print "[DBI] Rows: $row_count\n" if $verbose > 1;
430
    return $row_count;
431
}
432
 
433
#-------------------------------------------------------------------------------
434
# Function        : fetchrow_array
435
#
436
# Description     : Return the next row of data
437
#
438
# Inputs          : None
439
#
440
# Returns         : The next row of data
441
#                   undef on end of data
442
#
443
sub fetchrow_array
444
{
445
    my $self = shift;
446
    my $rowref = $self->{ROWS};
447
    my $data = pop @$rowref;
448
 
449
    return () unless ( $data );
450
    $data =~ s~\s+$~~;
451
 
452
    my @row;
453
    foreach my $item ( split (',', $data ) )
454
    {
455
        push @row, pack( 'H*', $item);
456
    }
457
 
458
    print "[DBI] RawData: ". join(',', @row)."\n" if $verbose > 1;
459
#   print "[DBI] RawData: ". join(',', @row)."\n";
460
    $self->{ROWS_READ}++;
461
    return @row;
462
}
463
 
464
#-------------------------------------------------------------------------------
465
# Function        : finish
466
#
467
# Description     : Finish the 'execute'
468
#
469
# Inputs          : None
470
#
471
# Returns         : Nothing
472
#
473
sub finish
474
{
475
    my $self = shift;
476
}
477
 
478
#-------------------------------------------------------------------------------
479
# Function        : DESTROY
480
#
481
# Description     : Called when the object is destroyed
482
#
483
# Inputs          :
484
#
485
# Returns         :
486
#
487
sub DESTROY
488
{
489
    my $self = shift;
490
    $self->dumpSelf() if $verbose > 1;
491
    print "[DBI] Query destroyed\n" if $verbose;
492
}
493
 
494
#==============================================================================
495
#   dumpSelf, debugging member to dump selfs hash
496
#==============================================================================
497
sub dumpSelf
498
{
499
    use Data::Dumper;
500
 
501
    my $self = shift;
502
 
503
    print Data::Dumper->Dump([$self], [ref($self)]);
504
}   # dumpSelf
505
 
506
 
507
1;
508