/* This file is part of libodbc++. Copyright (C) 1999-2000 Manush Dodunekov <manush@stendahls.net> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __ODBCXX_TYPES_H #define __ODBCXX_TYPES_H #include <odbc++/setup.h> #include <exception> #if !defined(ODBCXX_QT) # include <string> # else # include <qstring.h> #endif #include <ctime> #if defined(ODBCXX_QT) class QIODevice; #endif #if defined(ODBCXX_HAVE_ISQL_H) && defined(ODBCXX_HAVE_ISQLEXT_H) # include <isql.h> # include <isqlext.h> #elif defined(ODBCXX_HAVE_SQL_H) && defined(ODBCXX_HAVE_SQLEXT_H) # include <sql.h> # include <sqlext.h> #else # error "Whoops. Can not recognize the ODBC subsystem." #endif // fixups for current iODBC, which kindly doesn't provide SQL_TRUE and // SQL_FALSE macros #if !defined(SQL_TRUE) # define SQL_TRUE 1 #endif #if !defined(SQL_FALSE) # define SQL_FALSE 0 #endif // MS ODBC SDK misses this in some releases #if ODBCVER >= 0x0300 && !defined(SQL_NOT_DEFERRABLE) # define SQL_NOT_DEFERRABLE 7 #endif // Setup our ODBC3_C (odbc3 conditional) macro #if ODBCVER >= 0x0300 # define ODBC3_C(odbc3_value,old_value) odbc3_value #else # define ODBC3_C(odbc3_value,old_value) old_value #endif // ODBC3_DC (odbc3 dynamic conditional) // Every context using this macro should provide // a this->_getDriverInfo() method returning // a const DriverInfo* #if ODBCVER >= 0x0300 # define ODBC3_DC(odbc3_value,old_value) \ (this->_getDriverInfo()->getMajorVersion()>=3?odbc3_value:old_value) #else # define ODBC3_DC(odbc3_value,old_value) old_value #endif #if defined(ODBCXX_HAVE_INTTYPES_H) # include <inttypes.h> #endif #include <vector> namespace odbc { // We want Long to be at least 64 bits #if defined(WIN32) typedef __int64 Long; #elif defined(ODBCXX_HAVE_INTTYPES_H) typedef int64_t Long; #else # if ODBCXX_SIZEOF_INT == 8 typedef int Long; # elif ODBCXX_SIZEOF_LONG == 8 typedef long Long; # elif ODBCXX_SIZEOF_LONG_LONG == 8 typedef long long Long; # else # error "Can't find an appropriate at-least-64-bit integer" # endif #endif //constants: //how much we try to fetch with each SQLGetData call const int GETDATA_CHUNK_SIZE=4*1024; //how much we write with each SQLPutData call const int PUTDATA_CHUNK_SIZE=GETDATA_CHUNK_SIZE; //how much we read/write in string<->stream conversion //better names for those? const int STRING_TO_STREAM_CHUNK_SIZE=1024; const int STREAM_TO_STRING_CHUNK_SIZE=STRING_TO_STREAM_CHUNK_SIZE; struct Types { enum SQLType { BIGINT = SQL_BIGINT, BINARY = SQL_BINARY, BIT = SQL_BIT, CHAR = SQL_CHAR, DATE = ODBC3_C(SQL_TYPE_DATE,SQL_DATE), DECIMAL = SQL_DECIMAL, DOUBLE = SQL_DOUBLE, FLOAT = SQL_FLOAT, INTEGER = SQL_INTEGER, LONGVARBINARY = SQL_LONGVARBINARY, LONGVARCHAR = SQL_LONGVARCHAR, NUMERIC = SQL_NUMERIC, REAL = SQL_REAL, SMALLINT = SQL_SMALLINT, TIME = ODBC3_C(SQL_TYPE_TIME,SQL_TIME), TIMESTAMP = ODBC3_C(SQL_TYPE_TIMESTAMP,SQL_TIMESTAMP), TINYINT = SQL_TINYINT, VARBINARY = SQL_VARBINARY, VARCHAR = SQL_VARCHAR }; }; #if !defined(ODBCXX_QT) class ODBCXX_EXPORT Bytes { private: struct Rep { signed char* buf_; size_t len_; int refCount_; Rep(const signed char* b, size_t l) :len_(l), refCount_(0) { if(len_>0) { buf_=new signed char[len_]; memcpy((void*)buf_,(void*)b,len_); } else { buf_=NULL; } } ~Rep() { delete buf_; } }; Rep* rep_; public: Bytes() :rep_(new Rep(NULL,0)) { rep_->refCount_++; } Bytes(const signed char* data, size_t dataLen) :rep_(new Rep(data,dataLen)) { rep_->refCount_++; } Bytes(const Bytes& b) :rep_(b.rep_) { rep_->refCount_++; } Bytes& operator=(const Bytes& b) { if(--rep_->refCount_==0) { delete rep_; } rep_=b.rep_; rep_->refCount_++; return *this; } ~Bytes() { if(--rep_->refCount_==0) { delete rep_; } } const signed char* getData() const { return rep_->buf_; } size_t getSize() const { return rep_->len_; } }; #endif class ODBCXX_EXPORT Date { protected: int year_; int month_; int day_; virtual void _invalid(const char* what, int value); int _validateYear(int y) { return y; } int _validateMonth(int m) { if(m<1 || m>12) { this->_invalid("month",m); } return m; } int _validateDay(int d) { if(d<1 || d>31) { this->_invalid("day",d); } return d; } public: Date(int year, int month, int day) { this->setYear(year); this->setMonth(month); this->setDay(day); } explicit Date(); Date(time_t t) { this->setTime(t); } Date(const ODBCXX_STRING& str) { this->parse(str); } Date(const Date& d) :year_(d.year_), month_(d.month_), day_(d.day_) {} Date& operator=(const Date& d) { year_=d.year_; month_=d.month_; day_=d.day_; return *this; } virtual ~Date() {} virtual void setTime(time_t t); time_t getTime() const; void parse(const ODBCXX_STRING& str); int getYear() const { return year_; } int getMonth() const { return month_; } int getDay() const { return day_; } void setYear(int year) { year_=this->_validateYear(year); } void setMonth(int month) { month_=this->_validateMonth(month); } void setDay(int day) { day_=this->_validateDay(day); } virtual ODBCXX_STRING toString() const; }; class ODBCXX_EXPORT Time { protected: int hour_; int minute_; int second_; virtual void _invalid(const char* what, int value); int _validateHour(int h) { if(h<0 || h>23) { this->_invalid("hour",h); } return h; } int _validateMinute(int m) { if(m<0 || m>59) { this->_invalid("minute",m); } return m; } int _validateSecond(int s) { if(s<0 || s>61) { this->_invalid("second",s); } return s; } public: Time(int hour, int minute, int second) { this->setHour(hour); this->setMinute(minute); this->setSecond(second); } explicit Time(); Time(time_t t) { this->setTime(t); } Time(const ODBCXX_STRING& str) { this->parse(str); } Time(const Time& t) :hour_(t.hour_), minute_(t.minute_), second_(t.second_) {} Time& operator=(const Time& t) { hour_=t.hour_; minute_=t.minute_; second_=t.second_; return *this; } virtual ~Time() {} virtual void setTime(time_t t); time_t getTime() const; void parse(const ODBCXX_STRING& str); int getHour() const { return hour_; } int getMinute() const { return minute_; } int getSecond() const { return second_; } void setHour(int h) { hour_=this->_validateHour(h); } void setMinute(int m) { minute_=this->_validateMinute(m); } void setSecond(int s) { second_=this->_validateSecond(s); } virtual ODBCXX_STRING toString() const; }; class ODBCXX_EXPORT Timestamp : public Date, public Time { private: int nanos_; virtual void _invalid(const char* what, int value); int _validateNanos(int n) { if(n<0) { this->_invalid("nanoseconds",n); } return n; } public: Timestamp(int year, int month, int day, int hour, int minute, int second, int nanos =0) :Date(year,month,day), Time(hour,minute,second) { this->setNanos(nanos); } explicit Timestamp(); Timestamp(time_t t) { this->setTime(t); } Timestamp(const ODBCXX_STRING& s) { this->parse(s); } Timestamp(const Timestamp& t) :Date(t),Time(t),nanos_(t.nanos_) {} Timestamp& operator=(const Timestamp& t) { Date::operator=(t); Time::operator=(t); nanos_=t.nanos_; return *this; } virtual ~Timestamp() {} virtual void setTime(time_t t); virtual time_t getTime() { return Date::getTime()+Time::getTime(); } void parse(const ODBCXX_STRING& s); int getNanos() const { return nanos_; } void setNanos(int nanos) { nanos_=this->_validateNanos(nanos); } virtual ODBCXX_STRING toString() const; }; //this is used for several 'lists of stuff' below //expects T to be a pointer-to-something, and //the contents will get deleted when the vector //itself is deleted template <class T> class CleanVector : public std::vector<T> { private: CleanVector(const CleanVector<T>&); //forbid CleanVector<T>& operator=(const CleanVector<T>&); //forbid public: explicit CleanVector() {} virtual ~CleanVector() { typename std::vector<T>::iterator i=this->begin(); typename std::vector<T>::iterator end=this->end(); while(i!=end) { delete *i; ++i; } this->clear(); } }; class ODBCXX_EXPORT DriverMessage { friend class ErrorHandler; private: char state_[SQL_SQLSTATE_SIZE+1]; char description_[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER nativeCode_; DriverMessage() {} public: virtual ~DriverMessage() {} const char* getSQLState() const { return state_; } const char* getDescription() const { return description_; } int getNativeCode() const { return nativeCode_; } }; class SQLException : public std::exception { private: ODBCXX_STRING reason_; ODBCXX_STRING sqlState_; int errorCode_; #if defined(ODBCXX_QT) QCString reason8_; #endif public: SQLException(const ODBCXX_STRING& reason ="", const ODBCXX_STRING& sqlState ="", int vendorCode =0) :reason_(reason), sqlState_(sqlState), errorCode_(vendorCode) #if defined(ODBCXX_QT) ,reason8_(reason.local8Bit()) #endif {} SQLException(const DriverMessage& dm) :reason_(dm.getDescription()), sqlState_(dm.getSQLState()), errorCode_(dm.getNativeCode()) {} virtual ~SQLException() {} int getErrorCode() const { return errorCode_; } const ODBCXX_STRING& getSQLState() const { return sqlState_; } const ODBCXX_STRING& getMessage() const { return reason_; } virtual const char* what() const { // the conversion from QString involves a temporary, which // doesn't survive this scope. So here, we do a conditional #if defined(ODBCXX_QT) return reason8_.data(); #else return reason_.c_str(); #endif } }; class SQLWarning : public SQLException { SQLWarning(const SQLWarning&); //forbid SQLWarning& operator=(const SQLWarning&); //forbid public: SQLWarning(const ODBCXX_STRING& reason ="", const ODBCXX_STRING& sqlState ="", int vendorCode =0) :SQLException(reason,sqlState,vendorCode) {} SQLWarning(const DriverMessage& dm) :SQLException(dm) {} virtual ~SQLWarning() {} }; typedef CleanVector<SQLWarning*> WarningList; template <class T> class Deleter { private: T* ptr_; bool isArray_; Deleter(const Deleter<T>&); Deleter<T>& operator=(const Deleter<T>&); public: explicit Deleter(T* ptr, bool isArray =false) :ptr_(ptr), isArray_(isArray) {} ~Deleter() { if(!isArray_) { delete ptr_; } else { delete[] ptr_; } } }; }; // namespace odbc #endif // __ODBCXX_TYPES_H