• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

ocipl.cpp

Go to the documentation of this file.
00001 
00002  //
00003  // ocipl.cpp
00004  //
00005  // Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2014, 2017 Martin Fuchs <martin-fuchs@gmx.net>
00006  //
00007  // OCIPL Version 1.8
00008  //
00009 
00010  /// \file ocipl.cpp
00011  /// OCIPL implementation file
00012 
00013 
00014 /*
00015 
00016   All rights reserved.
00017 
00018   Redistribution and use in source and binary forms, with or without
00019   modification, are permitted provided that the following conditions are met:
00020 
00021   * Redistributions of source code must retain the above copyright
00022     notice, this list of conditions and the following disclaimer.
00023   * Redistributions in binary form must reproduce the above copyright
00024     notice, this list of conditions and the following disclaimer in
00025     the documentation and/or other materials provided with the
00026     distribution.
00027 
00028   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00029   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00030   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00031   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00032   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00033   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00034   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00035   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00036   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00037   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00038   POSSIBILITY OF SUCH DAMAGE.
00039 
00040 */
00041 
00042 #ifndef OCIPL_NO_COMMENT
00043 #define OCIPL_NO_COMMENT    // no #pragma comment(lib, ...) statements in .lib files -> free selection of orasql library
00044 #endif
00045 
00046 #define _olint  // for #define CONST const
00047 #include "ocipl.h"
00048 
00049 #include <sstream>
00050 #include <locale>
00051 
00052 #include <assert.h>
00053 #include <time.h>
00054 
00055 
00056 #ifndef _MSC_VER
00057 char* strupr(char* s)
00058 {
00059     for(char*p=s; *p; ++p)
00060         *p = toupper(*p);
00061 
00062     return s;
00063 }
00064 #endif
00065 
00066 size_t max_strlen(const char* s, size_t max_len)
00067 {
00068     if (!s)
00069         return 0;
00070 
00071     size_t cnt = 0;
00072 
00073     while(cnt<max_len && *s)
00074         ++cnt, ++s;
00075 
00076     return cnt;
00077 }
00078 
00079 char* max_strdup(const char* s, size_t max_len)
00080 {
00081     if (!s)
00082         return NULL;
00083 
00084     size_t l = max_strlen(s, max_len);
00085     char* ret = (char*) malloc(l+1);
00086 
00087 #ifdef __STDC_WANT_SECURE_LIB__
00088     strncpy_s(ret, l+1, s, l);
00089 #else
00090     strncpy(ret, s, l);
00091 #endif
00092     ret[l] = '\0';
00093 
00094     return ret;
00095 }
00096 
00097 
00098 namespace OCIPL {
00099 
00100 
00101  // We use bulk fetch with 100 rows per default.
00102 int g_OCIPL_BULK_ROWS = 100;
00103 
00104 
00105 void throw_oci_exception(OCIError* errh, sword res)
00106 {
00107     switch(res) {
00108       case OCI_ERROR:
00109       case OCI_NO_DATA:
00110         THROW_OCI_EXCEPTION(errh);
00111         break;
00112 
00113       case OCI_INVALID_HANDLE:
00114         THROW_OCI_EXCEPTION("invalid handle");
00115         break;
00116 
00117         //@todo handle other error states
00118 
00119     }
00120 }
00121 
00122 void throw_oci_exception(OCIEnv* envh, sword res)
00123 {
00124     switch(res) {
00125       case OCI_ERROR:
00126       case OCI_NO_DATA:
00127       case OCI_INVALID_HANDLE:
00128         THROW_OCI_EXCEPTION(envh);
00129 
00130         //@todo handle other error states
00131 
00132     }
00133 }
00134 
00135 
00136 OciException::OciException(OCIEnv* envh, const char* file, int line)
00137 {
00138     OraText buffer[1024];
00139 
00140     sb4 errorcode;
00141     sword res = OCIErrorGet(envh, 1, NULL, &errorcode, buffer, sizeof(buffer), OCI_HTYPE_ENV);
00142 
00143     if (res == OCI_SUCCESS) {
00144         _sql_error_code = errorcode;
00145         _msg = max_strdup((const char*)buffer, COUNTOF(buffer));
00146     } else {
00147         _sql_error_code = 0;
00148         _msg = NULL;
00149     }
00150 
00151     _file = file;
00152     _line = line;
00153     _parse_offset = 0;
00154 }
00155 
00156 OciException::OciException(OCIError* errh, const char* file, int line)
00157 {
00158     TCHAR buffer[1024];
00159 
00160     sb4 errorcode;
00161     sword res = OCIErrorGet(errh, 1, NULL, &errorcode, (OraText*)buffer, sizeof(buffer), OCI_HTYPE_ERROR);
00162 
00163     if (res == OCI_SUCCESS) {
00164         _sql_error_code = errorcode;
00165 #ifdef _UNICODE
00166         char nbuffer[2048];
00167 #ifdef _MSC_VER
00168         std::_USE(std::locale::empty(), std::ctype<wchar_t>)
00169 #else
00170         std::use_facet<std::ctype<wchar_t> >(std::locale::empty())
00171 #endif
00172                 .narrow((const TCHAR*)buffer, (const TCHAR*)buffer+_tcslen((const TCHAR*)buffer)+1, 0, nbuffer);
00173         _msg = max_strdup(nbuffer, COUNTOF(nbuffer));
00174 #else
00175         _msg = max_strdup(buffer, COUNTOF(buffer));
00176 #endif
00177     } else {
00178         _sql_error_code = 0;
00179         _msg = NULL;
00180     }
00181 
00182     _file = file;
00183     _line = line;
00184     _parse_offset = 0;
00185 }
00186 
00187 OciException::OciException(OCIError* errh, SqlStatement& stmt, const char* file, int line)
00188 {
00189     char buffer[4096];
00190 
00191     sb4 errorcode;
00192 #ifdef _UNICODE
00193     TCHAR wbuffer[4096];
00194 
00195     sword res = OCIErrorGet(errh, 1, NULL, &errorcode, (OraText*)wbuffer, sizeof(wbuffer), OCI_HTYPE_ERROR);
00196 
00197 #ifdef _MSC_VER
00198         std::_USE(std::locale::empty(), std::ctype<wchar_t>)
00199 #else
00200         std::use_facet<std::ctype<wchar_t> >(std::locale::empty())
00201 #endif
00202                 .narrow((const TCHAR*)wbuffer, (const TCHAR*)wbuffer+_tcslen((const TCHAR*)wbuffer)+1, 0, buffer);
00203 #else
00204     sword res = OCIErrorGet(errh, 1, NULL, &errorcode, (OraText*)buffer, sizeof(buffer), OCI_HTYPE_ERROR);
00205 #endif
00206 
00207     ub4 size = sizeof(_parse_offset);
00208     if (OCIAttrGet(stmt, OCI_HTYPE_STMT, &_parse_offset, &size, OCI_ATTR_PARSE_ERROR_OFFSET, errh) != OCI_SUCCESS)
00209         _parse_offset = 0;
00210 
00211     if (res == OCI_SUCCESS)
00212         _sql_error_code = errorcode;
00213     else {
00214         *buffer = '\0';
00215         _sql_error_code = 0;
00216     }
00217 
00218     _last_sql = stmt.get_last_sql();
00219 
00220     _file = file;
00221     _line = line;
00222 
00223     if (!_last_sql.empty()) {
00224         file = stmt.get_last_file();
00225 
00226          // copy source code position from statement if available
00227         if (file) {
00228             _file = file;
00229             _line = stmt.get_last_line();
00230         }
00231 
00232         const TCHAR* sql = _last_sql.c_str();
00233         size_t l = max_strlen(buffer, COUNTOF(buffer));
00234 
00235         int line = 1;
00236         const TCHAR* s = sql;
00237         const TCHAR* e = sql + _parse_offset;
00238         const TCHAR* lp = sql;
00239 
00240         while(s < e)
00241             if (*s == '\n') {
00242                 ++line;
00243 
00244                 if (*++s == '\r')
00245                     ++s;
00246 
00247                 lp = s;
00248             } else
00249                 ++s;
00250 
00251         int column = 1 + (s-lp);
00252 
00253 #ifdef __STDC_WANT_SECURE_LIB__
00254         char* b = buffer+l + _snprintf_s(buffer+l, sizeof(buffer)-l, _TRUNCATE, "\nerror at SQL position %d [%d.%d]:\n", _parse_offset, line, column);
00255 #else
00256         char* b = buffer+l + _snprintf(buffer+l, sizeof(buffer)-l-1, "\nerror at SQL position %d [%d.%d]:\n", _parse_offset, line, column);
00257 #endif
00258         char* p = b;
00259         s = lp;
00260         while(*s && *s!='\n' && p<buffer+sizeof(buffer)-3)
00261             *p++ = *s++;
00262 
00263         *p++ = '\n';
00264 
00265         b = p;
00266         const TCHAR* err_ptr = sql + _parse_offset;
00267         s = lp;
00268         for(; s<err_ptr && p<buffer+sizeof(buffer)-2; ++s) {
00269             if (*s=='\n' || *sql=='\r')
00270                 p = b;
00271             else if (*s == '\t')
00272                 *p++ = '\t';
00273             else
00274                 *p++ = ' ';
00275         }
00276 
00277         *p++ = '^';
00278         *p = '\0';
00279 
00280         l = max_strlen(buffer, COUNTOF(buffer));
00281 #ifdef __STDC_WANT_SECURE_LIB__
00282         _snprintf_s(buffer+l, sizeof(buffer)-l, _TRUNCATE, "\n\nlast SQL statement:\n%s", sql);
00283 #else
00284         _snprintf(buffer+l, sizeof(buffer)-l, "\n\nlast SQL statement:\n%s", sql);
00285 #endif
00286     }
00287 
00288     _msg = max_strdup(buffer, COUNTOF(buffer));
00289 }
00290 
00291 OciException::OciException(const char* msg, const char* file, int line)
00292 {
00293     _msg = _strdup(msg);
00294     _file = file;
00295     _line = line;
00296     _sql_error_code = 0;
00297 }
00298 
00299 OciException::OciException(const OciException& other)
00300 {
00301     _sql_error_code = other._sql_error_code;
00302     _msg = _strdup(other._msg);
00303     _file = other._file;
00304     _line = other._line;
00305     _last_sql = other._last_sql;
00306 }
00307 
00308 
00309 OciException::~OciException() throw()
00310 {
00311     free(_msg);
00312 }
00313 
00314 
00315 #ifndef _NO_ESQL
00316 
00317 #include <sql2oci.h>
00318 
00319 #ifdef _MSC_VER
00320 #if ORACLE_VERSION>=110
00321 #pragma comment(lib, "orasql11")
00322 #elif ORACLE_VERSION>=100
00323 #pragma comment(lib, "orasql10")
00324 #elif ORACLE_VERSION>=90
00325 #pragma comment(lib, "orasql9")
00326 #elif ORACLE_VERSION>=81    // no orasql library for Oracle 8.0 available
00327 #pragma comment(lib, "orasql8")
00328 #endif
00329 #endif
00330 
00331 #if ORACLE_VERSION>=81  // no SQLEnvGet() and SQLSvcCtxGet() for Oracle 8.0.x
00332 OciConnection* OciConnection::CreateFromESqlContext(void* context)
00333 {
00334     OCIEnv* envhp = NULL;
00335     sword res = SQLEnvGet(context, &envhp);
00336 
00337     if (res != OCI_SUCCESS)
00338         return NULL;
00339 
00340     OCISvcCtx* svchp = NULL;
00341     res = SQLSvcCtxGet(context, NULL, 0, &svchp);
00342 
00343     oci_check_error(envhp, res);
00344 
00345     return new OciConnection(envhp, svchp);
00346 }
00347 #endif
00348 
00349 #endif // _NO_ESQL
00350 
00351 
00352  /// cancel a pending OCI call in the worker thread
00353 void OciConnection::cancel()
00354 {
00355     sword res = OCIBreak(_ctx, _env._errh);
00356 
00357     oci_check_error(_env._errh, res);
00358 }
00359 
00360 #if ORACLE_VERSION>=81
00361  /// reset() is to be called after handling the cancellation in the calling worker thread.
00362 void OciConnection::reset()
00363 {
00364     sword res = OCIReset(_ctx, _env._errh);
00365 
00366     oci_check_error(_env._errh, res);
00367 }
00368 #endif
00369 
00370 
00371  // commit the current transaction
00372 void OciContext::commit(ub4 flags)
00373 {
00374     LocalOciState state(*this, OS_TRANSACTION);
00375 
00376     sword res = OCITransCommit(_handle, _env._errh, flags);
00377     oci_check_error(_env, res);
00378 
00379     _trans_cnt = 0;
00380 }
00381 
00382  // rollback the current transaction
00383 void OciContext::rollback(ub4 flags)
00384 {
00385     LocalOciState state(*this, OS_TRANSACTION);
00386 
00387     sword res = OCITransRollback(_handle, _env._errh, flags);
00388     oci_check_error(_env, res);
00389 
00390     _trans_cnt = 0;
00391 }
00392 
00393 
00394 SqlString& SqlString::operator=(const TCHAR* s)
00395 {
00396     size_t l = s? _tcslen(s): 0;
00397     if (l > _blen)
00398         resize(l);  // resize for longer new strings
00399 
00400     _tcscpy_s(_str, _blen+1, s?s:TEXT(""));
00401     _ind = l>0? 0: -1;
00402     return *this;
00403 }
00404 
00405 SqlString& SqlString::operator=(const tstring& s)
00406 {
00407     if (!s.empty()) {
00408         size_t l = s.length();
00409         if (_blen < l)
00410             resize(l);  // resize for longer new strings
00411 
00412         memcpy(_str, s.c_str(), (l+1)*sizeof(char));
00413         _ind = 0;
00414     } else {
00415         *_str = '\0';
00416         _ind = -1;
00417     }
00418 
00419     return *this;
00420 }
00421 
00422 
00423 int number_to_int(const oraclenumber& val, OCIError* errh)
00424 {
00425     int x;
00426 
00427 #if ORACLE_VERSION>=81
00428      // Oracle Version >= 8.1.x
00429     boolean isInt;
00430     sword res = OCINumberIsInt(errh, (OCINumber*)&val, &isInt);
00431 
00432     if (res==OCI_SUCCESS && isInt)
00433     {
00434         res = OCINumberToInt(errh, (OCINumber*)&val, sizeof(x), OCI_NUMBER_SIGNED, &x);
00435         oci_check_error(errh, res);
00436     }
00437     else
00438 #else
00439      // OCI.DLL of Oracle Version 8.0
00440     sword res = OCINumberToInt(errh, (OCINumber*)&val, sizeof(x), OCI_NUMBER_SIGNED, &x);
00441 
00442     if (res != OCI_SUCCESS)
00443 #endif
00444     {
00445         double d = number_to_double(val, errh);
00446 
00447         x = int(d + .5);
00448     }
00449 
00450     //x = atoi(str(true).c_str());
00451 
00452     return x;
00453 }
00454 
00455 #ifdef _MSC_VER
00456 LONGLONG number_to_int64(const oraclenumber& val, OCIError* errh, int null)
00457 {
00458     LONGLONG x;
00459 
00460     sword res = OCINumberToInt(errh, (OCINumber*)&val, sizeof(x), OCI_NUMBER_SIGNED, &x);
00461     oci_check_error(errh, res);
00462 
00463     return x;
00464 }
00465 #endif
00466 
00467 double number_to_double(const oraclenumber& val, OCIError* errh)
00468 {
00469     double x;
00470 
00471     sword res = OCINumberToReal(errh, (OCINumber*)&val, sizeof(x), &x);
00472     oci_check_error(errh, res);
00473 
00474     return x;
00475 }
00476 
00477 tstring number_to_str(const oraclenumber& val, OCIError* errh, const TCHAR* fmt, const TCHAR* nls_fmt)
00478 {
00479     OraText buffer[128];
00480     ub4 l = sizeof(buffer);
00481 
00482     sword res = OCINumberToText(errh,
00483                         (OCINumber*)&val,
00484                         (const OraText*)fmt, (ub4)_tcslen(fmt)*sizeof(TOraText),
00485                         (const OraText*)nls_fmt, (ub4)_tcslen(nls_fmt)*sizeof(TOraText),
00486                         &l, buffer);
00487 
00488     oci_check_error(errh, res);
00489 
00490 //  const TCHAR* p = (const TCHAR*)buffer;
00491 //  while(istspace(*p))
00492 //      ++p;
00493 
00494     return (const TCHAR*)buffer;//p
00495 }
00496 
00497 
00498 SqlNumber::SqlNumber(const oraclenumber* pnum)
00499 {
00500     memcpy(&_val.exp, &pnum->exp, pnum->len);
00501     _val.len = pnum->len;
00502     _ind.set();
00503 }
00504 
00505 SqlNumber::SqlNumber(OCIError* errh, const TCHAR* str, const TCHAR* fmt, const TCHAR* nls_fmt)
00506 {
00507     if (str) {
00508         while(istspace(*str))
00509             ++str;
00510 
00511         if (*str) {
00512             sword res = OCINumberFromText(errh,
00513                                 (const OraText*)str, (ub4)_tcslen(str)*sizeof(TOraText),
00514                                 (const OraText*)fmt, (ub4)_tcslen(fmt)*sizeof(TOraText),
00515                                 (const OraText*)nls_fmt, (ub4)_tcslen(nls_fmt)*sizeof(TOraText),
00516                                 (OCINumber*)&_val);
00517 
00518             oci_check_error(errh, res);
00519 
00520             _ind.set();
00521         } else
00522         _ind.clear();
00523     } else
00524         _ind.clear();
00525 }
00526 
00527 
00528 /*
00529 Oracle stores values of the NUMBER datatype in a variable-length format.
00530 The first byte is the exponent and is followed by 1 to 20 mantissa bytes.
00531 The high-order bit of the exponent byte is the sign bit; it is set for
00532 positive numbers and it is cleared for negative numbers. The lower 7 bits
00533 represent the exponent, which is a base-100 digit with an offset of 65.
00534 
00535 To calculate the decimal exponent, add 65 to the base-100 exponent and
00536 add another 128 if the number is positive. If the number is negative, you
00537 do the same, but subsequently the bits are inverted.
00538 For example, -5 has a base-100 exponent = 62 (0x3e). The decimal exponent
00539 is thus (~0x3e) -128 - 65 = 0xc1 -128 -65 = 193 -128 -65 = 0.
00540 
00541 Each mantissa byte is a base-100 digit, in the range 1 to 100.
00542 For positive numbers, the digit has 1 added to it. So, the mantissa
00543 digit for the value 5 is 6. For negative numbers, instead of adding 1
00544 the digit is subtracted from 101. So, the mantissa digit for the
00545 number -5 is 96 (101 - 5). Negative numbers have a byte containing 102
00546 appended to the data bytes. However, negative numbers that have
00547 20 mantissa bytes do not have the trailing 102 byte. Because the
00548 mantissa digits are stored in base-100, each byte can represent two
00549 decimal digits. The mantissa is normalized; leading zeroes are not stored.
00550 Up to 20 data bytes can represent the mantissa. However, only 19 are
00551 guaranteed to be accurate. The 19 data bytes, each representing
00552 a base-100 digit, yield a maximum precision of 38 digits for an
00553 internal datatype NUMBER.
00554 */
00555 
00556 /*
00557 tstring SqlNumber::str(bool internal) const
00558 {
00559     int sign = _val.exp & 0x80;
00560     int exp;
00561 
00562     tstring ret = sign? internal?TEXT(" "):TEXT(""): TEXT("-");
00563 
00564     if (sign) {
00565         if (_val.exp == 0x80)
00566             return TEXT("0");
00567 
00568         exp = (_val.exp & 0x7F) - 65;
00569     } else
00570         exp = 62 - (_val.exp & 0x7F);
00571 
00572     if (exp < 0) {
00573         ret.append(TEXT("0."));
00574 
00575         for(int e=exp; ++e<0; )
00576             ret.append(1, '0');
00577     }
00578 
00579     const ub1* p = _val.mant;
00580 
00581     if (sign) {
00582         for(int n=_val.len; ; ) {
00583             int x = *p++ - 1;
00584 
00585             if (internal || x/10 || !ret.empty())   // don't print leading zeros
00586                 ret.append(1, '0' + x/10);
00587 
00588             ret.append(1, '0' + x%10);
00589 
00590             --exp;
00591             if (--n <= 1)
00592                 break;
00593 
00594             if (exp == -1)
00595                 ret.append(1, '.');
00596         }
00597     } else {
00598         for(int n=_val.len; ; ) {
00599             int x = 101 - *p++;
00600 
00601             ret.append(1, '0' + x/10);
00602             ret.append(1, '0' + x%10);
00603 
00604             --exp;
00605             if (--n <= 2)
00606                 break;
00607 
00608             if (exp == -1)
00609                 ret.append(1, '.');
00610         }
00611 
00612         if (_val.len == 21) {
00613             int x = 101 - *p++;
00614 
00615             ret.append(1, '0' + x/10);
00616             ret.append(1, '0' + x%10);
00617 
00618             --exp;
00619         }// else
00620         //  assert(*p==102);
00621     }
00622 
00623     if (internal)
00624         for(; exp>=0; --exp)
00625             ret.append(TEXT("00"));
00626     else if (_tcschr(ret.c_str(), '.')) { // remove trailing zeros
00627         while(!ret.empty() && ret.at(ret.length()-1)=='0')
00628             ret.resize(ret.length()-1);
00629 
00630         if (!ret.empty() && ret.at(ret.length()-1)=='.')
00631             ret.resize(ret.length()-1);
00632     }
00633 
00634     return ret;
00635 }
00636 */
00637 
00638 
00639 tstring ocidate_to_string(const OCIDate& date)  // Usage of OCIDateToText would also be possible.
00640 {
00641     TCHAR buffer[40];
00642 
00643 #ifdef __STDC_WANT_SECURE_LIB__
00644     _stprintf_s(buffer, COUNTOF(buffer),
00645 #else
00646     _stprintf(buffer,
00647 #endif
00648                 TEXT("%02d.%02d.%04d %02d:%02d:%02d"),
00649                 date.OCIDateDD, date.OCIDateMM, date.OCIDateYYYY,
00650                 date.OCIDateTime.OCITimeHH, date.OCIDateTime.OCITimeMI, date.OCIDateTime.OCITimeSS);
00651 
00652     return buffer;
00653 }
00654 
00655 tstring ocidate_to_short_string(const OCIDate& date)
00656 {
00657     TCHAR buffer[40];
00658 
00659 #ifdef __STDC_WANT_SECURE_LIB__
00660     _stprintf_s(buffer, COUNTOF(buffer),
00661 #else
00662     _stprintf(buffer,
00663 #endif
00664                 TEXT("%02d.%02d.%04d"),
00665                 date.OCIDateDD, date.OCIDateMM, date.OCIDateYYYY);
00666 
00667     return buffer;
00668 }
00669 
00670 struct tm* ocidate_to_gmt(const OCIDate& date)
00671 {
00672     struct tm ltime = {
00673         date.OCIDateTime.OCITimeSS,
00674         date.OCIDateTime.OCITimeMI,
00675         date.OCIDateTime.OCITimeHH,
00676         date.OCIDateDD,
00677         date.OCIDateMM - 1,
00678         date.OCIDateYYYY - 1900,
00679         -1,
00680         -1,
00681         -1
00682     };
00683 
00684     time_t time = mktime(&ltime);
00685     assert(time!=-1);
00686 
00687 #ifdef __STDC_WANT_SECURE_LIB__
00688     struct tm newtime;
00689     gmtime_s(&newtime, &time);
00690     struct tm* gmt = &newtime;
00691 #else
00692     struct tm* gmt = gmtime(&time);
00693 #endif
00694 
00695     return gmt;
00696 }
00697 
00698 struct tm* ocidate_to_lctime(const OCIDate& date)
00699 {
00700     struct tm ltime = {
00701         date.OCIDateTime.OCITimeSS,
00702         date.OCIDateTime.OCITimeMI,
00703         date.OCIDateTime.OCITimeHH,
00704         date.OCIDateDD,
00705         date.OCIDateMM - 1,
00706         date.OCIDateYYYY - 1900,
00707         -1,
00708         -1,
00709         -1
00710     };
00711 
00712     time_t time = mktime(&ltime);
00713     assert(time!=-1);
00714 
00715 #ifdef __STDC_WANT_SECURE_LIB__
00716     struct tm newtime;
00717     localtime_s(&newtime, &time);
00718     struct tm* lct = &newtime;
00719 #else
00720     struct tm* lct = localtime(&time);
00721 #endif
00722 
00723     return lct;
00724 }
00725 
00726 time_t ocidate_to_time_t(const OCIDate& date)
00727 {
00728     time_t time = mktime(ocidate_to_lctime(date));
00729     assert(time!=-1);
00730 
00731     return time;
00732 }
00733 
00734 #ifdef _WIN32
00735 bool ocidate_to_systemtime(const OCIDate& date, SYSTEMTIME* pSysTime)
00736 {
00737     SYSTEMTIME stime;
00738 
00739     stime.wYear = date.OCIDateYYYY;
00740     stime.wMonth = date.OCIDateMM;
00741     stime.wDayOfWeek = 0;
00742     stime.wDay = date.OCIDateDD;
00743     stime.wHour = date.OCIDateTime.OCITimeHH;
00744     stime.wMinute = date.OCIDateTime.OCITimeMI;
00745     stime.wSecond = date.OCIDateTime.OCITimeSS;
00746     stime.wMilliseconds = 0;
00747 
00748      // Validate date and fill the wDayOfWeek field
00749     FILETIME ftime;
00750 
00751     if (!SystemTimeToFileTime(&stime, &ftime))
00752         return false;
00753 
00754     if (!FileTimeToSystemTime(&ftime, pSysTime))
00755         return false;
00756 
00757     return true;
00758 }
00759 #endif
00760 
00761 
00762 tstring ocidatetime_to_string(const ocidatetime& date)
00763 {
00764     TCHAR buffer[40];
00765 
00766 #ifdef __STDC_WANT_SECURE_LIB__
00767     _stprintf_s(buffer, COUNTOF(buffer),
00768 #else
00769     _stprintf(buffer,
00770 #endif
00771                 TEXT("%02d.%02d.%04d %02d:%02d:%02d"),
00772                 date.day, date.month, 100*(date.century-100)+(date.year-100),
00773                 date.hour-1, date.minute-1, date.second-1);
00774 
00775     return buffer;
00776 }
00777 
00778 
00779 OciDate::OciDate(const OCIDate& date, OCIInd ind)
00780  :  SqlValue(ind)
00781 {
00782     OCIDate::operator=(date);
00783 }
00784 
00785 OciDate::OciDate(const ocidatetime& date, OCIInd ind)
00786  :  SqlValue(ind)
00787 {
00788     OCIDateYYYY = 100*(date.century-100)+(date.year-100);
00789     OCIDateMM = date.month;
00790     OCIDateDD = date.day;
00791     OCIDateTime.OCITimeHH = date.hour-1;
00792     OCIDateTime.OCITimeMI = date.minute-1;
00793     OCIDateTime.OCITimeSS = date.second-1;
00794 }
00795 
00796 OciDate::OciDate(OCIError* errh, const TCHAR* str, const TCHAR* fmt)
00797 {
00798     if (str) {
00799         while(istspace(*str))
00800             ++str;
00801 
00802         if (*str) {
00803             sword res = OCIDateFromText(errh, (const OraText*)str, (ub4)_tcslen(str)*sizeof(TOraText),
00804                                               (const OraText*)fmt, (ub4)_tcslen(fmt)*sizeof(TOraText), NULL/*lang*/, 0, this);
00805 
00806             oci_check_error(errh, res);
00807 
00808             _ind.set();
00809         } else
00810             _ind.clear();
00811     } else
00812         _ind.clear();
00813 }
00814 
00815 OciDate::OciDate(struct tm* t)
00816 {
00817     OCIDateYYYY = t->tm_year + 1900;
00818     OCIDateMM = t->tm_mon + 1;
00819     OCIDateDD = t->tm_mday;
00820     OCIDateTime.OCITimeHH = t->tm_hour;
00821     OCIDateTime.OCITimeMI = t->tm_min;
00822     OCIDateTime.OCITimeSS = t->tm_sec;
00823 
00824     ind().set();
00825 }
00826 
00827 int OciDate::compare(const OciDate& other) const
00828 {
00829     if (OCIDateYYYY < other.OCIDateYYYY)
00830         return -1;
00831     else if (OCIDateYYYY > other.OCIDateYYYY)
00832         return 1;
00833 
00834     if (OCIDateMM < other.OCIDateMM)
00835         return -1;
00836     else if (OCIDateMM > other.OCIDateMM)
00837         return 1;
00838 
00839     if (OCIDateDD < other.OCIDateDD)
00840         return -1;
00841     else if (OCIDateDD > other.OCIDateDD)
00842         return 1;
00843 
00844     if (OCIDateTime.OCITimeHH < other.OCIDateTime.OCITimeHH)
00845         return -1;
00846     else if (OCIDateTime.OCITimeHH > other.OCIDateTime.OCITimeHH)
00847         return 1;
00848 
00849     if (OCIDateTime.OCITimeMI < other.OCIDateTime.OCITimeMI)
00850         return -1;
00851     else if (OCIDateTime.OCITimeMI > other.OCIDateTime.OCITimeMI)
00852         return 1;
00853 
00854     if (OCIDateTime.OCITimeSS < other.OCIDateTime.OCITimeSS)
00855         return -1;
00856     else if (OCIDateTime.OCITimeSS > other.OCIDateTime.OCITimeSS)
00857         return 1;
00858 
00859     return 0;
00860 }
00861 
00862 
00863 tstring ColumnTypeInfo::get_type_str(bool show_null) const
00864 {
00865     tostringstream str;
00866 
00867     switch(_data_type) {
00868       case OCI_TYPECODE_CHAR:
00869         str << TEXT("CHAR(") << _width << TEXT(")");
00870         break;
00871 
00872       case OCI_TYPECODE_VARCHAR:
00873         str << TEXT("VARCHAR(") << _width << TEXT(")");
00874         break;
00875 
00876       case OCI_TYPECODE_VARCHAR2:
00877         str << TEXT("VARCHAR2(") << _width << TEXT(")");
00878         break;
00879 
00880       case OCI_TYPECODE_NUMBER:
00881         if (_precision == 0)
00882             str << TEXT("NUMBER");
00883         else if (_scale == -127) {
00884             if (_precision == 126)
00885                 str << TEXT("FLOAT");
00886             else
00887                 str << TEXT("FLOAT(") << (int)_precision << TEXT(")");
00888         } else if (_scale)
00889             str << TEXT("NUMBER(") << (int)_precision << TEXT(",") << (int)_scale << TEXT(")");
00890         else
00891             str << TEXT("NUMBER(") << (int)_precision << TEXT(")");
00892         break;
00893 
00894 #ifdef SQLT_BFLOAT
00895       case OCI_TYPECODE_BFLOAT:
00896         str << TEXT("BINARY_FLOAT");
00897         break;
00898 
00899       case OCI_TYPECODE_BDOUBLE:
00900         str << TEXT("BINARY_DOUBLE");
00901         break;
00902 #endif
00903 
00904       case OCI_TYPECODE_DATE:
00905         str << TEXT("DATE");
00906         break;
00907 
00908 #if ORACLE_VERSION>=81
00909       case OCI_TYPECODE_TIMESTAMP:
00910         str << TEXT("TIMESTAMP");
00911         break;
00912 #endif
00913 
00914       case OCI_TYPECODE_BLOB:
00915         str << TEXT("BLOB");
00916         break;
00917 
00918       case OCI_TYPECODE_BFILE:
00919         str << TEXT("BFILE");
00920         break;
00921 
00922       case OCI_TYPECODE_CLOB:
00923         str << TEXT("CLOB");
00924         break;
00925 
00926       case OCI_TYPECODE_CFILE:
00927         str << TEXT("CFILE");
00928         break;
00929 
00930       case SQLT_LNG:
00931         str << TEXT("LONG");
00932         break;
00933 
00934       default:
00935         str << TEXT("unknown");
00936     }
00937 
00938     if (show_null)
00939         if (!_nullable)
00940             str << TEXT(" NOT NULL");
00941         else
00942             str << TEXT(" NULL");
00943 
00944     return str.str();
00945 }
00946 
00947 
00948 SqlStatement::~SqlStatement()
00949 {
00950     delete _res;
00951     _res = NULL;
00952 }
00953 
00954 
00955 #ifndef FORCE_CODEPOS
00956 void SqlStatement::prepare(const tstring& sql, ub4 lang)
00957 {
00958     prepare(sql, NULL, -1, lang);
00959 }
00960 #endif
00961 
00962 void SqlStatement::prepare(const tstring& sql, const char* file, int line, ub4 lang)
00963 {
00964     delete _res;
00965     _res = NULL;
00966 
00967     _last_sql = sql;
00968     _last_file = file;
00969     _last_line = line;
00970 
00971     LocalOciState state(_ctx, OS_PREPARE);
00972 
00973     sword res = OCIStmtPrepare(_handle/*stmtp*/, _env._errh, (OraText*)sql.c_str(), (ub4)sql.length()*sizeof(TOraText), lang, OCI_DEFAULT);
00974     oci_check_error(_env, res);
00975 
00976     _state = PREPARED;
00977     _stmt_type = -1;
00978     _result_buffers = 0;
00979 }
00980 
00981 
00982 #if ORACLE_VERSION>=90
00983 
00984 #ifndef FORCE_CODEPOS
00985 void SqlCacheStmt::prepare(const tstring& sql, ub4 lang)
00986 {
00987     prepare(sql, NULL, -1, lang);
00988 }
00989 #endif
00990 
00991 void SqlCacheStmt::prepare(const tstring& sql, const char* file, int line, ub4 lang)
00992 {
00993     if (!_tag.empty())
00994         release();
00995 
00996     tstring& tag = _stmt_cache[sql];
00997 
00998     if (tag.empty()) {
00999         TCHAR buffer[16];
01000 #ifdef __STDC_WANT_SECURE_LIB__
01001         _stprintf_s(buffer, COUNTOF(buffer),
01002 #else
01003         _stprintf(buffer,
01004 #endif
01005         TEXT("%x"), _stmt_cache.size());
01006         tag = buffer;
01007     }
01008 
01009     _last_sql = sql;
01010     _last_file = file;
01011     _last_line = line;
01012     _tag = tag;
01013 
01014     LocalOciState state(_ctx, OS_PREPARE);
01015 
01016     sword res = OCIStmtPrepare2(_ctx, &_handle/*stmtp*/, _env._errh,
01017                                 (OraText*)sql.c_str(), (ub4)sql.length()*sizeof(TOraText),
01018                                 (OraText*)_tag.c_str(), (ub4)_tag.length()*sizeof(TOraText), lang, OCI_DEFAULT);
01019     oci_check_error(_env, res);
01020 
01021     _state = PREPARED;
01022     _stmt_type = -1;
01023     _result_buffers = 0;
01024 }
01025 
01026 void SqlCacheStmt::release()
01027 {
01028     delete _res;
01029     _res = NULL;
01030 
01031     LocalOciState state(_ctx, OS_RELEASE);
01032 
01033     sword res = OCIStmtRelease(_handle, _env._errh, (OraText*)_tag.c_str(), (ub4)_tag.length()*sizeof(TOraText), OCI_DEFAULT);
01034     _handle = 0;
01035 
01036     oci_check_error(_env, res);
01037 }
01038 
01039 SqlCacheStmt::~SqlCacheStmt()
01040 {
01041     release();
01042 }
01043 
01044 #endif
01045 
01046 
01047 int SqlStatement::get_stmt_type() const
01048 {
01049     if (_stmt_type == -1) {
01050         ub2 stmt_type;  // OCI_STMT_SELECT, OCI_STMT_UPDATE, ...
01051         ub4 size = sizeof(stmt_type);
01052 
01053         sword res = OCIAttrGet(_handle/*stmtp*/, get_type_id(), &stmt_type, &size, OCI_ATTR_STMT_TYPE, _env._errh);
01054         oci_check_error(_env, res);
01055 
01056         _stmt_type = stmt_type;
01057     }
01058 
01059     return _stmt_type;
01060 }
01061 
01062 
01063 ub4 SqlStatement::fetched_rows() const
01064 {
01065 /*
01066  if ORACLE_VERSION>=90
01067     ub4 row_count;
01068     ub4 size = sizeof(row_count);
01069 
01070     sword res = OCIAttrGet(_handle, get_type_id(), &row_count, &size, OCI_ATTR_ROWS_FETCHED, _env._errh);
01071     oci_check_error(_env, res);
01072 
01073     return row_count;
01074  else
01075 */
01076     return _last_fetched_row - _last_row;
01077 }
01078 
01079 
01080 ub4 SqlStatement::row_count() const
01081 {
01082     ub4 row_count;
01083     ub4 size = sizeof(row_count);
01084 
01085     sword res = OCIAttrGet(_handle/*stmtp*/, get_type_id(), &row_count, &size, OCI_ATTR_ROW_COUNT, _env._errh);
01086     oci_check_error(_env, res);
01087 
01088     return row_count;
01089 }
01090 
01091 
01092 OCIDefine* SqlStatement::bind_result(int idx, DefinePar par, OCIDefine* defnp)
01093 {
01094     sword res = OCIDefineByPos(_handle/*stmtp*/, &defnp, _env._errh, idx+1,
01095                                 par.valuep, par.value_sz, par.dty, par.indp,
01096                                 (ub2*)0, (ub2*)0, OCI_DEFAULT);
01097     oci_check_error(_env, res);
01098 
01099     if (_state & DEFINED)
01100         assert(_result_buffers==par.buffers);   // check if all bind variables have the same buffer count
01101 
01102     if (_state & EXECUTED) {
01103         delete _res;
01104         _res = NULL;
01105 
01106         _state = (_state|DEFINED) & ~(FETCHED|EOF_DATA);
01107     } else
01108         _state |= DEFINED;
01109 
01110     _result_buffers = par.buffers;
01111 
01112     return defnp;   // Implicitly allocated define handles are freed automatically with the statement handle.
01113 }
01114 
01115 
01116 void SqlStatement::execute(ub4 rows, ub4 mode)
01117 {
01118      // a SELECT statement without ready defined variables?
01119     if (!(_state&DEFINED) && get_stmt_type()==OCI_STMT_SELECT) {
01120         execute_internal(0, mode);
01121 
01122          // define resultset variables
01123         assert(!_res);
01124 
01125         if (rows > 0) {
01126             _res = new SqlResult(*this, rows);
01127             fetch(rows);
01128         } else {
01129             _res = new SqlResult(*this, _bulk_rows);
01130         }
01131     } else
01132         execute_internal(rows, mode);
01133 }
01134 
01135 
01136 void SqlStatement::execute_fetch(ub4 mode)
01137 {
01138      // A SELECT statement without ready defined variables?
01139     if (!(_state&DEFINED) && get_stmt_type()==OCI_STMT_SELECT) {
01140         execute_internal(0, mode);
01141 
01142          // define resultset variables
01143         assert(!_res);
01144         _res = new SqlResult(*this, _bulk_rows);
01145 
01146         fetch(_result_buffers);
01147     } else
01148         execute_internal(_result_buffers, mode);
01149 }
01150 
01151 
01152 void SqlStatement::execute_internal(ub4 rows, ub4 mode)
01153 {
01154     int stmt_type = get_stmt_type();
01155 
01156     LocalOciState state(_ctx, OS_EXECUTE, stmt_type);
01157 
01158     if (rows==0 && stmt_type==OCI_STMT_SELECT) {
01159          // Optimizing of TCP packets by transfering multiple datasets in one packet
01160         try {
01161             //set_attribute(OCI_ATTR_PREFETCH_MEMORY, 1500);
01162             set_attribute(OCI_ATTR_PREFETCH_ROWS, 10);
01163         } catch(std::exception&) {
01164             // ignore exception of this optional performance tuning
01165         }
01166     }
01167 
01168      // execute and fetch
01169     sword res = OCIStmtExecute(_ctx, _handle, _env._errh, rows, 0/*rowoff*/,
01170                                 (CONST OCISnapshot*)0, (OCISnapshot*)0, mode);
01171 
01172     _last_row = 0;
01173     _last_fetched_row = row_count();
01174 
01175     if (res==OCI_NO_DATA && stmt_type>=OCI_STMT_SELECT && stmt_type<=OCI_STMT_INSERT) {
01176         _state |= EOF_DATA;
01177 
01178         // There are no additional rows pending to be fetched.
01179     } else if (res == OCI_ERROR) {
01180         _state = STMT_ERROR;
01181         //throw OCI_EXCEPTION(_env._errh, *this, CODEPOS);
01182         throw_ocipl_exception(OciException(_env._errh, *this, CODEPOS));
01183     } else {
01184         if (rows > 0)
01185             _state |= EXECUTED|FETCHED;
01186         else
01187             _state = (_state|EXECUTED) & ~(FETCHED|EOF_DATA);
01188 
01189         oci_check_error(_env, res);
01190 
01191         // There may be more rows available to be fetched (for queries) or the DML statement succeeded.
01192     }
01193 }
01194 
01195 
01196 void SqlStatement::fetch(ub4 rows/*=-1*/)
01197 {
01198     if (!(_state & EXECUTED)) {
01199         if (rows == (ub4)-1)
01200             if (!(_state & DEFINED))
01201                 rows = _bulk_rows;  // optimize using bulk fetch
01202             else
01203                 rows = _result_buffers;
01204 
01205         execute(rows);
01206     } else {
01207         if (rows == (ub4)-1)
01208             rows = _result_buffers;
01209 
01210         LocalOciState state(_ctx, OS_FETCH);
01211 
01212 #if ORACLE_VERSION>=90
01213         sword res = OCIStmtFetch2(_handle, _env._errh, rows, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
01214 #else
01215         sword res = OCIStmtFetch(_handle, _env._errh, rows, OCI_FETCH_NEXT, OCI_DEFAULT);
01216 #endif
01217 
01218         _last_row = _last_fetched_row;
01219         _last_fetched_row = row_count();
01220 
01221         if (res != OCI_NO_DATA) {   // more data available or did there occur an error?
01222             _state |= FETCHED;
01223             oci_check_error(_env, res);
01224 
01225             // There may be more rows available to be fetched.
01226         } else {
01227             _state |= EOF_DATA;
01228 
01229             // There are no additional rows pending to be fetched.
01230         }
01231     }
01232 }
01233 
01234 
01235 
01236 void SqlStatement::get_column_type(int idx, ColumnType& info) const
01237 {
01238     dvoid* parmdp;
01239 
01240     sword res = OCIParamGet(_handle, get_type_id(), _env._errh, &parmdp, idx+1);
01241     oci_check_error(_env, res);
01242 
01243     info.init(_env._errh, parmdp);
01244 
01245     res = OCIDescriptorFree(parmdp, OCI_DTYPE_PARAM);
01246     oci_check_error(_env, res);
01247 }
01248 
01249 void ColumnType::init(OCIError* errh, dvoid* handle)
01250 {
01251      // get column name
01252     TOraText* pcol_name = NULL;
01253     ub4 size = sizeof(pcol_name);
01254 
01255     sword res = OCIAttrGet(handle, OCI_DTYPE_PARAM, &pcol_name, &size, OCI_ATTR_NAME, errh);
01256     oci_check_error(errh, res);
01257     _name.assign((const TCHAR*)pcol_name, size);
01258 
01259      // get column data type
01260     size = sizeof(_data_type);
01261     res = OCIAttrGet(handle, OCI_DTYPE_PARAM, &_data_type, &size, OCI_ATTR_DATA_TYPE, errh);
01262     oci_check_error(errh, res);
01263 
01264      // get NULL-ability flag
01265     size = sizeof(_nullable);
01266     res = OCIAttrGet(handle, OCI_DTYPE_PARAM, &_nullable, &size, OCI_ATTR_IS_NULL, errh);
01267     oci_check_error(errh, res);
01268 
01269 #if ORACLE_VERSION>=90
01270      // retrieve the length semantics for the column
01271     size = sizeof(_char_semantics);
01272     res = OCIAttrGet(handle, OCI_DTYPE_PARAM, &_char_semantics, &size, OCI_ATTR_CHAR_USED, errh);
01273     if (res != OCI_SUCCESS)
01274         _char_semantics = 0;
01275 
01276     size = sizeof(_width);
01277     if (_char_semantics)
01278          // get the column width in characters
01279         res = OCIAttrGet(handle, OCI_DTYPE_PARAM, &_width, &size, OCI_ATTR_CHAR_SIZE, errh);
01280     else
01281 #endif
01282          // get the column width in bytes
01283         res = OCIAttrGet(handle, OCI_DTYPE_PARAM, &_width, &size, OCI_ATTR_DATA_SIZE, errh);
01284 
01285     oci_check_error(errh, res);
01286 
01287     switch(_data_type) {
01288       default: //case OCI_TYPECODE_VARCHAR:
01289         _precision = 0;
01290         _scale = -127;
01291         break;
01292 
01293       case OCI_TYPECODE_NUMBER:
01294 #ifdef SQLT_BFLOAT
01295       case OCI_TYPECODE_BFLOAT:
01296       case OCI_TYPECODE_BDOUBLE:
01297 #endif
01298         size = sizeof(_precision);
01299         res = OCIAttrGet(handle, OCI_DTYPE_PARAM, &_precision, &size, OCI_ATTR_PRECISION, errh);
01300         oci_check_error(errh, res);
01301 
01302         size = sizeof(_scale);
01303         res = OCIAttrGet(handle, OCI_DTYPE_PARAM, &_scale, &size, OCI_ATTR_SCALE, errh);
01304         oci_check_error(errh, res);
01305         break;
01306 
01307       case OCI_TYPECODE_DATE:
01308 #if ORACLE_VERSION>=81
01309       //case OCI_TYPECODE_TIME:
01310       //case OCI_TYPECODE_TIMESTAMP:
01311 #endif
01312         _precision = 0;
01313         _scale = -127;
01314         break;
01315     }
01316 }
01317 
01318 
01319 void SqlStatement::print_results(tostream& out, bool header)
01320 {
01321     if (!(_state & EXECUTED))
01322         execute();
01323     else if (!(_state & FETCHED))
01324         fetch(_result_buffers);
01325 
01326     if (header)
01327         _res->print_columns(out);
01328 
01329     int row_cnt = 0;
01330 
01331     for(ResultIterator it(*this); it.has_next(); ++it) {
01332         ++row_cnt;
01333 
01334         out << TEXT("row ") << row_cnt << TEXT(":\n");
01335 
01336         _res->print_values(out, it);
01337 
01338         out << TEXT("\n");
01339     }
01340 }
01341 
01342 
01343 SqlRecord::SqlRecord(SqlStatement& stmt, int rows)
01344  :  _env(stmt._env)
01345 {
01346     stmt.ensure_execute();
01347 
01348     int column_cnt = stmt.get_column_count();
01349 
01350     _values.resize(column_cnt);
01351     ColumnVector::iterator it = _values.begin();
01352 
01353     for(int idx=0; idx<column_cnt; ++idx,++it) {
01354         stmt.get_column_type(idx, it->_type);
01355 
01356         it->_pvar = new SqlVariantArray(it->_type, rows);
01357     }
01358 
01359     //_name_map.clear();
01360 }
01361 
01362 SqlRecord::~SqlRecord()
01363 {
01364     for(ColumnVector::iterator it=_values.begin(); it!=_values.end(); ++it)
01365         delete it->_pvar;
01366 }
01367 
01368 void SqlRecord::alloc_column(size_t col_idx, const ColumnTypeInfo& type, int rows)
01369 {
01370     Data& data = _values[col_idx];
01371 
01372      // (re)allocate variant data buffers
01373     delete data._pvar;
01374     data._pvar = new SqlVariantArray(type, rows);
01375 }
01376 
01377 const ColumnType& SqlRecord::get_column_type(const tstring& col_name) const
01378 {
01379 /*
01380     for(ColumnVector::const_iterator it=_values.begin(); it!=_values.end(); ++it)
01381         if (!stricmp(it->_type._name.c_str(), col_name.c_str()))
01382             return it->_type;
01383 */
01384     NameMap::const_iterator found = find_column(col_name);
01385 
01386     if (found != _name_map.end()) {
01387         int idx = found->second;
01388         return _values[idx]._type;
01389     } else {
01390         THROW_OCI_EXCEPTION("column not found");
01391 //      return ColumnType::s_empty;
01392     }
01393 }
01394 
01395 const SqlVariantArray& SqlRecord::get_column(const tstring& col_name) const
01396 {
01397 /*
01398     for(ColumnVector::const_iterator it=_values.begin(); it!=_values.end(); ++it)
01399         if (!stricmp(it->_type._name.c_str(), col_name.c_str()))
01400             return *it->_pvar;
01401 */
01402     NameMap::const_iterator found = find_column(col_name);
01403 
01404     if (found != _name_map.end()) {
01405         int idx = found->second;
01406         return *_values[idx]._pvar;
01407     } else {
01408         THROW_OCI_EXCEPTION("column not found");
01409 //      return SqlVariantArray::s_empty;
01410     }
01411 }
01412 
01413 SqlRecord::NameMap::const_iterator SqlRecord::find_column(const tstring& col_name) const
01414 {
01415     tstring upper_name;
01416 
01417      // initialize column name map
01418     if (_name_map.empty()) {
01419         int idx = 0;
01420 
01421         for(ColumnVector::const_iterator it=_values.begin(); it!=_values.end(); ++it,++idx) {
01422             upper_name = it->_type._name.c_str();
01423             _tcsupr_s((TCHAR*)upper_name.data(), upper_name.length()+1);
01424 
01425             _name_map[upper_name] = idx;
01426         }
01427     }
01428 
01429     upper_name = col_name;
01430     _tcsupr_s((TCHAR*)upper_name.data(), upper_name.length()+1);
01431 
01432     return _name_map.find(upper_name);
01433 }
01434 
01435 
01436 void SqlRecord::bind_result(SqlStatement& stmt)
01437 {
01438     int idx = 0;
01439 
01440     for(ColumnVector::iterator it=_values.begin(); it!=_values.end(); ++it,++idx)
01441         it->_pvar->bind_result(stmt, idx);
01442 }
01443 
01444 void SqlRecord::print_columns(tostream& out)
01445 {
01446     for(ColumnVector::const_iterator it=_values.begin(); it!=_values.end(); ++it)
01447         out << it->_type._name << TEXT(": ") << it->_type.get_type_str() << TEXT("\n");
01448 
01449     out << TEXT("\n");
01450 }
01451 
01452 void SqlRecord::print_values(tostream& out, int row)
01453 {
01454     ColumnVector::const_iterator it_type = _values.begin();
01455 
01456     for(ColumnVector::const_iterator it=_values.begin(); it!=_values.end(); ++it,++it_type)
01457         out << it->_type._name << TEXT("=") << it->_pvar->str(row, _env._errh) << TEXT("\n");
01458 }
01459 
01460 
01461 SqlVariantArray::SqlVariantArray(const ColumnTypeInfo& type, int size)
01462  :  _size(size),
01463     _data_type(type._data_type)
01464 {
01465     switch(type._data_type) {
01466       case OCI_TYPECODE_CHAR:
01467         _data_type = OCI_TYPECODE_VARCHAR;
01468         // fall through
01469 
01470       case OCI_TYPECODE_VARCHAR:
01471         _pstring = new SqlStringArray(size, type._width);
01472         break;
01473 
01474       case OCI_TYPECODE_NUMBER:
01475         _pnumber = new SqlNumberArray(size);
01476         break;
01477 
01478 #ifdef SQLT_BFLOAT
01479       case OCI_TYPECODE_BFLOAT:
01480         _pfloat = new float[size];
01481         break;
01482 
01483       case OCI_TYPECODE_BDOUBLE:
01484         _pdouble = new double[size];
01485         break;
01486 #endif
01487 
01488       case OCI_TYPECODE_DATE:
01489         _poci_date = new OciDateArray(size);
01490         break;
01491 
01492 #if ORACLE_VERSION>=81
01493       case OCI_TYPECODE_TIME:
01494       case OCI_TYPECODE_TIMESTAMP:
01495         _psql_date = new SqlDateTimeArray(size);
01496         break;
01497 /* no LOB allocation without available handles
01498       case OCI_TYPECODE_BLOB:
01499         _pblob = new OciBlobArray(size);
01500         break;
01501 
01502       case OCI_TYPECODE_CLOB:
01503         _pclob = new OciClobArray(size);
01504         break;
01505 */
01506 #endif
01507       case SQLT_LNG:
01508         _pstring = new SqlStringArray(size, type._width);   //@@
01509         break;
01510 
01511       default:
01512         THROW_OCI_EXCEPTION("unsupported datatype");
01513     }
01514 }
01515 
01516 SqlVariantArray::SqlVariantArray(const SqlVariantArray& other)
01517  :  _size(0),
01518     _data_type(0)
01519 {
01520     assign(other);
01521 }
01522 
01523 void SqlVariantArray::assign(const SqlVariantArray& other)
01524 {
01525     clear();
01526 
01527     _size = other._size;
01528     _data_type = other._data_type;
01529 
01530     switch(other._data_type) {
01531       case 0:
01532         break;
01533 
01534       case OCI_TYPECODE_VARCHAR:
01535         _pstring = new SqlStringArray(*other._pstring); //@@
01536         break;
01537 
01538       case OCI_TYPECODE_NUMBER:
01539         _pnumber = new SqlNumberArray(*other._pnumber);
01540         break;
01541 
01542 #ifdef SQLT_BFLOAT
01543       case OCI_TYPECODE_BFLOAT:
01544         _pfloat = new float[_size];
01545         memcpy(_pfloat, other._pfloat, sizeof(float)*_size);
01546         break;
01547 
01548       case OCI_TYPECODE_BDOUBLE:
01549         _pdouble = new double[_size];
01550         memcpy(_pfloat, other._pfloat, sizeof(double)*_size);
01551         break;
01552 #endif
01553 
01554       case OCI_TYPECODE_DATE:
01555         _poci_date = new OciDateArray(*other._poci_date);
01556         break;
01557 
01558 #if ORACLE_VERSION>=81
01559       case OCI_TYPECODE_TIME:
01560       case OCI_TYPECODE_TIMESTAMP:
01561         _psql_date = new SqlDateTimeArray(*other._psql_date);
01562         break;
01563 #endif
01564 /*
01565       case OCI_TYPECODE_BLOB:
01566         _pblob = new OciBlobArray(*other._pblob);
01567         break;
01568 
01569       case OCI_TYPECODE_CLOB:
01570         _pclob = new OciClobArray(*other._pclob);
01571         break;
01572 */
01573       case SQLT_LNG:
01574         _pstring = new SqlStringArray(*other._pstring); //@@
01575         break;
01576 
01577       default:
01578         assert(0);
01579     }
01580 }
01581 
01582 void SqlVariantArray::clear()
01583 {
01584     switch(_data_type) {
01585       case 0:
01586         break;
01587 
01588       case OCI_TYPECODE_VARCHAR:
01589         delete _pstring;
01590         break;
01591 
01592       case OCI_TYPECODE_NUMBER:
01593         delete _pnumber;
01594         break;
01595 
01596 #ifdef SQLT_BFLOAT
01597       case OCI_TYPECODE_BFLOAT:
01598         delete [] _pfloat;
01599         break;
01600 
01601       case OCI_TYPECODE_BDOUBLE:
01602         delete [] _pdouble;
01603         break;
01604 #endif
01605 
01606       case OCI_TYPECODE_DATE:
01607         delete _poci_date;
01608         break;
01609 
01610 #if ORACLE_VERSION>=81
01611       case OCI_TYPECODE_TIME:
01612       case OCI_TYPECODE_TIMESTAMP:
01613         delete _psql_date;
01614         break;
01615 #endif
01616 /*
01617       case OCI_TYPECODE_BLOB:
01618         delete _pblob;
01619         break;
01620 
01621       case OCI_TYPECODE_CLOB:
01622         delete _pclob;
01623         break;
01624 */
01625       case SQLT_LNG:
01626         delete _pstring;    //@@
01627         break;
01628 
01629       default:
01630         assert(0);
01631     }
01632 
01633     _size = 0;
01634     _data_type = 0;
01635 }
01636 
01637 tstring SqlVariantArray::str(int row, OCIError* errh) const
01638 {
01639 #ifdef SQLT_BFLOAT
01640     TCHAR buffer[16];
01641 #endif
01642 
01643     switch(_data_type) {
01644       case 0:
01645         return TEXT("");
01646 
01647       case OCI_TYPECODE_VARCHAR:
01648         return _pstring->c_str(row);
01649 //      return *_string;
01650 
01651       case OCI_TYPECODE_NUMBER:
01652         return _pnumber->str(row, errh);
01653 
01654 #ifdef SQLT_BFLOAT
01655       case OCI_TYPECODE_BFLOAT:
01656 #ifdef __STDC_WANT_SECURE_LIB__
01657         _stprintf_s(buffer, COUNTOF(buffer),
01658 #else
01659         _stprintf(buffer,
01660 #endif
01661         TEXT("%f"), _pfloat[row]);
01662         return buffer;
01663 
01664       case OCI_TYPECODE_BDOUBLE:
01665 #ifdef __STDC_WANT_SECURE_LIB__
01666         _stprintf_s(buffer, COUNTOF(buffer),
01667 #else
01668         _stprintf(buffer,
01669 #endif
01670         TEXT("%f"), _pdouble[row]);
01671         return buffer;
01672 #endif
01673 
01674       case OCI_TYPECODE_DATE:
01675         return _poci_date->str(row);
01676 
01677 #if ORACLE_VERSION>=81
01678       case OCI_TYPECODE_TIME:
01679       case OCI_TYPECODE_TIMESTAMP:
01680         return _psql_date->str(row);
01681 #endif
01682 /*
01683       case OCI_TYPECODE_BLOB:
01684         return TEXT("(BLOB)");
01685 
01686       case OCI_TYPECODE_BFILE:
01687         return TEXT("(BFILE)");
01688 
01689       case OCI_TYPECODE_CLOB:
01690         return TEXT("(CLOB)");
01691 
01692       case OCI_TYPECODE_CFILE:
01693         return TEXT("(CFILE)");
01694 */
01695       case SQLT_LNG:
01696         return _pstring->c_str(row);    //@@
01697 
01698       default:
01699         assert(0);
01700         return TEXT("");
01701     }
01702 }
01703 
01704 void SqlVariantArray::set_string(int row, const TCHAR* str)
01705 {
01706     if (_data_type != OCI_TYPECODE_VARCHAR)
01707         THROW_OCI_EXCEPTION("invalid variant data type");
01708 
01709     _pstring->assign(row, str);
01710 }
01711 
01712 
01713 SqlNumber SqlVariantArray::number(int row, OCIError* errh) const
01714 {
01715     switch(_data_type) {
01716       case 0:
01717         return SqlNumber();
01718 
01719       case OCI_TYPECODE_VARCHAR:
01720         return SqlNumber(errh, _pstring->c_str(row));
01721 
01722       case OCI_TYPECODE_NUMBER:
01723         if (_pnumber->is_not_null(row))
01724             return _pnumber->get_ref(row);
01725         else
01726             return SqlNumber();
01727 
01728 #ifdef SQLT_BFLOAT
01729       case OCI_TYPECODE_BFLOAT:
01730         return SqlNumber(errh, _pfloat[row]);
01731 
01732       case OCI_TYPECODE_BDOUBLE:
01733         return SqlNumber(errh, _pdouble[row]);
01734 #endif
01735 
01736     //case OCI_TYPECODE_DATE:
01737     //  return ...
01738 
01739       default:
01740         THROW_OCI_EXCEPTION("no conversion to number");
01741         //return SqlNumber();   // not reached
01742     }
01743 }
01744 
01745 void SqlVariantArray::set_number(int row, const SqlNumber& num)
01746 {
01747     if (_data_type != OCI_TYPECODE_NUMBER)
01748         THROW_OCI_EXCEPTION("invalid variant data type");
01749 
01750     _pnumber->set_number(row, num);
01751 }
01752 
01753 
01754 OciDate SqlVariantArray::oci_date(int row, OCIError* errh) const
01755 {
01756     switch(_data_type) {
01757       case 0:
01758         return OciDate();
01759 
01760       case OCI_TYPECODE_VARCHAR:
01761         return OciDate(errh, _pstring->c_str(row));
01762 
01763       case OCI_TYPECODE_DATE:
01764         if (_poci_date->is_not_null(row))
01765             return *_poci_date->get_ref(row);
01766         else
01767             return OciDate();
01768 /*@@todo convert type
01769 #if ORACLE_VERSION>=81
01770       case OCI_TYPECODE_TIME:
01771       case OCI_TYPECODE_TIMESTAMP:
01772         return *_sql_date;
01773 #endif
01774 */
01775       default:
01776         THROW_OCI_EXCEPTION("no conversion to date");
01777         //return OciDate(); // not reached
01778     }
01779 }
01780 
01781 void SqlVariantArray::set_date(int row, const OciDate& date)
01782 {
01783     if (_data_type != OCI_TYPECODE_DATE)
01784         THROW_OCI_EXCEPTION("invalid variant data type");
01785 
01786     _poci_date->set_date(row, date);
01787 }
01788 
01789 
01790 SqlDateTime SqlVariantArray::sql_date(int row, OCIError* errh) const
01791 {
01792     switch(_data_type) {
01793       case 0:
01794         return SqlDateTime();
01795 
01796 /*@@todo convert type
01797       case OCI_TYPECODE_VARCHAR:
01798         return SqlDateTime(errh, *_string);
01799 
01800       case OCI_TYPECODE_DATE:
01801         return *_oci_date;
01802 */
01803 #if ORACLE_VERSION>=81
01804       case OCI_TYPECODE_TIME:
01805       case OCI_TYPECODE_TIMESTAMP:
01806         if (_psql_date->is_not_null(row))
01807             return *_psql_date->get_ref(row);
01808         else
01809             return SqlDateTime();
01810 #endif
01811 
01812       default:
01813         THROW_OCI_EXCEPTION("no conversion to date");
01814         //return SqlDateTime(); // not reached
01815     }
01816 }
01817 
01818 void SqlVariantArray::set_datetime(int row, const SqlDateTime& datetime)
01819 {
01820     if (_data_type!=OCI_TYPECODE_TIME && _data_type!=OCI_TYPECODE_TIMESTAMP)
01821         THROW_OCI_EXCEPTION("invalid variant data type");
01822 
01823     _psql_date->set_datetime(row, datetime);
01824 }
01825 
01826 
01827 bool SqlVariantArray::is_not_null(int row) const
01828 {
01829     switch(_data_type) {
01830       case 0:
01831 #ifdef SQLT_BFLOAT
01832       case OCI_TYPECODE_BFLOAT:
01833       case OCI_TYPECODE_BDOUBLE:
01834 #endif
01835         return true;
01836 
01837       case OCI_TYPECODE_VARCHAR:
01838         return _pstring->is_not_null(row);
01839 
01840       case OCI_TYPECODE_NUMBER:
01841         return _pnumber->is_not_null(row);
01842 
01843       case OCI_TYPECODE_DATE:
01844         return _poci_date->is_not_null(row);
01845 
01846 #if ORACLE_VERSION>=81
01847       case OCI_TYPECODE_TIME:
01848       case OCI_TYPECODE_TIMESTAMP:
01849         return _psql_date->is_not_null(row);
01850 #endif
01851 /*
01852       case OCI_TYPECODE_BLOB:
01853         return _pblob->is_not_null(row);
01854 
01855       case OCI_TYPECODE_CLOB:
01856         return _pclob->is_not_null(row);
01857 */
01858       case SQLT_LNG:
01859         return _pstring->is_not_null(row);  //@@
01860 
01861       default:
01862         assert(0);
01863         return true;
01864     }
01865 }
01866 
01867 void SqlVariantArray::bind_result(SqlStatement& stmt, int idx)
01868 {
01869     switch(_data_type) {
01870       case OCI_TYPECODE_VARCHAR:
01871         stmt.bind_result(idx, *_pstring);
01872         break;
01873 
01874       case OCI_TYPECODE_NUMBER:
01875         stmt.bind_result(idx, *_pnumber);
01876         break;
01877 
01878 #ifdef SQLT_BFLOAT
01879       case OCI_TYPECODE_BFLOAT:
01880         stmt.bind_result(idx, *_pfloat);
01881         break;
01882 
01883       case OCI_TYPECODE_BDOUBLE:
01884         stmt.bind_result(idx, *_pdouble);
01885         break;
01886 #endif
01887 
01888       case OCI_TYPECODE_DATE:
01889         stmt.bind_result(idx, *_poci_date);
01890         break;
01891 
01892 #if ORACLE_VERSION>=81
01893       case OCI_TYPECODE_TIME:
01894       case OCI_TYPECODE_TIMESTAMP:
01895         stmt.bind_result(idx, *_psql_date);
01896         break;
01897 #endif
01898 /*
01899       case OCI_TYPECODE_BLOB:
01900         stmt.bind_result(idx, *_pblob);
01901         break;
01902 
01903       case OCI_TYPECODE_CLOB:
01904         stmt.bind_result(idx, *_pclob);
01905         break;
01906 */
01907       case SQLT_LNG:
01908         stmt.bind_result(idx, *_pstring);   //@@
01909         break;
01910 
01911       default:
01912         assert(0);
01913     }
01914 }
01915 
01916  // buffer bind values
01917 void SqlVariantArray::bind_input(SqlStatement& stmt, int idx, int row)
01918 {
01919     switch(_data_type) {
01920       case OCI_TYPECODE_VARCHAR:
01921         stmt.bind_input(idx, BindInput(_pstring->str(row), _pstring->alen(), SQLT_STR));
01922         break;
01923 
01924       case OCI_TYPECODE_NUMBER:
01925         stmt.bind_input(idx, BindInput(_pnumber->get_number(row), _pnumber->ind(row)));
01926         break;
01927 
01928 #ifdef SQLT_BFLOAT
01929       case OCI_TYPECODE_BFLOAT:
01930         stmt.bind_input(idx, *_pfloat);
01931         break;
01932 
01933       case OCI_TYPECODE_BDOUBLE:
01934         stmt.bind_input(idx, *_pdouble);
01935         break;
01936 #endif
01937 
01938       case OCI_TYPECODE_DATE:
01939         stmt.bind_input(idx, BindInput(_poci_date->get_date(row), _poci_date->ind(row)));
01940         break;
01941 
01942 #if ORACLE_VERSION>=81
01943       case OCI_TYPECODE_TIME:
01944       case OCI_TYPECODE_TIMESTAMP:
01945         stmt.bind_input(idx, BindInput(_psql_date->get_datetime(row), _psql_date->ind(row)));
01946         break;
01947 #endif
01948 /*
01949       case OCI_TYPECODE_BLOB:
01950         stmt.bind_input(idx, *_pblob);
01951         break;
01952 
01953       case OCI_TYPECODE_CLOB:
01954         stmt.bind_input(idx, *_pclob);
01955         break;
01956 */
01957       case SQLT_LNG:
01958         stmt.bind_input(idx, BindInput(_pstring->str(row), _pstring->alen(), SQLT_STR));    //@@
01959         break;
01960 
01961       default:
01962         assert(0);
01963     }
01964 }
01965 
01966 /*
01967 void SqlStringArray::assign(int row, const dvoid* ptr, sb4 size)
01968 {
01969     //TODO resize buffer as needed
01970     if (value_sz == -1)
01971         strcpy_s(_buffer, _blen, s);
01972     else {
01973         memcpy(_buffer, ptr, size);
01974         _buffer[size] = '\0';
01975     }
01976 } */
01977 
01978 const TCHAR* get_oci_ptype_str(ub1 type)
01979 {
01980     switch(type) {
01981       case OCI_PTYPE_TABLE:         return TEXT("table");
01982       case OCI_PTYPE_VIEW:          return TEXT("view");
01983       case OCI_PTYPE_PROC:          return TEXT("procedure");
01984       case OCI_PTYPE_FUNC:          return TEXT("function");
01985       case OCI_PTYPE_PKG:           return TEXT("package");
01986       case OCI_PTYPE_TYPE:          return TEXT("user-defined type");
01987       case OCI_PTYPE_SYN:           return TEXT("synonym");
01988       case OCI_PTYPE_SEQ:           return TEXT("sequence");
01989       case OCI_PTYPE_COL:           return TEXT("column");
01990       case OCI_PTYPE_ARG:           return TEXT("argument");
01991       case OCI_PTYPE_LIST:          return TEXT("list");
01992       case OCI_PTYPE_TYPE_ATTR:     return TEXT("user-defined type's attribute");
01993       case OCI_PTYPE_TYPE_COLL:     return TEXT("collection type's element ");
01994       case OCI_PTYPE_TYPE_METHOD:   return TEXT("user-defined type's method");
01995       case OCI_PTYPE_TYPE_ARG:      return TEXT("user-defined type method's argument");
01996       case OCI_PTYPE_TYPE_RESULT:   return TEXT("user-defined type method's result");
01997 #if ORACLE_VERSION>=81
01998       case OCI_PTYPE_SCHEMA:        return TEXT("schema");
01999       case OCI_PTYPE_DATABASE:      return TEXT("database");
02000 #endif
02001     }
02002 
02003     return TEXT("unknown type");
02004 }
02005 
02006 
02007 static tstring tokenize(const TCHAR** ptr, const TCHAR* sep)
02008 {
02009     const TCHAR* start = *ptr;
02010     const TCHAR* end;
02011 
02012     const TCHAR* found = _tcspbrk(*ptr, sep);
02013 
02014     if (found) {
02015         end = found;
02016         *ptr = found;
02017     } else
02018         *ptr = end = start + _tcslen(start);
02019 
02020     return tstring(start, end-start);
02021 }
02022 
02023 static tstring tokenize(const TCHAR** ptr, const TCHAR* sep, TCHAR key)
02024 {
02025     if (**ptr != key)
02026         return TEXT("");
02027 
02028     ++*ptr;
02029 
02030     return tokenize(ptr, sep);
02031 }
02032 
02033 void LoginPara::parse(const TCHAR* conn_str)
02034 {
02035     const TCHAR* ptr = conn_str;
02036 
02037     _username = tokenize(&ptr, TEXT("/@ "));
02038     _password = tokenize(&ptr, TEXT("@ "), TEXT('/'));
02039     _tnsname = tokenize(&ptr, TEXT(" "), TEXT('@'));
02040 
02041     while(istspace(*ptr))
02042         ++ptr;
02043 
02044     if (!_tcsnicmp(ptr, TEXT("as sysdba"), 9)) {
02045         _mode = OCI_SYSDBA;
02046         ptr += 9;
02047     } else if (!_tcsnicmp(ptr, TEXT("as sysoper"), 10)) {
02048         _mode = OCI_SYSDBA;
02049         ptr += 10;
02050     } else if (!_tcsnicmp(ptr, TEXT("migrate"), 7)) {
02051         _mode = OCI_MIGRATE;
02052         ptr += 7;
02053     }
02054 }
02055 
02056 
02057 } // namespace OCIPL

Generated on Fri Sep 22 2017 00:05:09 for OCIPL/C++ by  doxygen 1.7.2