Subversion Repositories DevTools

Rev

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

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