Index: branches/eam_branches/ipp-20100621/ippToPsps/perl/checkOdmStatus.pl
===================================================================
--- branches/eam_branches/ipp-20100621/ippToPsps/perl/checkOdmStatus.pl	(revision 28980)
+++ branches/eam_branches/ipp-20100621/ippToPsps/perl/checkOdmStatus.pl	(revision 28980)
@@ -0,0 +1,182 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use LWP::UserAgent;
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use XML::LibXML;
+use File::Temp qw(tempfile);
+use ippToPsps::IppToPspsDb;
+use ippToPsps::Datastore;
+
+my $singleBatch = undef;
+my $verbose = undef;
+my $save_temps = undef;
+my $fromTime = undef;
+my $toTime = undef;
+my $product = undef;
+
+
+GetOptions(
+        'batch|b=s' => \$singleBatch,
+        'from|f=s' => \$fromTime,
+        'to|t=s' => \$toTime,
+        'product|p=s' => \$product,
+        'verbose|v' => \$verbose,
+        'save_temps|s' => \$save_temps
+        );
+
+if (!defined $product) {
+    print "* OPTIONAL: a datastore product name        -p <name>\n";
+}
+if (!defined $singleBatch) {
+    print "* OPTIONAL: a single batch                  -b                   (default = none)\n";
+}
+if (!defined $fromTime) {
+    $fromTime = "2010-01-01";
+    print "* OPTIONAL: from time                       -f                   (default = $fromTime)\n";
+}
+if (!defined $toTime) {
+    $toTime = "2099-12-31";
+    print "* OPTIONAL: to time                         -t                   (default = $toTime)\n";
+}
+if (!defined $verbose) {
+    $verbose = 0;
+    print "* OPTIONAL: run in verbose mode             -v                   (default = $verbose)\n";
+}
+if (!defined $save_temps) {
+    $save_temps = 0;
+    print "* OPTIONAL: keep temp files                 -t                   (default = $save_temps)\n";
+}
+
+
+my $datastore = new ippToPsps::Datastore($product, 0, 0);
+my $ippToPspsDb = new ippToPsps::IppToPspsDb("ippToPsps", "ippdb01", "ipp", "ipp", $verbose, $save_temps);
+my $odmUrl = "http://web01.psps.ifa.hawaii.edu/a01/OdmWebService/OdmWebService.asmx/GetBatchStatus";
+my $ua = LWP::UserAgent->new;
+$ua->timeout(15);
+$ua->env_proxy;
+
+
+process();
+
+#######################################################################################
+# 
+# Loops through all processed exposures and checks against the ODM, then deletes if necessary 
+# 
+########################################################################################
+sub process {
+
+    my $batches;
+    my $numOfBatches;
+
+    if (defined $singleBatch ) { $numOfBatches = $ippToPspsDb->getSingleBatch($singleBatch, \$batches);}
+    else { $numOfBatches = $ippToPspsDb->getBatchList(\$batches, $fromTime, $toTime);}
+
+    if ($numOfBatches < 1) {return 0;}
+
+    print "\n";
+    printf("+----------------------+--------------+--------------+----------------+---------------+---------+----------+\n");
+    printf("|      Timestamp       |    Batch     |  Exposure ID | Loaded to ODM? | Merge worthy? | Merged? | Deleted? |\n");
+    printf("+----------------------+--------------+--------------+----------------+---------------+---------+----------+\n");
+
+    # loop round batches
+    my $batch;
+    my $numChecked = 0;
+    foreach $batch ( @{$batches} ) {
+        my ($timestamp, $expId, $batchId, $surveyType, $deleted) =  @{$batch};
+
+        if (checkBatch($timestamp, $expId, $batchId, $surveyType, $deleted)) {$numChecked++;}
+
+    }
+    printf("+----------------------+--------------+--------------+----------------+---------------+---------+----------+\n");
+
+    printf( "* Successfully checked %d batch%s out of %d\n", $numChecked, ($numChecked==1) ? "" : "es", $numOfBatches);
+
+}
+
+######################################################################################y
+# 
+# Check a single batch
+# 
+########################################################################################
+sub checkBatch {
+    my ($timestamp, $expId, $batchId, $surveyType, $deleted) = @_;
+
+
+    my $batchFilter = sprintf("B%08d", $batchId);
+    my $statusFilter = "*";
+
+    my $response = $ua->post($odmUrl,
+            [batchNameFilter => $batchFilter,
+            statusFilter => $statusFilter,
+            fromFilter => "2010-01-01",
+            toFilter => "2099-01-01"]
+            );
+
+    # '200' is the 'OK' response
+    if ($response->code != 200) {
+
+        print "Problem connecting to web service for '$batchFilter', HTTP response status: ".$response->status_line."\n";
+        return;
+    }
+    #        print( "HTTP response status: ".$response->content."\n" );
+
+    my ($tempFile, $tempName) = tempfile( "/tmp/ippToPsps_odmXml.XXXX", UNLINK => !$save_temps);
+    print $tempFile $response->content;
+    close($tempFile);
+
+    my $loadedToOdm = 0;
+    my $mergeWorthy = 0;
+    my $mergeCompleted = 0;
+
+    parseXml($tempName, \$loadedToOdm, \$mergeWorthy, \$mergeCompleted);
+
+    # delete from datastore
+    if(defined $product) {
+    
+        if (!$deleted && $loadedToOdm && $mergeWorthy) {
+        
+            $deleted = $datastore->remove($batchFilter);
+            if ($deleted) {
+                $ippToPspsDb->setBatchAsDeleted($batchId, $expId);
+            }
+        }
+    }
+    
+    printf( "| %18s  | %11s  | %10d   |    %6s      |    %6s     | %6s  |  %5s   |\n", 
+            $timestamp, 
+            $batchFilter, 
+            $expId, 
+            $loadedToOdm ? "yes" : "no", 
+            $mergeWorthy ? "yes" : "no", 
+            $mergeCompleted ? "yes" : "no",
+            $deleted ? "yes" : "no");
+
+    $ippToPspsDb->updateODMStatus($batchId, $expId, $loadedToOdm, $mergeWorthy, $mergeCompleted, $deleted);
+
+}
+
+######################################################################################y
+# 
+# Parses ODM XML
+# 
+########################################################################################
+sub parseXml {
+    my ($xmlFile, $loadedToOdm, $mergeWorthy, $mergeCompleted) = @_;
+
+    my $parser = XML::LibXML->new;
+    my $doc = $parser->parse_file($xmlFile);
+    my $xc = XML::LibXML::XPathContext->new($doc);
+    $xc->registerNs('ArrayOfOdmBatchState', 'PanSTARRS.Services.OdmWebService');
+    my $result = $xc->findvalue('//ArrayOfOdmBatchState:Message');
+    ${$loadedToOdm} = 0;
+    ${$mergeWorthy} = 0;
+    ${$mergeCompleted} = 0;
+
+    if ($result =~ m/LoadStarted/) { ${$loadedToOdm} = 1;}
+    if ($result =~ m/MergeWorthy/) { ${$loadedToOdm} = 1; ${$mergeWorthy} = 1;}
+    if ($result =~ m/Merge[1-9]Completed/) { ${$loadedToOdm} = 1; ${$mergeWorthy} = 1; ${$mergeCompleted} = 1;}
+}
+
Index: branches/eam_branches/ipp-20100621/ippToPsps/perl/convertPhotCodesToXml.pl
===================================================================
--- branches/eam_branches/ipp-20100621/ippToPsps/perl/convertPhotCodesToXml.pl	(revision 28980)
+++ branches/eam_branches/ipp-20100621/ippToPsps/perl/convertPhotCodesToXml.pl	(revision 28980)
@@ -0,0 +1,85 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use strict;
+use IPC::Cmd 0.36 qw( can_run run );
+use XML::Writer;
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my $inputPath = undef;
+my $outputPath = "photcodes.xml";
+
+# get user args
+GetOptions(
+        'input|i=s' => \$inputPath,
+        ) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+
+# tell off user for not providing proper args
+pod2usage(
+        -msg => "\n   Required options:\n\n".
+        "--input <path to dvo.photcodes files>\n".
+        -exitval => 3
+        ) unless
+defined $inputPath;
+
+
+
+my $output = new IO::File(">$outputPath");
+my $writer = new XML::Writer(OUTPUT => $output, DATA_MODE => 1, DATA_INDENT=>2);
+$writer->xmlDecl('UTF-8');
+
+$writer->startTag('table', "name" => "PhotoCal");
+
+open (PHOTCODES, $inputPath);
+my $photCode;
+my $zeroPoint;
+my $filter;
+my $description;
+
+while (<PHOTCODES>) {
+
+    chomp;
+
+    if ($_ =~ m/\s+([0-9]+)\s+GPC1.*/) {
+
+        my @columns = split(/\s+/, $_);
+
+        my $filter = $columns[11];
+        my $description = $columns[2];
+        my $photCode = $columns[1];
+        my $zeroPoint = $columns[4];
+        my $extinction = $columns[5];
+
+        $writer->startTag('row',
+                "photoCalID" => $photCode,
+                "filterID" => $filter,
+                "photoCodeDesc" => $description,
+                "AB" => "0.0", # TODO
+                "zeropoint" => $zeroPoint,
+                "extinction" => $extinction,
+                "colorterm" => "0.0", # TODO
+                "colorExtn" => "0.0", # TODO
+                "orphanCalColor" => "0.0", # TODO
+                "orphanCalColorErr" => "0.0", # TODO
+                "startDate" => "54000.");
+
+        $writer->endTag();
+
+
+
+    }
+}
+
+$writer->endTag();
+
+
+close PHOTCODES;
+
+# finish up XML
+#$writer->endTag();
+$writer->end();
+
+
Index: branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/Datastore.pm
===================================================================
--- branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/Datastore.pm	(revision 28980)
+++ branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/Datastore.pm	(revision 28980)
@@ -0,0 +1,84 @@
+#!/usr/bin/perl -w
+
+package ippToPsps::Datastore;
+
+use warnings;
+use strict;
+
+use File::Temp qw(tempfile);
+use IPC::Cmd 0.36 qw( can_run run );
+
+###########################################################################
+#
+# Constructor
+#
+###########################################################################
+sub new {
+
+    my $class = shift;
+    my $self = {
+        _product => shift,
+        _verbose => shift,
+        _save_temps => shift,
+    };
+
+    $self->{_dsreg} = can_run('dsreg') or (warn "* WARNING: Can't find 'dsreg' program");
+
+    bless $self, $class;
+    return $self;
+}
+
+#######################################################################################
+#
+# Register item with datastore
+#
+########################################################################################
+sub register {
+    my ($self, $name, $path, $file, $type, $fileType) = @_;
+
+    my ($tempFile, $tempName) = tempfile( "/tmp/Datastore_dsregList.XXXX", UNLINK => !$self->{_save_temps});
+
+    print $tempFile $file . '|||' . $fileType . "\n";
+
+    # build dsreg command command
+    my $command  = "$self->{_dsreg}";
+    $command .= " --add $name";
+    $command .= " --copy";
+    $command .= " --datapath $path";
+    $command .= " --type $type";
+    $command .= " --product $self->{_product}";
+    $command .= " --list $tempName";
+
+    # run command
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $self->{_verbose});
+
+    if (!$success) { print "* Unable to publish $file to datastore\n" and return 0 };
+
+    print "* Successfully published $file to datastore\n";
+
+    close($tempFile);
+
+    return 1;
+}
+
+#######################################################################################
+#
+# Remove item from datastore
+#
+########################################################################################
+sub remove {
+    my ($self, $name) = @_;
+
+    # build dsreg command command
+    my $command  = "$self->{_dsreg}";
+    $command .= " --del $name";
+    $command .= " --product $self->{_product}";
+
+    # run command                                           
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $self->{_verbose});          
+
+    return $success;
+}
+1;
Index: branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/Gpc1Db.pm
===================================================================
--- branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/Gpc1Db.pm	(revision 28794)
+++ branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/Gpc1Db.pm	(revision 28980)
@@ -28,5 +28,4 @@
         JOIN diffSkyfile USING (diff_id)
         WHERE rawExp.exp_id = $expId AND camRun.magicked
