nanodbc.cpp 86 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159
  1. //! \file nanodbc.cpp Implementation details.
  2. #ifndef DOXYGEN
  3. #include "nanodbc.h"
  4. #include <algorithm>
  5. #include <cassert>
  6. #include <clocale>
  7. #include <codecvt>
  8. #include <cstdint>
  9. #include <cstdio>
  10. #include <cstring>
  11. #include <ctime>
  12. #include <iomanip>
  13. #include <map>
  14. #include <sstream>
  15. #if defined(_MSC_VER) && _MSC_VER <= 1800
  16. // silence spurious Visual C++ warnings
  17. #pragma warning(disable:4244) // warning about integer conversion issues.
  18. #pragma warning(disable:4312) // warning about 64-bit portability issues.
  19. #pragma warning(disable:4996) // warning about snprintf() deprecated.
  20. #endif
  21. #ifdef __APPLE__
  22. // silence spurious OS X deprecation warnings
  23. #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
  24. #endif
  25. #ifdef _WIN32
  26. // needs to be included above sql.h for windows
  27. #define NOMINMAX
  28. #include <windows.h>
  29. #endif
  30. #include <sql.h>
  31. #include <sqlext.h>
  32. ///////////////////////////////////////////////////////////////////////////////////////////////////
  33. // Unicode Support
  34. ///////////////////////////////////////////////////////////////////////////////////////////////////
  35. #if defined(_MSC_VER)
  36. #ifdef NANODBC_USE_UNICODE
  37. #define NANODBC_TEXT(s) L ## s
  38. #define NANODBC_SNPRINTF std::swprintf
  39. #define NANODBC_STRFTIME std::wcsftime
  40. #define NANODBC_STRLEN std::wcslen
  41. #define NANADBC_STRNCMP std::wcsncmp
  42. #define NANODBC_UNICODE(f) f ## W
  43. #define NANODBC_SQLCHAR SQLWCHAR
  44. #else
  45. #define NANODBC_TEXT(s) s
  46. #define NANODBC_SNPRINTF _snprintf
  47. #define NANODBC_STRFTIME std::strftime
  48. #define NANODBC_STRLEN std::strlen
  49. #define NANADBC_STRNCMP std::strncmp
  50. #define NANODBC_UNICODE(f) f
  51. #define NANODBC_SQLCHAR SQLCHAR
  52. #endif
  53. #else
  54. #ifdef NANODBC_USE_UNICODE
  55. #define NANODBC_TEXT(s) L ## s
  56. #define NANODBC_SNPRINTF std::swprintf
  57. #define NANODBC_STRFTIME std::wcsftime
  58. #define NANODBC_STRLEN std::wcslen
  59. #define NANADBC_STRNCMP std::wcsncmp
  60. #define NANODBC_UNICODE(f) f ## W
  61. #define NANODBC_SQLCHAR SQLWCHAR
  62. #else
  63. #define NANODBC_TEXT(s) s
  64. #define NANODBC_SNPRINTF std::snprintf
  65. #define NANODBC_STRFTIME std::strftime
  66. #define NANODBC_STRLEN std::strlen
  67. #define NANADBC_STRNCMP std::strncmp
  68. #define NANODBC_UNICODE(f) f
  69. #define NANODBC_SQLCHAR SQLCHAR
  70. #endif
  71. #endif
  72. ///////////////////////////////////////////////////////////////////////////////////////////////////
  73. // ODBC API Interface
  74. ///////////////////////////////////////////////////////////////////////////////////////////////////
  75. #define NANODBC_STRINGIZE_I(text) #text
  76. #define NANODBC_STRINGIZE(text) NANODBC_STRINGIZE_I(text)
  77. // By making all calls to ODBC functions through this macro, we can easily get
  78. // runtime debugging information of which ODBC functions are being called,
  79. // in what order, and with what parameters by defining NANODBC_ODBC_API_DEBUG.
  80. #ifdef NANODBC_ODBC_API_DEBUG
  81. #include <iostream>
  82. #define NANODBC_CALL_RC(FUNC, RC, ...) \
  83. do \
  84. { \
  85. std::cerr << __FILE__ ":" NANODBC_STRINGIZE(__LINE__) " " \
  86. NANODBC_STRINGIZE(FUNC) "(" #__VA_ARGS__ ")" << std::endl; \
  87. RC = FUNC(__VA_ARGS__); \
  88. } while(false) \
  89. /**/
  90. #define NANODBC_CALL(FUNC, ...) \
  91. do \
  92. { \
  93. std::cerr << __FILE__ ":" NANODBC_STRINGIZE(__LINE__) " " \
  94. NANODBC_STRINGIZE(FUNC) "(" #__VA_ARGS__ ")" << std::endl; \
  95. FUNC(__VA_ARGS__); \
  96. } while(false) \
  97. /**/
  98. #else
  99. #define NANODBC_CALL_RC(FUNC, RC, ...) RC = FUNC(__VA_ARGS__)
  100. #define NANODBC_CALL(FUNC, ...) FUNC(__VA_ARGS__)
  101. #endif
  102. ///////////////////////////////////////////////////////////////////////////////////////////////////
  103. // Error and Exception Handling
  104. ///////////////////////////////////////////////////////////////////////////////////////////////////
  105. namespace
  106. {
  107. #ifdef NANODBC_ODBC_API_DEBUG
  108. inline nanodbc::string_type return_code(RETCODE rc)
  109. {
  110. switch(rc)
  111. {
  112. case SQL_SUCCESS: return NANODBC_UNICODE("SQL_SUCCESS");
  113. case SQL_SUCCESS_WITH_INFO: return NANODBC_UNICODE("SQL_SUCCESS_WITH_INFO");
  114. case SQL_ERROR: return NANODBC_UNICODE("SQL_ERROR");
  115. case SQL_INVALID_HANDLE: return NANODBC_UNICODE("SQL_INVALID_HANDLE");
  116. case SQL_NO_DATA: return NANODBC_UNICODE("SQL_NO_DATA");
  117. case SQL_NEED_DATA: return NANODBC_UNICODE("SQL_NEED_DATA");
  118. case SQL_STILL_EXECUTING: return NANODBC_UNICODE("SQL_STILL_EXECUTING");
  119. }
  120. assert(0);
  121. return "unknown"; // should never make it here
  122. }
  123. #endif
  124. // Easy way to check if a return code signifies success.
  125. inline bool success(RETCODE rc)
  126. {
  127. #ifdef NANODBC_ODBC_API_DEBUG
  128. std::cerr << "<-- rc: " << return_code(rc) << " | ";
  129. #endif
  130. return rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO;
  131. }
  132. // Returns the array size.
  133. template<typename T, std::size_t N>
  134. inline std::size_t arrlen(T(&)[N])
  135. {
  136. return N;
  137. }
  138. // Operates like strlen() on a character array.
  139. template<typename T, std::size_t N>
  140. inline std::size_t strarrlen(T(&a)[N])
  141. {
  142. const T* s = &a[0];
  143. std::size_t i = 0;
  144. while(*s++ && i < N) i++;
  145. return i;
  146. }
  147. inline void convert(const std::wstring& in, std::string& out)
  148. {
  149. std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
  150. out = conv.to_bytes(in);
  151. }
  152. #ifdef NANODBC_USE_UNICODE
  153. inline void convert(const std::string& in, std::wstring& out)
  154. {
  155. std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
  156. out = conv.from_bytes(in);
  157. }
  158. inline void convert(const std::wstring& in, std::wstring & out)
  159. {
  160. out = in;
  161. }
  162. #else
  163. inline void convert(const std::string& in, std::string& out)
  164. {
  165. out = in;
  166. }
  167. #endif
  168. // Attempts to get the most recent ODBC error as a string.
  169. // Always returns std::string, even in unicode mode.
  170. inline std::string recent_error(SQLHANDLE handle, SQLSMALLINT handle_type)
  171. {
  172. nanodbc::string_type result;
  173. std::string rvalue;
  174. std::vector<NANODBC_SQLCHAR> sql_message(SQL_MAX_MESSAGE_LENGTH);
  175. sql_message[0] = '\0';
  176. SQLINTEGER i = 1;
  177. SQLINTEGER native_error = 0;
  178. SQLSMALLINT total_bytes;
  179. NANODBC_SQLCHAR sql_state[6];
  180. RETCODE rc;
  181. do
  182. {
  183. NANODBC_CALL_RC(
  184. NANODBC_UNICODE(SQLGetDiagRec)
  185. , rc
  186. , handle_type
  187. , handle
  188. , i
  189. , sql_state
  190. , &native_error
  191. , 0
  192. , 0
  193. , &total_bytes);
  194. if(success(rc) && total_bytes > 0)
  195. sql_message.resize(total_bytes + 1);
  196. NANODBC_CALL_RC(
  197. NANODBC_UNICODE(SQLGetDiagRec)
  198. , rc
  199. , handle_type
  200. , handle
  201. , i
  202. , sql_state
  203. , &native_error
  204. , sql_message.data()
  205. , (SQLSMALLINT)sql_message.size()
  206. , &total_bytes);
  207. if(!success(rc))
  208. {
  209. convert(result, rvalue);
  210. return rvalue;
  211. }
  212. if(!result.empty())
  213. result += ' ';
  214. result += nanodbc::string_type(sql_message.begin(), sql_message.end());
  215. i++;
  216. } while(rc != SQL_NO_DATA);
  217. convert(result, rvalue);
  218. std::string status(&sql_state[0], &sql_state[arrlen(sql_state)]);
  219. status += ": ";
  220. status += rvalue;
  221. // some drivers insert \0 into error messages for unknown reasons
  222. using std::replace;
  223. replace(status.begin(), status.end(), '\0', ' ');
  224. return status;
  225. }
  226. } // namespace
  227. namespace nanodbc
  228. {
  229. type_incompatible_error::type_incompatible_error()
  230. : std::runtime_error("type incompatible") { }
  231. const char* type_incompatible_error::what() const noexcept
  232. {
  233. return std::runtime_error::what();
  234. }
  235. null_access_error::null_access_error()
  236. : std::runtime_error("null access") { }
  237. const char* null_access_error::what() const noexcept
  238. {
  239. return std::runtime_error::what();
  240. }
  241. index_range_error::index_range_error()
  242. : std::runtime_error("index out of range") { }
  243. const char* index_range_error::what() const noexcept
  244. {
  245. return std::runtime_error::what();
  246. }
  247. programming_error::programming_error(const std::string& info)
  248. : std::runtime_error(info.c_str()) { }
  249. const char* programming_error::what() const noexcept
  250. {
  251. return std::runtime_error::what();
  252. }
  253. database_error::database_error(void* handle, short handle_type, const std::string& info)
  254. : std::runtime_error(info + recent_error(handle, handle_type)) { }
  255. const char* database_error::what() const noexcept
  256. {
  257. return std::runtime_error::what();
  258. }
  259. } // namespace nanodbc
  260. // Throwing exceptions using NANODBC_THROW_DATABASE_ERROR enables file name
  261. // and line numbers to be inserted into the error message. Useful for debugging.
  262. #define NANODBC_THROW_DATABASE_ERROR(handle, handle_type) \
  263. throw nanodbc::database_error( \
  264. handle \
  265. , handle_type \
  266. , __FILE__ ":" NANODBC_STRINGIZE(__LINE__) ": ") \
  267. /**/
  268. ///////////////////////////////////////////////////////////////////////////////////////////////////
  269. // Implementation Details
  270. ///////////////////////////////////////////////////////////////////////////////////////////////////
  271. namespace
  272. {
  273. using namespace std; // if int64_t is in std namespace (in c++11)
  274. // A utility for calculating the ctype from the given type T.
  275. // I essentially create a lookup table based on the MSDN ODBC documentation.
  276. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms714556(v=vs.85).aspx
  277. template<class T>
  278. struct sql_ctype { };
  279. template<>
  280. struct sql_ctype<nanodbc::string_type::value_type>
  281. {
  282. #ifdef NANODBC_USE_UNICODE
  283. static const SQLSMALLINT value = SQL_C_WCHAR;
  284. #else
  285. static const SQLSMALLINT value = SQL_C_CHAR;
  286. #endif
  287. };
  288. template<>
  289. struct sql_ctype<short>
  290. {
  291. static const SQLSMALLINT value = SQL_C_SSHORT;
  292. };
  293. template<>
  294. struct sql_ctype<unsigned short>
  295. {
  296. static const SQLSMALLINT value = SQL_C_USHORT;
  297. };
  298. template<>
  299. struct sql_ctype<int32_t>
  300. {
  301. static const SQLSMALLINT value = SQL_C_SLONG;
  302. };
  303. template<>
  304. struct sql_ctype<uint32_t>
  305. {
  306. static const SQLSMALLINT value = SQL_C_ULONG;
  307. };
  308. template<>
  309. struct sql_ctype<int64_t>
  310. {
  311. static const SQLSMALLINT value = SQL_C_SBIGINT;
  312. };
  313. template<>
  314. struct sql_ctype<uint64_t>
  315. {
  316. static const SQLSMALLINT value = SQL_C_UBIGINT;
  317. };
  318. template<>
  319. struct sql_ctype<float>
  320. {
  321. static const SQLSMALLINT value = SQL_C_FLOAT;
  322. };
  323. template<>
  324. struct sql_ctype<double>
  325. {
  326. static const SQLSMALLINT value = SQL_C_DOUBLE;
  327. };
  328. template<>
  329. struct sql_ctype<nanodbc::string_type>
  330. {
  331. #ifdef NANODBC_USE_UNICODE
  332. static const SQLSMALLINT value = SQL_C_WCHAR;
  333. #else
  334. static const SQLSMALLINT value = SQL_C_CHAR;
  335. #endif
  336. };
  337. template<>
  338. struct sql_ctype<nanodbc::date>
  339. {
  340. static const SQLSMALLINT value = SQL_C_DATE;
  341. };
  342. template<>
  343. struct sql_ctype<nanodbc::timestamp>
  344. {
  345. static const SQLSMALLINT value = SQL_C_TIMESTAMP;
  346. };
  347. // Encapsulates resources needed for column binding.
  348. class bound_column
  349. {
  350. public:
  351. bound_column(const bound_column& rhs) =delete;
  352. bound_column& operator=(bound_column rhs) =delete;
  353. bound_column()
  354. : name_()
  355. , column_(0)
  356. , sqltype_(0)
  357. , sqlsize_(0)
  358. , scale_(0)
  359. , ctype_(0)
  360. , clen_(0)
  361. , blob_(false)
  362. , rowset_size_(0)
  363. , cbdata_(0)
  364. , pdata_(0)
  365. {
  366. }
  367. ~bound_column()
  368. {
  369. delete[] cbdata_;
  370. delete[] pdata_;
  371. }
  372. public:
  373. nanodbc::string_type name_;
  374. short column_;
  375. SQLSMALLINT sqltype_;
  376. SQLULEN sqlsize_;
  377. SQLSMALLINT scale_;
  378. SQLSMALLINT ctype_;
  379. SQLULEN clen_;
  380. bool blob_;
  381. long rowset_size_;
  382. nanodbc::null_type* cbdata_;
  383. char* pdata_;
  384. };
  385. // Allocates the native ODBC handles.
  386. inline void allocate_handle(SQLHENV& env, SQLHDBC& conn)
  387. {
  388. RETCODE rc;
  389. NANODBC_CALL_RC(
  390. SQLAllocHandle
  391. , rc
  392. , SQL_HANDLE_ENV
  393. , SQL_NULL_HANDLE
  394. , &env);
  395. if(!success(rc))
  396. NANODBC_THROW_DATABASE_ERROR(env, SQL_HANDLE_ENV);
  397. try
  398. {
  399. NANODBC_CALL_RC(
  400. SQLSetEnvAttr
  401. , rc
  402. , env
  403. , SQL_ATTR_ODBC_VERSION
  404. , (SQLPOINTER)SQL_OV_ODBC3
  405. , SQL_IS_UINTEGER);
  406. if(!success(rc))
  407. NANODBC_THROW_DATABASE_ERROR(env, SQL_HANDLE_ENV);
  408. NANODBC_CALL_RC(
  409. SQLAllocHandle
  410. , rc
  411. , SQL_HANDLE_DBC
  412. , env
  413. , &conn);
  414. if(!success(rc))
  415. NANODBC_THROW_DATABASE_ERROR(env, SQL_HANDLE_ENV);
  416. }
  417. catch(...)
  418. {
  419. NANODBC_CALL(
  420. SQLFreeHandle
  421. , SQL_HANDLE_ENV
  422. , env);
  423. throw;
  424. }
  425. }
  426. } // namespace
  427. ///////////////////////////////////////////////////////////////////////////////////////////////////
  428. // Private Implementation: connection
  429. ///////////////////////////////////////////////////////////////////////////////////////////////////
  430. namespace nanodbc
  431. {
  432. class connection::connection_impl
  433. {
  434. public:
  435. connection_impl(const connection_impl&) =delete;
  436. connection_impl& operator=(const connection_impl&) =delete;
  437. connection_impl()
  438. : env_(0)
  439. , conn_(0)
  440. , connected_(false)
  441. , transactions_(0)
  442. , rollback_(false)
  443. {
  444. allocate_handle(env_, conn_);
  445. }
  446. connection_impl(
  447. const string_type& dsn
  448. , const string_type& user
  449. , const string_type& pass
  450. , long timeout)
  451. : env_(0)
  452. , conn_(0)
  453. , connected_(false)
  454. , transactions_(0)
  455. , rollback_(false)
  456. {
  457. allocate_handle(env_, conn_);
  458. try
  459. {
  460. connect(dsn, user, pass, timeout);
  461. }
  462. catch(...)
  463. {
  464. NANODBC_CALL(
  465. SQLFreeHandle
  466. , SQL_HANDLE_DBC
  467. , conn_);
  468. NANODBC_CALL(
  469. SQLFreeHandle
  470. , SQL_HANDLE_ENV
  471. , env_);
  472. throw;
  473. }
  474. }
  475. connection_impl(const string_type& connection_string, long timeout)
  476. : env_(0)
  477. , conn_(0)
  478. , connected_(false)
  479. , transactions_(0)
  480. , rollback_(false)
  481. {
  482. allocate_handle(env_, conn_);
  483. try
  484. {
  485. connect(connection_string, timeout);
  486. }
  487. catch(...)
  488. {
  489. NANODBC_CALL(
  490. SQLFreeHandle
  491. , SQL_HANDLE_DBC
  492. , conn_);
  493. NANODBC_CALL(
  494. SQLFreeHandle
  495. , SQL_HANDLE_ENV
  496. , env_);
  497. throw;
  498. }
  499. }
  500. ~connection_impl() noexcept
  501. {
  502. try
  503. {
  504. disconnect();
  505. }
  506. catch(...)
  507. {
  508. // ignore exceptions thrown during disconnect
  509. }
  510. NANODBC_CALL(
  511. SQLFreeHandle
  512. , SQL_HANDLE_DBC
  513. , conn_);
  514. NANODBC_CALL(
  515. SQLFreeHandle
  516. , SQL_HANDLE_ENV
  517. , env_);
  518. }
  519. void connect(
  520. const string_type& dsn
  521. , const string_type& user
  522. , const string_type& pass
  523. , long timeout)
  524. {
  525. disconnect();
  526. RETCODE rc;
  527. NANODBC_CALL_RC(
  528. SQLFreeHandle
  529. , rc
  530. , SQL_HANDLE_DBC
  531. , conn_);
  532. if(!success(rc))
  533. NANODBC_THROW_DATABASE_ERROR(conn_, SQL_HANDLE_DBC);
  534. NANODBC_CALL_RC(
  535. SQLAllocHandle
  536. , rc
  537. , SQL_HANDLE_DBC
  538. , env_
  539. , &conn_);
  540. if(!success(rc))
  541. NANODBC_THROW_DATABASE_ERROR(env_, SQL_HANDLE_ENV);
  542. NANODBC_CALL_RC(
  543. SQLSetConnectAttr
  544. , rc
  545. , conn_
  546. , SQL_LOGIN_TIMEOUT
  547. , (SQLPOINTER)timeout
  548. , 0);
  549. if(!success(rc))
  550. NANODBC_THROW_DATABASE_ERROR(conn_, SQL_HANDLE_DBC);
  551. NANODBC_CALL_RC(
  552. NANODBC_UNICODE(SQLConnect)
  553. , rc
  554. , conn_
  555. , (NANODBC_SQLCHAR*)dsn.c_str(), SQL_NTS
  556. , !user.empty() ? (NANODBC_SQLCHAR*)user.c_str() : 0, SQL_NTS
  557. , !pass.empty() ? (NANODBC_SQLCHAR*)pass.c_str() : 0, SQL_NTS);
  558. if(!success(rc))
  559. NANODBC_THROW_DATABASE_ERROR(conn_, SQL_HANDLE_DBC);
  560. connected_ = success(rc);
  561. }
  562. void connect(const string_type& connection_string, long timeout)
  563. {
  564. disconnect();
  565. RETCODE rc;
  566. NANODBC_CALL_RC(
  567. SQLFreeHandle
  568. , rc
  569. , SQL_HANDLE_DBC
  570. , conn_);
  571. if(!success(rc))
  572. NANODBC_THROW_DATABASE_ERROR(conn_, SQL_HANDLE_DBC);
  573. NANODBC_CALL_RC(
  574. SQLAllocHandle
  575. , rc
  576. , SQL_HANDLE_DBC
  577. , env_
  578. , &conn_);
  579. if(!success(rc))
  580. NANODBC_THROW_DATABASE_ERROR(env_, SQL_HANDLE_ENV);
  581. NANODBC_CALL_RC(
  582. SQLSetConnectAttr
  583. , rc
  584. , conn_
  585. , SQL_LOGIN_TIMEOUT
  586. , (SQLPOINTER)timeout
  587. , 0);
  588. if(!success(rc))
  589. NANODBC_THROW_DATABASE_ERROR(conn_, SQL_HANDLE_DBC);
  590. NANODBC_SQLCHAR dsn[1024];
  591. SQLSMALLINT dsn_size = 0;
  592. NANODBC_CALL_RC(
  593. NANODBC_UNICODE(SQLDriverConnect)
  594. , rc
  595. , conn_
  596. , 0
  597. , (NANODBC_SQLCHAR*)connection_string.c_str(), SQL_NTS
  598. , dsn
  599. , sizeof(dsn) / sizeof(NANODBC_SQLCHAR)
  600. , &dsn_size
  601. , SQL_DRIVER_NOPROMPT);
  602. if(!success(rc))
  603. NANODBC_THROW_DATABASE_ERROR(conn_, SQL_HANDLE_DBC);
  604. connected_ = success(rc);
  605. }
  606. bool connected() const
  607. {
  608. return connected_;
  609. }
  610. void disconnect()
  611. {
  612. if(connected())
  613. {
  614. RETCODE rc;
  615. NANODBC_CALL_RC(
  616. SQLDisconnect
  617. , rc
  618. , conn_);
  619. if(!success(rc))
  620. NANODBC_THROW_DATABASE_ERROR(conn_, SQL_HANDLE_DBC);
  621. }
  622. connected_ = false;
  623. }
  624. std::size_t transactions() const
  625. {
  626. return transactions_;
  627. }
  628. void* native_dbc_handle() const
  629. {
  630. return conn_;
  631. }
  632. void* native_env_handle() const
  633. {
  634. return env_;
  635. }
  636. string_type driver_name() const
  637. {
  638. NANODBC_SQLCHAR name[1024];
  639. SQLSMALLINT length;
  640. RETCODE rc;
  641. NANODBC_CALL_RC(
  642. NANODBC_UNICODE(SQLGetInfo)
  643. , rc
  644. , conn_
  645. , SQL_DRIVER_NAME
  646. , name
  647. , sizeof(name) / sizeof(NANODBC_SQLCHAR)
  648. , &length);
  649. if(!success(rc))
  650. NANODBC_THROW_DATABASE_ERROR(conn_, SQL_HANDLE_DBC);
  651. return string_type(&name[0], &name[strarrlen(name)]);
  652. }
  653. std::size_t ref_transaction()
  654. {
  655. return --transactions_;
  656. }
  657. std::size_t unref_transaction()
  658. {
  659. return ++transactions_;
  660. }
  661. bool rollback() const
  662. {
  663. return rollback_;
  664. }
  665. void rollback(bool onoff)
  666. {
  667. rollback_ = onoff;
  668. }
  669. private:
  670. HENV env_;
  671. HDBC conn_;
  672. bool connected_;
  673. std::size_t transactions_;
  674. bool rollback_; // if true, this connection is marked for eventual transaction rollback
  675. };
  676. } // namespace nanodbc
  677. ///////////////////////////////////////////////////////////////////////////////////////////////////
  678. // Private Implementation: transaction
  679. ///////////////////////////////////////////////////////////////////////////////////////////////////
  680. namespace nanodbc
  681. {
  682. class transaction::transaction_impl
  683. {
  684. public:
  685. transaction_impl(const transaction_impl&) =delete;
  686. transaction_impl& operator=(const transaction_impl&) =delete;
  687. transaction_impl(const class connection& conn)
  688. : conn_(conn)
  689. , committed_(false)
  690. {
  691. if(conn_.transactions() == 0 && conn_.connected())
  692. {
  693. RETCODE rc;
  694. NANODBC_CALL_RC(
  695. SQLSetConnectAttr
  696. , rc
  697. , conn_.native_dbc_handle()
  698. , SQL_ATTR_AUTOCOMMIT
  699. , (SQLPOINTER)SQL_AUTOCOMMIT_OFF
  700. , SQL_IS_UINTEGER);
  701. if(!success(rc))
  702. NANODBC_THROW_DATABASE_ERROR(conn_.native_dbc_handle(), SQL_HANDLE_DBC);
  703. }
  704. conn_.ref_transaction();
  705. }
  706. ~transaction_impl() noexcept
  707. {
  708. if(!committed_)
  709. {
  710. conn_.rollback(true);
  711. conn_.unref_transaction();
  712. }
  713. if(conn_.transactions() == 0 && conn_.connected())
  714. {
  715. if(conn_.rollback())
  716. {
  717. NANODBC_CALL(
  718. SQLEndTran
  719. , SQL_HANDLE_DBC
  720. , conn_.native_dbc_handle()
  721. , SQL_ROLLBACK);
  722. conn_.rollback(false);
  723. }
  724. NANODBC_CALL(
  725. SQLSetConnectAttr
  726. , conn_.native_dbc_handle()
  727. , SQL_ATTR_AUTOCOMMIT
  728. , (SQLPOINTER)SQL_AUTOCOMMIT_ON
  729. , SQL_IS_UINTEGER);
  730. }
  731. }
  732. void commit()
  733. {
  734. if(committed_)
  735. return;
  736. committed_ = true;
  737. if(conn_.unref_transaction() == 0 && conn_.connected())
  738. {
  739. RETCODE rc;
  740. NANODBC_CALL_RC(
  741. SQLEndTran
  742. , rc
  743. , SQL_HANDLE_DBC
  744. , conn_.native_dbc_handle()
  745. , SQL_COMMIT);
  746. if(!success(rc))
  747. NANODBC_THROW_DATABASE_ERROR(conn_.native_dbc_handle(), SQL_HANDLE_DBC);
  748. }
  749. }
  750. void rollback() noexcept
  751. {
  752. if(committed_)
  753. return;
  754. conn_.rollback(true);
  755. }
  756. class connection& connection()
  757. {
  758. return conn_;
  759. }
  760. const class connection& connection() const
  761. {
  762. return conn_;
  763. }
  764. private:
  765. class connection conn_;
  766. bool committed_;
  767. };
  768. } // namespace nanodbc
  769. ///////////////////////////////////////////////////////////////////////////////////////////////////
  770. // Private Implementation: statement
  771. ///////////////////////////////////////////////////////////////////////////////////////////////////
  772. namespace nanodbc
  773. {
  774. class statement::statement_impl
  775. {
  776. public:
  777. statement_impl(const statement_impl&) =delete;
  778. statement_impl& operator=(const statement_impl&) =delete;
  779. statement_impl()
  780. : stmt_(0)
  781. , open_(false)
  782. , conn_()
  783. , bind_len_or_null_()
  784. {
  785. }
  786. statement_impl(class connection& conn)
  787. : stmt_(0)
  788. , open_(false)
  789. , conn_()
  790. , bind_len_or_null_()
  791. {
  792. open(conn);
  793. }
  794. statement_impl(class connection& conn, const string_type& query, long timeout)
  795. : stmt_(0)
  796. , open_(false)
  797. , conn_()
  798. , bind_len_or_null_()
  799. {
  800. prepare(conn, query, timeout);
  801. }
  802. ~statement_impl() noexcept
  803. {
  804. if(open() && connected())
  805. {
  806. NANODBC_CALL(
  807. SQLCancel
  808. , stmt_);
  809. reset_parameters();
  810. NANODBC_CALL(
  811. SQLFreeHandle
  812. , SQL_HANDLE_STMT
  813. , stmt_);
  814. }
  815. }
  816. void open(class connection& conn)
  817. {
  818. close();
  819. RETCODE rc;
  820. NANODBC_CALL_RC(
  821. SQLAllocHandle
  822. , rc
  823. , SQL_HANDLE_STMT
  824. , conn.native_dbc_handle()
  825. , &stmt_);
  826. open_ = success(rc);
  827. if(!open_)
  828. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  829. conn_ = conn;
  830. }
  831. bool open() const
  832. {
  833. return open_;
  834. }
  835. bool connected() const
  836. {
  837. return conn_.connected();
  838. }
  839. const class connection& connection() const
  840. {
  841. return conn_;
  842. }
  843. class connection& connection()
  844. {
  845. return conn_;
  846. }
  847. void* native_statement_handle() const
  848. {
  849. return stmt_;
  850. }
  851. void close()
  852. {
  853. if(open() && connected())
  854. {
  855. RETCODE rc;
  856. NANODBC_CALL_RC(
  857. SQLCancel
  858. , rc
  859. , stmt_);
  860. if(!success(rc))
  861. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  862. reset_parameters();
  863. NANODBC_CALL_RC(
  864. SQLFreeHandle
  865. , rc
  866. , SQL_HANDLE_STMT
  867. , stmt_);
  868. if(!success(rc))
  869. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  870. }
  871. open_ = false;
  872. stmt_ = 0;
  873. }
  874. void cancel()
  875. {
  876. RETCODE rc;
  877. NANODBC_CALL_RC(
  878. SQLCancel
  879. , rc
  880. , stmt_);
  881. if(!success(rc))
  882. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  883. }
  884. void prepare(class connection& conn, const string_type& query, long timeout)
  885. {
  886. open(conn);
  887. prepare(query, timeout);
  888. }
  889. void prepare(const string_type& query, long timeout)
  890. {
  891. if(!open())
  892. throw programming_error("statement has no associated open connection");
  893. RETCODE rc;
  894. NANODBC_CALL_RC(
  895. NANODBC_UNICODE(SQLPrepare)
  896. , rc
  897. , stmt_
  898. , (NANODBC_SQLCHAR*)query.c_str()
  899. , (SQLINTEGER)query.size());
  900. if(!success(rc))
  901. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  902. this->timeout(timeout);
  903. }
  904. void timeout(long timeout)
  905. {
  906. RETCODE rc;
  907. NANODBC_CALL_RC(
  908. SQLSetStmtAttr
  909. , rc
  910. , stmt_
  911. , SQL_ATTR_QUERY_TIMEOUT
  912. , (SQLPOINTER)timeout,
  913. 0);
  914. // some drivers don't support timeout for statements,
  915. // so only raise the error if a non-default timeout was requested.
  916. if(!success(rc) && (timeout != 0))
  917. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  918. }
  919. result execute_direct(
  920. class connection& conn
  921. , const string_type& query
  922. , long batch_operations
  923. , long timeout
  924. , statement& statement)
  925. {
  926. #ifdef NANODBC_HANDLE_NODATA_BUG
  927. const RETCODE rc = just_execute_direct(conn, query, batch_operations, timeout, statement);
  928. if(rc == SQL_NO_DATA)
  929. return result();
  930. #else
  931. just_execute_direct(conn, query, batch_operations, timeout, statement);
  932. #endif
  933. return result(statement, batch_operations);
  934. }
  935. RETCODE just_execute_direct(
  936. class connection& conn
  937. , const string_type& query
  938. , long batch_operations
  939. , long timeout
  940. , statement& statement)
  941. {
  942. open(conn);
  943. RETCODE rc;
  944. NANODBC_CALL_RC(
  945. SQLSetStmtAttr
  946. , rc
  947. , stmt_
  948. , SQL_ATTR_PARAMSET_SIZE
  949. , (SQLPOINTER)batch_operations
  950. , 0);
  951. if(!success(rc))
  952. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  953. this->timeout(timeout);
  954. NANODBC_CALL_RC(
  955. NANODBC_UNICODE(SQLExecDirect)
  956. , rc
  957. , stmt_
  958. , (NANODBC_SQLCHAR*)query.c_str()
  959. , SQL_NTS);
  960. if(!success(rc) && rc != SQL_NO_DATA)
  961. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  962. return rc;
  963. }
  964. result execute(long batch_operations, long timeout, statement& statement)
  965. {
  966. #ifdef NANODBC_HANDLE_NODATA_BUG
  967. const RETCODE rc = just_execute(batch_operations, timeout, statement);
  968. if(rc == SQL_NO_DATA)
  969. return result();
  970. #else
  971. just_execute(batch_operations, timeout, statement);
  972. #endif
  973. return result(statement, batch_operations);
  974. }
  975. RETCODE just_execute(long batch_operations, long timeout, statement& statement)
  976. {
  977. RETCODE rc;
  978. if(open())
  979. {
  980. // The ODBC cursor must be closed before subsequent executions, as described
  981. // here http://msdn.microsoft.com/en-us/library/windows/desktop/ms713584%28v=vs.85%29.aspx
  982. //
  983. // However, we don't necessarily want to call SQLCloseCursor() because that
  984. // will cause an invalid cursor state in the case that no cursor is currently open.
  985. // A better solution is to use SQLFreeStmt() with the SQL_CLOSE option, which has
  986. // the same effect without the undesired limitations.
  987. NANODBC_CALL_RC(
  988. SQLFreeStmt
  989. , rc
  990. , stmt_
  991. , SQL_CLOSE);
  992. if(!success(rc))
  993. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  994. }
  995. NANODBC_CALL_RC(
  996. SQLSetStmtAttr
  997. , rc
  998. , stmt_
  999. , SQL_ATTR_PARAMSET_SIZE
  1000. , (SQLPOINTER)batch_operations
  1001. , 0);
  1002. if(!success(rc) && rc != SQL_NO_DATA)
  1003. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1004. this->timeout(timeout);
  1005. NANODBC_CALL_RC(
  1006. SQLExecute
  1007. , rc
  1008. , stmt_);
  1009. if(!success(rc) && rc != SQL_NO_DATA)
  1010. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1011. return rc;
  1012. }
  1013. result procedure_columns(
  1014. const string_type& catalog
  1015. , const string_type& schema
  1016. , const string_type& procedure
  1017. , const string_type& column
  1018. , statement& statement)
  1019. {
  1020. if(!open())
  1021. throw programming_error("statement has no associated open connection");
  1022. RETCODE rc;
  1023. NANODBC_CALL_RC(
  1024. NANODBC_UNICODE(SQLProcedureColumns)
  1025. , rc
  1026. , stmt_
  1027. , (NANODBC_SQLCHAR*)(catalog.empty() ? NULL : catalog.c_str())
  1028. , (catalog.empty() ? 0 : SQL_NTS)
  1029. , (NANODBC_SQLCHAR*)(schema.empty() ? NULL : schema.c_str())
  1030. , (schema.empty() ? 0 : SQL_NTS)
  1031. , (NANODBC_SQLCHAR*)procedure.c_str()
  1032. , SQL_NTS
  1033. , (NANODBC_SQLCHAR*)(column.empty() ? NULL : column.c_str())
  1034. , (column.empty() ? 0 : SQL_NTS));
  1035. if (!success(rc))
  1036. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1037. return result(statement, 1);
  1038. }
  1039. long affected_rows() const
  1040. {
  1041. SQLLEN rows;
  1042. RETCODE rc;
  1043. NANODBC_CALL_RC(
  1044. SQLRowCount
  1045. , rc
  1046. , stmt_
  1047. , &rows);
  1048. if(!success(rc))
  1049. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1050. return rows;
  1051. }
  1052. short columns() const
  1053. {
  1054. SQLSMALLINT cols;
  1055. RETCODE rc;
  1056. NANODBC_CALL_RC(
  1057. SQLNumResultCols
  1058. , rc
  1059. , stmt_
  1060. , &cols);
  1061. if(!success(rc))
  1062. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1063. return cols;
  1064. }
  1065. void reset_parameters() noexcept
  1066. {
  1067. NANODBC_CALL(
  1068. SQLFreeStmt
  1069. , stmt_
  1070. , SQL_RESET_PARAMS);
  1071. }
  1072. unsigned long parameter_size(short param) const
  1073. {
  1074. RETCODE rc;
  1075. SQLSMALLINT data_type;
  1076. SQLULEN parameter_size;
  1077. NANODBC_CALL_RC(
  1078. SQLDescribeParam
  1079. , rc
  1080. , stmt_
  1081. , param + 1
  1082. , &data_type
  1083. , &parameter_size
  1084. , 0
  1085. , 0);
  1086. if(!success(rc))
  1087. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1088. return parameter_size;
  1089. }
  1090. static SQLSMALLINT param_type_from_direction(param_direction direction)
  1091. {
  1092. switch(direction)
  1093. {
  1094. default:
  1095. assert(false);
  1096. // fallthrough
  1097. case PARAM_IN:
  1098. return SQL_PARAM_INPUT;
  1099. break;
  1100. case PARAM_OUT:
  1101. return SQL_PARAM_OUTPUT;
  1102. break;
  1103. case PARAM_INOUT:
  1104. return SQL_PARAM_INPUT_OUTPUT;
  1105. break;
  1106. case PARAM_RETURN:
  1107. return SQL_PARAM_OUTPUT;
  1108. break;
  1109. }
  1110. // Remove warning C4702 : unreachable code nanodbc.cpp 1284 Nanodbc
  1111. assert(false);
  1112. }
  1113. // initializes bind_len_or_null_ and gets information for bind
  1114. void prepare_bind(
  1115. short param
  1116. , std::size_t elements
  1117. , param_direction direction
  1118. , SQLSMALLINT& data_type
  1119. , SQLSMALLINT& param_type
  1120. , SQLULEN& parameter_size)
  1121. {
  1122. RETCODE rc;
  1123. NANODBC_CALL_RC(
  1124. SQLDescribeParam
  1125. , rc
  1126. , stmt_
  1127. , param + 1
  1128. , &data_type
  1129. , &parameter_size
  1130. , 0
  1131. , 0);
  1132. if(!success(rc))
  1133. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1134. param_type = param_type_from_direction(direction);
  1135. if(!bind_len_or_null_.count(param))
  1136. bind_len_or_null_[param] = std::vector<null_type>();
  1137. std::vector<null_type>().swap(bind_len_or_null_[param]);
  1138. // ODBC weirdness: this must be at least 8 elements in size
  1139. const std::size_t indicator_size = elements > 8 ? elements : 8;
  1140. bind_len_or_null_[param].reserve(indicator_size);
  1141. bind_len_or_null_[param].assign(indicator_size, SQL_NULL_DATA);
  1142. }
  1143. // calls actual ODBC bind parameter function
  1144. template<class T>
  1145. void bind_parameter(
  1146. short param
  1147. , const T* data
  1148. , std::size_t /*elements*/
  1149. , SQLSMALLINT data_type
  1150. , SQLSMALLINT param_type
  1151. , SQLULEN parameter_size)
  1152. {
  1153. RETCODE rc;
  1154. NANODBC_CALL_RC(
  1155. SQLBindParameter
  1156. , rc
  1157. , stmt_ // handle
  1158. , param + 1 // parameter number
  1159. , param_type // input or output type
  1160. , sql_ctype<T>::value // value type
  1161. , data_type // parameter type
  1162. , parameter_size // column size ignored for many types, but needed for strings
  1163. , 0 // decimal digits
  1164. , (SQLPOINTER)data // parameter value
  1165. , parameter_size // buffer length
  1166. , bind_len_or_null_[param].data());
  1167. if(!success(rc))
  1168. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1169. }
  1170. // handles a single value (possibly a single string value), or multiple non-string values
  1171. template<class T>
  1172. void bind(short param, const T* values, std::size_t elements, param_direction direction);
  1173. // handles multiple string values
  1174. void bind_strings(
  1175. short param
  1176. , const string_type::value_type* values
  1177. , std::size_t /*length*/
  1178. , std::size_t elements
  1179. , param_direction direction)
  1180. {
  1181. bind(param, values, elements, direction);
  1182. }
  1183. // handles multiple null values
  1184. void bind_null(short param, std::size_t elements)
  1185. {
  1186. SQLSMALLINT data_type;
  1187. SQLSMALLINT param_type;
  1188. SQLULEN parameter_size;
  1189. prepare_bind(param, elements, PARAM_IN, data_type, param_type, parameter_size);
  1190. RETCODE rc;
  1191. NANODBC_CALL_RC(
  1192. SQLBindParameter
  1193. , rc
  1194. , stmt_
  1195. , param + 1
  1196. , param_type
  1197. , SQL_C_CHAR
  1198. , data_type
  1199. , parameter_size // column size ignored for many types, but needed for strings
  1200. , 0
  1201. , (SQLPOINTER)0 // null value
  1202. , 0 // parameter_size
  1203. , bind_len_or_null_[param].data());
  1204. if(!success(rc))
  1205. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1206. }
  1207. // comparator for null sentry values
  1208. template<class T>
  1209. bool equals(const T& lhs, const T& rhs)
  1210. {
  1211. return lhs == rhs;
  1212. }
  1213. // handles multiple non-string values with a null sentry
  1214. template<class T>
  1215. void bind(
  1216. short param
  1217. , const T* values
  1218. , std::size_t elements
  1219. , const bool* nulls
  1220. , const T* null_sentry
  1221. , param_direction direction);
  1222. // handles multiple string values
  1223. void bind_strings(
  1224. short param
  1225. , const string_type::value_type* values
  1226. , std::size_t length
  1227. , std::size_t elements
  1228. , const bool* nulls
  1229. , const string_type::value_type* null_sentry
  1230. , param_direction direction);
  1231. private:
  1232. HSTMT stmt_;
  1233. bool open_;
  1234. class connection conn_;
  1235. std::map<short, std::vector<null_type> > bind_len_or_null_;
  1236. };
  1237. // Supports code like: query.bind(0, std_string.c_str())
  1238. // In this case, we need to pass NULL to the final parameter of SQLBindParameter().
  1239. template<>
  1240. void statement::statement_impl::bind_parameter<string_type::value_type>(
  1241. short param
  1242. , const string_type::value_type* data
  1243. , std::size_t elements
  1244. , SQLSMALLINT data_type
  1245. , SQLSMALLINT param_type
  1246. , SQLULEN parameter_size)
  1247. {
  1248. RETCODE rc;
  1249. NANODBC_CALL_RC(
  1250. SQLBindParameter
  1251. , rc
  1252. , stmt_ // handle
  1253. , param + 1 // parameter number
  1254. , param_type // input or output type
  1255. , sql_ctype<string_type::value_type>::value // value type
  1256. , data_type // parameter type
  1257. , parameter_size // column size ignored for many types, but needed for strings
  1258. , 0 // decimal digits
  1259. , (SQLPOINTER)data // parameter value
  1260. , parameter_size // buffer length
  1261. , (elements <= 1 ? NULL : bind_len_or_null_[param].data()));
  1262. if(!success(rc))
  1263. NANODBC_THROW_DATABASE_ERROR(stmt_, SQL_HANDLE_STMT);
  1264. }
  1265. template<class T>
  1266. void statement::statement_impl::bind(
  1267. short param
  1268. , const T* values
  1269. , std::size_t elements
  1270. , param_direction direction)
  1271. {
  1272. SQLSMALLINT data_type;
  1273. SQLSMALLINT param_type;
  1274. SQLULEN parameter_size;
  1275. prepare_bind(param, elements, direction, data_type, param_type, parameter_size);
  1276. for(std::size_t i = 0; i < elements; ++i)
  1277. bind_len_or_null_[param][i] = parameter_size;
  1278. bind_parameter(param, values, elements, data_type, param_type, parameter_size);
  1279. }
  1280. template<class T>
  1281. void statement::statement_impl::bind(
  1282. short param
  1283. , const T* values
  1284. , std::size_t elements
  1285. , const bool* nulls
  1286. , const T* null_sentry
  1287. , param_direction direction)
  1288. {
  1289. SQLSMALLINT data_type;
  1290. SQLSMALLINT param_type;
  1291. SQLULEN parameter_size;
  1292. prepare_bind(param, elements, direction, data_type, param_type, parameter_size);
  1293. for(std::size_t i = 0; i < elements; ++i)
  1294. if((null_sentry && !equals(values[i], *null_sentry)) || (nulls && !nulls[i]))
  1295. bind_len_or_null_[param][i] = parameter_size;
  1296. bind_parameter(param, values, elements, data_type, param_type, parameter_size);
  1297. }
  1298. void statement::statement_impl::bind_strings(
  1299. short param
  1300. , const string_type::value_type* values
  1301. , std::size_t length
  1302. , std::size_t elements
  1303. , const bool* nulls
  1304. , const string_type::value_type* null_sentry
  1305. , param_direction direction)
  1306. {
  1307. SQLSMALLINT data_type;
  1308. SQLSMALLINT param_type;
  1309. SQLULEN parameter_size;
  1310. prepare_bind(param, elements, direction, data_type, param_type, parameter_size);
  1311. if(null_sentry)
  1312. {
  1313. const string_type rhs(null_sentry);
  1314. for(std::size_t i = 0; i < elements; ++i)
  1315. {
  1316. const string_type lhs(values + i * length, values + (i + 1) * length);
  1317. if(NANADBC_STRNCMP(lhs.c_str(), rhs.c_str(), length))
  1318. bind_len_or_null_[param][i] = parameter_size;
  1319. }
  1320. }
  1321. else if(nulls)
  1322. {
  1323. for(std::size_t i = 0; i < elements; ++i)
  1324. {
  1325. if(!nulls[i])
  1326. bind_len_or_null_[param][i] = SQL_NTS; // null terminated
  1327. }
  1328. }
  1329. bind_parameter(param, values, elements, data_type, param_type, parameter_size);
  1330. }
  1331. template<>
  1332. bool statement::statement_impl::equals(const date& lhs, const date& rhs)
  1333. {
  1334. return lhs.year == rhs.year
  1335. && lhs.month == rhs.month
  1336. && lhs.day == rhs.day;
  1337. }
  1338. template<>
  1339. bool statement::statement_impl::equals(const timestamp& lhs, const timestamp& rhs)
  1340. {
  1341. return lhs.year == rhs.year
  1342. && lhs.month == rhs.month
  1343. && lhs.day == rhs.day
  1344. && lhs.hour == rhs.hour
  1345. && lhs.min == rhs.min
  1346. && lhs.sec == rhs.sec
  1347. && lhs.fract == rhs.fract;
  1348. }
  1349. } // namespace nanodbc
  1350. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1351. // Private Implementation: result
  1352. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1353. namespace nanodbc
  1354. {
  1355. class result::result_impl
  1356. {
  1357. public:
  1358. result_impl(const result_impl&) =delete;
  1359. result_impl& operator=(const result_impl&) =delete;
  1360. result_impl(statement stmt, long rowset_size)
  1361. : stmt_(stmt)
  1362. , rowset_size_(rowset_size)
  1363. , row_count_(0)
  1364. , bound_columns_(0)
  1365. , bound_columns_size_(0)
  1366. , rowset_position_(0)
  1367. , bound_columns_by_name_()
  1368. {
  1369. RETCODE rc;
  1370. NANODBC_CALL_RC(
  1371. SQLSetStmtAttr
  1372. , rc
  1373. , stmt_.native_statement_handle()
  1374. , SQL_ATTR_ROW_ARRAY_SIZE
  1375. , (SQLPOINTER)rowset_size_
  1376. , 0);
  1377. if(!success(rc))
  1378. NANODBC_THROW_DATABASE_ERROR(stmt_.native_statement_handle(), SQL_HANDLE_STMT);
  1379. NANODBC_CALL_RC(
  1380. SQLSetStmtAttr
  1381. , rc
  1382. , stmt_.native_statement_handle()
  1383. , SQL_ATTR_ROWS_FETCHED_PTR
  1384. , &row_count_
  1385. , 0);
  1386. if(!success(rc))
  1387. NANODBC_THROW_DATABASE_ERROR(stmt_.native_statement_handle(), SQL_HANDLE_STMT);
  1388. auto_bind();
  1389. }
  1390. ~result_impl() noexcept
  1391. {
  1392. cleanup_bound_columns();
  1393. }
  1394. void* native_statement_handle() const
  1395. {
  1396. return stmt_.native_statement_handle();
  1397. }
  1398. long rowset_size() const
  1399. {
  1400. return rowset_size_;
  1401. }
  1402. long affected_rows() const
  1403. {
  1404. return stmt_.affected_rows();
  1405. }
  1406. long rows() const noexcept
  1407. {
  1408. return row_count_;
  1409. }
  1410. short columns() const
  1411. {
  1412. return stmt_.columns();
  1413. }
  1414. bool first()
  1415. {
  1416. rowset_position_ = 0;
  1417. return fetch(0, SQL_FETCH_FIRST);
  1418. }
  1419. bool last()
  1420. {
  1421. rowset_position_ = 0;
  1422. return fetch(0, SQL_FETCH_LAST);
  1423. }
  1424. bool next()
  1425. {
  1426. if(rows() && ++rowset_position_ < rowset_size_)
  1427. return rowset_position_ < rows();
  1428. rowset_position_ = 0;
  1429. return fetch(0, SQL_FETCH_NEXT);
  1430. }
  1431. bool prior()
  1432. {
  1433. if(rows() && --rowset_position_ >= 0)
  1434. return true;
  1435. rowset_position_ = 0;
  1436. return fetch(0, SQL_FETCH_PRIOR);
  1437. }
  1438. bool move(long row)
  1439. {
  1440. rowset_position_ = 0;
  1441. return fetch(row, SQL_FETCH_ABSOLUTE);
  1442. }
  1443. bool skip(long rows)
  1444. {
  1445. rowset_position_ += rows;
  1446. if(this->rows() && rowset_position_ < rowset_size_)
  1447. return rowset_position_ < this->rows();
  1448. rowset_position_ = 0;
  1449. return fetch(rows, SQL_FETCH_RELATIVE);
  1450. }
  1451. unsigned long position() const
  1452. {
  1453. SQLULEN pos = 0; // necessary to initialize to 0
  1454. RETCODE rc;
  1455. NANODBC_CALL_RC(
  1456. SQLGetStmtAttr
  1457. , rc
  1458. , stmt_.native_statement_handle()
  1459. , SQL_ATTR_ROW_NUMBER
  1460. , &pos
  1461. , SQL_IS_UINTEGER
  1462. , 0);
  1463. if(!success(rc))
  1464. NANODBC_THROW_DATABASE_ERROR(stmt_.native_statement_handle(), SQL_HANDLE_STMT);
  1465. return pos - 1 + rowset_position_;
  1466. }
  1467. bool end() const noexcept
  1468. {
  1469. SQLULEN pos = 0; // necessary to initialize to 0
  1470. RETCODE rc;
  1471. NANODBC_CALL_RC(
  1472. SQLGetStmtAttr
  1473. , rc
  1474. , stmt_.native_statement_handle()
  1475. , SQL_ATTR_ROW_NUMBER
  1476. , &pos
  1477. , SQL_IS_UINTEGER
  1478. , 0);
  1479. return (!success(rc) || rows() < 0 || pos - 1 > static_cast<unsigned long>(rows()));
  1480. }
  1481. bool is_null(short column) const
  1482. {
  1483. if(column >= bound_columns_size_)
  1484. throw index_range_error();
  1485. bound_column& col = bound_columns_[column];
  1486. if(rowset_position_ >= rows())
  1487. throw index_range_error();
  1488. return col.cbdata_[rowset_position_] == SQL_NULL_DATA;
  1489. }
  1490. bool is_null(const string_type& column_name) const
  1491. {
  1492. const short column = this->column(column_name);
  1493. return is_null(column);
  1494. }
  1495. string_type column_name(short column) const
  1496. {
  1497. if(column >= bound_columns_size_)
  1498. throw index_range_error();
  1499. return bound_columns_[column].name_;
  1500. }
  1501. long column_size(short column) const
  1502. {
  1503. if(column >= bound_columns_size_)
  1504. throw index_range_error();
  1505. bound_column& col = bound_columns_[column];
  1506. return col.sqlsize_;
  1507. }
  1508. short column(const string_type& column_name) const
  1509. {
  1510. typedef std::map<string_type, bound_column*>::const_iterator iter;
  1511. iter i = bound_columns_by_name_.find(column_name);
  1512. if(i == bound_columns_by_name_.end())
  1513. throw index_range_error();
  1514. return i->second->column_;
  1515. }
  1516. int column_datatype(short column) const
  1517. {
  1518. if(column >= bound_columns_size_)
  1519. throw index_range_error();
  1520. bound_column& col = bound_columns_[column];
  1521. return col.sqltype_;
  1522. }
  1523. int column_datatype(const string_type& column_name) const
  1524. {
  1525. const short column = this->column(column_name);
  1526. bound_column& col = bound_columns_[column];
  1527. return col.sqltype_;
  1528. }
  1529. int column_c_datatype(short column) const
  1530. {
  1531. if(column >= bound_columns_size_)
  1532. throw index_range_error();
  1533. bound_column& col = bound_columns_[column];
  1534. return col.ctype_;
  1535. }
  1536. int column_c_datatype(const string_type& column_name) const
  1537. {
  1538. const short column = this->column(column_name);
  1539. bound_column& col = bound_columns_[column];
  1540. return col.ctype_;
  1541. }
  1542. bool next_result()
  1543. {
  1544. RETCODE rc;
  1545. NANODBC_CALL_RC(
  1546. SQLMoreResults
  1547. , rc
  1548. , stmt_.native_statement_handle());
  1549. if(rc == SQL_NO_DATA)
  1550. return false;
  1551. if(!success(rc))
  1552. NANODBC_THROW_DATABASE_ERROR(stmt_.native_statement_handle(), SQL_HANDLE_STMT);
  1553. auto_bind();
  1554. return true;
  1555. }
  1556. template<class T>
  1557. void get_ref(short column, T& result) const
  1558. {
  1559. if(column >= bound_columns_size_)
  1560. throw index_range_error();
  1561. if(is_null(column))
  1562. throw null_access_error();
  1563. get_ref_impl<T>(column, result);
  1564. }
  1565. template<class T>
  1566. void get_ref(short column, const T& fallback, T& result) const
  1567. {
  1568. if(column >= bound_columns_size_)
  1569. throw index_range_error();
  1570. if(is_null(column))
  1571. {
  1572. result = fallback;
  1573. return;
  1574. }
  1575. get_ref_impl<T>(column, result);
  1576. }
  1577. template<class T>
  1578. void get_ref(const string_type& column_name, T& result) const
  1579. {
  1580. const short column = this->column(column_name);
  1581. if(is_null(column))
  1582. throw null_access_error();
  1583. get_ref_impl<T>(column, result);
  1584. }
  1585. template<class T>
  1586. void get_ref(const string_type& column_name, const T& fallback, T& result) const
  1587. {
  1588. const short column = this->column(column_name);
  1589. if(is_null(column))
  1590. {
  1591. result = fallback;
  1592. return;
  1593. }
  1594. get_ref_impl<T>(column, result);
  1595. }
  1596. template<class T>
  1597. T get(short column) const
  1598. {
  1599. T result;
  1600. get_ref(column, result);
  1601. return result;
  1602. }
  1603. template<class T>
  1604. T get(short column, const T& fallback) const
  1605. {
  1606. T result;
  1607. get_ref(column, fallback, result);
  1608. return result;
  1609. }
  1610. template<class T>
  1611. T get(const string_type& column_name) const
  1612. {
  1613. T result;
  1614. get_ref(column_name, result);
  1615. return result;
  1616. }
  1617. template<class T>
  1618. T get(const string_type& column_name, const T& fallback) const
  1619. {
  1620. T result;
  1621. get_ref(column_name, fallback, result);
  1622. return result;
  1623. }
  1624. private:
  1625. template<class T>
  1626. void get_ref_impl(short column, T& result) const;
  1627. void before_move() noexcept
  1628. {
  1629. for(short i = 0; i < bound_columns_size_; ++i)
  1630. {
  1631. bound_column& col = bound_columns_[i];
  1632. for(long j = 0; j < col.rowset_size_; ++j)
  1633. col.cbdata_[j] = 0;
  1634. if(col.blob_ && col.pdata_)
  1635. release_bound_resources(i);
  1636. }
  1637. }
  1638. void release_bound_resources(short column) noexcept
  1639. {
  1640. assert(column < bound_columns_size_);
  1641. bound_column& col = bound_columns_[column];
  1642. delete[] col.pdata_;
  1643. col.pdata_ = 0;
  1644. col.clen_ = 0;
  1645. }
  1646. void cleanup_bound_columns() noexcept
  1647. {
  1648. before_move();
  1649. delete[] bound_columns_;
  1650. bound_columns_ = NULL;
  1651. bound_columns_size_ = 0;
  1652. bound_columns_by_name_.clear();
  1653. }
  1654. bool fetch(long rows, SQLUSMALLINT orientation)
  1655. {
  1656. before_move();
  1657. RETCODE rc;
  1658. NANODBC_CALL_RC(
  1659. SQLFetchScroll
  1660. , rc
  1661. , stmt_.native_statement_handle()
  1662. , orientation
  1663. , rows);
  1664. if(rc == SQL_NO_DATA)
  1665. return false;
  1666. if(!success(rc))
  1667. NANODBC_THROW_DATABASE_ERROR(stmt_.native_statement_handle(), SQL_HANDLE_STMT);
  1668. return true;
  1669. }
  1670. void auto_bind()
  1671. {
  1672. cleanup_bound_columns();
  1673. const short n_columns = columns();
  1674. if(n_columns < 1)
  1675. return;
  1676. assert(!bound_columns_);
  1677. assert(!bound_columns_size_);
  1678. bound_columns_ = new bound_column[n_columns];
  1679. bound_columns_size_ = n_columns;
  1680. RETCODE rc;
  1681. NANODBC_SQLCHAR column_name[1024];
  1682. SQLSMALLINT sqltype, scale, nullable, len;
  1683. SQLULEN sqlsize;
  1684. for(SQLSMALLINT i = 0; i < n_columns; ++i)
  1685. {
  1686. NANODBC_CALL_RC(
  1687. NANODBC_UNICODE(SQLDescribeCol)
  1688. , rc
  1689. , stmt_.native_statement_handle()
  1690. , i + 1
  1691. , (NANODBC_SQLCHAR*)column_name
  1692. , sizeof(column_name)/sizeof(NANODBC_SQLCHAR)
  1693. , &len
  1694. , &sqltype
  1695. , &sqlsize
  1696. , &scale
  1697. , &nullable);
  1698. if(!success(rc))
  1699. NANODBC_THROW_DATABASE_ERROR(stmt_.native_statement_handle(), SQL_HANDLE_STMT);
  1700. // Adjust the sqlsize parameter in case of "unlimited" data (varchar(max), nvarchar(max)).
  1701. bool is_blob = false;
  1702. if (sqlsize == 0)
  1703. {
  1704. switch (sqltype)
  1705. {
  1706. case SQL_VARCHAR:
  1707. case SQL_WVARCHAR:
  1708. {
  1709. //// Divide in half, due to sqlsize being 32-bit in Win32 (and 64-bit in x64)
  1710. //sqlsize = std::numeric_limits<int32_t>::max() / 2 - 1;
  1711. is_blob = true;
  1712. }
  1713. }
  1714. }
  1715. bound_column& col = bound_columns_[i];
  1716. col.name_ = reinterpret_cast<string_type::value_type*>(column_name);
  1717. col.column_ = i;
  1718. col.sqltype_ = sqltype;
  1719. col.sqlsize_ = sqlsize;
  1720. col.scale_ = scale;
  1721. bound_columns_by_name_[col.name_] = &col;
  1722. using namespace std; // if int64_t is in std namespace (in c++11)
  1723. switch(col.sqltype_)
  1724. {
  1725. case SQL_BIT:
  1726. case SQL_TINYINT:
  1727. case SQL_SMALLINT:
  1728. case SQL_INTEGER:
  1729. col.ctype_ = SQL_C_LONG;
  1730. col.clen_ = sizeof(int32_t);
  1731. break;
  1732. case SQL_BIGINT:
  1733. col.ctype_ = SQL_C_SBIGINT;
  1734. col.clen_ = sizeof(int64_t);
  1735. break;
  1736. case SQL_DOUBLE:
  1737. case SQL_FLOAT:
  1738. case SQL_DECIMAL:
  1739. case SQL_REAL:
  1740. case SQL_NUMERIC:
  1741. col.ctype_ = SQL_C_DOUBLE;
  1742. col.clen_ = sizeof(double);
  1743. break;
  1744. case SQL_DATE:
  1745. case SQL_TYPE_DATE:
  1746. col.ctype_ = SQL_C_DATE;
  1747. col.clen_ = sizeof(date);
  1748. break;
  1749. case SQL_TIMESTAMP:
  1750. case SQL_TYPE_TIMESTAMP:
  1751. col.ctype_ = SQL_C_TIMESTAMP;
  1752. col.clen_ = sizeof(timestamp);
  1753. break;
  1754. case SQL_CHAR:
  1755. case SQL_VARCHAR:
  1756. col.ctype_ = SQL_C_CHAR;
  1757. col.clen_ = (col.sqlsize_ + 1) * sizeof(SQLCHAR);
  1758. if (is_blob)
  1759. {
  1760. col.clen_ = 0;
  1761. col.blob_ = true;
  1762. }
  1763. break;
  1764. case SQL_WCHAR:
  1765. case SQL_WVARCHAR:
  1766. col.ctype_ = SQL_C_WCHAR;
  1767. col.clen_ = (col.sqlsize_ + 1) * sizeof(SQLWCHAR);
  1768. if (is_blob)
  1769. {
  1770. col.clen_ = 0;
  1771. col.blob_ = true;
  1772. }
  1773. break;
  1774. case SQL_LONGVARCHAR:
  1775. col.ctype_ = SQL_C_CHAR;
  1776. col.blob_ = true;
  1777. col.clen_ = 0;
  1778. break;
  1779. case SQL_BINARY:
  1780. case SQL_VARBINARY:
  1781. col.ctype_ = SQL_C_BINARY;
  1782. col.clen_ = col.sqlsize_ + sizeof(NANODBC_SQLCHAR);
  1783. break;
  1784. case SQL_LONGVARBINARY:
  1785. col.ctype_ = SQL_C_BINARY;
  1786. col.blob_ = true;
  1787. col.clen_ = 0;
  1788. break;
  1789. default:
  1790. col.ctype_ = sql_ctype<string_type>::value;
  1791. col.clen_ = 128;
  1792. break;
  1793. }
  1794. }
  1795. for(SQLSMALLINT i = 0; i < n_columns; ++i)
  1796. {
  1797. bound_column& col = bound_columns_[i];
  1798. col.cbdata_ = new null_type[rowset_size_];
  1799. if(col.blob_)
  1800. {
  1801. NANODBC_CALL_RC(
  1802. SQLBindCol
  1803. , rc
  1804. , stmt_.native_statement_handle()
  1805. , i + 1
  1806. , col.ctype_
  1807. , 0
  1808. , 0
  1809. , col.cbdata_);
  1810. if(!success(rc))
  1811. NANODBC_THROW_DATABASE_ERROR(stmt_.native_statement_handle(), SQL_HANDLE_STMT);
  1812. }
  1813. else
  1814. {
  1815. col.rowset_size_ = rowset_size_;
  1816. col.pdata_ = new char[rowset_size_ * col.clen_];
  1817. NANODBC_CALL_RC(
  1818. SQLBindCol
  1819. , rc
  1820. , stmt_.native_statement_handle()
  1821. , i + 1 // ColumnNumber
  1822. , col.ctype_ // TargetType
  1823. , col.pdata_ // TargetValuePtr
  1824. , col.clen_ // BufferLength
  1825. , col.cbdata_); // StrLen_or_Ind
  1826. if(!success(rc))
  1827. NANODBC_THROW_DATABASE_ERROR(stmt_.native_statement_handle(), SQL_HANDLE_STMT);
  1828. }
  1829. }
  1830. }
  1831. private:
  1832. statement stmt_;
  1833. const long rowset_size_;
  1834. SQLULEN row_count_;
  1835. bound_column* bound_columns_;
  1836. short bound_columns_size_;
  1837. long rowset_position_;
  1838. std::map<string_type, bound_column*> bound_columns_by_name_;
  1839. };
  1840. template<>
  1841. inline void result::result_impl::get_ref_impl<date>(short column, date& result) const
  1842. {
  1843. bound_column& col = bound_columns_[column];
  1844. switch(col.ctype_)
  1845. {
  1846. case SQL_C_DATE:
  1847. result = *((date*)(col.pdata_ + rowset_position_ * col.clen_));
  1848. return;
  1849. case SQL_C_TIMESTAMP:
  1850. {
  1851. timestamp stamp = *( (timestamp*)( col.pdata_ + rowset_position_ * col.clen_ ) );
  1852. date d = { stamp.year, stamp.month, stamp.day };
  1853. result = d;
  1854. return;
  1855. }
  1856. }
  1857. throw type_incompatible_error();
  1858. }
  1859. template<>
  1860. inline void result::result_impl::get_ref_impl<timestamp>(short column, timestamp& result) const
  1861. {
  1862. bound_column& col = bound_columns_[column];
  1863. switch(col.ctype_)
  1864. {
  1865. case SQL_C_DATE:
  1866. {
  1867. date d = *((date*)(col.pdata_ + rowset_position_ * col.clen_));
  1868. timestamp stamp = { d.year, d.month, d.day, 0, 0, 0, 0 };
  1869. result = stamp;
  1870. return;
  1871. }
  1872. case SQL_C_TIMESTAMP:
  1873. result = *((timestamp*)(col.pdata_ + rowset_position_ * col.clen_));
  1874. return;
  1875. }
  1876. throw type_incompatible_error();
  1877. }
  1878. template<>
  1879. inline void result::result_impl::get_ref_impl<string_type>(short column, string_type& result) const
  1880. {
  1881. const bound_column& col = bound_columns_[column];
  1882. const SQLULEN column_size = col.sqlsize_;
  1883. switch(col.ctype_)
  1884. {
  1885. case SQL_C_CHAR:
  1886. {
  1887. if(col.blob_)
  1888. {
  1889. // Input is always std::string, while output may be std::string or std::wstring
  1890. std::stringstream ss;
  1891. char buff[1024] = {0};
  1892. std::size_t buff_size = sizeof(buff);
  1893. SQLLEN ValueLenOrInd;
  1894. SQLRETURN rc;
  1895. void* handle = native_statement_handle();
  1896. do
  1897. {
  1898. NANODBC_CALL_RC(
  1899. SQLGetData
  1900. , rc
  1901. , handle // StatementHandle
  1902. , column + 1 // Col_or_Param_Num
  1903. , SQL_C_CHAR // TargetType
  1904. , buff // TargetValuePtr
  1905. , buff_size // BufferLength
  1906. , &ValueLenOrInd); // StrLen_or_IndPtr
  1907. if (ValueLenOrInd > 0)
  1908. ss << buff;
  1909. } while(rc > 0);
  1910. convert(ss.str(), result);
  1911. }
  1912. else
  1913. {
  1914. const char* s = col.pdata_ + rowset_position_ * col.clen_;
  1915. const std::string::size_type str_size = std::strlen(s);
  1916. result.assign(s, s + str_size);
  1917. }
  1918. return;
  1919. }
  1920. case SQL_C_WCHAR:
  1921. {
  1922. if (col.blob_)
  1923. {
  1924. // Input is always std::wstring, output might be std::string or std::wstring.
  1925. // Use a string builder to build the output string.
  1926. std::wstringstream ss;
  1927. wchar_t buffer[512] = {0};
  1928. std::size_t buffer_size = sizeof(buffer);
  1929. SQLLEN ValueLenOrInd;
  1930. SQLRETURN rc;
  1931. void* handle = native_statement_handle();
  1932. do
  1933. {
  1934. NANODBC_CALL_RC(
  1935. SQLGetData
  1936. , rc
  1937. , handle // StatementHandle
  1938. , column + 1 // Col_or_Param_Num
  1939. , SQL_C_WCHAR // TargetType
  1940. , buffer // TargetValuePtr
  1941. , buffer_size // BufferLength
  1942. , &ValueLenOrInd); // StrLen_or_IndPtr
  1943. if (ValueLenOrInd > 0)
  1944. ss << buffer;
  1945. } while (rc > 0);
  1946. convert(ss.str(), result);
  1947. }
  1948. else
  1949. {
  1950. // Type is unicode in the database, convert if necessary
  1951. const SQLWCHAR* s = reinterpret_cast<SQLWCHAR*>(col.pdata_ + rowset_position_ * col.clen_);
  1952. const string_type::size_type str_size = *col.cbdata_ / sizeof(SQLWCHAR);
  1953. std::wstring temp(s, s + str_size);
  1954. convert(temp, result);
  1955. }
  1956. return;
  1957. }
  1958. case SQL_C_GUID:
  1959. case SQL_C_BINARY:
  1960. {
  1961. if(col.blob_)
  1962. throw std::runtime_error("blob not implemented yet");
  1963. const char* s = col.pdata_ + rowset_position_ * col.clen_;
  1964. result.assign(s, s + column_size);
  1965. return;
  1966. }
  1967. case SQL_C_LONG:
  1968. {
  1969. result.resize(column_size);
  1970. if(NANODBC_SNPRINTF(
  1971. const_cast<string_type::value_type*>(result.data())
  1972. , column_size
  1973. , NANODBC_TEXT("%d")
  1974. , *(int32_t*)(col.pdata_ + rowset_position_ * col.clen_)) == -1)
  1975. throw type_incompatible_error();
  1976. result.resize(NANODBC_STRLEN(result.c_str()));
  1977. return;
  1978. }
  1979. case SQL_C_SBIGINT:
  1980. {
  1981. using namespace std; // in case intmax_t is in namespace std
  1982. result.resize(column_size);
  1983. if(NANODBC_SNPRINTF(
  1984. const_cast<string_type::value_type*>(result.data())
  1985. , column_size
  1986. , NANODBC_TEXT("%jd")
  1987. , (intmax_t) *(int64_t*)(col.pdata_ + rowset_position_ * col.clen_)) == -1)
  1988. throw type_incompatible_error();
  1989. result.resize(NANODBC_STRLEN(result.c_str()));
  1990. return;
  1991. }
  1992. case SQL_C_FLOAT:
  1993. {
  1994. result.resize(column_size);
  1995. if(NANODBC_SNPRINTF(
  1996. const_cast<string_type::value_type*>(result.data())
  1997. , column_size
  1998. , NANODBC_TEXT("%f")
  1999. , *(float*)(col.pdata_ + rowset_position_ * col.clen_)) == -1)
  2000. throw type_incompatible_error();
  2001. result.resize(NANODBC_STRLEN(result.c_str()));
  2002. return;
  2003. }
  2004. case SQL_C_DOUBLE:
  2005. {
  2006. result.resize(column_size);
  2007. if(NANODBC_SNPRINTF(
  2008. const_cast<string_type::value_type*>(result.data())
  2009. , column_size
  2010. , NANODBC_TEXT("%lf")
  2011. , *(double*)(col.pdata_ + rowset_position_ * col.clen_)) == -1)
  2012. throw type_incompatible_error();
  2013. result.resize(NANODBC_STRLEN(result.c_str()));
  2014. return;
  2015. }
  2016. case SQL_C_DATE:
  2017. {
  2018. date d = *((date*)(col.pdata_ + rowset_position_ * col.clen_));
  2019. std::tm st = { 0 };
  2020. st.tm_year = d.year - 1900;
  2021. st.tm_mon = d.month - 1;
  2022. st.tm_mday = d.day;
  2023. char* old_lc_time = std::setlocale(LC_TIME, NULL);
  2024. std::setlocale(LC_TIME, "");
  2025. string_type::value_type date_str[512];
  2026. NANODBC_STRFTIME(
  2027. date_str
  2028. , sizeof(date_str) / sizeof(string_type::value_type)
  2029. , NANODBC_TEXT("%Y-%m-%d")
  2030. , &st);
  2031. std::setlocale(LC_TIME, old_lc_time);
  2032. result.assign(date_str);
  2033. return;
  2034. }
  2035. case SQL_C_TIMESTAMP:
  2036. {
  2037. timestamp stamp = *((timestamp*)(col.pdata_ + rowset_position_ * col.clen_));
  2038. std::tm st = { 0 };
  2039. st.tm_year = stamp.year - 1900;
  2040. st.tm_mon = stamp.month - 1;
  2041. st.tm_mday = stamp.day;
  2042. st.tm_hour = stamp.hour;
  2043. st.tm_min = stamp.min;
  2044. st.tm_sec = stamp.sec;
  2045. char* old_lc_time = std::setlocale(LC_TIME, NULL);
  2046. std::setlocale(LC_TIME, "");
  2047. string_type::value_type date_str[512];
  2048. NANODBC_STRFTIME(
  2049. date_str
  2050. , sizeof(date_str) / sizeof(string_type::value_type)
  2051. , NANODBC_TEXT("%Y-%m-%d %H:%M:%S %z")
  2052. , &st);
  2053. std::setlocale(LC_TIME, old_lc_time);
  2054. result.assign(date_str);
  2055. return;
  2056. }
  2057. }
  2058. throw type_incompatible_error();
  2059. }
  2060. template<class T>
  2061. void result::result_impl::get_ref_impl(short column, T& result) const
  2062. {
  2063. bound_column& col = bound_columns_[column];
  2064. using namespace std; // if int64_t is in std namespace (in c++11)
  2065. const char* s = col.pdata_ + rowset_position_ * col.clen_;
  2066. switch(col.ctype_)
  2067. {
  2068. case SQL_C_CHAR: result = (T)*(char*)(s); return;
  2069. case SQL_C_SSHORT: result = (T)*(short*)(s); return;
  2070. case SQL_C_USHORT: result = (T)*(unsigned short*)(s); return;
  2071. case SQL_C_LONG: result = (T)*(int32_t*)(s); return;
  2072. case SQL_C_SLONG: result = (T)*(int32_t*)(s); return;
  2073. case SQL_C_ULONG: result = (T)*(uint32_t*)(s); return;
  2074. case SQL_C_FLOAT: result = (T)*(float*)(s); return;
  2075. case SQL_C_DOUBLE: result = (T)*(double*)(s); return;
  2076. case SQL_C_SBIGINT: result = (T)*(int64_t*)(s); return;
  2077. case SQL_C_UBIGINT: result = (T)*(uint64_t*)(s); return;
  2078. }
  2079. throw type_incompatible_error();
  2080. }
  2081. } // namespace nanodbc
  2082. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2083. // Free Functions
  2084. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2085. namespace nanodbc
  2086. {
  2087. result execute(connection& conn, const string_type& query, long batch_operations, long timeout)
  2088. {
  2089. class statement statement;
  2090. return statement.execute_direct(conn, query, batch_operations, timeout);
  2091. }
  2092. void just_execute(connection& conn, const string_type& query, long batch_operations, long timeout) {
  2093. class statement statement;
  2094. statement.just_execute_direct(conn, query, batch_operations, timeout);
  2095. }
  2096. result execute(statement& stmt, long batch_operations)
  2097. {
  2098. return stmt.execute(batch_operations);
  2099. }
  2100. void just_execute(statement& stmt, long batch_operations)
  2101. {
  2102. return stmt.just_execute(batch_operations);
  2103. }
  2104. result transact(statement& stmt, long batch_operations)
  2105. {
  2106. class transaction transaction(stmt.connection());
  2107. result rvalue = stmt.execute(batch_operations);
  2108. transaction.commit();
  2109. return rvalue;
  2110. }
  2111. void just_transact(statement& stmt, long batch_operations)
  2112. {
  2113. class transaction transaction(stmt.connection());
  2114. stmt.just_execute(batch_operations);
  2115. transaction.commit();
  2116. }
  2117. void prepare(statement& stmt, const string_type& query, long timeout)
  2118. {
  2119. stmt.prepare(stmt.connection(), query, timeout);
  2120. }
  2121. } // namespace nanodbc
  2122. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2123. // Pimpl Forwards: connection
  2124. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2125. namespace nanodbc
  2126. {
  2127. connection::connection()
  2128. : impl_(new connection_impl())
  2129. {
  2130. }
  2131. connection::connection(const connection& rhs)
  2132. : impl_(rhs.impl_)
  2133. {
  2134. }
  2135. connection& connection::operator=(connection rhs)
  2136. {
  2137. swap(rhs);
  2138. return *this;
  2139. }
  2140. void connection::swap(connection& rhs) noexcept
  2141. {
  2142. using std::swap;
  2143. swap(impl_, rhs.impl_);
  2144. }
  2145. connection::connection(
  2146. const string_type& dsn
  2147. , const string_type& user
  2148. , const string_type& pass
  2149. , long timeout)
  2150. : impl_(new connection_impl(dsn, user, pass, timeout))
  2151. {
  2152. }
  2153. connection::connection(const string_type& connection_string, long timeout)
  2154. : impl_(new connection_impl(connection_string, timeout))
  2155. {
  2156. }
  2157. connection::~connection() noexcept
  2158. {
  2159. }
  2160. void connection::connect(
  2161. const string_type& dsn
  2162. , const string_type& user
  2163. , const string_type& pass
  2164. , long timeout)
  2165. {
  2166. impl_->connect(dsn, user, pass, timeout);
  2167. }
  2168. void connection::connect(const string_type& connection_string, long timeout)
  2169. {
  2170. impl_->connect(connection_string, timeout);
  2171. }
  2172. bool connection::connected() const
  2173. {
  2174. return impl_->connected();
  2175. }
  2176. void connection::disconnect()
  2177. {
  2178. impl_->disconnect();
  2179. }
  2180. std::size_t connection::transactions() const
  2181. {
  2182. return impl_->transactions();
  2183. }
  2184. void* connection::native_dbc_handle() const
  2185. {
  2186. return impl_->native_dbc_handle();
  2187. }
  2188. void* connection::native_env_handle() const
  2189. {
  2190. return impl_->native_env_handle();
  2191. }
  2192. string_type connection::driver_name() const
  2193. {
  2194. return impl_->driver_name();
  2195. }
  2196. std::size_t connection::ref_transaction()
  2197. {
  2198. return impl_->ref_transaction();
  2199. }
  2200. std::size_t connection::unref_transaction()
  2201. {
  2202. return impl_->unref_transaction();
  2203. }
  2204. bool connection::rollback() const
  2205. {
  2206. return impl_->rollback();
  2207. }
  2208. void connection::rollback(bool onoff)
  2209. {
  2210. impl_->rollback(onoff);
  2211. }
  2212. } // namespace nanodbc
  2213. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2214. // Pimpl Forwards: transaction
  2215. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2216. namespace nanodbc
  2217. {
  2218. transaction::transaction(const class connection& conn)
  2219. : impl_(new transaction_impl(conn))
  2220. {
  2221. }
  2222. transaction::transaction(const transaction& rhs)
  2223. : impl_(rhs.impl_)
  2224. {
  2225. }
  2226. transaction& transaction::operator=(transaction rhs)
  2227. {
  2228. swap(rhs);
  2229. return *this;
  2230. }
  2231. void transaction::swap(transaction& rhs) noexcept
  2232. {
  2233. using std::swap;
  2234. swap(impl_, rhs.impl_);
  2235. }
  2236. transaction::~transaction() noexcept
  2237. {
  2238. }
  2239. void transaction::commit()
  2240. {
  2241. impl_->commit();
  2242. }
  2243. void transaction::rollback() noexcept
  2244. {
  2245. impl_->rollback();
  2246. }
  2247. class connection& transaction::connection()
  2248. {
  2249. return impl_->connection();
  2250. }
  2251. const class connection& transaction::connection() const
  2252. {
  2253. return impl_->connection();
  2254. }
  2255. transaction::operator class connection&()
  2256. {
  2257. return impl_->connection();
  2258. }
  2259. transaction::operator const class connection&() const
  2260. {
  2261. return impl_->connection();
  2262. }
  2263. } // namespace nanodbc
  2264. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2265. // Pimpl Forwards: statement
  2266. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2267. namespace nanodbc
  2268. {
  2269. statement::statement()
  2270. : impl_(new statement_impl())
  2271. {
  2272. }
  2273. statement::statement(class connection& conn)
  2274. : impl_(new statement_impl(conn))
  2275. {
  2276. }
  2277. statement::statement(class connection& conn, const string_type& query, long timeout)
  2278. : impl_(new statement_impl(conn, query, timeout))
  2279. {
  2280. }
  2281. statement::statement(const statement& rhs)
  2282. : impl_(rhs.impl_)
  2283. {
  2284. }
  2285. statement& statement::operator=(statement rhs)
  2286. {
  2287. swap(rhs);
  2288. return *this;
  2289. }
  2290. void statement::swap(statement& rhs) noexcept
  2291. {
  2292. using std::swap;
  2293. swap(impl_, rhs.impl_);
  2294. }
  2295. statement::~statement() noexcept
  2296. {
  2297. }
  2298. void statement::open(class connection& conn)
  2299. {
  2300. impl_->open(conn);
  2301. }
  2302. bool statement::open() const
  2303. {
  2304. return impl_->open();
  2305. }
  2306. bool statement::connected() const
  2307. {
  2308. return impl_->connected();
  2309. }
  2310. const class connection& statement::connection() const
  2311. {
  2312. return impl_->connection();
  2313. }
  2314. class connection& statement::connection()
  2315. {
  2316. return impl_->connection();
  2317. }
  2318. void* statement::native_statement_handle() const
  2319. {
  2320. return impl_->native_statement_handle();
  2321. }
  2322. void statement::close()
  2323. {
  2324. impl_->close();
  2325. }
  2326. void statement::cancel()
  2327. {
  2328. impl_->cancel();
  2329. }
  2330. void statement::prepare(class connection& conn, const string_type& query, long timeout)
  2331. {
  2332. impl_->prepare(conn, query, timeout);
  2333. }
  2334. void statement::prepare(const string_type& query, long timeout)
  2335. {
  2336. impl_->prepare(query, timeout);
  2337. }
  2338. void statement::timeout(long timeout)
  2339. {
  2340. impl_->timeout(timeout);
  2341. }
  2342. result statement::execute_direct(
  2343. class connection& conn
  2344. , const string_type& query
  2345. , long batch_operations
  2346. , long timeout)
  2347. {
  2348. return impl_->execute_direct(conn, query, batch_operations, timeout, *this);
  2349. }
  2350. void statement::just_execute_direct(
  2351. class connection& conn
  2352. , const string_type& query
  2353. , long batch_operations
  2354. , long timeout)
  2355. {
  2356. impl_->just_execute_direct(conn, query, batch_operations, timeout, *this);
  2357. }
  2358. result statement::execute(long batch_operations, long timeout)
  2359. {
  2360. return impl_->execute(batch_operations, timeout, *this);
  2361. }
  2362. void statement::just_execute(long batch_operations, long timeout)
  2363. {
  2364. impl_->just_execute(batch_operations, timeout, *this);
  2365. }
  2366. result statement::procedure_columns(
  2367. const string_type& catalog
  2368. , const string_type& schema
  2369. , const string_type& procedure
  2370. , const string_type& column)
  2371. {
  2372. return impl_->procedure_columns(catalog, schema, procedure, column, *this);
  2373. }
  2374. long statement::affected_rows() const
  2375. {
  2376. return impl_->affected_rows();
  2377. }
  2378. short statement::columns() const
  2379. {
  2380. return impl_->columns();
  2381. }
  2382. void statement::reset_parameters() noexcept
  2383. {
  2384. impl_->reset_parameters();
  2385. }
  2386. unsigned long statement::parameter_size(short param) const
  2387. {
  2388. return impl_->parameter_size(param);
  2389. }
  2390. // We need to instantiate each form of bind() for each of our supported data types.
  2391. #define NANODBC_INSTANTIATE_BINDS(type) \
  2392. template void statement::bind(short, const type*, param_direction); /* 1-ary */ \
  2393. template void statement::bind(short, const type*, std::size_t, param_direction); /* n-ary */ \
  2394. template void statement::bind(short, const type*, std::size_t, const type*, param_direction); /* n-ary, sentry */ \
  2395. template void statement::bind(short, const type*, std::size_t, const bool*, param_direction) /* n-ary, flags */ \
  2396. /**/
  2397. // The following are the only supported instantiations of statement::bind().
  2398. NANODBC_INSTANTIATE_BINDS(string_type::value_type);
  2399. NANODBC_INSTANTIATE_BINDS(short);
  2400. NANODBC_INSTANTIATE_BINDS(unsigned short);
  2401. NANODBC_INSTANTIATE_BINDS(int32_t);
  2402. NANODBC_INSTANTIATE_BINDS(uint32_t);
  2403. NANODBC_INSTANTIATE_BINDS(int64_t);
  2404. NANODBC_INSTANTIATE_BINDS(uint64_t);
  2405. NANODBC_INSTANTIATE_BINDS(float);
  2406. NANODBC_INSTANTIATE_BINDS(double);
  2407. NANODBC_INSTANTIATE_BINDS(date);
  2408. NANODBC_INSTANTIATE_BINDS(timestamp);
  2409. #undef NANODBC_INSTANTIATE_BINDS
  2410. template<class T>
  2411. void statement::bind(short param, const T* value, param_direction direction)
  2412. {
  2413. impl_->bind(param, value, 1, direction);
  2414. }
  2415. template<class T>
  2416. void statement::bind(short param, const T* values, std::size_t elements, param_direction direction)
  2417. {
  2418. impl_->bind(param, values, elements, direction);
  2419. }
  2420. template<class T>
  2421. void statement::bind(
  2422. short param
  2423. , const T* values
  2424. , std::size_t elements
  2425. , const T* null_sentry
  2426. , param_direction direction)
  2427. {
  2428. impl_->bind(param, values, elements, 0, null_sentry, direction);
  2429. }
  2430. template<class T>
  2431. void statement::bind(
  2432. short param
  2433. , const T* values
  2434. , std::size_t elements
  2435. , const bool* nulls
  2436. , param_direction direction)
  2437. {
  2438. impl_->bind(param, values, elements, nulls, (T*)0, direction);
  2439. }
  2440. void statement::bind_strings(
  2441. short param
  2442. , const string_type::value_type* values
  2443. , std::size_t length
  2444. , std::size_t elements
  2445. , param_direction direction)
  2446. {
  2447. impl_->bind_strings(param, values, length, elements, direction);
  2448. }
  2449. void statement::bind_strings(
  2450. short param
  2451. , const string_type::value_type* values
  2452. , std::size_t length
  2453. , std::size_t elements
  2454. , const string_type::value_type* null_sentry
  2455. , param_direction direction)
  2456. {
  2457. impl_->bind_strings(param, values, length, elements, (bool*)0, null_sentry, direction);
  2458. }
  2459. void statement::bind_strings(
  2460. short param
  2461. , const string_type::value_type* values
  2462. , std::size_t length
  2463. , std::size_t elements
  2464. , const bool* nulls
  2465. , param_direction direction)
  2466. {
  2467. impl_->bind_strings(
  2468. param
  2469. , values
  2470. , length
  2471. , elements
  2472. , nulls
  2473. , (string_type::value_type*)0
  2474. , direction);
  2475. }
  2476. void statement::bind_null(short param, std::size_t elements)
  2477. {
  2478. impl_->bind_null(param, elements);
  2479. }
  2480. } // namespace nanodbc
  2481. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2482. // Pimpl Forwards: result
  2483. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2484. namespace nanodbc
  2485. {
  2486. result::result()
  2487. : impl_()
  2488. {
  2489. }
  2490. result::~result() noexcept
  2491. {
  2492. }
  2493. result::result(statement stmt, long rowset_size)
  2494. : impl_(new result_impl(stmt, rowset_size))
  2495. {
  2496. }
  2497. result::result(const result& rhs)
  2498. : impl_(rhs.impl_)
  2499. {
  2500. }
  2501. result& result::operator=(result rhs)
  2502. {
  2503. swap(rhs);
  2504. return *this;
  2505. }
  2506. void result::swap(result& rhs) noexcept
  2507. {
  2508. using std::swap;
  2509. swap(impl_, rhs.impl_);
  2510. }
  2511. void* result::native_statement_handle() const
  2512. {
  2513. return impl_->native_statement_handle();
  2514. }
  2515. long result::rowset_size() const noexcept
  2516. {
  2517. return impl_->rowset_size();
  2518. }
  2519. long result::affected_rows() const
  2520. {
  2521. return impl_->affected_rows();
  2522. }
  2523. long result::rows() const noexcept
  2524. {
  2525. return impl_->rows();
  2526. }
  2527. short result::columns() const
  2528. {
  2529. return impl_->columns();
  2530. }
  2531. bool result::first()
  2532. {
  2533. return impl_->first();
  2534. }
  2535. bool result::last()
  2536. {
  2537. return impl_->last();
  2538. }
  2539. bool result::next()
  2540. {
  2541. return impl_->next();
  2542. }
  2543. bool result::prior()
  2544. {
  2545. return impl_->prior();
  2546. }
  2547. bool result::move(long row)
  2548. {
  2549. return impl_->move(row);
  2550. }
  2551. bool result::skip(long rows)
  2552. {
  2553. return impl_->skip(rows);
  2554. }
  2555. unsigned long result::position() const
  2556. {
  2557. return impl_->position();
  2558. }
  2559. bool result::end() const noexcept
  2560. {
  2561. return impl_->end();
  2562. }
  2563. bool result::is_null(short column) const
  2564. {
  2565. return impl_->is_null(column);
  2566. }
  2567. bool result::is_null(const string_type& column_name) const
  2568. {
  2569. return impl_->is_null(column_name);
  2570. }
  2571. string_type result::column_name(short column) const
  2572. {
  2573. return impl_->column_name(column);
  2574. }
  2575. long result::column_size(short column) const
  2576. {
  2577. return impl_->column_size(column);
  2578. }
  2579. short result::column(const string_type& column_name) const
  2580. {
  2581. return impl_->column(column_name);
  2582. }
  2583. int result::column_datatype(short column) const
  2584. {
  2585. return impl_->column_datatype(column);
  2586. }
  2587. int result::column_datatype(const string_type& column_name) const
  2588. {
  2589. return impl_->column_datatype(column_name);
  2590. }
  2591. int result::column_c_datatype(short column) const
  2592. {
  2593. return impl_->column_c_datatype(column);
  2594. }
  2595. int result::column_c_datatype(const string_type& column_name) const
  2596. {
  2597. return impl_->column_c_datatype(column_name);
  2598. }
  2599. bool result::next_result()
  2600. {
  2601. return impl_->next_result();
  2602. }
  2603. template<class T>
  2604. void result::get_ref(short column, T& result) const
  2605. {
  2606. return impl_->get_ref<T>(column, result);
  2607. }
  2608. template<class T>
  2609. void result::get_ref(short column, const T& fallback, T& result) const
  2610. {
  2611. return impl_->get_ref<T>(column, fallback, result);
  2612. }
  2613. template<class T>
  2614. void result::get_ref(const string_type& column_name, T& result) const
  2615. {
  2616. return impl_->get_ref<T>(column_name, result);
  2617. }
  2618. template<class T>
  2619. void result::get_ref(const string_type& column_name, const T& fallback, T& result) const
  2620. {
  2621. return impl_->get_ref<T>(column_name, fallback, result);
  2622. }
  2623. template<class T>
  2624. T result::get(short column) const
  2625. {
  2626. return impl_->get<T>(column);
  2627. }
  2628. template<class T>
  2629. T result::get(short column, const T& fallback) const
  2630. {
  2631. return impl_->get<T>(column, fallback);
  2632. }
  2633. template<class T>
  2634. T result::get(const string_type& column_name) const
  2635. {
  2636. return impl_->get<T>(column_name);
  2637. }
  2638. template<class T>
  2639. T result::get(const string_type& column_name, const T& fallback) const
  2640. {
  2641. return impl_->get<T>(column_name, fallback);
  2642. }
  2643. result::operator bool() const
  2644. {
  2645. return static_cast<bool>(impl_);
  2646. }
  2647. // The following are the only supported instantiations of result::get_ref().
  2648. template void result::get_ref(short, string_type::value_type&) const;
  2649. template void result::get_ref(short, short&) const;
  2650. template void result::get_ref(short, unsigned short&) const;
  2651. template void result::get_ref(short, int32_t&) const;
  2652. template void result::get_ref(short, uint32_t&) const;
  2653. template void result::get_ref(short, int64_t&) const;
  2654. template void result::get_ref(short, uint64_t&) const;
  2655. template void result::get_ref(short, float&) const;
  2656. template void result::get_ref(short, double&) const;
  2657. template void result::get_ref(short, string_type&) const;
  2658. template void result::get_ref(short, date&) const;
  2659. template void result::get_ref(short, timestamp&) const;
  2660. template void result::get_ref(const string_type&, string_type::value_type&) const;
  2661. template void result::get_ref(const string_type&, short&) const;
  2662. template void result::get_ref(const string_type&, unsigned short&) const;
  2663. template void result::get_ref(const string_type&, int32_t&) const;
  2664. template void result::get_ref(const string_type&, uint32_t&) const;
  2665. template void result::get_ref(const string_type&, int64_t&) const;
  2666. template void result::get_ref(const string_type&, uint64_t&) const;
  2667. template void result::get_ref(const string_type&, float&) const;
  2668. template void result::get_ref(const string_type&, double&) const;
  2669. template void result::get_ref(const string_type&, string_type&) const;
  2670. template void result::get_ref(const string_type&, date&) const;
  2671. template void result::get_ref(const string_type&, timestamp&) const;
  2672. // The following are the only supported instantiations of result::get_ref() with fallback.
  2673. template void result::get_ref(short, const string_type::value_type&, string_type::value_type&) const;
  2674. template void result::get_ref(short, const short&, short&) const;
  2675. template void result::get_ref(short, const unsigned short&, unsigned short&) const;
  2676. template void result::get_ref(short, const int32_t&, int32_t&) const;
  2677. template void result::get_ref(short, const uint32_t&, uint32_t&) const;
  2678. template void result::get_ref(short, const int64_t&, int64_t&) const;
  2679. template void result::get_ref(short, const uint64_t&, uint64_t&) const;
  2680. template void result::get_ref(short, const float&, float&) const;
  2681. template void result::get_ref(short, const double&, double&) const;
  2682. template void result::get_ref(short, const string_type&, string_type&) const;
  2683. template void result::get_ref(short, const date&, date&) const;
  2684. template void result::get_ref(short, const timestamp&, timestamp&) const;
  2685. template void result::get_ref(const string_type&, const string_type::value_type&, string_type::value_type&) const;
  2686. template void result::get_ref(const string_type&, const short&, short&) const;
  2687. template void result::get_ref(const string_type&, const unsigned short&, unsigned short&) const;
  2688. template void result::get_ref(const string_type&, const int32_t&, int32_t&) const;
  2689. template void result::get_ref(const string_type&, const uint32_t&, uint32_t&) const;
  2690. template void result::get_ref(const string_type&, const int64_t&, int64_t&) const;
  2691. template void result::get_ref(const string_type&, const uint64_t&, uint64_t&) const;
  2692. template void result::get_ref(const string_type&, const float&, float&) const;
  2693. template void result::get_ref(const string_type&, const double&, double&) const;
  2694. template void result::get_ref(const string_type&, const string_type&, string_type&) const;
  2695. template void result::get_ref(const string_type&, const date&, date&) const;
  2696. template void result::get_ref(const string_type&, const timestamp&, timestamp&) const;
  2697. // The following are the only supported instantiations of result::get().
  2698. template string_type::value_type result::get(short) const;
  2699. template short result::get(short) const;
  2700. template unsigned short result::get(short) const;
  2701. template int32_t result::get(short) const;
  2702. template uint32_t result::get(short) const;
  2703. template int64_t result::get(short) const;
  2704. template uint64_t result::get(short) const;
  2705. template float result::get(short) const;
  2706. template double result::get(short) const;
  2707. template string_type result::get(short) const;
  2708. template date result::get(short) const;
  2709. template timestamp result::get(short) const;
  2710. template string_type::value_type result::get(const string_type&) const;
  2711. template short result::get(const string_type&) const;
  2712. template unsigned short result::get(const string_type&) const;
  2713. template int32_t result::get(const string_type&) const;
  2714. template uint32_t result::get(const string_type&) const;
  2715. template int64_t result::get(const string_type&) const;
  2716. template uint64_t result::get(const string_type&) const;
  2717. template float result::get(const string_type&) const;
  2718. template double result::get(const string_type&) const;
  2719. template string_type result::get(const string_type&) const;
  2720. template date result::get(const string_type&) const;
  2721. template timestamp result::get(const string_type&) const;
  2722. // The following are the only supported instantiations of result::get() with fallback.
  2723. template string_type::value_type result::get(short, const string_type::value_type&) const;
  2724. template short result::get(short, const short&) const;
  2725. template unsigned short result::get(short, const unsigned short&) const;
  2726. template int32_t result::get(short, const int32_t&) const;
  2727. template uint32_t result::get(short, const uint32_t&) const;
  2728. template int64_t result::get(short, const int64_t&) const;
  2729. template uint64_t result::get(short, const uint64_t&) const;
  2730. template float result::get(short, const float&) const;
  2731. template double result::get(short, const double&) const;
  2732. template string_type result::get(short, const string_type&) const;
  2733. template date result::get(short, const date&) const;
  2734. template timestamp result::get(short, const timestamp&) const;
  2735. template string_type::value_type result::get(const string_type&, const string_type::value_type&) const;
  2736. template short result::get(const string_type&, const short&) const;
  2737. template unsigned short result::get(const string_type&, const unsigned short&) const;
  2738. template int32_t result::get(const string_type&, const int32_t&) const;
  2739. template uint32_t result::get(const string_type&, const uint32_t&) const;
  2740. template int64_t result::get(const string_type&, const int64_t&) const;
  2741. template uint64_t result::get(const string_type&, const uint64_t&) const;
  2742. template float result::get(const string_type&, const float&) const;
  2743. template double result::get(const string_type&, const double&) const;
  2744. template string_type result::get(const string_type&, const string_type&) const;
  2745. template date result::get(const string_type&, const date&) const;
  2746. template timestamp result::get(const string_type&, const timestamp&) const;
  2747. } // namespace nanodbc
  2748. #undef NANODBC_THROW_DATABASE_ERROR
  2749. #undef NANODBC_STRINGIZE
  2750. #undef NANODBC_STRINGIZE_I
  2751. #undef NANODBC_CALL_RC
  2752. #undef NANODBC_CALL
  2753. #endif // DOXYGEN