Subversion Repositories DevTools

Rev

Rev 7326 | Details | Compare with Previous | Last modification | View Log | RSS feed

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