NCBI C++ ToolKit
dbapi_testspeed.cpp
Go to the documentation of this file.
00001 /*  $Id: dbapi_testspeed.cpp 53326 2012-03-08 17:02:40Z 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 * File Description:
00027 *   Run a series of insert/update/select statement,
00028 *   measure the time required for their execution.
00029 *
00030 *============================================================================
00031 */
00032 
00033 #include <ncbi_pch.hpp>
00034 #include <corelib/ncbitime.hpp>
00035 #include <corelib/ncbifile.hpp>
00036 #include "dbapi_testspeed.hpp"
00037 #include "../dbapi_sample_base.hpp"
00038 #include <common/test_assert.h>  /* This header must go last */
00039 
00040 USING_NCBI_SCOPE;
00041 
00042 /////////////////////////////////////////////////////////////////////////////
00043 //  CDbapiTestBcpApp::
00044 //
00045 
00046 class CDbapiTestSpeedApp : public CDbapiSampleApp
00047 {
00048 public:
00049     CDbapiTestSpeedApp(void);
00050     virtual ~CDbapiTestSpeedApp(void);
00051 
00052 protected:
00053     virtual void InitSample(CArgDescriptions& arg_desc);
00054     virtual int  RunSample(void);
00055 
00056 protected:
00057     ///
00058     void FetchFile (const string& table_name, bool readItems);
00059     ///
00060     void FetchResults (const string& table_name, bool readItems);
00061     string GetTableName(void) const;
00062 
00063 private:
00064     string m_TableName;
00065 };
00066 
00067 CDbapiTestSpeedApp::CDbapiTestSpeedApp(void)
00068 {
00069 }
00070 
00071 CDbapiTestSpeedApp::~CDbapiTestSpeedApp(void)
00072 {
00073 }
00074 
00075 inline
00076 string
00077 CDbapiTestSpeedApp::GetTableName(void) const
00078 {
00079     return m_TableName;
00080 }
00081 
00082 // const char usage[] =
00083 // "Run a series of BCP/insert/select commands,\n"
00084 // "measure the time required for their execution. \n"
00085 // "\n"
00086 // "USAGE:   dbapi_testspeed -parameters [file]\n"
00087 // "REQUIRED PARAMETERS:\n"
00088 // "  -S server\n"
00089 // "  -d driver (e.g. ctlib dblib ftds odbc gateway)\n"
00090 // "  -g sss_server:port for gateway database driver\n"
00091 // "     (only one of -d/-g is required to be present)\n"
00092 // "OPTIONAL PARAMETERS:\n"
00093 // "  -r row_count (default is 1)\n"
00094 // "  -b text_blob_size in kilobytes (default is 1 kb)\n"
00095 // "  -c column_count  1..5 (int_val fl_val date_val str_val txt_val)\n"
00096 // "  -t table_name (default is 'TestSpeed')\n"
00097 // "  -m mode_character:\n"
00098 // "     r  write and read as usual,\n"
00099 // "        use CDB_Result->ReadItem() instead of GetItem() whenever possible\n"
00100 // "     w  write to the table, do not read, do not delete it\n"
00101 // "     R  read using ReadItem() (can be done many times after '-m w' )\n"
00102 // "     G  read using GetItem()  (can be done many times after '-m w' )\n"
00103 // "FILE (optional):\n"
00104 // "  Upload the specified file as a blob into the table,\n"
00105 // "  then download it to \"./testspeed.out\".\n"
00106 // "  \"diff\" can then be used to verify the data.\n"
00107 // "  -r -b -c parameterss are ignored.\n"
00108 // "\n"
00109 // ;
00110 
00111 void
00112 CDbapiTestSpeedApp::InitSample(CArgDescriptions& arg_desc)
00113 {
00114     arg_desc.AddOptionalKey(
00115         "g", "sss_server",
00116         "Server:port for gateway database driver\n"
00117         "(only one of -d/-g is required to be present)",
00118          CArgDescriptions::eString
00119     );
00120 
00121     arg_desc.AddDefaultKey(
00122         "r", "row_count",
00123         "Row count",
00124         CArgDescriptions::eInteger,
00125         "1"
00126     );
00127 
00128     arg_desc.AddDefaultKey(
00129         "b", "text_blob_size",
00130         "Text blob size in kilobytes",
00131         CArgDescriptions::eInteger,
00132         "1"
00133     );
00134 
00135     arg_desc.AddOptionalKey(
00136         "c", "column_count",
00137         "Column count  1..5 (int_val fl_val date_val str_val txt_val)",
00138         CArgDescriptions::eInteger
00139     );
00140 
00141     arg_desc.AddDefaultKey(
00142         "t", "table_name",
00143         "Table name",
00144         CArgDescriptions::eString,
00145         "#spd"
00146     );
00147 
00148     arg_desc.AddOptionalKey(
00149         "m", "mode_character",
00150         "Mode character \n"
00151         "     r  write and read as usual,\n"
00152         "        use CDB_Result->ReadItem() instead of GetItem() whenever possible\n"
00153         "     w  write to the table, do not read, do not delete it\n"
00154         "     R  read using ReadItem() (can be done many times after '-m w' )\n"
00155         "     G  read using GetItem()  (can be done many times after '-m w' )",
00156         CArgDescriptions::eString
00157     );
00158     arg_desc.SetConstraint("m", new CArgAllow_Symbols("rwRG"));
00159 
00160     arg_desc.AddOptionalKey(
00161         "FILE", "mode_character",
00162         "Upload the specified file as a blob into the table,\n"
00163         "then download it to \"./testspeed.out\" \n"
00164         "\"diff\" can then be used to verify the data.\n"
00165         "-r -b -c parameterss are ignored.\n",
00166         CArgDescriptions::eInputFile
00167     );
00168 }
00169 
00170 // Create a table with 5 columns, fill it using BCP or insert commands(1),
00171 // fetch results(2), delete the table. Execution time is measured for steps 1, 2.
00172 int
00173 CDbapiTestSpeedApp::RunSample(void)
00174 {
00175     string host_name;
00176     string port_num;
00177     int count = 0;
00178     int row_count = 1;
00179     int col_count = 5;
00180     int blob_size = 1;
00181     bool readItems = false;
00182     bool writeOnly = false;
00183     bool selectOnly = false;
00184     string fileParam;
00185     CStopWatch timer;
00186     double timeElapsed;
00187 
00188     const CArgs& args = GetArgs();
00189 
00190     // Process additional arguments ...
00191 
00192     //
00193     if (args["g"]) {
00194         host_name = args["g"].AsString();
00195 
00196         int i = NStr::Find(host_name, ":");
00197         if ( i > 0 ) {
00198             port_num = host_name.substr( i + 1 );
00199             host_name.resize(i);
00200         }
00201 
00202         if ( GetDriverName().empty() ) {
00203             SetDriverName("gateway");
00204         }
00205     }
00206 
00207     //
00208     row_count = args["r"].AsInteger();
00209     if ( row_count < 1  ||  row_count > 0x100000 ) {
00210         cerr << "Error -- invalid row count; valid values are 1 .. 1 Meg.\n";
00211         return 1;
00212     }
00213 
00214     //
00215     if (args["c"]) {
00216         col_count = args["g"].AsInteger();
00217     }
00218 
00219     //
00220     blob_size = args["b"].AsInteger();
00221     if ( blob_size < 1  ||  blob_size > 1024000 ) {
00222         cerr << "Error -- invalid blob size; valid values are 1 (kb) to 1000 (kb)\n";
00223         return 1;
00224     }
00225     if ( col_count < 5 ) {
00226         cerr << "Error -- blob size makes sense for '-c 5' only.\n";
00227         return 1;
00228     }
00229 
00230     //
00231     m_TableName = args["t"].AsString();
00232 
00233     //
00234     if (args["m"]) {
00235         string key_value = args["m"].AsString();
00236 
00237         switch ( *key_value.c_str() ) {
00238         case 'r':
00239             readItems  = true;
00240             break;
00241         case 'w':
00242             writeOnly  = true;
00243             break;
00244         case 'G':
00245             selectOnly = true;
00246             break;
00247         case 'R':
00248             selectOnly = true;
00249             readItems  = true;
00250             break;
00251         default:
00252             cerr << "Error -- invalid mode character '" << key_value << "'\n";
00253             return 1;
00254         }
00255     }
00256 
00257     //
00258     if (args["FILE"]) {
00259         fileParam = args["FILE"].AsString();
00260     }
00261 
00262     // Modify connection atributes
00263     // Do it before establishing of a connection to a server ...
00264     if ( !host_name.empty() ) {
00265         SetDatabaseParameter("host", host_name);
00266     }
00267     if ( !port_num.empty() ) {
00268         SetDatabaseParameter("port", port_num);
00269     }
00270 
00271     try {
00272         auto_ptr<CDB_LangCmd> set_cmd;
00273         auto_ptr<CDB_LangCmd> ins_cmd;
00274         auto_ptr<CDB_BCPInCmd> bcp;
00275 
00276         string cmd_str("set textsize 1024000");
00277         set_cmd.reset(GetConnection().LangCmd(cmd_str));
00278         set_cmd->Send();
00279         while ( set_cmd->HasMoreResults() ) {
00280             auto_ptr<CDB_Result> r(set_cmd->Result());
00281         }
00282 
00283         // Create table, insert data
00284         if ( !selectOnly ) {
00285             // Deletes the pre-existing table, if present
00286             CreateTable(GetTableName());
00287             cout << ", rows " << row_count;
00288             cout << ", cols " << col_count;
00289             cout << ", blob size " << blob_size << "\n";
00290 
00291             if ( col_count > 4 ) {
00292                 // "Bulk copy in" command
00293                 bcp.reset(GetConnection().BCPIn(GetTableName()));
00294             } else {
00295                 string s  = "insert into ";
00296                 s += GetTableName();
00297                 s += " (int_val";
00298                 string sv = "@i";
00299 
00300                 if ( col_count > 1 ) {
00301                     s += ", fl_val";
00302                     sv +=", @f";
00303                 }
00304                 if ( col_count > 2 ) {
00305                     s += ", date_val";
00306                     sv += ", @d";
00307                 }
00308                 if ( col_count > 3 ) {
00309                     s += ", str_val";
00310                     sv +=", @s";
00311                 }
00312 
00313                 s += ") values (";
00314                 s += sv;
00315                 s += ")";
00316 
00317                 ins_cmd.reset(GetConnection().LangCmd(s));
00318             }
00319 
00320             CDB_Int int_val;
00321             CDB_Float fl_val;
00322             CDB_DateTime date_val(CTime::eCurrent);
00323             CDB_VarChar str_val;
00324             CDB_Text pTxt;
00325             int i;
00326 
00327             if ( !fileParam.empty() ) {
00328                 CNcbiIfstream f(fileParam.c_str(), IOS_BASE::in |
00329                                 IOS_BASE::binary);
00330                 if ( !f.is_open() ) {
00331                     cerr << "Error -- cannot read '" << fileParam << "'\n";
00332                     return 1;
00333                 }
00334                 char buf[10240];
00335                 int sz;
00336                 while ( f.good() && !f.eof() ) {
00337                     f.read( buf, sizeof(buf) );
00338                     sz = (size_t)f.gcount();
00339                     if ( sz <= 0 ) break;
00340                     pTxt.Append(buf, sz);
00341                     if ( sz != sizeof(buf) ) break;
00342                 }
00343                 f.close();
00344 
00345                 col_count = 5;
00346                 row_count = 1;
00347             } else if ( col_count > 4 ) {
00348                 for ( i = 0; i < blob_size; ++i ) {
00349                     // Add 1024 chars
00350                     for ( int j = 0; j < 32; ++j ) {
00351                         pTxt.Append("If you want to know who we are--");
00352                     }
00353                 }
00354             }
00355 
00356             timer.Start();
00357 
00358             // Bind program variables as data source
00359             if ( bcp.get() ) {
00360                 bcp->Bind(0, &int_val);
00361                 if ( col_count > 1 ) bcp->Bind(1, &fl_val  );
00362                 if ( col_count > 2 ) bcp->Bind(2, &date_val);
00363                 if ( col_count > 3 ) bcp->Bind(3, &str_val );
00364                 if ( col_count > 4 ) bcp->Bind(4, &pTxt    );
00365             } else {
00366                 if ( !ins_cmd->BindParam("@i", &int_val) ) {
00367                     cerr << "Error in BindParam()\n";
00368                     DeleteTable(GetTableName());
00369                     return 1;
00370                 }
00371 
00372                 if ( col_count > 1 ) ins_cmd->BindParam("@f", &fl_val  );
00373                 if ( col_count > 2 ) ins_cmd->BindParam("@d", &date_val );
00374                 if ( col_count > 3 ) ins_cmd->BindParam("@s", &str_val );
00375             }
00376 
00377             for ( i = 0; i < row_count; ++i ) {
00378                 int_val  = i;
00379                 fl_val   = static_cast<float>(i + 0.999);
00380                 if ( !fileParam.empty() ) {
00381                     CDirEntry fileEntry(fileParam);
00382                     CTime fileTime;
00383                     fileEntry.GetTime(&fileTime);
00384 
00385                     date_val = fileTime;
00386                     str_val = fileParam;
00387                 } else {
00388                     date_val = date_val.Value();
00389                     str_val  = string("Franz Joseph Haydn symphony # ") +
00390                         NStr::IntToString(i);
00391                 }
00392                 pTxt.MoveTo(0);
00393 
00394                 if ( bcp.get() ) {
00395                     bcp->SendRow();
00396 
00397                     if ( count == 2 ) {
00398                         bcp->CompleteBatch();
00399                         count = 0;
00400                     }
00401                     ++count;
00402                 } else {
00403                     ins_cmd->Send();
00404                     while ( ins_cmd->HasMoreResults() ) {
00405                         auto_ptr<CDB_Result> r(ins_cmd->Result());
00406                     }
00407                 }
00408             }
00409             if ( bcp.get() ) {
00410                 bcp->CompleteBCP();
00411             }
00412             timeElapsed = timer.Elapsed();
00413             cout << "inserting timeElapsed=" << NStr::DoubleToString(timeElapsed, 2) << "\n";
00414         } else {
00415             cout << "\n";
00416         }
00417 
00418         if ( !writeOnly ) {
00419             // Read data
00420             timer.Start();
00421             if ( !fileParam.empty() ) {
00422                 FetchFile(GetTableName(), readItems);
00423             } else {
00424                 FetchResults(GetTableName(), readItems);
00425             }
00426             timeElapsed = timer.Elapsed();
00427             cout << "fetching timeElapsed=" << NStr::DoubleToString(timeElapsed,2) << "\n";
00428             cout << "\n";
00429         }
00430 
00431         if ( !(selectOnly || writeOnly) ) {
00432             DeleteTable(GetTableName());
00433         }
00434 
00435         // Drop lost tables.
00436         DeleteLostTables();
00437     }
00438     catch ( CDB_Exception& e ) {
00439         CDB_UserHandler::GetDefault().HandleIt(&e);
00440         return 1;
00441     }
00442 
00443     return 0;
00444 }
00445 
00446 void
00447 CDbapiTestSpeedApp::FetchFile(const string& table_name, bool readItems)
00448 {
00449     CDB_VarChar str_val;
00450     CDB_DateTime date_val;
00451 
00452     string query = "select date_val,str_val,txt_val from ";
00453     query += table_name;
00454     auto_ptr<CDB_LangCmd> lcmd(GetConnection().LangCmd(query));
00455     lcmd->Send();
00456 
00457     //CTime fileTime;
00458     while ( lcmd->HasMoreResults() ) {
00459         auto_ptr<CDB_Result> r(lcmd->Result());
00460         if ( !r.get() ) continue;
00461 
00462         if ( r->ResultType() == eDB_RowResult ) {
00463             while ( r->Fetch() ) {
00464                 CNcbiOfstream f("testspeed.out", IOS_BASE::trunc|IOS_BASE::out|IOS_BASE::binary);
00465 
00466                 for ( unsigned int j = 0;  j < r->NofItems(); j++ ) {
00467                     EDB_Type rt = r->ItemDataType(j);
00468 
00469                     if ( readItems && rt == eDB_Text ) {
00470                         bool isNull=false;
00471                         char txt_buf[10240];
00472                         // cout<< "j=" << j
00473                         //    << " CurrentItemNo()=" << r->CurrentItemNo() << "\n";
00474                         for ( ;; ) {
00475                             int len_txt = r->ReadItem(txt_buf, sizeof(txt_buf), &isNull);
00476                             //cout << "len_txt=" << len_txt << " isNull=" << isNull << "\n";
00477                             if ( isNull || len_txt<=0 ) break;
00478                             f.write(txt_buf, len_txt);
00479                         }
00480                         f.close();
00481                         continue;
00482                     }
00483 
00484                     // Type-specific GetItem()
00485                     if ( rt == eDB_Char || rt == eDB_VarChar ) {
00486                         r->GetItem(&str_val);
00487 
00488                     } else if ( rt == eDB_DateTime || rt == eDB_SmallDateTime ) {
00489                         r->GetItem(&date_val);
00490                     } else if ( rt == eDB_Text ) {
00491                         CDB_Text text_val;
00492                         r->GetItem(&text_val);
00493 
00494                         if ( text_val.IsNULL() ) {
00495                             // cout << "{NULL}";
00496                         } else {
00497                             char txt_buf[10240];
00498                             //cout << "text_val.Size()=" << text_val.Size() << "\n";
00499                             for ( ;; ) {
00500                                 int len_txt = text_val.Read( txt_buf, sizeof(txt_buf) );
00501                                 if ( len_txt<=0 ) break;
00502                                 f.write(txt_buf, len_txt);
00503                             }
00504                         }
00505                         f.close();
00506                     } else {
00507                         r->SkipItem();
00508                         // cout << "{unprintable}";
00509                     }
00510                 }
00511                 // cout << "</ROW>" << endl << endl;
00512             }
00513         }
00514     }
00515 
00516     cout << "File " << str_val.Value() << " dated "
00517         << date_val.Value().AsString() << " was written to testspeed.out using "
00518         << (readItems?"ReadItem":"GetItem") << "\n";
00519 }
00520 
00521 void
00522 CDbapiTestSpeedApp::FetchResults (const string& table_name, bool readItems)
00523 {
00524     // char* txt_buf = NULL ; // Temporary disabled ...
00525     // long len_txt = 0;
00526 
00527 
00528     string query = "select int_val,fl_val,date_val,str_val,txt_val from ";
00529     query += table_name;
00530 
00531     auto_ptr<CDB_LangCmd> lcmd(GetConnection().LangCmd(query));
00532     lcmd->Send();
00533 
00534     while ( lcmd->HasMoreResults() ) {
00535         auto_ptr<CDB_Result> r(lcmd->Result());
00536         if ( !r.get() ) continue;
00537 
00538         if ( r->ResultType() == eDB_RowResult ) {
00539             while ( r->Fetch() ) {
00540                 // cout << "<ROW>"<< endl;
00541                 for ( unsigned int j = 0;  j < r->NofItems(); ++j ) {
00542                     //    Determination of data type:
00543                     EDB_Type rt = r->ItemDataType(j);
00544                     const string iname = r->ItemName(j);
00545 
00546                     // cout << iname << '=';
00547 
00548                     if ( readItems && rt!=eDB_Numeric &&
00549                          rt != eDB_DateTime && rt != eDB_SmallDateTime ) {
00550                         bool isNull;
00551                         char buf[1024];
00552                         int sz=0;
00553                         while ( j == abs(r->CurrentItemNo()) ) {
00554                             sz += r->ReadItem(buf, sizeof(buf), &isNull);
00555                         }
00556                         continue;
00557                     }
00558 
00559                     // Type-specific GetItem()
00560                     if ( rt == eDB_Char || rt == eDB_VarChar ) {
00561                         CDB_VarChar str_val;
00562                         r->GetItem(&str_val);
00563                         // cout << (str_val.IsNULL()? "{NULL}" : str_val.Value()) << endl << endl ;
00564 
00565                     } else if ( rt == eDB_Int || rt == eDB_SmallInt || rt == eDB_TinyInt ) {
00566                         CDB_Int int_val;
00567                         r->GetItem(&int_val);
00568                         if ( int_val.IsNULL() ) {
00569                             // cout << "{NULL}";
00570                         } else {
00571                             // cout << int_val.Value() << endl << endl ;
00572                         }
00573                     } else if ( rt == eDB_Float ) {
00574                         CDB_Float fl_val;
00575                         r->GetItem(&fl_val);
00576                         if ( fl_val.IsNULL() ) {
00577                             // cout << "{NULL}";
00578                         } else {
00579                             // cout << fl_val.Value() << endl<< endl ;
00580                         }
00581                     } else if ( rt == eDB_Double ) {
00582                         CDB_Double fl_val;
00583                         r->GetItem(&fl_val);
00584                         if ( fl_val.IsNULL() ) {
00585                             // cout << "{NULL}";
00586                         } else {
00587                             // cout << fl_val.Value() << endl<< endl ;
00588                         }
00589                     } else if ( rt == eDB_DateTime || rt == eDB_SmallDateTime ) {
00590                         CDB_DateTime date_val;
00591                         r->GetItem(&date_val);
00592                         if ( date_val.IsNULL() ) {
00593                             // cout << "{NULL}";
00594                         } else {
00595                             // cout << date_val.Value().AsString() << endl<< endl ;
00596                         }
00597                     } else if ( rt == eDB_Text ) {
00598                         CDB_Text text_val;
00599                         r->GetItem(&text_val);
00600 
00601                         if ( text_val.IsNULL() ) {
00602                             // cout << "{NULL}";
00603                         } else {
00604                             /* Do not do this at the moment ...
00605                             txt_buf = ( char*) malloc (text_val.Size() + 1);
00606                             len_txt = text_val.Read (( char*)txt_buf, text_val.Size());
00607                             txt_buf[text_val.Size()] = '\0';
00608                             */
00609                             // cout << txt_buf << endl<< endl ;
00610                         }
00611                     } else {
00612                         r->SkipItem();
00613                         // cout << "{unprintable}";
00614                     }
00615                 }
00616                 // cout << "</ROW>" << endl << endl;
00617             }
00618         }
00619     }
00620 }
00621 
00622 int main(int argc, char* argv[])
00623 {
00624     // Execute main application function
00625     return CDbapiTestSpeedApp().AppMain(argc, argv);
00626 }
00627 
00628 
Modified on Wed May 23 13:33:37 2012 by modify_doxy.py rev. 337098