Subversion Repositories DevTools

Rev

Rev 6912 | Go to most recent revision | 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};
6910 dpurdie 91
        Error ("Cannot convert old DB value to new form",
92
               "User requested: " . $self->{DB},
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;
6912 dpurdie 354
    my @colData;
227 dpurdie 355
 
356
    my $statement = $self->{STATEMENT};
357
 
358
 
359
    #
360
    #   The users query may contain '?' characters
361
    #   These are replaced with arguments passed in to the 'execute'
362
    #
363
    if ( @args )
364
    {
365
        foreach my $arg ( @args )
366
        {
367
            $statement =~ s~\?~'$arg'~;
368
        }
369
    }
370
 
371
    #
372
    #   Write the select statement to the helper server task on the writer pipe
373
    #   The server will execute the task on our behalf and return the results
374
    #   on our reader handle
375
    #
376
    $self->{ERRSTR} = 'None';
377
    my $fhw = $self->{CONNECTION}{FH_WRITE};
378
    print $fhw "$statement\n";
379
 
380
    #
381
    #   Extract ALL the data from the link
382
    #   This will allow for nested calls
383
    #
384
    #   Assume that we have an error, until we see the start of data marker
385
    #
386
    $self->{ERROR} = 1;
387
    my $fhr = $self->{CONNECTION}{FH_READ};
388
    while ( <$fhr> )
389
    {
390
        chomp;
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
 
6912 dpurdie 401
        if (m~^Info:ColumnInfo:(\d+):(.*)~) {
6911 dpurdie 402
            my $data = $2;
403
            $data =~ s~\s+$~~;
6912 dpurdie 404
            push @colData, $data;
6910 dpurdie 405
        }
227 dpurdie 406
 
407
        if ( m/^DataStart:/ )
408
        {
409
            $self->{ERROR} = 0;
410
        }
411
 
412
        if ( m/^DataEnd:/ )
413
        {
414
            last;
415
        }
416
 
417
        if ( m/^Warning:(.*?)\s*$/ )
418
        {
419
            $self->{ERROR} = 1;
420
            $self->{ERRSTR} = $1;
421
        }
422
 
423
    }
424
 
425
    $self->{ROWS} = \@rows;
6912 dpurdie 426
    $self->{COLDATA} = \@colData;
227 dpurdie 427
 
428
    return ! $self->{ERROR};
429
}
430
 
431
#-------------------------------------------------------------------------------
432
# Function        : errstr
433
#
434
# Description     : Return the last execute error
435
#
436
# Inputs          : None
437
#
438
# Returns         : String
439
#
440
sub errstr
441
{
442
    my $self = shift;
443
    return $self->{ERRSTR};
444
}
445
 
446
#-------------------------------------------------------------------------------
447
# Function        : rows
448
#
449
# Description     : Return the number of rows extracted in the query
450
#
451
# Inputs          : None
452
#
453
# Returns         : -1, because we don't know
454
#
455
sub rows
456
{
457
    my $self = shift;
458
    my $row_count = 1 + $#{$self->{ROWS}};
459
    print "[DBI] Rows: $row_count\n" if $verbose > 1;
460
    return $row_count;
461
}
462
 
463
#-------------------------------------------------------------------------------
464
# Function        : fetchrow_array
465
#
466
# Description     : Return the next row of data
467
#
468
# Inputs          : None
469
#
470
# Returns         : The next row of data
471
#                   undef on end of data
472
#
473
sub fetchrow_array
474
{
475
    my $self = shift;
476
    my $rowref = $self->{ROWS};
6887 dpurdie 477
    my $data = shift @$rowref;
227 dpurdie 478
 
479
    return () unless ( $data );
480
    $data =~ s~\s+$~~;
481
 
482
    my @row;
483
    foreach my $item ( split (',', $data ) )
484
    {
485
        push @row, pack( 'H*', $item);
486
    }
487
 
488
    print "[DBI] RawData: ". join(',', @row)."\n" if $verbose > 1;
489
#   print "[DBI] RawData: ". join(',', @row)."\n";
490
    $self->{ROWS_READ}++;
491
    return @row;
492
}
493
 
494
#-------------------------------------------------------------------------------
6912 dpurdie 495
# Function        : fetch_columndata
6910 dpurdie 496
#
497
# Description     : NonStandard function
498
#                   Fetch array of colum names
499
#
500
# Inputs          : None 
501
#
6912 dpurdie 502
# Returns         : An array of column data
503
#                   :Sep data of Name:Size:Type
6910 dpurdie 504
#
6912 dpurdie 505
sub fetch_columndata
6910 dpurdie 506
{
507
    my $self = shift;
6912 dpurdie 508
    return $self->{COLDATA};
6910 dpurdie 509
}
510
 
511
#-------------------------------------------------------------------------------
227 dpurdie 512
# Function        : finish
513
#
514
# Description     : Finish the 'execute'
515
#
516
# Inputs          : None
517
#
518
# Returns         : Nothing
519
#
520
sub finish
521
{
522
    my $self = shift;
523
}
524
 
525
#-------------------------------------------------------------------------------
526
# Function        : DESTROY
527
#
528
# Description     : Called when the object is destroyed
529
#
530
# Inputs          :
531
#
532
# Returns         :
533
#
534
sub DESTROY
535
{
536
    my $self = shift;
537
    $self->dumpSelf() if $verbose > 1;
538
    print "[DBI] Query destroyed\n" if $verbose;
539
}
540
 
541
#==============================================================================
542
#   dumpSelf, debugging member to dump selfs hash
543
#==============================================================================
544
sub dumpSelf
545
{
546
    use Data::Dumper;
547
 
548
    my $self = shift;
549
 
550
    print Data::Dumper->Dump([$self], [ref($self)]);
551
}   # dumpSelf
552
 
553
 
554
1;
555