diff options
Diffstat (limited to 'relblobif/test/blobdump.c')
-rw-r--r-- | relblobif/test/blobdump.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/relblobif/test/blobdump.c b/relblobif/test/blobdump.c new file mode 100644 index 0000000..bc2f44f --- /dev/null +++ b/relblobif/test/blobdump.c @@ -0,0 +1,323 @@ +#include "mymalloc/mymalloc.h" +/* Processed by ecpg (3.1.1) */ +/* These include files are added by the preprocessor */ +#include <ecpgtype.h> +#include <ecpglib.h> +#include <ecpgerrno.h> +#include <sqlca.h> +#line 1 "blobdump.pgc" +/* End of automatic include section */ +/* +* This file is part of rasdaman community. +* +* Rasdaman community is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* Rasdaman community is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +*/ +/************************************************************* + * + * + * PURPOSE: + * dump RAS_TILES blob table. + * Depending on parameters, either a particular tuple is printed + * or the whole table. Optionally also the blob is dumped in hex. + * Parameters: see usage(). + * + * + * COMMENTS: + * - assumes RAS_TILES + * + ************************************************************/ + +using namespace std; + +#include <iostream> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> /* getopt */ + +#include <sqlca.h> + +// SQL error codes: +#include "externs.h" + +// PG stuff +#include "libpq-fe.h" // C interface to PgSQL +#include "libpq/libpq-fs.h" /* large object (lo) api */ +// libq-style connection ptr taken from ECPG connect (needed for libq functions): +// (currently used by relblobif/blobtile.pgc) +PGconn *pgConn = NULL; +PGresult *pgResult = NULL; + +#define RC_OK 0 +#define RC_ERROR -1 + +#define QUERYSIZE 2000 +static char pgQuery[QUERYSIZE]; + +void exitNicely() +{ + PQclear( pgResult ); + (void) PQexec( pgConn, "ROLLBACK WORK" ); + PQfinish( pgConn ); + exit( RC_ERROR ); +} + + +void +disconnect() +{ + pgResult = PQexec( pgConn, "ROLLBACK WORK" ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + cerr << "error during disconnect: " << PQerrorMessage(pgConn) << endl << flush; + PQclear( pgResult ); + exit( RC_ERROR ); + } + PQclear( pgResult ); + + PQfinish( pgConn ); + pgConn = NULL; +} + +void +connect( const char * db ) +{ + char pgConnInfo[200]; + + (void) snprintf( pgConnInfo, (size_t) sizeof(pgConnInfo), "dbname = %s", db ); + pgConn = PQconnectdb( pgConnInfo ); + if (PQstatus(pgConn) != CONNECTION_OK) + { + cerr << "error during connect: " << PQerrorMessage(pgConn) << endl << flush; + exitNicely(); + } + + pgResult = PQexec( pgConn, "BEGIN TRANSACTION" ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + cerr << "error during being ta: " << PQerrorMessage(pgConn) << endl << flush; + PQclear( pgResult ); + exit( RC_ERROR ); + } + PQclear( pgResult ); + +} + +// read one tuple from ras_tiles, identified by myOId, and display it (with contents if withDump==true) +void +readFromDb( long myOId, bool withDump ) +{ + unsigned int blobOid = 0; + short dataFormat = 0; + unsigned long size = 0; + char *cells = NULL; + + // (1) --- access tuple + int result = snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile, DataFormat FROM RAS_TILES WHERE BlobId = %d", myOId ); + + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_TUPLES_OK) + { + cerr << "error during 'select': " << PQerrorMessage(pgConn) << endl << flush; + exitNicely(); + } + else if (PQntuples(pgResult) < 1) + { + cerr << "no tuple with id " << myOId << endl << flush; + exitNicely(); + } + + blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); + dataFormat = atoi( PQgetvalue( pgResult, 0, 1 ) ); + PQclear( pgResult ); + + // (2) --- open, read, close blob + int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication + size = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method?? + (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading + cells = (char*) mymalloc( size * sizeof(char) ); // allocate buffer for blob + if (cells == NULL) + { + cerr << "error during malloc()" << endl << flush; + exitNicely(); + } + int loResult = lo_read( pgConn, fd, cells, size ); + if (loResult < 0) + { + cerr << "error during lo_read(): " << PQerrorMessage(pgConn) << endl << flush; + exitNicely(); + } + else if (loResult != size) // did not get all + { + cerr << "error (did not get all bytes): " << PQerrorMessage(pgConn) << endl << flush; + exitNicely(); + } + int ignoredPgResult = lo_close( pgConn, fd ); // close blob + + if (withDump) + { + cout << " id = " << myOId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << ", contents = "; + for (int a = 0; a < size; a++) + cout << " " << hex << (0xff & (unsigned int)(cells[a])) << dec; + cout << dec << endl; + } + else + { + cout << " id = " << myOId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << endl; + } + + free( cells ); +} + +// read all tuples from ras_tiles and display them (with contents if withDump==true) +void +readAllFromDb( bool withDump ) +{ + unsigned int blobOid; + long myId; + short dataFormat; + unsigned long size = 0; + char *cells = NULL; + int rowNumber = 0; + + // (1) --- declare cursor + pgResult = PQexec( pgConn, "SELECT BlobId, Tile, DataFormat FROM RAS_TILES" ); + if (PQresultStatus(pgResult) != PGRES_TUPLES_OK && PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + cerr << "error during 'declare cursor': " << PQerrorMessage(pgConn) << endl << flush; + exitNicely(); + } + + do + { + myId = atoi( PQgetvalue( pgResult, rowNumber, 0 ) ); + blobOid = atoi( PQgetvalue( pgResult, rowNumber, 1 ) ); + dataFormat = atoi( PQgetvalue( pgResult, rowNumber, 2 ) ); + + // (2) --- open, read, close blob + int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication + size = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method?? + (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading + cells = (char*) mymalloc( size * sizeof(char) ); // allocate buffer for blob + if (cells == NULL) + { + cerr << "error: readFromDb() - no tuples found " << endl; + return; + } + int loResult = lo_read( pgConn, fd, cells, size ); + if (loResult < 0) + { + cerr << "error: readFromDb() - no tuples found " << endl; + return; + } + else if (loResult != size) // did not get all + { + cerr << "error: readFromDb() - no tuples found " << endl; + return; + } + int ignoredPgResult = lo_close( pgConn, fd ); // close blob + + if (withDump) + { + cout << " id = " << myId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << ", contents = "; + for (int a = 0; a < size; a++) + cout << " " << hex << (0xff & (unsigned int)(cells[a])) << dec; + cout << endl; + } + else + { + cout << " id = " << myId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << endl; + } + + rowNumber++; + } while (PQresultStatus(pgResult) == PGRES_TUPLES_OK || PQresultStatus(pgResult) == PGRES_COMMAND_OK); + + (void) PQexec( pgConn, "CLOSE TileLoop" ); + PQclear( pgResult ); + free( cells ); +} + +void usage(const char *prog) +{ + cout << "Usage: " << prog << " -d db [-i id] [-c]" << endl; + cout << "where:" << endl; + cout << " -d db log into PG server using PG database name db (mandatory)" << endl; + cout << " -i id dump blob with identifier id (default: dump whole table)" << endl; + cout << " -c dump blob contents too (default: descriptor data only)" << endl; + cout << " -h (help) print this overview" << endl; +} + +int +main(int argc, char* argv[]) +{ + char *prog = argv[0]; // prog name + char db[100]; // DB connect string + int blobOid = 0; // tuple to be dumped + bool withDump = false; // by default, don't dump blob contents + char c; // getop var + int result; // for sscanf() + + cout << prog << ": dump rasdaman blob table." << endl; + + opterr = 0; + while ((c = getopt(argc, argv, "d:i:c")) != -1) + { + switch (c) + { + case 'd': + (void) strncpy( db, optarg, sizeof(db) ); + break; + case 'i': + result = sscanf( optarg, "%d", &blobOid ); + if (result != 1) + { + cerr << prog << ": positive integer expected: " << optarg << endl; + exit( RC_ERROR ); + } + break; + case 'c': + withDump = true; + break; + case 'h': + case '?': + case ':': + usage(prog); + exit( RC_OK ); + break; + } + } + if (optind < argc || argc == 1) + { + usage( prog ); + exit( RC_ERROR ); + } + + connect( db ); + + if (blobOid > 0) + readFromDb( blobOid, withDump ); + else + readAllFromDb( withDump ); + + disconnect(); + + cout << prog << ": done." << endl; +} + |