|
278
|
|
|
|
|
|
|
$section = lc($1); |
|
279
|
|
|
|
|
|
|
$self->{'correct_case'}{$section} = $1; |
|
280
|
|
|
|
|
|
|
# remember which sections are tables |
|
281
|
|
|
|
|
|
|
$self->{'tables'}{$1} = 1; |
|
282
|
|
|
|
|
|
|
} elsif(/^<\/msi>/) { |
|
283
|
|
|
|
|
|
|
$section = 'trailer'; |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
if($section ne $lastsection) { |
|
287
|
|
|
|
|
|
|
$lastsection = $section; |
|
288
|
|
|
|
|
|
|
push(@{$self->{'order'}}, $section); |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# remember what tables each foreign key appears in |
|
292
|
|
|
|
|
|
|
if(/^\s*]+>([^<]+)) { |
|
293
|
|
|
|
|
|
|
my $colname = $1; |
|
294
|
|
|
|
|
|
|
if($colname =~ /_$/) { |
|
295
|
|
|
|
|
|
|
unless(exists($self->{'foreign_keys'}{$colname})) { |
|
296
|
|
|
|
|
|
|
$self->{'foreign_keys'}{$colname} = []; |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
push(@{$self->{'foreign_keys'}{$colname}}, $section); |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
push(@{$self->{'sections'}{$section}}, $_); |
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# find the file encoding |
|
306
|
|
|
|
|
|
|
foreach my $line (@{$self->{sections}->{header}}) { |
|
307
|
|
|
|
|
|
|
if($line =~ /\sencoding="([^"]+)"/) { |
|
308
|
|
|
|
|
|
|
$self->{'encoding'} = $1; |
|
309
|
|
|
|
|
|
|
last; |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
return 1; |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=item I |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
$is->savefile( ); |
|
319
|
|
|
|
|
|
|
$is->savefile( $filename ); |
|
320
|
|
|
|
|
|
|
$is->savefile( $io_file_handle ); |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Stores the ism data in a file. Can be called |
|
323
|
|
|
|
|
|
|
with either a filename or an IO::File object that is |
|
324
|
|
|
|
|
|
|
opened in write ("w") mode. If no argument is passed, |
|
325
|
|
|
|
|
|
|
and the last load was via a filename, savefile will |
|
326
|
|
|
|
|
|
|
default to the filename previously supplied. |
|
327
|
|
|
|
|
|
|
Returns 1 on success, 0 on failure. |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=cut |
|
330
|
|
|
|
|
|
|
sub savefile { |
|
331
|
|
|
|
|
|
|
my ($self, $file) = @_; |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
unless(defined($file)) { |
|
334
|
|
|
|
|
|
|
if(defined($self->{'filename'})) { |
|
335
|
|
|
|
|
|
|
$file = $self->{'filename'}; |
|
336
|
|
|
|
|
|
|
} else { |
|
337
|
|
|
|
|
|
|
carp("You must provide a filename to save to"); |
|
338
|
|
|
|
|
|
|
return 0; |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
my ($fh, $i_opened_file) = _openfile($file, "w"); |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
unless(defined($fh)) { |
|
345
|
|
|
|
|
|
|
return 0; |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
print $fh $self->save(); |
|
349
|
|
|
|
|
|
|
$fh->close() if($i_opened_file); |
|
350
|
|
|
|
|
|
|
return 1; |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=item I |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
$is->save(); |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
Returns the ism data as a string. |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=cut |
|
360
|
|
|
|
|
|
|
sub save { |
|
361
|
|
|
|
|
|
|
my ($self) = @_; |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
my $encoding = $self->{'encoding'}; |
|
364
|
|
|
|
|
|
|
my $has_encoding = defined($encoding); |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
my $text = ''; |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
foreach my $section (@{$self->{'order'}}) { |
|
369
|
|
|
|
|
|
|
if($self->{'parsed'}{$section}) { |
|
370
|
|
|
|
|
|
|
# the table has been (possibly) modified, so rebuild it |
|
371
|
|
|
|
|
|
|
if($section eq 'summary') { |
|
372
|
|
|
|
|
|
|
$text .= ($has_encoding) ? |
|
373
|
|
|
|
|
|
|
encode($encoding, $self->_save_summary) : |
|
374
|
|
|
|
|
|
|
$self->_save_summary; |
|
375
|
|
|
|
|
|
|
} else { |
|
376
|
|
|
|
|
|
|
$text .= ($has_encoding) ? |
|
377
|
|
|
|
|
|
|
encode($encoding, $self->_save_table($section)) : |
|
378
|
|
|
|
|
|
|
$self->_save_table($section); |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
} else { |
|
382
|
|
|
|
|
|
|
# when the last table gets modified, we end up with an |
|
383
|
|
|
|
|
|
|
# extra newline |
|
384
|
|
|
|
|
|
|
if($section eq 'trailer') { |
|
385
|
|
|
|
|
|
|
$text =~ s/\n\n$/\n/; |
|
386
|
|
|
|
|
|
|
} |
|
387
|
|
|
|
|
|
|
# section wasn't touched, just spit out the stored text |
|
388
|
|
|
|
|
|
|
$text .= join("\n", @{$self->{'sections'}{$section}}) . "\n"; |
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
} |
|
391
|
|
|
|
|
|
|
return $text; |
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub _save_summary { |
|
395
|
|
|
|
|
|
|
my ($self) = @_; |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
my $count = 0; |
|
398
|
|
|
|
|
|
|
my %order = |
|
399
|
|
|
|
|
|
|
map { $_ => $count++ } |
|
400
|
|
|
|
|
|
|
$self->summary_fields; |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
my $summary = $self->{'parsed'}{'summary'}; |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
my $text = "\t\n"; |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
foreach my $field (sort { $order{$a} <=> $order{$b} } keys %order) { |
|
407
|
|
|
|
|
|
|
if(exists($summary->{$field})) { |
|
408
|
|
|
|
|
|
|
if(!defined($summary->{$field}) || $summary->{$field} eq '') { |
|
409
|
|
|
|
|
|
|
$text .= "\t\t<$field/>\n"; |
|
410
|
|
|
|
|
|
|
} else { |
|
411
|
|
|
|
|
|
|
$text .= "\t\t<$field>" . $summary->{$field} . "$field>\n"; |
|
412
|
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
} |
|
414
|
|
|
|
|
|
|
} |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
$text .= "\t\n\t\n"; |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
return $text; |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
# internal function. formats the data in a table that has |
|
422
|
|
|
|
|
|
|
# been modified back to the appropriate output format |
|
423
|
|
|
|
|
|
|
sub _save_table { |
|
424
|
|
|
|
|
|
|
my ($self, $table) = @_; |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
427
|
|
|
|
|
|
|
my $text = "\t
|
428
|
|
|
|
|
|
|
foreach my $key (sort keys %{$p->{'attributes'}}) { |
|
429
|
|
|
|
|
|
|
$text .= " $key=\"$p->{'attributes'}{$key}\""; |
|
430
|
|
|
|
|
|
|
} |
|
431
|
|
|
|
|
|
|
$text .= ">\n"; |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
foreach my $col (@{$p->{'columns'}}) { |
|
434
|
|
|
|
|
|
|
$text .= "\t\t
|
|
435
|
|
|
|
|
|
|
if($col->{'is_key'}) { |
|
436
|
|
|
|
|
|
|
$text .= ' key="yes"'; |
|
437
|
|
|
|
|
|
|
} |
|
438
|
|
|
|
|
|
|
$text .= ' def="' . $col->{'type'} . $col->{'width'} . '"'; |
|
439
|
|
|
|
|
|
|
$text .= ">$col->{'name'}\n"; |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
foreach my $key (sort keys %{$p->{'data'}}) { |
|
442
|
|
|
|
|
|
|
my $row = $p->{'data'}{$key}; |
|
443
|
|
|
|
|
|
|
$text .= "\t\t"; |
|
444
|
|
|
|
|
|
|
foreach my $col (@$row) { |
|
445
|
|
|
|
|
|
|
if(defined($col) and length($col) > 0) { |
|
446
|
|
|
|
|
|
|
$text .= " | " . _xml_escape($col) . " | ";
|
447
|
|
|
|
|
|
|
} else { |
|
448
|
|
|
|
|
|
|
$text .= " | | ";
|
449
|
|
|
|
|
|
|
} |
|
450
|
|
|
|
|
|
|
} |
|
451
|
|
|
|
|
|
|
$text .= "\n"; |
|
452
|
|
|
|
|
|
|
} |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
$text .= "\t | \n\n"; |
|
455
|
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
return $text; |
|
457
|
|
|
|
|
|
|
} |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
# internal function. parses the text of an IS table |
|
460
|
|
|
|
|
|
|
# so that it can be easily manipulated |
|
461
|
|
|
|
|
|
|
sub _parse_table { |
|
462
|
|
|
|
|
|
|
my ($self, $table) = @_; |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
$table = lc($table); |
|
465
|
|
|
|
|
|
|
return if($self->{'parsed'}{$table}); |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
my $text = $self->{'sections'}{$table}; |
|
468
|
|
|
|
|
|
|
unless(defined($text)) { |
|
469
|
|
|
|
|
|
|
carp("No such table $table"); |
|
470
|
|
|
|
|
|
|
return; |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
my @cols; |
|
474
|
|
|
|
|
|
|
my %data; |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
my $xml = join("\n", @$text); |
|
477
|
|
|
|
|
|
|
my @parsed = @{$self->{'parser'}->parse($xml)->[1]}; |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
my $attributes = shift @parsed; |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
while(@parsed) { |
|
482
|
|
|
|
|
|
|
my $type = shift @parsed; |
|
483
|
|
|
|
|
|
|
if($type eq 'col') { |
|
484
|
|
|
|
|
|
|
my $columns = shift @parsed; |
|
485
|
|
|
|
|
|
|
my $column_name = $columns->[2]; |
|
486
|
|
|
|
|
|
|
my $is_key = ( defined($columns->[0]{'key'}) and $columns->[0]{'key'} eq 'yes' ); |
|
487
|
|
|
|
|
|
|
my ($type, $width) = ($columns->[0]{'def'} =~ /(\w)(\d+)/); |
|
488
|
|
|
|
|
|
|
push(@cols, { |
|
489
|
|
|
|
|
|
|
name => $column_name, |
|
490
|
|
|
|
|
|
|
is_key => $is_key, |
|
491
|
|
|
|
|
|
|
type => $type, |
|
492
|
|
|
|
|
|
|
width => $width, |
|
493
|
|
|
|
|
|
|
}); |
|
494
|
|
|
|
|
|
|
} elsif($type eq 'row') { |
|
495
|
|
|
|
|
|
|
my $columns = shift @parsed; |
|
496
|
|
|
|
|
|
|
my @row; |
|
497
|
|
|
|
|
|
|
my $lookup_key = ''; |
|
498
|
|
|
|
|
|
|
foreach my $i (0..$#cols) { |
|
499
|
|
|
|
|
|
|
my $value = $columns->[ ($i+1)*2 ][2]; |
|
500
|
|
|
|
|
|
|
$row[$i] = $value; |
|
501
|
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
if($cols[$i]{'is_key'}) { |
|
503
|
|
|
|
|
|
|
my $key_value = $value; |
|
504
|
|
|
|
|
|
|
unless(defined($key_value)) { $key_value = ''; } |
|
505
|
|
|
|
|
|
|
$lookup_key .= sprintf("%-" . $cols[$i]{'width'} . "s", $key_value) |
|
506
|
|
|
|
|
|
|
} |
|
507
|
|
|
|
|
|
|
} |
|
508
|
|
|
|
|
|
|
$data{ $lookup_key } = \@row; |
|
509
|
|
|
|
|
|
|
} else { |
|
510
|
|
|
|
|
|
|
# ignore text |
|
511
|
|
|
|
|
|
|
shift @parsed; |
|
512
|
|
|
|
|
|
|
} |
|
513
|
|
|
|
|
|
|
} |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
$self->{'parsed'}{$table} = { |
|
516
|
|
|
|
|
|
|
attributes => $attributes, |
|
517
|
|
|
|
|
|
|
columns => \@cols, |
|
518
|
|
|
|
|
|
|
data => \%data, |
|
519
|
|
|
|
|
|
|
}; |
|
520
|
|
|
|
|
|
|
} |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
sub _parsed { |
|
523
|
|
|
|
|
|
|
my ($self, $table) = @_; |
|
524
|
|
|
|
|
|
|
$table = lc($table); |
|
525
|
|
|
|
|
|
|
unless(exists($self->{'parsed'}{$table})) { |
|
526
|
|
|
|
|
|
|
$self->_parse_table($table); |
|
527
|
|
|
|
|
|
|
} |
|
528
|
|
|
|
|
|
|
return $self->{'parsed'}{$table}; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=item I |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
my $tables = $is->tables(); |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
Returns an arrayref containing a list of all the tables |
|
536
|
|
|
|
|
|
|
that were found in the ISM file. |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
=cut |
|
539
|
|
|
|
|
|
|
sub tables { |
|
540
|
|
|
|
|
|
|
my ($self) = @_; |
|
541
|
|
|
|
|
|
|
return [ sort keys %{$self->{'tables'}} ]; |
|
542
|
|
|
|
|
|
|
} |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=item I |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
if($is->has_table( 'ModuleSignature' ) { |
|
547
|
|
|
|
|
|
|
print "This is a merge module\n"; |
|
548
|
|
|
|
|
|
|
} |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
Returns true if a table exists with the supplied name, false otherwise. |
|
551
|
|
|
|
|
|
|
Table names are case-insensitive. |
|
552
|
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=cut |
|
554
|
|
|
|
|
|
|
sub has_table { |
|
555
|
|
|
|
|
|
|
my ($self, $table) = @_; |
|
556
|
|
|
|
|
|
|
return exists($self->{'sections'}{lc($table)}); |
|
557
|
|
|
|
|
|
|
} |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=item I |
|
560
|
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
my $is_key = $is->column_is_key( $table, $column_name ); |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
Returns true if the column is a key column, false |
|
564
|
|
|
|
|
|
|
other wise. Returns undef if the column doesn't exist. |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=cut |
|
567
|
|
|
|
|
|
|
sub column_is_key { |
|
568
|
|
|
|
|
|
|
my ($self, $table, $column) = @_; |
|
569
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
570
|
|
|
|
|
|
|
foreach my $col (@{$p->{'columns'}}) { |
|
571
|
|
|
|
|
|
|
if($col->{'name'} eq $column) { |
|
572
|
|
|
|
|
|
|
return $col->{'is_key'}; |
|
573
|
|
|
|
|
|
|
} |
|
574
|
|
|
|
|
|
|
} |
|
575
|
|
|
|
|
|
|
return; |
|
576
|
|
|
|
|
|
|
} |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=item I |
|
579
|
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
my $width = $is->column_width( $table, $column_name ); |
|
581
|
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
Returns the width of the named column. Returns undef if |
|
583
|
|
|
|
|
|
|
the column doesn't exist. |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=cut |
|
586
|
|
|
|
|
|
|
sub column_width { |
|
587
|
|
|
|
|
|
|
my ($self, $table, $column) = @_; |
|
588
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
589
|
|
|
|
|
|
|
return $p->{'columns'}{$column}{'width'}; |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=item I |
|
593
|
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
my $type = $is->column_type( $table, $column_name ); |
|
595
|
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
Returns the type of the named column. Returns undef if the |
|
597
|
|
|
|
|
|
|
column doesn't exist. |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
=cut |
|
600
|
|
|
|
|
|
|
sub column_type { |
|
601
|
|
|
|
|
|
|
my ($self, $table, $column) = @_; |
|
602
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
603
|
|
|
|
|
|
|
return $p->{'columns'}{$column}{'type'}; |
|
604
|
|
|
|
|
|
|
} |
|
605
|
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
=item I |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
my $columns = $is->columns( $table ); |
|
609
|
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
Returns an array ref containing the names of the columns |
|
611
|
|
|
|
|
|
|
in the given table. |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
=cut |
|
614
|
|
|
|
|
|
|
sub columns { |
|
615
|
|
|
|
|
|
|
my ($self, $table) = @_; |
|
616
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
617
|
|
|
|
|
|
|
my @cols; |
|
618
|
|
|
|
|
|
|
foreach my $col (@{$p->{'columns'}}) { |
|
619
|
|
|
|
|
|
|
push(@cols, $col->{'name'}); |
|
620
|
|
|
|
|
|
|
} |
|
621
|
|
|
|
|
|
|
return \@cols; |
|
622
|
|
|
|
|
|
|
} |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=item I |
|
625
|
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
my $key_columns = $is->key_columns( $table ); |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
Returns an array ref containing the names of the |
|
629
|
|
|
|
|
|
|
key columns in the given table. |
|
630
|
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
=cut |
|
632
|
|
|
|
|
|
|
sub key_columns { |
|
633
|
|
|
|
|
|
|
my ($self, $table) = @_; |
|
634
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
635
|
|
|
|
|
|
|
my @keys; |
|
636
|
|
|
|
|
|
|
foreach my $col (@{$p->{'columns'}}) { |
|
637
|
|
|
|
|
|
|
if($col->{'is_key'}) { |
|
638
|
|
|
|
|
|
|
push(@keys, $col->{'name'}); |
|
639
|
|
|
|
|
|
|
} |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
return \@keys; |
|
642
|
|
|
|
|
|
|
} |
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
sub _find_row { |
|
645
|
|
|
|
|
|
|
my ($self, $table, $rowdata) = @_; |
|
646
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
my $lookup_key = $self->_build_key( $table, $rowdata ); |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
if(exists($p->{'data'}{$lookup_key})) { |
|
651
|
|
|
|
|
|
|
return $lookup_key; |
|
652
|
|
|
|
|
|
|
} else { |
|
653
|
|
|
|
|
|
|
return; |
|
654
|
|
|
|
|
|
|
} |
|
655
|
|
|
|
|
|
|
} |
|
656
|
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
sub _search_row { |
|
658
|
|
|
|
|
|
|
my ($self, $table, $rowdata) = @_; |
|
659
|
|
|
|
|
|
|
my @results; |
|
660
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
661
|
|
|
|
|
|
|
foreach my $row (values %{$p->{'data'}}) { |
|
662
|
|
|
|
|
|
|
my $match = 1; |
|
663
|
|
|
|
|
|
|
foreach my $i (0..$#{$rowdata}) { |
|
664
|
|
|
|
|
|
|
# undef means they don't care about this column |
|
665
|
|
|
|
|
|
|
if(defined($rowdata->[$i])) { |
|
666
|
|
|
|
|
|
|
# empty string from the user matches undef in the data |
|
667
|
|
|
|
|
|
|
if(defined($row->[$i])) { |
|
668
|
|
|
|
|
|
|
if(ref($rowdata->[$i]) eq 'Regexp') { |
|
669
|
|
|
|
|
|
|
if($row->[$i] !~ /$rowdata->[$i]/) { |
|
670
|
|
|
|
|
|
|
$match = 0; |
|
671
|
|
|
|
|
|
|
last; |
|
672
|
|
|
|
|
|
|
} |
|
673
|
|
|
|
|
|
|
} elsif($rowdata->[$i] ne $row->[$i]) { |
|
674
|
|
|
|
|
|
|
$match = 0; |
|
675
|
|
|
|
|
|
|
last; |
|
676
|
|
|
|
|
|
|
} |
|
677
|
|
|
|
|
|
|
} elsif($rowdata->[$i] ne '') { |
|
678
|
|
|
|
|
|
|
$match = 0; |
|
679
|
|
|
|
|
|
|
last; |
|
680
|
|
|
|
|
|
|
} |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
} |
|
683
|
|
|
|
|
|
|
if($match) { |
|
684
|
|
|
|
|
|
|
push(@results, $row); |
|
685
|
|
|
|
|
|
|
} |
|
686
|
|
|
|
|
|
|
} |
|
687
|
|
|
|
|
|
|
return \@results; |
|
688
|
|
|
|
|
|
|
} |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
# the lookup key is just the primary key columns concatenated together, |
|
691
|
|
|
|
|
|
|
# with padding to the full column length. this function builds the key |
|
692
|
|
|
|
|
|
|
# given the column values |
|
693
|
|
|
|
|
|
|
sub _build_key { |
|
694
|
|
|
|
|
|
|
my ($self, $table, $values) = @_; |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
697
|
|
|
|
|
|
|
my $lookup_key = ''; |
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
# build the lookup key by concatenating the key columns |
|
700
|
|
|
|
|
|
|
foreach my $i (0..$#{$p->{'columns'}}) { |
|
701
|
|
|
|
|
|
|
if($p->{'columns'}[$i]{'is_key'}) { |
|
702
|
|
|
|
|
|
|
my $width = $p->{'columns'}[$i]{'width'}; |
|
703
|
|
|
|
|
|
|
$lookup_key .= sprintf("%-${width}s", |
|
704
|
|
|
|
|
|
|
(defined($values->[$i])) ? $values->[$i] : ''); |
|
705
|
|
|
|
|
|
|
} |
|
706
|
|
|
|
|
|
|
} |
|
707
|
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
return $lookup_key; |
|
709
|
|
|
|
|
|
|
} |
|
710
|
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
# takes the various formats allowed for specifying row data, |
|
712
|
|
|
|
|
|
|
# and returns a consistent structure to be used by other methods. |
|
713
|
|
|
|
|
|
|
# also fills in any missing columns with undef |
|
714
|
|
|
|
|
|
|
sub _reformat_args { |
|
715
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
718
|
|
|
|
|
|
|
my $row = []; |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
if(ref($args[0]) eq 'ARRAY') { |
|
721
|
|
|
|
|
|
|
$row = $args[0]; |
|
722
|
|
|
|
|
|
|
} elsif(ref($args[0]) eq 'HASH') { |
|
723
|
|
|
|
|
|
|
my $h = $args[0]; |
|
724
|
|
|
|
|
|
|
foreach my $col (@{$p->{'columns'}}) { |
|
725
|
|
|
|
|
|
|
push(@$row, $h->{ $col->{'name'} }); |
|
726
|
|
|
|
|
|
|
} |
|
727
|
|
|
|
|
|
|
} else { |
|
728
|
|
|
|
|
|
|
$row = \@args; |
|
729
|
|
|
|
|
|
|
} |
|
730
|
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
# if the user left columns off the end, fill them |
|
732
|
|
|
|
|
|
|
# with undef |
|
733
|
|
|
|
|
|
|
my $missing_columns = $#{$p->{'columns'}} - $#{$row}; |
|
734
|
|
|
|
|
|
|
if($missing_columns > 0) { |
|
735
|
|
|
|
|
|
|
for( 1..$missing_columns ) { |
|
736
|
|
|
|
|
|
|
push(@{$row}, undef); |
|
737
|
|
|
|
|
|
|
} |
|
738
|
|
|
|
|
|
|
} |
|
739
|
|
|
|
|
|
|
return $row; |
|
740
|
|
|
|
|
|
|
} |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
sub _check_args { |
|
743
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
744
|
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
746
|
|
|
|
|
|
|
my $row = $self->_reformat_args($table, @args); |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
unless( $#{$row} eq $#{$p->{'columns'}} ) { |
|
749
|
|
|
|
|
|
|
carp("Wrong number of columns supplied for table $table"); |
|
750
|
|
|
|
|
|
|
return; |
|
751
|
|
|
|
|
|
|
} |
|
752
|
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
foreach my $i (0..$#{$row}) { |
|
754
|
|
|
|
|
|
|
next unless(defined($row->[$i])); |
|
755
|
|
|
|
|
|
|
my $type = $p->{'columns'}[$i]{'type'}; |
|
756
|
|
|
|
|
|
|
if($type =~ /^i$/i) { |
|
757
|
|
|
|
|
|
|
if($row->[$i] =~ /[^\d-]/) { |
|
758
|
|
|
|
|
|
|
croak("Value in $p->{'columns'}[$i]{'name'} column must be numeric"); |
|
759
|
|
|
|
|
|
|
return; |
|
760
|
|
|
|
|
|
|
} |
|
761
|
|
|
|
|
|
|
} else { |
|
762
|
|
|
|
|
|
|
my $width = $p->{'columns'}[$i]{'width'}; |
|
763
|
|
|
|
|
|
|
if($width > 0 and length($row->[$i]) > $width) { |
|
764
|
|
|
|
|
|
|
croak("Value in $p->{'columns'}[$i]{'name'} column is too long"); |
|
765
|
|
|
|
|
|
|
return; |
|
766
|
|
|
|
|
|
|
} |
|
767
|
|
|
|
|
|
|
} |
|
768
|
|
|
|
|
|
|
} |
|
769
|
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
return $row; |
|
771
|
|
|
|
|
|
|
} |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=item I |
|
774
|
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
my $version = $is->property('ProductVersion'); |
|
776
|
|
|
|
|
|
|
my $success = $is->property('ProductVersion', $version); |
|
777
|
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
Gets or sets the value associated with a property. If a value is |
|
779
|
|
|
|
|
|
|
supplied, it will attempt to update the property and return 1 |
|
780
|
|
|
|
|
|
|
on success and 0 on failure. undef is returned if the property does not exist. |
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=cut |
|
783
|
|
|
|
|
|
|
sub property { |
|
784
|
|
|
|
|
|
|
my ($self, $property, $value) = @_; |
|
785
|
|
|
|
|
|
|
unless(defined($self->getHash_Property({ Property=>$property }))) { |
|
786
|
|
|
|
|
|
|
return; |
|
787
|
|
|
|
|
|
|
} |
|
788
|
|
|
|
|
|
|
if(defined($value)) { |
|
789
|
|
|
|
|
|
|
$self->update_Property({ Property=>$property, Value=>$value }); |
|
790
|
|
|
|
|
|
|
} |
|
791
|
|
|
|
|
|
|
return $self->getHash_Property({ Property=>$property }); |
|
792
|
|
|
|
|
|
|
} |
|
793
|
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
=item I |
|
795
|
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
my $summary_value = $is->summary( $summary_field ); |
|
797
|
|
|
|
|
|
|
my $success = $is->summary( $summary_field, $value ); |
|
798
|
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
my $summary_table = $is->summary; |
|
800
|
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
Gets or sets the value associated with a field in the summary table. |
|
802
|
|
|
|
|
|
|
If no field name is provided, a reference to a hash containing all |
|
803
|
|
|
|
|
|
|
of the summary field/value pairs. |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=cut |
|
806
|
|
|
|
|
|
|
sub summary { |
|
807
|
|
|
|
|
|
|
my ($self, $field, $value) = @_; |
|
808
|
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
unless(exists($self->{'parsed'}{'summary'})) { |
|
810
|
|
|
|
|
|
|
$self->_parse_summary; |
|
811
|
|
|
|
|
|
|
} |
|
812
|
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
my $data = $self->{'parsed'}{'summary'}; |
|
814
|
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
return $data unless(defined($field)); |
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
if(defined($value)) { |
|
818
|
|
|
|
|
|
|
# make sure this summary field is allowed by the DTD |
|
819
|
|
|
|
|
|
|
return 0 unless($self->valid_summary_field($field)); |
|
820
|
|
|
|
|
|
|
$data->{$field} = $value; |
|
821
|
|
|
|
|
|
|
return 1; |
|
822
|
|
|
|
|
|
|
} else { |
|
823
|
|
|
|
|
|
|
return $data->{$field}; |
|
824
|
|
|
|
|
|
|
} |
|
825
|
|
|
|
|
|
|
} |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=item I |
|
828
|
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
my @field_names = $is->summary_fields; |
|
830
|
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
Returns a list of the valid fields for the summary table, as they appear |
|
832
|
|
|
|
|
|
|
in the DTD embedded in the ISM file. |
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
=cut |
|
835
|
|
|
|
|
|
|
sub summary_fields { |
|
836
|
|
|
|
|
|
|
my ($self) = @_; |
|
837
|
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
$self->_parse_summary unless(defined($self->{'parsed'}{'summary'})); |
|
839
|
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
return @{$self->{'summary_fields'}}; |
|
841
|
|
|
|
|
|
|
} |
|
842
|
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
=item I |
|
844
|
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
my $is_valid = $is->valid_summary_field( $field_name ); |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
Returns 1 if the field $field_name is valid according to the DTD |
|
848
|
|
|
|
|
|
|
in the ISM file, 0 otherwise. |
|
849
|
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
=cut |
|
851
|
|
|
|
|
|
|
sub valid_summary_field { |
|
852
|
|
|
|
|
|
|
my ($self, $field) = @_; |
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
return 0 unless(defined($field)); |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
foreach my $valid_field ($self->summary_fields) { |
|
857
|
|
|
|
|
|
|
return 1 if($field eq $valid_field); |
|
858
|
|
|
|
|
|
|
} |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
return 0; |
|
861
|
|
|
|
|
|
|
} |
|
862
|
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
# get the list of valid summary fields from the DTD |
|
864
|
|
|
|
|
|
|
sub _parse_summary_fields { |
|
865
|
|
|
|
|
|
|
my ($self) = @_; |
|
866
|
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
my $text = join('', @{$self->{'sections'}{'dtd'}}); |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
my ($summary_fields_text) = $text =~ /
|
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
$summary_fields_text =~ s/[\?\s]//g; |
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
my @summary_fields = split(',', $summary_fields_text); |
|
874
|
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
$self->{'summary_fields'} = \@summary_fields; |
|
876
|
|
|
|
|
|
|
} |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
# turn the XML for the summary table into something we can manipulate easily |
|
879
|
|
|
|
|
|
|
sub _parse_summary { |
|
880
|
|
|
|
|
|
|
my ($self) = @_; |
|
881
|
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
$self->_parse_summary_fields; |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
my $text = $self->{'sections'}{'summary'}; |
|
885
|
|
|
|
|
|
|
unless(defined($text)) { |
|
886
|
|
|
|
|
|
|
carp("No summary found"); |
|
887
|
|
|
|
|
|
|
return; |
|
888
|
|
|
|
|
|
|
} |
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
my %data; |
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
my $xml = join("\n", @$text); |
|
893
|
|
|
|
|
|
|
my @parsed = @{$self->{'parser'}->parse($xml)->[1]}; |
|
894
|
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
my $attributes = shift @parsed; |
|
896
|
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
while(@parsed) { |
|
898
|
|
|
|
|
|
|
my $type = shift @parsed; |
|
899
|
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
# ignore text |
|
901
|
|
|
|
|
|
|
if($type eq '0') { |
|
902
|
|
|
|
|
|
|
shift @parsed; |
|
903
|
|
|
|
|
|
|
next; |
|
904
|
|
|
|
|
|
|
} |
|
905
|
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
my $value = shift @parsed; |
|
907
|
|
|
|
|
|
|
$data{ $type } = $value->[2]; |
|
908
|
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
} |
|
910
|
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
$self->{'parsed'}{'summary'} = \%data; |
|
912
|
|
|
|
|
|
|
} |
|
913
|
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
=item I |
|
915
|
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
my $components = $is->featureComponents( $feature ); |
|
917
|
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
Returns an arrayref of the components in the named feature. Returns |
|
919
|
|
|
|
|
|
|
undef if the feature does not exist. |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
=cut |
|
922
|
|
|
|
|
|
|
sub featureComponents { |
|
923
|
|
|
|
|
|
|
my ($self, $feature) = @_; |
|
924
|
|
|
|
|
|
|
my $list = $self->searchHash_FeatureComponents({ Feature_=>$feature }); |
|
925
|
|
|
|
|
|
|
unless(@{$list}) { |
|
926
|
|
|
|
|
|
|
return; |
|
927
|
|
|
|
|
|
|
} |
|
928
|
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
my @components = sort map { $_->{'Component_'} } @{$list}; |
|
930
|
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
return \@components; |
|
932
|
|
|
|
|
|
|
} |
|
933
|
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
=back |
|
935
|
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
=head1 COMPONENT ATTRIBUTES |
|
937
|
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
All of the attribute methods can accept an attribute as either |
|
940
|
|
|
|
|
|
|
a name or a value. The name can be prefixed with msidbComponentAttributes |
|
941
|
|
|
|
|
|
|
as it is in the MSI documentation, but it is not required. |
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
Valid attributes: |
|
944
|
|
|
|
|
|
|
LocalOnly 0 |
|
945
|
|
|
|
|
|
|
SourceOnly 1 |
|
946
|
|
|
|
|
|
|
Optional 2 |
|
947
|
|
|
|
|
|
|
RegistryKeyPath 4 |
|
948
|
|
|
|
|
|
|
SharedDllRefCount 8 |
|
949
|
|
|
|
|
|
|
Permanent 16 |
|
950
|
|
|
|
|
|
|
ODBCDataSource 32 |
|
951
|
|
|
|
|
|
|
Transitive 64 |
|
952
|
|
|
|
|
|
|
NeverOverwrite 128 |
|
953
|
|
|
|
|
|
|
64bit 256 |
|
954
|
|
|
|
|
|
|
DisableRegistryReflection 512 |
|
955
|
|
|
|
|
|
|
UninstallOnSupersedence 1024 |
|
956
|
|
|
|
|
|
|
AttributesShared 2048 |
|
957
|
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
=over 4 |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
=item I |
|
961
|
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
my $success = $is->set_component_attribute( $component_name, '64bit', 1 ); |
|
963
|
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
Update the value of a single component attribute flag. Returns 1 on success, |
|
965
|
|
|
|
|
|
|
0 on failure. |
|
966
|
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
=cut |
|
968
|
|
|
|
|
|
|
sub set_component_attribute { |
|
969
|
|
|
|
|
|
|
my ($self, $component_name, $attribute, $bit_on) = @_; |
|
970
|
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
my $attr_num = $self->get_component_attribute_value( $attribute ); |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
return 0 unless(defined($attr_num)); |
|
974
|
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
if($attr_num == 0) { |
|
976
|
|
|
|
|
|
|
$attr_num = 1; |
|
977
|
|
|
|
|
|
|
$bit_on = !$bit_on; |
|
978
|
|
|
|
|
|
|
} |
|
979
|
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
my $component = $self->getHash_Component($component_name); |
|
981
|
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
return 0 unless(defined($component)); |
|
983
|
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
if($bit_on) { |
|
985
|
|
|
|
|
|
|
$component->{'Attributes'} |= $attr_num; |
|
986
|
|
|
|
|
|
|
} else { |
|
987
|
|
|
|
|
|
|
my $inverted_attr_num = ~$attr_num; |
|
988
|
|
|
|
|
|
|
$component->{'Attributes'} &= $inverted_attr_num; |
|
989
|
|
|
|
|
|
|
} |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
return $self->update_component($component); |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
} |
|
994
|
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
=item I |
|
996
|
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
my $is_64bit = $is->get_component_attribute( $component_name, '64bit' ); |
|
998
|
|
|
|
|
|
|
my $is_shared = $is->get_component_attribute( $component_name, 8 ); |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
Returns 1 if the named component has the given attribute set, 0 otherwise. |
|
1001
|
|
|
|
|
|
|
Returns undef if the component does not exist, or the attribute is invalid. |
|
1002
|
|
|
|
|
|
|
The attribute name or value can be used. |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
=cut |
|
1005
|
|
|
|
|
|
|
sub get_component_attribute { |
|
1006
|
|
|
|
|
|
|
my ($self, $component_name, $attribute) = @_; |
|
1007
|
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
my $invert = 0; |
|
1009
|
|
|
|
|
|
|
my $attr_num = $self->get_component_attribute_value( $attribute ); |
|
1010
|
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
return unless(defined($attr_num)); |
|
1012
|
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
# for some reason, the docs have bit 1 listed twice, once for |
|
1014
|
|
|
|
|
|
|
# on and once for off (as hex value 0x0) |
|
1015
|
|
|
|
|
|
|
if($attr_num == 0) { |
|
1016
|
|
|
|
|
|
|
$attr_num = 1; |
|
1017
|
|
|
|
|
|
|
$invert = 1; |
|
1018
|
|
|
|
|
|
|
} |
|
1019
|
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
my $component = $self->getHash_Component($component_name); |
|
1021
|
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
# must find exactly one component with this name |
|
1023
|
|
|
|
|
|
|
return unless(defined($component)); |
|
1024
|
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
my $set = ($component->{'Attributes'} & $attr_num) ? 1 : 0; |
|
1026
|
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
$set = !$set if($invert); |
|
1028
|
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
return $set; |
|
1030
|
|
|
|
|
|
|
} |
|
1031
|
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
=item I |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
my $attr_number = $is->get_component_attribute_value( 'LocalOnly' ); |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
Given a component attribute name, returns the bit value associated |
|
1037
|
|
|
|
|
|
|
with the attribute. The msidbComponentAttributes prefix for attribute names |
|
1038
|
|
|
|
|
|
|
is accepted, but not required. Given a valid attribute value, simply returns |
|
1039
|
|
|
|
|
|
|
the value. Returns undef on invalid input. |
|
1040
|
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
=cut |
|
1042
|
|
|
|
|
|
|
sub get_component_attribute_value { |
|
1043
|
|
|
|
|
|
|
my ($self, $attribute) = @_; |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
$attribute =~ s/^msidbComponentAttributes//; |
|
1046
|
|
|
|
|
|
|
if($attribute =~ /^\d+$/) { |
|
1047
|
|
|
|
|
|
|
if(exists($component_attr_names{$attribute})) { |
|
1048
|
|
|
|
|
|
|
return $attribute; |
|
1049
|
|
|
|
|
|
|
} |
|
1050
|
|
|
|
|
|
|
} elsif(exists($component_attr_values{$attribute})) { |
|
1051
|
|
|
|
|
|
|
return $component_attr_values{$attribute}; |
|
1052
|
|
|
|
|
|
|
} |
|
1053
|
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
return; |
|
1055
|
|
|
|
|
|
|
} |
|
1056
|
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
=item I |
|
1058
|
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
my $attr_name = $is->get_component_attribute_name( 512 ); |
|
1060
|
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
Given a component attribute value, returns the name associated |
|
1062
|
|
|
|
|
|
|
with the value. Given a valid attribute name, simply returns |
|
1063
|
|
|
|
|
|
|
the name. The msidbComponentAttributes prefix for attribute names |
|
1064
|
|
|
|
|
|
|
is accepted, but not required. Returns undef on invalid input. |
|
1065
|
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
=cut |
|
1067
|
|
|
|
|
|
|
sub get_component_attribute_name { |
|
1068
|
|
|
|
|
|
|
my ($self, $attribute) = @_; |
|
1069
|
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
$attribute =~ s/^msidbComponentAttributes//; |
|
1071
|
|
|
|
|
|
|
if($attribute =~ /^\d+$/) { |
|
1072
|
|
|
|
|
|
|
if(exists($component_attr_names{$attribute})) { |
|
1073
|
|
|
|
|
|
|
return $component_attr_values{$attribute}; |
|
1074
|
|
|
|
|
|
|
} |
|
1075
|
|
|
|
|
|
|
} elsif(exists($component_attr_values{$attribute})) { |
|
1076
|
|
|
|
|
|
|
return $component_attr_names{$attribute}; |
|
1077
|
|
|
|
|
|
|
} |
|
1078
|
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
return; |
|
1080
|
|
|
|
|
|
|
} |
|
1081
|
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
=item I |
|
1083
|
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
my @attr_names = $is->valid_component_attributes; |
|
1085
|
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
Returns a list of valid attribute names. |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
=cut |
|
1089
|
|
|
|
|
|
|
sub valid_component_attributes { |
|
1090
|
|
|
|
|
|
|
return map { $component_attr_names{$_} } sort { $a <=> $b } keys %component_attr_names; |
|
1091
|
|
|
|
|
|
|
} |
|
1092
|
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
=back |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
=head1 ROW MANIPULATION METHOD SYNTAX |
|
1096
|
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
Row manipulation methods can be called in different ways. |
|
1098
|
|
|
|
|
|
|
First, they are all case insensitve, and the '_' is |
|
1099
|
|
|
|
|
|
|
optional, so for the 'Property' table, these are equivilent: |
|
1100
|
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
$is->add_row( 'Property', $rowdata ); |
|
1102
|
|
|
|
|
|
|
$is->AddRow( 'Property', $rowdata ); |
|
1103
|
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
Also, you can call each method using the table name in |
|
1105
|
|
|
|
|
|
|
place of the word 'row', so these are equivilent to the |
|
1106
|
|
|
|
|
|
|
two above: |
|
1107
|
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
$is->add_property( $rowdata ); |
|
1109
|
|
|
|
|
|
|
$is->AddProperty( $rowdata ); |
|
1110
|
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
All row manipulation methods are called with a set of data |
|
1112
|
|
|
|
|
|
|
describing a row. In the methods below, it is represented by |
|
1113
|
|
|
|
|
|
|
the variable $rowdata. It can be passed to the function in |
|
1114
|
|
|
|
|
|
|
one of three formats: a list, an array ref or a hash ref. |
|
1115
|
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
List |
|
1117
|
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
You can simply put the columns in an array in the correct |
|
1119
|
|
|
|
|
|
|
order (which you can get by looking at the ism or calling |
|
1120
|
|
|
|
|
|
|
the I method), and pass it to the method. |
|
1121
|
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
my @rowdata = ( 'Column_1_Value', 'Column_2_value' ); |
|
1123
|
|
|
|
|
|
|
$success = $is->update_row( $table, @rowdata ); |
|
1124
|
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
Array ref |
|
1126
|
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
You can do the same as above, but pass it as a single |
|
1128
|
|
|
|
|
|
|
array reference. |
|
1129
|
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
$success = $is->update_row( $table, \@rowdata ); |
|
1131
|
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
Hash ref |
|
1133
|
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
You can also pass a hash ref, using column names |
|
1135
|
|
|
|
|
|
|
as keys. |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
my %rowdata = ( |
|
1138
|
|
|
|
|
|
|
Property => 'ProductVersion', |
|
1139
|
|
|
|
|
|
|
Value => '1.2.3.4', |
|
1140
|
|
|
|
|
|
|
ISComments => '', |
|
1141
|
|
|
|
|
|
|
); |
|
1142
|
|
|
|
|
|
|
$success = $is->update_row( $table, \%rowdata ); |
|
1143
|
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
=head1 ROW MANIPULATION METHODS |
|
1145
|
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
=over 4 |
|
1147
|
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
=item I |
|
1149
|
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
my $row = $is->getHash_row( $table, $rowdata ); |
|
1151
|
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
Returns a hash ref containing the data that matches the keys |
|
1153
|
|
|
|
|
|
|
supplied in $rowdata. Returns undef if the row is not found. |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
=cut |
|
1156
|
|
|
|
|
|
|
sub _get_row_hash { |
|
1157
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
1158
|
|
|
|
|
|
|
my $args = $self->_reformat_args($table, @args); |
|
1159
|
|
|
|
|
|
|
my $rowkey = $self->_find_row($table, $args); |
|
1160
|
|
|
|
|
|
|
if(defined($rowkey)) { |
|
1161
|
|
|
|
|
|
|
my %rowdata; |
|
1162
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
1163
|
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
foreach my $i (0..$#{$p->{'columns'}}) { |
|
1165
|
|
|
|
|
|
|
$rowdata{ $p->{'columns'}[$i]{'name'} } = $p->{'data'}{$rowkey}[$i]; |
|
1166
|
|
|
|
|
|
|
} |
|
1167
|
|
|
|
|
|
|
return \%rowdata; |
|
1168
|
|
|
|
|
|
|
} else { |
|
1169
|
|
|
|
|
|
|
return; |
|
1170
|
|
|
|
|
|
|
} |
|
1171
|
|
|
|
|
|
|
} |
|
1172
|
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
=item I |
|
1174
|
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
my $row = $is->getArray_row( $table, $rowdata ); |
|
1176
|
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
Returns an array ref containing the data that matches the keys |
|
1178
|
|
|
|
|
|
|
supplied in $rowdata. Returns undef if the row is not found. |
|
1179
|
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
=cut |
|
1181
|
|
|
|
|
|
|
sub _get_row_array { |
|
1182
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
1183
|
|
|
|
|
|
|
my $args = $self->_reformat_args($table, @args); |
|
1184
|
|
|
|
|
|
|
my $rowkey = $self->_find_row($table, $args); |
|
1185
|
|
|
|
|
|
|
if(defined($rowkey)) { |
|
1186
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
1187
|
|
|
|
|
|
|
return $p->{'data'}{$rowkey}; |
|
1188
|
|
|
|
|
|
|
} else { |
|
1189
|
|
|
|
|
|
|
return; |
|
1190
|
|
|
|
|
|
|
} |
|
1191
|
|
|
|
|
|
|
} |
|
1192
|
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
=item I |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
my $success = $is->update_row( $table, $rowdata ); |
|
1196
|
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
Updates the row that matches the keys supplied in |
|
1198
|
|
|
|
|
|
|
$rowdata. Any columns for which an undef is supplied |
|
1199
|
|
|
|
|
|
|
will remain unchanged. An empty string will force |
|
1200
|
|
|
|
|
|
|
the column to be empty. Returns 1 on success, 0 on |
|
1201
|
|
|
|
|
|
|
failure. |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
=cut |
|
1204
|
|
|
|
|
|
|
sub _update_row { |
|
1205
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
1206
|
|
|
|
|
|
|
my $rowdata = $self->_check_args($table, @args); |
|
1207
|
|
|
|
|
|
|
unless(defined($rowdata)) { |
|
1208
|
|
|
|
|
|
|
return 0; |
|
1209
|
|
|
|
|
|
|
} |
|
1210
|
|
|
|
|
|
|
my $rowkey = $self->_find_row($table, $rowdata); |
|
1211
|
|
|
|
|
|
|
unless(defined($rowkey)) { |
|
1212
|
|
|
|
|
|
|
carp("Failed to locate row in $table for update"); |
|
1213
|
|
|
|
|
|
|
return 0; |
|
1214
|
|
|
|
|
|
|
} |
|
1215
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
1216
|
|
|
|
|
|
|
foreach my $i (0..$#{$rowdata}) { |
|
1217
|
|
|
|
|
|
|
if(defined($rowdata->[$i])) { |
|
1218
|
|
|
|
|
|
|
$p->{'data'}{$rowkey}[$i] = $rowdata->[$i]; |
|
1219
|
|
|
|
|
|
|
} |
|
1220
|
|
|
|
|
|
|
} |
|
1221
|
|
|
|
|
|
|
return 1; |
|
1222
|
|
|
|
|
|
|
} |
|
1223
|
|
|
|
|
|
|
|
|
1224
|
|
|
|
|
|
|
=item I |
|
1225
|
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
my $success = $is->add_row( $table, $rowdata ); |
|
1227
|
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
Adds a row containing the data in $rowdata. Returns |
|
1229
|
|
|
|
|
|
|
1 on success, 0 on failure. |
|
1230
|
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
=cut |
|
1232
|
|
|
|
|
|
|
sub _add_row { |
|
1233
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
1234
|
|
|
|
|
|
|
my $rowdata = $self->_check_args($table, @args); |
|
1235
|
|
|
|
|
|
|
unless(defined($rowdata)) { |
|
1236
|
|
|
|
|
|
|
return 0; |
|
1237
|
|
|
|
|
|
|
} |
|
1238
|
|
|
|
|
|
|
my $rowkey = $self->_find_row($table, $rowdata); |
|
1239
|
|
|
|
|
|
|
if(defined($rowkey)) { |
|
1240
|
|
|
|
|
|
|
carp("Row to add in '$table' table already exists"); |
|
1241
|
|
|
|
|
|
|
return 0; |
|
1242
|
|
|
|
|
|
|
} |
|
1243
|
|
|
|
|
|
|
$rowkey = $self->_build_key($table, $rowdata); |
|
1244
|
|
|
|
|
|
|
unless(defined($rowkey)) { |
|
1245
|
|
|
|
|
|
|
return 0; |
|
1246
|
|
|
|
|
|
|
} |
|
1247
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
1248
|
|
|
|
|
|
|
$p->{'data'}{$rowkey} = $rowdata; |
|
1249
|
|
|
|
|
|
|
return 1; |
|
1250
|
|
|
|
|
|
|
} |
|
1251
|
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
=item I |
|
1253
|
|
|
|
|
|
|
|
|
1254
|
|
|
|
|
|
|
my $success = $is->del_row( $table, $rowdata ); |
|
1255
|
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
Deletes the row that matches the keys supplied in |
|
1257
|
|
|
|
|
|
|
$rowdata. Returns 1 on success, 0 on failure. |
|
1258
|
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
=cut |
|
1260
|
|
|
|
|
|
|
sub _del_row { |
|
1261
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
1262
|
|
|
|
|
|
|
my $args = $self->_reformat_args($table, @args); |
|
1263
|
|
|
|
|
|
|
my $rowkey = $self->_find_row($table, $args); |
|
1264
|
|
|
|
|
|
|
unless(defined($rowkey)) { |
|
1265
|
|
|
|
|
|
|
carp("Failed to locate row in $table for delete"); |
|
1266
|
|
|
|
|
|
|
return 0; |
|
1267
|
|
|
|
|
|
|
} |
|
1268
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
1269
|
|
|
|
|
|
|
delete($p->{'data'}{$rowkey}); |
|
1270
|
|
|
|
|
|
|
return 1; |
|
1271
|
|
|
|
|
|
|
} |
|
1272
|
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
=item I |
|
1274
|
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
$is->purge_row( $table, $rowdata ); |
|
1276
|
|
|
|
|
|
|
$is->purge_row( 'Component', 'Awesome.dll' ); |
|
1277
|
|
|
|
|
|
|
$is->PurgeComponent( 'Awesome.dll' ); |
|
1278
|
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
Removes the row that matches the key in $rowdata from the given table, and any rows |
|
1280
|
|
|
|
|
|
|
in other tables with foreign keys that reference it. Key values are |
|
1281
|
|
|
|
|
|
|
case sensitive. This only works for tables with a key column that has |
|
1282
|
|
|
|
|
|
|
the same name as the table, which seems to be the only way you can use |
|
1283
|
|
|
|
|
|
|
foreign keys in an ISM in any case. Returns 1 on success, 0 on failure. |
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
=cut |
|
1286
|
|
|
|
|
|
|
sub _purge_row { |
|
1287
|
|
|
|
|
|
|
my ($self, $table, $key_value) = @_; |
|
1288
|
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
# make sure the key exists in the table |
|
1290
|
|
|
|
|
|
|
my $rowkey = $self->_find_row($table, $self->_reformat_args($table, $key_value)); |
|
1291
|
|
|
|
|
|
|
unless(defined($rowkey)) { |
|
1292
|
|
|
|
|
|
|
return 0; |
|
1293
|
|
|
|
|
|
|
} |
|
1294
|
|
|
|
|
|
|
|
|
1295
|
|
|
|
|
|
|
$self->_del_row($table, $rowkey); |
|
1296
|
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
my $foreign_key_col = $self->{'correct_case'}{$table} . '_'; |
|
1298
|
|
|
|
|
|
|
|
|
1299
|
|
|
|
|
|
|
foreach my $table (@{$self->{'foreign_keys'}{$foreign_key_col}}) { |
|
1300
|
|
|
|
|
|
|
my $rows_to_delete = $self->_search_row_array($table, { $foreign_key_col => $key_value }); |
|
1301
|
|
|
|
|
|
|
if(@{$rows_to_delete}) { |
|
1302
|
|
|
|
|
|
|
foreach my $row (@{$rows_to_delete}) { |
|
1303
|
|
|
|
|
|
|
$self->_del_row($table, $row) or return 0; |
|
1304
|
|
|
|
|
|
|
} |
|
1305
|
|
|
|
|
|
|
} |
|
1306
|
|
|
|
|
|
|
} |
|
1307
|
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
return 1; |
|
1309
|
|
|
|
|
|
|
} |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
=item I |
|
1312
|
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
my $success = $is->add_or_update_row( $table, $rowdata ); |
|
1314
|
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
Adds a row if no row exists with the supplied keys, updates |
|
1316
|
|
|
|
|
|
|
the matching row otherwise. |
|
1317
|
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
=cut |
|
1319
|
|
|
|
|
|
|
sub _add_or_update_row { |
|
1320
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
1321
|
|
|
|
|
|
|
my $args = $self->_reformat_args($table, @args); |
|
1322
|
|
|
|
|
|
|
my $rowkey = $self->_find_row($table, $args); |
|
1323
|
|
|
|
|
|
|
if(defined($rowkey)) { |
|
1324
|
|
|
|
|
|
|
return $self->_update_row($table, $args); |
|
1325
|
|
|
|
|
|
|
} else { |
|
1326
|
|
|
|
|
|
|
return $self->_add_row($table, $args); |
|
1327
|
|
|
|
|
|
|
} |
|
1328
|
|
|
|
|
|
|
} |
|
1329
|
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
=item I |
|
1331
|
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
my $rows = $is->searchHash_row( $table, $rowdata ); |
|
1333
|
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
Returns any rows in the given table that match the supplied |
|
1335
|
|
|
|
|
|
|
columns. The return value is an arrayref, where each entry is |
|
1336
|
|
|
|
|
|
|
a hash as would be returned by I. Returns an empty |
|
1337
|
|
|
|
|
|
|
arrayref if no matches are found. Returns the entire table if |
|
1338
|
|
|
|
|
|
|
no $rowdata argument is provided. |
|
1339
|
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
Columns with undefined values will be ignored for matching purposes. |
|
1341
|
|
|
|
|
|
|
Values used for matching can be either literal strings, in which |
|
1342
|
|
|
|
|
|
|
case an exact match is required, or quoted regular expressions such as: |
|
1343
|
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
my $rows = $is->searchHash_row( 'Property', { Property=>qr/^_/ } ); |
|
1345
|
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
This would search for all properties that begin with an underscore. |
|
1347
|
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
=cut |
|
1349
|
|
|
|
|
|
|
sub _search_row_hash { |
|
1350
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
1351
|
|
|
|
|
|
|
my $args = $self->_reformat_args($table, @args); |
|
1352
|
|
|
|
|
|
|
my $results = $self->_search_row($table, $args); |
|
1353
|
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
my @hash_results; |
|
1355
|
|
|
|
|
|
|
my $p = $self->_parsed($table); |
|
1356
|
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
foreach my $row (@{$results}) { |
|
1358
|
|
|
|
|
|
|
my %rowdata; |
|
1359
|
|
|
|
|
|
|
foreach my $i (0..$#{$p->{'columns'}}) { |
|
1360
|
|
|
|
|
|
|
$rowdata{ $p->{'columns'}[$i]{'name'} } = $row->[$i]; |
|
1361
|
|
|
|
|
|
|
} |
|
1362
|
|
|
|
|
|
|
push(@hash_results, \%rowdata); |
|
1363
|
|
|
|
|
|
|
} |
|
1364
|
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
return \@hash_results; |
|
1366
|
|
|
|
|
|
|
} |
|
1367
|
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
=item I |
|
1369
|
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
my $rows = $is->searchArray_row( $table, $rowdata ); |
|
1371
|
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
Works the same as I, but returns an arrayref containing |
|
1373
|
|
|
|
|
|
|
arrayrefs, like I instead of hashrefs. |
|
1374
|
|
|
|
|
|
|
|
|
1375
|
|
|
|
|
|
|
=cut |
|
1376
|
|
|
|
|
|
|
sub _search_row_array { |
|
1377
|
|
|
|
|
|
|
my ($self, $table, @args) = @_; |
|
1378
|
|
|
|
|
|
|
my $args = $self->_reformat_args($table, @args); |
|
1379
|
|
|
|
|
|
|
return $self->_search_row($table, $args); |
|
1380
|
|
|
|
|
|
|
} |
|
1381
|
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
# this is (almost) a copy of the xml_escape function in XML::Parser::Expat. |
|
1383
|
|
|
|
|
|
|
# The version there doesn't seem to work properly on data that was read |
|
1384
|
|
|
|
|
|
|
# in via XML::Parser, because a call to study causes subsequent matches to |
|
1385
|
|
|
|
|
|
|
# fail |
|
1386
|
|
|
|
|
|
|
sub _xml_escape { |
|
1387
|
|
|
|
|
|
|
my $text = shift @_; |
|
1388
|
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
$text =~ s/\&/\&/g; |
|
1390
|
|
|
|
|
|
|
$text =~ s/\</g; |
|
1391
|
|
|
|
|
|
|
$text =~ s/>/\>/g; |
|
1392
|
|
|
|
|
|
|
|
|
1393
|
|
|
|
|
|
|
foreach (@_) { |
|
1394
|
|
|
|
|
|
|
die "xml_escape: '$_' isn't a single character" if length($_) > 1; |
|
1395
|
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
if ($_ eq '"') { |
|
1397
|
|
|
|
|
|
|
$text =~ s/\"/\"/; |
|
1398
|
|
|
|
|
|
|
} |
|
1399
|
|
|
|
|
|
|
elsif ($_ eq "'") { |
|
1400
|
|
|
|
|
|
|
$text =~ s/\'/\'/; |
|
1401
|
|
|
|
|
|
|
} |
|
1402
|
|
|
|
|
|
|
else { |
|
1403
|
|
|
|
|
|
|
my $rep = '' . sprintf('x%X', ord($_)) . ';'; |
|
1404
|
|
|
|
|
|
|
if (/\W/) { |
|
1405
|
|
|
|
|
|
|
my $ptrn = "\\$_"; |
|
1406
|
|
|
|
|
|
|
$text =~ s/$ptrn/$rep/g; |
|
1407
|
|
|
|
|
|
|
} |
|
1408
|
|
|
|
|
|
|
else { |
|
1409
|
|
|
|
|
|
|
$text =~ s/$_/$rep/g; |
|
1410
|
|
|
|
|
|
|
} |
|
1411
|
|
|
|
|
|
|
} |
|
1412
|
|
|
|
|
|
|
} |
|
1413
|
|
|
|
|
|
|
$text; |
|
1414
|
|
|
|
|
|
|
} |
|
1415
|
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
=back |
|
1417
|
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
=head1 AUTHOR |
|
1419
|
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
Kirk Baucom, Ekbaucom@schizoid.comE |
|
1421
|
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
1423
|
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
Copyright 2003 by Kirk Baucom |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
|
1427
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
|
1428
|
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
=cut |
|
1430
|
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
1; |
|
1432
|
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
__DATA__ |