src/dbapi/driver/samples/dbapi_sample_base.cpp

Go to the documentation of this file.
00001 /*  $Id: dbapi_sample_base.cpp 173358 2009-10-16 13:23:56Z ivanovp $
00002 * ===========================================================================
00003 *
00004 *                            PUBLIC DOMAIN NOTICE
00005 *               National Center for Biotechnology Information
00006 *
00007 *  This software/database is a "United States Government Work" under the
00008 *  terms of the United States Copyright Act.  It was written as part of
00009 *  the author's official duties as a United States Government employee and
00010 *  thus cannot be copyrighted.  This software/database is freely available
00011 *  to the public for use. The National Library of Medicine and the U.S.
00012 *  Government have not placed any restriction on its use or reproduction.
00013 *
00014 *  Although all reasonable efforts have been taken to ensure the accuracy
00015 *  and reliability of the software and data, the NLM and the U.S.
00016 *  Government do not and cannot warrant the performance or results that
00017 *  may be obtained by using this software or data. The NLM and the U.S.
00018 *  Government disclaim all warranties, express or implied, including
00019 *  warranties of performance, merchantability or fitness for any particular
00020 *  purpose.
00021 *
00022 *  Please cite the author in any work or product based on this material.
00023 *
00024 * ===========================================================================
00025 *
00026 * Author:  Denis Vakatov
00027 *
00028 * File Description:
00029 *    CDbapiSampleApp_Base
00030 *      A base class for various DBAPI tests and sample applications.
00031 *
00032 *   Test the implementation of BCP by DBAPI driver(s):
00033 *     1) CREATE a table with 5 rows
00034 *     2) make BCP of this table
00035 *     3) PRINT the table on screen (use <ROW> and </ROW> to separate the rows)
00036 *     4) DELETE the table from the database
00037 *
00038 */
00039 
00040 
00041 #include <ncbi_pch.hpp>
00042 
00043 #include "dbapi_sample_base.hpp"
00044 #include <corelib/ncbiargs.hpp>
00045 #include <corelib/ncbienv.hpp>
00046 #include <corelib/ncbi_process.hpp>
00047 #include <util/smalldns.hpp>
00048 #include <dbapi/driver/driver_mgr.hpp>
00049 #include <dbapi/driver/dbapi_svc_mapper.hpp>
00050 #include <dbapi/driver/drivers.hpp>
00051 #include <dbapi/error_codes.hpp>
00052 #include <util/random_gen.hpp>
00053 
00054 #include <algorithm>
00055 
00056 
00057 #define NCBI_USE_ERRCODE_X   Dbapi_SampleBase
00058 
00059 BEGIN_NCBI_SCOPE
00060 
00061 
00062 const char*  file_name[] = {
00063     "../test1.txt",
00064     "../test2.txt",
00065     "../test3.txt",
00066     "../test4.txt",
00067     "../test5.txt",
00068     ""
00069 };
00070 
00071 
00072 /////////////////////////////////////////////////////////////////////////////
00073 //  CDbapiSampleApp::
00074 //
00075 
00076 
00077 CDbapiSampleApp::CDbapiSampleApp(EUseSampleDatabase sd)
00078     : CNcbiApplication(),
00079       m_DriverContext(0),
00080       m_UseSampleDatabase(sd),
00081       m_UseSvcMapper(false)
00082 {
00083     m_TableUID += "_" + CSmallDNS::GetLocalHost() + "_";
00084     m_TableUID += NStr::IntToString(CProcess::GetCurrentPid()) + "_";
00085     m_TableUID += CTime(CTime::eCurrent).AsString("MDy");
00086     replace( m_TableUID.begin(), m_TableUID.end(), '-', '_' );
00087 
00088 #ifdef NCBI_DLL_SUPPORT
00089     CPluginManager_DllResolver::EnableGlobally(true);
00090 #else
00091 
00092 #ifdef HAVE_LIBSYBASE
00093     DBAPI_RegisterDriver_CTLIB();
00094 #endif
00095 
00096 #ifdef HAVE_ODBC
00097     DBAPI_RegisterDriver_ODBC();
00098 #endif
00099 
00100     DBAPI_RegisterDriver_FTDS();
00101 
00102 #endif // NCBI_DLL_BUILD
00103 }
00104 
00105 
00106 CDbapiSampleApp::~CDbapiSampleApp()
00107 {
00108     return;
00109 }
00110 
00111 
00112 // Default implementation ...
00113 void
00114 CDbapiSampleApp::InitSample(CArgDescriptions&)
00115 {
00116 }
00117 
00118 
00119 // Default implementation ...
00120 void
00121 CDbapiSampleApp::ExitSample(void)
00122 {
00123 }
00124 
00125 
00126 CDbapiSampleApp::EServerType
00127 CDbapiSampleApp::GetServerType(void) const
00128 {
00129     if ( GetServerName() == "STRAUSS"
00130          || GetServerName() == "MOZART"
00131          || GetServerName() == "SCHUMANN"
00132          || GetServerName() == "CLEMENTI"
00133          || GetServerName() == "OBERON"
00134          || GetServerName() == "TAPER"
00135          || GetServerName() == "THALBERG"
00136          || GetServerName() == "DBAPI_SYB_TEST"
00137          || NStr::StartsWith(GetServerName(), "DBAPI_DEV")
00138          || NStr::StartsWith(GetServerName(), "BARTOK")
00139          ) {
00140         return eSybase;
00141     } else if (NStr::StartsWith(GetServerName(), "MS_DEV")
00142                || NStr::StartsWith(GetServerName(), "MSSQL")
00143                || GetServerName() == "DBAPI_MS_TEST"
00144                ) {
00145         return eMsSql;
00146     }
00147 
00148     return eUnknown;
00149 }
00150 
00151 
00152 void
00153 CDbapiSampleApp::Init()
00154 {
00155     // Create command-line argument descriptions class
00156     auto_ptr<CArgDescriptions> arg_desc(new CArgDescriptions);
00157 
00158     // Specify USAGE context
00159     arg_desc->SetUsageContext(GetArguments().GetProgramBasename(),
00160                               "DBAPI Sample Application");
00161 
00162     // Describe the expected command-line arguments
00163 #if defined(NCBI_OS_MSWIN)
00164 #define DEF_SERVER    "MS_DEV1"
00165 #define DEF_DRIVER    "ftds"
00166 #define ALL_DRIVERS   "ctlib", "dblib", "ftds", \
00167                       "gateway", "odbc"
00168 #elif defined(HAVE_LIBSYBASE)
00169 #define DEF_SERVER    "CLEMENTI"
00170 #define DEF_DRIVER    "ctlib"
00171 #define ALL_DRIVERS   "ctlib", "dblib", "ftds", "gateway", \
00172                       "odbc"
00173 #else
00174 #define DEF_SERVER    "MS_DEV1"
00175 #define DEF_DRIVER    "ftds"
00176 #define ALL_DRIVERS   "ftds", "gateway", \
00177                       "odbc"
00178 #endif
00179 
00180     arg_desc->AddDefaultKey("S", "server",
00181                             "Name of the SQL server to connect to",
00182                             CArgDescriptions::eString, DEF_SERVER);
00183 
00184     arg_desc->AddDefaultKey("d", "driver",
00185                             "Name of the DBAPI driver to use",
00186                             CArgDescriptions::eString,
00187                             DEF_DRIVER);
00188     arg_desc->SetConstraint("d", &(*new CArgAllow_Strings, ALL_DRIVERS));
00189 
00190     arg_desc->AddDefaultKey("U", "username",
00191                             "User name",
00192                             CArgDescriptions::eString, "anyone");
00193 
00194     arg_desc->AddDefaultKey("P", "password",
00195                             "Password",
00196                             CArgDescriptions::eString, "allowed");
00197 
00198     arg_desc->AddOptionalKey("v", "version",
00199                             "TDS protocol version",
00200                             CArgDescriptions::eInteger);
00201 
00202     arg_desc->AddDefaultKey("lb", "use_load_balancer",
00203                             "Use load balancer for service mapping",
00204                             CArgDescriptions::eString, "off");
00205     arg_desc->SetConstraint("lb", &(*new CArgAllow_Strings,
00206                                     "on", "off", "random"));
00207 
00208     // Add user's command-line argument descriptions
00209     InitSample(*arg_desc);
00210 
00211     // Setup arg.descriptions for this application
00212     SetupArgDescriptions(arg_desc.release());
00213 }
00214 
00215 
00216 int
00217 CDbapiSampleApp::Run()
00218 {
00219 
00220     const CArgs& args = GetArgs();
00221 
00222     // Get command-line arguments ...
00223     m_DriverName = args["d"].AsString();
00224     m_ServerName = args["S"].AsString();
00225     m_UserName   = args["U"].AsString();
00226     m_Password   = args["P"].AsString();
00227     if ( args["v"].HasValue() ) {
00228         m_TDSVersion = args["v"].AsString();
00229     } else {
00230         m_TDSVersion.erase();
00231     }
00232 
00233     string service_mapping = args["lb"].AsString();
00234     if (service_mapping == "on") {
00235         m_UseSvcMapper = true;
00236     } else if (service_mapping == "random") {
00237         static Uint4   rdm_seed = static_cast<Uint4>(time(NULL));
00238         static CRandom rdm_gen(rdm_seed);
00239         m_UseSvcMapper = (rdm_gen.GetRand(0, 1) != 0);
00240     }
00241 
00242     if (UseSvcMapper()) {
00243         DBLB_INSTALL_DEFAULT();
00244 #ifdef HAVE_LIBCONNEXT
00245         LOG_POST_X(1, "Using load-balancer service to server mapper ...");
00246 #else
00247         ERR_POST_X(2, "Load balancing requested, but not available in this build");
00248 #endif
00249     }
00250 
00251     if ( m_TDSVersion.empty() ) {
00252         // Setup some driver-specific attributes
00253         if ( GetDriverName() == "dblib" &&
00254              GetServerType() == eSybase ) {
00255             // Due to the bug in the Sybase 12.5 server, DBLIB cannot do
00256             // BcpIn to it using protocol version other than "100".
00257             SetDatabaseParameter("version", "100");
00258 //         } else if ( GetDriverName() == "ftds"  &&  GetServerType() == eMsSql ) {
00259 //             SetDatabaseParameter("version", "100");
00260         }
00261     } else {
00262         SetDatabaseParameter("version", m_TDSVersion);
00263     }
00264 
00265     try {
00266         return RunSample();
00267     } catch ( CDB_Exception& e ) {
00268         CDB_UserHandler::GetDefault().HandleIt(&e);
00269         return 1;
00270     }
00271 
00272     return 0;
00273 }
00274 
00275 
00276 void
00277 CDbapiSampleApp::Exit()
00278 {
00279     ExitSample();
00280 }
00281 
00282 
00283 I_DriverContext&
00284 CDbapiSampleApp::GetDriverContext(void)
00285 {
00286     if ( m_DriverContext.get() )
00287         return *m_DriverContext;
00288 
00289     // Create driver context
00290     C_DriverMgr driver_mgr;
00291     string      err_msg;
00292     m_DriverContext.reset
00293         (driver_mgr.GetDriverContext(GetDriverName(),
00294                                      &err_msg,
00295                                      &GetDatabaseParameters()));
00296 
00297     if ( !m_DriverContext.get() ) {
00298         ERR_POST_X(3, Fatal << "Cannot load driver: " << GetDriverName() << " ["
00299                       << err_msg << "] ");
00300     }
00301 
00302     return *m_DriverContext;
00303 }
00304 
00305 
00306 CDB_Connection*
00307 CDbapiSampleApp::CreateConnection(IConnValidator*                  validator,
00308                                   I_DriverContext::TConnectionMode mode,
00309                                   bool                             reusable,
00310                                   const string&                    pool_name)
00311 {
00312     auto_ptr<CDB_Connection> conn;
00313     I_DriverContext& dc(GetDriverContext());
00314 
00315     if (validator) {
00316         conn.reset(dc.ConnectValidated(GetServerName(),
00317                               GetUserName(),
00318                               GetPassword(),
00319                               *validator,
00320                               mode,
00321                               reusable,
00322                               pool_name));
00323     } else {
00324         conn.reset(dc.Connect(GetServerName(),
00325                               GetUserName(),
00326                               GetPassword(),
00327                               mode,
00328                               reusable,
00329                               pool_name));
00330     }
00331 
00332     if ( !conn.get() ) {
00333         ERR_POST_X(4, Fatal << "Cannot open connection to the server: "
00334                       << GetServerName());
00335     }
00336 
00337     // Print database name
00338     string sql("select @@servername");
00339 
00340     auto_ptr<CDB_LangCmd> stmt(conn->LangCmd(sql));
00341     stmt->Send();
00342 
00343     while ( stmt->HasMoreResults() ) {
00344         auto_ptr<CDB_Result> result(stmt->Result());
00345         if ( !result.get() )
00346             continue;
00347 
00348         if ( result->ResultType() == eDB_RowResult ) {
00349             if ( result->Fetch() ) {
00350                 CDB_LongChar v;
00351                 result->GetItem(&v);
00352                 LOG_POST_X(5, "Connected to the server '" << v.Value() << "'");
00353             }
00354         }
00355     }
00356 
00357     if ( m_UseSampleDatabase == eUseSampleDatabase ) {
00358         conn->SetDatabaseName("DBAPI_Sample");
00359     }
00360 
00361     return conn.release();
00362 }
00363 
00364 void
00365 CDbapiSampleApp::DeleteTable(const string& table_name)
00366 {
00367     try {
00368         string sql;
00369 
00370         // Drop the table.
00371         sql = "DROP TABLE " + table_name;
00372         auto_ptr<CDB_LangCmd> lcmd(GetConnection().LangCmd(sql));
00373         lcmd->Send();
00374         lcmd->DumpResults();
00375     } catch ( const CDB_Exception& ) {
00376     }
00377 }
00378 
00379 
00380 void
00381 CDbapiSampleApp::DeleteLostTables(void)
00382 {
00383     string sql = "select name from sysobjects WHERE type = 'U'";
00384     typedef list<string> table_name_list_t;
00385     table_name_list_t table_name_list;
00386     table_name_list_t::const_iterator citer;
00387 
00388     auto_ptr<CDB_LangCmd> lcmd(GetConnection().LangCmd(sql));
00389     lcmd->Send();
00390 
00391     while ( lcmd->HasMoreResults() ) {
00392 
00393         auto_ptr<CDB_Result> r(lcmd->Result());
00394         if ( !r.get() ) continue;
00395         if ( r->ResultType() == eDB_RowResult ) {
00396 
00397             while ( r->Fetch() ) {
00398                 EDB_Type rt = r->ItemDataType(0);
00399 
00400                 if ( !(rt == eDB_Char || rt == eDB_VarChar) ) continue;
00401                 CDB_VarChar str_val;
00402                 r->GetItem(&str_val);
00403 
00404                 if ( str_val.IsNULL() ) continue;
00405                 string table_creation_date;
00406                 string table_name = str_val.Value();
00407                 string::size_type pos = table_name.find_last_of('_');
00408 
00409                 if ( pos == string::npos ) continue;
00410                 table_creation_date = table_name.substr(pos + 1);
00411                 try {
00412                     // Table name suffix may be not a date ...
00413                     CTime creation_date(table_creation_date, "MDy");
00414 
00415                     if ( CTimeSpan(3, 0, 0, 0) < (CTime(CTime::eCurrent) - creation_date) ) {
00416               table_name_list.push_back(table_name);
00417                     }
00418                 }
00419                 catch(CException&)
00420                 {
00421                     // Ignore any problems ...
00422                 }
00423             }
00424         }
00425     }
00426 
00427     for(citer = table_name_list.begin(); citer != table_name_list.end(); ++citer)
00428     {
00429       DeleteTable(*citer);
00430     }
00431 }
00432 
00433 void
00434 CDbapiSampleApp::ShowResults (const string& query)
00435 {
00436     auto_ptr<CDB_LangCmd> lcmd(GetConnection().LangCmd(query));
00437     lcmd->Send();
00438 
00439     while ( lcmd->HasMoreResults() ) {
00440         auto_ptr<CDB_Result> r(lcmd->Result());
00441         if ( !r.get() )
00442             continue;
00443 
00444         if ( r->ResultType() == eDB_RowResult ) {
00445             while ( r->Fetch() ) {
00446                 cout << "<ROW>";
00447                 for ( unsigned int j = 0;  j < r->NofItems(); j++ ) {
00448                     EDB_Type rt = r->ItemDataType(j);
00449                     const string iname = r->ItemName(j);
00450                     cout << '<' << iname << '>';
00451                     if ( rt == eDB_Char || rt == eDB_VarChar ) {
00452                         CDB_VarChar v;
00453                         r->GetItem(&v);
00454                         cout << (v.IsNULL()? "{NULL}" : v.Value());
00455                     } else if ( rt == eDB_Int ||
00456                                 rt == eDB_SmallInt ||
00457                                 rt == eDB_TinyInt ) {
00458                         CDB_Int v;
00459                         r->GetItem(&v);
00460                         if ( v.IsNULL() ) {
00461                             cout << "{NULL}";
00462                         } else {
00463                             cout << v.Value();
00464                         }
00465                     } else if ( rt == eDB_Float ) {
00466                         CDB_Float v;
00467                         r->GetItem(&v);
00468                         if ( v.IsNULL() ) {
00469                             cout << "{NULL}";
00470                         } else {
00471                             cout << v.Value();
00472                         }
00473                     } else if ( rt == eDB_Double ) {
00474                         CDB_Double v;
00475                         r->GetItem(&v);
00476                         if ( v.IsNULL() ) {
00477                             cout << "{NULL}";
00478                         } else {
00479                             cout << v.Value();
00480                         }
00481                     } else if ( rt == eDB_DateTime ||
00482                                 rt == eDB_SmallDateTime ) {
00483                         CDB_DateTime v;
00484                         r->GetItem(&v);
00485                         if ( v.IsNULL() ) {
00486                             cout << "{NULL}";
00487                         } else {
00488                             cout << v.Value().AsString();
00489                         }
00490                     } else if ( rt == eDB_Numeric ) {
00491                         CDB_Numeric v;
00492                         r->GetItem(&v);
00493                         if ( v.IsNULL() ) {
00494                             cout << "{NULL}";
00495                         } else {
00496                             cout << v.Value();
00497                         }
00498                     } else if ( rt == eDB_Text ) {
00499                         CDB_Text v;
00500                         r->GetItem(&v);
00501                         cout << "{text (" << v.Size() << " bytes)}";
00502                     } else if ( rt == eDB_Image ) {
00503                         CDB_Image v;
00504                         r->GetItem(&v);
00505                         cout << "{image (" << v.Size() << " bytes)}";
00506                     } else {
00507                         r->SkipItem();
00508                         cout << "{unprintable}";
00509                     }
00510                     cout << "</" << iname << '>';
00511                 }
00512                 cout << "</ROW>" << endl << endl;
00513             }
00514         }
00515     }
00516 
00517 }
00518 
00519 void
00520 CDbapiSampleApp::CreateTable (const string& table_name)
00521 {
00522     string sql;
00523 
00524     // Drop a table with same name.
00525     sql  = string(" IF EXISTS (select * from sysobjects WHERE name = '");
00526     sql += table_name + "' AND type = 'U') begin ";
00527     sql += " DROP TABLE " + table_name + " end ";
00528 
00529     auto_ptr<CDB_LangCmd> lcmd(GetConnection().LangCmd (sql));
00530     lcmd->Send();
00531     lcmd->DumpResults();
00532 
00533     // Create a new table.
00534     sql  = " create table " + table_name + "( \n";
00535     sql += "    int_val int not null, \n";
00536     sql += "    fl_val real not null, \n";
00537     sql += "    date_val datetime not null, \n";
00538     sql += "    str_val varchar(255) null, \n";
00539     sql += "    txt_val text null \n";
00540 //     sql += "    primary key clustered(int_val) \n";
00541     sql += ")";
00542 
00543     lcmd.reset(GetConnection().LangCmd ( sql ));
00544     lcmd->Send();
00545     lcmd->DumpResults();
00546 }
00547 
00548 
00549 CDB_Connection&
00550 CDbapiSampleApp::GetConnection(void)
00551 {
00552     if ( !m_Connection.get() ) {
00553         m_Connection.reset(CreateConnection());
00554     }
00555 
00556     return *m_Connection;
00557 }
00558 
00559 
00560 ///////////////////////////////////////////////////////////////////////////////
00561 CDbapiSampleErrHandler::CDbapiSampleErrHandler(void)
00562 {
00563 }
00564 
00565 CDbapiSampleErrHandler::~CDbapiSampleErrHandler(void)
00566 {
00567 }
00568 
00569 // Return TRUE if "ex" is processed, FALSE if not (or if "ex" is NULL)
00570 bool
00571 CDbapiSampleErrHandler::HandleIt(CDB_Exception* ex)
00572 {
00573     if ( !ex )
00574         return false;
00575 
00576     // Ignore errors with ErrorCode set to 0
00577     // (this is related mostly to the FreeTDS driver)
00578     if (ex->GetDBErrCode() == 0)
00579         return true;
00580 
00581     // On other errors, throw an exception (was not allowed before!)
00582     throw *ex;
00583 }
00584 
00585 END_NCBI_SCOPE
00586 
00587 
00588 
00589 

Generated on Sun Dec 6 22:23:25 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:59 2009 by modify_doxy.py rev. 173732