-
 SQL
 
@@ -37,5 +36,28 @@
 ###########################################################################
 #
-# Returns camera-stage smf files for this exposure
+# Returns camera-stage smf file for this exposure as used in the provided DVO Db
+#
+###########################################################################
+sub getCameraStageSmfForThisDvoDb {
+    my ($self, $dvoDb, $expId) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT path_base 
+        FROM camProcessedExp 
+        JOIN addRun USING(cam_id)   
+        JOIN camRun USING(cam_id)  
+        JOIN chipRun USING(chip_id)   
+        JOIN rawExp USING(exp_id)   
+        WHERE addRun.dvodb LIKE '$dvoDb' 
+        AND exp_id = $expId;
+SQL
+
+    $query->execute;
+    return $query->fetchrow_array();
+}
+
+###########################################################################
+#
+# Returns latest processed camera-stage smf file for this exposure ID
 #
 ###########################################################################
@@ -64,22 +86,20 @@
 ###########################################################################
 #
-# Returns a list of exposure IDs for this survey
+# Returns a list of exposure IDs in a given DVO database  
 #
 ###########################################################################
-sub getExposureListFromSurvey {
-    my ($self, $survey) = @_;
+sub getExposureListFromDvoDb {
+    my ($self, $dvoDb, $exposures) = @_;
 
     my $query = $self->{_db}->prepare(<<SQL);
-
-    SELECT rawExp.exp_id, rawExp.exp_name, camRun.dist_group 
-        FROM camRun, chipRun, rawExp 
-        WHERE camRun.state = 'full' 
-        AND camRun.chip_id = chipRun.chip_id 
-        AND chipRun.exp_id = rawExp.exp_id 
-        AND camRun.dist_group = '$survey'   
-        GROUP BY  rawExp.exp_id 
-        ORDER BY rawExp.exp_id ASC;
+    SELECT exp_id, exp_name, camRun.dist_group 
+        FROM addRun 
+        JOIN camRun USING(cam_id) 
+        JOIN chipRun USING(chip_id) 
+        JOIN rawExp USING(exp_id) 
+        WHERE addRun.dvodb LIKE '$dvoDb' 
+        AND addRun.state = 'full'
+        ORDER BY exp_id ASC;
 SQL
-
 
     #AND rawExp.exp_id > 133887
@@ -93,27 +113,47 @@
 
     $query->execute;
-    return $query->fetchall_arrayref();
+    ${$exposures} = $query->fetchall_arrayref();
+    my $numOfExposures = scalar @{${$exposures}};
+    if ($numOfExposures > 0) {
+    
+        print "* Found $numOfExposures exposures in DVO Db '$dvoDb'\n";
+        return 1;
+    }
+
+    print "* No exposures found in DVO Db '$dvoDb'\n";
+    return 0;
 }
 
 ###########################################################################
 #
-# Returns info for this exposure ID
+# Returns info for this exposure ID for given DVO Db
 #
 ###########################################################################
-sub getExposureListFromExpId {
-    my ($self, $expId) = @_;
+sub getSingleExposureFromDvoDb {
+    my ($self, $dvoDb, $expId, $exposures) = @_;
 
     my $query = $self->{_db}->prepare(<<SQL);
-    SELECT DISTINCT rawExp.exp_id,  rawExp.exp_name, dist_group 
-        FROM rawExp, chipRun 
-        WHERE chipRun.exp_id = rawExp.exp_id 
-        AND rawExp.exp_id = $expId
+    SELECT exp_id, exp_name, camRun.dist_group 
+        FROM addRun 
+        JOIN camRun USING(cam_id) 
+        JOIN chipRun USING(chip_id) 
+        JOIN rawExp USING(exp_id) 
+        WHERE addRun.dvodb LIKE '$dvoDb' 
+        AND exp_id = $expId;
 SQL
 
     $query->execute;
-    return $query->fetchall_arrayref();
+
+    ${$exposures} = $query->fetchall_arrayref();
+
+    if (scalar @{${$exposures}} > 0) {
+    
+        print "* Found exposure $expId in DVO Db '$dvoDb'\n";
+        return 1;
+    }
+
+    print "* Exposure $expId NOT found in DVO Db '$dvoDb'\n";
+    return 0;
 }
 
-
-
 1;
Index: branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/IppToPspsDb.pm
===================================================================
--- branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/IppToPspsDb.pm	(revision 28794)
+++ branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps/IppToPspsDb.pm	(revision 28980)
@@ -8,4 +8,55 @@
 use ippToPsps::MySQLDb;
 our @ISA = qw(ippToPsps::MySQLDb);    # inherits from MySQLDb
+
+
+###########################################################################
+#
+# Returns a list of batches that have been processed and loaded to datastore
+#
+###########################################################################
+sub getBatchList {
+    my ($self, $exposures, $fromTime, $toTime) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT created, exp_id, batch_id, survey_id, deleted 
+        FROM batches 
+        WHERE processed = 1 
+        AND on_datastore = 1
+        AND created >= '$fromTime'
+        AND created <= '$toTime';
+SQL
+
+    # TODO remove date restriction
+    $query->execute;
+    ${$exposures} = $query->fetchall_arrayref();
+    my $count = scalar @{${$exposures}};
+
+   printf( "* Found %d batch%s\n", $count, ($count==1) ? "" : "es");
+   return $count;
+}
+
+###########################################################################
+#
+# Returns a info about one particular batch
+#
+###########################################################################
+sub getSingleBatch{
+    my ($self, $batch_id, $exposures) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT created, exp_id, batch_id, survey_id, deleted 
+        FROM batches 
+        WHERE batch_id = $batch_id 
+        AND processed = 1 
+        AND on_datastore = 1;
+SQL
+  
+    $query->execute;
+    ${$exposures} = $query->fetchall_arrayref();
+    my $count = scalar @{${$exposures}};
+
+   printf( "* Found %d batch%s\n", $count, ($count==1) ? "" : "es");
+   return $count;
+}
 
 #######################################################################################
@@ -56,8 +107,9 @@
 #
 ########################################################################################
-sub updateDb {
-    my ($self, $batchId, $expId, $processed, $published, $totalDetections) = @_;
-
-print "HJHJH '$batchId', '$expId', '$processed', '$published', '$totalDetections'\n";
+sub updateBatch {
+    my ($self, $batchId, $expId, $processed, $published, $totalDetections, $minObjId, $maxObjId) = @_;
+
+    if (!$minObjId) {$minObjId = -1;}
+    if (!$maxObjId) {$maxObjId = -1;}
 
 if (!$totalDetections) {$totalDetections = -1;}
@@ -65,5 +117,10 @@
     my $query = $self->{_db}->prepare(<<SQL);
     UPDATE batches 
-        SET processed = $processed, on_datastore = $published, total_detections = $totalDetections 
+        SET 
+          processed = $processed, 
+          on_datastore = $published, 
+          total_detections = $totalDetections,
+          min_obj_id = $minObjId,
+          max_obj_id = $maxObjId
         WHERE batch_id = $batchId 
         AND exp_id = $expId;
@@ -84,5 +141,6 @@
     SELECT COUNT(*) 
         FROM batches 
-        WHERE exp_id = $expId 
+        WHERE exp_id = $expId
+        AND created > '2010-08-12'
         AND processed = 1;
 SQL
@@ -102,6 +160,6 @@
 #
 ########################################################################################
-sub getNewBatchId {
-    my ($self, $expId, $surveyType, $batchType) = @_;
+sub createNewBatch {
+    my ($self, $expId, $surveyType, $batchType, $dvoDb, $datastoreProduct) = @_;
 
     my $query = $self->{_db}->prepare(<<SQL);
@@ -118,10 +176,9 @@
     $batchId++;
 
-    my $query = $self->{_db}->prepare(<<SQL);
+    $query = $self->{_db}->prepare(<<SQL);
     INSERT INTO batches
-        (batch_id, exp_id, survey_id, batch_type)
+        (batch_id, exp_id, survey_id, batch_type, dvo_db, datastore_product)
         VALUES
-        ($batchId, $expId, '$surveyType', '$batchType');
-
+        ($batchId, $expId, '$surveyType', '$batchType', '$dvoDb', '$datastoreProduct');
 SQL
 
@@ -133,4 +190,42 @@
 }
 
+#######################################################################################
+#
+# Updates an existing database record to show datastore status
+#
+#######################################################################################
+sub setBatchAsDeleted {
+    my ($self,$batchId, $expId) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    UPDATE batches 
+        SET deleted = 1 
+        WHERE batch_id = $batchId 
+        AND exp_id = $expId;
+SQL
+
+        $query->execute; # TODO check response of these
+}
+
+#######################################################################################
+#
+# Updates an existing database record with info from ODM
+#
+#######################################################################################
+sub updateODMStatus {
+    my ($self,$batchId, $expId, $loadedToOdm, $mergeWorthy, $mergeCompleted) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    UPDATE batches 
+        SET loaded_to_ODM = $loadedToOdm, merge_worthy = $mergeWorthy, merged = $mergeCompleted 
+        WHERE batch_id = $batchId 
+        AND exp_id = $expId;
+SQL
+
+        $query->execute; # TODO check response of these
+}
+
+
+
 ###########################################################################
 #
@@ -142,10 +237,10 @@
 
     my $currentRevision = -1;
-    my $latestRevision = 4;
+    my $latestRevision = 6;
 
     while ($currentRevision != $latestRevision) {
 
         $currentRevision = $self->getRevision();
-        if ($self->{_verbose}) {print "* Current revision = $currentRevision\n";}
+        if ($self->{_verbose}) {print "* Current database revision = $currentRevision\n";}
 
         if ($currentRevision == 0) {$self->createRevision_1();}
@@ -153,4 +248,6 @@
         elsif ($currentRevision == 2) {$self->createRevision_3();}
         elsif ($currentRevision == 3) {$self->createRevision_4();}
+        elsif ($currentRevision == 4) {$self->createRevision_5();}
+        elsif ($currentRevision == 5) {$self->createRevision_6();}
     }
 }
@@ -164,5 +261,5 @@
     my ($self) = @_;
 
-    print "* Creating revision 1 of '$dbname'\n";
+    print "* Creating revision 1 of '$self->{_dbName}'\n";
 
     my $query = $self->{_db}->prepare(<<SQL);
@@ -175,5 +272,5 @@
         $query->execute;
 
-    my $query = $self->{_db}->prepare(<<SQL);
+    $query = $self->{_db}->prepare(<<SQL);
     CREATE TABLE batches (
             batch_id BIGINT NOT NULL, 
@@ -192,5 +289,5 @@
         $query->execute;
 
-    setRevision(1);
+    $self->setRevision(1);
 }
 
@@ -203,5 +300,5 @@
     my ($self) = @_;
 
-    print "* Creating revision 2 of '$dbname'\n";
+    print "* Creating revision 2 of '$self->{_dbName}'\n";
 
     my $query = $self->{_db}->prepare(<<SQL);
@@ -211,5 +308,5 @@
         $query->execute;
 
-    setRevision(2);
+    $self->setRevision(2);
 }
 
@@ -222,5 +319,5 @@
     my ($self) = @_;
 
-    print "* Creating revision 3 of '$dbname'\n";
+    print "* Creating revision 3 of '$self->{_dbName}'\n";
 
     my $query = $self->{_db}->prepare(<<SQL);
@@ -230,5 +327,5 @@
         $query->execute;
 
-    setRevision(3);
+    $self->setRevision(3);
 }
 
@@ -241,5 +338,5 @@
     my ($self) = @_;
 
-    print "* Creating revision 4 of '$dbname'\n";
+    print "* Creating revision 4 of '$self->{_dbName}'\n";
 
     my $query = $self->{_db}->prepare(<<SQL);
@@ -249,5 +346,45 @@
         $query->execute;
 
-    setRevision(4);
+    $self->setRevision(4);
+}
+
+#######################################################################################
+# 
+# Create revision 5 of the database 
+#
+#######################################################################################
+sub createRevision_5 {
+    my ($self) = @_;
+
+    print "* Creating revision 5 of '$self->{_dbName}'\n";
+
+    my $query = $self->{_db}->prepare(<<SQL);
+         CREATE INDEX batchesIndex ON batches (batch_id);
+SQL
+    $query->execute;
+
+    $self->setRevision(5);
+}
+
+#######################################################################################
+# 
+# Create revision 6 of the database 
+#
+#######################################################################################
+sub createRevision_6 {
+    my ($self) = @_;
+
+    print "* Creating revision 6 of '$self->{_dbName}'\n";
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    ALTER TABLE batches 
+        ADD COLUMN dvo_db VARCHAR(50) DEFAULT "UNKNOWN",
+        ADD COLUMN datastore_product VARCHAR(50)  DEFAULT "UNKNOWN",
+        ADD COLUMN min_obj_id BIGINT DEFAULT 0,
+        ADD COLUMN max_obj_id BIGINT DEFAULT 0
+SQL
+    $query->execute;
+
+    $self->setRevision(6);
 }
 
Index: branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps_run.pl
===================================================================
--- branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps_run.pl	(revision 28794)
+++ branches/eam_branches/ipp-20100621/ippToPsps/perl/ippToPsps_run.pl	(revision 28980)
@@ -6,21 +6,22 @@
 use PS::IPP::Config 1.01 qw( :standard );
 use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
-use Pod::Usage qw( pod2usage );
 use IPC::Cmd 0.36 qw( can_run run );
 use File::Temp qw(tempfile);
 use XML::LibXML;
+use File::Basename;
 
 # local classes
 use ippToPsps::Gpc1Db;
 use ippToPsps::IppToPspsDb;
+use ippToPsps::Datastore;
 
 # globals
 my $camera = 'GPC1';
 my $batchType = undef;
-my $survey = undef;
-my $dvodb = undef;
+my $dvoLocation = undef;
+my $dvoDb = undef;
+my $fullDvoPath = undef;
 my $verbose = undef;
 my $save_temps = undef; 
-my $no_update = undef;
 my $output = undef;
 my $singleExpId = undef;
@@ -34,11 +35,9 @@
         'output|o=s' => \$output,
         'batch|b=s' => \$batchType,
-        'dvodb|d=s' => \$dvodb,
-        'survey|s=s' => \$survey,
+        'dvo|d=s' => \$fullDvoPath,
         'expid|e=s' => \$singleExpId,
         'product|p=s' => \$datastoreProduct,
         'verbose|v' => \$verbose,
         'save_temps|t' => \$save_temps,
-        'no-update|u' => \$no_update,
         'force|f' => \$force,
         'tarnzip|z' => \$dontTarNZip,
@@ -49,41 +48,73 @@
 print "* \n";
 if (@ARGV) {
-    print "* UNKNKOWN: option:                         @ARGV\n"; $quit=1;}
+    $quit=1;
+    print "* UNKNKOWN: option                          @ARGV\n";
+}
 if (!defined $output) {
-    print "* REQUIRED: need to provide an output path: -o <path>\n"; $quit=1;}
+    $quit=1;
+    print "* REQUIRED: need to provide an output path  -o <path>\n";
+}
 if (!defined $batchType) {
-    print "* REQUIRED: need to define a batch type:    -b <init|det|diff|stack>\n"; $quit=1;}
-if (!defined $dvodb) {
-    print "* REQUIRED: need to provide a DVO Db path:  -d <path>\n"; $quit=1;}
-if (!defined $survey and !defined $singleExpId) {
-    print "* REQUIRED: need to provide a survey type:  -s <ThreePi|STS|SAS|M31|MD01|MD02|etc> ***OR***\n";
-    print "*           an exposure ID                  -e <expID>\n"; $quit=1;}
+    $quit=1;
+    print "* REQUIRED: need to define a batch type     -b <init|det|diff|stack>\n";
+}
+if (!defined $fullDvoPath) {
+    $quit=1;
+    print "* REQUIRED: need to provide a DVO Db        -d <pathToDVO>\n";
+}
+if (!defined $singleExpId) {
+
+    print "* OPTIONAL: a single exposure ID            -e <expID>           (default = none)\n";
+}
 if (!defined $datastoreProduct) {
-    print "* OPTIONAL: datastore product:              -p <product>\n";}
+
+    print "* OPTIONAL: datastore product               -p <product>         (default = none, i.e. data will not be published)\n";
+}
 if (!defined $verbose) {
-    print "* OPTIONAL: run in verbose mode:            -v\n"; $verbose = 0;}
+    $verbose = 0;
+    print "* OPTIONAL: run in verbose mode             -v                   (default = $verbose)\n";
+}
 if (!defined $save_temps) {
-    print "* OPTIONAL: keep temp files:                -t\n"; $save_temps = 0;}
-if (!defined $no_update) {
-    print "* OPTIONAL: don't update database:          -u\n"; $no_update = 0;}
+    $save_temps = 0;
+    print "* OPTIONAL: keep temp files                 -t                   (default = $save_temps)\n";
+}
 if (!defined $force) {
-    print "* OPTIONAL: force if already processed :    -f\n"; $force = 0;}
+    $force = 0;
+    print "* OPTIONAL: force if already processed      -f                   (default = $force)\n";
+}
 if (!defined $dontTarNZip) {
-    print "* OPTIONAL: don't tar and zip output :      -z\n"; $dontTarNZip = 0;}
-    print "*\n*******************************************************************************\n";
+    $dontTarNZip = 0;
+    print "* OPTIONAL: don't tar and zip output        -z                   (default = $dontTarNZip)\n";
+}
+print "*\n*******************************************************************************\n";
 
 if ($quit) { exit; }
