File Coverage

blib/lib/Win32/SqlServer/DTS/Package.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package Win32::SqlServer::DTS::Package;
2            
3             =head1 NAME
4            
5             Win32::SqlServer::DTS::Package - a Perl class to access Microsoft SQL Server 2000 DTS Packages
6            
7             =head1 SYNOPSIS
8            
9             use Win32::SqlServer::DTS::Package;
10            
11             # $OLE_package is an already instantied class using Win32::OLE
12             my $package = Win32::SqlServer::DTS::Package->new( $OLE_package );
13            
14             # prints the custom task name
15             print $custom_task->get_name, "\n";
16            
17             =head1 DESCRIPTION
18            
19             C is an class created to be used as a layer that represent a package object in DTS packages.
20            
21             =head2 EXPORT
22            
23             Nothing.
24            
25             =cut
26            
27 1     1   31494 use strict;
  1         4  
  1         44  
28 1     1   6 use warnings;
  1         1  
  1         33  
29 1     1   6 use Carp qw(confess);
  1         2  
  1         160  
30 1     1   7 use base qw(Class::Accessor Win32::SqlServer::DTS);
  1         3  
  1         1129  
31             use Win32::SqlServer::DTS::TaskFactory;
32             use Win32::SqlServer::DTS::Connection;
33             use Win32::OLE qw(in);
34             use Win32::SqlServer::DTS::DateTime;
35             use Win32::SqlServer::DTS::Package::Step;
36             use Hash::Util qw(lock_keys);
37             use File::Spec;
38             use Win32::SqlServer::DTS::TaskTypes;
39            
40             __PACKAGE__->follow_best_practice;
41             __PACKAGE__->mk_ro_accessors(
42             qw(creation_date creator_computer description log_file max_steps name id priority version_id )
43             );
44            
45             =head2 METHODS
46            
47             =head3 execute
48            
49             Execute all the steps available in the package.
50            
51             Requires that the C<_sibling> attribute exists and is defined correctly, otherwise method call will abort program
52             execution.get_connections
53            
54             Returns a array reference with C objects for error checking.
55            
56             =cut
57            
58             sub execute {
59            
60             my $self = shift;
61            
62             $self->get_sibling()->Execute();
63            
64             my $iterator = $self->get_steps();
65            
66             my @results;
67            
68             while ( my $step = $iterator->() ) {
69            
70             push( @results, $step->get_exec_error_info() );
71            
72             }
73            
74             return \@results;
75            
76             }
77            
78             =head3 get_steps
79            
80             Returns an iterator to get all steps defined inside the DTS package. Each call to the iterator (that is a code reference)
81             will return a C object until all steps are returned.
82            
83             =cut
84            
85             sub get_steps {
86            
87             my $self = shift;
88            
89             my $steps = $self->get_sibling()->Steps;
90             my $total = scalar( in($steps) );
91             my $counter = 0;
92            
93             return sub {
94            
95             return unless ( $counter < $total );
96            
97             my $step = ( in($steps) )[$counter];
98            
99             $counter++;
100            
101             return Win32::SqlServer::DTS::Package::Step->new($step);
102            
103             }
104            
105             }
106            
107             =head3 log_to_server
108            
109             Returns true or false (in Perl terms, this means 1 or 0 respectivally) if the "Log package execution to SQL Server" is
110             set.
111            
112             =cut
113            
114             sub log_to_server {
115            
116             my $self = shift;
117             return $self->{log_to_server};
118            
119             }
120            
121             =head3 auto_commit
122            
123             Returns true or false (in Perl terms, this means 1 or 0 respectivally) if the "Auto Commit Transaction property" is set.
124            
125             =cut
126            
127             sub auto_commit {
128            
129             my $self = shift;
130             return $self->{auto_commit};
131            
132             }
133            
134             =head3 new
135            
136             Expects a DTS.Package2 object as a parameter and returns a new C object.
137            
138             Not all properties from a DTS.Package2 will be available, specially the inner objects inside a DTS package will
139             be available only at execution of the respective methods. These methods may depend on the C<_sibling> attribute,
140             so one should not remove it before invoking those methods. The documentation tells where the method depends or
141             not on C<_sibling> attribute.
142            
143             =cut
144            
145             sub new {
146            
147             my $class = shift;
148             my $self = { _sibling => shift };
149            
150             bless $self, $class;
151            
152             $self->{auto_commit} = $self->get_sibling()->AutoCommitTransaction;
153             $self->{creator_computer} = $self->get_sibling()->CreatorComputerName;
154             $self->{description} = $self->get_sibling()->Description;
155             $self->{fail_on_error} = $self->get_sibling()->FailOnError;
156             $self->{log_file} = $self->get_sibling()->LogFileName;
157             $self->{max_steps} = $self->get_sibling()->MaxConcurrentSteps;
158             $self->{name} = $self->get_sibling()->Name;
159             $self->{id} = $self->get_sibling()->PackageID;
160             $self->{version_id} = $self->get_sibling()->VersionID;
161             $self->{nt_event_log} =
162             $self->{_sibling}->WriteCompletionStatusToNTEventLog;
163            
164             $self->{log_to_server} = $self->get_sibling()->LogToSQLServer;
165             $self->{explicit_global_vars} =
166             $self->get_sibling()->ExplicitGlobalVariables;
167            
168             $self->_set_lineage_opts();
169             $self->_set_priority();
170            
171             $self->{creation_date} =
172             Win32::SqlServer::DTS::DateTime->new( $self->get_sibling()->CreationDate );
173            
174             $self->{_known_tasks} = undef;
175            
176             lock_keys( %{$self} );
177            
178             return $self;
179            
180             }
181            
182             =head3 use_explicit_global_vars
183            
184             Returns true if the property "Explicit Global Variables" is set. Otherwise returns false.
185            
186             =cut
187            
188             sub use_explicit_global_vars {
189            
190             my $self = shift;
191             return $self->{explicit_global_vars};
192            
193             }
194            
195             =head3 use_event_log
196            
197             Returns true if the property "Write completation status to event log" is set. Otherwise returns false.
198            
199             =cut
200            
201             sub use_event_log {
202            
203             my $self = shift;
204             return $self->{nt_event_log};
205            
206             }
207            
208             =head3 fail_on_error
209            
210             Returns true if the property "Fail package on first error" is set. Otherwise returns false.
211            
212             =cut
213            
214             sub fail_on_error {
215            
216             my $self = shift;
217             return $self->{fail_on_error};
218            
219             }
220            
221             sub _set_priority {
222            
223             my $self = shift;
224             my $numeric_code = $self->get_sibling()->PackagePriorityClass;
225            
226             CASE: {
227            
228             if ( $numeric_code == 3 ) {
229            
230             $self->{priority} = 'High';
231             last CASE;
232            
233             }
234            
235             if ( $numeric_code == 1 ) {
236            
237             $self->{priority} = 'Low';
238             last CASE;
239            
240             }
241            
242             if ( $numeric_code == 2 ) {
243            
244             $self->{priority} = 'Normal';
245             last CASE;
246            
247             }
248            
249             }
250            
251             }
252            
253             sub _set_lineage_opts {
254            
255             my $self = shift;
256            
257             my $numeric_code = $self->get_sibling()->LineageOptions;
258            
259             $self->{add_lineage_vars} = 0;
260             $self->{is_lineage_none} = 0;
261             $self->{is_repository} = 0;
262             $self->{is_repository_required} = 0;
263            
264             # those values come from DTSLineageOptions in the DTS Programming MS SQL Server documentation
265             $self->{add_lineage_vars} = $numeric_code & 1;
266             $self->{is_lineage_none} = 1 if ( $numeric_code == 0 );
267             $self->{is_repository} = $numeric_code & 2;
268             $self->{is_repository_required} = $numeric_code & 3;
269            
270             }
271            
272             =head3 add_lineage_vars
273            
274             Returns true or false (1 or 0 respectivally) if the Add Lineage Variables property is set.
275            
276             =cut
277            
278             sub add_lineage_vars {
279            
280             my $self = shift;
281             return $self->{add_lineage_vars};
282            
283             }
284            
285             =head3 is_lineage_none
286            
287             Returns true if provide no lineage (default) or false otherwise.
288            
289             =cut
290            
291             sub is_lineage_none {
292            
293             my $self = shift;
294             return $self->{is_lineage_none};
295            
296             }
297            
298             =head3 is_repository
299            
300             Returns true or false if the package will write to Meta Data Services if available.
301            
302             =cut
303            
304             sub is_repository {
305            
306             my $self = shift;
307             return $self->{is_repository};
308            
309             }
310            
311             =head3 is_repository_required
312            
313             Returns true or false if writing to Meta Data Services is required.
314            
315             =cut
316            
317             sub is_repository_required {
318            
319             my $self = shift;
320             return $self->{is_repository_required};
321            
322             }
323            
324             =head3 to_string
325            
326             Returns a string will all properties from the package, separated with new line characters. Each property also has
327             a text with a sort description of the property.
328            
329             This method will not fetch automatically the properties from objects inside the package, line connections and
330             tasks. Each object must be fetched first using the apropriated method and them invoking the C from each
331             object.
332            
333             =cut
334            
335             sub to_string {
336            
337             my $self = shift;
338            
339             return "\tName: "
340             . $self->get_name
341             . "\n\tID: "
342             . $self->get_id
343             . "\n\tVersion ID: "
344             . $self->get_version_id
345             . "\n\tComputer where the package was created: "
346             . $self->get_creator_computer
347             . "\n\tDescription: "
348             . $self->get_description
349             . "\n\tExecution priority: "
350             . $self->get_priority
351             . "\n\tAuto commit enable? "
352             . ( ( $self->auto_commit ) ? 'true' : 'false' )
353             . "\n\tCreation date: "
354             . $self->get_creation_date->datetime
355             . "\n\tFail on error? "
356             . ( ( $self->fail_on_error ) ? 'true' : 'false' )
357             . "\n\tLog file: "
358             . $self->get_log_file
359             . "\n\tMaximum number of steps: "
360             . $self->get_max_steps
361             . "\n\tAdd lineage variables? "
362             . ( ( $self->add_lineage_vars ) ? 'true' : 'false' )
363             . "\n\tIs lineage none? "
364             . ( ( $self->is_lineage_none ) ? 'true' : 'false' )
365             . "\n\tWrite to repository if available? "
366             . ( ( $self->is_repository ) ? 'true' : 'false' )
367             . "\n\tWrite to repository is required? "
368             . ( ( $self->is_repository_required ) ? 'true' : 'false' )
369             . "\n\tLog to SQL Server? "
370             . ( ( $self->log_to_server ) ? 'true' : 'false' )
371             . "\n\tUse explicit global variables? "
372             . ( ( $self->use_explicit_global_vars ) ? 'true' : 'false' )
373             . "\n\tUse event log for logging? "
374             . ( ( $self->use_event_log ) ? 'true' : 'false' );
375            
376             }
377            
378             =head3 get_connections
379            
380             Returns an iterator (code reference) that will return a C object at each invocation until there are no
381             more objects available.
382            
383             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
384             after invoking the C method.
385            
386             =cut
387            
388             sub get_connections {
389            
390             my $self = shift;
391             my $total = scalar( in( $self->get_sibling()->Connections ) );
392             my $counter = 0;
393            
394             return sub {
395            
396             return unless ( $counter < $total );
397            
398             my $conn = ( in( $self->get_sibling()->Connections ) )[$counter];
399            
400             $counter++;
401            
402             return Win32::SqlServer::DTS::Connection->new($conn);
403            
404             }
405            
406             }
407            
408             =head3 count_connections
409            
410             Returns an integer that represents the total amount of connections available in the package object.
411            
412             Besides the convenience, this method is uses less resources than invoking the respective C method and
413             looping over the references in the array reference.
414            
415             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
416             after invoking the C method.
417            
418             =cut
419            
420             sub count_connections {
421            
422             my $self = shift;
423             my $counter = 0;
424            
425             foreach my $connection ( in( $self->get_sibling->Connections ) ) {
426            
427             $counter++;
428            
429             }
430            
431             return $counter;
432            
433             }
434            
435             =head3 get_tasks
436            
437             Returns an iterator. At each iterator (which is a code reference) call, one subclass object of C will be
438             returned.
439            
440             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
441             after invoking the C method.
442            
443             B C method will abort with an error message if the DTS package has tasks that are not available
444             as subclasses of C class. In doubt, use the available methods to fetch only the supported tasks. This
445             should be "fixed" in future releases with the implementation of the missing classes.
446            
447             =cut
448            
449             sub get_tasks {
450            
451             my $self = shift;
452             my $tasks = $self->get_sibling()->Tasks;
453             my $total = scalar( in($tasks) );
454             my $counter = 0;
455            
456             return sub {
457            
458             return unless ( $counter < $total );
459            
460             my $task = ( in($tasks) )[$counter];
461            
462             $counter++;
463            
464             return Win32::SqlServer::DTS::TaskFactory::create($task);
465            
466             }
467            
468             }
469            
470             =head3 count_tasks
471            
472             Returns a integer with the number of tasks available inside the package.
473            
474             Besides the convenience, this method is uses less resources than invoking the respective C method and
475             looping over the references in the array reference.
476            
477             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
478             after invoking the C method.
479            
480             =cut
481            
482             sub count_tasks {
483            
484             my $self = shift;
485             my $counter = 0;
486            
487             map { $counter++; } ( in( $self->get_sibling->Tasks ) );
488            
489             return $counter;
490            
491             }
492            
493             =head3 _get_tasks_by_type
494            
495             C<_get_tasks_by_type> is a "private method". It will return an iterator (which is a code reference) that will return
496             C subclasses objects at each call depending on the type passed as a parameter. It will not return and will
497             complete ignore any Task class that is not returned by C.
498            
499             This method creates a cache after first call, so don't expect it will find new tasks after first invocation.
500            
501             =cut
502            
503             sub _get_tasks_by_type {
504            
505             my $self = shift;
506             my $type = shift;
507             my $iterator_counter = 0;
508            
509             unless ( keys( %{ $self->{_known_tasks} } ) ) {
510            
511             my $list = Win32::SqlServer::DTS::TaskTypes::get_types();
512            
513             foreach my $item ( @{$list} ) {
514            
515             $self->{_known_tasks}->{$item} = [];
516            
517             }
518            
519             #avoid caching invalid types
520             lock_keys( %{ $self->{_known_tasks} } );
521            
522             my $counter = 0;
523            
524             foreach my $task ( in( $self->get_sibling()->Tasks ) ) {
525            
526             # :TRICKY:3/11/2008:arfreitas: must avoid completely caching an unimplemeted DTS class in Perldts
527             if ( grep { $task->CustomTaskID eq $_ } @{$list} ) {
528            
529             push(
530             @{ $self->{_known_tasks}->{ $task->CustomTaskID } },
531             $counter
532             );
533            
534             }
535            
536             # counter must be incremented anyway to get the proper indexes returned by in() function
537             $counter++;
538            
539             }
540            
541             }
542            
543             return sub {
544            
545             my $total = scalar( @{ $self->{_known_tasks}->{$type} } );
546            
547             return unless ( $iterator_counter < $total );
548            
549             #array slash of all tasks using as a index the number provided by known tasks cache
550             my $task =
551             ( in( $self->get_sibling()->Tasks ) )
552             [ $self->{_known_tasks}->{$type}->[$iterator_counter] ];
553            
554             $iterator_counter++;
555            
556             return Win32::SqlServer::DTS::TaskFactory::create($task);
557            
558             }
559            
560             }
561            
562             sub _count_tasks_by_type {
563            
564             my $self = shift;
565             my $type = shift;
566             my $counter = 0;
567            
568             foreach my $task ( in( $self->get_sibling()->Tasks ) ) {
569            
570             next unless ( $task->CustomTaskID eq $type );
571             $counter++;
572            
573             }
574            
575             return $counter;
576            
577             }
578            
579             =head3 count_datapumps
580            
581             Returns an integer represents the total amount of C tasks available in the package.
582            
583             Besides the convenience, this method is uses less resources than invoking the respective C method and
584             looping over the references in the array reference.
585            
586             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
587             after invoking the C method.
588            
589             =cut
590            
591             sub count_datapumps {
592            
593             my $self = shift;
594             return $self->_count_tasks_by_type('DTSDataPumpTask');
595            
596             }
597            
598             =head3 get_datapumps
599            
600             Returns a iterator (code reference) that will return, at each invocation, a the C tasks available
601             in the package.
602            
603             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
604             after invoking the C method.
605            
606             =cut
607            
608             sub get_datapumps {
609            
610             my $self = shift;
611             return $self->_get_tasks_by_type('DTSDataPumpTask');
612            
613             }
614            
615             =head3 count_dynamic_props
616            
617             Returns an integer represents the total amount of C tasks available in the package.
618            
619             Besides the convenience, this method is uses less resources than invoking the respective C method and
620             looping over the references in the array reference.
621            
622             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
623             after invoking the C method.
624            
625             =cut
626            
627             sub count_dynamic_props {
628            
629             my $self = shift;
630             return $self->_count_tasks_by_type('DTSDynamicPropertiesTask');
631            
632             }
633            
634             =head3 get_dynamic_props
635            
636             Returns a iterator (code reference) that will return a C object at each invocation until
637             there is no more tasks to return.
638            
639             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
640             after invoking the C method.
641            
642             =cut
643            
644             sub get_dynamic_props {
645            
646             my $self = shift;
647             return $self->_get_tasks_by_type('DTSDynamicPropertiesTask');
648            
649             }
650            
651             =head3 get_execute_pkgs
652            
653             Returns a iterator (code reference) that will return a C object at each invocation until
654             there is no more tasks to return.
655            
656             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
657             after invoking the C method.
658            
659             =cut
660            
661             sub get_execute_pkgs {
662            
663             my $self = shift;
664             return $self->_get_tasks_by_type('DTSExecutePackageTask');
665            
666             }
667            
668             =head3 count_execute_pkgs
669            
670             Returns an integer with the total of C tasks available in the package.
671            
672             Besides the convenience, this method is uses less resources than invoking the respective C method and
673             looping over the references in the array reference.
674            
675             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
676             after invoking the C method.
677            
678             =cut
679            
680             sub count_execute_pkgs {
681            
682             my $self = shift;
683             return $self->_count_tasks_by_type('DTSExecutePackageTask');
684            
685             }
686            
687             =head3 get_send_emails
688            
689             Returns an iterator (code reference) that will return a C at each invocation until there is no
690             more tasks available.
691            
692             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
693             after invoking the C method.
694            
695             =cut
696            
697             sub get_send_emails {
698            
699             my $self = shift;
700            
701             return $self->_get_tasks_by_type('DTSSendMailTask');
702            
703             }
704            
705             =head3 count_send_emails
706            
707             Returns an integer with the total of C tasks available in the package.
708            
709             Besides the convenience, this method is uses less resources than invoking the respective C method and
710             looping over the references in the array reference.
711            
712             This method depends on having the C<_sibling> attribute available, therefore is not possible to invoke this method
713             after invoking the C method.
714            
715             =cut
716            
717             sub count_send_emails {
718            
719             my $self = shift;
720             return $self->_count_tasks_by_type('DTSSendMailTask');
721            
722             }
723            
724             =head3 save_to_server
725            
726             Saves the package to a SQL Server. This method must be called if the Win32::SqlServer::DTS::Package was modified (or it's inner object
727             were).
728            
729             Expectes a L object as a parameter. If the Package will be saved in the same server
730             from where it was fetched it's useful to use the method C from the L
731             object.
732            
733             The optional parameters:
734            
735             =over
736            
737             =item *
738             PackageOwnerPassword
739            
740             =item *
741             PackageOperatorPassword
742            
743             =item *
744             PackageCategoryID
745            
746             =item *
747             pVarPersistStgOfHost
748            
749             =item *
750             bReusePasswords
751            
752             =back
753            
754             from the original DTS API are not implemented.
755            
756             =cut
757            
758             sub save_to_server {
759            
760             my $self = shift;
761             my $credential = shift;
762            
763             confess "invalid credential parameter"
764             unless ( $credential->isa('Win32::SqlServer::DTS::Credential') );
765            
766             $self->get_sibling()->SaveToSQLServer( $credential->to_list() );
767            
768             confess 'could not save the packate to a SQL Server: '
769             . Win32::OLE->LastError()
770             if ( Win32::OLE->LastError() );
771            
772             }
773            
774             =head3 save_to_file
775            
776             Saves the package to a structured file.
777            
778             Expects a complete pathname as a parameter. If a DTS structure filename is not passed together with the path,
779             the method will use the package name followed by a '.dts' extension.
780            
781             The optional parameters:
782            
783             =over
784            
785             =item *
786             OwnerPassword
787            
788             =item *
789             OperatorPassword
790            
791             =item *
792             pVarPersistStgOfHost
793            
794             =item *
795             bReusePasswords
796            
797             =back
798            
799             from the original DTS API are not implemented.
800            
801             =cut
802            
803             sub save_to_file {
804            
805             my $self = shift;
806             my $path = shift;
807             my $file = shift;
808            
809             confess "invalid complete pathname parameter" unless ( defined($path) );
810            
811             $file = $self->get_name() . '.dts' unless ( defined($file) );
812            
813             $path = File::Spec->catfile( $path, $file );
814             $self->get_sibling()->SaveToStorageFile($path);
815            
816             confess "could not save '$path': " . Win32::OLE->LastError()
817             if ( Win32::OLE->LastError() );
818            
819             }
820            
821             1;
822             __END__