File Coverage

lib/DBIx/JCL.pm
Criterion Covered Total %
statement 67 1999 3.3
branch 4 828 0.4
condition 0 123 0.0
subroutine 21 230 9.1
pod 0 155 0.0
total 92 3335 2.7


line stmt bran cond sub pod time code
1             ##@@JCL.pm,dbixlib
2             ##$$Job Control Library for Data Management Tasks
3             ##author:Brad Adkins
4             ##format:codehtml
5             ##outfile:JCL.html
6             ##title:Job Control Library
7             ##toc:yes
8             ##header:

DBIx-JCL

9              
10             =head1 NAME
11              
12             DBIx::JCL - Job Control Library for database load tasks.
13              
14             =head1 SYNOPSIS
15              
16             # file: test_job.pl
17             use strict;
18             use warnings;
19             use DBIx::JCL qw( :all );
20              
21             my $jobname = 'name_of_job';
22             sys_init( $jobname );
23              
24             # perform database tasks calling DBIx-JCL functions
25             # ...
26              
27             sys_end();
28             exit sys_get_errorlevel();
29              
30             =head1 DESCRIPTION
31              
32             This documentation describes the perl module DBIx-JCL.pm and the use of
33             standardized perl scripts which together provide a common job execution
34             environment to support database backend load and maintenance tasks.
35              
36             =head1 RATIONALE
37              
38             Provide a suite of standard functions that can be shared across all batch
39             job scripts used to support database back end tasks. Provide a standardized
40             approach for the development of all back end database job scripts.
41             Centralize the administration and access to configuration data. Enforce
42             coding standards and documentation. Abstract the sql used to support back
43             end processes from the task processing logic, by placing all sqlinto an sql
44             library. This will make maintenance of back end sql a trivial task. Provide
45             generalized logging, notification, and system information functions.
46              
47             If you want to write a robust database extract and load job with complete
48             support for logging and error notification, and do it in 25 lines of code,
49             read on.
50              
51             =head1 OPTIONS
52              
53             Database maintenance and load jobs written using DBIx-JCL support the following
54             options out-of-the-box, with no additional work required on your part.
55              
56             Job Options:
57              
58             | -r | Run job
59             | -rb | Run job in the background
60             | -rs | Run job at requested start time
61             | -rr | Restart job after failure
62             | -rde | Run using specified DE number
63             | -x | Pass extra parameters to job script
64             | -c | Specify database connections
65             | -v | Verbose
66             | -vv | Very Verbose
67             | -ng | No greeting
68             | -tc | Test database connections
69              
70             Logging Options:
71              
72             | -lf | Log filename
73             | -lg | Log generations
74             | -ll | Log log levels
75             | -lp | Log file prefix
76             | -lr | Log archive file radix
77             | -cl | Log console levels
78              
79             Notificaiton Options:
80              
81             | -ne | Notify email on completion
82             | -np | Notify pager on completion
83             | -et | Email notification to list
84             | -el | Email notification levels
85             | -pt | Pager notification to list
86             | -pl | Pager notification levels
87              
88             Information Options:
89              
90             | -dp | Display job parameters
91             | -dq | Display job querys
92             | -dd | Display job documentation
93             | -dl | Display last log file
94             | -da | Display archived log files
95             | -dj | Display a list of job scripts
96             | -dja | Diaplay jobs active in the system
97              
98             Utility Options:
99              
100             | -se | Send email message
101             | -sp | Send pager message
102             | -um | Util no move files
103             | -h | Help
104             | -ha | Help on option arguments
105              
106             Please see L below.
107              
108             =head1 CAPABILITIES
109              
110             The DBIx-JCL modules provides many capabilities commonly needed in support of
111             database maintenance jobs designed to run in a production environment. Below
112             is a summary list of features and the types of functions provided to support
113             those features.
114              
115             =head2 Features
116              
117             The following features have been designed in to the DBIx-JCL module:
118              
119             =over 4
120              
121             =item * Logging support with log file rotation
122              
123             =item * Notification support
124              
125             =item * Simplified DBI interface
126              
127             =item * Configuration data stored externally
128              
129             =item * High level functions not available in the DBI
130              
131             =item * SQL stored in "SQL books"
132              
133             =item * Job documentation enforced
134              
135             =item * Job control functions
136              
137             =item * Plugin support
138              
139             =back
140              
141             =head2 Implementation
142              
143             The features listed above have been implemented by providing [many] functions
144             for use by your database mantenance jobs:
145              
146             =over 4
147              
148             =item * Functions for command line interaction
149              
150             =item * Functions for initialization, monitoring, and control
151              
152             =item * Functions for database interaction
153              
154             =item * Functions for log file access and maintenance
155              
156             =item * Functions for file manipulation
157              
158             =back
159              
160             Please see L below.
161              
162             =head1 EXAMPLE JOB
163              
164             Shown below is the standard approach to writing job scripts.
165              
166             ##@@name_of_script.pl,bin
167             ##$$Description of this job
168              
169             use strict;
170             use warnings;
171             use DBIx::JCL qw( :all );
172              
173             # initialize
174             # -------------------------------------------------------------------------
175              
176             my $jobname = 'name_of_script';
177             sys_init( $jobname );
178              
179             my $dbenv1 = 'mydb1';
180             my $mysql1 = sys_get_sql( 'query_number_1' );
181              
182             # main
183             # -------------------------------------------------------------------------
184              
185             log_info( sys_get_dbdescr( $dbenv1 ) );
186             db_connect( $dbenv1 );
187              
188             # do more db stuff here
189              
190             # end
191             # -------------------------------------------------------------------------
192              
193             =begin wiki
194              
195             !1 NAME
196              
197             Name of script
198              
199             ----
200              
201             !1 DESCRIPTION
202              
203             Describe the job script here.
204              
205             ----
206              
207             !1 RECOVERY NOTES
208              
209             Document recovery notes here.
210              
211             ----
212              
213             !1 DEPENDENCIES
214              
215             Document dependencies here.
216              
217             =cut
218              
219             __END__
220              
221             Please see L below.
222              
223             =head1 ADDITIONAL INFORMATION
224              
225             Please see the documentation embedded in this source file for [LOTS!] of
226             additional details on how to use JCL.pm. You can view this documentation using
227             WikiText.pm module to format the WikiText content in this file. Hint: download
228             and install WikiText.pm.
229              
230             Thank you!
231              
232             =head1 COPYRIGHT
233              
234             Copyright 2008 Brad Adkins .
235              
236             Permission is granted to copy, distribute and/or modify this document under the
237             terms of the GNU Free Documentation License, published by the Free Software
238             Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no
239             Back-Cover Texts.
240              
241             =head1 AUTHOR
242              
243             Brad Adkins, dbijcl@gmail.com
244              
245             =cut
246              
247             =begin wiki
248              
249             !1 Name
250              
251             DBIx-JCL - Job Control Library for database load tasks.
252              
253             ----
254              
255             !1 Description
256              
257             This documentation describes the perl module DBIx::JCL.pm and the use of \
258             standardized perl scripts which together provide a common job execution \
259             environment to support database backend maintenance.
260              
261             ----
262              
263             !1 Synopsis
264              
265             % language=Perl
266             % # file: test_job.pl
267             % use strict;
268             % use warnings;
269             % use DBIx::JCL qw( :all );
270             %
271             % my $jobname = 'name_of_job';
272             % sys_init( $jobname );
273             %
274             % # perform database tasks
275             %
276             % sys_end();
277             % exit sys_get_errorlevel();
278             %%
279              
280             For a file named %test_job.pl% the %$jobname% would normally be simply \
281             %test_job%.
282              
283             ----
284              
285             !1 Options
286              
287             Job Options:
288              
289             | -r | Run job|
290             | -rb | Run job in the background|
291             | -rs | Run job at requested start time|
292             | -rr | Restart job after failure|
293             | -rde | Run using specified DE number|
294             | -x | Pass extra parameters to job script|
295             | -c | Specify database connections|
296             | -v | Verbose|
297             | -vv | Very Verbose|
298             | -ng | No greeting|
299             | -tc | Test database connections|
300              
301             Logging Options:
302              
303             | -lf | Log filename|
304             | -lg | Log generations|
305             | -ll | Log log levels|
306             | -lp | Log file prefix|
307             | -lr | Log archive file radix|
308             | -cl | Log console levels|
309              
310             Notificaiton Options:
311              
312             | -ne | Notify email on completion|
313             | -np | Notify pager on completion|
314             | -et | Email notification to list|
315             | -el | Email notification levels|
316             | -pt | Pager notification to list|
317             | -pl | Pager notification levels|
318              
319             Information Options:
320              
321             | -dp | Display job parameters|
322             | -dq | Display job querys|
323             | -dd | Display job documentation|
324             | -dl | Display last log file|
325             | -da | Display archived log files|
326             | -dj | Display a list of job scripts|
327             | -dja | Diaplay jobs active in the system|
328              
329             Utility Options:
330              
331             | -se | Send email message|
332             | -sp | Send pager message|
333             | -um | Util no move files|
334             | -h | Help|
335             | -ha | Help on option arguments|
336              
337             ----
338              
339             !1 Arguments
340              
341             Job Params:
342              
343             | -r | (on/off)|
344             | -rb | (on/off)|
345             | -rs | starttime Example: 17:30|
346             | -rr | jobstep Example: 3|
347             | -rde | denumber Example: 64753|
348             | -x | extra params Example: -x="a=1 b=2 c=3"|
349             | -c | connectdef Example: mydb:myinst|
350             | -v | (on/off)|
351             | -vv | (on/off)|
352             | -ng | (on/off)|
353             | -tc | connectdef Example: mydb:myinst|
354              
355             Logging Params:
356              
357             | -lf | filename Example: mylog.log|
358             | -lg | numgdg Example: 10|
359             | -ll | loglevels Example: FATAL,ERROR,WARN or WARN|
360             | -lp | logprefix Example: pre_|
361             | -lr | logradix Example: 3|
362             | -cl | loglevels Example: FATAL,ERROR,WARN,INFO,DEBUG or DEBUG|
363              
364             Notificaiton Params:
365              
366             | -ne | (on/off)|
367             | -np | (on/off)|
368             | -et | addrlist Example: me@myhost.com,you@myhost.com|
369             | -el | levels Example: FATAL,ERROR,WARN|
370             | -pt | addrlist Example: me@myhost.com,you@myhost.com|
371             | -pl | levels Example: FATAL,ERROR,WARN|
372              
373             Information Params:
374              
375             | -dp | (on/off)|
376             | -dq | (on/off)|
377             | -dd | (on/off)|
378             | -dl | (on/off)|
379             | -da | (on/off)|
380             | -dj | (on/off)|
381             | -dja | (on/off)|
382              
383             Utility Params:
384              
385             | -se | addrlist:msg Example: "me@myhost.com~Message text"|
386             | -sp | addrlist:msg Example: "me@myhost.com~Message text"|
387             | -um | (on/off)|
388             | -h | (on/off)|
389             | -ha | (on/off)|
390              
391             ----
392              
393             !1 Rationale
394              
395             Provide a suite of standard functions that can be shared across all batch \
396             job scripts used to support database back end tasks. Provide a standardized \
397             approach for the development of all back end database job scripts. \
398             Centralize the administration and access to configuration data. Enforce \
399             coding standards and documentation. Abstract the sql used to support back \
400             end processes from the task processing logic, by placing all sqlinto an sql \
401             library. This will make maintenance of back end sql a trivial task. Provide \
402             generalized logging, notification, and system information functions.
403              
404             If you want to write a robust database extract and load job with complete \
405             support for logging and error notification, and do it in 25 lines of code, \
406             read on.
407              
408             ----
409              
410             !1 Capabilities
411              
412             Some of the capabilities provided by DBIx-JCL are: System initialization, \
413             variables for system-wide use, configuration file interface support, \
414             command line processing support, command line help interface, sql library \
415             interface, system documentation in pod form, handy information display \
416             routines, source filtering for quality control, database connection and \
417             sql processing, log file access and managment, email and pager notification, \
418             general file access routines, and a generic plugin interface.
419              
420             ----
421              
422             !1 Configuration And Environment
423              
424             Configuration is provided using an enhanced version of ini style \
425             configuration files. The big difference between the conf files used and \
426             ini files is that the conf files support here document syntax. This makes \
427             storing sql querys a trivial task. Several configuration files are used, \
428             these are described individually below.
429              
430             !2 Environments
431              
432             DBIx-JCL can support multiple database environments over multiple file \
433             systems, with attachments to any number of remote databases. An environment \
434             is actually a combination of file system and database instance. Remote \
435             databases and local databases can also be specified on the command line. \
436             The example conf files define the database environments shown in the \
437             diagram below.
438              
439             On each local server, the default combination of database/instance is \
440             identified by an environment variable (shown in square brackets). The name \
441             of the environment variable is stored in the C file.
442              
443             % language=Ini_Files
444             % (-------------------------------------+------------------------------------)
445             % LOCAL | REMOTE
446             % (-------------------------------------+------------------------------------)
447             % |
448             % .------------. .------------. | .------------.
449             % | Server 1 |--.--| mydb2/dev1 |-->| .-->| mydb1/frz |
450             % '------------' | `------------' | | '------------'
451             % | [mydev1] | |
452             % | | |
453             % | .------------. | | .------------.
454             % |--| mydb2/dev2 |-->| +-->| mydb1/prd |
455             % | '------------' | | '------------'
456             % | [mydev2] | |
457             % | | |
458             % | .------------. | | .------------.
459             % +--| mydb2/int |-->| +-->| mydb3/dev |
460             % '------------' | | '------------'
461             % [myint] |---+
462             % | |
463             % .------------. .------------. | | .------------.
464             % | Server 2 |-----| mydb2/frz |-->| +-->| mydb3/int |
465             % '------------' '------------' | | '------------'
466             % [myfrz] | |
467             % | |
468             % .------------. .------------. | | .------------.
469             % | Server 3 |-----| mydb2/prd |-->| +-->| mydb3/sys |
470             % '------------' '------------' | | '------------'
471             % [myprd] | |
472             % | |
473             % | | +------------.
474             % | +-->| mydb3/prd |
475             % | '------------'
476             % Key |
477             % (-----------------------------) |
478             % dev - development region |
479             % dev1 - development region |
480             % dev2 - development region |
481             % int - integration test region |
482             % frz - system test region |
483             % sys - system test region |
484             % prd - production region |
485             % (-----------------------------) |
486             % |
487             % (-------------------------------------+------------------------------------)
488             %%
489              
490             !2 System Configuration
491              
492             The /system.conf/ stores information about your installation environment. \
493             The default database environment related to this file system, a list of \
494             database environments, and a list of valid job acronyms:
495              
496             % language=Ini_Files
497             % [system]
498             %
499             % envvar = mydbenv1
500             % dat_envrs = mydbenv1,mydbenv2,mydbenv3,mydbenv4
501             % job_acros = load_,extr_,merg_,vend_,job_,util_,test_,temp_
502             %%
503              
504             Following this section are the directory sections, There is one directory \
505             section for each type of directory used: bin, lib, log, load, extr, and \
506             plugin. Each directory section is named as using the form \
507             %[directory ]%. Directory specifications for the the bin \
508             directory are shown below. For each database environment, you would have \
509             a directory entry for that particular environment. So for the bin directory, \
510             the entry would be something like the following:
511              
512             % language=Ini_Files
513             % [directory bin]
514             %
515             % mydbenv1 = /home/account/bin/
516             % mydbenv2 = /home/account/bin/
517             % mydbenv3 = /home/account/bin/
518             % mydbenv4 = /home/account/bin/
519             %%
520              
521             The trailing slashes on the directory entries are required.
522              
523             The last section in the C file is the restart section. This \
524             stores the last job step attempted. This is set immediately before a job \
525             is restarted. The example below shows a job restart step of 3.
526              
527             % language=Ini_Files
528             % [restart]
529             %
530             % restart=3
531             %%
532              
533             !2 Job Configuration
534              
535             The /job.conf/ file stores information about specific jobs. The key entry \
536             is the logfile entry. This entry provides a name to use for this job's log \
537             file. The entry is placed in a section named after the jobname used in the \
538             script. If your script uses:
539              
540             % language=Perl
541             % my $jobname = 'job_number_1';
542             % sys_init( $jobname );
543             %%
544              
545             Then the job section for that script would be:
546              
547             % language=Ini_Files
548             %
549             % [job_number_1]
550             % logfile=epdw_contractor.log
551             %%
552              
553             There are also several optional entries that can be made for a given job. \
554             These will be permanent overrides for that particular job. All of these are \
555             also available as command line options.
556              
557             % language=Ini_Files
558             % logging_levels=
559             % gdg=
560             % emailto=
561             % pagerto=
562             % email_levels=
563             % pager_levels=
564             %%
565              
566             This gives you the ability to set up logging and notifications differently \
567             for every job if you want to (probably not a good idea).
568              
569             !2 Data Configuration
570              
571             The /data.conf/ file is possibly the most complex file. This file is used \
572             to map your databases and database instances, both local and remote, and \
573             provides a default instance for each database.
574              
575             Here is a sample /data.conf/ file. In the example below, the C<[instances]> \
576             section maps the available database instances for each database. The default \
577             sections %[default ]
578             instance to connect to for each supported database, based on the current \
579             database environment variable. The last set of sections provide the \
580             connection parameters for each database/instance combination. (Only one of \
581             these is shown below.)
582              
583             Keep in mind when trying to decipher the example below, that database mydb2 \
584             is in all cases the "local" database (attached to a file system where the \
585             DBIx-JCL are running. The databases mydb1 and mydb2 are remote databases.
586              
587             % language=Ini_Files
588             % [databases]
589             % databases = mydb1,mydb2,mydb3
590             %
591             % [names]
592             % mydb1 = A Long Name for mydb1
593             % mydb2 = A Long Name for mydb2
594             % mydb3 = A Long Name for mydb3
595             %
596             % [instances]
597             % mydb1 = prd,frz
598             % mydb2 = prd,frz,int,dev1,dev2
599             % mydb3 = prd,sys,int,dev
600             %
601             % [default db2dev1]
602             % mydb1 = frz
603             % mydb2 = dev1
604             % mydb3 = dev
605             %
606             % [default db2dev2]
607             % mydb1 = frz
608             % mydb2 = dev2
609             % mydb3 = dev
610             %
611             % default db2int]
612             % mydb1 = frz
613             % mydb2 = int
614             % mydb3 = int
615             %
616             % [default db2frz]
617             % mydb1 = prd
618             % mydb2 = frz
619             % mydb3 = sys
620             %
621             % [default db2prd]
622             % mydb1 = prd
623             % mydb2 = prd
624             % mydb3 = prd
625             %
626             % [mydb2 int]
627             % database=dbi:Oracle:db2int
628             % username=myaccount
629             % password=12345678
630             %%
631              
632             !2 Mail Configuration
633              
634             The /mail.conf/ file stores settings used when sending email and pager \
635             notifications. The entries are placed in a section named mail.
636              
637             % language=Ini_Files
638             % [mail]
639             % server=mail.server.com
640             % from=me@mycompany.com
641             % emailto=me@mycompany.com,you@mycompany.com
642             % pagerto=1234567890@somepager.com,0987654321@somepager.com
643             % email_levels=FATAL,ERROR,WARN
644             % pager_levels=FATAL,ERROR
645             %%
646              
647             !2 Log Configuration
648              
649             The /log.conf/ file contains settings used by the logging functions. The \
650             settings are placed in a section named log. The gdg entry specifies the \
651             default number of log archive files that will be maintained. In case you \
652             are curious, gdg stands for generation data group.
653              
654             % language=Ini_Files
655             % [log]
656             % default_logfile=job.log
657             % logging_levels=FATAL,ERROR,WARN,INFO
658             % gdg=5
659             %%
660              
661             !2 Query Configuration
662              
663             The /query.conf/ file contains all the sql used by DBIx-JCL on your \
664             installations. Each job has its own section in this file. Querys are \
665             entered using heredoc syntax, which makes it very easy to cut-and-paste \
666             sql from other sources into this file, and vice-versa. Abstracting your \
667             sql into a separate file should make your maintenance life much easier. \
668             It would be a good idea to put this file under configuration management \
669             control.
670              
671             !2 Util Configuration
672              
673             The /util.conf/ file is currently not used. It is anticipated that there \
674             will be a need for this file in the future.
675              
676             ----
677              
678             !1 Logging
679              
680             One of the real strengths of DBIx-JCL is its support for logging. The goal \
681             is to log all significant events, including DBI errors. You decide what types \
682             of events are significant by setting the logging levels prior to running your \
683             script, or on the command line when starting your script.
684              
685             !2 Writing to the log
686              
687             You use the log write functions to write data to the log. If the log \
688             statement is in the list of logging levels to be output for this script, \
689             the log statement will be written, if the log statement used is lower than \
690             any of the set logging levels, it will not be written to the log file. An \
691             example may clarify. Let's say you have set the logging levels to include \
692             FATAL,ERROR,WARNING. If your job script calls C or C \
693             functions, they would not write to the log file becuase those log levels \
694             are not in the list of logging levels to be output. If you want to see you \
695             log messages on the console while your job is running, use the Verbose \
696             command line option.
697              
698             The log write functions are:
699              
700             |%log_fatal()% |outputs FATAL level messages|
701             |%log_error()% |outputs ERROR level messages|
702             |%log_warn()% |outputs WARN level messages|
703             |%log_info()% |outputs INFO level messages|
704             |%log_debug()% |outputs DEBUG level messages|
705              
706             !2 Using Oracle's DBMS_OUTPUT Package
707              
708             The functions used here to implement stored procedure calls (DBD::Oracle only) \
709             will gather dbms output automatically. If any is found, these are sent to \
710             the current log file using an appropriate logging level. To make your log \
711             files more readable, you should consider using a a custom package for all \
712             dbms output generated from stored procedures and functions. I've also found \
713             that if you preceed your dbms output messages with some white space, they \
714             will look better when viewed in your log files.
715              
716             ----
717              
718             !1 Notifications
719              
720             Another real strength of DBIx-JCL is the built-in support for notifications. \
721             There are two types of notifications, email notifications and pager \
722             notifications. One of the nice features of email notifications is that the \
723             log file is included in the email message following the message text. Pager \
724             notifications are just short versions of email notifications, pager \
725             notifications never have the contents of the log file appended.
726              
727             The pager notifications are really just an email message. Your pager device \
728             must be able to support messaging via email interface to make use of this \
729             feature. Most cell phone devices and text pagers have this capability.
730              
731             The severity of the message is included in the message subject line so you \
732             can immediately see if you need to respond to the message or not.
733              
734             The log writing functions are hooked into the notification functions. \
735             Whenever a log write function is called it checks to see if a notification \
736             should also be sent based on the email and pager severity levels. These work
737             the same as described above for logging levels, in fact, the same levels are \
738             used. Care should be exercised when setting the notifications levels, if you \
739             set them too low you script could generate a lot of email/pager messages. \
740             Caveat emptor.
741              
742             ----
743              
744             !1 Database Interface
745              
746             This module uses the Perl DBI for all database functionality. However you do \
747             not have to deal with the raw DBI functions. All DBI access thru this module \
748             is made via a virtual name that you assign to each database connection used \
749             by your running job script. The virtual name is resolved using entries in a \
750             configuration file. Furthermore, all calls to DBI functions just require that \
751             virtual name. Underneath, the module functions handle storage of database \
752             handles and statement handles automatically for you. This has two benefits, \
753             it makes writing database job scripts for the novice much simpler, and it \
754             makes for cleaner, more readable job scripts.
755              
756             You probably can't fully appreciation the latter until you are reading a \
757             job script at 2am, trying to figure out what went wrong with a production \
758             job. Of course, one of the design goals of this module is to make it so you \
759             never have to read a script when one of your jobs fails. All the information \
760             you need to diagnose and fix the problem should be in the most recent log \
761             file, with previous log history right at your finger tips as well.
762              
763             ----
764              
765             !1 Script Naming Convention
766              
767             Scripts which use DBIx-JCL are required to use a script naming convention, \
768             however, the convention chosen is up to you. All scripts using DBIx-JCL \
769             should be prefixed with an acronym. For example, if you had a script that \
770             sent a warning message on some condition, you might name it "util_warn.pl" \
771             where "util_" is the script prefix acronym. You decide what script prefix \
772             acronyms you want to use, and configure those in the system.conf file. This \
773             module will check that all invoking scripts adhere to your naming convention. \
774             DBIx-JCL will complain at runtime if a script is inappropriately named.
775              
776             Some examples of script acronyms are:
777              
778             |Acro |Description|
779             |load_ |load data script|
780             |extr_ |extract data script|
781             |merg_ |merge/update data script|
782             |job_ |job which runs other scripts|
783             |util_ |utility script|
784             |test_ |test script|
785             |temp_ |temporary scipt|
786              
787             You should examine the sampel system configuration files that some with \
788             DBIx-JCL.
789              
790             ----
791              
792             !1 Installation
793              
794             The DBIx-JCL module can be installed into a private directory or appended to \
795             your Perl installation using the normal install process. If you intall into a \
796             private directory, you'll need to set the environment variable PERL5LIB so \
797             your scripts can find the module.
798              
799             /Environment Variables/
800              
801             The module also uses several envirnoment variables besides PERL5LIB, sample \
802             export entries are shown below. The module needs to know where your home \
803             directory is, this should normally be set for you in most installations. The \
804             module will look for a configuration file named /system.conf/ to start the \
805             boot-strap process, this location is identified by the JCLCONF environment \
806             variable. A default database environment needs to be identified. You \
807             determine what this variable will be called, in the example below the \
808             variable is named MYDBENV. The name you choose is stored in the \
809             /system.conf/ file in section %[system]%, under the key %envvar%.
810              
811             Sample export settings:
812              
813             % language=IniFiles
814             % export PERL5LIB=/home/myaccount/lib
815             % export HOME=/home/myaccount
816             % export JCLCONF=/home/myaccount/conf
817             % export MYDBENV=dbenv1
818             %%
819              
820             Under a Windows system you will want to set these in yous Control Panel \
821             under System and Advanced options.
822              
823             ----
824              
825             !1 Example Script
826              
827             Shown below is the standard approach to writing job scripts.
828              
829             % language=Perl
830             % #!perl
831             % ##@@name_of_script.pl,bin
832             % ##$$Description of the Job
833             %
834             % use strict;
835             % use warnings;
836             % use DBIx::JCL qw( :all );
837             %
838             % # initialize
839             % # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
840             %
841             % my $jobname = 'name_of_script';
842             % sys_init( $jobname );
843             %
844             % my $dbenv1 = 'mydb1';
845             % my $mysql1 = sys_get_sql( 'query_number_1' );
846             %
847             % # main
848             % # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
849             %
850             % log_info( sys_get_dbdescr( $dbenv1 ) );
851             % db_connect( $dbenv1 );
852             %
853             % # do more db stuff here
854             %
855             % # end
856             % # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
857             %
858             % =begin wiki
859             %
860             % !1 NAME
861             %
862             % Name of script
863             %
864             % ----
865             %
866             % !1 DESCRIPTION
867             %
868             % Describe the job script here.
869             %
870             % ----
871             %
872             % !1 RECOVERY NOTES
873             %
874             % Document recovery notes here.
875             %
876             % ----
877             %
878             % !1 DEPENDENCIES
879             %
880             % Document dependencies here.
881             %
882             % =cut
883             %
884             % __END__
885             %
886             %%
887              
888             The second and third lines of the example are required for every job script. \
889             The second line identifies the script and the script installation directory. \
890             The third line provides a brief description of the job and is used by the \
891             command line option that displays all installed jobs.
892              
893             ----
894              
895             !1 Functions
896              
897             The following provides an explanation of each of the functions provided by \
898             DBIx-JCL.
899              
900             =cut
901              
902              
903             # package
904             # ------------------------------------------------------------------------------
905              
906             package DBIx::JCL;
907 1     1   940 use strict;
  1         2  
  1         38  
908 1     1   6 use warnings;
  1         1  
  1         64  
909              
910             # package exports
911             # ------------------------------------------------------------------------------
912              
913             require Exporter;
914 1     1   17 use base qw( Exporter );
  1         2  
  1         491  
915             our @EXPORT_OK = qw(
916             sys_init
917             sys_init_setuser
918             sys_end
919             sys_init_plugin
920             sys_get_sql
921             sys_get_item
922             sys_get_hash
923             sys_get_array
924             sys_get_common_sql
925             sys_get_run_control
926             sys_get_dbdescr
927             sys_get_dbinst
928             sys_set_restart
929             sys_load_library
930             sys_set_verbose
931             sys_die
932             sys_warn
933             sys_info
934             sys_ctime2str
935             sys_disp_active_jobs
936             sys_run_job
937             sys_run_job_background
938             sys_run_job_wait
939             sys_run_job_maxrc
940             sys_run_job_reset
941             sys_get_path_bin_dir
942             sys_get_path_lib_dir
943             sys_get_path_log_dir
944             sys_get_path_load_dir
945             sys_get_path_extr_dir
946             sys_get_path_scripts_dir
947             sys_get_path_plugin_dir
948             sys_get_path_prev_dir
949             sys_get_mail_server
950             sys_get_mail_from
951             sys_get_mail_emailto
952             sys_get_mail_pagerto
953             sys_get_mail_email_levels
954             sys_get_mail_pager_levels
955             sys_get_log_file
956             sys_get_log_filefull
957             sys_get_log_logging_levels
958             sys_get_log_console_levels
959             sys_get_log_gdg
960             sys_get_dataenvr
961             sys_get_errorlevel
962             sys_get_conf_dir
963             sys_get_email_levels
964             sys_get_pager_levels
965             sys_get_logging_levels
966             sys_get_console_levels
967             sys_get_commandline
968             sys_get_commandline_opt
969             sys_get_commandline_val
970             sys_get_script_file
971             sys_get_user
972             sys_get_util_move
973             sys_get_maxval
974             sys_set_errorlevel
975             sys_set_die
976             sys_set_warn
977             sys_set_conf_file
978             sys_set_email_levels
979             sys_set_pager_levels
980             sys_set_mail_emailto
981             sys_set_logging_levels
982             sys_set_console_levels
983             sys_set_script_file
984             sys_set_path_log_dir
985             sys_set_path_plugin_dir
986             sys_set_maxval
987             sys_check_dataenvr
988             sys_timer
989             sys_wait
990             sys_disp_doc
991             log_fatal
992             log_error
993             log_warn
994             log_info
995             log_debug
996             log_close
997             log_write_log
998             log_write_screen
999             db_init
1000             db_connect
1001             db_nil
1002             db_finish
1003             db_disconnect
1004             db_prepare
1005             db_execute
1006             db_commit
1007             db_get_sth
1008             db_get_defenvr
1009             db_pef
1010             db_pef_list
1011             db_fetchrow
1012             db_bindcols
1013             db_rollback
1014             db_insert_from_file
1015             db_query_to_file
1016             db_dump_query
1017             db_dump_table
1018             db_grant
1019             db_func
1020             db_proc
1021             db_proc_in
1022             db_proc_out
1023             db_proc_inout
1024             db_rowcount_query
1025             db_sanity_check
1026             db_rowcount_table
1027             db_truncate
1028             db_dbms_output_enable
1029             db_dbms_output_disable
1030             db_dbms_output_get
1031             db_drop_index
1032             db_drop_table
1033             db_drop_procedure
1034             db_drop_function
1035             db_drop_package
1036             db_rename_index
1037             db_rename_table
1038             db_purge_table
1039             db_purge_index
1040             db_update_statistics
1041             db_sqlloader
1042             db_sqlloaderx
1043             db_sqlloaderx_parse_logfile
1044             db_sqlloaderx_read
1045             db_sqlloaderx_skipped
1046             db_sqlloaderx_rejected
1047             db_sqlloaderx_discarded
1048             db_sqlloaderx_elapsed_time
1049             db_sqlloaderx_cpu_time
1050             db_index_rebuild
1051             db_exchange_partition
1052             util_get_filename_load
1053             util_get_filename_extr
1054             util_get_filename_log
1055             util_read_header
1056             util_read_footer
1057             util_read_file
1058             util_write_header
1059             util_write_footer
1060             util_move
1061             util_trim
1062             util_zsdf
1063             test_init
1064             test_ok
1065             test_results
1066             test_harness_init
1067             test_harness_run
1068             test_harness_results
1069             $VERSION
1070             $SQLLDR_SUCC
1071             $SQLLDR_WARN
1072             $SQLLDR_FAIL
1073             $SQLLDR_FTL
1074             );
1075              
1076             our %EXPORT_TAGS = (
1077             all => [
1078             @EXPORT_OK
1079             ],
1080             sys => [ qw(
1081             sys_init
1082             sys_init_setuser
1083             sys_end
1084             sys_init_plugin
1085             sys_get_sql
1086             sys_get_item
1087             sys_get_hash
1088             sys_get_array
1089             sys_get_common_sql
1090             sys_get_run_control
1091             sys_get_dbdescr
1092             sys_get_dbinst
1093             sys_set_restart
1094             sys_load_library
1095             sys_set_verbose
1096             sys_die
1097             sys_warn
1098             sys_info
1099             sys_ctime2str
1100             sys_disp_active_jobs
1101             sys_run_job
1102             sys_run_job_background
1103             sys_run_job_wait
1104             sys_run_job_maxrc
1105             sys_run_job_reset
1106             sys_get_path_bin_dir
1107             sys_get_path_lib_dir
1108             sys_get_path_log_dir
1109             sys_get_path_load_dir
1110             sys_get_path_extr_dir
1111             sys_get_path_prev_dir
1112             sys_get_path_scripts_dir
1113             sys_get_mail_server
1114             sys_get_mail_from
1115             sys_get_mail_emailto
1116             sys_get_mail_pagerto
1117             sys_get_mail_email_levels
1118             sys_get_mail_pager_levels
1119             sys_get_log_file
1120             sys_get_log_filefull
1121             sys_get_log_logging_levels
1122             sys_get_log_console_levels
1123             sys_get_log_gdg
1124             sys_get_dataenvr
1125             sys_get_errorlevel
1126             sys_get_conf_dir
1127             sys_get_email_levels
1128             sys_get_pager_levels
1129             sys_get_logging_levels
1130             sys_get_console_levels
1131             sys_get_commandline
1132             sys_get_commandline_opt
1133             sys_get_commandline_val
1134             sys_get_script_file
1135             sys_get_path_plugin_dir
1136             sys_get_util_move
1137             sys_get_user
1138             sys_get_maxval
1139             sys_set_errorlevel
1140             sys_set_die
1141             sys_set_warn
1142             sys_set_email_levels
1143             sys_set_pager_levels
1144             sys_set_mail_emailto
1145             sys_set_logging_levels
1146             sys_set_console_levels
1147             sys_set_script_file
1148             sys_set_conf_file
1149             sys_set_path_log_dir
1150             sys_set_path_plugin_dir
1151             sys_set_maxval
1152             sys_check_dataenvr
1153             sys_timer
1154             sys_wait
1155             sys_disp_doc
1156             ) ],
1157             log => [ qw(
1158             log_fatal
1159             log_error
1160             log_warn
1161             log_info
1162             log_debug
1163             log_close
1164             log_write_log
1165             log_write_screen
1166             ) ],
1167             db => [ qw(
1168             db_init
1169             db_connect
1170             db_nil
1171             db_finish
1172             db_disconnect
1173             db_prepare
1174             db_execute
1175             db_commit
1176             db_get_sth
1177             db_get_defenvr
1178             db_pef
1179             db_pef_list
1180             db_fetchrow
1181             db_bindcols
1182             db_rollback
1183             db_insert_from_file
1184             db_query_to_file
1185             db_dump_query
1186             db_dump_table
1187             db_grant
1188             db_func
1189             db_proc
1190             db_proc_in
1191             db_proc_out
1192             db_proc_inout
1193             db_rowcount_query
1194             db_sanity_check
1195             db_rowcount_table
1196             db_truncate
1197             db_dbms_output_enable
1198             db_dbms_output_disable
1199             db_dbms_output_get
1200             db_drop_index
1201             db_drop_table
1202             db_drop_procedure
1203             db_drop_function
1204             db_drop_package
1205             db_rename_index
1206             db_rename_table
1207             db_purge_table
1208             db_purge_index
1209             db_update_statistics
1210             db_sqlloader
1211             db_sqlloaderx
1212             db_sqlloaderx_parse_logfile
1213             db_sqlloaderx_read
1214             db_sqlloaderx_skipped
1215             db_sqlloaderx_rejected
1216             db_sqlloaderx_discarded
1217             db_sqlloaderx_elapsed_time
1218             db_sqlloaderx_cpu_time
1219             db_index_rebuild
1220             db_exchange_partition
1221             ) ],
1222             util => [ qw(
1223             util_get_filename_load
1224             util_get_filename_extr
1225             util_get_filename_log
1226             util_read_header
1227             util_read_footer
1228             util_read_file
1229             util_write_header
1230             util_write_footer
1231             util_move
1232             util_trim
1233             util_zsdf
1234             ) ],
1235             test => [ qw(
1236             test_init
1237             test_ok
1238             test_results
1239             test_harness_init
1240             test_harness_run
1241             test_harness_results
1242             ) ],
1243             const => [ qw(
1244             $SQLLDR_SUCC
1245             $SQLLDR_WARN
1246             $SQLLDR_FAIL
1247             $SQLLDR_FTL
1248             ) ],
1249             );
1250              
1251             # package imports
1252             # ------------------------------------------------------------------------------
1253              
1254 1     1   1092 use English qw( -no_match_vars );
  1         2432  
  1         10  
1255 1     1   2568 use Getopt::Long;
  1         13778  
  1         9  
1256 1     1   1573 use Config::IniFiles;
  1         39680  
  1         40  
1257 1     1   1201 use Pod::WikiText;
  1         121193  
  1         136  
1258 1     1   1094 use IO::File;
  1         1237  
  1         226  
1259 1     1   8 use IO::Handle;
  1         3  
  1         40  
1260 1     1   1045 use IO::LockedFile;
  1         1869  
  1         7  
1261 1     1   1362 use Fcntl qw(:flock);
  1         3  
  1         98  
1262 1     1   979 use File::Copy;
  1         4173  
  1         91  
1263 1     1   1014 use File::Bidirectional;
  1         2667  
  1         37  
1264 1     1   10 use File::Basename;
  1         2  
  1         78  
1265 1     1   1505 use MIME::Lite;
  1         60977  
  1         40  
1266 1     1   716 use Date::Format;
  1         20705  
  1         94  
1267 1     1   10125 use DBI;
  1         59817  
  1         488  
1268             #|++ ## flush print buffer on write
1269              
1270             # version
1271             # ------------------------------------------------------------------------------
1272              
1273             our $VERSION = "0.12";
1274              
1275             # const exports
1276             # ------------------------------------------------------------------------------
1277              
1278             our $SQLLDR_SUCC = 0;
1279             our $SQLLDR_WARN = 2;
1280             our $SQLLDR_FAIL = 1;
1281             our $SQLLDR_FTL = 3;
1282              
1283             # state variables
1284             # ------------------------------------------------------------------------------
1285              
1286             my $path_bin_dir = '';
1287             my $path_lib_dir = '';
1288             my $path_log_dir = '';
1289             my $path_load_dir = '';
1290             my $path_extr_dir = '';
1291             my $path_prev_dir = '';
1292             my $path_scripts_dir = '';
1293             my $mail_server = '';
1294             my $mail_from = '';
1295             my $mail_emailto = '';
1296             my $mail_pagerto = '';
1297             my $mail_email_levels = '';
1298             my $mail_pager_levels = '';
1299             my $log_file = '';
1300             my $log_filefull = '';
1301             my $log_logging_levels = '';
1302             my $log_console_levels = '';
1303             my $dataenvr = '';
1304             my $log_gdg = 0;
1305             my $log_prefix = '';
1306             my $log_radix = 2;
1307             my $errorlevel = 0;
1308             my $util_move = 1;
1309              
1310             # command line variables
1311             # ------------------------------------------------------------------------------
1312              
1313             my $opt_run = 0;
1314             my $opt_run_background = 0;
1315             my $opt_run_scheduled = '';
1316             my $opt_run_restart = '';
1317             my $opt_connection = '';
1318             my $opt_run_de = '';
1319             my $opt_commandline_ext = '';
1320             my $opt_verbose = 0;
1321             my $opt_very_verbose = 0;
1322             my $opt_no_greeting = 0;
1323             my $opt_test_dbcon = '';
1324             my $opt_log_file = '';
1325             my $opt_logging_levels = '';
1326             my $opt_console_levels = '';
1327             my $opt_log_gdg = 0;
1328             my $opt_log_prefix = '';
1329             my $opt_log_radix = 0;
1330             my $opt_notify_email_oncomp = 0;
1331             my $opt_notify_pager_oncomp = 0;
1332             my $opt_notify_email_tolist = '';
1333             my $opt_notify_pager_tolist = '';
1334             my $opt_notify_email_levels = '';
1335             my $opt_notify_pager_levels = '';
1336             my $opt_disp_params = 0;
1337             my $opt_disp_sql = 0;
1338             my $opt_disp_doc = 0;
1339             my $opt_disp_sysdoc = 0;
1340             my $opt_disp_logprev = 0;
1341             my $opt_disp_logarch = 0;
1342             my $opt_disp_jobs = 0;
1343             my $opt_disp_active_jobs = 0;
1344             my $opt_disp_exec = 0;
1345             my $opt_send_email = '';
1346             my $opt_send_pager = '';
1347             my $opt_util_move = 0;
1348             my $opt_help = 0;
1349             my $opt_help_args = 0;
1350             my $opt_commandline = join ' ', @ARGV;
1351              
1352             # module variables
1353             # ------------------------------------------------------------------------------
1354              
1355 1     1   13 use constant QUOTE => q{"};
  1         2  
  1         86  
1356 1     1   7 use constant SPACE => q{ };
  1         3  
  1         54088  
1357              
1358             my $RC_FATAL = 32;
1359             my $RC_ERROR = 16;
1360             my $RC_WARN = 8;
1361              
1362             my %MONTHS = (
1363             Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5,
1364             Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec=> 11,
1365             );
1366              
1367             my $jobname = ''; # name used to identify job script
1368             my $pid = 0; # os process id number
1369             my %pidlib = (); # hash of info about background jobs
1370             my $pidcnt = 0; # count of child pids
1371             my $maxrc = 0; # max return code for foreground jobs
1372             my $osuser = ''; # os username
1373             my $commandline_ext = ''; # extended command line
1374             my @plugins = (); # loaded plugin information
1375             my %timers = (); # hash of timers
1376             my %function_params = (); # hash of stored function params
1377             my $wt_seconds = 0; # wait seconds
1378             my $wt_start = time; # init wait start time
1379             my %maxval = (); # hash of max values
1380             my $t_num = 0; # test script
1381             my $t_ok = 0; # test script
1382             my $t_notok = 0; # test script
1383             my $th_num = 0; # test harness
1384             my $th_error = 0; # test harness
1385             my $sys_dbms_output = 0; # has dbms_output been enabled
1386             my $sys_log_open = 0; # is log file open
1387             my $sys_stderr_redirected = 0; # STDERR has been redirected to /dev/null
1388             my $sys_jobconf_override = 0; # using override job conf file
1389             my $sys_jobconf_file = ''; # override jobconf filename
1390             my $path_plugin_dir = ''; # path to plugin directory
1391             my $path_conf_dir = ''; # path to conf file directory
1392             my %sqlloader_results = (); # hash of SQL*Loader results
1393             my %log_level_opts = (); # hash of logging options
1394              
1395             my (%conf_data, %conf_log, %conf_mail, %conf_query, %conf_job, %conf_util);
1396             my (%conf_system, %conf_de, %conf_rcontrols);
1397             my (@databases, @dat_envrs, @job_acros);
1398             my (%dbname, %dbdefenvr, %dbinst, %dbconn, %dbhandles);
1399              
1400             my $script_file = $PROGRAM_NAME;
1401             my $script_filefull = $script_file;
1402             my $log_ext = '.log';
1403             my $dbitrace_base = 'dbitrace';
1404             my $dbitrace_file = $dbitrace_base . $log_ext;
1405             my $dbitrace_filefull = '';
1406              
1407             $script_file =~ s{^/.*/}{};
1408              
1409             $path_conf_dir = $ENV{JCLCONF} || '';
1410             if ( ! defined $path_conf_dir ) {
1411             sys_die( 'Environment variable JCLCONF not set', 0 );
1412             }
1413              
1414             if ( $path_conf_dir =~ m/(.*)\/$/ ) { $path_conf_dir = $1; }
1415              
1416             my %db_func_params = (
1417             db_insert_from_file => {
1418             TrimLead => 'no',
1419             TrimFieldLead => 'no',
1420             TrimFieldTrail => 'no',
1421             CommentChar => '#',
1422             SkipComments => 'no',
1423             SkipLastField => 'no',
1424             UseRegex => 'no',
1425             },
1426             db_insert_from_conf => {
1427             TrimLead => 'no',
1428             TrimFieldLead => 'no',
1429             TrimFieldTrail => 'no',
1430             CommentChar => '#',
1431             SkipComments => 'no',
1432             SkipLastField => 'no',
1433             UseRegex => 'no',
1434             },
1435             db_sqlloader => {
1436             DatFilePath => '',
1437             DbEnvr => '',
1438             NetService => '',
1439             },
1440             );
1441              
1442             # public methods
1443             # ------------------------------------------------------------------------------
1444              
1445             =begin wiki
1446              
1447             !2 System Functions
1448              
1449             These functions provide general job information and job managment \
1450             capabilities.
1451              
1452             =cut
1453              
1454             sub sys_init {
1455             =begin wiki
1456              
1457             !3 sys_init
1458              
1459             ( jobname )
1460              
1461             This is the job script initialization function. All job scripts should call \
1462             this function first before any other JCL functions. This will validate a job \
1463             name and does all the other setup work necessary to run a job script. This \
1464             function also provides a standard command line interface and supporting \
1465             functions for the supplied command line options.
1466              
1467             =cut
1468 0     0 0 0 my ($jn, @cl) = @_;
1469 0         0 $jobname = $jn;
1470 0         0 foreach my $opt ( @cl ) {
1471 0         0 push @ARGV, $opt; # add additional command line option
1472             }
1473              
1474 0 0       0 unless ( $jobname ) {
1475 0         0 sys_die( 'Please specify jobname when initializing', 0 );
1476             }
1477              
1478 0         0 _sys_init_vars();
1479              
1480 0         0 $log_file = $jobname . $log_ext;
1481 0         0 $log_filefull = $path_log_dir.$log_file;
1482              
1483 0 0       0 push @ARGV, '-r' if $jobname eq "JCL"; # for convenience
1484              
1485 0         0 $sys_jobconf_file = _sys_check_de_override( $jobname );
1486              
1487 0         0 $sys_jobconf_file .= ".conf";
1488 0         0 _sys_read_conf( $sys_jobconf_file ); # tie %conf_job to job's conf file
1489 0         0 _sys_read_job(); # read job specific settings from %conf_job
1490              
1491 0 0       0 GetOptions( "r" => \$opt_run,
1492             "rb" => \$opt_run_background,
1493             "rs=s" => \$opt_run_scheduled,
1494             "rr=s" => \$opt_run_restart,
1495             "rde=s" => \$opt_run_de,
1496             "x=s" => \$opt_commandline_ext,
1497             "c=s" => \$opt_connection,
1498             "v" => \$opt_verbose,
1499             "vv" => \$opt_very_verbose,
1500             "ng" => \$opt_no_greeting,
1501             "tc=s" => \$opt_test_dbcon,
1502             "lf=s" => \$opt_log_file,
1503             "lg=i" => \$opt_log_gdg,
1504             "lp=s" => \$opt_log_prefix,
1505             "lr=i" => \$opt_log_radix,
1506             "ll=s" => \$opt_logging_levels,
1507             "cl=s" => \$opt_console_levels,
1508             "ne" => \$opt_notify_email_oncomp,
1509             "np" => \$opt_notify_pager_oncomp,
1510             "et=s" => \$opt_notify_email_tolist,
1511             "el=s" => \$opt_notify_email_levels,
1512             "pt=s" => \$opt_notify_pager_tolist,
1513             "pl=s" => \$opt_notify_pager_levels,
1514             "dp" => \$opt_disp_params,
1515             "dq" => \$opt_disp_sql,
1516             "dd" => \$opt_disp_doc,
1517             "dl" => \$opt_disp_logprev,
1518             "da" => \$opt_disp_logarch,
1519             "dj" => \$opt_disp_jobs,
1520             "dja" => \$opt_disp_active_jobs,
1521             "se=s" => \$opt_send_email,
1522             "sp=s" => \$opt_send_pager,
1523             "um" => \$opt_util_move,
1524             "h" => \$opt_help,
1525             "ha" => \$opt_help_args,
1526             ) || _sys_help(0);
1527              
1528 0 0       0 if ( $opt_connection ) {
1529 0         0 foreach my $connectdef ( split m/,/, $opt_connection ) {
1530 0         0 my ($db, $inst) = split m/:/, $connectdef;
1531 0 0       0 _check_array_val( $db, \@databases )
1532             || sys_die( "Invalid database: [$db]", 0 );
1533 0 0       0 _check_array_val( $inst, [split m/,/, $dbinst{$db}] )
1534             || sys_die( "Invalid database instance: [$db.$inst]", 0 );
1535             ## update default connection data
1536 0         0 $dbdefenvr{$db} = $inst;
1537             }
1538             }
1539              
1540             # create dbitrace file if not found
1541 0 0       0 if ( ! -e $dbitrace_filefull ) {
1542 0   0     0 open my $fh, ">", $dbitrace_filefull
1543             || sys_die( 'Unable to open dbitrace file', 0 );
1544 0         0 close $fh;
1545             }
1546              
1547 0 0       0 if ( $opt_help ) {
1548 0         0 _sys_help( 1 ); }
1549 0 0       0 if ( $opt_help_args ) {
1550 0         0 _sys_help( 2 ); }
1551 0 0       0 if ( $opt_run_background ) {
1552 0         0 _sys_run_background(); }
1553 0 0       0 if ( $opt_run_scheduled ) {
1554 0         0 _sys_run_scheduled(); }
1555 0 0       0 if ( $opt_run_de ) {
1556 0         0 _sys_run_de( $opt_run_de ); }
1557 0 0       0 if ( $opt_run_restart ) {
1558 0         0 _sys_run_restart(); }
1559 0 0       0 if ( $opt_test_dbcon ) {
1560 0         0 _sys_test_dbcon( $opt_test_dbcon); }
1561 0 0       0 if ( $opt_commandline_ext ) {
1562 0         0 $commandline_ext = $opt_commandline_ext; }
1563 0 0       0 if ( $opt_logging_levels ) {
1564 0         0 $log_logging_levels = _sys_check_severity_levels( $opt_logging_levels ); }
1565 0 0       0 if ( $opt_console_levels ) {
1566 0         0 $log_console_levels = _sys_check_severity_levels( $opt_console_levels ); }
1567 0 0       0 if ( $opt_log_gdg ) {
1568 0         0 $log_gdg = _sys_check_log_gdg( $opt_log_gdg ); }
1569 0 0       0 if ( $opt_log_prefix ) {
1570 0         0 $log_prefix = $opt_log_prefix; }
1571 0 0       0 if ( $opt_log_radix ) {
1572 0         0 $log_radix = _sys_check_log_radix( $opt_log_radix ); }
1573 0 0       0 if ( $opt_notify_email_tolist ) {
1574 0         0 $mail_emailto = $opt_notify_email_tolist; }
1575 0 0       0 if ( $opt_notify_pager_tolist ) {
1576 0         0 $mail_pagerto = $opt_notify_pager_tolist; }
1577 0 0       0 if ( $opt_notify_email_levels ) {
1578 0         0 $mail_email_levels = _sys_check_severity_levels( $opt_notify_email_levels ); }
1579 0 0       0 if ( $opt_notify_pager_levels ) {
1580 0         0 $mail_pager_levels = _sys_check_severity_levels( $opt_notify_pager_levels ); }
1581 0 0       0 if ( $opt_disp_logprev ) {
1582 0         0 _sys_disp_logprev(); }
1583 0 0       0 if ( $opt_disp_logarch ) {
1584 0         0 _sys_disp_logarch(); }
1585 0 0       0 if ( $opt_disp_exec ) {
1586 0         0 _sys_disp_exec(); }
1587 0 0       0 if ( $opt_disp_sql ) {
1588 0         0 _sys_disp_sql(); }
1589 0 0       0 if ( $opt_disp_params ) {
1590 0         0 _sys_disp_params(); }
1591 0 0       0 if ( $opt_disp_doc ) {
1592 0         0 _sys_disp_doc(); }
1593 0 0       0 if ( $opt_disp_jobs ) {
1594 0         0 _sys_disp_jobs(); }
1595 0 0       0 if ( $opt_disp_active_jobs ) {
1596 0         0 _sys_disp_active_jobs( 0 ); }
1597 0 0       0 if ( $opt_send_email ) {
1598 0         0 _sys_send_email_message($opt_send_email); }
1599 0 0       0 if ( $opt_send_pager ) {
1600 0         0 _sys_send_pager_message($opt_send_pager); }
1601 0 0       0 if ( $opt_util_move ) {
1602 0         0 $util_move = 0; }
1603              
1604             # must have a Run option to continue
1605 0 0       0 if ( ! $opt_run ) {
1606 0         0 _sys_help(1);
1607             }
1608              
1609 0         0 $log_file = $log_prefix . $jobname . $log_ext; # default
1610              
1611 0 0       0 if ( $osuser ) { # custom
1612 0         0 $log_file = $log_prefix . $jobname . '_' . $osuser . $log_ext;
1613             }
1614 0         0 $log_filefull = $path_log_dir . $log_file;
1615              
1616 0 0       0 if ( $opt_log_file ) { # override
1617 0         0 $log_file = $opt_log_file;
1618 0         0 $log_filefull = $path_log_dir . $log_file;
1619             }
1620              
1621 0         0 _log_init_log_file(); # log rotation handler
1622              
1623             # validate script name using configured acros
1624 0         0 my ($base, $path, $type) = fileparse( $script_file );
1625 0 0       0 if ( $base =~ m/^([a-z]+_)/x ) { ## acro + underscore
1626 0         0 $base = $1;
1627             }
1628 0 0       0 _check_array_val($base, \@job_acros) || sys_die( "Not a valid job acro", 0 );
1629              
1630 0         0 _sys_init_source_validation();
1631              
1632 0         0 sys_timer( 'start', '__default_timer' );
1633              
1634 0 0       0 log_info( "Start: $jobname" ) unless $opt_no_greeting;
1635              
1636 0 0       0 if ( $opt_very_verbose ) { $opt_verbose = 1; }
  0         0  
1637 0 0       0 if ( $opt_verbose ) {
1638 0         0 log_info( 'Running in verbose mode' );
1639 0         0 log_info( "Process: $pid" );
1640 0         0 log_info( "Options: $opt_commandline" );
1641             }
1642              
1643 0 0       0 if ( $sys_jobconf_override ) {
1644 0         0 log_info( "Jobconf override: $sys_jobconf_file" );
1645             }
1646              
1647 0         0 _sys_job_init();
1648              
1649 0         0 return 0;
1650             }
1651              
1652             sub sys_init_setuser {
1653             =begin wiki
1654              
1655             !3 sys_init_setuser
1656              
1657             ( jn, cl )
1658              
1659             Please write this documentation.
1660              
1661             =cut
1662 0     0 0 0 my ($jn, @cl) = @_;
1663 0   0     0 $osuser = getlogin || 'unknown';
1664 0         0 sys_init( $jn, @cl );
1665 0         0 return 0;
1666             }
1667              
1668             sub sys_end {
1669             =begin wiki
1670              
1671             !3 sys_end
1672              
1673             No Parameters
1674              
1675             Please write this documentation.
1676              
1677             =cut
1678 0     0 0 0 _sys_job_end();
1679              
1680 0 0       0 if ( $opt_no_greeting ) { return 0; }
  0         0  
1681              
1682 0         0 sys_timer( 'stop', '__default_timer' );
1683              
1684 0         0 log_info( "Errorlevel: $errorlevel" );
1685 0         0 log_info( "Elapsed time: " . sys_timer( 'elapsed', '__default_timer' ) );
1686 0 0       0 log_info( "End: $jobname" ) unless $opt_no_greeting;
1687              
1688 0         0 return 0;
1689             }
1690              
1691             sub sys_load_library {
1692             =begin wiki
1693              
1694             !3 sys_load_library
1695              
1696             ( conf_filename )
1697              
1698             Give the user an opportunity to load a different conf file replacing the \
1699             contents of sys_common.conf with the requested conf file contents.
1700              
1701             =cut
1702 0     0 0 0 my $conf_filename = shift;
1703              
1704             ## load a conf file replacing the contents of sys_common.conf
1705 0 0       0 tie %conf_query, 'Config::IniFiles', ( -file => $path_conf_dir.'/'.$conf_filename )
1706             or sys_die( "Unable to load conf file $conf_filename", 0 );
1707 0         0 return 0;
1708             }
1709              
1710             sub sys_init_plugin {
1711             =begin wiki
1712              
1713             !3 sys_init_plugin
1714              
1715             ( plugin_file, package_name )
1716              
1717             Provide plugin support. This function accepts a plugin filename and attempts \
1718             to load a plugin file by that name from the plugin directory. Plugins are \
1719             standard Perl modules with nothing exported. The package name used by the \
1720             module is also passed in to this function and is used to call an \
1721             initialization function named start.
1722              
1723             Plugins should always implement a start and an end function, these take no \
1724             parameters. All plugins should also implement a main plugin function named \
1725             odly enough, plugin_main. The start and end functions should not take any \
1726             parameters. The main plugin function can be written to accept whatever \
1727             parameters are needed.
1728              
1729             This little bit of deep magic by merlyn gleened from the Perl Monastery was \
1730             very educational (I almost had it before finding this):
1731              
1732             % language=Perl
1733             % my %codeRefs = map {
1734             % "Package"->can($_) || sub { die "can't find $_" }
1735             % } qw(subroutine1 subroutine2 subroutine3);
1736             %%
1737              
1738             Merlyn, aka, Tom Christensen???
1739              
1740             =cut
1741 0     0 0 0 my ($plugin_file, $package_name) = @_;
1742              
1743 0         0 my $plugin_filefull = $path_plugin_dir.$plugin_file.'.pm';
1744 0 0       0 unless ( -f $plugin_filefull ) { sys_die( "Plugin not found: $plugin_file", 0 ); }
  0         0  
1745              
1746 0         0 require $plugin_filefull;
1747              
1748 0         0 push @plugins, join '~', ($package_name, $plugin_file, $plugin_filefull);
1749 0         0 $package_name->start($path_conf_dir, $path_plugin_dir, $dataenvr);
1750 0         0 return $package_name->can('plugin_main'); ## deep magic
1751             }
1752              
1753             sub sys_ctime2str {
1754             =begin wiki
1755              
1756             !3 sys_time2str
1757              
1758             ( format )
1759              
1760             This is an interface to the Data::Format::time2str function. This simply \
1761             provides an easier way for the job script to make use of the time2str \
1762             function for acquiring a formatted current date/time. You can pass as a \
1763             format string any of the following meta characters.
1764              
1765             |%% |PERCENT|
1766             |%a |day of the week abbr|
1767             |%A |day of the week|
1768             |%b |month abbr|
1769             |%B |month|
1770             |%c |MM/DD/YY HH:MM:SS|
1771             |%C |ctime format: Sat Nov 19 21:05:57 1994|
1772             |%d |numeric day of the month, with leading zeros (eg 01..31)|
1773             |%e |numeric day of the month, without leading zeros (eg 1..31)|
1774             |%D |MM/DD/YY|
1775             |%G |GPS week number (weeks since January 6, 1980)|
1776             |%h |month abbr|
1777             |%H |hour, 24 hour clock, leading 0's)|
1778             |%I |hour, 12 hour clock, leading 0's)|
1779             |%j |day of the year|
1780             |%k |hour|
1781             |%l |hour, 12 hour clock|
1782             |%L |month number, starting with 1|
1783             |%m |month number, starting with 01|
1784             |%M |minute, leading 0's|
1785             |%n |NEWLINE|
1786             |%o |ornate day of month -- "1st", "2nd", "25th", etc.|
1787             |%p |AM or PM|
1788             |%P |am or pm (Yes %p and %P are backwards :)|
1789             |%q |Quarter number, starting with 1|
1790             |%r |time format: 09:05:57 PM|
1791             |%R |time format: 21:05|
1792             |%s |seconds since the Epoch, UCT|
1793             |%S |seconds, leading 0's|
1794             |%t |TAB|
1795             |%T |time format: 21:05:57|
1796             |%U |week number, Sunday as first day of week|
1797             |%w |day of the week, numerically, Sunday == 0|
1798             |%W |week number, Monday as first day of week|
1799             |%x |date format: 11/19/94|
1800             |%X |time format: 21:05:57|
1801             |%y |year (2 digits)|
1802             |%Y |year (4 digits)|
1803             |%Z |timezone in ascii. eg: PST|
1804             |%z |timezone in format -/+0000|
1805              
1806             /end of table/
1807              
1808             =cut
1809 0     0 0 0 my $format = shift;
1810 0         0 return time2str($format, time);
1811             }
1812              
1813             sub sys_die {
1814             =begin wiki
1815              
1816             !3 sys_die
1817              
1818             Parameters: ( message, notify )
1819              
1820             Print a message to STDOUT and then exit returning $errorlevel $RC_FATAL. The \
1821             message is printed to STDOUT because STDERR is redirected while running.
1822              
1823             =cut
1824 0     0 0 0 my ($message, $notify) = @_;
1825 0 0       0 $notify = 0 unless defined $notify;
1826 0         0 $errorlevel = $RC_FATAL;
1827              
1828 0         0 _log_write_to_screen( 'FATAL', $notify, $message );
1829              
1830 0 0       0 if ( $sys_log_open ) {
1831 0         0 _log_write_to_log( 'FATAL', $notify, $message );
1832             }
1833              
1834             ## save a call if possible
1835 0 0       0 if ( $notify ) { _log_send_notifications( 'FATAL', $notify, $message ); }
  0         0  
1836              
1837 0         0 _sys_job_end();
1838              
1839 0         0 exit $errorlevel;
1840             }
1841              
1842             sub sys_warn {
1843             =begin wiki
1844              
1845             !3 sys_warn
1846              
1847             Parameters: ( message, notify )
1848              
1849             Print a message to STDOUT and then return to caller setting $errorlevel \
1850             $RC_WARN. The message is printed to STDOUT because STDERR is redirected \
1851             while running.
1852              
1853             =cut
1854 0     0 0 0 my ($message, $notify) = @_;
1855 0 0       0 $notify = 1 unless defined $notify;
1856 0         0 $errorlevel = $RC_WARN;
1857              
1858             ## force write to screen
1859 0         0 _log_write_to_screen( 'WARN', 1, $message );
1860              
1861             ## force write to log if log is open
1862 0 0       0 if ( $sys_log_open ) {
1863 0         0 _log_write_to_log( 'WARN', 1, $message );
1864             }
1865              
1866             ## force notifications if notification requested
1867 0 0       0 if ( $notify ) { _log_send_notifications( 'WARN', 1, $message ); }
  0         0  
1868              
1869 0         0 return $errorlevel;
1870             }
1871              
1872             sub sys_info {
1873             =begin wiki
1874              
1875             !3 sys_info
1876              
1877             Parameters: ( message, notify )
1878              
1879             =cut
1880 0     0 0 0 my ($message, $extmsg, $notify, $nolog) = @_;
1881 0 0       0 $notify = 1 unless defined $notify;
1882 0 0       0 $nolog = 0 unless defined $nolog;
1883              
1884             ## get destination email address from job conf
1885 0         0 my $emailto = sys_get_item( 'sys_info_emailto' );
1886 0         0 my $mail_emailto_save = $mail_emailto;
1887 0         0 $mail_emailto = $emailto;
1888              
1889 0         0 log_info( $message, $extmsg, $nolog );
1890 0 0       0 _log_send_notifications( 'INFO', 1, $message ) if $notify;
1891              
1892 0         0 $mail_emailto = $mail_emailto_save;
1893 0         0 return 0;
1894             }
1895              
1896             sub sys_disp_active_jobs {
1897             =begin wiki
1898              
1899             !3 sys_disp_active_jobs
1900              
1901             No Parameters
1902              
1903             Please write this documentation.
1904              
1905             =cut
1906 0     0 0 0 _sys_disp_active_jobs( 1 );
1907 0         0 return 0;
1908             }
1909              
1910             sub sys_run_job {
1911             =begin wiki
1912              
1913             !3 sys_run_job
1914              
1915             Parameters: (jobname, job_maxrc, params )
1916              
1917             |$job |name of script or application to execute|
1918             |@params |list of parameters to pass to the executed process|
1919              
1920             This function usese the built-in Perl system function to invoke a JCL script \
1921             (or other application). As such, this function will wait until the child \
1922             completes before returning to the caller.
1923              
1924             A reasonable attempt is made to insure that the process execute is invoked \
1925             via a shell. This is accomplished by passing the system function the \
1926             paramaters as a quoted string, rather than as a list.
1927              
1928             Returns: Process return code from the script/application executed.
1929              
1930             =cut
1931 0     0 0 0 my ($jobname, $job_maxrc, @params) = @_;
1932              
1933 0         0 my @args = ($jobname, @params);
1934 0         0 system(@args);
1935 0         0 my $childrc = $CHILD_ERROR >> 8;
1936              
1937 0 0       0 if ( $childrc > $job_maxrc ) {
1938 0         0 sys_die( "Process failed with return code $childrc" );
1939             }
1940              
1941 0 0       0 if ( $job_maxrc > $maxrc ) { $maxrc = $job_maxrc; }
  0         0  
1942              
1943 0         0 return $childrc;
1944             }
1945              
1946             sub sys_run_job_background {
1947             =begin wiki
1948              
1949             !3 sys_run_job_background
1950              
1951             Parameters: ( jobname, maxrc, params )
1952              
1953             Please write this documentation.
1954              
1955             Returns:
1956              
1957             =cut
1958 0     0 0 0 my ($jobname, $maxrc, @params) = @_;
1959 0 0       0 $maxrc = 0 unless $maxrc;
1960              
1961 0         0 my $pid = _sys_forkexec( $jobname, @params );
1962 0         0 $pidlib{$pid} = { jobname => $jobname,
1963             maxrc => $maxrc,
1964             retcd => 0
1965             };
1966 0         0 $pidcnt++;
1967 0         0 return $pid;
1968             }
1969              
1970             sub sys_run_job_wait {
1971             =begin wiki
1972              
1973             !3 sys_run_job_wait
1974              
1975             Parameters: ( p1, p2, p3 )
1976              
1977             Please write this documentation.
1978              
1979             Returns:
1980              
1981             =cut
1982 0 0   0 0 0 return 0 if $pidcnt < 1;
1983 0         0 while (1) {
1984 0         0 my $pid = _sys_reap_child();
1985 0         0 $pidcnt--;
1986 0         0 my $childrc = $pidlib{$pid}{retcd};
1987 0         0 my $msg = "Complete $pidlib{$pid}{jobname}. Return code: $childrc.";
1988 0 0       0 if ( $childrc > $pidlib{$pid}{maxrc} ) {
1989             ## log_warn sets errorlevel
1990 0         0 log_warn( "$msg Max allowed: $pidlib{$pid}{maxrc}." );
1991             } else {
1992 0         0 log_info( $msg );
1993             }
1994 0 0       0 last if $pidcnt < 1;
1995             }
1996 0         0 return $pidcnt;
1997             }
1998              
1999             sub sys_run_job_maxrc {
2000             =begin wiki
2001              
2002             !3 sys_run_job_maxrc
2003              
2004             Parameters: ( p1, p2, p3 )
2005              
2006             Please write this documentation.
2007              
2008             Returns:
2009              
2010             =cut
2011             ## return the max of either the current background max return code or the
2012             ## current foreground max return code
2013 0     0 0 0 my $tmprc = 0;
2014 0         0 foreach my $pid ( keys %pidlib ) {
2015 0 0       0 if ( $pidlib{$pid}{retcd} > $tmprc ) { $tmprc = $pidlib{$pid}{retcd}; }
  0         0  
2016             }
2017              
2018 0 0       0 ( $tmprc >= $maxrc ) ? return $tmprc : return $maxrc;
2019             }
2020              
2021             sub sys_run_job_reset {
2022             =begin wiki
2023              
2024             !3 sys_run_job_reset
2025              
2026             Parameters: ( p1, p2, p3 )
2027              
2028             Please write this documentation.
2029              
2030             Returns:
2031              
2032             =cut
2033 0     0 0 0 $pidcnt = 0; ## reset background jobs count
2034 0         0 %pidlib = (); ## reset background jobs info hash
2035 0         0 $maxrc = 0; ## reset foreground jobs max return code
2036 0         0 return 0;
2037             }
2038              
2039             sub sys_get_path_bin_dir {
2040             =begin wiki
2041              
2042             !3 sys_get_path_bin_dir
2043              
2044             Parameters: ( p1, p2, p3 )
2045              
2046             Please write this documentation.
2047              
2048             Returns:
2049              
2050             =cut
2051 0     0 0 0 return $path_bin_dir;
2052             }
2053              
2054             sub sys_get_path_lib_dir {
2055             =begin wiki
2056              
2057             !3 sys_get_path_lib_dir
2058              
2059             Parameters: ( p1, p2, p3 )
2060              
2061             Please write this documentation.
2062              
2063             Returns:
2064              
2065             =cut
2066 0     0 0 0 return $path_lib_dir;
2067             }
2068              
2069             sub sys_get_path_log_dir {
2070             =begin wiki
2071              
2072             !3 sys_get_path_log_dir
2073              
2074             Parameters: ( p1, p2, p3 )
2075              
2076             Please write this documentation.
2077              
2078             Returns:
2079              
2080             =cut
2081 0     0 0 0 return $path_log_dir;
2082             }
2083              
2084             sub sys_get_path_load_dir {
2085             =begin wiki
2086              
2087             !3 sys_get_path_load_dir
2088              
2089             Parameters: ( p1, p2, p3 )
2090              
2091             Please write this documentation.
2092              
2093             Returns:
2094              
2095             =cut
2096 0     0 0 0 return $path_load_dir;
2097             }
2098              
2099             sub sys_get_path_extr_dir {
2100             =begin wiki
2101              
2102             !3 sys_get_path_extr_dir
2103              
2104             Parameters: ( p1, p2, p3 )
2105              
2106             Please write this documentation.
2107              
2108             Returns:
2109              
2110             =cut
2111 0     0 0 0 return $path_extr_dir;
2112             }
2113              
2114             sub sys_get_path_prev_dir {
2115             =begin wiki
2116              
2117             !3 sys_get_path_prev_dir
2118              
2119             Parameters: ( p1, p2, p3 )
2120              
2121             Please write this documentation.
2122              
2123             Returns:
2124              
2125             =cut
2126 0     0 0 0 return $path_prev_dir;
2127             }
2128              
2129             sub sys_get_path_scripts_dir {
2130             =begin wiki
2131              
2132             !3 sys_get_path_scripts_dir
2133              
2134             Parameters: ( p1, p2, p3 )
2135              
2136             Please write this documentation.
2137              
2138             Returns:
2139              
2140             =cut
2141 0     0 0 0 return $path_scripts_dir;
2142             }
2143              
2144             sub sys_get_path_plugin_dir {
2145             =begin wiki
2146              
2147             !3 sys_get_path_plugin_dir
2148              
2149             Parameters: ( p1, p2, p3 )
2150              
2151             Please write this documentation.
2152              
2153             Returns:
2154              
2155             =cut
2156 0     0 0 0 return $path_plugin_dir;
2157             }
2158              
2159             sub sys_get_mail_server {
2160             =begin wiki
2161              
2162             !3 sys_get_mail_server
2163              
2164             Parameters: ( p1, p2, p3 )
2165              
2166             Please write this documentation.
2167              
2168             Returns:
2169              
2170             =cut
2171 0     0 0 0 return $mail_server;
2172             }
2173              
2174             sub sys_get_mail_from {
2175             =begin wiki
2176              
2177             !3 sys_get_mail_from
2178              
2179             Parameters: ( p1, p2, p3 )
2180              
2181             Please write this documentation.
2182              
2183             Returns:
2184              
2185             =cut
2186 0     0 0 0 return $mail_from;
2187             }
2188              
2189             sub sys_get_mail_emailto {
2190             =begin wiki
2191              
2192             !3 sys_get_mail_emailto
2193              
2194             Parameters: ( p1, p2, p3 )
2195              
2196             Please write this documentation.
2197              
2198             Returns:
2199              
2200             =cut
2201 0     0 0 0 return $mail_emailto;
2202             }
2203              
2204             sub sys_get_mail_pagerto {
2205             =begin wiki
2206              
2207             !3 sys_get_mail_pagerto
2208              
2209             Parameters: ( p1, p2, p3 )
2210              
2211             Please write this documentation.
2212              
2213             Returns:
2214              
2215             =cut
2216 0     0 0 0 return $mail_pagerto;
2217             }
2218              
2219             sub sys_get_mail_email_levels {
2220             =begin wiki
2221              
2222             !3 sys_get_mail_email_levels
2223              
2224             Parameters: ( p1, p2, p3 )
2225              
2226             Please write this documentation.
2227              
2228             Returns:
2229              
2230             =cut
2231 0     0 0 0 return $mail_email_levels;
2232             }
2233              
2234             sub sys_get_mail_pager_levels {
2235             =begin wiki
2236              
2237             !3 sys_get_mail_pager_levels
2238              
2239             Parameters: ( p1, p2, p3 )
2240              
2241             Please write this documentation.
2242              
2243             Returns:
2244              
2245             =cut
2246 0     0 0 0 return $mail_pager_levels;
2247             }
2248              
2249             sub sys_get_log_file {
2250             =begin wiki
2251              
2252             !3 sys_get_log_file
2253              
2254             Parameters: ( p1, p2, p3 )
2255              
2256             Please write this documentation.
2257              
2258             Returns:
2259              
2260             =cut
2261 0     0 0 0 return $log_file;
2262             }
2263              
2264             sub sys_get_log_filefull {
2265             =begin wiki
2266              
2267             !3 sys_get_log_filefull
2268              
2269             Parameters: ( p1, p2, p3 )
2270              
2271             Please write this documentation.
2272              
2273             Returns:
2274              
2275             =cut
2276 0     0 0 0 return $log_filefull;
2277             }
2278              
2279             sub sys_get_log_logging_levels {
2280             =begin wiki
2281              
2282             !3 sys_get_log_logging_levels
2283              
2284             Parameters: ( p1, p2, p3 )
2285              
2286             Please write this documentation.
2287              
2288             Returns:
2289              
2290             =cut
2291 0     0 0 0 return $log_logging_levels;
2292             }
2293              
2294             sub sys_get_log_console_levels {
2295             =begin wiki
2296              
2297             !3 sys_get_log_console_levels
2298              
2299             Parameters: ( p1, p2, p3 )
2300              
2301             Please write this documentation.
2302              
2303             Returns:
2304              
2305             =cut
2306 0     0 0 0 return $log_console_levels;
2307             }
2308              
2309             sub sys_get_log_gdg {
2310             =begin wiki
2311              
2312             !3 sys_get_log_gdg
2313              
2314             Parameters: ( p1, p2, p3 )
2315              
2316             Please write this documentation.
2317              
2318             Returns:
2319              
2320             =cut
2321 0     0 0 0 return $log_gdg;
2322             }
2323              
2324             sub sys_get_dataenvr {
2325             =begin wiki
2326              
2327             !3 sys_get_dataenvr
2328              
2329             Parameters: ( p1, p2, p3 )
2330              
2331             Please write this documentation.
2332              
2333             Returns:
2334              
2335             =cut
2336 0     0 0 0 return $dataenvr;
2337             }
2338              
2339             sub sys_get_errorlevel {
2340             =begin wiki
2341              
2342             !3 sys_get_errorlevel
2343              
2344             Parameters: ( p1, p2, p3 )
2345              
2346             Please write this documentation.
2347              
2348             Returns:
2349              
2350             =cut
2351 0     0 0 0 return $errorlevel;
2352             }
2353              
2354             sub sys_get_dbdescr {
2355             =begin wiki
2356              
2357             !3 sys_get_dbdescr
2358              
2359             Parameters: ( dbacro )
2360              
2361             Accept a database acro and return a database description string which \
2362             consists of database name, acro, and current instance.
2363              
2364             Returns:
2365              
2366             =cut
2367 0     0 0 0 my $dbacro = shift;
2368              
2369 0         0 my $dbdescr = 'Database: acronym not found';
2370 0         0 foreach my $acro ( @databases ) {
2371 0 0       0 if ( $acro eq $dbacro ) {
2372 0         0 $dbdescr = 'Database Connection: ' . $dbname{$dbacro} . ' (' .
2373             $dbacro . '/' . $dbdefenvr{$dbacro} . ')';
2374             }
2375             }
2376 0         0 return $dbdescr;
2377             }
2378             sub sys_get_dbinst {
2379             =begin wiki
2380              
2381             !3 sys_get_dbinst
2382              
2383             Parameters: ( dbacro )
2384              
2385             Please write this documentation.
2386              
2387             Returns:
2388              
2389             =cut
2390 0     0 0 0 my $dbacro = shift;
2391              
2392 0         0 my $dbdescr = 'Database: instance not found';
2393 0         0 foreach my $acro ( @databases ) {
2394 0 0       0 if ( $acro eq $dbacro ) {
2395 0         0 $dbdescr = $dbacro . '/' . $dbdefenvr{$dbacro};
2396             }
2397             }
2398 0         0 return uc($dbdescr);
2399             }
2400              
2401             sub sys_get_conf_dir {
2402             =begin wiki
2403              
2404             !3 sys_get_conf_dir
2405              
2406             Parameters: ( p1, p2, p3 )
2407              
2408             Please write this documentation.
2409              
2410             Returns:
2411              
2412             =cut
2413 0     0 0 0 return $path_conf_dir . '/';
2414             }
2415              
2416             sub sys_get_sql {
2417             =begin wiki
2418              
2419             !3 sys_get_sql
2420              
2421             Parameters: ( sqlname, alternate_job_name )
2422              
2423             Return the sql query from the query.conf file using the sqlname provided. \
2424             If the requested sql name is not found, the name gets 'sql:' prepended and \
2425             then another attempt is made. This allows entries of the form 'name' or \
2426             alternately 'sql:name' to be used in the query.conf file.
2427              
2428             The user may also pass in an optionl section name which will override the \
2429             default section name. (Default section name is the current $jobname.)
2430              
2431             Returns:
2432              
2433             =cut
2434 0     0 0 0 my ($sqlname, $altsection) = @_;
2435 0   0     0 my $section = $altsection || 'sql';
2436              
2437 0 0       0 if ( ! $conf_job{$section}{$sqlname} ) {
2438 0         0 $sqlname = 'sql:'.$sqlname;
2439 0 0       0 if ( ! $conf_job{$section}{$sqlname} ) {
2440 0         0 sys_die( "The job conf file does not contain a query named [$sqlname]", 0 );
2441             }
2442             }
2443 0         0 return $conf_job{$section}{$sqlname};
2444             }
2445              
2446             sub sys_get_item {
2447             =begin wiki
2448              
2449             !3 sys_get_item
2450              
2451             Parameters: ( p1, p2, p3 )
2452              
2453             Please write this documentation.
2454              
2455             Returns:
2456              
2457             =cut
2458 0     0 0 0 my ($item, $altsection) = @_;
2459 0   0     0 my $section = $altsection || 'job';
2460              
2461 0         0 my $value = $conf_job{$section}{$item};
2462              
2463 0 0       0 if ( ! defined $value ) {
2464 0         0 sys_die( "Job conf missing entry [$item] in section [$section]", 0 );
2465             }
2466              
2467 0 0       0 if ( $value eq '0' ) {
2468 0         0 return $conf_job{$section}{$item};
2469             }
2470              
2471 0         0 return $value;
2472             }
2473              
2474             sub sys_get_hash {
2475             =begin wiki
2476              
2477             !3 sys_get_hash
2478              
2479             Parameters: ( p1, p2, p3 )
2480              
2481             Please write this documentation.
2482              
2483             Returns:
2484              
2485             =cut
2486 0     0 0 0 my ($section, $entry, $delim) = @_;
2487 0 0       0 $delim = ':' unless $delim;
2488              
2489 0         0 my ($pseudo, %hash);
2490              
2491 0 0       0 if ( $conf_job{$section}{$entry} ) {
2492 0         0 $pseudo = $conf_job{$section}{$entry};
2493             } else {
2494 0         0 sys_die( "No job conf entry found for $entry in section $section" );
2495             }
2496              
2497             ## construct a real hash from the pseudo hash
2498 0         0 foreach my $item ( split "\n", $pseudo ) {
2499 0         0 my ($key, $value) = split m/$delim/, $item;
2500 0         0 $hash{$key} = $value;
2501             }
2502              
2503 0         0 return \%hash; ## ref to hash
2504             }
2505              
2506             sub sys_get_array {
2507             =begin wiki
2508              
2509             !3 sys_get_array
2510              
2511             Parameters: ( p1, p2, p3 )
2512              
2513             Please write this documentation.
2514              
2515             Returns:
2516              
2517             =cut
2518 0     0 0 0 my ($section, $entry, $delim) = @_;
2519 0 0       0 $delim = ':' unless $delim;
2520              
2521 0         0 my ($pseudo, @array);
2522              
2523 0 0       0 if ( $conf_job{$section}{$entry} ) {
2524 0         0 $pseudo = $conf_job{$section}{$entry};
2525             } else {
2526 0         0 sys_die( "No job conf entry found for $entry in section $section" );
2527             }
2528              
2529             ## construct a real array from the pseudo array
2530 0         0 foreach my $item ( split "\n", $pseudo ) {
2531 0         0 push @array, $item;
2532             }
2533              
2534 0         0 return \@array; ## ref to an array
2535             }
2536              
2537             sub sys_get_common_sql {
2538             =begin wiki
2539              
2540             !3 sys_get_common_sql
2541              
2542             Parameters: ( p1, p2, p3 )
2543              
2544             Please write this documentation.
2545              
2546             Returns:
2547              
2548             =cut
2549 0     0 0 0 my ($sqlname, $altsection) = @_;
2550 0   0     0 my $section = $altsection || 'sql';
2551              
2552 0 0       0 if ( ! $conf_query{$section}{$sqlname} ) {
2553 0         0 $sqlname = 'sql:'.$sqlname;
2554 0 0       0 if ( ! $conf_query{$section}{$sqlname} ) {
2555 0         0 sys_die( 'Common sql conf missing query by that name', 0 );
2556             }
2557             }
2558 0         0 return $conf_query{$section}{$sqlname};
2559             }
2560              
2561             sub sys_get_run_control {
2562             =begin wiki
2563              
2564             !3 sys_get_run_control
2565              
2566             Parameters: ( p1, p2, p3 )
2567              
2568             Please write this documentation.
2569              
2570             Returns:
2571              
2572             =cut
2573 0     0 0 0 my ($jobname, $section, $default) = @_;
2574              
2575 0   0     0 my $rcontrol = $default || 0;
2576 0 0       0 if ( ! $conf_rcontrols{$section}{$jobname} ) {
2577 0         0 return $rcontrol;
2578             }
2579              
2580 0         0 return $conf_rcontrols{$section}{$jobname};
2581             }
2582              
2583             sub sys_get_email_levels {
2584             =begin wiki
2585              
2586             !3 sys_get_email_levels
2587              
2588             Parameters: ( p1, p2, p3 )
2589              
2590             Please write this documentation.
2591              
2592             Returns:
2593              
2594             =cut
2595 0     0 0 0 return $mail_email_levels;
2596             }
2597              
2598             sub sys_get_pager_levels {
2599             =begin wiki
2600              
2601             !3 sys_get_pager_levels
2602              
2603             Parameters: ( p1, p2, p3 )
2604              
2605             Please write this documentation.
2606              
2607             Returns:
2608              
2609             =cut
2610 0     0 0 0 return $mail_pager_levels;
2611             }
2612              
2613             sub sys_get_logging_levels {
2614             =begin wiki
2615              
2616             !3 sys_get_logging_levels
2617              
2618             Parameters: ( p1, p2, p3 )
2619              
2620             Please write this documentation.
2621              
2622             Returns:
2623              
2624             =cut
2625 0     0 0 0 return $log_logging_levels;
2626             }
2627              
2628             sub sys_get_console_levels {
2629             =begin wiki
2630              
2631             !3 sys_get_console_levels
2632              
2633             Parameters: ( p1, p2, p3 )
2634              
2635             Please write this documentation.
2636              
2637             Returns:
2638              
2639             =cut
2640 0     0 0 0 return $log_console_levels;
2641             }
2642              
2643             sub sys_get_commandline {
2644             =begin wiki
2645              
2646             !3 sys_get_commandline
2647              
2648             Parameters: ( p1, p2, p3 )
2649              
2650             Please write this documentation.
2651              
2652             Returns:
2653              
2654             =cut
2655 0     0 0 0 return join ' ', @ARGV;
2656             }
2657              
2658             sub sys_get_commandline_opt {
2659             =begin wiki
2660              
2661             !3 sys_get_commandline_opt
2662              
2663             Parameters: ( p1, p2, p3 )
2664              
2665             Please write this documentation.
2666              
2667             Returns:
2668              
2669             =cut
2670 0     0 0 0 my $target_opt = shift;
2671 0         0 foreach my $option ( @ARGV ) {
2672 0         0 my ($opt,$val) = split m/=/, $option;
2673 0         0 $opt =~ s/^-\s*//x;
2674 0         0 $opt =~ s/\s+$//x;
2675 0 0       0 if ( $opt =~ m/^$target_opt$/ix ) {
2676 0         0 return 1;
2677             }
2678             }
2679 0         0 return 0;
2680             }
2681              
2682             sub sys_get_commandline_val {
2683             =begin wiki
2684              
2685             !3 sys_get_commandline_val
2686              
2687             Parameters: ( p1, p2, p3 )
2688              
2689             Please write this documentation.
2690              
2691             Returns:
2692              
2693             =cut
2694 0     0 0 0 my ($target_opt,$default_value) = @_;
2695             ## handle:
2696             ## >script.pl -r -- -batchsize=10
2697 0         0 foreach my $option ( @ARGV ) {
2698 0         0 $option =~ s/\s+=/=/x;
2699 0         0 $option =~ s/=\s+/=/x;
2700 0         0 my ($opt,$val) = split m/=/, $option;
2701 0         0 $opt =~ s/^-\s*//x;
2702 0         0 $opt =~ s/\s+$//x;
2703 0 0       0 if ( $opt =~ m/^$target_opt$/ix ) {
2704             #$val =~ s/^\s*//;
2705             #$val =~ s/\s*$//;
2706 0         0 return $val;
2707             }
2708             }
2709 0         0 return $default_value;
2710             }
2711              
2712             sub sys_get_script_file {
2713             =begin wiki
2714              
2715             !3 sys_get_script_file
2716              
2717             Parameters: ( p1, p2, p3 )
2718              
2719             Please write this documentation.
2720              
2721             Returns:
2722              
2723             =cut
2724 0     0 0 0 return $script_file;
2725             }
2726              
2727             sub sys_get_util_move {
2728             =begin wiki
2729              
2730             !3 sys_get_util_move
2731              
2732             Parameters: ( p1, p2, p3 )
2733              
2734             Please write this documentation.
2735              
2736             Returns:
2737              
2738             =cut
2739 0     0 0 0 return $util_move;
2740             }
2741              
2742             sub sys_get_user {
2743             =begin wiki
2744              
2745             !3 sys_get_user
2746              
2747             Parameters: ( p1, p2, p3 )
2748              
2749             Please write this documentation.
2750              
2751             Returns:
2752              
2753             =cut
2754 0   0 0 0 0 return getlogin || 'unknown';
2755             }
2756              
2757             sub sys_get_maxval {
2758             =begin wiki
2759              
2760             !3 sys_get_maxval
2761              
2762             Parameters: ( p1, p2, p3 )
2763              
2764             Please write this documentation.
2765              
2766             Returns:
2767              
2768             =cut
2769 0     0 0 0 my $key = shift;
2770 0   0     0 return $maxval{$key} || 0;
2771             }
2772              
2773             sub sys_set_restart {
2774             =begin wiki
2775              
2776             !3 sys_set_restart
2777              
2778             Parameters: ( restart_option )
2779              
2780             Write the requested restart_option to the the system.conf file. This value \
2781             is the last step attempted by the calling script.
2782              
2783             Returns:
2784              
2785             =cut
2786 0     0 0 0 my $restart_option = shift;
2787              
2788 0 0       0 if ( $restart_option !~ m/^\d+/x ) {
2789 0         0 sys_die( 'Restart option is not numeric', 0 );
2790 0         0 return 1;
2791             }
2792              
2793 0         0 my $rtconf = $path_conf_dir.'/'.$jobname.'.running';
2794 0         0 my $conf = new Config::IniFiles( -file => $rtconf );
2795 0 0       0 unless ( defined $conf ) { sys_die( "Error opening runtime jobconf file", 0 ); }
  0         0  
2796 0         0 $conf->setval( 'restart', 'restart', $restart_option );
2797 0         0 $conf->RewriteConfig;
2798              
2799 0         0 return 0;
2800             }
2801              
2802             sub sys_set_verbose {
2803             =begin wiki
2804              
2805             !3 sys_set_verbose
2806              
2807             Parameters: ( p1, p2, p3 )
2808              
2809             Please write this documentation.
2810              
2811             Returns:
2812              
2813             =cut
2814 0     0 0 0 $opt_verbose = 1;
2815 0         0 return 0;
2816             }
2817              
2818             sub sys_set_errorlevel {
2819             =begin wiki
2820              
2821             !3 sys_set_errorlevel
2822              
2823             Parameters: ( p1, p2, p3 )
2824              
2825             Please write this documentation.
2826              
2827             Returns:
2828              
2829             =cut
2830 0     0 0 0 my $errlvl = shift;
2831              
2832 0 0       0 if ( $errlvl !~ /^\d+$/ ) {
2833 0         0 sys_die( "Invalid value passed to sys_set_errorlevel()" );
2834             }
2835              
2836 0         0 my $save_errlvl = $errorlevel;
2837 0         0 $errorlevel = $errlvl;
2838 0         0 return $save_errlvl;
2839             }
2840              
2841             sub sys_set_warn {
2842             =begin wiki
2843              
2844             !3 sys_set_warn
2845              
2846             Parameters: ( p1, p2, p3 )
2847              
2848             Please write this documentation.
2849              
2850             Returns:
2851              
2852             =cut
2853 0     0 0 0 $errorlevel = $RC_WARN;
2854 0         0 return $RC_WARN;
2855             }
2856              
2857             sub sys_set_die {
2858             =begin wiki
2859              
2860             !3 sys_set_die
2861              
2862             Parameters: ( p1, p2, p3 )
2863              
2864             Please write this documentation.
2865              
2866             Returns:
2867              
2868             =cut
2869 0     0 0 0 $errorlevel = $RC_FATAL;
2870 0         0 return $RC_FATAL;
2871             }
2872              
2873             sub sys_set_email_levels {
2874             =begin wiki
2875              
2876             !3 sys_set_email_levels
2877              
2878             Parameters: ( email_levels )
2879              
2880             Accept a comma delimited list of message levels to use as the source for \
2881             determing which message levels will generate a notification, and which \
2882             message levels will be ignored when email notification is invoked.
2883              
2884             Valid values for the list are: FATAL,ERROR,WARN,INFO,DEBUG,NONE
2885              
2886             Returns:
2887              
2888             =cut
2889 0   0 0 0 0 my $email_levels = shift || "FATAL";
2890 0         0 $mail_email_levels = _sys_check_severity_levels( $email_levels );
2891 0         0 return $mail_email_levels;
2892             }
2893              
2894             sub sys_set_pager_levels {
2895             =begin wiki
2896              
2897             !3 sys_set_pager_levels
2898              
2899             Parameters: ( pager_levels )
2900              
2901             Accept a comma delimited list of message levels to use as the source for \
2902             determing which message levels will generate a notification, and which \
2903             message levels will be ignored when pager notification is invoked.
2904              
2905             Valid values for the list are: FATAL,ERROR,WARN,INFO,DEBUG,NONE
2906              
2907             Returns:
2908              
2909             =cut
2910 0   0 0 0 0 my $pager_levels = shift || "FATAL";
2911 0         0 $mail_pager_levels = _sys_check_severity_levels( $pager_levels );
2912 0         0 return $mail_pager_levels;
2913             }
2914              
2915             sub sys_set_mail_emailto {
2916             =begin wiki
2917              
2918             !3 sys_set_mail_emailto
2919              
2920             Parameters: ( p1, p2, p3 )
2921              
2922             Please write this documentation.
2923              
2924             Returns:
2925              
2926             =cut
2927 0     0 0 0 my $new_emailto = shift;
2928 0         0 my $old_emailto = $mail_emailto;
2929 0         0 $mail_emailto = $new_emailto;
2930 0         0 return $old_emailto;
2931             }
2932              
2933             sub sys_set_logging_levels {
2934             =begin wiki
2935              
2936             !3 sys_set_logging_levels
2937              
2938             Parameters: ( p1, p2, p3 )
2939              
2940             Please write this documentation.
2941              
2942             Returns:
2943              
2944             =cut
2945 0   0 0 0 0 my $logging_levels = shift || "FATAL,ERROR,WARN,INFO";
2946 0         0 $log_logging_levels = _sys_check_severity_levels( $logging_levels );
2947 0         0 return $log_logging_levels;
2948             }
2949              
2950             sub sys_set_console_levels {
2951             =begin wiki
2952              
2953             !3 sys_set_console_levels
2954              
2955             Parameters: ( p1, p2, p3 )
2956              
2957             Please write this documentation.
2958              
2959             Returns:
2960              
2961             =cut
2962 0   0 0 0 0 my $console_levels = shift || "FATAL,ERROR,WARN,INFO";
2963 0         0 $log_console_levels = _sys_check_severity_levels( $console_levels );
2964 0         0 return $log_console_levels;
2965             }
2966              
2967             sub sys_set_script_file {
2968             =begin wiki
2969              
2970             !3 sys_set_script_file
2971              
2972             Parameters: ( p1, p2, p3 )
2973              
2974             Please write this documentation.
2975              
2976             Returns:
2977              
2978             =cut
2979 0   0 0 0 0 my $file = shift || $script_file;
2980 0         0 $script_file = $file;
2981 0         0 return $script_file;
2982              
2983             }
2984              
2985             sub sys_set_conf_file {
2986             =begin wiki
2987              
2988             Parameters: ( jobconf )
2989              
2990             Manage the job conf file.
2991              
2992             Set the value of the job conf filename and read the corresponding file. If \
2993             no job conf filename is given, set the job conf filename back to the default \
2994             value and reread the default job conf file (perform a reset).
2995              
2996             Returns:
2997              
2998             =cut
2999 0   0 0 0 0 my $jobconf = shift || '';
3000              
3001 0 0       0 if ( $jobconf ) {
3002             ## change jobconf file and read
3003 0         0 $sys_jobconf_file = $jobconf . '.conf';
3004 0         0 _sys_read_conf( $sys_jobconf_file ); ## tie %conf_job to job conf file
3005 0         0 _sys_read_job(); ## read job specific settings from %conf_job
3006             } else {
3007             ## reset jobconf file to default and reread
3008 0         0 $sys_jobconf_file = _sys_check_de_override( $jobname . '.conf' );
3009 0         0 _sys_read_conf( $sys_jobconf_file ); ## tie %conf_job to job conf file
3010 0         0 _sys_read_job(); ## read job specific settings from %conf_job
3011             }
3012 0         0 return 0;
3013             }
3014              
3015             sub sys_set_path_log_dir {
3016             =begin wiki
3017              
3018             !3 sys_set_path_log_dir
3019              
3020             Parameters: ( p1, p2, p3 )
3021              
3022             Please write this documentation.
3023              
3024             Returns:
3025              
3026             =cut
3027 0   0 0 0 0 my $path = shift || $path_log_dir;
3028 0         0 $path_log_dir = $path;
3029 0         0 return $path_log_dir;
3030             }
3031              
3032             sub sys_set_path_plugin_dir {
3033             =begin wiki
3034              
3035             !3 sys_set_path_plugin_dir
3036              
3037             Parameters: ( p1, p2, p3 )
3038              
3039             Please write this documentation.
3040              
3041             Returns:
3042              
3043             =cut
3044 0   0 0 0 0 my $path = shift || $path_plugin_dir;
3045 0         0 $path_plugin_dir = $path;
3046 0         0 return $path_plugin_dir;
3047             }
3048              
3049             sub sys_set_maxval {
3050             =begin wiki
3051              
3052             !3 sys_set_maxval
3053              
3054             Parameters: ( p1, p2, p3 )
3055              
3056             Please write this documentation.
3057              
3058             Returns:
3059              
3060             =cut
3061 0     0 0 0 my ($key, $val) = @_;
3062 0 0       0 if ( $maxval{$key} ) {
3063 0 0       0 if ( $val > $maxval{$key} ) {
3064 0         0 $maxval{$key} = $val;
3065             }
3066 0         0 return $val;
3067             }
3068 0         0 $maxval{$key} = $val;
3069 0         0 return $val;
3070             }
3071              
3072             sub sys_check_dataenvr {
3073             =begin wiki
3074              
3075             !3 sys_check_dataenvr
3076              
3077             Parameters:
3078              
3079             /data_envrs/ = dataenvrs to check
3080              
3081             Accept either a dataenvr or a ref to an array of dataenvrs. If \
3082             /data_envrs/ contains the current dataenvr, return true, otherwise return \
3083             false.
3084              
3085             Returns:
3086              
3087             =cut
3088 0     0 0 0 my $data_envrs = shift;
3089 0         0 my @check_envrs;
3090              
3091 0 0       0 if ( ref $data_envrs eq 'ARRAY' ) {
3092 0         0 @check_envrs = map { $_ } @{$data_envrs};
  0         0  
  0         0  
3093             } else {
3094 0         0 push @check_envrs, $data_envrs; ## single entry
3095             }
3096              
3097             ## is current data environment in the list of acceptable environments
3098 0 0       0 if ( grep { $_ eq $dataenvr } @check_envrs ) {
  0         0  
3099 0         0 return 1;
3100             }
3101              
3102 0         0 return 0;
3103             }
3104              
3105             sub sys_disp_doc {
3106             =begin wiki
3107              
3108             !3 sys_disp_doc
3109              
3110             Parameters: ( p1, p2, p3 )
3111              
3112             Please write this documentation.
3113              
3114             Returns:
3115              
3116             =cut
3117 0     0 0 0 return _sys_disp_doc();
3118             }
3119              
3120             sub sys_timer {
3121             =begin wiki
3122              
3123             !3 sys_timer
3124              
3125             Parameters: ( p1, p2, p3 )
3126              
3127             Please write this documentation.
3128              
3129             Returns:
3130              
3131             =cut
3132 0     0 0 0 my ($opt, $timer_name) = @_;
3133 0 0       0 $timer_name = 't1' unless $timer_name;
3134              
3135 0 0       0 if ( $opt =~ m/start/ix ) {
3136 0         0 $timers{$timer_name.'_start'} = time;
3137 0         0 return $timers{$timer_name.'_start'};
3138             }
3139 0 0       0 if ( $opt =~ m/stop/ix ) {
3140 0         0 $timers{$timer_name.'_stop'} = time;
3141 0         0 return $timers{$timer_name.'_stop'};
3142             }
3143 0 0       0 if ( $opt =~ m/elapsed/ix ) {
3144 0         0 my $estart = $timers{$timer_name.'_start'};
3145 0         0 my $estop = $timers{$timer_name.'_stop'};
3146 0         0 my $eelapsed = $estop - $estart;
3147 0         0 my $ehours = int $eelapsed / 3600;
3148 0         0 my $emins = int $eelapsed / 60 % 60;
3149 0         0 my $esecs = int $eelapsed % 60;
3150 0         0 return sprintf "%02d:%02d:%02d", $ehours, $emins, $esecs;
3151             }
3152 0 0       0 if ( $opt =~ /elapsed_seconds/i ) {
3153 0         0 my $sstart = $timers{$timer_name.'_start'};
3154 0         0 my $sstop = $timers{$timer_name.'_stop'};
3155 0         0 my $selapsed = $sstop - $sstart;
3156 0         0 return $selapsed;
3157             }
3158 0         0 return 'TIMER ERROR';
3159             }
3160              
3161             sub sys_wait {
3162             =begin wiki
3163              
3164             !3 sys_wait
3165              
3166             Parameters: ( $action, $minutes )
3167              
3168             $action can be either:
3169              
3170             * 'init' - initialize wait's start time and elapsed time
3171             * 'wait' - wait until $minutes has elapsed since start time
3172              
3173             Example:
3174              
3175             % language=Perl
3176             % sys_wait( 'init', 3 );
3177             % ... do some work
3178             % sys_wait( 'wait' );
3179             %%
3180              
3181             Returns:
3182              
3183             =cut
3184 0     0 0 0 my ($action, $minutes) = @_;
3185              
3186 0 0       0 if ( $action =~ /^init$/i ) {
3187 0         0 $wt_start = time;
3188 0         0 $wt_seconds = 0;
3189 0 0       0 return 0 unless $minutes =~ /^\d+$/;
3190 0         0 $wt_seconds = $minutes * 60;
3191             }
3192              
3193 0 0       0 if ( $action =~ /^wait$/i ) {
3194 0         0 while ( 1 ) {
3195 0         0 my $currtime = time;
3196 0         0 my $elapsedt = $currtime - $wt_start;
3197 0         0 log_info( "Waiting $wt_seconds, Elapsed: $elapsedt" );
3198 0 0       0 if ( ($currtime - $wt_start) < $wt_seconds ) {
3199 0         0 sleep 10;
3200             } else {
3201 0         0 last;
3202             }
3203             }
3204             }
3205              
3206 0         0 return 0;
3207             }
3208              
3209             =begin wiki
3210              
3211             !2 Logging Functions
3212              
3213             These functions provide logging and notification capabilities.
3214              
3215             =cut
3216              
3217             sub log_fatal {
3218             =begin wiki
3219              
3220             !3 log_fatal
3221              
3222             Parameters: ( message )
3223              
3224             Call lower level logging functions using severity level FATAL.
3225              
3226             Returns:
3227              
3228             =cut
3229 0     0 0 0 my ($message, $extmsg) = @_;
3230 0         0 $errorlevel = $RC_FATAL;
3231 0         0 _log_write_to_log( 'FATAL', 0, $message, $extmsg);
3232 0         0 _log_write_to_screen( 'FATAL', 0, $message, $extmsg);
3233 0         0 return $errorlevel;
3234             }
3235              
3236             sub log_error {
3237             =begin wiki
3238              
3239             !3 log_error
3240              
3241             Parameters: ( message )
3242              
3243             Call lower level logging functions using severity level ERROR.
3244              
3245             Returns:
3246              
3247             =cut
3248 0     0 0 0 my ($message, $extmsg) = @_;
3249 0         0 $errorlevel = $RC_ERROR;
3250 0         0 _log_write_to_log( 'ERROR', 0, $message, $extmsg);
3251 0         0 _log_write_to_screen( 'ERROR', 0, $message, $extmsg);
3252 0         0 return $errorlevel;
3253             }
3254              
3255             sub log_warn {
3256             =begin wiki
3257              
3258             !3 log_warn
3259              
3260             Parameters: ( message )
3261              
3262             Call lower level logging functions using severity level WARN.
3263              
3264             Returns:
3265              
3266             =cut
3267 0     0 0 0 my ($message, $extmsg) = @_;
3268 0         0 $errorlevel = $RC_WARN;
3269 0         0 _log_write_to_log( 'WARN', 0, $message, $extmsg);
3270 0         0 _log_write_to_screen( 'WARN', 0, $message, $extmsg);
3271 0         0 return $errorlevel;
3272             }
3273              
3274             sub log_info {
3275             =begin wiki
3276              
3277             !3 log_info
3278              
3279             Parameters: ( message )
3280              
3281             Call lower level logging functions using severity level INFO.
3282              
3283             Returns:
3284              
3285             =cut
3286 0     0 0 0 my ($message, $extmsg, $nolog) = @_;
3287 0 0       0 $nolog = 0 unless $nolog;
3288 0 0       0 return 0 if $nolog;
3289 0         0 _log_write_to_log( 'INFO', 0, $message, $extmsg);
3290 0         0 _log_write_to_screen( 'INFO', 0, $message, $extmsg);
3291 0         0 return 0;
3292             }
3293              
3294             sub log_debug {
3295             =begin wiki
3296              
3297             !3 log_debug
3298              
3299             Parameters: ( message )
3300              
3301             Call lower level logging functions using severity level DEBUG.
3302              
3303             Returns:
3304              
3305             =cut
3306 0     0 0 0 my ($message, $extmsg) = @_;
3307 0         0 _log_write_to_log( 'DEBUG', 0, $message, $extmsg);
3308 0         0 _log_write_to_screen( 'DEBUG', 0, $message, $extmsg);
3309 0         0 return 0;
3310             }
3311              
3312             sub log_close {
3313             =begin wiki
3314              
3315             !3 log_close
3316              
3317             Parameters: ( message )
3318              
3319             Close the currently open log file.
3320              
3321             Returns: 0
3322              
3323             =cut
3324 0     0 0 0 my ($message, $extmsg) = @_;
3325              
3326 0         0 _log_write_to_log( 'INFO', 0, $message, $extmsg);
3327 0         0 _log_write_to_screen( 'INFO', 0, $message, $extmsg);
3328 0         0 $sys_log_open = 0;
3329              
3330 0         0 return 0;
3331             }
3332              
3333             sub log_write_screen {
3334             =begin wiki
3335              
3336             !3 log_write_screen
3337              
3338             Parameters: ( p1, p2, p3 )
3339              
3340             Please write this documentation.
3341              
3342             Returns:
3343              
3344             =cut
3345 0     0 0 0 my $message = shift;
3346 0         0 _log_write_to_screen( 'INFO', 1, $message);
3347 0         0 return 0;
3348             }
3349              
3350             sub log_write_log {
3351             =begin wiki
3352              
3353             !3 log_write_log
3354              
3355             Parameters: ( p1, p2, p3 )
3356              
3357             Please write this documentation.
3358              
3359             Returns:
3360              
3361             =cut
3362 0     0 0 0 my $message = shift;
3363 0         0 _log_write_to_log( 'INFO', 1, $message);
3364 0         0 return 0;
3365             }
3366              
3367             =begin wiki
3368              
3369             !2 Database Functions
3370              
3371             These functions provide the database interface and data manipulation \
3372             capabilities.
3373              
3374             =cut
3375              
3376             sub db_init {
3377             =begin wiki
3378              
3379             !3 db_init
3380              
3381             Parameters: ( )
3382              
3383             User interface to settings used by the various db functions. Requested \
3384             settings are validated against those held in the db_func_parmas hash.
3385              
3386             Returns:
3387              
3388             =cut
3389 0     0 0 0 my ($id, %params) = @_;
3390 0 0       0 if ( ! defined $db_func_params{$id} ) {
3391 0         0 sys_die( "Param $id to db_init is invalid")
3392             }
3393 0         0 foreach my $key ( keys %params ) {
3394 0 0       0 if ( ! defined $db_func_params{$id}{$key} ) {
3395 0         0 sys_die( "Param $key to db_init is invalid" );
3396             }
3397 0         0 $db_func_params{$id}{$key} = $params{$key};
3398             }
3399 0         0 return 0;
3400             }
3401              
3402             sub db_connect {
3403             =begin wiki
3404              
3405             !3 db_connect
3406              
3407             Parameters: ( vdn )
3408              
3409             This function accepts a virtual database name and makes a connection to the \
3410             database resource identified by that name. The desired database instance has \
3411             already been determined and stored before this function is called.
3412              
3413             This function sets the DBI tracing mode so that we have a dbitrace.log file \
3414             with pertinent history in it. This file will get large, so it should be \
3415             rotated frequently. Contrary to what I've read, this does not supress \
3416             output to STDERR. It appears that this just forces DBI to write errors to \
3417             both STDERR and the dbitrace file. To fix that, this function redirects \
3418             STDERR to /dev/null. This is an ugly hack. So until I can figure out if I \
3419             read the docs wrong, or if DBI is just broken in this regard, I need to \
3420             leave this to prevent garbage output. It's garbage because I always check \
3421             and log DBI errors anyway.
3422              
3423             Returns:
3424              
3425             =cut
3426 0     0 0 0 my ($vdn, %connect_params) = @_;
3427 0         0 my ($starttime, $dbh, $instance);
3428              
3429             ## time increment is secs, action is either 'run' or 'fail'
3430 0   0     0 my $dependent_jobname = $connect_params{dependent_jobname} || '';
3431 0   0     0 my $wait_duration = $connect_params{wait_duration} || 60;
3432 0   0     0 my $wait_max_secs = $connect_params{wait_max_secs} || 60*60;
3433 0   0     0 my $wait_action = $connect_params{wait_action} || 'fail';
3434 0   0     0 my $retry_duration = $connect_params{retry_duration} || 0;
3435 0   0     0 my $retry_max_secs = $connect_params{retry_max_secs} || 0;
3436              
3437 0 0       0 if ( $vdn =~ m/:/x ) { ## vdn contains instance definiton
3438 0         0 my ($db, $inst) = split m/:/, $vdn;
3439 0 0       0 _check_array_val( $db, \@databases )
3440             || sys_die( "Invalid database: [$db]", 0 );
3441 0 0       0 _check_array_val( $inst, [split m/,/, $dbinst{$db}] )
3442             || sys_die( "Invalid database instance: [$db.$inst]", 0 );
3443 0         0 $dbdefenvr{$db} = $inst; ## update default connection data
3444 0         0 $vdn = $db; ## vdn gets true vdn
3445             }
3446              
3447             ## check for dependent job
3448             _db_connect_check_dependent(
3449 0         0 $dependent_jobname, $wait_duration, $wait_max_secs, $wait_action
3450             );
3451              
3452             ## get database parameters
3453 0         0 my ($db, $un, $pw) = _db_vdn('connect', $vdn);
3454 0         0 DBI->trace( 1, $dbitrace_filefull );
3455 0 0       0 open STDERR, '>', '/dev/null' unless $opt_very_verbose;
3456              
3457             ## connect with retry
3458 0         0 $dbh = _db_connect_retry(
3459             $db, $un, $pw, $retry_duration, $retry_max_secs
3460             );
3461              
3462             ## connection established
3463 0         0 $dbhandles{$vdn}{'dbh'} = $dbh; ## store handle for cleanup on exit
3464              
3465 0         0 db_nil( $vdn );
3466 0         0 return 0;
3467             }
3468              
3469             sub db_nil {
3470             =begin wiki
3471              
3472             !3 db_nil
3473              
3474             Parameters: ( )
3475              
3476             This is just a convenience function. When running in test mode, this will \
3477             call the internal C<_db_vdn> to function for force closure of all database \
3478             connections immediately.
3479              
3480             Returns:
3481              
3482             =cut
3483 0     0 0 0 my $vdn = shift;
3484 0         0 my ($dbh, $sth) = _db_vdn( 'nil', $vdn);
3485 0         0 return 0;
3486             }
3487              
3488             sub db_disconnect {
3489             =begin wiki
3490              
3491             !3 db_disconnect
3492              
3493             Parameters: ( vdn )
3494              
3495             Accept a virtual database name and disconnect from the datatabase specified \
3496             by the virtual database name.
3497              
3498             Returns:
3499              
3500             =cut
3501 0     0 0 0 my $vdn = shift;
3502 0         0 my ($dbh, $sth) = _db_vdn( 'disconnect', $vdn);
3503              
3504 0 0       0 if ( $dbh ) {
3505 0         0 $dbh->disconnect;
3506 0 0       0 if ( DBI->errstr ) {
3507 0         0 log_warn( DBI->errstr );
3508 0         0 return 1;
3509             }
3510             }
3511 0         0 $dbhandles{$vdn}{'dbh'} = 0;
3512 0         0 return 0;
3513             }
3514              
3515             sub db_finish {
3516             =begin wiki
3517              
3518             !3 db_finish
3519              
3520             Parameters: ( vdn )
3521              
3522             Accept a virtual database name and close the current statement handle for \
3523             the database specified by the virtual database name.
3524              
3525             Returns:
3526              
3527             =cut
3528 0     0 0 0 my $vdn = shift;
3529 0         0 my ($dbh, $sth) = _db_vdn( 'finish', $vdn);
3530              
3531 0 0       0 if ( $sth ) {
3532 0         0 $sth->finish;
3533 0 0       0 if ( DBI->errstr ) {
3534 0         0 log_warn( DBI->errstr );
3535 0         0 return 1;
3536             }
3537             }
3538 0         0 $dbhandles{$vdn}{'sth'} = 0;
3539 0         0 return 0;
3540             }
3541              
3542             sub db_prepare {
3543             =begin wiki
3544              
3545             !3 db_prepare
3546              
3547             Parameters: ( vdn, sql_query )
3548              
3549             Accept a virtual database name and an sql query and prepares the query for \
3550             database processing. This function stores the resulting statement handle for \
3551             subsequent access under the via the virtual database name.
3552              
3553             Returns:
3554              
3555             =cut
3556 0     0 0 0 my ($vdn, $sql, $longrlen) = @_;
3557 0 0       0 $longrlen = 0 unless $longrlen;
3558 0         0 my $sth_name = 'sth_default'; ## default statement handle name
3559 0 0       0 if ( $vdn =~ m/\./x ) {
3560 0         0 ($vdn, $sth_name) = split m/\./x, $vdn;
3561 0 0       0 if ( $sth_name eq 'sth_default' ) {
3562 0         0 sys_die( 'Invalid statement handle name', 0 );
3563             }
3564             }
3565              
3566 0         0 my ($dbh, $sth) = _db_vdn('prepare', $vdn);
3567              
3568 0 0       0 if ( $longrlen > 0 ) { $dbh->{LongReadLen} = $longrlen; }
  0         0  
3569              
3570 0 0       0 $sth = $dbh->prepare( $sql )
3571             or sys_die( $dbh->errstr );
3572              
3573             ## store statement handle for this vdn
3574 0         0 $dbhandles{$vdn}{$sth_name} = $sth;
3575              
3576 0         0 return 0;
3577             }
3578              
3579             sub db_truncate {
3580             =begin wiki
3581              
3582             !3 db_truncate
3583              
3584             Parameters: ( vdn, table_name )
3585              
3586             Accept a virtual database name and a table name. Truncate the specified \
3587             table. This function returns number of rows truncated.
3588              
3589             Returns:
3590              
3591             =cut
3592 0     0 0 0 my ($vdn, $table_name) = @_;
3593 0         0 my ($dbh, $sth) = _db_vdn('truncate', $vdn);
3594              
3595 0         0 my $sql = "truncate table $table_name";
3596 0 0       0 $dbh->do( $sql )
3597             or sys_die( DBI->errstr );
3598              
3599 0         0 return 0;
3600             }
3601              
3602             sub db_execute {
3603             =begin wiki
3604              
3605             !3 db_execute
3606              
3607             Parameters: ( vdn, sql_substitution_paramaters )
3608              
3609             Accept a virtual database name and sql substitution parameters. Execute \
3610             the query against the stored statement handle associated with the supplied \
3611             virtual database name. The statement handle needs to be prepard before this \
3612             function is called.
3613              
3614             Returns:
3615              
3616             =cut
3617 0     0 0 0 my ($vdn, @params) = @_;
3618 0         0 my ($dbh, $sth) = _db_vdn('execute', $vdn);
3619              
3620 0 0       0 $sth->execute( @params )
3621             or sys_die( $sth->errstr );
3622              
3623 0         0 return 0;
3624             }
3625              
3626             sub db_get_sth {
3627             =begin wiki
3628              
3629             !3 db_get_sth
3630              
3631             Parameters: ( p1, p2, p3 )
3632              
3633             Please write this documentation.
3634              
3635             Returns:
3636              
3637             =cut
3638 0     0 0 0 my $vdn = shift;
3639 0         0 my $sth_name = 'sth_default'; ## default statement handle name
3640 0 0       0 if ( $vdn =~ m/\./x ) {
3641 0         0 ($vdn, $sth_name) = split m/\./x, $vdn;
3642             }
3643 0         0 return $dbhandles{$vdn}{$sth_name};
3644             }
3645              
3646             sub db_get_defenvr {
3647             =begin wiki
3648              
3649             !3 db_get_defenvr
3650              
3651             Parameters: ( p1, p2, p3 )
3652              
3653             Please write this documentation.
3654              
3655             Returns:
3656              
3657             =cut
3658 0     0 0 0 my $vdn = shift;
3659              
3660 0 0       0 if ( $dbdefenvr{$vdn} ) {
3661 0         0 return $dbdefenvr{$vdn};
3662             }
3663              
3664 0         0 return '';
3665             }
3666              
3667             sub db_bindcols {
3668             =begin wiki
3669              
3670             !3 db_bindcols
3671              
3672             Parameters: ( p1, p2, p3 )
3673              
3674             Please write this documentation.
3675              
3676             Returns:
3677              
3678             =cut
3679             #
3680             # interface:
3681             # interface to sth->bind_columns()
3682             #
3683             # accepts:
3684             # 1st position
3685             # a raw statement handle
3686             # a vdn which is used to obtain a default statment handle (one per vdn)
3687             # a vdn, named statement handle pair in the form vdn||nsth
3688             # remaining
3689             # any number of references to scalars
3690             #
3691             # returns:
3692             # 0 = success
3693             # errors handled internally
3694             #
3695 0     0 0 0 my ($vdn,@colrefs) = @_;
3696 0         0 my $sth;
3697 0 0       0 if ( ref $vdn ) {
3698 0         0 $sth = $vdn; ## received a raw sth
3699             } else {
3700 0         0 my $sth_name = 'sth_default'; ## default statement handle name
3701 0 0       0 if ( $vdn =~ m/\./x ) { ## dot notation vdn.sthn
3702 0         0 ($vdn, $sth_name) = split m/\./x, $vdn;
3703             }
3704 0         0 $sth = $dbhandles{$vdn}{$sth_name};
3705             }
3706 0         0 foreach my $colref ( @colrefs ) {
3707 0 0       0 if ( ! ref $colref ) { sys_die( "Received bad ref in db_bindcols" ); }
  0         0  
3708             }
3709 0         0 $sth->bind_columns( @colrefs );
3710 0         0 return 0;
3711             }
3712              
3713             sub db_pef {
3714             =begin wiki
3715              
3716             !3 db_pef
3717              
3718             Parameters: ( )
3719              
3720             Prepare, Execute, Fetch a scalar value
3721              
3722             This function always returns the first element of the first row of the
3723             result set.
3724              
3725             Returns:
3726              
3727             =cut
3728 0     0 0 0 my ($vdn, $sqlname, @params) = @_;
3729              
3730 0         0 my $sql = sys_get_sql( $sqlname );
3731 0         0 db_prepare( $vdn, $sql );
3732 0         0 db_execute( $vdn, @params );
3733 0         0 my $row = db_fetchrow( $vdn );
3734              
3735 0         0 return @{$row}[0];
  0         0  
3736             }
3737              
3738             sub db_pef_list {
3739             =begin wiki
3740              
3741             !3 db_pef_list
3742              
3743             Parameters: ( )
3744              
3745             Prepare, Execute, Fetch a result set as a list of scalars
3746              
3747             This function returns a list of the first element from each row of the \
3748             result set.
3749              
3750             Returns:
3751              
3752             =cut
3753 0     0 0 0 my ($vdn, $sqlname, @params) = @_;
3754 0         0 my @rsalist;
3755              
3756 0         0 my $sql = sys_get_sql( $sqlname );
3757 0         0 db_prepare( $vdn, $sql );
3758 0         0 db_execute( $vdn, @params );
3759 0         0 while ( my $row = db_fetchrow( $vdn ) ) {
3760 0         0 push @rsalist, @{$row}[0];
  0         0  
3761             }
3762              
3763 0         0 return \@rsalist; ## return result set asa list
3764             }
3765              
3766             sub db_fetchrow {
3767             =begin wiki
3768              
3769             !3 db_fetchrow
3770              
3771             Parameters: ( p1, p2, p3 )
3772              
3773             Please write this documentation.
3774              
3775             Returns:
3776              
3777             =cut
3778             #
3779             # interface:
3780             # interface to sth->fetchrow_arrayref()
3781             #
3782             # accepts:
3783             # a raw statement handle
3784             # a vdn which is used to obtain a default statment handle (one per vdn)
3785             # a vdn, named statement handle pair in the form vdn||nsth
3786             #
3787             # note:
3788             # If you are going to make lots of calls to db_fetchrow for the
3789             # same execute cycle, you will get better performance using a raw
3790             # statement handle over a statement handle name
3791             #
3792             # returns:
3793             # reference to an array
3794             #
3795 0     0 0 0 my $vdn = shift;
3796 0         0 my $sth;
3797 0 0       0 if ( ref $vdn ) {
3798 0         0 $sth = $vdn; ## received a raw sth
3799             } else {
3800 0         0 my $sth_name = 'sth_default'; ## default statement handle name
3801 0 0       0 if ( $vdn =~ m/\./x ) {
3802 0         0 ($vdn, $sth_name) = split m/\./x, $vdn;
3803             }
3804 0         0 $sth = $dbhandles{$vdn}{$sth_name};
3805             }
3806 0         0 return $sth->fetchrow_arrayref();
3807             }
3808              
3809             sub db_commit {
3810             =begin wiki
3811              
3812             !3 db_commit
3813              
3814             Parameters: ( virtual_database_name )
3815              
3816             Accept a virtual database name and perform a commit against the specified \
3817             database connection.
3818              
3819             Returns:
3820              
3821             =cut
3822 0     0 0 0 my ($vdn) = shift;
3823 0         0 my ($dbh, $sth) = _db_vdn('commit', $vdn);
3824              
3825 0         0 $dbh->commit;
3826 0 0       0 if ( DBI->errstr ) {
3827 0         0 sys_die( DBI->errstr );
3828 0         0 return 1; ## test harness returns from sys_die
3829             }
3830 0         0 return 0;
3831             }
3832              
3833             sub db_rollback {
3834             =begin wiki
3835              
3836             !3 db_rollback
3837              
3838             Parameters: ( p1, p2, p3 )
3839              
3840             Please write this documentation.
3841              
3842             Returns:
3843              
3844             =cut
3845 0     0 0 0 my ($vdn) = shift;
3846 0         0 my ($dbh, $sth) = _db_vdn('rollback', $vdn);
3847              
3848 0         0 $dbh->rollback;
3849 0 0       0 if ( DBI->errstr ) {
3850 0         0 sys_die( DBI->errstr );
3851 0         0 return 1; ## test harness returns from sys_die
3852             }
3853 0         0 return 0;
3854             }
3855              
3856             sub db_rowcount_table {
3857             =begin wiki
3858              
3859             !3 db_rowcount_table
3860              
3861             Parameters: ( vdn, table_name )
3862              
3863             Accept a virtual database name and a tablename and using the table name, \
3864             do a select count(*) query against that table to get the current rowcount.
3865              
3866             Returns:
3867              
3868             =cut
3869 0     0 0 0 my ($vdn, $table_name) = @_;
3870 0         0 my ($dbh, $sth) = _db_vdn('rowcount_table', $vdn);
3871              
3872 0         0 my $sql = "select count(*) from $table_name";
3873 0         0 my $count = $dbh->selectrow_array( $sql );
3874 0         0 return $count;
3875             }
3876              
3877             sub db_rowcount_query {
3878             =begin wiki
3879              
3880             !3 db_rowcount_query
3881              
3882             Parameters: ( vdn, sql )
3883              
3884             Using a supplied query that does a select count(*), get a row count. This \
3885             function will accept optional params for the query.
3886              
3887             Returns:
3888              
3889             =cut
3890 0     0 0 0 my ($vdn, $sql, @params ) = @_;
3891 0         0 my ($dbh, $sth) = _db_vdn('rowcount_query', $vdn);
3892              
3893 0 0       0 if ( @params ) {
3894 0 0       0 my $tmp_sth = $dbh->prepare( $sql )
3895             or sys_die( $dbh->errstr );
3896 0 0       0 $tmp_sth->execute( @params )
3897             or sys_die( $sth->errstr );
3898 0         0 my @row = $tmp_sth->fetchrow_array();
3899 0         0 return $row[0];
3900             } else {
3901 0         0 my $count = $dbh->selectrow_array( $sql );
3902 0         0 return $count;
3903             }
3904             }
3905              
3906             sub db_sanity_check {
3907             =begin wiki
3908              
3909             !3 db_sanity_check
3910              
3911             Parameters: ( vdn, query_name, notify )
3912              
3913             /vdn/ - virtual database name
3914             /query_name/ - name of query in job conf file
3915             /notify/ - send notification on warning
3916              
3917             Verify that table contents are within acceptable range limits for a given \
3918             column value.
3919              
3920             This function utilizes information stored in the current job conf file. The \
3921             query executed to perform each range limit test is passed as a parameter in \
3922             /query_name/. That query is executed for each test stored in the \
3923             "checkpoints" array in conf section "thereshold" in the job conf file.
3924              
3925             A checkpoints array should be defined for each database environment. This \
3926             function will look for a checkpoints by database environment by combining \
3927             the name of the current database environment with the liter string \
3928             "checkpoints". If you have four database environments, you should have \
3929             four checkpoint entries in your job conf file. The name of the current \
3930             database environment is determined using the function sys_get_dataenvr().
3931              
3932             Once the range limit query and all of the checkpoint values have been \
3933             obtained, the parameter vdn is used to execute the range limit query.
3934              
3935             Each checkpoint entry takes the form:
3936              
3937             COLUMN_VALUE = count:percent_deviation
3938              
3939             The range limit query will be executed for each COLUMN_VALUE entry. The \
3940             actual count returned will be compared to the checkpoint count, if the \
3941             count returned is within the percent range specified by the checkpoint \
3942             percent_deviation, the test will pass, otherwise the test will fail and a \
3943             log warning will be generated.
3944              
3945             A percent_deviation of 0 (zero) represents a special case. If a \
3946             percent_deviation of 0 is used, this instructs db_sanity_check to accept \
3947             any positive value for count as a valid value. Typically, this behavior \
3948             would be invoked by using a column value entry of "1:0".
3949              
3950             An expected value of 0 (zero) represents a special case as well. When the \
3951             expected value is 0, checking for that column value will be bypassed. In \
3952             this way you can "turn off" sanity checking for an entire database \
3953             environment by making all of the column value entries equal to "0:0".
3954              
3955             If the /notify/ parameter is set, a notification will be sent in addition \
3956             to a log warning.
3957              
3958             Returns:
3959              
3960             =cut
3961 0     0 0 0 my ($vdn, $query_name, $notify) = @_;
3962 0 0       0 $notify = 0 unless $notify;
3963              
3964 0         0 my $warnings = 0;
3965 0         0 my $lead = "Sanity check:";
3966 0         0 my $okay = " Ok ";
3967 0         0 my $outofbounds = " Out Of Bounds ";
3968 0         0 my $disabled = " Disabled ";
3969              
3970             ## get checkpoints
3971 0         0 my $checkpoints;
3972 0         0 my $conf_entry = sys_get_dataenvr . '_checkpoints';
3973 0 0       0 if ( $conf_job{threshold}{$conf_entry} ) {
3974 0         0 $checkpoints = $conf_job{threshold}{$conf_entry};
3975             } else {
3976 0         0 log_warn( "No threshold checkpoints found in job conf for: $conf_entry" );
3977 0         0 return 1;
3978             }
3979              
3980             ## prepare range limit query
3981 0         0 my $query = sys_get_sql( $query_name );
3982 0         0 db_prepare( $vdn, $query );
3983              
3984 0         0 log_info( "$lead Status [Test] Expected/Actual/Threshold(%)/Threshold(#)" );
3985              
3986             ## perform checkpoint tests
3987 0         0 foreach my $chkpt ( split "\n", $checkpoints ) {
3988 0         0 my ($param,$rest) = split m/=/, $chkpt;
3989 0         0 my ($exp,$range) = split m/:/, $rest;
3990 0         0 $param = _trim($param); ## col to check
3991 0         0 $exp = _trim($exp); ## expected value
3992 0         0 $range = _trim($range); ## range/tolerance
3993              
3994 0         0 db_execute( $vdn, $param );
3995 0         0 my $row = db_fetchrow( $vdn );
3996 0         0 my $act = @{$row}[0]; ## actual value
  0         0  
3997 0         0 my $dev = int $exp * ( $range / 100 ); ## deviation as a percent
3998              
3999 0         0 my $status = "[$param] $exp/$act/$range/$dev ";
4000              
4001 0 0       0 if ( $exp == 0 ) { ## checking has been disabled
4002 0         0 log_info( $lead . $disabled . $status );
4003 0         0 next;
4004             }
4005              
4006 0 0       0 if ( $range == 0 ) { ## any positive value for actual is acceptable
4007 0 0       0 if ( $act > 0 ) {
4008 0         0 log_info( $lead . $okay . $status );
4009 0         0 next;
4010             }
4011 0         0 $warnings++;
4012 0         0 log_info( $lead . $outofbounds . $status );
4013 0         0 next;
4014             }
4015              
4016 0 0       0 if ( $act < $exp ) { ## actual is below threshold
4017 0 0       0 if ( $act < $exp - $dev ) {
4018 0         0 log_info( $lead . $outofbounds . $status );
4019 0         0 $warnings++;
4020 0         0 next;
4021             }
4022             }
4023              
4024 0 0       0 if ( $act > $exp ) { ## actual is above threshold
4025 0 0       0 if ( $act > $exp + $dev ) {
4026 0         0 log_info( $lead . $outofbounds . $status );
4027 0         0 $warnings++;
4028 0         0 next;
4029             }
4030             }
4031              
4032 0         0 log_info( $lead . $okay . $status );
4033             }
4034              
4035             ## send out notifications if there are warnings
4036 0 0 0     0 if ( $warnings && $notify ) {
4037 0         0 _log_send_notifications( "WARN", 1, "Sanity check threshold exceeded" );
4038             }
4039              
4040 0         0 return 0;
4041             }
4042              
4043             sub db_drop_index {
4044             =begin wiki
4045              
4046             !3 db_drop_index
4047              
4048             Parameters: ( vdn, index_name )
4049              
4050             Accept a virtual database name and an index name. Drop the index identified \
4051             by index name. If there was a database error, we check last error. If the \
4052             last error indicates that the index we are trying to drop did not exist, \
4053             then the error is ignored, otherwise the error is logged.
4054              
4055             Returns:
4056              
4057             =cut
4058 0     0 0 0 my ($vdn, $index_name) = @_;
4059 0         0 my ($dbh, $sth) = _db_vdn('drop_index', $vdn);
4060              
4061 0 0       0 my $tmp_sth = $dbh->prepare("drop index $index_name")
4062             or sys_die( DBI->errstr );
4063              
4064              
4065 0         0 $tmp_sth->execute;
4066 0 0 0     0 if ( DBI->err && DBI->err != 1418 ) { ## ORA-00942: specified index does not exist
4067 0         0 sys_die( DBI->errstr );
4068             }
4069              
4070 0         0 return 0;
4071             }
4072              
4073             sub db_drop_table {
4074             =begin wiki
4075              
4076             !3 db_drop_table
4077              
4078             Parameters: ( vdn, table_name )
4079              
4080             Accept a virtual database name and a table name. Drop the table identified \
4081             by table name. If there was a database error, we check last error. If the \
4082             last error indicates that the table we are trying to drop did not exist, \
4083             then the error is ignored, otherwise the error is logged.
4084              
4085             Returns:
4086              
4087             =cut
4088 0     0 0 0 my ($vdn, $table_name) = @_;
4089 0         0 my ($dbh, $sth) = _db_vdn('drop_table', $vdn);
4090              
4091 0 0       0 my $tmp_sth = $dbh->prepare("drop table $table_name" )
4092             or sys_die( DBI->errstr );
4093              
4094 0         0 $tmp_sth->execute;
4095 0 0 0     0 if ( DBI->err && DBI->err != 942 ) { ## ORA-00942: specified table does not exist
4096 0         0 sys_die( DBI->errstr );
4097             }
4098 0         0 $tmp_sth->finish;
4099 0         0 return 0;
4100             }
4101              
4102             sub db_drop_procedure {
4103             =begin wiki
4104              
4105             !3 db_drop_procedure
4106              
4107             Parameters: ( vdn, procedure_name )
4108              
4109             Accept a virtual database name and a procedure name. Drop the procedure \
4110             identified by the given name. Check the last error, if it indicates the \
4111             procedure did not exist, then the error is ignored, otherwise the error is \
4112             logged.
4113              
4114             Returns:
4115              
4116             =cut
4117 0     0 0 0 my ($vdn, $procedure_name) = @_;
4118 0         0 my ($dbh, $sth) = _db_vdn('drop_procedure', $vdn);
4119              
4120 0 0       0 my $tmp_sth = $dbh->prepare("drop procedure $procedure_name")
4121             or sys_die( DBI->errstr );
4122              
4123 0         0 $tmp_sth->execute;
4124 0 0 0     0 if ( DBI->err && DBI->err != 4043 ) { ## ORA-04043: object does not exist
4125 0         0 sys_die( DBI->errstr );
4126             }
4127 0         0 $tmp_sth->finish;
4128 0         0 return 0;
4129             }
4130              
4131             sub db_drop_function {
4132             =begin wiki
4133              
4134             !3 db_drop_function
4135              
4136             Parameters: ( $vdn, $function_name )
4137              
4138             Accept a virtual database name and a function name. Drop the function \
4139             identified by the given name. Check the last error, if it indicates the \
4140             function did not exist, then the error is ignored, otherwise the error is \
4141             logged.
4142              
4143             Returns:
4144              
4145             =cut
4146 0     0 0 0 my ($vdn, $function_name) = @_;
4147 0         0 my ($dbh, $sth) = _db_vdn('drop_function', $vdn);
4148              
4149 0 0       0 my $tmp_sth = $dbh->prepare("drop function $function_name")
4150             or sys_die( DBI->errstr );
4151              
4152 0         0 $tmp_sth->execute;
4153 0 0 0     0 if ( DBI->err && DBI->err != 4043 ) { ## ORA-04043: object does not exist
4154 0         0 sys_die( DBI->errstr );
4155             }
4156 0         0 $tmp_sth->finish;
4157 0         0 return 0;
4158             }
4159              
4160             sub db_drop_package {
4161             =begin wiki
4162              
4163             !3 db_drop_package
4164              
4165             Parameters: ( vdn, package_name )
4166              
4167             Accept a virtual database name and a package name. Drop the package \
4168             identified by the given name. Check the last error, if it indicates \
4169             that the the package we are trying to drop did not exist, then the error \
4170             is ignored, otherwise the error is logged.
4171              
4172             Returns:
4173              
4174             =cut
4175 0     0 0 0 my ($vdn, $package_name) = @_;
4176 0         0 my ($dbh, $sth) = _db_vdn('drop_package', $vdn);
4177              
4178 0 0       0 my $tmp_sth = $dbh->prepare("drop package $package_name")
4179             or sys_die( DBI->errstr );
4180              
4181 0         0 $tmp_sth->execute;
4182 0 0 0     0 if ( DBI->err && DBI->err != 4043 ) { ## ORA-04043: object does not exist
4183 0         0 sys_die( DBI->errstr );
4184             }
4185 0         0 $tmp_sth->finish;
4186 0         0 return 0;
4187             }
4188              
4189             sub db_rename_index {
4190             =begin wiki
4191              
4192             !3 db_rename_index
4193              
4194             Parameters: ( vdn, oldndxname, newndxname )
4195              
4196             Please write the documentation.
4197              
4198             Returns:
4199              
4200             =cut
4201 0     0 0 0 my ($vdn, $oldname, $newname) = @_;
4202 0         0 my ($dbh, $sth) = _db_vdn('rename_index', $vdn);
4203              
4204 0 0       0 my $tmp_sth = $dbh->prepare("alter index $oldname rename to $newname")
4205             or sys_die( DBI->errstr );
4206              
4207 0         0 $tmp_sth->execute;
4208 0 0       0 if ( DBI->err ) {
4209 0         0 sys_die( DBI->errstr );
4210             }
4211              
4212 0         0 return 0;
4213             }
4214              
4215             sub db_rename_table {
4216             =begin wiki
4217              
4218             !3 db_rename_table
4219              
4220             Parameters: ( vdn, oldtabname, newtabname )
4221              
4222             Please write this documentation.
4223              
4224             Returns:
4225              
4226             =cut
4227 0     0 0 0 my ($vdn, $oldname, $newname) = @_;
4228 0         0 my ($dbh, $sth) = _db_vdn('rename_table', $vdn);
4229              
4230 0 0       0 my $tmp_sth = $dbh->prepare("alter table $oldname rename to $newname" )
4231             or sys_die( DBI->errstr );
4232              
4233 0         0 $tmp_sth->execute;
4234 0 0       0 if ( DBI->err ) {
4235 0         0 sys_die( DBI->errstr );
4236             }
4237 0         0 $tmp_sth->finish;
4238 0         0 return 0;
4239             }
4240              
4241             sub db_purge_table {
4242             =begin wiki
4243              
4244             !3 db_purge_table
4245              
4246             Parameters: ( vdn, table_name )
4247              
4248             Please write this documentations.
4249              
4250             Returns:
4251              
4252             =cut
4253 0     0 0 0 my ($vdn, $table_name) = @_;
4254 0         0 my ($dbh, $sth) = _db_vdn('purge_table', $vdn);
4255              
4256 0 0       0 my $tmp_sth = $dbh->prepare("purge table $table_name" )
4257             or sys_die( DBI->errstr );
4258              
4259 0         0 $tmp_sth->execute;
4260 0 0 0     0 if ( DBI->err && DBI->err != 38307 ) { ## ORA-38307: object not in recycle bin
4261 0         0 sys_die( DBI->errstr );
4262             }
4263 0         0 $tmp_sth->finish;
4264 0         0 return 0;
4265             }
4266              
4267             sub db_purge_index {
4268             =begin wiki
4269              
4270             !3 db_purge_index
4271              
4272             Parameters: ( vdn, index_name )
4273              
4274             Please write this documentation.
4275              
4276             Returns:
4277              
4278             =cut
4279 0     0 0 0 my ($vdn, $table_name) = @_;
4280 0         0 my ($dbh, $sth) = _db_vdn('purge_index', $vdn);
4281              
4282 0 0       0 my $tmp_sth = $dbh->prepare("purge index $table_name")
4283             or sys_die( DBI->errstr );
4284              
4285 0         0 $tmp_sth->execute;
4286 0 0 0     0 if ( DBI->err && DBI->err != 38307 ) { ## ORA-38307: object not in recycle bin
4287 0         0 sys_die( DBI->errstr );
4288             }
4289              
4290 0         0 return 0;
4291             }
4292              
4293             sub db_grant {
4294             =begin wiki
4295              
4296             !3 db_grant
4297              
4298             Parameters: ( p1, p2, p3 )
4299              
4300             Please write this documentation.
4301              
4302             Returns:
4303              
4304             =cut
4305 0     0 0 0 my ($vdn, $priv, $objname, $ag) = @_;
4306 0         0 my ($dbh, $sth) = _db_vdn('grant', $vdn);
4307              
4308 0 0       0 unless ( $priv =~ m/^r$|^u$/x ) {
4309 0         0 log_warn( "Privilege to db_grant must be either 'r' or 'u'" );
4310 0         0 return 1;
4311             }
4312 0         0 my $sql;
4313 0 0       0 if ( $priv eq 'r' ) {
4314 0         0 $sql = qq{begin execute immediate 'grant select on $objname to $ag'; end;};
4315             }
4316 0 0       0 if ( $priv eq 'u' ) {
4317 0         0 $sql = qq{begin execute immediate 'grant update, insert, delete on $objname to $ag'; end;};
4318             }
4319              
4320 0 0       0 my $tmp_sth = $dbh->prepare( $sql )
4321             or sys_die( DBI->errstr );
4322 0 0       0 $tmp_sth->execute
4323             or sys_die( DBI->errstr );
4324 0         0 $tmp_sth->finish;
4325 0         0 return 0;
4326             }
4327              
4328             sub db_update_statistics {
4329             =begin wiki
4330              
4331             !3 db_update_statistics
4332              
4333             Parameters: ( vdn, table_name )
4334              
4335             Please write this documentation.
4336              
4337             Returns:
4338              
4339             =cut
4340 0     0 0 0 my ($vdn, $table_name) = @_;
4341 0         0 my ($dbh, $sth) = _db_vdn('update_statistics', $vdn);
4342              
4343 0 0       0 unless ( _db_is_oracle($vdn) ) {
4344 0         0 sys_die( 'Not an Oracle database connection in db_update_statistics', 0 );
4345             }
4346              
4347 0         0 my $sql = "BEGIN dbms_stats.gather_table_stats('','"
4348             . "$table_name',NULL,NULL,FALSE,'FOR ALL COLUMNS SIZE 1'"
4349             . ",NULL,'DEFAULT',TRUE); END;";
4350              
4351 0         0 my $tmp_sth = $dbh->prepare( $sql );
4352 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
4353 0         0 $tmp_sth->execute;
4354 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
4355 0         0 $tmp_sth->finish;
4356 0         0 return 0;
4357             }
4358              
4359             sub db_insert_from_file {
4360             =begin wiki
4361              
4362             !3 db_insert_from_file
4363              
4364             Parameters: ( vdn, file_name, delim )
4365              
4366             * /vdn/ - Virtual Database Name
4367             * /file_name/ - File containing data to read
4368             * /delim/ - Field delimiter (can be a regex)
4369              
4370             Accept a virtual database name, file name, and field delimiter. Insert records \
4371             from specified file into the database table using the statement handle tied \
4372             to the virtual database name. The file name should include full path \
4373             information.
4374              
4375             It is desireable to call db_init before using this function. There are several \
4376             advanced options implemented by this function that can be configured by call \
4377             db_init first.
4378              
4379             By default the field delimiter is not interpreted as a Regular Expression, \
4380             however by calling db_init first, you can make this function treat your \
4381             delimiter as a regex, in that case the delimiter can be more than one \
4382             character in length.
4383              
4384             SQL used by this function should be prepared before calling this function.
4385              
4386             Returns:
4387              
4388             =cut
4389 0     0 0 0 my ($vdn, $file_name, $delim) = @_;
4390 0         0 my ($dbh, $sth) = _db_vdn('insert_from_file', $vdn);
4391              
4392 0         0 my $id = 'db_insert_from_file';
4393 0         0 my $TrimLead = _is_yes($db_func_params{$id}{'TrimLead'});
4394 0         0 my $TrimFieldLead = _is_yes($db_func_params{$id}{'TrimFieldLead'});
4395 0         0 my $TrimFieldTrail = _is_yes($db_func_params{$id}{'TrimFieldTrail'});
4396 0         0 my $SkipComments = _is_yes($db_func_params{$id}{'SkipComments'});
4397 0         0 my $SkipLastField = _is_yes($db_func_params{$id}{'SkipLastField'});
4398 0         0 my $UseRegex = _is_yes($db_func_params{$id}{'UseRegex'});
4399 0         0 my $CommentChar = $db_func_params{$id}{'CommentChar'};
4400              
4401 0         0 my ($count, @row);
4402 0 0       0 open my $fh, "<", $file_name or sys_die( "Error opening $file_name" );
4403              
4404 0         0 my $regex = "\Q$delim\E"; # escape regex meta chars
4405 0 0       0 if ( $UseRegex ) {
4406 0         0 $regex = $delim; # do escaping meta chars
4407             }
4408              
4409 0         0 while ( <$fh> ) {
4410 0         0 my $line = $_;
4411 0         0 chomp $line;
4412 0 0       0 if ( $TrimLead ) {
4413 0         0 $line = _trim_lead($line);
4414             }
4415 0 0       0 if ( $SkipComments ) {
4416 0 0       0 if ( substr($line,0,1) eq $CommentChar ) { next; }
  0         0  
4417             }
4418              
4419 0         0 @row = split($regex,$line,-1); # -1 preserves trailing null fields
4420              
4421 0 0       0 if ( $SkipLastField ){
4422 0         0 pop @row;
4423             }
4424 0 0       0 if ( $TrimFieldLead ) {
4425 0         0 for (my $i=0;$i<@row;$i++) {
4426 0         0 $row[$i]=_trim_lead($row[$i]);
4427             }
4428             }
4429 0 0       0 if ( $TrimFieldTrail ) {
4430 0         0 for (my $i=0;$i<@row;$i++) {
4431 0         0 $row[$i]=_trim_trail($row[$i]);
4432             }
4433             }
4434              
4435 0         0 $sth->execute( @row );
4436 0 0       0 if ( DBI->errstr ) {
4437 0         0 print DBI->errstr;
4438 0         0 log_warn( DBI->errstr );
4439 0         0 my $errrec = 'RECORD: ' . join "~", @row;
4440 0         0 log_warn( $errrec );
4441 0         0 sys_die( 'Aborting' );
4442             }
4443 0         0 $count++;
4444             }
4445              
4446 0         0 db_commit( $vdn );
4447 0 0       0 close $fh or sys_die( "Error closing $file_name" );
4448              
4449 0         0 return $count;
4450             }
4451              
4452             sub db_insert_from_query {
4453             =begin wiki
4454              
4455             !3 db_insert_from_query
4456              
4457             Parameters: ( source_vdn, target_vdn )
4458              
4459             Accept a virtual database name for a source and target databases and insert \
4460             rows into the target database from the source database.
4461              
4462             Note: This needs to be rewritten to use fetchrow_arrayref() instead for \
4463             better performance.
4464              
4465             Returns:
4466              
4467             =cut
4468 0     0 0 0 my ($src_vdn, $des_vdn, $plugin) = @_;
4469 0 0       0 $plugin = 0 unless $plugin;
4470              
4471             ## set up array of plugins
4472 0         0 my @plugins;
4473 0 0       0 if ( ref $plugin eq 'ARRAY' ) {
4474 0         0 @plugins = map { $_ } @{$plugin}; ## copy plugin list to plugin array
  0         0  
  0         0  
4475             } else {
4476 0         0 push @plugins, $plugin; ## copy single plugin entry to plugin array
4477             }
4478              
4479 0         0 my ($src_dbh, $src_sth) = _db_vdn('insert_from_query', $src_vdn);
4480 0         0 my ($des_dbh, $des_sth) = _db_vdn('insert_from_query', $des_vdn);
4481              
4482 0         0 my $count = 0;
4483 0         0 while ( my $row = $src_sth->fetchrow_arrayref() ) { ## fetch insert loop
4484 0         0 my @tmprow = @{$row};
  0         0  
4485              
4486 0         0 my $plugin_result = 0;
4487 0         0 foreach my $plugin ( @plugins ) { ## call each plugin
4488 0 0       0 my $result = $plugin->( \@tmprow ) if $plugin;
4489 0 0       0 if ( $result > 1000 ) { $plugin_result = 1; } ## plugin bad return
  0         0  
4490             }
4491 0 0       0 next if $plugin_result; ## if any plugin complains, skip the record
4492              
4493 0         0 $des_sth->execute( @tmprow );
4494 0 0       0 if ( DBI->errstr ) {
4495 0         0 log_warn( DBI->errstr );
4496 0         0 my $errrec = 'RECORD: ' . join "~", @{$row};
  0         0  
4497 0         0 log_warn( $errrec );
4498 0         0 sys_die( 'Aborting' );
4499             }
4500 0         0 $count++;
4501             }
4502 0         0 return $count;
4503             }
4504              
4505             sub db_query_to_file {
4506             =begin wiki
4507              
4508             !3 db_query_to_file
4509              
4510             Parameters: ( vdn, file_name, delim )
4511              
4512             Accept a virtual database name and a file name and write the result set to \
4513             the requested file. This function should be passed a file name that includes \
4514             full path information. The specified delimiter is used as a field separator \
4515             when writing the result set to the file.
4516              
4517             Plugins
4518              
4519             Plugins can be called for each row returned in the record set. Plugins can \
4520             return a value, any value returned that is greater than 1000 will cause the \
4521             current record to be skiped rather than written to the output file.
4522              
4523             Returns:
4524              
4525             =cut
4526 0     0 0 0 my ($vdn, $file_name, $delim, $append, $plugin, $protect) = @_;
4527 0 0       0 $delim = '~' unless $delim;
4528 0 0       0 $append = 0 unless $append;
4529 0 0       0 $plugin = 0 unless $plugin; ## unblessed ref to a plugin or ref to array
4530 0 0       0 $protect = 0 unless $protect; ## ref to array of cols to protect
4531              
4532             ## set up array of plugins
4533 0         0 my @plugins;
4534 0 0       0 if ( ref $plugin eq 'ARRAY' ) {
4535 0         0 @plugins = map { $_ } @{$plugin}; ## copy plugin list to plugin array
  0         0  
  0         0  
4536             } else {
4537 0         0 push @plugins, $plugin; ## copy single plugin entry to plugin array
4538             }
4539              
4540 0         0 my ($dbh, $sth) = _db_vdn('query_to_file', $vdn);
4541              
4542 0         0 my $mode;
4543 0 0       0 if ( $append ) {
4544 0         0 $mode = '>>';
4545             } else {
4546 0         0 $mode = '>';
4547             }
4548              
4549 0         0 my $count = 0;
4550 0 0       0 open my $fh, $mode, $file_name or sys_die( "Error opening $file_name" );
4551 0         0 while ( my $row = $sth->fetchrow_arrayref() ) {
4552 0         0 my @outrow = @{$row};
  0         0  
4553              
4554 0         0 my $plugin_result = 0;
4555 0         0 foreach my $plugin ( @plugins ) { ## call each plugin in turn
4556 0 0       0 my $result = $plugin->( \@outrow ) if $plugin;
4557 0 0       0 if ( $result > 1000 ) { $plugin_result = 1; } ## bypass this record
  0         0  
4558             }
4559 0 0       0 next if $plugin_result;
4560              
4561 0 0       0 _db_query_to_file_protect( \@outrow, $protect ) if $protect;
4562 0         0 print {$fh} join $delim, @outrow;
  0         0  
4563 0         0 print {$fh} "\n";
  0         0  
4564 0         0 $count++;
4565             }
4566 0 0       0 close $fh or sys_die( "Error closing $file_name" );
4567              
4568 0         0 return $count;
4569             }
4570              
4571             sub db_dump_query {
4572             =begin wiki
4573              
4574             !3 db_dump_query
4575              
4576             Parameters: ( vdn, columns )
4577              
4578             Accept a virtual database name and a list of column names, dump the \
4579             query showing column names and field values.
4580              
4581             Returns:
4582              
4583             =cut
4584 0     0 0 0 my ($vdn, $cols) = @_;
4585 0         0 my ($dbh, $sth) = _db_vdn('dump_query', $vdn);
4586              
4587 0         0 while ( my @row = $sth->fetchrow_array() ) {
4588 0         0 print "RECORD:\n";
4589 0         0 for my $i ( 0 .. $#row ) {
4590 0         0 print "\t", $cols->[$i], '=', _db_null( $row[$i] ), "\n";
4591             }
4592             }
4593              
4594 0         0 return 0;
4595             }
4596              
4597             sub db_dump_table {
4598             =begin wiki
4599              
4600             !3 db_dump_table
4601              
4602             Parameters: ( vdn, table_name, max_rows )
4603              
4604             Accept a virtual database name and a table name, dump the contents of the \
4605             requested table showing column names and field values. If optional paramater \
4606             max rows is provided, query output will be limited to that many rows. There \
4607             is an upper limit on the number of rows that this query will return, this \
4608             is set rather high, so in most cases you should probably supply a max rows \
4609             limit.
4610              
4611             Returns:
4612              
4613             =cut
4614 0     0 0 0 my ($vdn, $table_name, $max_rows) = @_;
4615 0         0 my ($dbh, $sth) = _db_vdn('dump_table', $vdn);
4616 0 0       0 $max_rows = 999_999 unless defined $max_rows;
4617              
4618 0         0 $table_name = uc $table_name;
4619 0         0 my $col_sql = "select column_name " .
4620             " from all_tab_columns " .
4621             " where table_name = '$table_name'";
4622 0         0 my ( $tmp_sth, @cols );
4623              
4624 0 0       0 $tmp_sth = $dbh->prepare( $col_sql )
4625             or sys_die( DBI->errstr );
4626 0 0       0 $tmp_sth->execute
4627             or sys_die( DBI->errstr );
4628 0         0 while ( my @row = $tmp_sth->fetchrow_array() ) {
4629 0         0 push @cols, $row[0];
4630             }
4631 0         0 $tmp_sth->finish;
4632              
4633 0         0 my $columns = join ', ', @cols;
4634 0         0 my $tab_sql = "select $columns " .
4635             " from $table_name";
4636 0 0       0 $tmp_sth = $dbh->prepare( $tab_sql )
4637             or sys_die( DBI->errstr );
4638 0 0       0 $tmp_sth->execute
4639             or sys_die( DBI->errstr );
4640              
4641 0         0 my $row_count = 0;
4642 0         0 while ( my @row = $tmp_sth->fetchrow_array() ) {
4643 0         0 print "RECORD:\n";
4644 0         0 for my $i ( 0 .. $#row ) {
4645 0         0 print "\t", $cols[$i], "=", _db_null( $row[$i] ), "\n";
4646             }
4647 0 0       0 last if ++$row_count >= $max_rows;
4648             }
4649 0         0 $tmp_sth->finish;
4650              
4651 0         0 return 0;
4652             }
4653              
4654             sub db_sqlloader {
4655             =begin wiki
4656              
4657             !3 db_sqlloader
4658              
4659             Parameters: ( vdn, datfile, ctlname, maxerrors )
4660              
4661             * /vdn/ - Virtual Database Name
4662             * /datfile/ - SQL*Loader data file
4663             * /ctlname/ - Job conf key for control file input
4664             * /maxerrors/ - Maximum number of errors allowed
4665              
4666             This is a convenience function which provides a simplified method for calling \
4667             the various db_sqlloader functions. This will invoke SQL*Loader and handle \
4668             the various execution and output parsing that whould otherwise have to be \
4669             handled by calling the db_sqlloader functions directly (which certainly you \
4670             can if you prefer).
4671              
4672             Execute SQL*Loader using the supplied paramaters. The Virtual Database \
4673             Name is used to obtain login credentials. This will launch SQL*Loader \
4674             and wait for it to finish, returning the SQL*Loader return code to the \
4675             caller.
4676              
4677             Data file name must be fully qualified. Path provided by data file name \
4678             will be used for out, bad, and dis files.
4679              
4680             Return: One of
4681              
4682             * SQLLDR_SUCC
4683             * SQLLDR_WARN
4684             * SQLLDR_FAIL
4685              
4686             =cut
4687 0     0 0 0 my ($vdn, $datfile, $ctlname, $maxerrors) = @_;
4688              
4689 0         0 my $id = 'db_sqlloader';
4690 0         0 my $datfilepath = $db_func_params{$id}{DatFilePath};
4691 0         0 my $dbenvr = $db_func_params{$id}{DbEnvr};
4692 0         0 my $netservice = $db_func_params{$id}{NetService};
4693              
4694 0         0 my $datfilefull = $datfilepath . $datfile;
4695              
4696 0         0 my ($sqlldr_retcd, $sqlldr_result);
4697              
4698 0         0 log_info( "Executing SQLLoader" );
4699 0 0       0 if ( $dbenvr =~ /$netservice/ ) {
4700 0         0 log_info( "Using netservice db connection symantics" );
4701 0         0 $sqlldr_retcd = db_sqlloaderx( "$vdn:$dbenvr", $datfilefull, $ctlname, $maxerrors );
4702             } else {
4703 0         0 log_info( "Using local db connection symantics" );
4704 0         0 $sqlldr_retcd = db_sqlloaderx( $vdn, $datfilefull, $ctlname, $maxerrors );
4705             }
4706              
4707 0         0 $sqlldr_result = db_sqlloaderx_parse_logfile( $datfilefull );
4708 0         0 log_info( "SQLLoader Output:", $sqlldr_result );
4709              
4710 0 0       0 if ( $sqlldr_retcd == $SQLLDR_SUCC ) {
4711 0         0 log_info( "Load data file $datfile completed successfully" );
4712             }
4713 0 0       0 if ( $sqlldr_retcd == $SQLLDR_WARN ) {
4714 0         0 log_warn( "Load data file $datfile completed with warnings" );
4715             }
4716 0 0 0     0 if ( $sqlldr_retcd == $SQLLDR_FTL || $sqlldr_retcd == $SQLLDR_FAIL ) {
4717 0         0 $sqlldr_retcd = $SQLLDR_FAIL;
4718 0         0 log_warn( "Load data file $datfile failed" );
4719             }
4720              
4721 0         0 my $rej_count = db_sqlloaderx_rejected();
4722 0 0       0 if ( $rej_count > 0 ) {
4723 0         0 log_warn( "SQLLoader rejected $rej_count records loading $datfile to " . sys_get_dbinst( $vdn ) );
4724             }
4725              
4726 0 0       0 if ( $rej_count > $maxerrors ) {
4727 0         0 log_warn( "SQLLoader failed loading $datfile to " . sys_get_dbinst( $vdn ) . " due to max rejected records" );
4728             }
4729              
4730 0         0 return $sqlldr_retcd;
4731             }
4732              
4733             sub db_sqlloaderx {
4734             =begin wiki
4735              
4736             !3 db_sqlloaderx
4737              
4738             See: db_sqlloader for Parameters and Return Values.
4739              
4740             =cut
4741 0     0 0 0 my ($vdn, $datfile, $ctlname, $maxerrors) = @_;
4742              
4743 0         0 my $defenvr = $dbdefenvr{$vdn};
4744 0         0 my $netservice = _db_netservice( $vdn );
4745 0         0 my ($db, $un, $pw) = _db_vdn('connect', $vdn);
4746              
4747 0   0     0 $maxerrors = $maxerrors || 50;
4748              
4749             ## validate the data file exists
4750 0 0       0 if ( ! -e $datfile ) { sys_die( "Data file $datfile not found" ); }
  0         0  
4751              
4752             ## get control file input from job conf
4753 0         0 my $key = $ctlname;
4754 0         0 my $section = 'sqlloader';
4755 0 0       0 if ( ! $conf_job{$section}{$key} ) {
4756 0         0 $key = 'control_file:' . $key;
4757 0 0       0 if ( ! $conf_job{$section}{$key} ) {
4758 0         0 sys_die( "No loader definition found in [$section] for key [$ctlname]", 0 );
4759             }
4760             }
4761 0         0 my $control = $conf_job{$section}{$key};
4762              
4763 0         0 my ($base,$path,$type) = fileparse($datfile,qr{\.dat|\.txt});
4764 0         0 my $ctlfile = $path.$base.'.ctl';
4765 0         0 my $parfile = $path.$base.'.par';
4766 0         0 my $badfile = $path.$base.'.bad';
4767 0         0 my $disfile = $path.$base.'.dis';
4768 0         0 my $outfile = $path.$base.'.out';
4769              
4770             ## build control file
4771 0   0     0 open my $fh, ">", $ctlfile || sys_die( 'Unable to create SQLLoader ctlfile', 0 );
4772 0         0 print $fh $control;
4773 0         0 close $fh;
4774              
4775             ## build params file
4776 0   0     0 open $fh, ">", $parfile || sys_die( 'Unable to create SQLLoader parfile', 0 );
4777 0         0 print $fh "userid=$un/$pw$netservice\n";
4778 0         0 print $fh "control=$ctlfile\n";
4779 0         0 print $fh "silent=(all)\n";
4780 0         0 print $fh "data=$datfile\n";
4781 0         0 print $fh "log=$outfile\n";
4782 0         0 print $fh "bad=$badfile\n";
4783 0         0 print $fh "discard=$disfile\n";
4784 0         0 close $fh;
4785              
4786 0         0 my @args = ("sqlldr", "PARFILE=$parfile errors=$maxerrors");
4787 0         0 system @args;
4788 0         0 my $sqlldr_retcd = $CHILD_ERROR >> 8;
4789              
4790             ## Normalize os dependent return codes. Why Oracle returns an os dependent
4791             ## return code from a cross-platform product is a mystery to me...
4792 0 0       0 if ( $OSNAME eq 'MSWin32' ) {
4793 0 0       0 if ( $sqlldr_retcd == 3 ) { $sqlldr_retcd = 1; }
  0         0  
4794 0 0       0 if ( $sqlldr_retcd == 4 ) { $sqlldr_retcd = 3; }
  0         0  
4795             }
4796              
4797 0         0 unlink $parfile;
4798 0         0 unlink $ctlfile;
4799              
4800 0         0 return $sqlldr_retcd;
4801             }
4802              
4803             sub db_sqlloaderx_parse_logfile {
4804             =begin wiki
4805              
4806             !3 db_sqlloaderx_parse_logfile
4807              
4808             Parameters: ( p1, p2, p3 )
4809              
4810             Please write this documentation.
4811              
4812             Returns:
4813              
4814             =cut
4815 0     0 0 0 my $datfile = shift;
4816              
4817 0         0 my ($base,$path,$type) = fileparse($datfile,qr{\.dat|\.txt});
4818 0         0 my $outfile = $path.$base.'.out';
4819              
4820 0         0 return _db_sqlloaderx_parse_logfile( $outfile );
4821             }
4822              
4823             sub db_sqlloaderx_skipped {
4824             =begin wiki
4825              
4826             !3 db_sqlloaderx_skipped
4827              
4828             Parameters: ( p1, p2, p3 )
4829              
4830             Please write this documentation.
4831              
4832             Returns:
4833              
4834             =cut
4835 0 0   0 0 0 if ( defined $sqlloader_results{'skipped'} ) {
4836 0         0 return $sqlloader_results{'skipped'}
4837             } else {
4838 0         0 return -1;
4839             }
4840             }
4841              
4842             sub db_sqlloaderx_read {
4843             =begin wiki
4844              
4845             !3 db_sqlloaderx_read
4846              
4847             Parameters: ( p1, p2, p3 )
4848              
4849             Please write this documentation.
4850              
4851             Returns:
4852              
4853             =cut
4854 0 0   0 0 0 if ( defined $sqlloader_results{'read'} ) {
4855 0         0 return $sqlloader_results{'read'}
4856             } else {
4857 0         0 return -1;
4858             }
4859             }
4860              
4861             sub db_sqlloaderx_rejected {
4862             =begin wiki
4863              
4864             !3 db_sqlloaderx_rejected
4865              
4866             Parameters: ( p1, p2, p3 )
4867              
4868             Please write this documentation.
4869              
4870             Returns:
4871              
4872             =cut
4873 0 0   0 0 0 if ( defined $sqlloader_results{'rejected'} ) {
4874 0         0 return $sqlloader_results{'rejected'}
4875             } else {
4876 0         0 return -1;
4877             }
4878             }
4879              
4880             sub db_sqlloaderx_discarded {
4881             =begin wiki
4882              
4883             !3 db_sqlloaderx_discarded
4884              
4885             Parameters: ( p1, p2, p3 )
4886              
4887             Please write this documentation.
4888              
4889             Returns:
4890              
4891             =cut
4892 0 0   0 0 0 if ( defined $sqlloader_results{'discarded'} ) {
4893 0         0 return $sqlloader_results{'discarded'}
4894             } else {
4895 0         0 return -1;
4896             }
4897             }
4898              
4899             sub db_sqlloaderx_elapsed_time {
4900             =begin wiki
4901              
4902             !3 db_sqlloaderx_elapsed_time
4903              
4904             Parameters: ( p1, p2, p3 )
4905              
4906             Please write this documentation.
4907              
4908             Returns:
4909              
4910             =cut
4911 0 0   0 0 0 if ( defined $sqlloader_results{'elapsed_time'} ) {
4912 0         0 return $sqlloader_results{'elapsed_time'}
4913             } else {
4914 0         0 return 'error';
4915             }
4916             }
4917              
4918             sub db_sqlloaderx_cpu_time {
4919             =begin wiki
4920              
4921             !3 db_sqlloaderx_cpu_time
4922              
4923             Parameters: ( p1, p2, p3 )
4924              
4925             Please write this documentation.
4926              
4927             Returns:
4928              
4929             =cut
4930 0 0   0 0 0 if ( defined $sqlloader_results{'cpu_time'} ) {
4931 0         0 return $sqlloader_results{'cpu_time'}
4932             } else {
4933 0         0 return 'error';
4934             }
4935             }
4936              
4937             sub db_func {
4938             =begin wiki
4939              
4940             !3 db_func
4941              
4942             Parameters: ( )
4943              
4944             This function executes an Oracle stored procedure that takes no input \
4945             parameters and returns a result via RETURN. This interface is Oracle \
4946             specific, so a check is performed to make sure that the supplied vdn is \
4947             pointing to an Oracle database. If a database error is raised it is \
4948             trapped and reported. The existing vdn statement handle is preserved.
4949              
4950             Returns:
4951              
4952             =cut
4953 0     0 0 0 my ($vdn, $package, $proc_name) = @_;
4954 0         0 my ($dbh, $sth) = _db_vdn('funcx', $vdn);
4955              
4956 0 0       0 unless ( _db_is_oracle($vdn) ) {
4957 0         0 sys_die( 'Not an Oracle database connection in db_funcx' );
4958             }
4959              
4960 0 0       0 if ( $package ) { $proc_name = $package. '.' .$proc_name; }
  0         0  
4961 0         0 my $sql = 'BEGIN :result := ' . $proc_name . '; END;';
4962              
4963 0         0 my $result;
4964 0         0 my $tmp_sth = $dbh->prepare( $sql );
4965 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
4966              
4967 0         0 $tmp_sth->bind_param_inout( ':result', \$result, 100 );
4968 0         0 $tmp_sth->execute;
4969 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
4970 0         0 $tmp_sth->finish;
4971              
4972 0         0 return $result;
4973             }
4974              
4975             sub db_proc {
4976             =begin wiki
4977              
4978             !3 db_proc
4979              
4980             Parameters: ( vdn, package, proc_name )
4981              
4982             This function executes an Oracle stored procedure that takes no input \
4983             parameters and returns no output. This interface is Oracle specific, so a \
4984             check is performed to make sure that the supplied vdn is pointing to an \
4985             Oracle database. If a database error is raised it is trapped and reported. \
4986             The existing vdn statement handle is preserved.
4987              
4988             Returns:
4989              
4990             =cut
4991 0     0 0 0 my ($vdn, $package, $proc_name) = @_;
4992 0         0 my ($dbh, $sth) = _db_vdn('procx', $vdn);
4993              
4994 0 0       0 unless ( _db_is_oracle($vdn) ) {
4995 0         0 sys_die( 'Not an Oracle database connection in db_procx' );
4996             }
4997              
4998 0 0       0 if ( $package ) { $proc_name = $package . '.' . $proc_name; }
  0         0  
4999 0         0 my $sql = 'BEGIN ' . $proc_name . '; END;';
5000              
5001 0         0 my $tmp_sth = $dbh->prepare( $sql );
5002 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5003 0         0 $tmp_sth->execute;
5004 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5005 0         0 $tmp_sth->finish;
5006              
5007 0         0 return 0;
5008             }
5009              
5010             sub db_proc_in {
5011             =begin wiki
5012              
5013             !3 db_proc_in
5014              
5015             Parameters: ( vdn, package, proc_name, parameters )
5016              
5017             This function executes an Oracle stored procedure that takes any number of \
5018             IN parameters and returns no output. This interface is Oracle specific, so a \
5019             check is performed to make sure that the supplied vdn is pointing to an \
5020             Oracle database. If a database error is raised it is trapped and reported. \
5021             The existing vdn statement handle is preserved.
5022              
5023             Returns:
5024              
5025             =cut
5026 0     0 0 0 my ($vdn, $package, $proc_name, $params) = @_;
5027 0 0       0 unless ( ref $params eq 'ARRAY' ) {
5028 0         0 sys_die( 'Invalid type in call to db_procx_in' );
5029             }
5030 0         0 my ($dbh, $sth) = _db_vdn('procx_in', $vdn);
5031              
5032 0 0       0 unless ( _db_is_oracle($vdn) ) {
5033 0         0 sys_die( 'Not an Oracle database connection in db_procx_in' );
5034             }
5035              
5036 0         0 my $sql = _db_proc_build_sql( $package, $proc_name, $params );
5037 0         0 my $tmp_sth = $dbh->prepare( $sql );
5038 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5039              
5040 0         0 $tmp_sth = _db_proc_bind_inparams( $tmp_sth, $params );
5041 0         0 $tmp_sth->execute;
5042 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5043 0         0 $tmp_sth->finish;
5044              
5045 0         0 return 0;
5046             }
5047              
5048             sub db_proc_out {
5049             =begin wiki
5050              
5051             !3 db_proc_out
5052              
5053             Parameters: ( vdn, package, proc_name, parameters )
5054              
5055             This function executes an Oracle stored procedure that takes no input and \
5056             returns any number of OUT parameters. This interface is Oracle specific, so \
5057             a check is performed to make sure that the supplied vdn is pointing to an \
5058             Oracle database. If a database error is raised it is trapped and reported. \
5059             The existing vdn statement handle is preserved.
5060              
5061             Returns:
5062              
5063             =cut
5064 0     0 0 0 my ($vdn, $package, $proc_name, $params) = @_;
5065 0 0       0 unless ( ref $params eq 'ARRAY' ) {
5066 0         0 sys_die( 'Invalid type in call to db_procx_out' );
5067             }
5068 0         0 my ($dbh, $sth) = _db_vdn('procx_out', $vdn);
5069              
5070 0 0       0 unless ( _db_is_oracle($vdn) ) {
5071 0         0 sys_die( 'Not an Oracle database connection in db_procx_out' );
5072             }
5073              
5074 0         0 my $sql = _db_proc_build_sql( $package, $proc_name, $params );
5075 0         0 my $tmp_sth = $dbh->prepare( $sql );
5076 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5077              
5078 0         0 $tmp_sth = _db_proc_bind_outparams( $tmp_sth, $params);
5079 0         0 $tmp_sth->execute;
5080 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5081 0         0 $tmp_sth->finish;
5082              
5083 0         0 return 0;
5084             }
5085              
5086             sub db_proc_inout {
5087             =begin wiki
5088              
5089             !3 db_proc_inout
5090              
5091             Parameters: ( vdn, package, proc_name, parameters )
5092              
5093             This function executes an Oracle stored procedure that takes any combination \
5094             of IN, IN OUT, or OUT parameters. This interface is Oracle specific, so a \
5095             check is performed to make sure that the supplied vdn is pointing to an \
5096             Oracle database. If a database error is raised it is trapped and reported. \
5097             The existing vdn statement handle is preserved.
5098              
5099             Returns:
5100              
5101             =cut
5102 0     0 0 0 my ($vdn, $package, $proc_name, $params) = @_;
5103 0 0       0 unless ( ref $params eq 'ARRAY' ) {
5104 0         0 sys_die( 'Invalid type in call to db_procx_inout' );
5105             }
5106 0         0 my ($dbh, $sth) = _db_vdn('procx_inout', $vdn);
5107              
5108 0 0       0 unless ( _db_is_oracle($vdn) ) {
5109 0         0 sys_die( 'Not an Oracle database connection in db_procx_inout' );
5110             }
5111              
5112 0         0 my $sql = _db_proc_build_sql( $package, $proc_name, $params );
5113 0         0 my $tmp_sth = $dbh->prepare( $sql );
5114 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5115              
5116 0         0 $tmp_sth = _db_proc_bind_inoutparams( $tmp_sth, $params);
5117 0         0 $tmp_sth->execute;
5118 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5119 0         0 $tmp_sth->finish;
5120              
5121 0         0 return 0;
5122             }
5123              
5124             sub db_dbms_output_enable {
5125             =begin wiki
5126              
5127             !3 db_dbms_output_enable
5128              
5129             Parameters: ( vdn, output_buffer_size)
5130              
5131             This function enables dbms_output in the database. You may send this \
5132             function an output buffer size if desired. If no buffersize is provided, \
5133             a default buffer size of 1000000 is used. This interface is Oracle specific, \
5134             so a check is performed to make sure that the supplied vdn is pointing to \
5135             an Oracle database.
5136              
5137             Returns:
5138              
5139             =cut
5140 0     0 0 0 my ($vdn, $bufsize) = shift;
5141 0         0 my ($dbh, $sth) = _db_vdn('enable_dbms_output', $vdn);
5142              
5143 0 0       0 unless ( _db_is_oracle($vdn) ) {
5144 0         0 sys_die( 'Not an Oracle database connection in db_dbms_output_get' );
5145             }
5146              
5147 0         0 $sys_dbms_output = 1;
5148 0 0       0 $bufsize = 1_000_000 unless $bufsize;
5149 0         0 $dbh->func($bufsize, 'dbms_output_enable');
5150 0 0       0 if ( DBI->errstr ) { log_warn( DBI->errstr ); return 1; }
  0         0  
  0         0  
5151              
5152 0         0 return 0;
5153             }
5154              
5155             sub db_dbms_output_disable {
5156             =begin wiki
5157              
5158             !3 db_dbms_output_disable
5159              
5160             Parameters: ( vdn )
5161              
5162             This function disables dbms_output retrieval. It does this by setting a \
5163             module flag value. This interface is Oracle specific, so a check is \
5164             performed to make sure that the supplied vdn is pointing to an Oracle \
5165             database.
5166              
5167             Returns:
5168              
5169             =cut
5170 0     0 0 0 my $vdn = shift;
5171              
5172 0 0       0 unless ( _db_is_oracle($vdn) ) {
5173 0         0 sys_die( 'Not an Oracle database connection in db_dbms_output_get' );
5174             }
5175              
5176 0         0 $sys_dbms_output = 0;
5177 0         0 return 0;
5178             }
5179              
5180             sub db_dbms_output_get {
5181             =begin wiki
5182              
5183             !3 db_dbms_output_get
5184              
5185             Parameters: ( vdn )
5186              
5187             This function retrieves the current dbms_output buffer and returns it to \
5188             the caller as a reference to an array. This interface is Oracle specific, \
5189             so a check is performed to make sure that the supplied vdn is pointing to \
5190             an Oracle database. You need to call db_dbms_output_enable first.
5191              
5192             Returns:
5193              
5194             =cut
5195 0     0 0 0 my $vdn = shift;
5196 0         0 my ($dbh, $sth) = _db_vdn('get_dbms_output', $vdn);
5197              
5198 0 0       0 unless ( _db_is_oracle($vdn) ) {
5199 0         0 sys_die( 'Not an Oracle database connection in db_dbms_output_get' );
5200             }
5201              
5202 0         0 my @arr;
5203 0 0       0 unless ( $sys_dbms_output ) {
5204 0         0 log_warn( 'Output option has not been enabled' );
5205 0         0 return \@arr;
5206             }
5207              
5208 0         0 @arr = $dbh->func('dbms_output_get');
5209 0 0       0 if ( DBI->errstr ) { log_warn( DBI->errstr ); }
  0         0  
5210              
5211 0         0 return \@arr;
5212             }
5213              
5214             sub db_index_rebuild {
5215             =begin wiki
5216              
5217             !3 db_index_rebuild
5218              
5219             Parameters: ( p1, p2, p3 )
5220              
5221             Please write this documentation.
5222              
5223             Returns:
5224              
5225             =cut
5226 0     0 0 0 my ($vdn, $index_name) = @_;
5227 0         0 my ($dbh, $sth) = _db_vdn('ora_index_rebuild', $vdn);
5228              
5229 0 0       0 unless ( _db_is_oracle($vdn) ) {
5230 0         0 sys_die( 'Not an Oracle database connection in function index_rebuild', 0 );
5231             }
5232              
5233 0         0 my $sql = "ALTER INDEX $index_name REBUILD";
5234              
5235 0         0 my $tmp_sth = $dbh->prepare( $sql );
5236 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5237              
5238 0         0 $tmp_sth->execute;
5239 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5240              
5241 0         0 $tmp_sth->finish;
5242 0         0 return 0;
5243             }
5244              
5245             sub db_exchange_partition {
5246             =begin wiki
5247              
5248             !3 db_exchange_partition
5249              
5250             Parameters: ( p1, p2, p3 )
5251              
5252             Please write this documentation.
5253              
5254             Returns:
5255              
5256             =cut
5257 0     0 0 0 my ($vdn, $to_table, $from_table, $partition) = @_;
5258 0         0 my ($dbh, $sth) = _db_vdn('ora_swap_partition', $vdn);
5259              
5260 0 0       0 unless ( _db_is_oracle($vdn) ) {
5261 0         0 sys_die( 'Not an Oracle database connection in function swap_partition', 0 );
5262             }
5263              
5264             ## REPAIR REQUIRED need to figure out why this is required...
5265 0         0 db_commit( $vdn );
5266 0         0 sleep 3;
5267              
5268 0         0 my $sql = "ALTER TABLE $to_table "
5269             . "EXCHANGE PARTITION $partition "
5270             . "WITH TABLE $from_table "
5271             . "INCLUDING INDEXES "
5272             . "WITH VALIDATION";
5273              
5274 0         0 my $tmp_sth = $dbh->prepare( $sql );
5275 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5276              
5277 0         0 $tmp_sth->execute;
5278 0 0       0 if ( DBI->errstr ) { sys_die( DBI->errstr ); }
  0         0  
5279              
5280 0         0 $tmp_sth->finish;
5281 0         0 return 0;
5282             }
5283              
5284             =begin wiki
5285              
5286             !2 Utility Functions
5287              
5288             These functions provide the general purpose file access capabilities.
5289              
5290             =cut
5291              
5292             sub util_get_filename_load {
5293             =begin wiki
5294              
5295             !3 util_get_filename_load
5296              
5297             Parameters: ( p1, p2, p3 )
5298              
5299             Please write this documentation.
5300              
5301             Returns:
5302              
5303             =cut
5304 0     0 0 0 my ($base, $ext) = @_;
5305 0         0 my $filename = $base . '.' . $ext;
5306 0 0       0 if ( $osuser ) {
5307 0         0 $filename = $base . '_' . $osuser . '.' . $ext;
5308             }
5309 0         0 return $path_load_dir . $filename;
5310             }
5311              
5312             sub util_get_filename_extr {
5313             =begin wiki
5314              
5315             !3 util_get_filename_extr
5316              
5317             Parameters: ( p1, p2, p3 )
5318              
5319             Please write this documentation.
5320              
5321             Returns:
5322              
5323             =cut
5324 0     0 0 0 my ($base, $ext) = @_;
5325 0         0 my $filename = $base . '.' . $ext;
5326 0 0       0 if ( $osuser ) {
5327 0         0 $filename = $base . '_' . $osuser . '.' . $ext;
5328             }
5329 0         0 return $path_extr_dir . $filename;
5330             }
5331              
5332             sub util_get_filename_log {
5333             =begin wiki
5334              
5335             !3 util_get_filename_log
5336              
5337             Parameters: ( p1, p2, p3 )
5338              
5339             Please write this documentation.
5340              
5341             Returns:
5342              
5343             =cut
5344 0     0 0 0 my $base = shift;
5345 0         0 return $path_log_dir . $base . $log_ext;
5346             }
5347              
5348             sub util_read_header {
5349             =begin wiki
5350              
5351             !3 util_read_header
5352              
5353             Parameters: ( filename, format )
5354              
5355             Please write this documentation.
5356              
5357             Returns:
5358              
5359             =cut
5360 0     0 0 0 my ($filename, $format) = @_;
5361 0 0       0 my $fh = File::Bidirectional->new($filename, {origin => 1} )
5362             or sys_die( "Unable to open file $filename" );
5363 0         0 my $head = $fh->readline();
5364 0         0 $fh->close;
5365 0         0 return $head;
5366             }
5367              
5368             sub util_read_footer {
5369             =begin wiki
5370              
5371             !3 util_read_footer
5372              
5373             Parameters: ( filename, format_string )
5374              
5375             Please write this documentation.
5376              
5377             Returns:
5378              
5379             =cut
5380 0     0 0 0 my ($filename, $format) = @_;
5381 0 0       0 my $fh = File::Bidirectional->new($filename, {origin => -1} )
5382             or sys_die( "Unable to open file $filename" );
5383 0         0 my $foot = $fh->readline();
5384 0         0 $fh->close;
5385 0         0 return $foot;
5386             }
5387              
5388             sub util_read_file {
5389             =begin wiki
5390              
5391             Parameters: ( )
5392              
5393             Slurp a file in one go and return a return a reference to the text contained \
5394             in the file.
5395              
5396             Returns:
5397              
5398             =cut
5399 0     0 0 0 my $file = shift;
5400 0 0       0 open( my $fh, $file ) or return 0;
5401 0         0 my $text = do { local( $/ ) ; <$fh> } ;
  0         0  
  0         0  
5402 0         0 return \$text;
5403             }
5404              
5405             sub util_write_header {
5406             =begin wiki
5407              
5408             !3 util_write_header
5409              
5410             Parameters: ( p1, p2, p3 )
5411              
5412             Please write this documentation.
5413              
5414             Returns:
5415              
5416             =cut
5417 0     0 0 0 my ($filename, $header, $append) = @_;
5418 0 0       0 $header = 'HEADER' unless $header;
5419 0         0 my $mode = ">>";
5420 0 0       0 $mode = ">" unless $append;
5421 0 0       0 open my $fh, $mode, $filename or sys_die( "Error writing header to $filename" );
5422 0         0 print {$fh} "$header\n";
  0         0  
5423 0 0       0 close $fh or sys_die( "Error closing $filename" );
5424 0         0 return 0;
5425             }
5426              
5427             sub util_write_footer {
5428             =begin wiki
5429              
5430             !3 util_write_footer
5431              
5432             Parameters: ( p1, p2, p3 )
5433              
5434             Please write this documentation.
5435              
5436             Returns:
5437              
5438             =cut
5439 0     0 0 0 my ($filename, $footer) = @_;
5440 0 0       0 $footer = 'FOOTER' unless $footer;
5441 0 0       0 open my $fh, ">>", $filename or sys_die( "Error writing footer to $filename" );
5442 0         0 print {$fh} "$footer\n";
  0         0  
5443 0 0       0 close $fh or sys_die( "Error closing $filename" );
5444 0         0 return 0;
5445             }
5446              
5447             sub util_move {
5448             =begin wiki
5449              
5450             Parameters: ( )
5451              
5452             The move function also takes two parameters: the current name and the \
5453             intended name of the file to be moved. If the destination already exists \
5454             and is a directory, and the source is not a directory, then the source \
5455             file will be renamed into the directory specified by the destination.
5456              
5457             If possible, move() will simply rename the file. Otherwise, it copies the \
5458             file to the new location and deletes the original. If an error occurs \
5459             during this copy-and-delete process, you may be left with a (possibly \
5460             partial) copy of the file under the destination name.
5461              
5462             Returns:
5463              
5464             =cut
5465 0     0 0 0 my ($from, $to) = @_;
5466              
5467 0 0       0 return 0 unless $util_move;
5468 0         0 my $result = move($from, $to);
5469 0         0 return $result;
5470             }
5471              
5472             sub util_trim {
5473 0     0 0 0 my $str = shift;
5474 0         0 $str =~ s/^\s+//;
5475 0         0 $str =~ s/\s+$//;
5476 0         0 return $str;
5477             }
5478              
5479             sub util_zsdf {
5480             =begin wiki
5481              
5482             Parameters: ( )
5483              
5484             This regex was taken from the book "Regular Expression Recipes", by Nathan \
5485             A. Good. The idea for util_zsdf (Zero Supress Decimal Format) came from my \
5486             first mentor, Ed Bowlen.
5487              
5488             Returns:
5489              
5490             =cut
5491 0     0 0 0 my ($number, $width) = @_;
5492 0         0 $number =~ s/(?<=\d)(?=(\d{3})+(?!\d))/,/g;
5493 0         0 return sprintf '%*s', $width, $number;
5494             }
5495              
5496             =begin wiki
5497              
5498             !2 Testing Functions
5499              
5500             These functions some basic test capabilities. These can be used to write simple
5501             database test scripts.
5502              
5503             =cut
5504              
5505             sub test_init {
5506             =begin wiki
5507              
5508             !3 test_init
5509              
5510             Parameters: ( p1, p2, p3 )
5511              
5512             Please write this documentation.
5513              
5514             Returns:
5515              
5516             =cut
5517 0     0 0 0 $t_ok = 0;
5518 0         0 $t_notok = 0;
5519 0         0 return 0;
5520             }
5521              
5522             sub test_ok {
5523             =begin wiki
5524              
5525             !3 test_ok
5526              
5527             Parameters: ( p1, p2, p3 )
5528              
5529             Please write this documentation.
5530              
5531             Returns:
5532              
5533             =cut
5534 0     0 0 0 my ($actual,$expected,$description) = @_;
5535              
5536 0         0 $t_num++;
5537 0 0       0 if ($actual eq $expected) {
5538 0         0 $t_ok++;
5539 0         0 log_info("ok $t_num");
5540             } else {
5541 0         0 $t_notok++;
5542 0         0 sys_set_errorlevel(sys_get_errorlevel()+1);
5543 0         0 log_info("not ok $t_num - $description");
5544             }
5545              
5546 0         0 return 0;
5547             }
5548              
5549             sub test_results {
5550             =begin wiki
5551              
5552             !3 test_results
5553              
5554             Parameters: ( p1, p2, p3 )
5555              
5556             Please write this documentation.
5557              
5558             Returns:
5559              
5560             =cut
5561 0     0 0 0 log_info("Test script: passed $t_ok, failed $t_notok");
5562 0 0       0 if ( $t_notok == 0 ) {
5563 0         0 log_info("Test script: PASS");
5564             } else {
5565 0         0 log_info("Test script: FAIL");
5566             }
5567 0         0 return 0;
5568             }
5569              
5570             sub test_harness_init {
5571             =begin wiki
5572              
5573             !3 test_harness_init
5574              
5575             Parameters: ( p1, p2, p3 )
5576              
5577             Please write this documentation.
5578              
5579             Returns:
5580              
5581             =cut
5582 0     0 0 0 $th_num = 0;
5583 0         0 return 0;
5584             }
5585              
5586             sub test_harness_run {
5587             =begin wiki
5588              
5589             !3 test_harness_run
5590              
5591             Parameters: ( p1, p2, p3 )
5592              
5593             Please write this documentation.
5594              
5595             Returns:
5596              
5597             =cut
5598 0     0 0 0 my $test_scripts = shift;
5599              
5600 0         0 foreach my $ts ( @{$test_scripts} ) {
  0         0  
5601 0         0 $th_num++;
5602 0         0 log_info("Test script: $ts");
5603 0         0 my $retcd = sys_run_job($ts, 8, '-r', '-v');
5604 0 0       0 if ( $retcd > 0 ) {
5605 0         0 sys_set_errorlevel( sys_get_errorlevel() + $retcd );
5606             }
5607             }
5608              
5609 0         0 return 0;
5610             }
5611              
5612             sub test_harness_results {
5613             =begin wiki
5614              
5615             !3 test_harness_results
5616              
5617             Parameters: ( p1, p2, p3 )
5618              
5619             Please write this documentation.
5620              
5621             Returns:
5622              
5623             =cut
5624 0     0 0 0 my $test_scripts = shift;
5625              
5626 0         0 my ($ts_passed, $ts_failed);
5627 0         0 my $th_result = 'PASS';
5628 0         0 my $th_passed = 0;
5629 0         0 my $th_failed = 0;
5630              
5631 0         0 foreach my $ts ( @{$test_scripts} ) {
  0         0  
5632 0         0 $ts =~ s/\.pl$//;
5633 0         0 my $tsfull = util_get_filename_log( $ts );
5634 0         0 my $log = util_read_file( $tsfull );
5635 0 0       0 if ( ! $log ) {
5636 0         0 log_info( "Error reading log for test script: $ts" );
5637 0         0 next;
5638             }
5639              
5640 0         0 $ts_passed = 0;
5641 0         0 $ts_failed = 0;
5642 0         0 $th_num++;
5643              
5644 0         0 $$log =~ m#.{19,19} Test script: (PASS|FAIL|DUBIOUS)#;
5645 0         0 my $ts_result = $1;
5646              
5647 0         0 $$log =~ m#.{19,19} Test script: passed (\d+), failed (\d+)#;
5648 0         0 $ts_passed = $1;
5649 0         0 $ts_failed = $2;
5650              
5651 0 0       0 if ( $ts_result eq 'PASS' ) {
5652 0         0 $th_passed++;
5653             }
5654 0 0       0 if ( $ts_result eq 'FAIL' ) {
5655 0         0 $th_failed++;
5656 0         0 $th_result = 'FAIL';
5657             }
5658              
5659 0         0 log_info( "Test harness: script $ts, passed $ts_passed, failed $ts_failed, $ts_result" );
5660             }
5661              
5662 0         0 log_info( "Test harness: passed $th_passed, failed $th_failed" );
5663 0         0 log_info( "Test harness: $th_result" );
5664              
5665 0         0 return 0;
5666             }
5667              
5668             sub test_harness_summary {
5669             =begin wiki
5670              
5671             !3 test_harness_summary
5672              
5673             Parameters: ( p1, p2, p3 )
5674              
5675             Please write this documentation.
5676              
5677             Returns:
5678              
5679             =cut
5680 0     0 0 0 my $test_harnesses = shift;
5681              
5682 0         0 foreach my $th ( @{$test_harnesses} ) {
  0         0  
5683 0         0 $th =~ s/\.pl$//;
5684 0         0 my $thfull = util_get_filename_log( $th );
5685 0         0 my $log = util_read_file( $thfull );
5686 0 0       0 if ( ! $log ) {
5687 0         0 log_info( "Error reading log for test harness: $th" );
5688 0         0 next;
5689             }
5690              
5691 0         0 log_info( "Test harness summary: $th" );
5692              
5693             }
5694              
5695 0         0 return 0;
5696             }
5697              
5698             # private methods
5699             # -----------------------------------------------------------------------------
5700              
5701             =begin wiki
5702              
5703             !2 Private Functions
5704              
5705             These functions provide internal module support.
5706              
5707             =cut
5708              
5709             sub _sys_init_vars {
5710             =begin wiki
5711              
5712             !3 _sys_init_vars
5713              
5714             Parameters: ( )
5715              
5716             This function provides variable initialization for a particular jobname. \
5717             Once sys_init has been called with a jobname, this function is called to \
5718             initialize or reinitialize system variables. It is possible, although not \
5719             recommended, to stack jobs in a single perl script. my callling sys_init with \
5720             different jobnames each time. This feature has not been thoroughly tested.
5721              
5722             Returns:
5723              
5724             =cut
5725 0     0   0 $pid = $PROCESS_ID;
5726 0         0 $errorlevel = 0;
5727 0         0 @plugins = ();
5728 0         0 $sys_dbms_output = 1;
5729 0         0 $sys_log_open = 0;
5730 0         0 $sys_jobconf_override = 0;
5731 0         0 $sys_jobconf_file = '';
5732              
5733 0         0 %log_level_opts = (
5734             FATAL => 'FATAL',
5735             ERROR => 'FATAL,ERROR',
5736             WARN => 'FATAL,ERROR,WARN',
5737             INFO => 'FATAL,ERROR,WARN,INFO',
5738             DEBUG => 'FATAL,ERROR,WARN,INFO,DEBUG',
5739             NONE => 'NONE',
5740             );
5741              
5742 0         0 _sys_read_conf( 'sys_data.conf' );
5743 0         0 _sys_read_conf( 'sys_log.conf' );
5744 0         0 _sys_read_conf( 'sys_mail.conf' );
5745 0         0 _sys_read_conf( 'sys_common.conf' );
5746 0         0 _sys_read_conf( 'sys_util.conf' );
5747 0         0 _sys_read_conf( 'sys_environment.conf' );
5748 0         0 _sys_read_conf( 'sys_de.conf');
5749 0         0 _sys_read_conf( 'sys_run_controls.conf');
5750              
5751 0         0 my $envvar = uc $conf_system{'system'}{'envvar'};
5752 0         0 $dataenvr = lc $ENV{$envvar};
5753 0 0       0 if ( ! defined $dataenvr ) {
5754 0         0 sys_die( "Environment variable $dataenvr not set", 0 );
5755             }
5756              
5757 0         0 $path_bin_dir = $conf_system{"$OSNAME directory bin"}{$dataenvr};
5758 0         0 $path_lib_dir = $conf_system{"$OSNAME directory lib"}{$dataenvr};
5759 0         0 $path_log_dir = $conf_system{"$OSNAME directory log"}{$dataenvr};
5760 0         0 $path_load_dir = $conf_system{"$OSNAME directory load"}{$dataenvr};
5761 0         0 $path_extr_dir = $conf_system{"$OSNAME directory extr"}{$dataenvr};
5762 0         0 $path_prev_dir = $conf_system{"$OSNAME directory prev"}{$dataenvr};
5763 0         0 $path_scripts_dir = $conf_system{"$OSNAME directory scripts"}{$dataenvr};
5764 0         0 $mail_server = $conf_mail{'mail'}{'server'};
5765 0         0 $mail_from = $conf_mail{'mail'}{'from'};
5766 0         0 $mail_emailto = $conf_mail{'mail'}{'emailto'};
5767 0         0 $mail_pagerto = $conf_mail{'mail'}{'pagerto'};
5768 0   0     0 $mail_email_levels = $conf_mail{'mail'}{'email_levels'} || "FATAL";
5769 0   0     0 $mail_pager_levels = $conf_mail{'mail'}{'pager_levels'} || "FATAL";
5770 0         0 $log_file = $conf_log{'log'}{'default_logfile'};
5771 0         0 $log_filefull = $path_log_dir . $log_file;
5772 0   0     0 $log_logging_levels = $conf_log{'log'}{'logging_levels'} || "FATAL,ERROR,WARN,INFO";
5773 0   0     0 $log_console_levels = $conf_log{'log'}{'console_levels'} || "FATAL,ERROR,WARN,INFO";
5774 0   0     0 $log_gdg = $conf_log{'log'}{'gdg'} || 5;
5775              
5776 0         0 $path_plugin_dir = $conf_system{"$OSNAME directory plugin"}{$dataenvr};
5777 0 0       0 if ( $osuser ) {
5778 0         0 $dbitrace_file = $dbitrace_base . '_' . $osuser . $log_ext;
5779             }
5780 0         0 $dbitrace_filefull = $path_log_dir.$dbitrace_file;
5781              
5782             ## load data structures
5783 0         0 @databases = split m/,/, $conf_data{'databases'}{'databases'};
5784 0         0 @dat_envrs = split m/,/, $conf_system{'system'}{'dat_envrs'};
5785 0         0 @job_acros = split m/,/, $conf_system{'system'}{'job_acros'};
5786              
5787 0         0 foreach my $db ( @databases ) {
5788 0         0 $dbname{$db} = $conf_data{'names'}{$db};
5789             }
5790 0         0 foreach my $db ( @databases ) {
5791 0         0 $dbdefenvr{$db} = $conf_data{'default '.$dataenvr}{$db};
5792             }
5793 0         0 foreach my $db ( @databases ) {
5794 0         0 $dbhandles{$db}{'dbh'} = 0;
5795 0         0 $dbhandles{$db}{'sth'} = 0;
5796             }
5797 0         0 foreach my $db ( @databases ) {
5798 0         0 $dbinst{$db} = $conf_data{'instances'}{$db};
5799             }
5800 0         0 foreach my $db ( @databases ) {
5801 0         0 foreach my $inst ( split m/,/, $conf_data{'instances'}{$db} ) {
5802 0         0 $dbconn{$db}{$inst}{'netservice'} = $conf_data{"$db $inst"}{'netservice'};
5803 0         0 $dbconn{$db}{$inst}{'database' } = $conf_data{"$db $inst"}{'database'};
5804 0         0 $dbconn{$db}{$inst}{'username' } = $conf_data{"$db $inst"}{'username'};
5805 0         0 $dbconn{$db}{$inst}{'password' } = $conf_data{"$db $inst"}{'password'};
5806             }
5807             }
5808              
5809 0         0 return 0;
5810             }
5811              
5812             sub _sys_job_init {
5813             =begin wiki
5814              
5815             !3 _sys_job_init
5816              
5817             Parameters: ( p1, p2, p3 )
5818              
5819             Please write this documentation.
5820              
5821             Returns:
5822              
5823             =cut
5824 0     0   0 my $rtconf = $path_conf_dir.'/'.$jobname.'.'.$pid.'.running';
5825              
5826             ## create runtime conf file
5827 0 0       0 open my $cfile, '>', $rtconf or sys_die( "Error creating runtime jobconf file" );
5828 0         0 close $cfile;
5829              
5830 0         0 my $conf = new Config::IniFiles( -file => $rtconf );
5831 0 0       0 unless ( defined $conf ) { sys_die( "Error opening runtime jobconf file" ); }
  0         0  
5832              
5833 0         0 my $starttime = time;
5834 0         0 $conf->newval( 'pid', 'pid', $pid );
5835 0         0 $conf->newval( 'starttime', 'starttime', $starttime );
5836 0         0 $conf->newval( 'restart', 'restart', 0 );
5837 0         0 $conf->RewriteConfig;
5838 0         0 return 0;
5839             }
5840              
5841             sub _sys_job_end {
5842             =begin wiki
5843              
5844             !3 _sys_job_end
5845              
5846             Parameters: ( p1, p2, p3 )
5847              
5848             Please write this documentation.
5849              
5850             Returns:
5851              
5852             =cut
5853 1     1   5 my $rtconf = $path_conf_dir.'/'.$jobname.'.'.$pid.'.running';
5854 1 50       30 if ( -e $rtconf ) {
5855 0         0 unlink $rtconf;
5856             }
5857 1         1 return 0;
5858             }
5859              
5860             sub _sys_job_dependent {
5861             =begin wiki
5862              
5863             !3 _sys_job_dependent
5864              
5865             Parameters: ( p1, p2, p3 )
5866              
5867             Please write this documentation.
5868              
5869             Returns:
5870              
5871             =cut
5872 0     0     my $dependent_jobname = shift;
5873 0 0         return 0 unless $dependent_jobname;
5874              
5875 0           my $conf = new Config::IniFiles( -file => $path_conf_dir.'/sys_environment.conf' );
5876 0 0         unless ( defined $conf ) { sys_die( "Error opening sys_environment.conf (4)" ); }
  0            
5877 0           my $params = join '~', $conf->Parameters( 'jobs' );
5878 0 0         if ( $params =~ m/$dependent_jobname/x ) { ## case sensitive
5879             ## one or more instances of dependent job is currently running
5880 0           log_info( "Job name $dependent_jobname is active in the system, waiting" );
5881 0           return 1;
5882             }
5883 0           return 0;
5884             }
5885              
5886             sub _sys_read_conf {
5887             =begin wiki
5888              
5889             !3 _sys_read_conf
5890              
5891             Parameters: ( p1, p2, p3 )
5892              
5893             Please write this documentation.
5894              
5895             Returns:
5896              
5897             =cut
5898 0     0     my $conf = shift;
5899 0           my $conf_filefull = $path_conf_dir . '/' . $conf;
5900              
5901 0           my $msg1 = "Probably syntax error, unable to load";
5902              
5903 0 0         if ( $conf =~ m/^sys_data/x ) {
5904 0 0         tie %conf_data, 'Config::IniFiles', ( -file => $conf_filefull )
5905             or sys_die( "$msg1 data conf: $conf", 0 );
5906             }
5907 0 0         if ( $conf =~ m/^sys_log/x ) {
5908 0 0         tie %conf_log, 'Config::IniFiles', ( -file => $conf_filefull )
5909             or sys_die( "$msg1 log conf: $conf", 0 );
5910             }
5911 0 0         if ( $conf =~ m/^sys_mail/x ) {
5912 0 0         tie %conf_mail, 'Config::IniFiles', ( -file => $conf_filefull )
5913             or sys_die( "$msg1 mail conf: $conf", 0 );
5914             }
5915 0 0         if ( $conf =~ m/^sys_common/x ) {
5916 0 0         tie %conf_query, 'Config::IniFiles', ( -file => $conf_filefull )
5917             or sys_die( "$msg1 query conf: $conf", 0 );
5918             }
5919 0 0         if ( $conf =~ m/^sys_util/x ) {
5920 0 0         tie %conf_util, 'Config::IniFiles', ( -file => $conf_filefull )
5921             or sys_die( "$msg1 util conf: $conf", 0 );
5922             }
5923 0 0         if ( $conf =~ m/^sys_environment/x ) {
5924 0 0         tie %conf_system, 'Config::IniFiles', ( -file => $conf_filefull )
5925             or sys_die( "$msg1 environment conf: $conf", 0 );
5926             }
5927 0 0         if ( $conf =~ m/^sys_test/x ) {
5928 0 0         tie %conf_job, 'Config::IniFiles', ( -file => $conf_filefull )
5929             or sys_die( "$msg1 test conf: $conf", 0 );
5930             }
5931 0 0         if ( $conf =~ m/^sys_de/x ) {
5932 0 0         tie %conf_de, 'Config::IniFiles', ( -file => $conf_filefull )
5933             or sys_die( "$msg1 de conf: $conf", 0 );
5934             }
5935 0 0         if ( $conf =~ m/^sys_run_controls/x ) {
5936 0 0         tie %conf_rcontrols, 'Config::IniFiles', ( -file => $conf_filefull )
5937             or sys_die( "$msg1 run controls conf: $conf", 0 );
5938             }
5939             ## job specific conf file
5940 0 0         if ( $conf !~ m/^sys_/x ) {
5941 0 0         tie %conf_job, 'Config::IniFiles', ( -file => $conf_filefull )
5942             or sys_die( "$msg1 job conf: $conf", 0 );
5943             }
5944 0           return 0;
5945             }
5946              
5947             sub _sys_read_job {
5948             =begin wiki
5949              
5950             !3 _sys_read_job
5951              
5952             Parameters: ( p1, p2, p3 )
5953              
5954             Please write this documentation.
5955              
5956             Returns:
5957              
5958             =cut
5959 0 0   0     if ( $conf_job{job}{'logfile'} ) {
5960 0           $log_file = $conf_job{job}{'logfile'};
5961             }
5962 0 0         if ( $conf_job{job}{'logging_levels'} ) {
5963 0           $log_logging_levels = $conf_job{job}{'logging_levels'};
5964             }
5965 0 0         if ( $conf_job{job}{'console_levels'} ) {
5966 0           $log_console_levels = $conf_job{job}{'console_levels'};
5967             }
5968 0 0         if ( $conf_job{job}{'log_gdg'} ) {
5969 0           $log_gdg = $conf_job{job}{'log_gdg'};
5970             }
5971 0 0         if ( $conf_job{job}{'log_prefix'} ) {
5972 0           $log_prefix = $conf_job{job}{'log_prefix'};
5973             }
5974 0 0         if ( $conf_job{job}{'emailto'} ) {
5975 0           $mail_emailto = $conf_job{job}{'emailto'};
5976             }
5977 0 0         if ( $conf_job{job}{'pagerto'} ) {
5978 0           $mail_pagerto = $conf_job{job}{'pagerto'};
5979             }
5980 0 0         if ( $conf_job{job}{'email_levels'} ) {
5981 0           $mail_email_levels = $conf_job{job}{'email_levels'};
5982             }
5983 0 0         if ( $conf_job{job}{'pager_levels'} ) {
5984 0           $mail_pager_levels = $conf_job{job}{'pager_levels'};
5985             }
5986 0           return 0;
5987             }
5988              
5989             sub _sys_init_source_validation {
5990             =begin wiki
5991              
5992             !3 _sys_init_source_validation
5993              
5994             Parameters: ( p1, p2, p3 )
5995              
5996             Please write this documentation.
5997              
5998             Returns:
5999              
6000             =cut
6001 0   0 0     open my $fh, "<", $script_filefull
6002             || sys_die( "Unable to open $script_file for validatation", 0 );
6003 0           my @r = <$fh>;
6004 0           close $fh;
6005 0           my $source = join '', @r;
6006              
6007 0           my $errm1 = "$script_file failed source validation, id tag ";
6008 0           my $errm2 = "$script_file failed source validation, pod section ";
6009 0           my $errm3 = " is missing or invalid";
6010 0           my $checkfor;
6011              
6012 0           $checkfor = "FILENAME";
6013 0 0         $source =~ m/^\#\#@@.*/m
6014             or sys_die( $errm1.$checkfor.$errm3, 0 );
6015              
6016 0           $checkfor = "SOURCETITLE";
6017 0 0         $source =~ m/^\#\#\$\$.*/m
6018             or sys_die( $errm1.$checkfor.$errm3, 0 );
6019              
6020 0           $checkfor = "NAME";
6021 0 0         $source =~ m/^!1 $checkfor\n\n[A-Za-z]/m
6022             or sys_die( $errm2.$checkfor.$errm3, 1 );
6023              
6024 0           $checkfor = "DESCRIPTION";
6025 0 0         $source =~ m/^!1 $checkfor\n\n[A-Za-z]/m
6026             or sys_die( $errm2.$checkfor.$errm3, 1 );
6027              
6028 0           $checkfor = "RECOVERY NOTES";
6029 0 0         $source =~ m/^!1 $checkfor\n\n[A-Za-z]/m
6030             or sys_die( $errm2.$checkfor.$errm3, 1 );
6031              
6032 0           $checkfor = "ENVIRONMENT NOTES";
6033 0 0         $source =~ m/^!1 $checkfor\n\n[A-Za-z]/m
6034             or sys_die( $errm2.$checkfor.$errm3, 1 );
6035              
6036 0           $checkfor = "DEPENDENCIES";
6037 0 0         $source =~ m/^!1 $checkfor\n\n[A-Za-z]/m
6038             or sys_die( $errm2.$checkfor.$errm3, 1 );
6039              
6040 0           $checkfor = "HISTORY";
6041 0 0         $source =~ m/^!1 $checkfor\n\n[A-Za-z0-9\*]/m
6042             or sys_die( $errm2.$checkfor.$errm3, 1 );
6043              
6044 0           return 0;
6045             }
6046              
6047             sub _sys_run_background {
6048             =begin wiki
6049              
6050             !3 _sys_run_background
6051              
6052             Parameters: ( p1, p2, p3 )
6053              
6054             Please write this documentation.
6055              
6056             Returns:
6057              
6058             =cut
6059 0 0   0     if ( $OSNAME eq 'MSWin32' ) {
6060 0           sys_die( 'Background run mode not available on Windows', 0 );
6061             }
6062 0           $opt_commandline =~ s{-rb }{-r };
6063 0           $opt_commandline =~ s{-rb$}{-r};
6064 0           print "$script_filefull $opt_commandline".' &';
6065 0           exit 0;
6066             }
6067              
6068             sub _sys_run_scheduled {
6069             =begin wiki
6070              
6071             !3 _sys_run_scheduled
6072              
6073             Parameters: ( p1, p2, p3 )
6074              
6075             Please write this documentation.
6076              
6077             Returns:
6078              
6079             =cut
6080             ## this die is temporary should use sys_die
6081 0     0     die "Not yet implemented\n\n";
6082             }
6083              
6084             sub _sys_run_de {
6085             =begin wiki
6086              
6087             !3 _sys_run_de
6088              
6089             Parameters: ( p1, p2, p3 )
6090              
6091             Please write this documentation.
6092              
6093             Returns:
6094              
6095             =cut
6096 0     0     my $de = shift;
6097 0           my $conf_file = $jobname . '.' . $de . '.conf';
6098 0           _sys_read_conf( $conf_file ); ## tie %conf_job to job specific conf file
6099 0           _sys_read_job(); ## read job specific settings from %conf_job
6100 0           return 0;
6101             }
6102              
6103             sub _sys_run_restart {
6104             =begin wiki
6105              
6106             !3 _sys_run_restart
6107              
6108             Parameters: ( p1, p2, p3 )
6109              
6110             Please write this documentation.
6111              
6112             Returns:
6113              
6114             =cut
6115             ## this die is temporary should use sys_die
6116 0     0     die "Not yet implemented\n\n";
6117             }
6118              
6119             sub _sys_forkexec {
6120             =begin wiki
6121              
6122             !3 _sys_forkexec
6123              
6124             Parameters: ( p1, p2, p3 )
6125              
6126             Please write this documentation.
6127              
6128             Returns:
6129              
6130             =cut
6131 0     0     my ($jobname, @params) = @_;
6132 0           my $pid;
6133 0 0         if ( $pid = fork ) {
    0          
6134 0           return $pid;
6135             ## this is the parent, so return the pid, everything below here is
6136             ## either the child or a major system failure
6137             }
6138             elsif ( defined $pid ) {
6139 0           exec $jobname, @params;
6140             ## shouldn't reach this unless exec fails, we exit here (not return)
6141             ## becuase we are in the child
6142 0           exit 0;
6143             } else {
6144 0           log_warn( "Could not fork $!" );
6145 0           return 0;
6146             }
6147             }
6148              
6149             sub _sys_reap_child {
6150             =begin wiki
6151              
6152             !3 _sys_reap_child
6153              
6154             Parameters: ( p1, p2, p3 )
6155              
6156             Please write this documentation.
6157              
6158             Returns:
6159              
6160             =cut
6161 0     0     my $pid = 0;
6162 0 0         if ( ($pid = waitpid(-1, 0)) > 0 ) {
6163 0           $pidlib{$pid}{retcd} = $? >> 8;
6164             }
6165 0           return $pid;
6166             }
6167              
6168             sub _sys_test_dbcon {
6169             =begin wiki
6170              
6171             !3 _sys_test_dbcon
6172              
6173             Parameters: ( p1, p2, p3 )
6174              
6175             Please write this documentation.
6176              
6177             Returns:
6178              
6179             =cut
6180 0     0     my $connections = shift;
6181             ## open dbi trace file
6182 0           DBI->trace(1, $dbitrace_filefull );
6183 0           foreach my $connectdef ( split m/,/, $connections ) {
6184 0           my ($db, $inst) = split m/:/, $connectdef;
6185 0 0         _check_array_val( $db, \@databases )
6186             || sys_die( "Invalid database: [$db]", 0 );
6187 0 0         _check_array_val( $inst, [split m/,/, $dbinst{$db}] )
6188             || sys_die( "Invalid database instance: [$db.$inst]", 0 );
6189 0           my $database = $dbconn{$db}{$inst}{'database'};
6190 0           my $username = $dbconn{$db}{$inst}{'username'};
6191 0           my $password = $dbconn{$db}{$inst}{'password'};
6192 0           print "Connecting to: $db/$inst\n";
6193 0 0         my $dbh = DBI->connect( $database, $username, $password, { RaiseError => 0, AutoCommit => 0 } )
6194             or sys_die( DBI->errstr, 0 );
6195             ## push resulting handle onto handle stack for cleanup on exit
6196 0           $dbhandles{$db}{'dbh'} = $dbh;
6197 0           print "Success\n\n";
6198             }
6199 0           exit 0;
6200             }
6201              
6202             sub _sys_check_severity_levels {
6203             =begin wiki
6204              
6205             !3 _sys_check_severity_levels
6206              
6207             Parameters: ( p1, p2, p3 )
6208              
6209             Please write this documentation.
6210              
6211             Returns:
6212              
6213             =cut
6214 0     0     my $lvls_str = shift;
6215              
6216             ## levls_str can be either a single value or a comma delimited list
6217 0 0         if ( $lvls_str =~ /,/ ) {
6218             ## received a list of severity levels
6219 0           my @loglvls = split m/,/, $lvls_str;
6220 0           foreach my $level ( @loglvls ) {
6221 0 0         if ( $level !~ /FATAL|ERROR|WARN|INFO|DEBUG|NONE/ ) {
6222 0           sys_die( 'Invalid logging/notification severity list', 0 );
6223             }
6224             }
6225 0           return $lvls_str;
6226             } else {
6227             ## received a single severity level to be translated to a list
6228 0 0         if ( $lvls_str =~ /^FATAL$/i ) {
6229 0           $lvls_str = 'FATAL';
6230 0           return $lvls_str;
6231             }
6232 0 0         if ( $lvls_str =~ /^ERROR$/i ) {
6233 0           $lvls_str = 'FATAL,ERROR';
6234 0           return $lvls_str;
6235             }
6236 0 0         if ( $lvls_str =~ /^WARN$/i ) {
6237 0           $lvls_str = 'FATAL,ERROR,WARN';
6238 0           return $lvls_str;
6239             }
6240 0 0         if ( $lvls_str =~ /^INFO$/i ) {
6241 0           $lvls_str = 'FATAL,ERROR,WARN,INFO';
6242 0           return $lvls_str;
6243             }
6244 0 0         if ( $lvls_str =~ /^DEBUG$/i ) {
6245 0           $lvls_str = 'FATAL,ERROR,WARN,INFO,DEBUG';
6246 0           return $lvls_str;
6247             }
6248 0 0         if ( $lvls_str =~ /^NONE$/i ) {
6249 0           $lvls_str = '';
6250 0           return $lvls_str;
6251             }
6252 0           sys_die( 'Invalid logging/notification severity level', 0 );
6253             }
6254 0           return 0;
6255             }
6256              
6257             sub _sys_check_log_gdg {
6258             =begin wiki
6259              
6260             !3 _sys_check_log_gdg
6261              
6262             Parameters: ( p1, p2, p3 )
6263              
6264             Please write this documentation.
6265              
6266             Returns:
6267              
6268             =cut
6269 0 0   0     if ( $opt_log_gdg =~ /[0-9]{1,3}/ ) {
6270 0           sys_die( 'Invalid log gdg specified', 0 );
6271             }
6272 0           return $opt_log_gdg;
6273             }
6274              
6275             sub _sys_check_log_radix {
6276             =begin wiki
6277              
6278             !3 _sys_check_log_radix
6279              
6280             Parameters: ( p1, p2, p3 )
6281              
6282             Please write this documentation.
6283              
6284             Returns:
6285              
6286             =cut
6287 0 0 0 0     if ( $opt_log_radix < 1 || $opt_log_radix > 4 ) {
6288 0           sys_die( 'Invalid log radix specified', 0 );
6289             }
6290 0           return $opt_log_radix;
6291             }
6292              
6293             sub _sys_check_de_override {
6294             =begin wiki
6295              
6296             !3 _sys_check_de_override
6297              
6298             Parameters: ( p1, p2, p3 )
6299              
6300             Please write this documentation.
6301              
6302             Returns:
6303              
6304             =cut
6305 0     0     my $tmp_jobname = shift;
6306 0           my $tmp_jobconf_file = $tmp_jobname;
6307 0           my $delist = $conf_de{jobname}{$tmp_jobname};
6308 0 0         if ( $delist ) { ## possible override of job conf
6309 0           my $de = '0000';
6310 0 0         if ( $delist =~ /(\d\d\d\d\d)\s?$/ ) {
6311 0           $de = $1;
6312             }
6313 0           my $overenvs = $conf_de{$de}{'env'};
6314 0 0         if ( $overenvs =~ /$dataenvr/i ) {
6315             ## as a side-effect, sys_jobconf_override gets set here...
6316 0           $sys_jobconf_override = 1; ## so we know override is effective
6317 0           $tmp_jobconf_file .= ".$de";
6318             }
6319             }
6320 0           return $tmp_jobconf_file;
6321             }
6322              
6323             sub _sys_disp_logprev {
6324             =begin wiki
6325              
6326             !3 _sys_disp_logprev
6327              
6328             Parameters: ( p1, p2, p3 )
6329              
6330             Please write this documentation.
6331              
6332             Returns:
6333              
6334             =cut
6335 0 0   0     if ( $opt_log_file ) { $log_file = $opt_log_file; }
  0            
6336 0           $log_filefull = $path_log_dir . $log_file;
6337 0 0         if ( -e $log_filefull ) {
6338 0           print "Log: $log_filefull\n";
6339 0           system "cat $log_filefull";
6340 0           print "\n";
6341 0           exit 0;
6342             }
6343 0           print "No previous log file found\n\n";
6344 0           return 0;
6345             }
6346              
6347             sub _sys_disp_logarch {
6348             =begin wiki
6349              
6350             !3 _sys_disp_logarch
6351              
6352             Parameters: ( p1, p2, p3 )
6353              
6354             Please write this documentation.
6355              
6356             Returns:
6357              
6358             =cut
6359 0 0   0     if ( $opt_log_file ) { $log_file = $opt_log_file; }
  0            
6360 0           $log_filefull = $path_log_dir . $log_file;
6361 0           my @logs = glob $log_filefull . '.*';
6362 0 0         if ( @logs ) {
6363 0           foreach my $log ( sort @logs ) {
6364 0           print "Log: $log\n";
6365 0           system "cat $log";
6366             }
6367 0           print "\n";
6368 0           exit 0;
6369             }
6370 0           print "No archived log files found\n\n";
6371 0           return 0;
6372             }
6373              
6374             sub _sys_disp_jobs {
6375             =begin wiki
6376              
6377             !3 _sys_disp_jobs
6378              
6379             Parameters: ( p1, p2, p3 )
6380              
6381             Please write this documentation.
6382              
6383             Returns:
6384              
6385             =cut
6386 0     0     my @jobs = glob $path_bin_dir.'*.pl';
6387 0 0         if ( @jobs ) {
6388 0           foreach my $job ( sort @jobs ) {
6389 0           my $description = 'No description found';
6390 0 0         open my $fh, "<", $job or sys_die( "Unable to open $job", 0 );
6391 0           while ( <$fh> ) {
6392 0           chomp;
6393 0 0         if ( /^\#\#\$\$/ ) {
6394 0           $description = substr $_, 4;
6395             }
6396             }
6397 0           close $fh;
6398 0           $job =~ s{^\/.*\/}{};
6399 0           print "Job: $job\n";
6400 0           print " $description\n";
6401             }
6402 0           print "\n";
6403 0           exit 0;
6404             }
6405 0           print "No archived job files found\n\n";
6406 0           return 0;
6407             }
6408              
6409             sub _sys_disp_active_jobs {
6410             =begin wiki
6411              
6412             !3 _sys_disp_active_jobs
6413              
6414             Parameters: ( p1, p2, p3 )
6415              
6416             Please write this documentation.
6417              
6418             Returns:
6419              
6420             =cut
6421 0     0     my $logging = shift; ## needs implementing
6422              
6423 0           my @actjobs = glob $path_conf_dir.'/*.running';
6424 0           print 'Jobs currently active: ' . scalar @actjobs . "\n";
6425 0 0         if ( @actjobs ) {
6426 0           foreach my $job ( sort @actjobs ) {
6427 0           my $conf = new Config::IniFiles( -file => $job );
6428 0 0         unless ( defined $conf ) { sys_die( "Error opening $job" ); }
  0            
6429 0           my $pid = $conf->val( 'pid', 'pid' );
6430             ## NOTE: use Unix::PID to determine if pid is still runninng...
6431             ## If pid is no longer running, replace "Job:" with "???:".
6432 0           my $starttime = $conf->val( 'starttime', 'starttime' );
6433 0           my $fmtdtime = time2str( '%Y/%m/%d %T', $starttime );
6434 0           $job =~ s{^\/.*\/}{};
6435 0           $job =~ s{\.\d+\.running$}{};
6436 0           print "Job: $job\n";
6437 0           print " pid=$pid\n";
6438 0           print " starttime=$fmtdtime\n";
6439 0           $conf = undef;
6440             }
6441             }
6442 0           print "\n";
6443 0           exit 0;
6444             }
6445              
6446             sub _sys_disp_doc {
6447             =begin wiki
6448              
6449             !3 _sys_disp_doc
6450              
6451             Parameters: ( p1, p2, p3 )
6452              
6453             Please write this documentation.
6454              
6455             Returns:
6456              
6457             =cut
6458 0 0   0     if ( -e $script_filefull ) {
6459 0           my %podparams = (
6460             infile => $script_filefull,
6461             outfile => "STDOUT",
6462             );
6463 0           wikipod2text( %podparams );
6464             } else {
6465 0           print "File not found $script_filefull\n\n";
6466             }
6467 0           exit 0;
6468             }
6469              
6470             sub _sys_disp_sql {
6471             =begin wiki
6472              
6473             !3 _sys_disp_sql
6474              
6475             Parameters: ( p1, p2, p3 )
6476              
6477             Please write this documentation.
6478              
6479             Returns:
6480              
6481             =cut
6482 0     0     my @query_names = keys %{$conf_query{$jobname}};
  0            
6483 0 0         if ( @query_names ) {
6484 0           foreach my $query_name ( sort @query_names ) {
6485 0           my $query = $conf_query{$jobname}{$query_name};
6486 0           print "Query: $query_name\n";
6487 0           print $query;
6488 0           print "\n\n";
6489             }
6490             } else {
6491 0           print "No querys found\n\n";
6492             }
6493 0           exit 0;
6494             }
6495              
6496             sub _sys_disp_params {
6497             =begin wiki
6498              
6499             !3 _sys_disp_params
6500              
6501             Parameters: ( p1, p2, p3 )
6502              
6503             Please write this documentation.
6504              
6505             Returns:
6506              
6507             =cut
6508 0     0     my $dblen = 0;
6509 0           foreach my $db ( @databases ) {
6510 0 0         if ( length $dbname{$db} > $dblen ) { $dblen = length $dbname{$db}; }
  0            
6511             }
6512 0           print "\n" . uc($dataenvr) . " Database Connections:\n";
6513 0           foreach my $db ( @databases ) {
6514 0           my $dbstr = sprintf "%-${dblen}s", $dbname{$db};
6515 0           $dbstr .= ' = ' . $db . '/' . $dbdefenvr{$db};
6516 0           print " $dbstr\n",;
6517             }
6518              
6519 0           print "\n" . uc($dataenvr) . " Job Settings:\n";
6520 0           print " Job Name = ", $jobname, "\n";
6521 0           print " Log File = ", $log_file, "\n";
6522 0           print " Log Logging Levels = ", $log_logging_levels, "\n";
6523 0           print " Log Console Levels = ", $log_console_levels, "\n";
6524 0           print " Log Gdg = ", $log_gdg, "\n";
6525 0           print " Path Bin Dir = ", $path_bin_dir, "\n";
6526 0           print " Path Log Dir = ", $path_log_dir, "\n";
6527 0           print " Path Lib Dir = ", $path_lib_dir, "\n";
6528 0           print " Path Conf Dir = ", $path_conf_dir, "\n";
6529 0           print " Path Plugin Dir = ", $path_plugin_dir, "\n";
6530 0           print " Path Load Dir = ", $path_load_dir, "\n";
6531 0           print " path Extract Dir = ", $path_extr_dir, "\n";
6532 0           print " path Prev Dir = ", $path_prev_dir, "\n";
6533 0           print " path Scripts Dir = ", $path_scripts_dir, "\n";
6534 0           print " Mail Server = ", $mail_server, "\n";
6535 0           print " Mail Email From = ", $mail_from, "\n";
6536 0           print " Mail Email To = ", $mail_emailto, "\n";
6537 0           print " Mail Pager To = ", $mail_pagerto, "\n";
6538 0           print " Mail Email Levels = ", $mail_email_levels, "\n";
6539 0           print " Mail Pager Levels = ", $mail_pager_levels, "\n";
6540 0           print "\n";
6541 0           exit 0;
6542             }
6543              
6544             sub _sys_send_email_message {
6545             =begin wiki
6546              
6547             !3 _sys_send_email_message
6548              
6549             Parameters: ( p1, p2, p3 )
6550              
6551             Please write this documentation.
6552              
6553             Returns:
6554              
6555             =cut
6556 0     0     my $params = shift;
6557 0           my ($addrlist, $message) = split m/~/, $params;
6558 0           $mail_emailto = $addrlist;
6559 0           _log_send_mail($message, 'MESSAGE');
6560 0           exit 0;
6561             }
6562              
6563             sub _sys_send_pager_message {
6564             =begin wiki
6565              
6566             !3 _sys_send_pager_message
6567              
6568             Parameters: ( p1, p2, p3 )
6569              
6570             Please write this documentation.
6571              
6572             Returns:
6573              
6574             =cut
6575 0     0     my $params = shift;
6576 0           my ($addrlist, $message) = split m/~/, $params;
6577 0           $mail_pagerto = $addrlist;
6578 0           _log_send_page($message, 'MESSAGE');
6579 0           exit 0;
6580             }
6581              
6582             sub _sys_help {
6583             =begin wiki
6584              
6585             !3 _sys_help
6586              
6587             Parameters: ( p1, p2, p3 )
6588              
6589             Please write this documentation.
6590              
6591             Returns:
6592              
6593             =cut
6594 0     0     my $verbose = shift;
6595 0 0         $verbose = 0 unless $verbose;
6596 0           my $section;
6597              
6598 0 0         if ( $verbose == 0 ) {
6599 0           print "\nUSAGE\n $script_file [options]\n\n";
6600 0           print "Use option -h for help with options\n";
6601 0           print "Use option -hp for help with option parameters\n";
6602 0           print "Use option -man for system documentation\n";
6603 0           exit 1;
6604             }
6605              
6606 0 0         if ( $verbose == 1 ) { $section = 'OPTIONS'; };
  0            
6607 0 0         if ( $verbose == 2 ) { $section = 'ARGUMENTS'; };
  0            
6608              
6609 0           print "\n";
6610 0           my %podparams = (
6611             infile => $path_lib_dir."DBIx/JCL.pm",
6612             outfile => "STDOUT",
6613             section => $section,
6614             );
6615 0           wikipod2text( %podparams );
6616 0           exit 1;
6617             }
6618              
6619             sub _log_init_log_file {
6620             =begin wiki
6621              
6622             !3 _log_init_log_file
6623              
6624             Parameters: ( p1, p2, p3 )
6625              
6626             Please write this documentation.
6627              
6628             Returns:
6629              
6630             =cut
6631             ## log file rotation if generations > 0
6632 0 0 0 0     if ( -e $log_filefull && $log_gdg > 0 ) {
6633 0           _log_rotate();
6634             }
6635              
6636             ## create new locked log file
6637             ## if the file is already locked, will wait until the file is unlocked
6638 0 0         my $fh = new IO::LockedFile(">$log_filefull")
6639             or sys_die( 'Failed opening log file', 0 );
6640             ## close and unlock the file
6641 0           $fh->close();
6642              
6643 0           $sys_log_open = 1;
6644              
6645 0           return 0;
6646             }
6647              
6648             sub _log_write_to_log {
6649             =begin wiki
6650              
6651             !3 _log_write_to_log
6652              
6653             Parameters: ( p1, p2, p3 )
6654              
6655             Please write this documentation.
6656              
6657             Returns:
6658              
6659             =cut
6660 0     0     my ($level, $force, $msg, $exmsg) = @_;
6661 0           my ($message,$exmessage);
6662              
6663 0 0         if ( ref $exmsg eq 'ARRAY' ) {
6664 0           my $lead = ' ' x 18;
6665 0           $lead .= '+ ';
6666 0           my @output = map { $lead . $_ . "\n" } @{$exmsg};
  0            
  0            
6667 0           my $exmessage = join '', @output;
6668 0           $exmessage =~ s/\n$//ms;
6669 0           $message = $msg . "\n" . $exmessage;
6670             } else {
6671 0           $message = $msg;
6672 0           $message =~ s/\n/ /g;
6673             }
6674              
6675 0 0 0       if ( $log_logging_levels =~ /$level/ || $force ) {
6676 0           _log_print_log( $level, $message );
6677             }
6678              
6679 0           _log_send_notifications( $level, $force, $msg );
6680              
6681 0           return 0;
6682             }
6683              
6684             sub _log_write_to_screen {
6685             =begin wiki
6686              
6687             !3 _log_write_to_screen
6688              
6689             Parameters: ( p1, p2, p3 )
6690              
6691             Please write this documentation.
6692              
6693             Returns:
6694              
6695             =cut
6696 0     0     my ($level, $force, $msg, $exmsg) = @_;
6697 0           my ($message,$exmessage);
6698              
6699 0 0         if ( ref $exmsg eq 'ARRAY' ) {
6700 0           my $lead = ' ' x 18;
6701 0           $lead .= '+ ';
6702 0           my @output = map { $lead . $_ . "\n" } @{$exmsg};
  0            
  0            
6703 0           my $exmessage = join '', @output;
6704 0           $message = $msg . "\n" . $exmessage;
6705             } else {
6706 0           $message = $msg;
6707 0           $message =~ s/\n/ /g;
6708             }
6709              
6710 0           $message = _log_trim_msg( $message );
6711              
6712 0 0         if ( $opt_verbose ) {
6713 0           print "$message\n";
6714             } else {
6715 0 0 0       if ( $log_console_levels =~ /$level/ || $force ) {
6716 0           print "$message\n";
6717             }
6718             }
6719              
6720 0           return 0;
6721             }
6722              
6723             sub _log_print_log {
6724             =begin wiki
6725              
6726             !3 _log_print_log
6727              
6728             Parameters: ( p1, p2, p3 )
6729              
6730             Please write this documentation.
6731              
6732             Returns:
6733              
6734             =cut
6735 0     0     my ($level, $message) = @_;
6736              
6737 0           my $preamble = time2str( '%Y/%m/%d %T', time );
6738 0 0         if ( $level eq 'FATAL' ) { $preamble .= ' FATAL'; }
  0            
6739 0 0         if ( $level eq 'ERROR' ) { $preamble .= ' ERROR'; }
  0            
6740 0 0         if ( $level eq 'WARN' ) { $preamble .= ' WARNING'; }
  0            
6741              
6742             ## open locked log file for appending
6743             ## if the file is already locked, will wait until the file is unlocked
6744 0 0         my $fh = new IO::LockedFile(">>$log_filefull")
6745             or sys_die( 'Failed opening log file', 0 );
6746 0           print {$fh} "$preamble $message\n";
  0            
6747             ## close and unlock the file
6748 0           $fh->close();
6749 0           return 0;
6750             }
6751              
6752             sub _log_trim_msg {
6753             =begin wiki
6754              
6755             !3 _log_trim_msg
6756              
6757             Parameters: ( message )
6758              
6759             Format log file text so that it looks good when printed to STDOUT. This \
6760             function is only called from the logging functions. This takes message \
6761             text that was previously retrieved by dbms_output_get and stringified by \
6762             a logging function and removes the leading whitespace from each line of \
6763             text, if there is any. This is made necessary due to the fact that this \
6764             text started life as an array of lines retrieved from dbms_output_get(), \
6765             and each of these lines had leading whitespace to make them more readable \
6766             in the log file.
6767              
6768             Returns:
6769              
6770             =cut
6771 0     0     my $msg = shift;
6772 0           my $trimmed = '';
6773 0 0         if ( $msg =~ /\n/ms ) { ## trim leading spaces from multi-line messages
6774 0           foreach my $m ( split m/\n/, $msg ) {
6775 0           $m =~ s/^\s+//;
6776 0           $trimmed .= $m."\n";
6777             }
6778 0           $trimmed =~ s/\n$//ms;
6779             } else {
6780 0           $trimmed = $msg;
6781             }
6782 0           return $trimmed;
6783             }
6784              
6785             sub _log_send_notifications {
6786             =begin wiki
6787              
6788             !3 _log_send_notifications
6789              
6790             Parameters: ( message, severity_level )
6791              
6792             Send email and pager notifications based on supplied severity. If the \
6793             severity levels for email and or pager notifications are at or below the \
6794             severity level supplied to this function, a notification will be sent.
6795              
6796             Note: if running under test harness (different than test mode), all \
6797             messages are logged, but no notifications of any severity will be generated. \
6798             Generation of actual email and pager notices is not testable using the test \
6799             harness.
6800              
6801             Returns:
6802              
6803             =cut
6804 0     0     my ($level, $force, $message) = @_;
6805              
6806             # if ( $tst_harness ) {
6807             # return 0;
6808             # }
6809              
6810 0 0 0       if ( $mail_email_levels =~ /$level/ || $force ) {
6811 0           _log_send_mail( $message, $level );
6812             }
6813 0 0 0       if ( $mail_pager_levels =~ /$level/ || $force ) {
6814 0           _log_send_page( $message, $level );
6815             }
6816 0           return 0;
6817             }
6818              
6819             sub _log_send_mail {
6820             =begin wiki
6821              
6822             !3 _log_send_mail
6823              
6824             Parameters: ( p1, p2, p3 )
6825              
6826             Please write this documentation.
6827              
6828             Returns:
6829              
6830             =cut
6831 0     0     my ($message, $severity) = @_;
6832 0 0         return 0 unless $mail_emailto;
6833 0 0         return 0 if $mail_emailto =~ /NONE/i;
6834              
6835 0           my ($subject, $job);
6836              
6837 0 0         if ( $severity eq 'MESSAGE' ) {
6838 0           $subject = 'Message from ' . uc $dataenvr;
6839             } else {
6840 0           $subject = uc($dataenvr). ' Batch Notice';
6841 0           $message = time2str("%Y/%m/%d %H:%M:%S : ", time) . uc($severity) . " : $script_file : $message";
6842             }
6843              
6844             ## get the log file contents and append to message
6845 0 0         if ( ! $severity eq 'MESSAGE' ) {
6846 0 0         if ( -e $log_filefull ) {
6847 0           $message .= "\nLog Entries:\n";
6848 0           open my $fh, "<", $log_filefull;
6849 0           while ( <$fh> ) {
6850 0           $message .= $_;
6851             }
6852 0           close $fh;
6853             }
6854             }
6855              
6856 0           MIME::Lite->send('smtp', $mail_server, Timeout => 60);
6857              
6858 0           my $msg = MIME::Lite->new(
6859             From => $mail_from,
6860             To => $mail_emailto,
6861             Subject => $subject,
6862             Data => $message
6863             );
6864 0           $msg->send;
6865 0           return 0;
6866             }
6867              
6868             sub _log_send_page {
6869             =begin wiki
6870              
6871             !3 _log_send_page
6872              
6873             Parameters: ( p1, p2, p3 )
6874              
6875             Please write this documentation.
6876              
6877             Returns:
6878              
6879             =cut
6880 0     0     my ($message, $severity) = @_;
6881 0 0         return 0 unless $mail_pagerto;
6882 0 0         return 0 if $mail_pagerto =~ /NONE/i;
6883              
6884 0           my ($subject, $job);
6885              
6886 0 0         if ( $severity eq 'MESSAGE' ) {
6887 0           $subject = 'Message from ' . uc $dataenvr;
6888             } else {
6889 0           my $subject = uc($dataenvr). ' Batch Notice';
6890 0           $message = time2str("%Y/%m/%d %H:%M:%S : ", time) . uc($severity) . " : $script_file : $message";
6891             }
6892              
6893 0           MIME::Lite->send('smtp', $mail_server, Timeout => 60);
6894              
6895 0           my $msg = MIME::Lite->new(
6896             From => $mail_from,
6897             To => $mail_pagerto,
6898             Subject => $subject,
6899             Data => $message
6900             );
6901 0           $msg->send;
6902 0           return 0;
6903             }
6904              
6905             sub _log_rotate {
6906             =begin wiki
6907              
6908             !3 _log_rotate
6909              
6910             Parameters: ( p1, p2, p3 )
6911              
6912             Please write this documentation.
6913              
6914             Returns:
6915              
6916             =cut
6917 0     0     my ($prev,$next,$i,$j);
6918              
6919 0           my $curr = $log_filefull;
6920 0           my $currn = $curr;
6921              
6922 0           for ($i = $log_gdg; $i > 1; $i--) {
6923 0           $j = $i - 1;
6924 0           my $nextgen = sprintf("%0${log_radix}d", $i);
6925 0           my $prevgen = sprintf("%0${log_radix}d", $j);
6926 0           $next = "${currn}." . $nextgen; ##. $ext;
6927 0           $prev = "${currn}." . $prevgen; ##. $ext;
6928 0 0 0       if ( -r $prev && -f $prev ) {
6929 0 0         move($prev,$next) or sys_die( "Log move failed: ($prev,$next)" );
6930             }
6931             }
6932              
6933             ## copy current to next incremental
6934 0           my $nextgen = sprintf("%0${log_radix}d", 1);
6935 0           $next = "${currn}." . $nextgen;
6936 0           copy($curr, $next);
6937              
6938             ## preserve permissions and status
6939 0           my @stat = stat $curr;
6940 0 0         chmod( $stat[2], $next ) or sys_warn( "log chmod failed: ($next)" );
6941 0 0         utime( $stat[8], $stat[9], $next ) or sys_warn( "log utime failed: ($next)" );
6942 0 0         chown( $stat[4], $stat[5], $next ) or sys_warn( "log chown failed: ($next)" );
6943              
6944             ## now truncate the file
6945 0 0         truncate $curr, 0 or sys_die( "Could not truncate $curr" );
6946              
6947 0           return 0;
6948             }
6949              
6950             sub _db_connect_check_dependent {
6951             =begin wiki
6952              
6953             !3 _db_connect_check_dependent
6954              
6955             Parameters: ( p1, p2, p3 )
6956              
6957             Please write this documentation.
6958              
6959             Returns:
6960              
6961             =cut
6962 0     0     my ($dependent_jobname,$wait_duration,$wait_max_secs,$wait_action) = @_;
6963 0           my $starttime = time;
6964 0           while ( 1 ) {
6965 0 0         if ( _sys_job_dependent($dependent_jobname) ) {
6966 0           sleep $wait_duration;
6967 0           my $curtime = time;
6968 0 0         if ( $curtime - $starttime > $wait_max_secs ) {
6969 0 0         if ( $wait_action =~ m/^run$/ix ) {
6970 0           log_info( "Maximum dependent job wait time exceeded, starting" );
6971 0           last;
6972             } else {
6973 0           sys_die( "Maximum dependent job wait time exceeded, aborting" );
6974 0           return 1; ## reachable if $sys_test_harness
6975             }
6976             }
6977             } else {
6978 0           last;
6979             }
6980             }
6981 0           return 0;
6982             }
6983              
6984             sub _db_connect_retry {
6985             =begin wiki
6986              
6987             !3 _db_connect_retry
6988              
6989             Parameters: ( p1, p2, p3 )
6990              
6991             Please write this documentation.
6992              
6993             Returns:
6994              
6995             =cut
6996 0     0     my ($db,$un,$pw,$retry_duration,$retry_max_secs) = @_;
6997 0           my $dbh = 0;
6998 0           my $starttime = time;
6999 0           while ( 1 ) {
7000 0           $dbh = DBI->connect( $db, $un, $pw, { RaiseError => 0, AutoCommit => 0 } );
7001 0 0         if ( DBI->errstr ) {
7002 0 0         if ( $retry_max_secs < 1 ) {
7003 0           sys_die( DBI->errstr );
7004 0           return 1; ## reachable if $sys_test_harness
7005             }
7006 0 0         if ( DBI->err == 1017 ) { ## ora invalid account or password
7007 0           sys_die( DBI->errstr );
7008 0           return 1; ## reachable if $sys_test_harness
7009             }
7010 0           log_info( DBI->errstr );
7011 0           log_info( "Connection retry requested, waiting" );
7012 0           sleep $retry_duration;
7013 0           my $curtime = time;
7014 0 0         if ( $curtime - $starttime > $retry_max_secs ) {
7015 0           sys_die( "Maximum connection retry time exceeded, aborting" );
7016 0           return 1; ## reachable if $sys_test_harness
7017             }
7018             } else {
7019 0           last;
7020             }
7021             }
7022 0           return $dbh;
7023             }
7024              
7025             sub _db_vdn {
7026             =begin wiki
7027              
7028             !3 _db_vdn
7029              
7030             Parameters: ( caller_id_string, vdn )
7031              
7032             This function accepts a caller id string and a virtual database name. A \
7033             virtual database name is a text string which identifies a database \
7034             connection. If we are running in test mode and the caller is not the \
7035             db_connect function, this function will gracefully shut-down. Otherwise \
7036             it returns either raw database connection information or it returns the \
7037             appropriate database handle and statement handle for the named database.
7038              
7039             Returns:
7040              
7041             =cut
7042 0     0     my ($caller, $vdn) = @_;
7043              
7044 0           my $sth_name = 'sth_default'; ## default statement handle name
7045              
7046             ## does vdn contains explicit statement handle?
7047 0 0         if ( $vdn =~ /\./ ) {
7048 0           ($vdn, $sth_name) = split /\./, $vdn;
7049             }
7050              
7051 0           my ($this_db, $this_inst);
7052              
7053 0 0         if ( $vdn =~ m/:/x ) { ## does vdn contain explicit instance?
7054 0           ($this_db, $this_inst) = split m/:/, $vdn;
7055             } else {
7056 0           $this_db = $vdn;
7057 0           $this_inst = $dbdefenvr{$vdn};
7058             }
7059              
7060 0 0         if ( ! $dbname{$this_db} ) {
7061 0           sys_die( "Virtual database name [$vdn] is invalid" );
7062             }
7063              
7064             ## special return values if caller is 'connect'
7065 0 0         if ( $caller eq 'connect' ) {
7066 0           my $database = $dbconn{$this_db}{$this_inst}{'database'};
7067 0           my $username = $dbconn{$this_db}{$this_inst}{'username'};
7068 0           my $password = $dbconn{$this_db}{$this_inst}{'password'};
7069 0           return ($database, $username, $password);
7070             }
7071              
7072             # ## shutdown gracefully if running under the 'test connections' flag
7073             # if ( $opt_test ) {
7074             # log_close( "End connection test: $jobname" );
7075             # sys_end();
7076             # exit 0;
7077             # }
7078              
7079             ## return database and statement handles for this vdn
7080 0           my $dbh = $dbhandles{$this_db}{'dbh'};
7081 0           my $sth = $dbhandles{$vdn}{$sth_name};
7082 0           return ($dbh, $sth);
7083             }
7084              
7085             sub _db_netservice {
7086             =begin wiki
7087              
7088             !3 _db_netservice
7089              
7090             Parameters: ( vdn )
7091              
7092             This function accepts a virtual database name that contains an explicit \
7093             instance. A virtual database name is a text string which identifies a \
7094             database connection. The "network service", i.e., remote database \
7095             connection string is returned from sys_data.conf for the provided instance.
7096              
7097             Returns:
7098              
7099             =cut
7100 0     0     my ($vdni) = shift;
7101              
7102 0           my $netservice = '';
7103              
7104 0 0         if ( $vdni =~ m/:/x ) { ## vdn contains instance definiton
7105 0           my ($db, $inst) = split m/:/, $vdni;
7106 0 0         _check_array_val( $db, \@databases )
7107             || sys_die( "Invalid database: [$db]", 0 );
7108 0 0         _check_array_val( $inst, [split m/,/, $dbinst{$db}] )
7109             || sys_die( "Invalid database instance: [$db.$inst]", 0 );
7110 0           $netservice = $dbconn{$db}{$inst}{netservice};
7111             }
7112              
7113 0           return $netservice;
7114             }
7115              
7116             sub _db_proc_build_sql {
7117             =begin wiki
7118              
7119             !3 _db_proc_build_sql
7120              
7121             Parameters: ( package_name, procedure_name, parameters)
7122              
7123             * /parameters/ - parameters is a reference to an array
7124              
7125             This function builds a sql statement to execute an Oracle Stored Procedure. \
7126             The sql statement uses generated variable names, e.g., :p1, :p2, :p3, etc. \
7127             This works because functions that use this sql statement all pass parameters \
7128             to the requested stored procedure positionally. The function accepts a \
7129             reference to an array of param in parameters. This is used only to get a \
7130             count of the number of parameters in the procedure's signature.
7131              
7132             Returns:
7133              
7134             =cut
7135 0     0     my ($package, $proc_name, $params) = @_;
7136 0           my $numparams = scalar @{$params};
  0            
7137 0 0         if ( $package ) { $proc_name = $package . '.' . $proc_name; }
  0            
7138              
7139 0           my $sql = 'BEGIN ' . $proc_name . '(';
7140 0           for my $i ( 0 .. $numparams - 1 ) {
7141 0           $sql .= ':p'.$i;
7142 0 0         if ( $i < $numparams - 1 ) { $sql .= ','; }
  0            
7143             }
7144 0           $sql .= '); END;';
7145 0           return $sql;
7146             }
7147              
7148             sub _db_sqlloaderx_parse_logfile {
7149             =begin wiki
7150              
7151             !3 _db_sqlloaderx_parse_logfile
7152              
7153             Parameters: ( p1, p2, p3 )
7154              
7155             Please write this documentation.
7156              
7157             Returns:
7158              
7159             =cut
7160 0     0     my $logfile = shift;
7161 0           %sqlloader_results = (); ## hash of SQL*Loader results
7162              
7163             ## default values
7164 0           $sqlloader_results{'skipped'} = "Problem obtaining value";
7165 0           $sqlloader_results{'read'} = $sqlloader_results{'skipped'};
7166 0           $sqlloader_results{'rejected'} = $sqlloader_results{'skipped'};
7167 0           $sqlloader_results{'discarded'} = $sqlloader_results{'skipped'};
7168 0           $sqlloader_results{'elapsed_time'} = $sqlloader_results{'skipped'};
7169 0           $sqlloader_results{'cpu_time'} = $sqlloader_results{'skipped'};
7170              
7171 0           my $log = new IO::File "<$logfile";
7172 0 0         if (! defined $log) {
7173 0           sys_warn( "Failed to open SQL*Loader log file $logfile" );
7174 0           return 1;
7175             }
7176              
7177             ## skip the first line, check the second for the SQL*Loader declaration
7178 0           my $line = <$log>;
7179 0           $line = <$log>;
7180 0 0         unless ($line =~ /^SQL\*Loader/) {
7181 0           sys_warn( 'File does not appear to be a valid SQL*Loader log file' );
7182 0           return 1;
7183             }
7184              
7185 0           while (<$log>) {
7186 0           chomp;
7187 0 0         if ( m/^Total logical records skipped:\s+(\d+)/ ) {
7188 0           $sqlloader_results{'skipped'} = $1;
7189 0           next;
7190             }
7191 0 0         if ( m/^Total logical records read:\s+(\d+)/ ) {
7192 0           $sqlloader_results{'read'} = $1;
7193 0           next;
7194             }
7195 0 0         if ( m/^Total logical records rejected:\s+(\d+)/ ) {
7196 0           $sqlloader_results{'rejected'} = $1;
7197 0           next;
7198             }
7199 0 0         if ( m/^Total logical records discarded:\s+(\d+)/ ) {
7200 0           $sqlloader_results{'discarded'} = $1;
7201 0           next;
7202             }
7203 0 0         if( m/^Elapsed time was:\s+(.+)/ ) {
7204 0           $sqlloader_results{'elapsed_time'} = $1;
7205 0           next;
7206             }
7207 0 0         if( m/^CPU time was:\s+(.+)/ ) {
7208 0           $sqlloader_results{'cpu_time'} = $1;
7209 0           next;
7210             }
7211             }
7212              
7213 0           $log->close;
7214              
7215 0           my @results;
7216              
7217 0           push @results, "Skipped: " . $sqlloader_results{'skipped'};
7218 0           push @results, "Read: " . $sqlloader_results{'read'};
7219 0           push @results, "Rejected: " . $sqlloader_results{'rejected'};
7220 0           push @results, "Discarded: " . $sqlloader_results{'discarded'};
7221 0           push @results, "Elapsed Time: " . $sqlloader_results{'elapsed_time'};
7222 0           push @results, "CPU Time: " . $sqlloader_results{'cpu_time'};
7223              
7224             ## return ref to array of results
7225 0           return \@results;
7226             }
7227              
7228             sub _db_proc_bind_inparams {
7229             =begin wiki
7230              
7231             !3 _db_proc_bind_inparams
7232              
7233             Parameters: ( statement_handle, parameters )
7234              
7235             This function binds parameters to a prepared statement. The parameters are \
7236             passed as a ref to an array. This uses the same parameter names as those \
7237             defined by the build_sql function. All parameters are bound as type IN \
7238             parameters.
7239              
7240             Returns:
7241              
7242             =cut
7243 0     0     my ($sth, $params) = @_;
7244 0           my $numparams = scalar @{$params};
  0            
7245              
7246 0           for my $i ( 0 .. $numparams - 1 ) {
7247 0           my $var = ':p'.$i;
7248 0           $sth->bind_param( $var, ${$params}[$i] );
  0            
7249             }
7250 0           return $sth;
7251             }
7252              
7253             sub _db_proc_bind_outparams {
7254             =begin wiki
7255              
7256             !3 _db_proc_bind_outparams
7257              
7258             Parameters ( )
7259              
7260             This function binds parameters to a prepared statement. The parameters are \
7261             passed as a ref to an array. This uses the same parameter names as those \
7262             defined by the build_sql function. All parameters are bound as type IN \
7263             OUT/OUT parameters.
7264              
7265             Returns:
7266              
7267             =cut
7268 0     0     my ($sth, $params) = @_;
7269 0           my $numparams = scalar @{$params};
  0            
7270              
7271 0           for my $i ( 0 .. $numparams - 1 ) {
7272 0           my $var = ':p'.$i;
7273 0           $sth->bind_param_inout( $var, @{$params}[$i], 100 );
  0            
7274             }
7275 0           return $sth;
7276             }
7277              
7278             sub _db_proc_bind_inoutparams {
7279             =begin wiki
7280              
7281             !3 _db_proc_bind_inoutparams
7282              
7283             Parameters: ( )
7284              
7285             This function binds parameters to a prepared statement. The parameters are \
7286             passed as a ref to an array. This uses the same parameter names as those \
7287             defined by the build_sql function. All parameters are bound as type IN or \
7288             as type IN OUT/OUT. If the user passes a ref as an array member, that element \
7289             will be bound as IN OUT/OUT. If the users passes a scalar as an array member, \
7290             that element will be bound as a type IN parameter.
7291              
7292             Returns:
7293              
7294             =cut
7295 0     0     my ($sth, $params) = @_;
7296 0           my $numparams = scalar @{$params};
  0            
7297              
7298 0           for my $i ( 0 .. $numparams - 1 ) {
7299 0           my $var = ':p'.$i;
7300 0 0         if ( ref @{$params}[$i] eq 'SCALAR' ) {
  0            
7301 0           $sth->bind_param_inout( $var, @{$params}[$i], 100 );
  0            
7302             } else {
7303 0           $sth->bind_param( $var, ${$params}[$i] );
  0            
7304             }
7305             }
7306 0           return $sth;
7307             }
7308              
7309             sub _db_is_oracle {
7310             =begin wiki
7311              
7312             !3 _db_is_oracle
7313              
7314             Parameters: ( p1, p2, p3 )
7315              
7316             Please write this documentation.
7317              
7318             Returns:
7319              
7320             =cut
7321 0     0     my $vdn = shift;
7322 0           my $inst = $dbdefenvr{$vdn};
7323 0           my $database = $dbconn{$vdn}{$inst}{'database'}; ## e.g., dbi:Oracle:myinst
7324 0 0         if ( $database=~ /^dbi:Oracle:/ ) {
7325 0           return 1;
7326             }
7327 0           return 0;
7328             }
7329              
7330             sub _db_null {
7331             =begin wiki
7332              
7333             !3 _db_null
7334              
7335             Parameters: ( p1, p2, p3 )
7336              
7337             Please write this documentation.
7338              
7339             Returns:
7340              
7341             =cut
7342 0     0     my $val = shift;
7343 0 0         return '' unless defined $val;
7344 0           return $val;
7345             }
7346              
7347             sub _db_query_to_file_protect {
7348             =begin wiki
7349              
7350             !3 _db_query_to_file_protect
7351              
7352             Parameters: ( p1, p2, p3 )
7353              
7354             Please write this documentation.
7355              
7356             Returns:
7357              
7358             =cut
7359 0     0     my ($row, $protect) = @_;
7360              
7361 0 0         return 0 if scalar @{$protect} < 1;
  0            
7362              
7363 0           foreach my $i ( @{$protect} ) {
  0            
7364 0           my $len = length @{$row}[$i];
  0            
7365 0           my $fil = '*'x$len;
7366 0           @{$row}[$i] = $fil;
  0            
7367             }
7368              
7369 0           return 0;
7370             }
7371              
7372             sub _check_array_val {
7373             =begin wiki
7374              
7375             !3 _check_array_val
7376              
7377             Parameters: ( p1, p2, p3 )
7378              
7379             Please write this documentation.
7380              
7381             Returns:
7382              
7383             =cut
7384 0     0     my ($val, $arr) = @_;
7385 0 0         if ( grep { $_ eq $val } @{$arr} ) {
  0            
  0            
7386 0           return 1;
7387             }
7388 0           return 0;
7389             }
7390              
7391             sub _trim {
7392             =begin wiki
7393              
7394             !3 _trim
7395              
7396             Parameters: ( str )
7397              
7398             Trim leading and trailing spaces from a string. Return the trimmed string.
7399              
7400             Returns:
7401              
7402             =cut
7403 0     0     my $str = shift;
7404 0           $str =~ s/^\s+//;
7405 0           $str =~ s/\s+$//;
7406 0           return $str;
7407             }
7408              
7409             sub _trim_lead {
7410             =begin wiki
7411              
7412             !3 _trim_lead
7413              
7414             Parameters: ( str )
7415              
7416             Trim leading spaces from a string. Return the trimmed string.
7417              
7418             =cut
7419 0     0     my $str = shift;
7420 0           $str =~ s/^\s+//;
7421 0           return $str;
7422             }
7423              
7424             sub _trim_trail {
7425             =begin wiki
7426              
7427             !3 _trim_trail
7428              
7429             Parameters: ( str )
7430              
7431             Trim trailing spaces from a string. Return the trimmed string.
7432              
7433             Results:
7434              
7435             =cut
7436 0     0     my $str = shift;
7437 0           $str =~ s/\s+$//;
7438 0           return $str;
7439             }
7440              
7441             sub _is_yes {
7442             =begin wiki
7443              
7444             !3 _is_yes
7445              
7446             Parameters: ( str )
7447              
7448             Examing a string and determine if the string indicates 'YES'. The string is \
7449             examined as case insensitive and must be either a 'y' or 'yes'. If so, the \
7450             function returns true (1), otherwise it returns false (0).
7451              
7452             You can use this as a conversion function to make tests simpler using a \
7453             technique like this:
7454              
7455             % language=Perl
7456             % my $truth = 'Y';
7457             % $truth = _is_yes( $truth );
7458             % # later
7459             % if ( $truth ) {
7460             % # do something
7461             % }
7462             %%
7463              
7464             =cut
7465 0     0     my $str = shift;
7466 0 0         if ( $str =~ /^y$|^yes$/i ) { return 1; }
  0            
7467 0           return 0;
7468             }
7469              
7470             sub _is_no {
7471             =begin wiki
7472              
7473             !3 _is_no
7474              
7475             Parameters: ( str )
7476              
7477             Examing a string and determine if the string indicates 'NO'. The string is \
7478             examined as case insensitive and must be either a 'n' or 'no' exactly. If so, \
7479             the function returns true (1), otherwise it returns false (0).
7480              
7481             Returns:
7482              
7483             =cut
7484 0     0     my $str = shift;
7485 0 0         if ( $str =~ /^n$|^no$/i ) { return 1; }
  0            
7486 0           return 0;
7487             }
7488              
7489             sub END {
7490             =begin wiki
7491              
7492             !3 END
7493              
7494             Parameters: None
7495              
7496             Close all open statement handles and database handles. Statement handles and \
7497             Database handles are stored for us by the database connection function. The \
7498             end function in each loaded plugin is also called here. They are called in \
7499             reverse load order. Send exit notifications if any have been requested.
7500              
7501             Returns:
7502              
7503             =cut
7504             ## remove job information from sys_environment.conf
7505 1     1   854 _sys_job_end();
7506              
7507             ## disconnect any open database handles
7508 1         4 foreach my $vdn ( keys %dbhandles ) {
7509 0         0 my $dbh = $dbhandles{$vdn}{'dbh'};
7510 0         0 my $sth = $dbhandles{$vdn}{'sth'};
7511 0 0 0     0 if ( defined $sth && $sth ) { $sth->finish; }
  0         0  
7512 0 0 0     0 if ( defined $dbh && $dbh ) { $dbh->disconnect; }
  0         0  
7513             }
7514              
7515             ## call plugin end functions
7516 1         4 while ( my $pluginf = pop @plugins ) {
7517 0         0 my ($pp, $pf, $pff) = split m/~/, $pluginf;
7518 0         0 $pp->end();
7519             }
7520              
7521             ## send completion notifications
7522 1 50       3 unless ( defined $jobname ) { $jobname = '?'; }
  0         0  
7523 1         4 my $msg = "Job $jobname ($script_file) has completed ($errorlevel).";
7524 1 50       3 if ( $opt_notify_email_oncomp ) {
7525 0         0 _log_send_mail($msg, 'MESSAGE' );
7526             }
7527 1 50       9 if ( $opt_notify_pager_oncomp ) {
7528 0         0 _log_send_page($msg, 'MESSAGE' );
7529             }
7530             }
7531              
7532             1;
7533              
7534             =begin wiki
7535              
7536             ----
7537              
7538             !1 Dependencies
7539              
7540             The following modules are all used by DBIx-JCL.
7541              
7542             * English
7543             * Getopt::Long
7544             * Config::IniFiles
7545             * IO::File
7546             * IO::Handle
7547             * IO::LockedFile
7548             * Fcntl
7549             * File::Copy
7550             * File::Bidirectional
7551             * File::Basename
7552             * MIME::Lite
7553             * Date::Format
7554             * Pod::WikiText
7555             * DBI
7556              
7557             ----
7558              
7559             !1 Incompatibilities
7560              
7561             None currently documented. Please feel free to notify the author if you have \
7562             concern that you would like to see addressed.
7563              
7564             ----
7565              
7566             !1 Test Support
7567              
7568             There are a number of test functions built-in to DBIx-JCL. Please see the \
7569             function reference section for descriptions of all the testing functions.
7570              
7571             ----
7572              
7573             !1 Tips
7574              
7575             Here are some tips for using job scripts. (A job script is any perl script \
7576             that uses the DBIx-JCL Module.
7577              
7578             !2 Verbose and Very Verbose
7579              
7580             If you are running jobs from the console and you want tactile feedback, use \
7581             the Verbose C<-v> option. If your job is failing and your not sure why, turn \
7582             on the Very Verbose C<-vv> option. Very Verbose gives you everything that \
7583             Verbose gives you, plus more.
7584              
7585             !2 Required Options
7586              
7587             A "Run job" option is always required. This is to avoid accidentally invoking \
7588             a job script.
7589              
7590             !2 Built-in Display Features
7591              
7592             There are several built-in display features that you will find useful. When \
7593             you use the Help option, C<-h> and C<-ha>, these will be listed under the \
7594             heading of "Information Options". The most useful is possibly the C<-dl> \
7595             option, which will display the last log file generated by the script that you \
7596             are currently running.
7597              
7598             !2 Use the Test Options
7599              
7600             Use the /-t/ option to invoke the job script and run it to the point of \
7601             database connection and then exit after database connections have been made.
7602              
7603             Use the /-tc/ option to test any database connection interactively without \
7604             invoking the current job script. Very handy for diagnostic purposes.
7605              
7606             !2 Multiple Database Connections
7607              
7608             You can set up jobs that make multiple connections to the same database. To \
7609             do that, you simply add another set of connection parameters in your data.conf \
7610             file. So if for example you have a database named 'xyz1' in your list of \
7611             databases in %data.conf%, add another database named 'xyz2' and duplicate all \
7612             other connection parameters from 'xyz1' under the new key 'xyz2'.
7613              
7614             !2 Global Variables
7615              
7616             There are a number of global variables that are automatically imported into \
7617             your script's namespace. These are listed below with a brief explanation of \
7618             each.
7619              
7620             * %$path_bin_dir # path to bin directory%
7621             * %$path_lib_dir # path to lib directory%
7622             * %$path_log_dir # path to log directory%
7623             * %$path_load_dir # path to load directory%
7624             * %$path_extr_dir # path to extract directo%ry
7625             * %$path_prev_dir # path to store previous vrsion files%
7626             * %$path_scripts_dir # path to scripts directory%
7627             * %$mail_server # mail server address%
7628             * %$mail_from # from email address%
7629             * %$mail_emailto # email to address list%
7630             * %$mail_pagerto # pager to address list%
7631             * %$mail_email_levels # log levels which initiate email notifications%
7632             * %$mail_pager_levels # log levels which initiate pager notifications%
7633             * %$log_file # log file filename%
7634             * %$log_filefull # full path to log filename%
7635             * %$log_logging_levels # log levels which initiate log mesages%
7636             * %$log_console_levels # log levels which initiate console messages%
7637             * %$log_gdg # number of log archive files to maintain%
7638              
7639             Default values for all of these are defined in system conf files. The value \
7640             of many of these can be set at runtime using command line options.
7641              
7642             A special global variable defines the current database environment. This is \
7643             the $dataenvr variable.
7644              
7645             ----
7646              
7647             !1 Source Code Validation
7648              
7649             In order to help maintain consistency across an entire library of job \
7650             scripts. Several aspects of script files are check for compliance before \
7651             the job will be executed. The following rules are checked before a job \
7652             will be run by DBIx-JCL
7653              
7654             /Header Checks/
7655              
7656             There must be valid %##@@% and %##$$% statements. These statements can be \
7657             used to help manage script libraries. The %##$$% statement is also used by \
7658             the display jobs option to provide a brief description of each job.
7659              
7660             /Documentation Checks/
7661              
7662             There needs to be valid Pod containing at least a DESCRIPTION section, a \
7663             RECOVERY NOTES section, and a DEPENDENCIES section in each job script.
7664              
7665             ----
7666              
7667             !1 File And Directory Permissions
7668              
7669             This information is here to document one approach to file and directory \
7670             permissions. You should not adopt these for your use without careful \
7671             consideration and testing.
7672              
7673             All files owned by the account which processes batch jobs should be set to \
7674             permission level 750, which will give owner rwx, group r-x, and all others no \
7675             access.
7676              
7677             % language=Ini_Files
7678             % >chmod 750 filename
7679             %
7680             % 7 - owner permissions (rwx) i.e., read & write & execute
7681             % 5 - group permissions (r-x) i.e., read & execute
7682             % 0 - world permissions (---) i.e., none
7683             %%
7684              
7685             All directories owned by the account which processes batch jobs should \
7686             normally be set to permission level 750.
7687              
7688             Permission reference table:
7689              
7690             |0 |--- |no access|
7691             |1 |--x |execute|
7692             |2 |-w- |write|
7693             |3 |-wx |write and execute|
7694             |4 |r-- |read|
7695             |5 |r-x |read and execute|
7696             |6 |rw- |read and write|
7697             |7 |rwx |read write execute (full access)|
7698              
7699             ----
7700              
7701             !1 Plugins
7702              
7703             DBIx-JCL supports plugin modules using a simple plugin architecture. This \
7704             will allow you to write your own modules and have them loaded at runtime to \
7705             provide additional functionality for your job scripts. For example, you might \
7706             want to write a module that uses http to turn off your web site before some \
7707             processing in your batch job occurs.
7708              
7709             Plugin modules are simple Perl modules with no exported functions or \
7710             variables. Here is a trivial example of a plugin module:
7711              
7712             % language=Perl
7713             % package TestPlugin1;
7714             %
7715             % use strict;
7716             % use warnings;
7717             %
7718             % my $tp_num = 0;
7719             %
7720             % sub start {
7721             % my ($path_conf_dir, $path_plugin_dir, $dataenvr) = @_;
7722             % $tp_num = 100;
7723             % print "TestPlugin1 start function\n";
7724             % }
7725             %
7726             % sub plugin_main {
7727             % my $n = shift;
7728             % $tp_num += $n;
7729             % return $tp_num;
7730             % }
7731             %
7732             % sub tp_add {
7733             % my $n = shift;
7734             % $tp_num += $n;
7735             % return $tp_num;
7736             % }
7737             %
7738             % sub end {
7739             % print "TestPlugin1 end function\n";
7740             % }
7741             %
7742             % 1;
7743             %%
7744              
7745             There are three functions that plugin modules are required to implement, a \
7746             C, a C, and an C. The start and end functions \
7747             are called automatically for you on load and script termination. The address \
7748             to the C function is returned to you when your plugin is \
7749             loaded. All of your plugin code can be implemented in C, or in \
7750             additional functions that you supply. The decision will vary depending on \
7751             your plugin's needs. All functions in your plugin module are callable, but \
7752             the symantics vary.
7753              
7754             !2 Loading your plugin
7755              
7756             Your plugin is loaded using the C function. This function \
7757             takes two parameters, The file name used by your plugin (without the .pm \
7758             extension) and the package name used by your plugin. All plugins need to be \
7759             installed in a plugins directory which has been specified in the system.conf \
7760             file. For example, if you created the plugin shown above and placed it in a \
7761             file named TestPlugin1.pm, you would load the plugin like this:
7762              
7763             sys_init_plugin( 'TestPlugin1', 'TestPlugin1' );
7764              
7765             or
7766              
7767             my $plugin1 = 'TestPlugin1';
7768             sys_init_plugin( $plugin1, $plugin1 );
7769              
7770             !2 Calling functions in plugin modules
7771              
7772             There are three ways (probably more) to call functions in your plugin.
7773              
7774             B>
7775              
7776             Use the fully qualified package name and function name.
7777              
7778             sys_init_plugin( 'TestPlugin1', 'TestPlugin1' );
7779              
7780             later
7781              
7782             TestPlugin1::tp_add(1);
7783              
7784             B>
7785              
7786             If you are going to call your plugin from serveral places in your script, \
7787             you might prefer to take this approach.
7788              
7789             sys_init_plugin( 'TestPlugin1', 'TestPlugin1' );
7790             my $plug_1 = \&TestPlugin1::tp_add;
7791              
7792             later
7793              
7794             $plug_1->(1);
7795              
7796             B>
7797              
7798             Probably the simplest approach it to implement as much of your plugin's code \
7799             as possible within the C function. Then use the supplied \
7800             coderef to execute your plugin.
7801              
7802             my $plug1 = sys_init_plugin( 'TestPlugin1', 'TestPlugin1' );
7803              
7804             later
7805              
7806             $plug1->(1);
7807              
7808             ----
7809              
7810             !1 Exported Variables
7811              
7812             The following variables are available for use in job scripts and are \
7813             exported by default.
7814              
7815             |!Variable |Mod?|Description|
7816             |%$path_bin_dir% |No |path to bin directory|
7817             |%$path_lib_dir% |No |path to lib directory|
7818             |%$path_log_dir% |No |path to log directory|
7819             |%$path_load_dir% |No |path to load data directory|
7820             |%$path_extr_dir% |No |path to extract data directory|
7821             |%$path_prev_dir% |No |path to previous version files|
7822             |%$path_scripts_dir% |No |path to scripts directory|
7823             |%$mail_server% |. |mail server|
7824             |%$mail_from% |. |mail from address|
7825             |%$mail_emailto% |. |email to address list|
7826             |%$mail_pagerto% |. |pager to address list|
7827             |%$mail_email_levels% |. |email severity/notification levels|
7828             |%$mail_pager_levels% |. |pager severity/notification levels|
7829             |%$log_file% |No |name of log file|
7830             |%$log_filefull% |No |full name including path of log file|
7831             |%$log_logging_levels% |. |severity levels for log file logging|
7832             |%$log_console_levels% |. |severity levels for console logging|
7833             |%$log_gdg% |. |number of generations for log archiving|
7834             |%$dataenvr% |No |environment variable which holds default datbase/instance |
7835             |%$commandline_ext% |No |extra command variables passed to job script|
7836             |%$errorlevel% |No |.|
7837              
7838             Variables with "No" should not be modified.
7839              
7840             ----
7841              
7842             !1 Bugs And Limitations
7843              
7844             Please report all bugs to the author. Every attempt will be made to \
7845             incorporate bug fixes into future releases of this package.
7846              
7847             ----
7848              
7849             !1 Author
7850              
7851             Brad Adkins brad.j.adkins@gmail.com.
7852              
7853             You may contact the author regarding this module at dbijcl@gmail.com.
7854              
7855             ----
7856              
7857             !1 License And Copyright
7858              
7859             Copyright (c) 2008, Brad Adkins. All rights reserved.
7860              
7861             This software may be freely distributed under the same terms as Perl itself.
7862              
7863             ----
7864             =cut