+
+# determine PSPS batch 'type'
+my $pspsBatchType;
+if ($batchType eq 'init') {$pspsBatchType = "IN";}
+elsif ($batchType eq 'det') {$pspsBatchType = "P2";}
+elsif ($batchType eq 'stack') {$pspsBatchType = "ST";}
+elsif ($batchType eq 'diff') {$pspsBatchType = "OB";}
+else {$pspsBatchType = "UNKNOWN";}
+
+# spilt full DVO path into Db and path
+$fullDvoPath =~ s/\/$//; # strip off trailing '\'
+($dvoDb, $dvoLocation) = fileparse($fullDvoPath);
 
 my $gpc1Db = new ippToPsps::Gpc1Db("gpc1", "ippdb01", "ippuser", "ippuser", $verbose, $save_temps);
 my $ippToPspsDb = new ippToPsps::IppToPspsDb("ippToPsps", "ippdb01", "ipp", "ipp", $verbose, $save_temps);
+my $datastore = undef;
+if ($datastoreProduct) {$datastore = new ippToPsps::Datastore($datastoreProduct, $verbose, $save_temps);}
 
 # check we can run programs and get camera config
 my $ippToPsps = can_run('ippToPsps') or (warn "Can't find 'ippToPsps' program" and exit($PS_EXIT_CONFIG_ERROR));
