TNB Library
TnbTinySqlAccessor.h
[詳解]
1#pragma once
13#include <TnbStrOperator.h>
14#include <TnbHandleHandle.h>
15#include <TnbPointerVector.h>
16
17
18
19#ifndef _WIN32_WCE
20 #include <sql.h>
21 #include <sqltypes.h>
22 #include <sqlucode.h>
23 #pragma comment(lib, "odbc32.lib")
24#else
25 #include "minodbc.h" // 要 Mimer SDK。
26 #pragma comment(lib, "mimodbcp.lib")
27 #pragma comment(lib, "minodbcw.lib")
28 #pragma comment(lib, "minsql32.lib")
29#endif
30
31
32
33namespace TNB
34{
35
36
37
38#ifndef _TnbDOXYGEN //Document作成用シンボル
39
41struct TPhFreeStmtHandle
42{
43 void operator()(SQLHSTMT h)
44 {
45 __try
46 {
47 ::SQLFreeHandle(SQL_HANDLE_STMT, h);
48 }
49 __except( EXCEPTION_EXECUTE_HANDLER )
50 {
51 ASSERT0( false, "", "先に CTinySqlAccessor が Disconnect しているか Stop しているか破棄されています。" );
52 }
53 }
54};
55
56#endif //_TnbDOXYGEN
57
58
59
141{
142public:
143
145 enum EType
146 {
147 Type_Null = SQL_TYPE_NULL,
148 Type_Binary = SQL_BINARY,
149 Type_AsciiString = SQL_CHAR,
150 Type_UnicodeString = SQL_WCHAR,
151 Type_DoubleFloat = SQL_DOUBLE,
152 Type_Float = SQL_FLOAT,
153 Type_Integer = SQL_INTEGER,
154 Type_Short = SQL_SMALLINT,
155 Type_TimeStamp = SQL_TYPE_TIMESTAMP,
156 Type_Bit = SQL_BIT
157 };
158
170 {
171 public:
172
177 struct TCodes
178 {
180 SQLINTEGER nativeError;
182 SQLINTEGER plm_Rownumber;
185 {
186 }
187 };
188
191
196 CReturnCode(void) : m_type(0), m_handle(0), m_returnCode(SQL_SUCCESS)
197 {
198 }
199
208 CReturnCode(SQLSMALLINT type, SQLHANDLE handle, SQLRETURN rc, bool isSilent = false) : m_type(type), m_handle(handle), m_returnCode(rc)
209 {
210 if ( ! isSilent )
211 {
212 Dump();
213 }
214 }
215
225 SQLRETURN GetReturnCode(void) const
226 {
227 return m_returnCode;
228 }
229
235 operator bool(void) const
236 {
237 return ! HasError();
238 }
239
245 bool HasError(void) const
246 {
247 return (m_returnCode != SQL_SUCCESS && m_returnCode != SQL_SUCCESS_WITH_INFO);
248 }
249
256 {
257 CStr s;
258 switch ( m_returnCode )
259 {
260 case SQL_SUCCESS:
261 case SQL_SUCCESS_WITH_INFO:
262 break;
263 case SQL_NO_DATA:
264 s = _T("No Data");
265 break;
266 case SQL_ERROR:
267 s = _T("Error");
268 break;
269 case SQL_INVALID_HANDLE:
270 s = _T("Invalid Handle");
271 break;
272 case SQL_NEED_DATA:
273 s = _T("Need Data");
274 break;
275 default:
276 s = _T("Unknown Error");
277 break;
278 }
279 return s;
280 }
281
287 CCodeVector GetDetialCode(bool withDiagnostics = false) const
288 {
289 CCodeVector codes;
290 SQLRETURN rc = SQL_SUCCESS;
291 SQLSMALLINT record = 1;
292 while ( rc == SQL_SUCCESS )
293 {
294 TCodes c;
295 SQLSMALLINT emLen = 0;
296 rc = ::SQLGetDiagRec(m_type, m_handle, record, GetSqlChar(c.sqlState, MAX_PATH), &c.nativeError
297 , GetSqlChar(c.errorMessage, MAX_PATH), MAX_PATH, &emLen);
300 if ( rc == SQL_SUCCESS )
301 {
302 if ( withDiagnostics )
303 {
304 m_GetDiagField(record, SQL_DIAG_ROW_NUMBER, &c.plm_Rownumber, SQL_IS_INTEGER);
305 }
306 codes.Add(c);
307 }
308 record++;
309 }
310 return codes;
311 }
312
320 static bool IsReturnCodeSuccess(SQLRETURN r)
321 {
322 switch ( r )
323 {
324 case SQL_SUCCESS:
325 case SQL_SUCCESS_WITH_INFO:
326 return true;
327 default:
328 break;
329 }
330 return false;
331 }
332
338 void Dump(void)
339 {
340 #ifdef _TnbDEBUG_ON
341 if ( m_returnCode != SQL_SUCCESS )
342 {
343 TTRACE2("*SqlReturn %d[%s]\n", m_returnCode, GetErrorString());
345 loop ( i, v )
346 {
347 const TCodes& t = v[i];
348 TTRACE2("No%d; state[%s]", i + 1, t.sqlState);
349 TTRACE3(", e=%d<%s>, %d\n", t.nativeError, t.errorMessage, t.plm_Rownumber);
350 }
351 }
352 #endif
353 }
354
355 private:
357 SQLRETURN m_GetDiagField(SQLSMALLINT iRecord, SQLSMALLINT fDiagField, SQLPOINTER rgbDiagInfo, SQLSMALLINT cbDiagInfoMax, SQLSMALLINT* pcbDiagInfo = NULL) const
358 {
359 return ::SQLGetDiagField(m_type, m_handle, iRecord, fDiagField, rgbDiagInfo, cbDiagInfoMax, pcbDiagInfo);
360 }
361 SQLSMALLINT m_type;
362 SQLHANDLE m_handle;
363 SQLRETURN m_returnCode;
364 };
365
366
367 //-----------------------------
368
369
380
381
382 //-----------------------------
383
384
408 {
409 public:
410
415 CColumnIndex(INDEX number) : m_number(number)
416 {
417 }
418
423 CColumnIndex(LPCTSTR lpszLabel) : m_label(lpszLabel), m_number(0)
424 {
425 }
426
432 bool HasLabel(void) const
433 {
434 return ! m_label.IsEmpty();
435 }
436
441 LPCTSTR GetLabel(void) const
442 {
443 return m_label;
444 }
445
450 INDEX GetNumber(void) const
451 {
452 return m_number;
453 }
454
455 private:
456 INDEX m_number;
457 CStr m_label;
458 };
459
460
461 //-----------------------------
462
463
479 {
480 public:
481
484 {
486 SQLSMALLINT dataType;
487 SQLULEN size;
488 SQLSMALLINT decimalDigits;
490 };
491
496 CResultSet(CStmtHandle hStmt) : m_hStmt(hStmt), m_isBinding(false), m_isLastNull(false)
497 {
498 }
499
504 CResultSet(const CResultSet& other) : m_hStmt(other.m_hStmt), m_isBinding(false), m_isLastNull(false)
505 {
506 }
507
514 {
515 m_hStmt = other.m_hStmt;
516 m_isBinding = false;
517 m_isLastNull = false;
518 return *this;
519 }
520
526 bool IsValid(void) const
527 {
528 return ! m_hStmt.IsNull();
529 }
530
535 void Destroy(void)
536 {
537 m_hStmt = NULL;
538 }
539
546 bool Next(void)
547 {
548 if ( ! Binding() )
549 {
550 return false;
551 }
552 if ( ! m_Rst(::SQLFetch(m_hStmt)) )
553 {
554 return false;
555 }
556 loop ( i, m_bindWorks.GetSize() )
557 {
558 TBindWork &b = m_bindWorks[i];
559 SQLLEN ll;
560 if ( b.dataType == SQL_VARBINARY )
561 {
562 ll = b.size;
563 b.work.Resize(ll);
564 if ( ! m_Rst(::SQLGetData(m_hStmt, down_cast<SQLUSMALLINT>(i + 1), Type_Binary, b.work.Ref(), ll, &b.length)) )
565 {
566 return false;
567 }
568 b.dataType = Type_Binary;
569 }
570 else
571 {
572 if ( b.size == 0x7FFFFFFF )
573 {
574 BYTE tmp;
575 RETCODE rc = ::SQLGetData(m_hStmt, down_cast<SQLUSMALLINT>(i + 1), SQL_C_CHAR, &tmp, 1, &ll);
576 if ( rc < 0 )
577 {
578 return m_Rst(rc);
579 }
580 }
581 else
582 {
583 ll = b.size;
584 }
585 ll = ll * 2 + 2;
586 b.work.Resize(ll);
587 SQLSMALLINT cc = (sizeof(TCHAR) == 1) ? SQL_C_CHAR : SQL_WCHAR;
588 if ( ! m_Rst(::SQLGetData(m_hStmt, down_cast<SQLUSMALLINT>(i + 1), b.dataType, b.work.Ref(), ll, &b.length), true) )
589 {
590 if ( ! m_Rst(::SQLGetData(m_hStmt, down_cast<SQLUSMALLINT>(i + 1), cc, b.work.Ref(), ll, &b.length)) )
591 {
592 return false;
593 }
594 b.dataType = cc;
595 }
596 }
597 }
598 return true;
599 }
600
607 bool WasNull(void) const
608 {
609 return m_isLastNull;
610 }
611
621 {
622 CStr r;
623 m_Check(index).Get(r);
624 return r;
625 }
626
636 {
637 CUnicode r;
638 m_Check(index).Get(r);
639 return r;
640 }
641
651 {
652 CAscii r;
653 m_Check(index).Get(r);
654 return r;
655 }
656
666 {
667 double r = 0.0;
668 m_Check(index).Get(r);
669 return r;
670 }
671
681 {
682 float r = 0.0;
683 m_Check(index).Get(r);
684 return r;
685 }
686
696 {
697 int r = 0;
698 m_Check(index).Get(r);
699 return r;
700 }
701
711 {
712 Zero(_v);
713 m_Check(index).Get(_v);
714 }
715
725 {
726 _v.Resize(0);
727 TBindWork& B = m_Check(index);
728 _v.Reset(B.length, B.work.Ref());
729 }
730
739 {
740 Binding();
741 return m_bindWorks[m_Find(index)];
742 }
743
751 INDEX FindColumn(LPCTSTR lpszLabel)
752 {
753 Binding();
754 loop ( i, m_bindWorks.GetSize() )
755 {
756 if ( m_bindWorks[i].name.CompareNoCase(lpszLabel) == 0 )
757 {
758 return i + 1;
759 }
760 }
761 return 0;
762 }
763
769 size_t GetColumnCount(void) const
770 {
771 return m_bindWorks.GetSize();
772 }
773
779 {
780 return m_lastReturnCode;
781 }
782
783 protected:
785 bool Binding(void)
786 {
787 if ( m_isBinding )
788 {
789 return m_Rst();
790 }
791 //== カラム数取得
792 SQLSMALLINT columnCount;
793 SQLRETURN r = ::SQLNumResultCols(m_hStmt, &columnCount);
794 if ( ! m_Rst(r, true) )
795 {
796 return false;
797 }
798 //== カラム情報取得
799 m_bindWorks.Resize(columnCount);
800 loop ( i, columnCount )
801 {
802 SQLSMALLINT nameLen;
803 TBindWork& b = m_bindWorks[i];
804 SQLSMALLINT nullable;
805 r = ::SQLDescribeCol(m_hStmt, // [in] ステートメント
806 down_cast<SQLUSMALLINT>(i + 1), // [in] カラム番号(1〜)
807 GetSqlChar(b.name, 100), // [out] カラム名
808 100, // [in] カラム名領域
809 &nameLen, // [out] カラム名長
810 &b.dataType, // [out] 型
811 &b.size, // [out] 型サイズ
812 &b.decimalDigits, // [out] 小数点情報
813 &nullable); // [out] NULLが有効か
814 b.isNullable = (nullable != 0);
815 b.name.ReleaseBuffer();
816 if ( ! m_Rst(r) )
817 {
818 return false;
819 }
820 TTRACE3("Col %d-[%s], type=%d, ", i + 1, b.name, b.dataType);
821 TTRACE3("size=%d, dec=%d, nullable=%d\n", b.size, b.decimalDigits, b.isNullable);
822 }
823 m_isBinding = true;
824 return true;
825 }
826
827 private:
829 struct TBindWork : TColumnInformation
830 {
831 CWorkMem work;
832 SQLLEN length;
840 bool Get(CUnicode& _value) const
841 {
842 if ( length >= 0 )
843 {
844 CStr s;
845 if ( m_Get(s) )
846 {
847 _value = s;
848 return true;
849 }
850 throw CNotSupportException();
851 }
852 return false;
853 }
861 bool Get(CAscii& _value) const
862 {
863 if ( length >= 0 )
864 {
865 CStr s;
866 if ( m_Get(s) )
867 {
868 _value = s;
869 return true;
870 }
871 throw CNotSupportException();
872 }
873 return false;
874 }
882 bool Get(double& _value) const
883 {
884 if ( length >= 0 )
885 {
886 if ( dataType == Type_DoubleFloat )
887 {
888 if ( length < sizeof(double) )
889 {
890 throw CNotSupportException();
891 }
892 _value = *reinterpret_cast<const double*>(work.Ref());
893 return true;
894 }
895 else if ( dataType == Type_Float )
896 {
897 if ( length < sizeof(float) )
898 {
899 throw CNotSupportException();
900 }
901 _value = *reinterpret_cast<const float*>(work.Ref());
902 return true;
903 }
904 else
905 {
906 CStr s;
907 if ( m_Get(s) )
908 {
909 _value = s.ToDouble();
910 return true;
911 }
912 }
913 throw CNotSupportException();
914 }
915 return false;;
916 }
924 bool Get(float& _value) const
925 {
926 double d;
927 if ( Get(d) )
928 {
929 _value = static_cast<float>(d);
930 return true;
931 }
932 return false;;
933 }
941 bool Get(int& _value) const
942 {
943 if ( length >= 0 )
944 {
945 if ( dataType == Type_Integer )
946 {
947 if ( length < sizeof(int) )
948 {
949 throw CNotSupportException();
950 }
951 _value = *reinterpret_cast<const int*>(work.Ref());
952 return true;
953 }
954 else if ( dataType == Type_Short )
955 {
956 if ( length < sizeof(short) )
957 {
958 throw CNotSupportException();
959 }
960 _value = *reinterpret_cast<const short*>(work.Ref());
961 return true;
962 }
963 else if ( dataType == Type_Bit )
964 {
965 if ( length < sizeof(BYTE) )
966 {
967 throw CNotSupportException();
968 }
969 _value = work[0];
970 return true;
971 }
972 else
973 {
974 CStr s;
975 if ( m_Get(s) )
976 {
977 _value = s.ToInt();
978 return true;
979 }
980 }
981 throw CNotSupportException();
982 }
983 return false;;
984 }
992 bool Get(SYSTEMTIME& _time) const
993 {
994 if ( length >= 0 )
995 {
996 if ( dataType == Type_TimeStamp )
997 {
998 if ( length < sizeof(TIMESTAMP_STRUCT) )
999 {
1000 throw CNotSupportException();
1001 }
1002 const TIMESTAMP_STRUCT* T = reinterpret_cast<const TIMESTAMP_STRUCT*>(work.Ref());
1003 Zero(_time);
1004 _time.wYear = T->year;
1005 _time.wMonth = T->month;
1006 _time.wDay = T->day;
1007 _time.wHour = T->hour;
1008 _time.wMinute = T->minute;
1009 _time.wSecond = T->second;
1010 return true;
1011 }
1012 throw CNotSupportException();
1013 }
1014 return false;;
1015 }
1021 CStr ToString(void) const
1022 {
1023 CStr s;
1024 try
1025 {
1026 if ( ! Get(s) )
1027 {
1028 s = _T("NULL");
1029 }
1030 }
1031 catch ( CNotSupportException& e )
1032 {
1033 e.OnCatch();
1034 s = _T("Unknown");
1035 }
1036 return s;
1037 }
1038 private:
1046 bool m_Get(CStr& _value) const
1047 {
1048 if ( length >= 0 )
1049 {
1050 if ( dataType == Type_TimeStamp )
1051 {
1052 CSystemTime st;
1053 Get(st);
1054 _value = SystemTimeToString(st);
1055 return true;
1056 }
1057 else if ( dataType == Type_Integer || dataType == Type_Short )
1058 {
1059 int v;
1060 Get(v);
1061 _value.Format(_T("%d"), v);
1062 return true;
1063 }
1064 else if ( dataType == Type_DoubleFloat || dataType == Type_Float )
1065 {
1066 double v;
1067 Get(v);
1068 _value.Format(_T("%.2f"), v);
1069 }
1070 else if ( dataType == Type_Binary )
1071 {
1072 _value = CStrOperator::BinaryToHexString(length, work.Ref());
1073 return true;
1074 }
1075 else if ( dataType == Type_Bit )
1076 {
1077 _value.Format(_T("%u"), work[0]);
1078 return true;
1079 }
1080 else if ( dataType == Type_AsciiString )
1081 {
1082 CAscii a;
1083 a.SetFromLeft(reinterpret_cast<LPCSTR>(work.Ref()), length);
1084 _value = a;
1085 }
1086 else if ( dataType == Type_UnicodeString )
1087 {
1088 CUnicode u;
1089 u.SetFromLeft(reinterpret_cast<LPCWSTR>(work.Ref()), length);
1090 _value = u;
1091 }
1092 else
1093 {
1094 _value.SetFromLeft(reinterpret_cast<LPCTSTR>(work.Ref()), length);
1095 }
1096 return true;
1097 }
1098 return false;
1099 }
1100 };
1101
1107 INDEX m_Find(const CColumnIndex& index) const
1108 {
1109 if ( index.HasLabel() )
1110 {
1111 //== ラベル指定
1112 loop ( i, m_bindWorks.GetSize() )
1113 {
1114 if ( m_bindWorks[i].name.CompareNoCase(index.GetLabel()) == 0 )
1115 {
1116 return i;
1117 }
1118 }
1119 throw CNotFoundException();
1120 }
1121 //== 番号指定
1122 INDEX i = index.GetNumber();
1123 if ( m_bindWorks.GetSize() > i - 1 )
1124 {
1125 return i - 1;
1126 }
1128 }
1134 TBindWork& m_Check(const CColumnIndex& index)
1135 {
1136 INDEX i = m_Find(index);
1137 TBindWork& B = m_bindWorks[i];
1138 m_isLastNull = (B.length < 0); //マイナスは NULL ってこと
1139 return B;
1140 }
1141 // 戻り値処理
1142 bool m_Rst(SQLRETURN rc = 0, bool isSilent = false)
1143 {
1144 m_lastReturnCode = CReturnCode(SQL_HANDLE_STMT, m_hStmt, rc, isSilent);
1146 }
1147 bool m_isBinding;
1148 CStmtHandle m_hStmt;
1149 CWorkMemT<TBindWork> m_bindWorks;
1150 bool m_isLastNull;
1151 CReturnCode m_lastReturnCode;
1152 friend class CResultSetTest;
1153 };
1154
1155
1156 //-------------------------------
1157
1158
1176 {
1177 public:
1178
1184 CStatement(SQLHDBC hDbc, DWORD tm = 0) : m_hDbc(hDbc), m_timeout(tm)
1185 {
1186 }
1187
1192 CStatement(const CStatement& other)
1194 {
1195 }
1196
1203 {
1204 m_hDbc = other.m_hDbc;
1205 m_timeout = other.m_timeout;
1206 m_hStmt = other.m_hStmt;
1208 return *this;
1209 }
1210
1216 bool IsValid(void)
1217 {
1218 m_Init();
1219 return ! m_hStmt.IsNull();
1220 }
1221
1226 void Destroy(void)
1227 {
1228 m_hStmt = NULL;
1229 }
1230
1238 bool Execute(LPCTSTR lpszSql)
1239 {
1240 m_Init();
1241 //== SQL文実行
1242 CStr sql = lpszSql;
1243 SQLRETURN r = ::SQLExecDirect(m_hStmt, GetSqlChar(sql), SQL_NTS);
1244 return m_Rst(r);
1245 }
1246
1253 {
1254 return CResultSet(m_hStmt);
1255 }
1256
1262 {
1263 return m_lastReturnCode;
1264 }
1265
1272 {
1273 SQLULEN tm;
1274 SQLRETURN r = ::SQLGetStmtAttr(m_hStmt, SQL_ATTR_QUERY_TIMEOUT, static_cast<SQLPOINTER>(&tm), SQL_IS_UINTEGER, NULL);
1275 if ( m_Rst(r) )
1276 {
1277 return static_cast<DWORD>(tm);
1278 }
1279 return DWORD_MAX;
1280 }
1281
1287 virtual bool CloseCursor(void)
1288 {
1289 return m_Rst(::SQLCloseCursor(m_hStmt));
1290 }
1291
1292 protected:
1293
1297 bool m_Init(void)
1298 {
1299 if ( m_hStmt.IsNull() )
1300 {
1301 SQLHSTMT hStmt = NULL;
1302 SQLRETURN r = ::SQLAllocHandle(SQL_HANDLE_STMT, m_hDbc, &hStmt);
1303 m_lastReturnCode = CReturnCode(SQL_HANDLE_DBC, m_hDbc, r);
1304 if ( ! m_lastReturnCode )
1305 {
1306 return false;
1307 }
1308 m_hStmt = hStmt;
1309 SQLULEN tm = m_timeout;
1310 ::SQLSetStmtAttr(m_hStmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>(tm), 0);
1311 ASSERT( GetQueryTimeout() == m_timeout );
1312 }
1313 return true;
1314 }
1319 bool m_Rst(SQLRETURN rc = 0)
1320 {
1321 m_lastReturnCode = CReturnCode(SQL_HANDLE_STMT, m_hStmt, rc);
1323 }
1324 SQLHDBC m_hDbc;
1328 };
1329
1330
1331 //---------------------------
1332
1333
1356 {
1357 DEFSUPER(CStatement);
1358 public:
1359
1366 CPreparedStatement(SQLHDBC hDbc, LPCTSTR lpszSql, DWORD tm = 0) : _super(hDbc, tm), m_sql(lpszSql), m_isPrepared(false)
1367 {
1368 }
1369
1374 CPreparedStatement(const CPreparedStatement& other) : _super(other), m_sql(other.m_sql), m_isPrepared(false)
1375 {
1376 }
1377
1384 {
1385 _super::operator=(other);
1386 m_sql = other.m_sql; // SQL 文
1387 m_isPrepared = false;
1388 m_bindParams.RemoveAll(); // バインドワーク
1389 return *this;
1390 }
1391
1400 bool ExecuteDirect(LPCTSTR lpszSql)
1401 {
1402 return _super::Execute(lpszSql);
1403 }
1404
1411 bool Execute(void)
1412 {
1413 if ( ! m_Prepare() )
1414 {
1415 return false;
1416 }
1417 SQLRETURN r = ::SQLExecute(m_hStmt);
1418 return m_Rst(r);
1419 }
1420
1427 bool SetNull(INDEX parameterIndex)
1428 {
1429 return m_BindParam(parameterIndex, SQL_C_NUMERIC, SQL_NUMERIC, SQL_NULL_DATA, NULL);
1430 }
1431
1439 bool SetInt(INDEX parameterIndex, int value)
1440 {
1441 return m_BindParam(parameterIndex, SQL_C_SLONG, SQL_INTEGER, sizeof(value), &value);
1442 }
1443
1451 bool SetDouble(INDEX parameterIndex, double value)
1452 {
1453 return m_BindParam(parameterIndex, SQL_C_DOUBLE, SQL_DOUBLE, sizeof(value), &value);
1454 }
1455
1464 bool SetBinary(INDEX parameterIndex, size_t size, LPCVOID P)
1465 {
1466 SQLLEN l = down_cast<SQLLEN>(size);
1467 if ( l == 0 )
1468 {
1469 return SetNull(parameterIndex);
1470 }
1471 return m_BindParam(parameterIndex, SQL_C_BINARY, SQL_BINARY, l, P);
1472 }
1473
1481 bool SetString(INDEX parameterIndex, LPCSTR lpsz)
1482 {
1483 SQLLEN l = down_cast<SQLLEN>(STRLIB::GetLen(lpsz));
1484 if ( l == 0 )
1485 {
1486 return SetNull(parameterIndex);
1487 }
1488 return m_BindParam(parameterIndex, SQL_C_CHAR, SQL_CHAR, l, lpsz);
1489 }
1490
1499 bool SetString(INDEX parameterIndex, LPCWSTR lpsz)
1500 {
1501 SQLLEN l = down_cast<SQLLEN>(STRLIB::GetLen(lpsz) * 2);
1502 if( l == 0 )
1503 {
1504 return SetNull(parameterIndex);
1505 }
1506 return m_BindParam(parameterIndex, SQL_C_WCHAR, SQL_WCHAR, l, lpsz);
1507 }
1508
1516 bool SetTime(INDEX parameterIndex, const SYSTEMTIME& time)
1517 {
1518 TIMESTAMP_STRUCT ts;
1519 Zero(ts);
1520 ts.year = time.wYear;
1521 ts.month = time.wMonth;
1522 ts.day = time.wDay;
1523 ts.hour = time.wHour;
1524 ts.minute = time.wMinute;
1525 ts.second = time.wSecond;
1526 return m_BindParam(parameterIndex, SQL_C_TIMESTAMP, SQL_C_TIMESTAMP, sizeof(ts), &ts);
1527 }
1528
1529// bool SetDefault(INDEX parameterIndex)
1530// {
1531// return m_BindParam(parameterIndex, SQL_C_DEFAULT, SQL_BINARY, SQL_DEFAULT_PARAM, NULL);
1532// }
1533
1539 virtual bool CloseCursor(void)
1540 {
1541 m_isPrepared = false;
1542 return _super::CloseCursor();
1543 }
1544 private:
1545 // 使用禁止宣言
1546 bool Execute(LPCTSTR lpszSql);
1547 // バインドワーク型
1548 struct TBindWork
1549 {
1550 CWorkMem work;
1551 SQLLEN length;
1552 };
1553 // プレペア処理
1554 bool m_Prepare(void)
1555 {
1556 m_Init();
1557 if ( ! m_isPrepared )
1558 {
1559 SQLRETURN r = ::SQLPrepare(m_hStmt, GetSqlChar(m_sql), SQL_NTS);
1560 m_sql.ReleaseBuffer();
1561 if ( ! m_Rst(r) )
1562 {
1563 return false;
1564 }
1565 m_isPrepared = true;
1566 }
1567 return true;
1568 }
1569 // バインド処理
1570 bool m_BindParam(INDEX parameterIndex, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLLEN len, LPCVOID P)
1571 {
1572 if ( ! m_Prepare() )
1573 {
1574 return false;
1575 }
1576 if ( m_bindParams.GetSize() <= parameterIndex )
1577 {
1578 m_bindParams.SetSize(parameterIndex + 1);
1579 }
1580 TBindWork* W = m_bindParams.Get(parameterIndex);
1581 if ( W == NULL )
1582 {
1583 W = new TBindWork;
1584 m_bindParams.Set(parameterIndex, W);
1585 }
1586 else if ( W->length == len )
1587 {
1588 if ( len > 0 && ToInt(W->work.GetSize()) == len )
1589 {
1590 memcpy(W->work.Ref(), P, len);
1591 }
1592 return true;
1593 }
1594 W->length = len;
1595 SQLRETURN r;
1596 if ( fCType == SQL_C_TIMESTAMP )
1597 {
1598 W->work.Reset(len, static_cast<const BYTE*>(P));
1599 r = ::SQLBindParameter(m_hStmt, down_cast<SQLUSMALLINT>(parameterIndex)
1600 , SQL_PARAM_INPUT, fCType, fSqlType, 23/*TIMESTAMP_PRECISION*/, 0, W->work.Ref(), 0, &W->length);
1601 }
1602 else if ( len >= 0 )
1603 {
1604 W->work.Reset(len, static_cast<const BYTE*>(P));
1605 r = ::SQLBindParameter(m_hStmt, down_cast<SQLUSMALLINT>(parameterIndex)
1606 , SQL_PARAM_INPUT, fCType, fSqlType, len, 0, W->work.Ref(), len, &W->length);
1607 }
1608 else
1609 {
1610 W->work.Resize(1);
1611 r = ::SQLBindParameter(m_hStmt, down_cast<SQLUSMALLINT>(parameterIndex)
1612 , SQL_PARAM_INPUT, fCType, fSqlType, 13, 6, NULL, 0, &W->length);
1613 }
1614 return m_Rst(r);
1615 }
1616 CStr m_sql;
1617 bool m_isPrepared;
1618 CPointerVectorT<TBindWork> m_bindParams;
1619 };
1620
1621
1622 //-------------------------------
1623
1624
1630 {
1631 Stop();
1632 }
1633
1637 CTinySqlAccessor(void) : m_hEnv(NULL), m_hDbc(NULL), m_isConnecting(false), m_timeout(0)
1638 {
1639 }
1640
1647 bool IsStarted(void) const
1648 {
1649 return m_hEnv != NULL;
1650 }
1651
1661 bool Stop(void)
1662 {
1663 if ( IsStarted() )
1664 {
1665 Disconnect();
1666 // DB接続用ハンドル開放
1667 SQLRETURN r = ::SQLFreeHandle(SQL_HANDLE_DBC, m_hDbc);
1668 if ( ! m_Rst(SQL_HANDLE_DBC, m_hDbc, r) )
1669 {
1670 return false;
1671 }
1672 m_hDbc = NULL;
1673 // 環境用のハンドル開放
1674 r = ::SQLFreeHandle(SQL_HANDLE_ENV, m_hEnv);
1675 if ( ! m_Rst(SQL_HANDLE_ENV, m_hEnv, r) )
1676 {
1677 return false;
1678 }
1679 m_hEnv = NULL;
1680 }
1681 return m_Rst();
1682 }
1683
1690 bool Start(void)
1691 {
1692 Stop();
1693 //== ODBC環境ハンドル取得
1694 SQLRETURN r = ::SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_hEnv);
1695 if ( ! m_CheckReturnCode(r) )
1696 {
1697 m_hEnv = NULL;
1698 }
1699 else
1700 {
1701 //== ODBCバージョン設定
1702 r = ::SQLSetEnvAttr(m_hEnv, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3), 0);
1703 if ( m_CheckReturnCode(r) )
1704 {
1705 //== ODBCデータベースハンドル取得
1706 r = ::SQLAllocHandle(SQL_HANDLE_DBC, m_hEnv, &m_hDbc);
1707 }
1708 if ( ! m_CheckReturnCode(r) )
1709 {
1710 ::SQLFreeHandle(SQL_HANDLE_ENV, m_hEnv);
1711 m_hEnv = NULL;
1712 }
1713 }
1714 return m_Rst(SQL_HANDLE_ENV, m_hEnv, r);
1715 }
1716
1722 bool IsConnecting(void) const
1723 {
1724 return m_isConnecting;
1725 }
1726
1734 bool Disconnect(void)
1735 {
1736 if ( ! IsConnecting() )
1737 {
1738 return m_Rst();
1739 }
1740 // コミット
1741 SQLRETURN r = ::SQLEndTran(SQL_HANDLE_DBC, m_hDbc, SQL_COMMIT);
1742 // DB ディスコネクト
1743 r = ::SQLDisconnect(m_hDbc);
1744 if ( m_Rst(SQL_HANDLE_DBC, m_hDbc, r) )
1745 {
1746 m_isConnecting = false;
1747 return true;
1748 }
1749 return false;
1750 }
1751
1762 bool Connect(LPCTSTR lpszDataBaseName, LPCTSTR lpszUserName, LPCTSTR lpszPassword)
1763 {
1764 if ( m_PreConnect() )
1765 {
1766 //== データベース接続
1767 CStr dn = lpszDataBaseName;
1768 CStr un = lpszUserName;
1769 CStr pw = lpszPassword;
1770 SQLRETURN r = ::SQLConnect(m_hDbc, GetSqlChar(dn), SQL_NTS, GetSqlChar(un), SQL_NTS, GetSqlChar(pw), SQL_NTS);
1771 if ( m_Rst(SQL_HANDLE_DBC, m_hDbc, r) )
1772 {
1773 m_isConnecting = true;
1774 return true;
1775 }
1776 }
1777 return false;
1778 }
1779
1789 bool Connect(LPCTSTR lpszConnect, SQLUSMALLINT options = SQL_DRIVER_NOPROMPT)
1790 {
1791 if ( m_PreConnect() )
1792 {
1793 CStr cs = lpszConnect;
1794 //== データベース接続
1795 SQLHWND hWnd = ::GetDesktopWindow();
1796 CStr n;
1797 SQLSMALLINT length = 0;
1798 SQLRETURN r = ::SQLDriverConnect(m_hDbc, hWnd, GetSqlChar(cs), SQL_NTS, GetSqlChar(n, 256), 256, &length, options);
1799 if ( m_Rst(SQL_HANDLE_DBC, m_hDbc, r) )
1800 {
1801 m_isConnecting = true;
1802 return true;
1803 }
1804 }
1805 return false;
1806 }
1807
1820 bool Connect(LPCTSTR lpszDriverName, LPCTSTR lpszDataBaseName, LPCTSTR lpszUserName, LPCTSTR lpszPassword, SQLUSMALLINT options = SQL_DRIVER_NOPROMPT)
1821 {
1822 //== 名前作成
1823 CStr cs;
1824 cs.Format(_T("DRIVER={%s};Database=%s;UID=%s;PWD=%s;"), lpszDriverName, lpszDataBaseName, lpszUserName, lpszPassword);
1825 return Connect(cs, options);
1826 }
1827
1832 void SetQueryTimeout(DWORD tm)
1833 {
1834 m_timeout = tm;
1835 }
1836
1842 {
1843 return CStatement(m_hDbc, m_timeout);
1844 }
1845
1852 {
1853 return CPreparedStatement(m_hDbc, lpszSql, m_timeout);
1854 }
1855
1862 bool IsAutoCommit(void)
1863 {
1864 DWORD l = DWORD_MAX;
1865 SQLINTEGER len = 0;
1866 SQLRETURN r = ::SQLGetConnectAttr(m_hDbc, SQL_AUTOCOMMIT, &l, sizeof(l), &len);
1867 if ( m_Rst(SQL_HANDLE_DBC, m_hDbc, r) )
1868 {
1869 return (l == SQL_AUTOCOMMIT_ON);
1870 }
1871 return false;
1872 }
1873
1881 bool SetAutoCommit(bool isEnable)
1882 {
1883 DWORD l = isEnable ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
1884 SQLRETURN r = ::SQLSetConnectAttr(m_hDbc, SQL_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(static_cast<SQLLEN>(l)), 0);
1885 return m_Rst(SQL_HANDLE_DBC, m_hDbc, r);
1886 }
1887
1894 bool Commit(void)
1895 {
1896 SQLRETURN r = ::SQLEndTran(SQL_HANDLE_DBC, m_hDbc, SQL_COMMIT);
1897 return m_Rst(SQL_HANDLE_DBC, m_hDbc, r);
1898 }
1899
1906 bool Rollback(void)
1907 {
1908 SQLRETURN r = ::SQLEndTran(SQL_HANDLE_DBC, m_hDbc, SQL_ROLLBACK);
1909 return m_Rst(SQL_HANDLE_DBC, m_hDbc, r);
1910 }
1911
1917 {
1918 return m_lastReturnCode;
1919 }
1920
1928 {
1929 return CStr::Fmt(_T("%4d-%02d-%02d %02d:%02d:%02d"), time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond);
1930 }
1931
1932
1933 //----------------
1934
1935
1944 static SQLTCHAR* GetSqlChar(CStr& _s, size_t len = 0)
1945 {
1946 #ifndef _UNICODE
1947 return reinterpret_cast<SQLCHAR*>(_s.GetBuffer(len));
1948 #else
1949 return _s.GetBuffer(len);
1950 #endif
1951 }
1952
1953private:
1955 bool m_PreConnect(void)
1956 {
1957 if ( ! IsStarted() && ! Start() )
1958 {
1959 return false;
1960 }
1961 return Disconnect();
1962 }
1963 // 戻り値チェック
1964 bool m_CheckReturnCode(SQLRETURN r) const
1965 {
1967 }
1968 // 戻り値処理
1969 bool m_Rst(SQLSMALLINT type = 0, SQLHANDLE handle = NULL, SQLRETURN rc = 0)
1970 {
1971 m_lastReturnCode = CReturnCode(type, handle, rc);
1972 return m_CheckReturnCode(rc);
1973 }
1974
1975 SQLHENV m_hEnv;
1976 SQLHDBC m_hDbc;
1977 DWORD m_timeout;
1978 bool m_isConnecting;
1979 CReturnCode m_lastReturnCode;
1980};
1981
1982
1983
1984}; // TNB
1985
1986
#define loop(VAR, CNT)
loop構文.
Definition: TnbDef.h:343
ハンドルハンドル関係のヘッダ
ポインタ配列管理関係のヘッダ
文字列操作関係のヘッダ
[ETC] コピー不可能スーパークラス.
Definition: TnbDef.h:599
INDEX範囲外例外
Definition: TnbException.h:81
見付からない例外
Definition: TnbException.h:198
サポート外例外
Definition: TnbException.h:185
bool IsNull(void) const
[確認] NULLチェック
virtual size_t GetSize(void) const
[取得] 要素数取得
void RemoveAll(void)
[削除] 空化
void SetSize(size_t size)
[操作] サイズ指定
bool Set(INDEX index, TYP *P)
[設定] 要素の設定
static CStrT< TYP > BinaryToHexString(const IConstCollectionT< BYTE > &c)
[作成] バイナリ→HEX文字列
bool IsEmpty(void) const
[確認] 空チェック
Definition: TnbStr.h:528
void ReleaseBuffer(void)
[操作] 割り当てたバッファを開放.
Definition: TnbStr.h:954
static CStrT Fmt(const TCHAR *lpszFormat,...)
[作成] 書式付き文字列作成
Definition: TnbStr.h:1206
double ToDouble(INDEX iOffset=0) const
[取得] 数値(double)へ変換
Definition: TnbStr.h:874
CStrT & SetFromLeft(const TYP *lpText, size_t iLen)
[代入] 文字数制限代入.
Definition: TnbStr.h:278
void Format(const TYP *lpszFormat,...)
[代入] 書式付き文字列代入.
Definition: TnbStr.h:359
int ToInt(INDEX iOffset=0, int iBase=10) const
[取得] 数値(int)へ変換
Definition: TnbStr.h:842
TYP * GetBuffer(size_t iLength=0)
[操作] 書き込みバッファ要求.
Definition: TnbStr.h:914
システムタイム管理クラス
Definition: TnbTime.h:294
簡易 SQL アクセサ用カラムインデックス.
bool HasLabel(void) const
[確認] ラベル指定か?
CColumnIndex(LPCTSTR lpszLabel)
コンストラクタ.
LPCTSTR GetLabel(void) const
[取得] ラベル.
CColumnIndex(INDEX number)
コンストラクタ.
INDEX GetNumber(void) const
[取得] 番号.
簡易 SQL アクセサ用プリペアドステートメント.
CPreparedStatement & operator=(const CPreparedStatement &other)
コピーオペレータ.
bool SetBinary(INDEX parameterIndex, size_t size, LPCVOID P)
[設定] バイナリ設定.
bool SetInt(INDEX parameterIndex, int value)
[設定] int 値設定.
bool SetNull(INDEX parameterIndex)
[設定] NULL 値設定.
bool SetString(INDEX parameterIndex, LPCSTR lpsz)
[設定] 文字列設定.
bool SetDouble(INDEX parameterIndex, double value)
[設定] double 値設定.
bool SetTime(INDEX parameterIndex, const SYSTEMTIME &time)
[設定] タイムスタンプ設定.
CPreparedStatement(const CPreparedStatement &other)
コピーコンストラクタ.
bool ExecuteDirect(LPCTSTR lpszSql)
[設定] 実行.
bool SetString(INDEX parameterIndex, LPCWSTR lpsz)
[設定] 文字列設定.
virtual bool CloseCursor(void)
[設定] クローズカーソル.
CPreparedStatement(SQLHDBC hDbc, LPCTSTR lpszSql, DWORD tm=0)
コンストラクタ.
簡易 SQL アクセサ用結果セット管理.
CResultSet(CStmtHandle hStmt)
コンストラクタ.
const TColumnInformation & GetColumnInformation(CColumnIndex index)
[取得] カラム情報取得.
float GetFloat(CColumnIndex index)
[取得] Float 値取得.
int GetInt(CColumnIndex index)
[取得] int 値取得.
CUnicode GetUnicodeString(CColumnIndex index)
[取得] 文字列取得.
CStr GetString(CColumnIndex index)
[取得] 文字列取得.
bool Next(void)
[設定] 次読み出し.
CReturnCode GetLastReturnCode(void) const
[取得] 戻り値詳細取得.
void GetTime(SYSTEMTIME &_v, CColumnIndex index)
[取得] タイムスタンプ値取得.
bool WasNull(void) const
[確認] NULL確認.
bool IsValid(void) const
[確認] 正しい情報?
double GetDouble(CColumnIndex index)
[取得] double 値取得.
INDEX FindColumn(LPCTSTR lpszLabel)
[取得] ラベル名検索.
void Destroy(void)
[設定] 使用不可.
size_t GetColumnCount(void) const
[取得] カラム数取得.
bool Binding(void)
バインド(現在はカラム情報取得のみ)
CAscii GetAsciiString(CColumnIndex index)
[取得] 文字列取得.
void GetBinary(CWorkMem &_v, CColumnIndex index)
[取得] バイナリデータ取得.
CResultSet & operator=(const CResultSet &other)
コピーオペレータ.
CResultSet(const CResultSet &other)
コピーコンストラクタ.
簡易 SQL アクセサ用戻り値管理.
void Dump(void)
[出力] ダンプ.
CVectorT< TCodes > CCodeVector
コード群配列管理
CStr GetErrorString(void) const
[取得] エラー文字列取得.
static bool IsReturnCodeSuccess(SQLRETURN r)
[確認] 成功確認.
SQLRETURN GetReturnCode(void) const
[取得] 戻り値取得.
CReturnCode(void)
コンストラクタ.
CCodeVector GetDetialCode(bool withDiagnostics=false) const
[取得] 詳細情報取得.
bool HasError(void) const
[確認] 失敗か?
CReturnCode(SQLSMALLINT type, SQLHANDLE handle, SQLRETURN rc, bool isSilent=false)
コンストラクタ.
簡易 SQL アクセサ用ステートメント.
CStatement(SQLHDBC hDbc, DWORD tm=0)
コンストラクタ.
CReturnCode m_lastReturnCode
最後の戻り値
CReturnCode GetLastReturnCode(void) const
[取得] 戻り値詳細取得.
bool IsValid(void)
[確認] 有効確認.
CResultSet GetResultSet(void) const
[取得] 結果セット取得.
CStatement & operator=(const CStatement &other)
コピーオペレータ.
bool m_Init(void)
[確認] 準備処理
void Destroy(void)
[設定] 使用不可.
bool m_Rst(SQLRETURN rc=0)
[確認] 戻り値処理
virtual bool CloseCursor(void)
[設定] クローズカーソル.
DWORD m_timeout
タイムアウト(s)
bool Execute(LPCTSTR lpszSql)
[設定] 実行.
DWORD GetQueryTimeout(void)
[取得] タイムアウト取得
CStmtHandle m_hStmt
ステートメントハンドル
CStatement(const CStatement &other)
コピーコンストラクタ.
簡易 SQL アクセサクラス
bool Disconnect(void)
[設定] 切断.
static SQLTCHAR * GetSqlChar(CStr &_s, size_t len=0)
[変換] 文字列ポインタ取得.
CReturnCode GetLastReturnCode(void) const
[取得] 戻り値詳細取得.
void SetQueryTimeout(DWORD tm)
[設定] タイムアウト設定.
CPreparedStatement PreparedStatement(LPCTSTR lpszSql)
[作成] プリペアドステートメント作成.
bool Connect(LPCTSTR lpszDataBaseName, LPCTSTR lpszUserName, LPCTSTR lpszPassword)
[設定] 接続.
bool Commit(void)
[設定] コミット.
bool IsConnecting(void) const
[確認] 接続中か?
bool IsStarted(void) const
[確認] 開始している?.
CTinySqlAccessor(void)
コンストラクタ.
~CTinySqlAccessor(void)
デストラクタ.
bool Connect(LPCTSTR lpszConnect, SQLUSMALLINT options=SQL_DRIVER_NOPROMPT)
[設定] 接続.
bool Start(void)
[設定] 開始.
static CStr SystemTimeToString(const SYSTEMTIME &time)
[変換] 時間文字列化.
bool Rollback(void)
[設定] ロールバック.
bool Connect(LPCTSTR lpszDriverName, LPCTSTR lpszDataBaseName, LPCTSTR lpszUserName, LPCTSTR lpszPassword, SQLUSMALLINT options=SQL_DRIVER_NOPROMPT)
[設定] 接続.
@ Type_Short
16bit signed 整数
@ Type_UnicodeString
UNICODE文字列
@ Type_AsciiString
ASCII文字列
@ Type_TimeStamp
タイムスタンプ
@ Type_DoubleFloat
64bit double float 実数
@ Type_Float
32bit float 実数
@ Type_Integer
32bit signed 整数
CStatement CreateStatement(void)
[作成] ステートメント作成.
bool Stop(void)
[設定] 停止.
bool IsAutoCommit(void)
[取得] 自動コミット状態確認
bool SetAutoCommit(bool isEnable)
[設定] 自動コミット設定.
void OnCatch(void) const
[表示] 内容表示
Definition: TnbException.h:69
配列型情報管理テンプレート
Definition: TnbVector.h:75
virtual INDEX Add(const TYP &t)
[追加] 要素一つ追加.
Definition: TnbVector.h:383
size_t GetSize(void) const
[取得] サイズ取得
Definition: TnbDef.h:665
void Resize(size_t l)
[設定] サイズ再設定
Definition: TnbDef.h:672
void Reset(size_t l, const TYP *P)
[設定] 再設定
Definition: TnbDef.h:690
const TYP * Ref(void) const
[取得] ポインタ取得
Definition: TnbDef.h:712
TNB::CPointerHandleBaseT< SQLHSTMT, TPhFreeStmtHandle > CStmtHandle
簡易 SQL アクセサ用 STMT ハンドルハンドル.
size_t GetLen(LPCSTR lpsz)
[計算] 文字列長計算(ASCII/SJIS用)
Definition: TnbStrLib.h:44
int ToInt(LPCSTR lpsz, int iBase=10)
[変換] INT変換(ASCII/SJIS用).
Definition: TnbStrLib.h:367
void Zero(V &value)
[設定] ゼロクリア.
Definition: TnbDef.h:399
TNB Library
Definition: TnbDoxyTitle.txt:2
CStr ToString(const CSingleSetT< TYP > &v, TCHAR period=_T(','))
[変換] 文字列化.
Definition: TnbNumberList.h:75
システムタイム型.
Definition: TnbTime.h:876
WORD wYear
Definition: TnbTime.h:877
WORD wSecond
Definition: TnbTime.h:883
WORD wMonth
Definition: TnbTime.h:878
WORD wHour
Definition: TnbTime.h:881
WORD wDay
Definition: TnbTime.h:880
WORD wMinute
Definition: TnbTime.h:882
virtual TYP Get(INDEX index) const
[取得] 要素の取得.