Subversion Repositories DevTools

Rev

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

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