-my $dsreg = can_run('dsreg') or (warn "Can't find 'dsreg' program" and exit($PS_EXIT_CONFIG_ERROR));
 my $ipprc = PS::IPP::Config->new($camera) or (warn "Can't get camera configuration" and exit($PS_EXIT_CONFIG_ERROR)); 
 
 if ($batchType eq "init") {$initBatch = 1;}
 else {$initBatch = 0;}
-process();
+
+if (!process()) {print "* Finished unsuccessfully\n";}
+else {print "* Finished successfully\n";}
 
 #######################################################################################
@@ -114,16 +145,22 @@
     my ($resultsFile, $resultsFilePath) = tempfile( "/tmp/ippToPsps_results.XXXX", UNLINK => !$save_temps);
     my $lastExpId = $ippToPspsDb->getLastExpId();
-    my $rows = undef;
+    my $exposures;
 
     my $query;
     if ($initBatch) {
-   
-        my @row = (0, 'NULL', 'ThreePi');
-        @{$rows} = (\@row);
-    }
-    elsif ($singleExpId) { $rows = $gpc1Db->getExposureListFromExpId($singleExpId); }
-    else { $rows = $gpc1Db->getExposureListFromSurvey($survey); }
-
-# TODO check if there are no exposures and give a warning
+
+        my @exposure = (0, 'NULL', 'ThreePi');
+        @{$exposures} = (\@exposure);
+    }
+    # get single exposure
+    elsif ($singleExpId) {
+       
+        if (!$gpc1Db->getSingleExposureFromDvoDb($dvoDb, $singleExpId, \$exposures)) {return 0;}
+    }
+    # get all exposures in this DVO Db
+    else {
+        
+        if (!$gpc1Db->getExposureListFromDvoDb($dvoDb, \$exposures)) {return 0;}
+    }
 
     my $batchId = 0;
