diff options
Diffstat (limited to 'applications/directql/directql.cc')
-rw-r--r-- | applications/directql/directql.cc | 993 |
1 files changed, 993 insertions, 0 deletions
diff --git a/applications/directql/directql.cc b/applications/directql/directql.cc new file mode 100644 index 0000000..98bd3ba --- /dev/null +++ b/applications/directql/directql.cc @@ -0,0 +1,993 @@ +/* +* 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>. +/ + +/** +* rasql +* +* PURPOSE: +* Provides a command line interpretter for rasql queries, with +* options for displaying results or storing them to file(s) +* +* COMMENTS: +* +* BUGS: +* - query filename "" is interpreted as stdin +*/ + + +static const char rasql_rcsid[] = "@(#)rasql,rasql.cc: $Id: rasql.cc,v 1.3 2006/11/06 21:59:01 rasdev Exp $"; + +#ifndef RMANVERSION +#error "Please specify RMANVERSION variable!" +#endif + +#ifndef COMPDATE +#error "Please specify the COMPDATE variable!" +/* +COMPDATE=`date +"%d.%m.%Y %H:%M:%S"` +and -DCOMPDATE="\"$(COMPDATE)\"" when compiling +*/ +#endif + +#define __EXECUTABLE__ +#define EARLY_TEMPLATE +#define DEBUG_MAIN +#define DEBUG +#define RMANDEBUG + +#include "debug.hh" +#include "template_inst.hh" +#include "raslib/template_inst.hh" + +extern char* myExecArgv0 = ""; +extern int tiling = 1; +extern unsigned long maxTransferBufferSize = 4000000; +extern int globalOptimizationLevel = 4; +extern char* dbSchema = 0; +extern int noTimeOut = 0; +bool udfEnabled = true; + +//RMINITGLOBALS('C'); + + +#ifdef __VISUALC__ +#include <strstrea.h> +#else +#include <strstream> +#endif + +#include <stdio.h> +#include <string.h> +#include <sstream> +#include <fstream> + +using namespace std; + +#ifdef __VISUALC__ + #define __EXECUTABLE__ +#endif + +#include "rasodmg/ref.hh" +#include "raslib/marraytype.hh" +#include "rasodmg/set.hh" +#include "rasodmg/marray.hh" +#include "rasodmg/iterator.hh" +#include "rasodmg/oqlquery.hh" + +#include "raslib/type.hh" + +#include "raslib/minterval.hh" + +#include "raslib/primitive.hh" +#include "raslib/complex.hh" +#include "raslib/structure.hh" + +#include "raslib/structuretype.hh" +#include "raslib/primitivetype.hh" + +#include "cmlparser.hh" + +#include "directql_error.hh" + +#include "servercomm/servercomm.hh" + + +#ifdef __VISUALC__ + #undef __EXECUTABLE__ +#endif + +// debug facility; relies on -DDEBUG at compile time +// tell debug that here is the place for the variables (to be done in the main() src file) +#define DEBUG_MAIN +#include "debug-clt.hh" + +const int MAX_STR_LEN = 255; +const int MAX_QUERY_LEN = 10240; + +// possible types of output +typedef enum +{ OUT_UNDEF, + OUT_FILE, + OUT_NONE, + OUT_STRING, + OUT_HEX, + OUT_FORMATTED +} OUTPUT_TYPE; + +// rasdaman MDD type for byte strings (default type used for file format reading) +#define MDD_STRINGTYPE "GreyString" + +/// program exit codes +#define EXIT_SUCCESS 0 +#define EXIT_USAGE 2 +#define EXIT_FAILURE -1 + +// parameter names, defaults, and help texts + +#define PARAM_HELP_FLAG 'h' +#define PARAM_HELP "help" +#define HELP_HELP "show command line switches" + +#define PARAM_SERV_FLAG 's' +#define PARAM_SERV "server" +#define HELP_SERV "<host-name> rasdaman server" +#define DEFAULT_SERV "localhost" + +#define PARAM_PORT_FLAG 'p' +#define PARAM_PORT "port" +#define HELP_PORT "<p> rasmgr port number" +#define DEFAULT_PORT 5432 +#define DEFAULT_PORT_STR "5432" + +#define PARAM_DB_FLAG 'd' +#define PARAM_DB "database" +#define HELP_DB "<db-name> name of database" +#define DEFAULT_DB "RASBASE" + +#define PARAM_USER "user" +#define HELP_USER "<user-name> name of user" +#define DEFAULT_USER "rasguest" + +#define PARAM_PASSWD "passwd" +#define HELP_PASSWD "<user-passwd> password of user" +#define DEFAULT_PASSWD "rasguest" + +#define PARAM_FILE_FLAG 'f' +#define PARAM_FILE "file" +#define HELP_FILE "<f> file name for upload through $i parameters within queries; each $i needs its own file parameter, in proper sequence. Requires --mdddomain and --mddtype" + +#define PARAM_DOMAIN "mdddomain" +#define HELP_DOMAIN "<mdd-domain> domain of marray, format: \'[x0:x1,y0:y1]\' (required only if --file specified and file is in data format r_Array)" + +#define PARAM_MDDTYPE "mddtype" +// this is for display only; internally MDD_STRINGTYPE is used +#define DEFAULT_MDDTYPE "byte string" +#define HELP_MDDTYPE "<mdd-type> type of marray (required only if --file specified and file is in data format r_Array)" + +#define PARAM_QUERY_FLAG 'q' +#define PARAM_QUERY "query" +#define HELP_QUERY "<q> query string to be sent to the rasdaman server for execution" + +#define PARAM_OUT "out" +#define HELP_OUT "<t> use display method t for cell values of result MDDs where t is one of none, file, formatted, string, hex. Implies --content" +#define DEFAULT_OUT OUT_NONE +#define PARAM_OUT_FILE "file" +#define PARAM_OUT_STRING "string" +#define PARAM_OUT_HEX "hex" +#define PARAM_OUT_FORMATTED "formatted" +#define PARAM_OUT_NONE "none" +#define DEFAULT_OUT_STR PARAM_OUT_NONE + +#define PARAM_CONTENT "content" +#define HELP_CONTENT "display result, if any (see also --out and --type for output formatting)" + +#define PARAM_TYPE "type" +#define HELP_TYPE "display type information for results" + +#define PARAM_OUTFILE_FLAG 'o' +#define PARAM_OUTFILE "outfile" +#define HELP_OUTFILE "<of> file name template for storing result images (ignored for scalar results). Use '%d' to indicate auto numbering position, like with printf(1). For well-known file types, a proper suffix is appended to the resulting file name. Implies --out file." +#define DEFAULT_OUTFILE "rasql_%d" + +#define PARAM_QUIET "quiet" +#define HELP_QUIET "print no ornament messages, only results and errors" + +#define PARAM_DEBUG "debug" +#define HELP_DEBUG "generate diagnostic output" + + +char globalConnectId[255] = {0}; +ServerComm *server; + +// global variables and default settings +// ------------------------------------- + +bool dbIsOpen = false; +bool taIsOpen = false; + +DatabaseIf database; +TransactionIf ta; + +// suppress regular messages in log? (cmd line parameter '--quiet') +bool quietLog = false; +// logging mechanism that respects 'quiet' flag: +#define LOG(a) { if (!quietLog) std::cout << a; } + +int optionValueIndex=0; + +const char *serverName = DEFAULT_SERV; +r_ULong serverPort = DEFAULT_PORT; +const char *baseName = DEFAULT_DB; + +const char *user = DEFAULT_USER; +const char *passwd = DEFAULT_PASSWD; + +const char *fileName = NULL; +const char *queryString=NULL; + +bool output = false; +bool displayType = false; + +OUTPUT_TYPE outputType = DEFAULT_OUT; + +const char *outFileMask = DEFAULT_OUTFILE; + +r_Minterval mddDomain; +bool mddDomainDef = false; + +const char* mddTypeName = NULL; +bool mddTypeNameDef = false; + +// query result set. +// we define it here because on empty results the set seems to be corrupt which kills the default destructor +r_Set< r_Ref_Any > result_set; + +// end of globals + +void +parseParams(int argc, char** argv) throw (RasqlError, r_Error) +{ + CommandLineParser &cmlInter = CommandLineParser::getInstance(); + + CommandLineParameter &clp_help = cmlInter.addFlagParameter( PARAM_HELP_FLAG, PARAM_HELP, HELP_HELP ); + + CommandLineParameter &clp_query = cmlInter.addStringParameter(PARAM_QUERY_FLAG, PARAM_QUERY, HELP_QUERY ); + CommandLineParameter &clp_file = cmlInter.addStringParameter(PARAM_FILE_FLAG, PARAM_FILE, HELP_FILE ); + + CommandLineParameter &clp_content = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_CONTENT, HELP_CONTENT ); + CommandLineParameter &clp_out = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_OUT, HELP_OUT, DEFAULT_OUT_STR ); + CommandLineParameter &clp_outfile = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_OUTFILE, HELP_OUTFILE, DEFAULT_OUTFILE ); + CommandLineParameter &clp_mddDomain = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_DOMAIN, HELP_DOMAIN ); + CommandLineParameter &clp_mddType = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_MDDTYPE, HELP_MDDTYPE, DEFAULT_MDDTYPE ); + CommandLineParameter &clp_type = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_TYPE, HELP_TYPE ); + + CommandLineParameter &clp_server = cmlInter.addStringParameter( PARAM_SERV_FLAG, PARAM_SERV, HELP_SERV, DEFAULT_SERV ); + CommandLineParameter &clp_port = cmlInter.addStringParameter( PARAM_PORT_FLAG, PARAM_PORT, HELP_PORT, DEFAULT_PORT_STR); + CommandLineParameter &clp_database = cmlInter.addStringParameter( PARAM_DB_FLAG, PARAM_DB, HELP_DB, DEFAULT_DB ); + CommandLineParameter &clp_user = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_USER, HELP_USER, DEFAULT_USER ); + CommandLineParameter &clp_passwd = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_PASSWD, HELP_PASSWD, DEFAULT_PASSWD ); + CommandLineParameter &clp_quiet = cmlInter.addFlagParameter(CommandLineParser::noShortName, PARAM_QUIET, HELP_QUIET ); + +#ifdef DEBUG + CommandLineParameter &clp_debug = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_DEBUG, HELP_DEBUG ); +#endif + + try + { + cmlInter.processCommandLine(argc, argv); + + if (cmlInter.isPresent( PARAM_HELP_FLAG ) || argc == 1) + { + cout << "usage: " << argv[0] << " [--query querystring|-q querystring] [options]" << endl; + cout << "options:" << endl; + cmlInter.printHelp(); + exit( EXIT_USAGE ); // FIXME: exit no good style!! + } + + // check mandatory parameters ==================================================== + + // evaluate mandatory parameter collection -------------------------------------- + if (cmlInter.isPresent( PARAM_QUERY )) + queryString = cmlInter.getValueAsString( PARAM_QUERY ); + else + throw RasqlError( NOQUERY ); + + // check optional parameters ==================================================== + + // evaluate optional parameter file -------------------------------------- + if (cmlInter.isPresent( PARAM_FILE )) + fileName = cmlInter.getValueAsString( PARAM_FILE ); + + // evaluate optional parameter server -------------------------------------- + if (cmlInter.isPresent( PARAM_SERV )) + serverName = cmlInter.getValueAsString( PARAM_SERV ); + + // evaluate optional parameter port -------------------------------------- + if (cmlInter.isPresent( PARAM_PORT )) + serverPort = cmlInter.getValueAsLong( PARAM_PORT ); + + // evaluate optional parameter database -------------------------------------- + if (cmlInter.isPresent( PARAM_DB )) + baseName = cmlInter.getValueAsString( PARAM_DB ); + + // evaluate optional parameter user -------------------------------------- + if (cmlInter.isPresent( PARAM_USER )) + user = cmlInter.getValueAsString( PARAM_USER ); + + // evaluate optional parameter passwd -------------------------------------- + if (cmlInter.isPresent( PARAM_PASSWD )) + passwd = cmlInter.getValueAsString( PARAM_PASSWD ); + + // evaluate optional parameter content -------------------------------------- + if (cmlInter.isPresent( PARAM_CONTENT )) + output = true; + + // evaluate optional parameter type -------------------------------------- + if (cmlInter.isPresent( PARAM_TYPE )) + displayType = true; + + // evaluate optional parameter hex -------------------------------------- + if (cmlInter.isPresent( PARAM_OUT )) + { + output = true; + const char* val = cmlInter.getValueAsString( PARAM_OUT ); + if (val !=0 && strcmp( val, PARAM_OUT_STRING ) == 0) + outputType = OUT_STRING; + else if (val !=0 && strcmp( val, PARAM_OUT_FILE ) == 0) + outputType = OUT_FILE; + else if (val !=0 && strcmp( val, PARAM_OUT_FORMATTED ) == 0) + outputType = OUT_FORMATTED; + else if (val !=0 && strcmp( val, PARAM_OUT_HEX ) == 0) + outputType = OUT_HEX; + else if (val !=0 && strcmp( val, PARAM_OUT_NONE ) == 0) + outputType = OUT_NONE; + else + throw RasqlError( ILLEGALOUTPUTTYPE ); + } + + // evaluate optional parameter outfile -------------------------------------- + if (cmlInter.isPresent( PARAM_OUTFILE )) + { + outFileMask = cmlInter.getValueAsString( PARAM_OUTFILE ); + outputType = OUT_FILE; + } + + // evaluate optional parameter domain -------------------------------------- + if ( cmlInter.isPresent( PARAM_DOMAIN ) ) + { + try + { + mddDomain = r_Minterval(cmlInter.getValueAsString( PARAM_DOMAIN )); + mddDomainDef = true; + } + catch ( r_Error& e ) // Minterval constructor had syntax problems + { + throw RasqlError( NOVALIDDOMAIN ); + } + } + + // evaluate optional parameter MDD type name -------------------------------------- + if (cmlInter.isPresent( PARAM_MDDTYPE )) + { + mddTypeName = cmlInter.getValueAsString( PARAM_MDDTYPE ); + mddTypeNameDef = true; + } + + // evaluate optional parameter 'quiet' -------------------------------------------- + if (cmlInter.isPresent( PARAM_QUIET )) + { + quietLog = true; + } + +#ifdef DEBUG + // evaluate optional parameter MDD type name -------------------------------------- + SET_OUTPUT( cmlInter.isPresent( PARAM_DEBUG ) ); +#endif + + } + catch(CmlException& err) + { + cerr << err.what() << endl; + throw RasqlError( ERRORPARSINGCOMMANDLINE ); + } +} // parseParams() + + +void +openDatabase() throw (r_Error) +{ + ENTER( "openDatabase" ); + + if (! dbIsOpen) + { + LOG( "opening database " << baseName << " at " << serverName << ":" << serverPort << "..." << flush ); + // + sprintf(globalConnectId, "tcp:postgresql://%s:%d/%s", serverName, serverPort, baseName); + //strcpy(globalConnectId, "tcp:postgresql://$serverName:$serverPort/$baseName"); + printf("conn = %s\n", globalConnectId); + + server = new ServerComm(300, 120, 7013, "rasmgr", 7001, "N1"); + + + AdminIf* myAdmin = AdminIf::instance(); + database.open( "RASSERVICE"); + + //ta.begin( &database ); + + ServerComm::ClientTblElt *r = new ServerComm::ClientTblElt("testclient", 2); + server->addClientTblEntry (r); + accessControl.setServerName("NT1"); + accessControl.crunchCapability("$I1$ER.$BRASBASE$T1:3:2008:23:39:24$NNT1$D983893f406445a922cba0301bc5a85ec$K"); + server->openDB(2, "RASBASE", "costea"); + SET_OUTPUT(TRUE); + + TALK( "ok" ); + dbIsOpen = true; + LOG( "ok" << endl << flush ); + } + + LEAVE( "openDatabase" ); +} // openDatabase() + +void +closeDatabase() throw (r_Error) +{ + ENTER( "closeDatabase" ); + + if (dbIsOpen) + { + TALK( "database was open, closing it" ); + dbIsOpen = false; + } + + LEAVE( "closeDatabase" ); + return; +} // closeDatabase() + +void +openTransaction(bool readwrite) throw (r_Error) +{ + ENTER( "openTransaction, readwrite=" << (readwrite ? "rw" : "ro" ) ); + + if (! taIsOpen) + { + if (readwrite) + { + TALK( "transaction was closed, opening rw..." ); + ta.begin(&database); + TALK( "ok" ); + } + else + { + TALK( "transaction was closed, opening ro..." ); + ta.begin(&database); + TALK( "ok" ); + } + + taIsOpen = true; + } + + LEAVE( "openTransaction" ); +} // openTransaction() + +void +closeTransaction( bool doCommit ) throw (r_Error) +{ + ENTER( "closeTransaction, doCommit=" << doCommit ); + + if (taIsOpen) + { + if (doCommit) + { + TALK( "transaction was open, committing it..." ); + ta.commit(); + TALK( "ok" ); + } + else + { + TALK( "transaction was open, aborting it..." ); + ta.abort(); + TALK( "ok" ); + } + taIsOpen = false; + } + + LEAVE( "closeTransaction" ); + return; +} // closeTransaction() + +void printScalar( const r_Scalar& scalar ) +{ + ENTER( "printScalar" ); + + switch( scalar.get_type()->type_id() ) + { + case r_Type::BOOL: + LOG( ( ((r_Primitive*)&scalar)->get_boolean() ? "t" : "f" ) << flush ); + break; + + case r_Type::CHAR: + LOG( (int)((r_Primitive*)&scalar)->get_char() << flush ); + break; + + case r_Type::OCTET: + LOG( (int)((r_Primitive*)&scalar)->get_octet() << flush ); + break; + + case r_Type::SHORT: + LOG( ((r_Primitive*)&scalar)->get_short() << flush ); + break; + + case r_Type::USHORT: + LOG( ((r_Primitive*)&scalar)->get_ushort() << flush ); + break; + + case r_Type::LONG: + LOG( ((r_Primitive*)&scalar)->get_long() << flush ); + break; + + case r_Type::ULONG: + LOG( ((r_Primitive*)&scalar)->get_ulong() << flush ); + break; + + case r_Type::FLOAT: + LOG( ((r_Primitive*)&scalar)->get_float() << flush ); + break; + + case r_Type::DOUBLE: + LOG( ((r_Primitive*)&scalar)->get_double() << flush ); + break; + + case r_Type::COMPLEXTYPE1: + case r_Type::COMPLEXTYPE2: + LOG( "(" << ((r_Complex*)&scalar)->get_re() << "," << ((r_Complex*)&scalar)->get_im() << ")" << flush ); + break; + + case r_Type::STRUCTURETYPE: + { + r_Structure* structValue = (r_Structure*)&scalar; + LOG( "{ " << flush ); + for( int i=0; i<structValue->count_elements(); i++ ) + { + printScalar( (*structValue)[i] ); + if( i < structValue->count_elements()-1 ) + LOG( ", " << flush ); + } + LOG( " }" << endl ); + } + break; + default: + LOG( "scalar type " << scalar.get_type()->type_id() << " not supported!" << endl ); + break; + } + LEAVE( "printScalar" ); +} // printScalar() + + +// result_set should be parameter, but is global -- see def for reason +void printResult( r_Minterval &mddDomain, char* &typeName, + char* &typeStructure, + r_OId &oid, + unsigned short ¤tFormat) +{ + ENTER( "printResult" ); + + if (displayType) + { + cout << " Oid...................: " << oid << endl; + cout << " Type Structure........: " + << ( typeStructure ? typeStructure : "<nn>" ) << endl; + cout << endl; + } + + /* The following can be used if the type is known and the element type is not atomic. + + r_Set< r_Ref< r_Point > >* set2 = (r_Set< r_Ref< r_Point > >*)&result_set; + r_Iterator< r_Ref<r_Point> > iter2 = set2->create_iterator(); + for( iter2.reset(); iter2.not_done(); iter2++ ) + cout << **iter2 << endl; + */ + + r_Iterator< r_Ref_Any > iter = result_set.create_iterator(); + // iter.not_done() seems to behave wrongly on empty set, therefore this additional check -- PB 2003-aug-16 + for ( int i=1 ; i<=result_set.cardinality() && iter.not_done(); iter++, i++ ) + { + switch( result_set.get_element_type_schema()->type_id() ) + { + case r_Type::MARRAYTYPE: + switch ( outputType ) + { + case OUT_NONE: + break; + case OUT_STRING: + { + int numCells = r_Ref<r_GMarray>(*iter)->get_array_size(); + const char* theStuff = r_Ref<r_GMarray>(*iter)->get_array(); + LOG( " Result object " << i << ": " ); + for (int cnt = 0; cnt < numCells; cnt++) + cout << theStuff[cnt]; + cout << endl; + } + break; + case OUT_HEX: + { + int numCells = r_Ref<r_GMarray>(*iter)->get_array_size(); + const char* theStuff = r_Ref<r_GMarray>(*iter)->get_array(); + LOG( " Result object " << i << ": " ); + cout << hex; + for (int cnt = 0; cnt < numCells; cnt++) + cout << setw(2) << (unsigned short) (0xff & theStuff[cnt]) << " "; + cout << dec << endl; + } + break; + case OUT_FORMATTED: + LOG( " Result object " << i << ":" << endl ); + // for (int cnt = 0; cnt < numCells; cnt++) + printScalar( *(r_Ref<r_Scalar>(*iter)) ); + cout << endl; + break; + case OUT_FILE: + { + char defFileName[FILENAME_MAX]; + (void) snprintf( defFileName, sizeof(defFileName)-1, outFileMask, i ); + TALK( "filename for #" << i << " is " << defFileName ); + + // special treatment only for DEFs + r_Data_Format mafmt = r_Ref<r_GMarray>(*iter)->get_current_format(); + switch (mafmt) + { + case r_TIFF: + strcat( defFileName, ".tif" ); break; + case r_JPEG: + strcat( defFileName, ".jpg" ); break; + case r_HDF: + strcat( defFileName, ".hdf" ); break; + case r_PNG: + strcat( defFileName, ".png" ); break; + case r_BMP: + strcat( defFileName, ".bmp" ); break; + case r_VFF: + strcat( defFileName, ".vff" ); break; + default: + strcat( defFileName, ".unknown" ); break; + break; + } + + LOG( " Result object " << i << ": going into file " << defFileName << "..." << flush ); + FILE *tfile = fopen( defFileName, "wb" ); + fwrite((void*)r_Ref<r_GMarray>(*iter)->get_array(), 1, r_Ref<r_GMarray>(*iter)->get_array_size(), tfile ); + fclose(tfile); + LOG( "ok." << endl ); + } + break; + default: + cerr << "Internal error: unknown output type, ignoring action: " << outputType << endl; + break; + } // switch(outputType) + break; + + case r_Type::POINTTYPE: + LOG( " Result element " << i << ": " ); + cout << *(r_Ref<r_Point>(*iter)) << endl; + break; + + case r_Type::SINTERVALTYPE: + LOG( " Result element " << i << ": " ); + cout << *(r_Ref<r_Sinterval>(*iter)) << endl; + break; + + case r_Type::MINTERVALTYPE: + LOG( " Result element " << i << ": " ); + cout << *(r_Ref<r_Minterval>(*iter)) << endl; + break; + + case r_Type::OIDTYPE: + LOG( " Result element " << i << ": " ); + cout << *(r_Ref<r_OId>(*iter)) << endl; + break; + + default: + LOG( " Result element " << i << ": " << flush ); + printScalar( *(r_Ref<r_Scalar>(*iter)) ); + cout << endl; + // or simply + // r_Ref<r_Scalar>(*iter)->print_status( cout ); + } // switch + } // for(...) + + LEAVE( "printResult" ); +} // printResult() + + +/* + * get database type structure from type name + * returns ptr if an MDD type with the given name exists in the database, NULL otherwise + * throws r_Error upon general database comm error + * needs an open transaction + */ +r_Marray_Type * getTypeFromDatabase( const char *mddTypeName ) throw(RasqlError, r_Error) +{ + ENTER( "getTypeFromDatabase, mddTypeName=" << mddTypeName ); + r_Marray_Type *retval = NULL; + char* typeStructure = NULL; + + // first, try to get type structure from database using a separate r/o transaction + try + { + server->getTypeStructure(2, mddTypeName, ClientComm::r_MDDType_Type, typeStructure); + TALK( "type structure is " << typeStructure ); + } + catch (r_Error& err) + { + if (err.get_kind() == r_Error::r_Error_DatabaseClassUndefined) + { + TALK( "Type is not a well known type: " << typeStructure ); + typeStructure = new char[strlen(mddTypeName) + 1]; + // earlier code tried this one below, but I feel we better are strict -- PB 2003-jul-06 + // strcpy(typeStructure, mddTypeName); + // TALK( "using instead: " << typeStructure ); + throw RasqlError( MDDTYPEINVALID ); + } + else // unanticipated error + { + TALK( "Error during type retrieval from database: " << err.get_errorno() << " " << err.what() ); + throw; + } + } + + // next, find out whether it is an MDD type (and not a base or set type, eg) + try + { + r_Type* tempType = r_Type::get_any_type(typeStructure); + TALK( "get_any_type() for this type returns: " << tempType ); + if (tempType->isMarrayType()) + { + retval = (r_Marray_Type*)tempType; + tempType = NULL; + TALK( "found MDD type: " << retval ); + } + else + { + TALK( "type is not an marray type: " << typeStructure ); + delete tempType; + tempType = NULL; + retval = NULL; + throw RasqlError( MDDTYPEINVALID ); + } + } + catch (r_Error& err) + { + TALK( "Error during retrieval of MDD type structure (" << typeStructure << "): " << err.get_errorno() << " " << err.what() ); + throw; + } + + delete [] typeStructure; + typeStructure = NULL; + + LEAVE( "getTypeFromDatabase, retval=" << retval ); + return retval; +} // getTypeFromDatabase() + +void doStuff( int argc, char** argv ) throw (r_Error) +{ + char *fileContents = NULL; // contents of file satisfying "$1" parameter in query + r_Ref<r_GMarray> fileMDD = NULL; // MDD to satisfy a "$1" parameter + r_Marray_Type *mddType = NULL; // this MDD's type + + ENTER( "doStuff" ); + + r_OQL_Query query( queryString ); + TALK( "query is: " << query.get_query() ); + + if ( fileName != NULL ) + { + openTransaction( false ); + + // if no type name was specified then assume byte string (for encoded files) + if ( ! mddTypeNameDef ) + mddTypeName = MDD_STRINGTYPE; + + LOG( "fetching type information for " << mddTypeName << " from database, using readonly transaction..." << flush ); + mddType = getTypeFromDatabase( mddTypeName ); + closeTransaction( true ); + LOG( "ok" << endl ); + + LOG( "reading file " << fileName << "..." << flush ); + FILE* fileD = fopen( fileName, "r" ); + if (fileD == NULL) + throw RasqlError( FILEINACCESSIBLE ); + + fseek( fileD, 0, SEEK_END ); + int size = ftell( fileD ); + TALK( "file size is " << size << " bytes" ); + try + { + fileContents = new char[size]; + } + catch(std::bad_alloc) + { + TALK( "Unable to claim memory: " << size << " Bytes" ); + throw RasqlError( UNABLETOCLAIMRESOURCEFORFILE ); + } + + fseek( fileD, 0, SEEK_SET ); + fread( fileContents, 1, size, fileD ); + fclose( fileD ); + + // if no domain specified (this is the case with encoded files), then set to byte stream: + if ( ! mddDomainDef ) + { + mddDomain = r_Minterval( 1 ) << r_Sinterval ( 0, size-1 ); + TALK( "domain set to " << mddDomain ); + } + + if (size != mddDomain.cell_count() * mddType->base_type().size()) + throw RasqlError( FILESIZEMISMATCH ); + LOG( "ok" << endl ); + + TALK( "setting up MDD with domain " << mddDomain << " and base type " << mddTypeName ); + fileMDD = new (mddTypeName) r_GMarray( mddDomain, mddType->base_type().size() ); + fileMDD->set_type_schema( mddType ); + fileMDD->set_array_size( mddDomain.cell_count() * mddType->base_type().size() ); + fileMDD->set_array( fileContents ); + + query << *fileMDD; + + TALK( "constants are:" ); + r_Set<r_GMarray *> * myConstSet = (r_Set<r_GMarray *> *) query.get_constants(); + r_Iterator< r_GMarray *> iter = myConstSet->create_iterator(); + int i; + for ( i=1, iter.reset(); iter.not_done(); iter++, i++ ) + { + r_Ref< r_GMarray > myConstant = *iter; + LOG( " constant " << i << ": " ); + myConstant->print_status( cout ); +// the following can be used for sporadic debugging of input files, but beware: is very verbose! +#if 0 + cout << " Contents: " << hex; + const char *a = myConstant->get_array(); + for (int m=0; m < myConstant->get_array_size(); m++) + cout << (unsigned short) (a[m] & 0xFF) << " "; + cout << dec << endl; +#endif + } + } + + ExecuteQueryRes result; + + if( query.is_update_query() ) + { + openTransaction( true ); + + r_Marray<r_ULong>* mddConst = NULL; + + LOG( "Executing update query..." << flush ); + server->executeQuery(2, queryString, result ); + LOG( "ok" << endl ); + + if( mddConst ) + delete mddConst; + + closeTransaction( true ); + } + else + { + openTransaction( false ); + + // should be defined here, but is global; see def for reason + // r_Set< r_Ref_Any > result_set; + + LOG( "Executing retrieval query..." << flush ); + int status; + status = server->executeQuery(2, queryString, result ); + switch (status) + { + case 0: LOG("holds MDD elements" << endl); + break; + case 1: LOG("holds non-MDD elements" << endl); + break; + case 2: LOG("holds no elements" << endl); + break; + }; + + r_Minterval mddDomain; + char* typeName; + char* typeStructure; + r_OId oid; + unsigned short currentFormat; + + LOG( "Getting result..." << flush ); + if( output ) { + while (true) { + LOG( "Getting mdd..." << endl << flush ); + status = server->getNextMDD(2, mddDomain, typeName, typeStructure, oid, currentFormat); + if (status==2) { + printf("Empty MDD\n"); + break; + } + + } + } + //result_set = result; + LOG( "ok" << endl ); + + closeTransaction( true ); + } + + if (fileContents != NULL) + delete [] fileContents; + + LEAVE( "doStuff" ); +} + +/* + * returns 0 on success, -1 on error + */ +int main(int argc, char** argv) +{ + SET_OUTPUT( true ); // inhibit unconditional debug output, await cmd line evaluation + + int retval = EXIT_SUCCESS; // overall result status + + try + { + parseParams( argc, argv ); + + // put LOG after parsing parameters to respect a '--quiet' + LOG( argv[0] << ": rasdaman query tool v1.0, rasdaman v" << RMANVERSION/1000 << " -- generated on " << COMPDATE << "." << endl ); + + openDatabase(); + doStuff( argc, argv ); + closeDatabase(); + retval = EXIT_SUCCESS; + } + catch (RasqlError& e) + { + cerr << argv[0] << ": " << e.what() << endl; + retval = EXIT_FAILURE; + } + catch (const r_Error& e) + { + cerr << "rasdaman error " << e.get_errorno() << ": " << e.what() << endl; + retval = EXIT_FAILURE; + } + catch (...) + { + cerr << argv[0] << ": panic: unexpected internal exception." << endl; + retval = EXIT_FAILURE; + } + + if (retval != EXIT_SUCCESS && (dbIsOpen || taIsOpen) ) + { + LOG( "aborting transaction..." << flush ); + closeTransaction( false ); // abort transaction and close database, ignore any further exceptions + LOG( "ok" << endl ); + closeDatabase(); + } + + LOG( argv[0] << " done." << endl ); + return retval; +} // main() + +// end of rasql.cc + |