Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 13:31:54

0001 #!/usr/bin/perl
0002 
0003 use warnings;
0004 use strict;
0005 
0006 use DBI;
0007 
0008 package CondDB::MySQL;
0009 
0010 our $MAXNAME = 32;
0011 
0012 # creates a new database interface
0013 sub new {
0014   my $proto = shift;
0015   my $class = ref($proto) || $proto;
0016   my $this = {};
0017 
0018   $this->{counter} = 0;
0019   $this->{max_cnt} = 100;
0020 
0021   my %args = @_;
0022   $this->{check_overlap} = 1;
0023 
0024   bless($this, $class);
0025   return $this;
0026 }
0027 
0028 sub DESTROY {
0029   my $this = shift;
0030   if ($this->{transaction}) {
0031     $this->commit();
0032   }
0033 
0034   foreach (keys %{$this->{prepared}}) {
0035     $this->{prepared}->{$_}->finish();
0036   }
0037 
0038   foreach (keys %{$this->{prepared_overlap}}) {
0039     $this->{prepared_overlap}->{$_}->finish();
0040   }
0041 
0042   $this->{dbh}->disconnect() if defined $this->{dbh};
0043 }
0044 
0045 sub set_option {
0046   my $this = shift;
0047   my %args = @_;
0048 
0049   if (exists $args{-check_overlap}) {
0050     $this->{check_overlap} = !!$args{-check_overlap};
0051   }
0052 }
0053 
0054 # connect to a database server, optionally selecting the database
0055 sub connect {
0056   my $this = shift;
0057   my %args = @_;
0058   my $host = $args{-host};
0059   my $user = $args{-user};
0060   my $pass = $args{-pass};
0061   my $db_opts = $args{-db_opts};
0062 
0063   unless ($host) {
0064     die "ERROR:  Must give at least host to connect():, $!"
0065   }
0066 
0067   $db_opts->{AutoCommit} = 1;
0068 
0069   my $db = $args{-db};
0070 
0071   my $dsn;
0072   if ($db) {
0073     $dsn = "DBI:mysql:database=$db;host=$host";
0074   } else {
0075     $dsn = "DBI:mysql:host=$host";
0076   }
0077 
0078   my $dbh = DBI->connect($dsn, $user, $pass, $db_opts)
0079     or die "Database connection failed, $DBI::errstr";
0080 
0081   $this->{host} = $host;
0082   $this->{user} = $user;
0083   $this->{db} = $db;
0084   $this->{db_opts} = $db_opts;
0085   $this->{dbh} = $dbh;
0086 
0087   return 1;
0088 }
0089 
0090 sub begin_work {
0091   my $this = shift;
0092   $this->{dbh}->begin_work();
0093   $this->{transaction} = 1;
0094 }
0095 
0096 sub commit {
0097   my $this = shift;
0098   $this->{dbh}->commit();
0099   $this->{transaction} = 0;
0100 }
0101 
0102 sub rollback {
0103   my $this = shift;
0104   $this->{dbh}->rollback();
0105   $this->{transaction} = 0;
0106 }
0107 
0108 # creates and uses a new database
0109 sub newdb {
0110   my $this = shift;
0111   my $dbh = $this->ensure_connect();
0112 
0113   my %args = @_;
0114   my $name = $args{-name} or die "ERROR:  Must give name to newdb(), $!";
0115   $dbh->do(qq[ CREATE DATABASE $name ]) or die "ERROR:  DB creation failed, ".
0116     $dbh->errstr;
0117   $dbh->do(qq[ USE $name ]);
0118 
0119   my $sql =<<END_SQL;
0120 CREATE TABLE conditionDescription (
0121   name varchar($MAXNAME) NOT NULL,
0122   description text,
0123   units varchar(255) default NULL,
0124   datatype char(1) NOT NULL,
0125   datasize int NOT NULL default '1',
0126   hasError tinyint(1) NOT NULL default '0',
0127   PRIMARY KEY  (name)
0128 ) TYPE=InnoDB;
0129 END_SQL
0130 
0131   $dbh->do($sql);
0132 
0133   $sql =<<END_SQL;
0134 CREATE TABLE viewDescription (
0135   name varchar($MAXNAME) NOT NULL,
0136   description text,
0137   id1name varchar($MAXNAME) default NULL,
0138   id2name varchar($MAXNAME) default NULL,
0139   id3name varchar($MAXNAME) default NULL,
0140   PRIMARY KEY  (name)
0141 ) TYPE=InnoDB;
0142 END_SQL
0143 
0144   $dbh->do($sql);
0145 
0146   $sql =<<END_SQL;
0147 CREATE TABLE channelView (
0148   name varchar($MAXNAME) NOT NULL,
0149   id1 int(11) default NULL,
0150   id2 int(11) default NULL,
0151   id3 int(11) default NULL,
0152   maps_to varchar($MAXNAME) NOT NULL,
0153   logic_id int(11) NOT NULL,
0154   UNIQUE (name, id1, id2, id3, logic_id),
0155   INDEX maps_to (maps_to),
0156   INDEX logic_id (logic_id)
0157 ) TYPE=InnoDB;
0158 END_SQL
0159   $dbh->do($sql);
0160 
0161 $sql = <<END_SQL;
0162 CREATE TABLE runs (
0163   run_number INT PRIMARY KEY,
0164   since DATETIME,
0165   till DATETIME,
0166   status TINYINT DEFAULT 1,
0167   comments TEXT,
0168   INDEX (since, till)
0169 ) Type=InnoDB
0170 END_SQL
0171 
0172   $dbh->do($sql);
0173 
0174   $this->{db} = $name;
0175   return 1;
0176 }
0177 
0178 # drop a database
0179 sub destroydb {
0180   my $this = shift;
0181   my $dbh = $this->ensure_connect();
0182 
0183   my %args = @_;
0184   my $name = $args{-name} or die "Must give name to newdb(), $!";
0185 
0186   $dbh->do(qq[ DROP DATABASE IF EXISTS $name ]) 
0187     or die "destroydb failed, ".$dbh->errstr;
0188 
0189   return 1;
0190 }
0191 
0192 # choose the database to use
0193 sub selectdb {
0194   my $this = shift;
0195   my $dbh = $this->ensure_connect();
0196 
0197   my %args = @_;
0198   my $name = $args{-name} or die "Must give name to newdb(), $!";
0199 
0200   $dbh->do(qq[ USE $name ]);
0201 }
0202 
0203 
0204 # delete existing view if it exists and create view in DB
0205 sub new_channelView_type {
0206   my $this = shift;
0207   my $dbh = $this->ensure_connect();
0208 
0209   my %args = @_;
0210   my $name = $args{-name};
0211   my $description = $args{-description};
0212   my ($id1name, $id2name, $id3name) = @{$args{-idnames}};
0213 
0214   check_names($name, $id1name, $id2name, $id3name);
0215 
0216   my $sql;
0217   { no warnings;
0218     $sql = qq[ DELETE FROM channelView WHERE name="$name" ];
0219     $sql =~ s/\"\"/NULL/g;
0220   }
0221   $dbh->do($sql);
0222 
0223   { no warnings;
0224     $sql = qq[ DELETE FROM viewDescription WHERE name="$name" ];
0225     $sql =~ s/\"\"/NULL/g;
0226   }
0227   $dbh->do($sql);
0228 
0229   { no warnings;
0230     $sql = qq[ INSERT INTO viewDescription
0231            SET name="$name",
0232                description="$description",
0233                id1name="$id1name",
0234                id2name="$id2name",
0235                id3name="$id3name" ];
0236     $sql =~ s/\"\"/NULL/g;
0237   }
0238   $dbh->do($sql);
0239 
0240   return 1;
0241 }
0242 
0243 # delete old condition information if it exists, then create a new condition
0244 sub new_cond_type {
0245   my $this = shift;
0246   my $dbh = $this->ensure_connect();
0247 
0248   my %args = @_;
0249   my $name = $args{-name} or die "ERROR:  -name required, $!";
0250   my $description = $args{-description};
0251   my $datasize = $args{-datasize};
0252   my $units = $args{-units};
0253   my $datatype = $args{-datatype} or die "ERROR:  -datatype required, $!";
0254   my $hasError = $args{-hasError};
0255   my $ddl = $args{-ddl};
0256 
0257   $name = "COND_".$name unless $name =~ /^COND_/;
0258   check_names($name);
0259 
0260   $datasize = 1 unless defined $datasize;
0261   $hasError = 0 unless defined $hasError;
0262 
0263   if ($datasize < 1 || $datasize >= 100) {
0264     die "ERROR:  datasize is out of range [1, 99], $!\n";
0265   }
0266 
0267   my $typecode;
0268   my $mysqltype;
0269   if ($datatype =~ /float/) {
0270     $typecode = "f";
0271     $mysqltype = "float";
0272   } elsif ($datatype =~ /int/) {
0273     $typecode = "i";
0274     $mysqltype = "int";
0275   } elsif ($datatype =~ /string/) {
0276     $typecode = "s";
0277     $mysqltype = "varchar(255)";
0278   } else {
0279     die "ERROR:  unknown datatype, $!";
0280   }
0281 
0282   my $sql;
0283   # delete existing condition tables and information if it exists
0284   { no warnings;
0285     $sql = qq[ DROP TABLE IF EXISTS $name ];
0286   }
0287   $dbh->do($sql);
0288 
0289   { no warnings;
0290     $sql = qq[ DELETE FROM conditionDescription WHERE name="$name" ];
0291   }
0292   $dbh->do($sql);
0293 
0294   # create new condition tables and information
0295   { no warnings;
0296     $sql = qq[ CREATE TABLE $name ( logic_id INT NOT NULL,
0297                                     since DATETIME NOT NULL,
0298                                     till DATETIME NOT NULL, ];
0299     if (!$hasError) {
0300       for (0..$datasize-1) {
0301     $sql .= sprintf "value%02d $mysqltype,", $_;
0302       }
0303     } else {
0304       for (0..$datasize-1) {
0305     $sql .= sprintf "value%02d $mysqltype, error%02d $mysqltype,", $_, $_;
0306       }
0307     }
0308     $sql .= qq[ PRIMARY KEY (logic_id, since, till),
0309                 INDEX IoV (since, till)
0310           ) TYPE=INNODB ];
0311   }
0312   $dbh->do($sql);
0313   $ddl = $sql if $ddl;
0314   { no warnings;
0315     $sql = qq[ INSERT INTO conditionDescription
0316              SET name="$name",
0317              description="$description",
0318              units="$units",
0319              datatype="$typecode",
0320                      datasize="$datasize",
0321              hasError="$hasError"];
0322     $sql =~ s/\"\"/NULL/g;
0323   }
0324   $dbh->do($sql);
0325 
0326   if ($ddl) { return $ddl; }
0327   else { return 1; }
0328 }
0329 
0330 # insert a channel
0331 sub insert_channel {
0332     my $this = shift;
0333     my $dbh = $this->ensure_connect();
0334 
0335     my %args = @_;
0336 
0337     my $name = $args{-name};
0338     my ($id1, $id2, $id3) = @{ $args{-channel_ids} };
0339     my $maps_to = $args{-maps_to};
0340     my $logic_id = $args{-logic_id};
0341 
0342     # it is a direct view  by default
0343     $maps_to = $name unless $maps_to;
0344 
0345     # XXX check exists, types are ok, etc
0346 
0347     my $sql;
0348     $sql = qq[ INSERT INTO channelView
0349          SET name=?,
0350          id1=?,
0351          id2=?,
0352          id3=?,
0353                  maps_to=?,
0354          logic_id=? ];
0355 
0356     my $sth = $dbh->prepare_cached($sql);
0357     $sth->execute($name, $id1, $id2, $id3, $maps_to, $logic_id);
0358 
0359     return 1;
0360 }
0361 
0362 # validates and inserts a condition to the database
0363 sub insert_condition {
0364   my $this = shift;
0365   my $dbh = $this->ensure_connect();
0366 
0367   my %args = @_;
0368 
0369   foreach (qw/-name -logic_id -IoV/) {
0370     unless (defined $args{$_}) {
0371       die "ERROR:  $_ required, $!";
0372     }
0373   }
0374 
0375   my $name = $args{-name};
0376   my $logic_id = $args{-logic_id};
0377   my $IoV = $args{-IoV};
0378   my $value = $args{-value}; # single value
0379   my $error = $args{-error}; # single error
0380   my $values = $args{-values}; # arrayref of values
0381   my $errors = $args{-errors}; # arrayref of errors
0382   my $hasError = (defined $error || defined $errors);
0383 
0384   $name = "COND_".$name unless $name =~ /^COND_/;
0385 
0386   if ((defined $value && defined $values) ||
0387       (defined $error && defined $errors)) {
0388     die "ERROR:  defined input of both scalar and array\n";
0389   }
0390 
0391   # check that the IoV is valid
0392   unless (check_iov($IoV)) {
0393     die "ERROR:  IoV ($IoV->{since}, $IoV->{till}) fails validation\n";
0394   }
0395 
0396   # check that the IoV does not overlap something in the DB
0397   if ($this->{check_overlap}) {
0398     my $overlap = $this->is_overlap(-name=>$name,
0399                     -logic_id=>$logic_id,
0400                     -IoV=>$IoV);
0401     if ($overlap) {
0402       die "ERROR:  overlapping condition:\n", $overlap;
0403     }
0404   }
0405 
0406   # check to see if a statement has been prepared
0407   unless (exists $this->{prepared}->{$name}) {
0408     $this->prepare_cached(-name=>$name);
0409   }
0410 
0411   if ($this->{counter} == 0) { $this->begin_work(); }
0412 
0413   my @vars = ($logic_id, $IoV->{since}, $IoV->{till});
0414   if (defined $value) {
0415     push @vars, $value;
0416     push @vars, $error if $hasError;
0417   } elsif (defined $values && !defined $errors) {
0418     push @vars, @{$values};
0419   } elsif (defined $values && defined $errors) {
0420     my $num_vals = scalar @{$values};
0421     my $num_errs = scalar @{$errors};
0422     unless ($num_vals == $num_errs) {
0423       die "ERROR:  Number of values different than number of errors, $!";
0424     }
0425     for (0..$num_vals-1) {
0426       push @vars, shift @{$values}, shift @{$errors};
0427     }
0428   } else {
0429     die "ERROR:  undefined data input\n";
0430   }
0431 
0432   # XXX should check that the number of params matches the expected datasize
0433 
0434   my $sth = $this->{prepared}->{$name};
0435   $sth->execute(@vars);
0436 
0437   # counter management.  For performance evaluation
0438   $this->{counter}++;
0439   if ($this->{counter} >= $this->{max_cnt}) {
0440     $this->commit();
0441     $this->{counter} = 0;
0442   }
0443   return 1;
0444 }
0445 
0446 # insert a run
0447 sub insert_run {
0448   my $this = shift;
0449   my $dbh = $this->{dbh};
0450 
0451   my %args = @_;
0452   my $run_number = $args{-run_number};
0453   my $IoV = $args{-IoV};
0454 
0455   unless (defined $run_number) {
0456     die "ERROR:  insert_run needs -run_number\n";
0457   }
0458 
0459   # check that the IoV is valid
0460   unless (check_iov($IoV)) {
0461     die "ERROR:  IoV ($IoV->{since}, $IoV->{till}) fails validation\n";
0462   }
0463 
0464   my $sql = qq[ INSERT INTO runs VALUES (?, ?, ?, NULL, NULL) ];
0465   my $insert = $dbh->prepare_cached($sql);
0466   
0467   $insert->execute($run_number, $IoV->{since}, $IoV->{till});
0468 
0469   return 1;
0470 }
0471 
0472 # update a run
0473 sub update_run {
0474   my $this = shift;
0475 
0476   my %args = @_;
0477 
0478   my $run = $args{-run_number};
0479   my $status = $args{-status};
0480   my $comments = $args{-comments};
0481 
0482   unless (defined $run && defined $status) {
0483     die "Need to at least send a status to update_run.  skipping.\n";
0484   }
0485   
0486   unless (defined $comments) {
0487     $comments = "NULL";
0488   }
0489 
0490   my $sql = qq[ UPDATE runs SET status=$status, comments="$comments"
0491         WHERE run_number=$run ];
0492 
0493   $this->{dbh}->do($sql);
0494   return 1;
0495 }
0496 
0497 sub prepare_cached {
0498   my $this = shift;
0499   my $dbh = $this->ensure_connect();
0500 
0501   my %args = @_;
0502 
0503   unless (defined $args{'-name'}) {
0504     die "ERROR:  $_ required, $!";
0505   }
0506 
0507   my $name = $args{-name};
0508 
0509   $name = "COND_".$name unless $name =~ /^COND_/;
0510   my $desc = $this->get_conditionDescription(-name=>$name);
0511   unless (defined $desc) {
0512     die "ERROR:  Condition $name is not defined in the DB\n";
0513   }
0514   my $hasError = $desc->{hasError};
0515   my $datasize = $desc->{datasize};
0516 
0517   my $sql;
0518   { no warnings;
0519     $sql = qq[ INSERT INTO $name
0520            SET logic_id=?,
0521            since=?,
0522            till=?, ];
0523     my @fields;
0524     for (0..$datasize-1) {
0525       push @fields, sprintf("value%02d=?", $_);
0526       if ($hasError) {
0527     push @fields, sprintf("error%02d=?", $_);
0528       }
0529     }
0530     $sql .= join ',', @fields;
0531   }
0532   my $sth = $dbh->prepare_cached($sql);
0533   $this->{prepared}->{$name} = $sth;
0534 
0535   return 1;
0536 }
0537 
0538 # returns overlap information if the given $IoV has any overlaps with IoVs 
0539 # in the DB.  Else returns 0
0540 sub is_overlap {
0541   my $this = shift;
0542   my $dbh = $this->ensure_connect();
0543 
0544   my %args = @_;
0545   my $name = $args{-name};
0546   my $logic_id = $args{-logic_id};
0547   my $IoV = $args{-IoV};
0548 
0549   my $t1 = $IoV->{since};
0550   my $t2 = $IoV->{till};
0551 
0552   my $sql;
0553 
0554   unless (exists $this->{prepared_overlap}->{$name}) {
0555     $this->prepare_overlap_check(-name=>$name);
0556   }
0557 
0558   my $sth = $this->{prepared_overlap}->{$name};
0559   $sth->execute($logic_id, $t1, $t2, $t1, $t2, $t1, $t2);
0560 #  $sth->execute(($logic_id, $t1, $t2)x3);
0561   my ($db_id, $db_t1, $db_t2) = $sth->fetchrow_array();
0562 
0563   if ($db_id) {
0564     my $in_str = "input:  ". join ' ', $logic_id, $t1, $t2;
0565     my $db_str = "   db:  ". join ' ', $db_id, $db_t1, $db_t2;
0566     return "$in_str\n$db_str";
0567   } else {
0568     return 0;
0569   }
0570 }
0571 
0572 sub prepare_overlap_check {
0573   my $this = shift;
0574   my $dbh = $this->ensure_connect();
0575 
0576   my %args = @_;
0577 
0578   unless (defined $args{'-name'}) {
0579     die "ERROR:  $_ required, $!";
0580   }
0581 
0582   my $name = $args{-name};
0583 
0584   $name = "COND_".$name unless $name =~ /^COND_/;
0585 
0586   my $sql;
0587   { no warnings;
0588     # argument order is logic_id, t1, t2, t1, t2, t1, t2
0589     $sql = qq[ SELECT logic_id, since, till FROM $name
0590            WHERE logic_id = ?
0591              AND ((since >= ? AND since < ?)
0592                   OR (till  >  ? AND till  < ?)
0593                   OR (? >= since AND ? < till))
0594            LIMIT 1
0595          ];
0596   }
0597 
0598 
0599 #    { no warnings;
0600 #      $sql = qq[ SELECT logic_id, since, till FROM $name
0601 #            WHERE logic_id = ?
0602 #            AND (since >= ? AND since < ?)
0603 #          UNION
0604 #          SELECT logic_id, since, till FROM $name
0605 #            WHERE logic_id = ?
0606 #            AND (till  >  ? AND till  < ?)
0607 #          UNION
0608 #          SELECT logic_id, since, till FROM $name
0609 #            WHERE logic_id = ?
0610 #            AND (? >= since AND ? < till) ];
0611 #    }
0612 
0613   my $sth = $dbh->prepare_cached($sql);
0614   $this->{prepared_overlap}->{$name} = $sth;
0615 
0616   return 1;
0617 }
0618 
0619 
0620 # get a condition, returns a scalar only if the condition table is only
0621 # defined as a sigle value.  else it returns an array in the form
0622 # (value00, value01, value03, ...) or
0623 # (value00, error00, value01, error01, ...)
0624 # depending on if there are errors defined
0625 sub get_condition {
0626   my $this = shift;
0627   my $dbh = $this->ensure_connect();
0628 
0629   my %args = @_;
0630   my $name = $args{-name};
0631   my $logic_id = $args{-logic_id};
0632   my $time = $args{-time};
0633 
0634   $name = "COND_".$name unless $name =~ /^COND_/;
0635 
0636   my @fields;
0637   $name = "COND_".$name unless $name =~ /^COND_/;
0638   my $desc = $this->get_conditionDescription(-name=>$name);
0639   unless (defined $desc) {
0640     die "ERROR:  Condition $name is not defined in the DB\n";
0641   }
0642   my $hasError = $desc->{hasError};
0643   my $datasize = $desc->{datasize};
0644 
0645   for (0..$datasize-1) {
0646     push @fields, sprintf("value%02d", $_);
0647     if ($hasError) {
0648       push @fields, sprintf("error%02d", $_);
0649     }
0650   }
0651   my $fields = join ',', @fields;
0652 
0653   my $sql;
0654   { no warnings;
0655     $sql = qq[ SELECT $fields FROM $name
0656            WHERE logic_id="$logic_id"
0657              AND since <= "$time"
0658              AND till  >  "$time" ];
0659   }
0660 
0661   my @results = @{$dbh->selectall_arrayref($sql)};
0662   if (scalar @results > 1) {
0663     warn "ERROR:  Overlapping IoV found in table $name, logic_id, $logic_id, ".
0664       "time $time";
0665   }
0666 
0667   if (scalar @{$results[0]} == 1) {
0668     return $results[0][0];
0669   } else {
0670     return @{$results[0]};
0671   }
0672 }
0673 
0674 # return an entire channel map of view_ids pointing to a logic_id
0675 sub get_channelView {
0676   my $this = shift;
0677   my $dbh = $this->ensure_connect();
0678 
0679   my %args = @_;
0680   my $name = $args{-name};
0681   my $maps_to = $args{-maps_to};
0682 
0683   # channel is a canonical channel by default
0684   $maps_to = $name unless $maps_to;
0685 
0686   my $sql;
0687   { no warnings;
0688     $sql = qq[ SELECT id1, id2, id3, logic_id
0689            FROM channelView WHERE name="$name" AND maps_to="$maps_to"];
0690   }
0691 
0692   # this recursive subroutine turns an array of values into a hash tree with
0693   # the last item as the leaf
0694   # e.g. ($ref, 1, 2, 3, undef, undef, undef, "VALUE")
0695   # makes $ref->{1}->{2}->{3} = "VALUE"
0696   # sub tack_on {
0697 #     my ($ref, @values) = @_;
0698 #     my $key = shift @values;
0699 #     if (defined $key && defined $values[0]) {
0700 #       $ref->{$key} = {} unless exists $ref->{$key};
0701 #       tack_on($ref->{$key}, @values);
0702 #     } else {
0703 #       $ref->{$key} = pop @values;
0704 #     }
0705 #   }
0706 
0707 #   my $view = {};
0708 #   my @results = @{$dbh->selectall_arrayref($sql)};
0709 #   foreach (@results) {
0710 #     my @row = @{$_};
0711 #     tack_on($view, @row);
0712 #   }
0713 
0714   my $view = {};
0715   my @results = @{$dbh->selectall_arrayref($sql)};
0716   
0717   if (scalar @results == 0) {
0718     return undef;
0719   }
0720 
0721   foreach (@results) {
0722     my ($id1, $id2, $id3, $logic_id) = map {defined $_ ? $_ : ''} @{$_};
0723     $view->{$id1}->{$id2}->{$id3} = $logic_id;
0724   }
0725 
0726   return $view;
0727 }
0728 
0729 # returns an array of logic_ids for used in a channelView
0730 sub get_channelView_logic_ids {
0731   my $this = shift;
0732   my $dbh = $this->ensure_connect();
0733 
0734   my %args = @_;
0735   my $name = $args{-name};
0736   my $maps_to = $args{-maps_to};
0737 
0738   # channel is a canonical channel by default
0739   $maps_to = $name unless $maps_to;
0740 
0741   my $sql;
0742   $sql = qq[ SELECT logic_id
0743          FROM channelView WHERE name="$name" AND maps_to="$maps_to"];
0744   return @{$dbh->selectcol_arrayref($sql)};
0745 }
0746 
0747 # returns true if a condition type has an error defined
0748 sub hasError {
0749   my $this = shift;
0750   my $dbh = $this->ensure_connect();
0751 
0752   my %args = @_;
0753   my $name = $args{-name};
0754 
0755   my $desc = $this->get_conditionDescription(-name=>$name);
0756   return $desc->{hasError};
0757 }
0758 
0759 # return a list of condition types defined in the DB
0760 sub get_conditionDescription {
0761   my $this = shift;
0762   my $dbh = $this->ensure_connect();
0763 
0764   my %args = @_;
0765   my $name = $args{-name};
0766 
0767   my $sql;
0768   { no warnings;
0769     $sql = qq[ SELECT * FROM conditionDescription WHERE name="$name"];
0770   }
0771 
0772   return $dbh->selectrow_hashref($sql);
0773 }
0774 
0775 # return a list of channel view types defined in the DB
0776 sub get_view_description {
0777 }
0778 
0779 # die if we are not connected
0780 sub ensure_connect {
0781   my $this = shift;
0782 
0783   unless (exists $this->{dbh} && defined $this->{dbh}) {
0784     die "ERROR:  Not connected to database.\n";
0785   }
0786 
0787   # XXX really check the connection
0788 
0789   return $this->{dbh};
0790 }
0791 
0792 ###
0793 ###   PRIVATE FUNCTIONS
0794 ###
0795 
0796 sub check_names {
0797   no warnings;
0798   foreach (@_) {
0799     my $count = length $_;
0800     if ($count > $MAXNAME) {
0801       die "ERROR:  Name \"$_\" is too long.  Names for conditions and ids ".
0802     "can only be $MAXNAME characters long\n";
0803     }
0804   }
0805 }
0806 
0807 sub check_date {
0808   my $date = shift;
0809 
0810   return 0 unless defined $date;
0811 
0812   my @date = ($date =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
0813 
0814   foreach (@date) {
0815     return 0 unless defined $_;
0816   }
0817 
0818   if ($date[0] < 0 || $date[0] > 9999 || # year
0819       $date[1] < 1 || $date[1] > 12 ||   # month
0820       $date[2] < 1 || $date[2] > 31 ||   # day
0821       $date[3] < 0 || $date[3] > 23 ||   # hour
0822       $date[4] < 0 || $date[4] > 59 ||   # minute
0823       $date[5] < 0 || $date[5] > 59) {   # second
0824     return 0;
0825   }
0826 
0827   return 1;
0828 }
0829 
0830 sub check_iov {
0831   my $IoV = shift;
0832   return (check_date($IoV->{since}) &&               # since valid
0833       check_date($IoV->{till})  &&               # till valid
0834       ($IoV->{since} lt $IoV->{till})            # since < till
0835      );
0836 }
0837 
0838 1;