@@ -132,17 +169,12 @@
 
     #my $batchId = -1;
-    my $row;
-    foreach $row ( @{$rows} ) {
-        my ($expId, $expName, $distGroup) = @{$row};
-    #        print "JHGHGHGHGH2 $expId, $expName, $distGroup\n";
-
-    # loop round exposures
-    #while (my @row = $query->fetchrow_array()) {
-     #   my ($expId, $expName, $distGroup) = @row;
+    my $exposure;
+    foreach $exposure ( @{$exposures} ) {
+        my ($expId, $expName, $distGroup) = @{$exposure};
 
         if (!$initBatch && $ippToPspsDb->isExposureAlreadyProcessed($expId)) {
-                
-                if ($force) {print "* Forcing....\n";} 
-                else {next};
+
+            if ($force) {print "* Forcing....\n";} 
+            else {next};
         }
 
@@ -150,5 +182,5 @@
         if (!$surveyType) {next;}
 
-        $batchId = $ippToPspsDb->getNewBatchId($expId, $surveyType, $batchType);
+        $batchId = $ippToPspsDb->createNewBatch($expId, $distGroup, $pspsBatchType, $dvoDb, (defined $datastore) ? $datastoreProduct : "NONE");
 
         # TODO quit here if no sensible batch ID
@@ -156,6 +188,11 @@
         # generate batch path from batch IDs
         my $batch = sprintf("B%08d", $batchId);
-        my $batchDir = sprintf("$output/$batch");
+        my $dvoDir = "$output/$dvoDb";
+        my $batchDir = "$dvoDir/$batch";
+
+        # make directories
+        unless(-d $dvoDir) {mkdir($dvoDir, 0777);}
         mkdir($batchDir, 0777);
+
         $published = 0;
 
@@ -171,11 +208,17 @@
             if (writeBatchManifest($batchDir, $batch, $batchType, $surveyType, $filename, $minObjId, $maxObjId)) {
 
+                # tar n' zip
                 if (!$dontTarNZip) {
-                    my $tarball = tarAndZipBatch($output, $batch);
-                    if ($tarball && $datastoreProduct && publishToDatastore($batch, $output, $tarball)) {$published = 1;}
+                    my $tarball = tarAndZipBatch($dvoDir, $batch);
+
+                    # and publish
+                    if ($tarball && defined $datastore ) {
+                        
+                        $published = $datastore->register($batch, $dvoDir, $tarball, "IPP_PSPS", "tgz");
+                    }
                 }
             }
 
-            $ippToPspsDb->updateDb($batchId, $expId, 1, $published, $totalDetections);
+            $ippToPspsDb->updateBatch($batchId, $expId, 1, $published, $totalDetections, $minObjId, $maxObjId);
         }
 
@@ -330,12 +373,4 @@
     my $timeStamp = sprintf "%4d-%02d-%02d %02d:%02d:%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec;
 
-    # determine batch 'type'
-    my $type;
-    if ($batchType eq 'init') {$type = "IN";}
-    elsif ($batchType eq 'det') {$type = "P2";}
-    elsif ($batchType eq 'stack') {$type = "ST";}
-    elsif ($batchType eq 'diff') {$type = "OB";}
-    else {$type = "UNKNOWN";}
-
     # create XML file
     my $writer = new XML::Writer(OUTPUT => $output, DATA_MODE => 1, DATA_INDENT=>2);
@@ -372,5 +407,5 @@
                 $writer->startTag('manifest',
                         "name" => "$batch",
-                        "type" => $type,
+                        "type" => $pspsBatchType,
                         "survey" => $pspsSurvey,
                         "timestamp" => "$timeStamp",
@@ -382,5 +417,5 @@
                 $writer->startTag('manifest',
                         "name" => "$batch",
-                        "type" => $type,
+                        "type" => $pspsBatchType,
                         "timestamp" => "$timeStamp");
             }
@@ -404,38 +439,4 @@
 
 #######################################################################################
-#
-# register new job with the datastore
-#
-########################################################################################
-sub publishToDatastore {
-    my ($batch, $path, $tarball) = @_;
-
-    my ($tempFile, $tempName) = tempfile( "/tmp/ippToPsps_dsregList.XXXX", UNLINK => !$save_temps);
-
-    print $tempFile $tarball . '|||tgz' . "\n";
-
-    # build dsreg command command
-    my $command  = "$dsreg";
-    $command .= " --add $batch";
-    $command .= " --copy";
-    $command .= " --datapath $path";
-    $command .= " --type IPP_PSPS";
-    $command .= " --product $datastoreProduct";
-    $command .= " --list $tempName";
-
-    # run command
-    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => $verbose);
-
-    if (!$success) { print "* Unable to publish $tarball to datastore\n" and return 0 };
-
-    print "* Successfully published $tarball to datastore\n";
-
-    close($tempFile);
-
-    return 1;
-}
-
-#######################################################################################
 # 
 # runs ippToPsps to produce init batch 
