1 /*  $Id: dbapi_unit_test_common.cpp 583697 2019-04-01 15:00:36Z ucko $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Sergey Sikorskiy
27  *
28  * File Description: DBAPI unit-test
29  *
30  * ===========================================================================
31  */
32 
33 #include "dbapi_unit_test_pch.hpp"
34 
35 #include <corelib/ncbiargs.hpp>
36 //#include <corelib/ncbithr.hpp>
37 #include <corelib/expr.hpp>
38 
39 #include <connect/ncbi_core_cxx.hpp>
40 #ifdef HAVE_LIBCONNEXT
41 #  include <connect/ext/ncbi_crypt.h>
42 #endif
43 
44 #include <dbapi/driver/drivers.hpp>
45 #include <dbapi/driver/impl/dbapi_driver_utils.hpp>
46 #include <dbapi/driver/dbapi_svc_mapper.hpp>
47 #include <dbapi/driver/impl/dbapi_impl_context.hpp>
48 
49 BEGIN_NCBI_SCOPE
50 
51 ///////////////////////////////////////////////////////////////////////////////
CDBSetConnParams(const string & server_name,const string & user_name,const string & password,Uint4 tds_version,const CDBConnParams & other)52 CDBSetConnParams::CDBSetConnParams(
53         const string& server_name,
54         const string& user_name,
55         const string& password,
56         Uint4 tds_version,
57         const CDBConnParams& other)
58 : CDBConnParamsDelegate(other)
59 , m_ProtocolVersion(tds_version)
60 , m_ServerName(server_name)
61 , m_UserName(user_name)
62 , m_Password(password)
63 {
64 }
65 
~CDBSetConnParams(void)66 CDBSetConnParams::~CDBSetConnParams(void)
67 {
68 }
69 
70 Uint4
GetProtocolVersion(void) const71 CDBSetConnParams::GetProtocolVersion(void) const
72 {
73     return m_ProtocolVersion;
74 }
75 
76 string
GetServerName(void) const77 CDBSetConnParams::GetServerName(void) const
78 {
79     return m_ServerName;
80 }
81 
82 string
GetUserName(void) const83 CDBSetConnParams::GetUserName(void) const
84 {
85     return m_UserName;
86 }
87 
88 string
GetPassword(void) const89 CDBSetConnParams::GetPassword(void) const
90 {
91     return m_Password;
92 }
93 
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 const char* ftds95_driver = "ftds95";
97 const char* ftds100_driver = "ftds100";
98 const char* ftds_driver = "ftds";
99 
100 const char* odbc_driver = "odbc";
101 const char* ctlib_driver = "ctlib";
102 
103 ////////////////////////////////////////////////////////////////////////////////
104 const char* msg_record_expected = "Record expected";
105 
106 /////////////////////////////////////////////////////////////////////////////
107 const string&
GetTableName(void)108 GetTableName(void)
109 {
110     static const string s_TableName = "#dbapi_unit_table";
111     return s_TableName;
112 }
113 
114 const CTestArguments&
GetArgs(void)115 GetArgs(void)
116 {
117     static CRef<CTestArguments> s_Args(new CTestArguments());
118     return *s_Args;
119 }
120 
121 int
GetMaxVarcharSize(void)122 GetMaxVarcharSize(void)
123 {
124     static int s_max_varchar_size = 0;
125 
126     if (s_max_varchar_size == 0) {
127         if ( GetArgs().GetServerType() == CDBConnParams::eMSSqlServer) {
128             s_max_varchar_size = 8000;
129         } else {
130             // Sybase
131             s_max_varchar_size = 1900;
132         }
133     }
134 
135     return s_max_varchar_size;
136 }
137 
138 
139 ///////////////////////////////////////////////////////////////////////////////
140 static IDataSource* s_DS = NULL;
141 
142 IDataSource&
GetDS(void)143 GetDS(void)
144 {
145     _ASSERT(s_DS);
146     return *s_DS;
147 }
148 
149 static
s_CommonInit(void)150 bool s_CommonInit(void)
151 {
152     // Using old log format ...
153     // Show time (no msec.) ...
154     SetDiagPostFlag(eDPF_DateTime);
155     CONNECT_Init(&CNcbiApplication::Instance()->GetConfig());
156 
157     DBLB_INSTALL_DEFAULT();
158 
159 #ifndef NCBI_DLL_SUPPORT
160 
161 #ifdef HAVE_LIBSYBASE
162     DBAPI_RegisterDriver_CTLIB();
163 #endif
164 
165 #ifdef HAVE_ODBC
166     DBAPI_RegisterDriver_ODBC();
167 #endif
168 
169     DBAPI_RegisterDriver_FTDS();
170     DBAPI_RegisterDriver_FTDS95();
171     DBAPI_RegisterDriver_FTDS100();
172 
173 #else
174     CPluginManager_DllResolver::EnableGlobally(true);
175 #endif // NCBI_DLL_SUPPORT
176 
177     if (false) {
178         // Two calls below will cause problems with the Sybase 12.5.1 client
179         // (No problems with the Sybase 12.5.0 client)
180         IDataSource* ds = GetDM().MakeDs(GetArgs().GetConnParams());
181         GetDM().DestroyDs(ds);
182     }
183 
184     try {
185         s_DS = GetDM().MakeDs(GetArgs().GetConnParams());
186     }
187     catch (CException& ex) {
188         LOG_POST(Warning << "Error loading database driver: " << ex.what());
189         NcbiTestSetGlobalDisabled();
190         return false;
191     }
192 
193     I_DriverContext* drv_context = GetDS().GetDriverContext();
194     drv_context->SetLoginTimeout(4);
195     drv_context->SetTimeout(4);
196 
197     if (GetArgs().GetTestConfiguration() != CTestArguments::eWithoutExceptions) {
198         if (GetArgs().IsODBCBased()) {
199             drv_context->PushCntxMsgHandler(
200                 new CDB_UserHandler_Exception_ODBC,
201                 eTakeOwnership
202                 );
203             drv_context->PushDefConnMsgHandler(
204                 new CDB_UserHandler_Exception_ODBC,
205                 eTakeOwnership
206                 );
207         } else {
208             drv_context->PushCntxMsgHandler(
209                 new CDB_UserHandler_Exception,
210                 eTakeOwnership
211                 );
212             drv_context->PushDefConnMsgHandler(
213                 new CDB_UserHandler_Exception,
214                 eTakeOwnership
215                 );
216         }
217     }
218 
219     return true;
220 }
221 
222 static
s_CommonFini(void)223 void s_CommonFini(void)
224 {
225     if (s_DS) {
226         GetDM().DestroyDs(s_DS);
227     }
228 }
229 
230 ///////////////////////////////////////////////////////////////////////////////
231 static AutoPtr<IConnection> s_Conn = NULL;
232 
233 static void s_ResetConnection(void);
234 
235 IConnection&
GetConnection(void)236 GetConnection(void)
237 {
238     _ASSERT(s_Conn.get());
239     if ( !s_Conn->IsAlive() ) {
240         s_ResetConnection();
241     }
242     return *s_Conn;
243 }
244 
245 
246 ///////////////////////////////////////////////////////////////////////////////
NCBITEST_AUTO_INIT()247 NCBITEST_AUTO_INIT()
248 {
249     if (!s_CommonInit())
250         return;
251 
252     s_ResetConnection();
253 }
254 
s_ResetConnection(void)255 static void s_ResetConnection(void)
256 {
257     s_Conn.reset(GetDS().CreateConnection( CONN_OWNERSHIP ));
258     _ASSERT(s_Conn.get());
259 
260     s_Conn->Connect(GetArgs().GetConnParams());
261     //CTrivialConnValidator validator(GetArgs().GetDatabaseName());
262     //s_Conn->ConnectValidated(validator, GetArgs().GetUserName(), GetArgs().GetUserPassword(), GetArgs().GetServerName());
263     //cout << s_Conn->GetCDB_Connection()->ServerName() << endl;
264 
265     unique_ptr<IStatement> auto_stmt(GetConnection().GetStatement());
266 
267     // Create a test table ...
268     string sql;
269 
270     sql  = " CREATE TABLE " + GetTableName() + "( \n";
271     sql += "    id NUMERIC(18, 0) IDENTITY NOT NULL, \n";
272     sql += "    int_field INT NULL, \n";
273     sql += "    vc1000_field VARCHAR(1000) NULL, \n";
274     sql += "    text_field TEXT NULL, \n";
275     sql += "    image_field IMAGE NULL \n";
276     sql += " )";
277 
278     // Create the table
279     auto_stmt->ExecuteUpdate(sql);
280 
281     sql  = " CREATE UNIQUE INDEX #ind01 ON " + GetTableName() + "( id ) \n";
282 
283     // Create an index
284     auto_stmt->ExecuteUpdate( sql );
285 
286     sql  = " CREATE TABLE #dbapi_bcp_table2 ( \n";
287     sql += "    id INT NULL, \n";
288     // Identity won't work with bulk insert ...
289     // sql += "    id NUMERIC(18, 0) IDENTITY NOT NULL, \n";
290     sql += "    int_field INT NULL, \n";
291     sql += "    vc1000_field VARCHAR(1000) NULL, \n";
292     sql += "    text_field TEXT NULL \n";
293     sql += " )";
294 
295     auto_stmt->ExecuteUpdate( sql );
296 
297     sql  = " CREATE TABLE #test_unicode_table ( \n";
298     sql += "    id NUMERIC(18, 0) IDENTITY NOT NULL, \n";
299     sql += "    nvc255_field NVARCHAR(255) NULL \n";
300 //        sql += "    nvc255_field VARCHAR(255) NULL \n";
301     sql += " )";
302 
303     // Create table
304     auto_stmt->ExecuteUpdate(sql);
305 }
306 
NCBITEST_AUTO_FINI()307 NCBITEST_AUTO_FINI()
308 {
309 //     I_DriverContext* drv_context = GetDS().GetDriverContext();
310 //
311 //     drv_context->PopDefConnMsgHandler( m_ErrHandler.get() );
312 //     drv_context->PopCntxMsgHandler( m_ErrHandler.get() );
313 
314     s_Conn.reset(NULL);
315     s_CommonFini();
316 }
317 
318 
319 ///////////////////////////////////////////////////////////////////////////////
320 
GetSybaseClientVersion(void)321 string GetSybaseClientVersion(void)
322 {
323     string sybase_version;
324 
325 #if defined(NCBI_OS_MSWIN)
326     sybase_version = "15.5";
327 #else
328     impl::CDriverContext::ResetEnvSybase();
329 
330     CNcbiEnvironment env;
331     sybase_version = env.Get("SYBASE");
332 
333     if (!sybase_version.empty()) {
334         CDirEntry dir_entry(sybase_version);
335         dir_entry.DereferenceLink();
336         sybase_version = dir_entry.GetPath();
337 
338         sybase_version = sybase_version.substr(
339                 sybase_version.find_last_of('/') + 1
340                 );
341     } else {
342         sybase_version = "0.0";
343     }
344 #endif
345 
346     return sybase_version;
347 }
348 
349 
NCBITEST_INIT_VARIABLES(parser)350 NCBITEST_INIT_VARIABLES(parser)
351 {
352     ////////////////////////
353     // Sybase ...
354     {
355         double syb_client_ver = 0.0;
356         const string syb_client_ver_str = GetSybaseClientVersion();
357 
358         if (!syb_client_ver_str.empty()) {
359             try {
360                 syb_client_ver = NStr::StringToDouble(syb_client_ver_str.substr(0, 4));
361             } catch (const CStringException&) {
362                 // Conversion error
363             }
364         }
365 
366         parser->AddSymbol("SYBASE_ClientVersion", syb_client_ver);
367 
368     }
369 
370     ///////////////////////
371     // Configuration-related ...
372 #ifdef HAVE_LIBCONNEXT
373     parser->AddSymbol("HAVE_LibConnExt", CRYPT_Version(-1) != -1);
374 #else
375     parser->AddSymbol("HAVE_LibConnExt", false);
376 #endif
377 
378 #ifdef HAVE_LIBSYBASE
379     parser->AddSymbol("HAVE_Sybase", true);
380 #else
381     parser->AddSymbol("HAVE_Sybase", false);
382 #endif
383 
384 #ifdef HAVE_ODBC
385     parser->AddSymbol("HAVE_ODBC", true);
386 #else
387     parser->AddSymbol("HAVE_ODBC", false);
388 #endif
389 
390 #ifdef HAVE_MYSQL
391     parser->AddSymbol("HAVE_MYSQL", true);
392 #else
393     parser->AddSymbol("HAVE_MYSQL", false);
394 #endif
395 
396     parser->AddSymbol("DRIVER_AllowsMultipleContexts", GetArgs().DriverAllowsMultipleContexts());
397 
398     parser->AddSymbol("SERVER_MySQL", GetArgs().GetServerType() == CDBConnParams::eMySQL);
399     parser->AddSymbol("SERVER_SybaseOS", GetArgs().GetServerType() == CDBConnParams::eSybaseOpenServer);
400     parser->AddSymbol("SERVER_SybaseSQL", GetArgs().GetServerType() == CDBConnParams::eSybaseSQLServer);
401     parser->AddSymbol("SERVER_MicrosoftSQL", GetArgs().GetServerType() == CDBConnParams::eMSSqlServer);
402 
403     parser->AddSymbol("DRIVER_ftds", GetArgs().IsFreeTDS());
404     parser->AddSymbol("DRIVER_ftds95", GetArgs().GetDriverName() == ftds95_driver);
405     parser->AddSymbol("DRIVER_ftds100", GetArgs().GetDriverName() == ftds100_driver);
406     parser->AddSymbol("DRIVER_odbc", GetArgs().GetDriverName() == odbc_driver);
407     parser->AddSymbol("DRIVER_ctlib", GetArgs().GetDriverName() == ctlib_driver);
408     parser->AddSymbol("DRIVER_mysql", GetArgs().GetDriverName() == "mysql");
409 
410     parser->AddSymbol("DRIVER_IsBcpAvailable", GetArgs().IsBCPAvailable());
411     parser->AddSymbol("DRIVER_IsOdbcBased", GetArgs().GetDriverName() == odbc_driver);
412 }
413 
414 
415 ////////////////////////////////////////////////////////////////////////////////
CUnitTestParams(const CDBConnParams & other)416 CUnitTestParams::CUnitTestParams(const CDBConnParams& other)
417 : CDBConnParamsDelegate(other)
418 {
419 }
420 
~CUnitTestParams(void)421 CUnitTestParams::~CUnitTestParams(void)
422 {
423 }
424 
GetServerName(void) const425 string CUnitTestParams::GetServerName(void) const
426 {
427     const string server_name = CDBConnParamsDelegate::GetServerName();
428 
429     if (NStr::CompareNocase(server_name, "MsSql") == 0) {
430 #ifdef HAVE_LIBCONNEXT
431         return "DBAPI_MS_TEST";
432 #else
433         return "MSDEV1";
434 #endif
435     } else if (NStr::CompareNocase(server_name, "Sybase") == 0) {
436 #ifdef HAVE_LIBCONNEXT
437         return "DBAPI_SYB160_TEST";
438 #else
439         return "DBAPI_DEV16_2K";
440 #endif
441     }
442 
443     return server_name;
444 }
445 
446 CDBConnParams::EServerType
GetServerType(void) const447 CUnitTestParams::GetServerType(void) const
448 {
449     return CDBConnParamsDelegate::GetServerType();
450 }
451 
452 ////////////////////////////////////////////////////////////////////////////////
CTestArguments(void)453 CTestArguments::CTestArguments(void)
454 : m_TestConfiguration(eWithExceptions)
455 , m_NumOfDisabled(0)
456 , m_ReportDisabled(false)
457 , m_ReportExpected(false)
458 , m_ConnParams(m_ParamBase)
459 , m_CPPParams(m_ParamBase2)
460 , m_ConnParams2(m_CPPParams)
461 // , m_CPPParams(m_ParamBase)
462 // , m_ConnParams(m_CPPParams)
463 {
464     const CNcbiApplication* app = CNcbiApplication::Instance();
465 
466     if (!app) {
467         return;
468     }
469 
470     const CArgs& args = app->GetArgs();
471 
472     // Get command-line arguments ...
473     m_ParamBase.SetServerName(args["S"].AsString());
474     m_ParamBase2.SetServerName(args["S"].AsString());
475     m_ParamBase.SetUserName(args["U"].AsString());
476     m_ParamBase2.SetUserName(args["U"].AsString());
477     m_ParamBase.SetPassword(args["P"].AsString());
478     m_ParamBase2.SetPassword(args["P"].AsString());
479 
480     if (args["dr"].HasValue()) {
481         m_ParamBase.SetDriverName(args["dr"].AsString());
482         m_ParamBase2.SetDriverName(args["dr"].AsString());
483         if (args["dr"].AsString() == ctlib_driver) {
484             // Force the traditional C locale when using Sybase ctlib
485             // to avoid error #4847 from Sybase ASE 15.5 (reporting
486             // that character set mismatches block bulk insertion).
487             CNcbiEnvironment& env
488                 = CNcbiApplication::Instance()->SetEnvironment();
489             env.Unset("LANG");
490             env.Unset("LC_ALL");
491             env.Unset("LC_CTYPE");
492         }
493     }
494 
495     if (args["D"].HasValue()) {
496         m_ParamBase.SetDatabaseName(args["D"].AsString());
497         m_ParamBase2.SetDatabaseName(args["D"].AsString());
498     }
499 
500     if ( args["V"].HasValue() ) {
501         m_ParamBase.SetProtocolVersion(args["V"].AsInteger());
502         m_ParamBase2.SetProtocolVersion(args["V"].AsInteger());
503     }
504 
505     if (args["conf"].AsString() == "with-exceptions") {
506         m_TestConfiguration = CTestArguments::eWithExceptions;
507     } else if (args["conf"].AsString() == "without-exceptions") {
508         m_TestConfiguration = CTestArguments::eWithoutExceptions;
509     } else if (args["conf"].AsString() == "fast") {
510         m_TestConfiguration = CTestArguments::eFast;
511     }
512 
513     SetDatabaseParameters();
514 }
515 
516 bool
IsBCPAvailable(void) const517 CTestArguments::IsBCPAvailable(void) const
518 {
519 #if defined(NCBI_OS_SOLARIS)
520     const bool os_solaris = true;
521 #else
522     const bool os_solaris = false;
523 #endif
524 
525     if (os_solaris && HOST_CPU[0] == 'i' && GetDriverName() == ctlib_driver) {
526         // Solaris Intel native Sybase drivers ...
527         // There is no apropriate client
528         return false;
529     }
530 
531     return true;
532 }
533 
534 bool
IsFreeTDS(void) const535 CTestArguments::IsFreeTDS(void) const
536 {
537     return NStr::StartsWith(GetDriverName(), "ftds");
538 }
539 
540 bool
IsODBCBased(void) const541 CTestArguments::IsODBCBased(void) const
542 {
543     return GetDriverName() == odbc_driver;
544 }
545 
DriverAllowsMultipleContexts(void) const546 bool CTestArguments::DriverAllowsMultipleContexts(void) const
547 {
548     return (GetDriverName() == ctlib_driver) || IsFreeTDS() || IsODBCBased();
549 }
550 
551 void
SetDatabaseParameters(void)552 CTestArguments::SetDatabaseParameters(void)
553 {
554     if ((IsFreeTDS() /*  ||  GetDriverName() == odbc_driver */)
555         &&  GetServerType() == CDBConnParams::eMSSqlServer)
556     {
557         m_ParamBase.SetEncoding(eEncoding_UTF8);
558         m_ParamBase2.SetEncoding(eEncoding_UTF8);
559     }
560 
561     if (!m_GatewayHost.empty()) {
562         m_ParamBase.SetParam("host_name", m_GatewayHost);
563         m_ParamBase2.SetParam("host_name", m_GatewayHost);
564         m_ParamBase.SetParam("port_num", m_GatewayPort);
565         m_ParamBase2.SetParam("port_num", m_GatewayPort);
566         m_ParamBase.SetParam("driver_name", GetDriverName());
567         m_ParamBase2.SetParam("driver_name", GetDriverName());
568     }
569 }
570 
PutMsgDisabled(const char * msg) const571 void CTestArguments::PutMsgDisabled(const char* msg) const
572 {
573     ++m_NumOfDisabled;
574 
575     if (m_ReportDisabled) {
576         LOG_POST(Warning << "- " << msg << " is disabled !!!");
577     }
578 }
579 
PutMsgExpected(const char * msg,const char * replacement) const580 void CTestArguments::PutMsgExpected(const char* msg, const char* replacement) const
581 {
582     if (m_ReportExpected) {
583         LOG_POST(Warning << "? " << msg << " is expected instead of " << replacement);
584     }
585 }
586 
587 ////////////////////////////////////////////////////////////////////////////////
NCBITEST_INIT_CMDLINE(arg_desc)588 NCBITEST_INIT_CMDLINE(arg_desc)
589 {
590 // Describe the expected command-line arguments
591 #define FTDS_DRIVERS ftds_driver, ftds95_driver, ftds100_driver
592 
593 #define DEF_SERVER    "MSSQL"
594 #define DEF_DRIVER    ftds_driver
595 #define ALL_DRIVERS   ctlib_driver, FTDS_DRIVERS, odbc_driver
596 
597 //#if defined(NCBI_OS_MSWIN)
598 //#define DEF_SERVER    "MSSQL"
599 //#define DEF_DRIVER    ftds_driver
600 //#define ALL_DRIVERS   ctlib_driver, FTDS_DRIVERS, odbc_driver
601 
602 //#elif defined(HAVE_LIBSYBASE)
603 //#define DEF_SERVER    "Sybase"
604 //#define DEF_DRIVER    ctlib_driver
605 //#define ALL_DRIVERS   ctlib_driver, FTDS_DRIVERS
606 //#else
607 //#define DEF_SERVER    "MSSQL"
608 //#define DEF_DRIVER    ftds_driver
609 //#define ALL_DRIVERS   FTDS_DRIVERS
610 //#endif
611 
612     arg_desc->AddDefaultKey("S", "server",
613                             "Name of the SQL server to connect to",
614                             CArgDescriptions::eString, DEF_SERVER);
615 
616     arg_desc->AddDefaultKey("dr", "driver",
617                             "Name of the DBAPI driver to use",
618                             CArgDescriptions::eString, DEF_DRIVER);
619     arg_desc->SetConstraint("dr", &(*new CArgAllow_Strings, ALL_DRIVERS));
620 
621     arg_desc->AddDefaultKey("U", "username",
622                             "User name",
623                             CArgDescriptions::eString, "DBAPI_test");
624 
625     arg_desc->AddDefaultKey("P", "password",
626                             "Password",
627                             CArgDescriptions::eString, "allowed");
628     arg_desc->AddDefaultKey("D", "database",
629                             "Name of the database to connect",
630                             CArgDescriptions::eString, "DBAPI_Sample");
631 
632     arg_desc->AddOptionalKey("V", "version",
633                             "TDS protocol version",
634                             CArgDescriptions::eInteger);
635 #if BOOST_VERSION < 106000
636     arg_desc->AddAlias("v", "V");
637 #endif
638 
639     arg_desc->AddDefaultKey("conf", "configuration",
640                             "Configuration for testing",
641                             CArgDescriptions::eString, "with-exceptions");
642     arg_desc->SetConstraint("conf", &(*new CArgAllow_Strings,
643                             "with-exceptions", "without-exceptions", "fast"));
644 }
645 
646 
647 
648 END_NCBI_SCOPE
649