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

Generated on Wed Sep 29 00:05:05 2010 for OCIPL/C++ by  doxygen 1.5.4