@@ -457,5 +458,5 @@
     my ($expId, $expName, $surveyType, $outputPath, $resultsFilePath) = @_;
 
-    my $nebPath = $gpc1Db->getCameraStageSmf($expId);
+    my $nebPath = $gpc1Db->getCameraStageSmfForThisDvoDb($dvoDb, $expId);
     if (!$nebPath) { return 0; }
 
@@ -527,7 +528,7 @@
     $command .= " -input $input";
     $command .= " -output $output";
-    $command .= " -D CATDIR $dvodb";
+    $command .= " -D CATDIR $fullDvoPath";
     $command .= " -config ../config"; # TODO
-    $command .= " -expid $expid";
+        $command .= " -expid $expid";
     $command .= " -expname $expName";
     $command .= " -survey $surveyType";
Index: branches/eam_branches/ipp-20100621/ippToPsps/perl/pspsSchema2xml.pl
===================================================================
--- branches/eam_branches/ipp-20100621/ippToPsps/perl/pspsSchema2xml.pl	(revision 28980)
+++ branches/eam_branches/ipp-20100621/ippToPsps/perl/pspsSchema2xml.pl	(revision 28980)
@@ -0,0 +1,337 @@
+#!/usr/bin/perl -w
+
+#######################################################################################
+#
+# Script that searches a dir containing PSPS schema files, finds those that comtain the 
+# tables on interest then parses them into an XML format. Also generates C-header files 
+# containing enums that detail table column names and numbers.
+#
+#######################################################################################
+
+use warnings;
+use strict;
+use IPC::Cmd 0.36 qw( can_run run );
+use XML::Writer;
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my $schemaPath = undef;
+my $type = undef;
+
+# get user args
+GetOptions(
+        'schema|s=s' => \$schemaPath,
+        'type|t=s' => \$type,
+        ) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+
+# tell off user for not providing proper args
+pod2usage(
+        -msg => "\n   Required options:\n\n".
+        "--schema <path to PSPS schema>\n".
+        "--type <init|det|diff|stack|object>\n".
+        -exitval => 3
+        ) unless
+defined $schemaPath and
+defined $type;
+
+if ($type ne "init" && $type ne "det" && $type ne "diff" && $type ne "stack" && $type ne "object" ) {
+
+    print "Don't understand type '$type'\n"; 
+    die;
+}
+
+my $enumsHeader = "ippToPsps".ucfirst($type)."Enums";
+open(OUT, ">".$enumsHeader.".h") or die("Error");
+
+print OUT "#ifndef ".uc($enumsHeader)."_H\n";
+print OUT "#define ".uc($enumsHeader)."_H\n\n";
+
+
+my $output = new IO::File(">tables.xml");
+my $writer = new XML::Writer(OUTPUT => $output, DATA_MODE => 1, DATA_INDENT=>2);
+$writer->xmlDecl('UTF-8');
+#    $writer->doctype('manifest', "", "psps-manifest.dtd");
+$writer->startTag('tableDescriptions', "type" => "$type");
+
+if ($type eq "init") {createInit();}
+elsif ($type eq "det") {createDetections();}
+elsif ($type eq "diff") {createDiffs();}
+elsif ($type eq "stack") {createStacks();}
+elsif ($type eq "object") {createObjects();}
+
+# finish up XML
+$writer->endTag();
+$writer->end();
+
+print OUT "\n#endif";
+close OUT;
+
+
+#######################################################################################
+#
+# Finds the schema file containing the table name passed in
+#
+#######################################################################################
+sub findSchemaFile {
+    my ($tableName) = @_;
+
+    opendir(DIR, $schemaPath) or print "Cannot open '$schemaPath'\n" and return "";
+    my @files= readdir(DIR);
+    closedir(DIR);
+
+    foreach my $f (@files) {
+
+        if ($f =~ m/.*\.sql$/) {
+            #print "....$f\n";
+
+            open FILE, "<$schemaPath/$f" or next;
+
+            while (<FILE>) {
+                if ($_ =~ m/.*CREATE TABLE\s+dbo\.$tableName\s*\(/i) {
+
+                    close (FILE);
+                    return "$schemaPath/$f";
+                }
+            }
+
+            close (FILE);
+
+        }
+    }
+
+    print "Could not find table '$tableName'\n";
+    return "";
+}
+
+#######################################################################################
+#
+# Creates detection batch tables
+#
+#######################################################################################
+sub createInit {
+
+    parseTable("Filter");
+    parseTable("FitModel");
+    parseTable("PhotozRecipe");
+    parseTable("Survey");
+    parseTable("CameraConfig");
+    parseTable("PhotoCal");
+    parseTable("SkyCell");
+    parseTable("ProjectionCell");
+    parseTable("Region");
+    parseTable("StackType");
+    parseTable("ImageFlags");
+    parseTable("DetectionFlags");
+}
+
+#######################################################################################
+#
+# Creates initialisation batch tables
+#
+#######################################################################################
+sub createDetections {
+
+    parseTable("FrameMeta");
+    parseTable("ImageMeta");
+    parseTable("Detection");
+    parseTable("SkinnyObject");
+    parseTable("ObjectCalColor");
+}
+
+#######################################################################################
+#
+# Creates difference batch tables
+#
+#######################################################################################
+sub createDiffs {
+
+    parseTable("StackMeta");
+    parseTable("StackToImage");
+    parseTable("StackLowSigDelta");
+    parseTable("StackHighSigDelta");
+    parseTable("ObjectCalColor");
+}
+
+#######################################################################################
+#
+# Creates stack batch tables
+#
+#######################################################################################
+sub createStacks {
+
+    parseTable("StackMeta");
+    parseTable("StackDetection");
+    parseTable("SkinnyObject");
+    parseTable("StackOrphan");
+    parseTable("ObjectCalColor");
+}
+
+#######################################################################################
+#
+# Creates object batch tables
+#
+#######################################################################################
+sub createObjects {
+
+    parseTable("Object");
+}
+
+#######################################################################################
+#
+# Parses a particular table from the SQL file and converts it to an XML description 
+#
+#######################################################################################
+sub parseTable {
+    my ($tableName, $newName) = @_;
+
+    my $path =  findSchemaFile($tableName);
+
+    if ($path eq "") {return;}
+
+    # sort out table name, either same as in schema or as defined
+    my $tableNameOut; 
+    if ($newName) { $tableNameOut = $newName;}
+    else {$tableNameOut = $tableName}
+
+    print OUT "\ntypedef enum {\n";
+    $writer->startTag('table', "name" => $tableNameOut);
+
+    open (SCHEMA, $path);
+
+    my $reading = 0;
+    my $found = 0;
+    my $colNum = 0;
+    my $table;
+
+    while (<SCHEMA>) {
+        chomp;
+
+        if ($_ =~ m/.*CREATE TABLE\s+dbo\.([a-zA-Z0-9.]+)\s*\(/i) {
+
+            $table = $1;
+
+            if ($table eq $tableName) {
+
+                $reading = 1;
+                $found = 1;
+                $colNum = 0;
+                next;
+            }
+        }
+
+        if($reading && $_ =~ m/^\s*\)\s*/) {$reading = 0;}
+
+        if(!$reading) {next;}
+
+        my $line = $_;
+        $line =~ s/[\s]*$//;
+
+        if (!$line) {next;}
+        if (length($line) < 5) {next;}
+        if ($line =~ m/^\s*--/) {next;}
+        if ($line =~ m/\/\*/) {next;}
+        if ($line =~ m/\*\//) {next;}
+
+        $colNum = processLine($line, $tableName, $colNum);
+
+    }
+
+    if (!$found) {print "Could not find table '$tableName'\n";}
+    $writer->endTag();
+    print OUT "} ".$tableNameOut.";\n";
+
+    close SCHEMA;
+}
+
+#######################################################################################
+#
+# Processes a line from the PSPS schema table description and converts to XML
+#
+#######################################################################################
+sub processLine {
+    my ($line, $tableName, $colNum) = @_;
+
+    my $name;
+    my $typeStr;
+    my $type;
+    my $comment;
+    my $default;
+
+    # parse line
+    if ($line =~ m/\s*([a-zA-Z0-9()-\[\]]+)\s+(.*)\s*--\/(.*)/) {
+
+        $name = $1;
+        $typeStr = $2;
+        $comment = $3;
+
+        # neaten up the comment
+        $comment =~ s/<[\/]{0,1}column>//g;
+        $comment =~ s/^[\s]*//;
+        $comment =~ s/[\s]*$//;
+        if ($comment =~ m/<column unit="(.*)">(.*)/ ) {$comment = "$2 (unit = $1)"}
+    }
+    # no comment case
+    elsif ($line =~ m/\s*([a-zA-Z0-9()-\[\]]+)\s+(.*)/) {
+
+        $name = $1;
+        $typeStr = $2;
+        $comment = "No comment";
+    }
+    else {
+
+        print "In '$tableName', can't process: '$line'\n";
+        return $colNum
+    }
+
+    my $ISBINARY = 0;
+
+    # remove [] from name
+    $name =~ s/[\[\]]//g;
+
+    # sort out type
+    if ($typeStr =~ m/([a-zA-Z0-9()-]*)[ \t]+.*/) {
+
+        $type = $1; 
+        $type =~ s/BIGINT/TLONGLONG/;
+        $type =~ s/SMALLINT/TSHORT/;
+        $type =~ s/TINYINT/TBYTE/;
+        $type =~ s/INT/TLONG/;
+        $type =~ s/FLOAT/TDOUBLE/;
+        $type =~ s/REAL/TFLOAT/;
+        $type =~ s/DATE/TSTRING/;
+        if ($type =~ m/^VARCHAR.*/) {$type = "TSTRING";}
+        if ($type =~ m/^VARBINARY.*/) {$type = "TSTRING"; $ISBINARY = 1;}
+    }
+
+    # get default value
+    if ($typeStr =~ m/.*DEFAULT[ \t]*(.*)/i) {
+
+        $default = $1;
+        $default =~ s/,//;
+            $default =~ s/[\(\)]//g;
+        $default =~ s/[\s]*$//;
+        $default =~ s/'//g;
+        if ($type ne "TSTRING" && !$default) {$default = "0";}
+        if ($ISBINARY && $default eq "0x") {$default = "";}
+    }
+    elsif ($type eq "TSTRING") {$default = " ";}
+    else {$default = 0;}
+
+    if ($type eq "TSTRING" && $default eq "") {$default = " ";}
+
+    $colNum++;
+
+    print OUT "  ".uc($tableName)."_".uc($name)." = ".$colNum.",\n";
+
+    $writer->startTag('column',
+            "name" => $name,
+            "type" => $type,
+            "default" => $default,
+            "comment" => $comment);
+
+    $writer->endTag();
+
+    return $colNum;
+}
Index: branches/eam_branches/ipp-20100621/ippToPsps/perl/removeFromDatastore.pl
===================================================================
--- branches/eam_branches/ipp-20100621/ippToPsps/perl/removeFromDatastore.pl	(revision 28980)
+++ branches/eam_branches/ipp-20100621/ippToPsps/perl/removeFromDatastore.pl	(revision 28980)
@@ -0,0 +1,56 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+use ippToPsps::Datastore;
+
+my $start = undef;
+my $end = undef;
+my $product = undef;
+
+GetOptions( 
+        'start|s=s' => \$start,
+        'end|e=s' => \$end,
+        'product|p=s' => \$product,
+        );
+
+my $quit = 0;
+print "\n*******************************************************************************\n";
+print "* \n";
+if (@ARGV) {
+    $quit=1;
+    print "* UNKNKOWN: option                          @ARGV\n";
+}
+if (!defined $product) {
+    $quit=1;
+    print "* REQUIRED: a datastore product name          -p <name>\n";
+}
+if (!defined $start) {
+    $quit=1;
+    print "* REQUIRED: starting batch number             -s <number>\n";
+}
+if (!defined $end) {
+    $end=99999999999;
+    print "* OPTIONAL: ending batch number               -e <number>    (default=$end)\n";
+}
+print "*\n*******************************************************************************\n";
+
+if ($quit) { exit; }
+
+my $datastore = new ippToPsps::Datastore($product, 0, 0);
+
+my $i;
+
+for ($i=$start; $i<$end+1; $i++) {
+
+    my $name = sprintf("B%08d", $i);
+    if ($datastore->remove($name)) {
+        print "* Successfully removed $name from datastore\n";
+    }
+    else {
+        print "* Unable to remove $name from datastore\n";
+    }
+}
