#include "Firebird.h" #include NAMESPACE_UPP TransAuto::TransAuto(SqlSession& s) : abort(true), isSession(true), session(&s) { session->Begin(); } TransAuto::TransAuto(Sql& s) : abort(true), isSession(false), sql(&s) { sql->Begin(); } TransAuto::~TransAuto() { try { if (isSession) { if(abort) { session->Rollback(); } else { session->Commit(); } } else { if(abort) { sql->Rollback(); } else { sql->Commit(); } } } catch(...) { // Ignore all exceptions in destructor. ASSERT(false); } } class TransRetain { public: TransRetain(FBSession& s) : abort(true), session(&s) { } ~TransRetain() { try { if(abort) { session->RollbackRetaining(); } else { session->CommitRetaining(); } } catch(...) { // Ignore all exceptions in the destructor. ASSERT(false); } } public: operator bool() const { return abort; } void Finish() { abort = false; } protected: bool abort:1; FBSession* session; }; #define TRANSACTION_RETAIN(trans) \ for(TransRetain auto_trans_##__LINE__(trans); \ auto_trans_##__LINE__; \ auto_trans_##__LINE__.Finish() ) struct FBValue { short nullInd; XSQLVAR* pXSQLVar; FBValue(XSQLVAR& v); virtual ~FBValue(); bool CanBeNull() const { return pXSQLVar->sqltype & 1; } bool IsNull() const { return nullInd == -1; } void SetNull(bool flag = true) { nullInd = flag ? -1 : 0; } virtual void GetValue(Ref r) const = 0; virtual void SetValue(const Value& v) = 0; }; FBValue::FBValue(XSQLVAR& v) { pXSQLVar = &v; if (CanBeNull()) { v.sqlind = &nullInd; nullInd = -1; } } FBValue::~FBValue() { } struct FBInt : public FBValue { int value; FBInt(XSQLVAR& v); virtual void GetValue(Ref r) const; virtual void SetValue(const Value& v); }; FBInt::FBInt(XSQLVAR& v) : FBValue(v) { v.sqltype = SQL_LONG + (v.sqltype & 1); v.sqldata = reinterpret_cast(&value); v.sqllen = sizeof(value); } void FBInt::GetValue(Ref r) const { if (IsNull()) r = Null; else { switch(r.GetType()) { case INT_V: RefInt(r) = value; break; case DOUBLE_V: RefDouble(r) = static_cast(value); break; case STRING_V: RefString(r) = FormatInt(value); break; case VALUE_V: RefValue(r) = Value(value); break; case WSTRING_V: RefWString(r) = FormatInt(value).ToWString(); break; case INT64_V: RefInt64(r) = value; break; case BOOL_V: RefBool(r) = value != 0; break; case DATE_V: case TIME_V: default: ASSERT(false); break; } } } void FBInt::SetValue(const Value& v) { SetNull(v.IsNull()); if (v.IsNull()) return; switch (v.GetType()) { case INT_V: value = ValueTo(v); break; case DOUBLE_V: value = static_cast(ValueTo(v)); break; case STRING_V: value = ScanInt(ValueTo(v)); break; // case DATE_V: // case TIME_V: case VALUE_V: SetValue(ValueTo(v)); break; case WSTRING_V: value = ScanInt(ValueTo(v).ToString()); break; case INT64_V: value = static_cast(ValueTo(v)); break; case BOOL_V: value = ValueTo(v) ? 1 : 0; break; default: ASSERT(false); break; } } struct FBInt64 : public FBValue { int64 value; FBInt64(XSQLVAR& v); virtual void GetValue(Ref r) const; virtual void SetValue(const Value& v); }; FBInt64::FBInt64(XSQLVAR& v) : FBValue(v) { v.sqltype = SQL_INT64 + (v.sqltype & 1); v.sqldata = reinterpret_cast(&value); v.sqllen = sizeof(value); } void FBInt64::GetValue(Ref r) const { if (IsNull()) r = Null; else { switch(r.GetType()) { case INT_V: RefInt(r) = static_cast(value); break; case DOUBLE_V: RefDouble(r) = static_cast(value); break; case STRING_V: RefString(r) = FormatInt64(value); break; case VALUE_V: RefValue(r) = Value(value); break; case WSTRING_V: RefWString(r) = FormatInt64(value).ToWString(); break; case INT64_V: RefInt64(r) = value; break; case BOOL_V: RefBool(r) = value != 0; break; case DATE_V: case TIME_V: default: ASSERT(false); break; } } } void FBInt64::SetValue(const Value& v) { SetNull(v.IsNull()); if (v.IsNull()) return; switch (v.GetType()) { case INT_V: value = ValueTo(v); break; case DOUBLE_V: value = static_cast(ValueTo(v)); break; case STRING_V: value = ScanInt64(ValueTo(v)); break; // case DATE_V: // case TIME_V: case VALUE_V: SetValue(ValueTo(v)); break; case WSTRING_V: value = ScanInt64(ValueTo(v).ToString()); break; case INT64_V: value = ValueTo(v); break; case BOOL_V: value = ValueTo(v) ? 1 : 0; break; default: ASSERT(false); break; } } struct FBDouble : public FBValue { double value; FBDouble(XSQLVAR& v); virtual void GetValue(Ref r) const; virtual void SetValue(const Value& v); }; FBDouble::FBDouble(XSQLVAR& v) : FBValue(v) { v.sqltype = SQL_DOUBLE + (v.sqltype & 1); v.sqldata = reinterpret_cast(&value); v.sqllen = sizeof(value); v.sqlscale = 18; } void FBDouble::GetValue(Ref r) const { if (IsNull()) r = Null; else { switch(r.GetType()) { case INT_V: RefInt(r) = static_cast(value); break; case DOUBLE_V: RefDouble(r) = value; break; case STRING_V: RefString(r) = FormatDouble(value); break; case VALUE_V: RefValue(r) = Value(value); break; case WSTRING_V: RefWString(r) = FormatDouble(value).ToWString(); break; case INT64_V: RefInt64(r) = static_cast(value); break; case BOOL_V: RefBool(r) = value != 0.0; break; case DATE_V: case TIME_V: default: ASSERT(false); break; } } } void FBDouble::SetValue(const Value& v) { SetNull(v.IsNull()); if (v.IsNull()) return; switch (v.GetType()) { case INT_V: value = ValueTo(v); break; case DOUBLE_V: value = ValueTo(v); break; case STRING_V: value = ScanDouble(ValueTo(v)); break; // case DATE_V: // case TIME_V: case VALUE_V: SetValue(ValueTo(v)); break; case WSTRING_V: value = ScanDouble(ValueTo(v).ToString()); break; case INT64_V: value = static_cast(ValueTo(v)); break; case BOOL_V: value = ValueTo(v) ? 1.0 : 0.0; break; default: ASSERT(false); break; } } // This macro is used to declare structures representing SQL VARCHAR types #define SQL_VARCHAR(len) struct {short vary_length; char vary_string[(len) + 1];} struct FBVarying : public FBValue { // enum { max_varchar_size = 8 * 1024 }; enum { max_varchar_size = 32765 }; //String value; SQL_VARCHAR(32765) buff; FBVarying(XSQLVAR& v); void SetValue(const String& str); virtual void GetValue(Ref r) const; virtual void SetValue(const Value& v); }; FBVarying::FBVarying(XSQLVAR& v) : FBValue(v) { v.sqltype = SQL_VARYING + (v.sqltype & 1); v.sqldata = reinterpret_cast(&buff); v.sqllen = v.sqllen == 0 ? max_varchar_size : v.sqllen; } void FBVarying::SetValue(const String& str) { ASSERT(pXSQLVar); buff.vary_length = min(str.GetCount(), pXSQLVar->sqllen); strncpy(buff.vary_string, ~str, buff.vary_length); } void FBVarying::GetValue(Ref r) const { if (IsNull()) r = Null; else { switch(r.GetType()) { case INT_V: { const char* e = buff.vary_string + buff.vary_length; RefInt(r) = ScanInt(buff.vary_string, &e); } break; case DOUBLE_V: { const char* e = buff.vary_string + buff.vary_length; RefDouble(r) = ScanDouble(buff.vary_string, &e); } break; case STRING_V: RefString(r) = String(buff.vary_string, buff.vary_length); break; case DATE_V: r.SetValue(UPP::Scan(DATE_V, String(buff.vary_string, buff.vary_length))); break; case TIME_V: r.SetValue(UPP::Scan(TIME_V, String(buff.vary_string, buff.vary_length))); break; case VALUE_V: RefValue(r) = Value(String(buff.vary_string, buff.vary_length)); break; case WSTRING_V: RefWString(r) = WString(buff.vary_string, buff.vary_length); break; case INT64_V: { const char* e = buff.vary_string + buff.vary_length; RefInt64(r) = ScanInt64(buff.vary_string, &e); } break; case BOOL_V: { const char* e = buff.vary_string + buff.vary_length; RefBool(r) = ScanInt(buff.vary_string, &e) != 0; } break; default: ASSERT(false); break; } } } void FBVarying::SetValue(const Value& v) { SetNull(v.IsNull()); if (v.IsNull()) return; switch (v.GetType()) { case INT_V: SetValue(AsString(ValueTo(v))); break; case DOUBLE_V: SetValue(AsString(ValueTo(v))); break; case STRING_V: SetValue(ValueTo(v)); break; // case DATE_V: // case TIME_V: case VALUE_V: SetValue(ValueTo(v)); break; case WSTRING_V: SetValue(ValueTo(v).ToString()); break; case INT64_V: SetValue(AsString(ValueTo(v))); break; case BOOL_V: SetValue(IntStr((int)ValueTo(v))); break; default: ASSERT(false); break; } } struct FBTimeStamp : public FBValue { ISC_TIMESTAMP value; FBTimeStamp(XSQLVAR& v, T_FB& dll); virtual void GetValue(Ref r) const; virtual void SetValue(const Value& v); T_FB& dll; }; FBTimeStamp::FBTimeStamp(XSQLVAR& v, T_FB& dll) : FBValue(v), dll(dll) { v.sqltype = SQL_TIMESTAMP + (v.sqltype & 1); v.sqldata = reinterpret_cast(&value); v.sqllen = sizeof(value); } void FBTimeStamp::GetValue(Ref r) const { if (IsNull()) r = Null; else { const LanguageInfo& li = GetLanguageInfo(); struct tm time; dll.isc_decode_timestamp(&value, &time); const Time t(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); switch(r.GetType()) { case STRING_V: RefString(r) = li.FormatTime(t); break; case DATE_V: RefDate(r) = t; break; case TIME_V: RefTime(r) = t; break; case VALUE_V: RefValue(r) = t; break; case WSTRING_V: RefWString(r) = li.FormatTime(t).ToWString(); break; case INT64_V: RefInt64(r) = t.Get(); break; case DOUBLE_V: RefDouble(r) = static_cast(t.Get()); break; case INT_V: case BOOL_V: default: ASSERT(false); break; } } } void FBTimeStamp::SetValue(const Value& v) { SetNull(v.IsNull()); if (v.IsNull()) return; Time t; switch (v.GetType()) { case INT_V: t.Set(ValueTo(v)); break; case DOUBLE_V: t.Set((int64)ValueTo(v)); case STRING_V: t = UPP::Scan(TIME_V, ValueTo(v)); break; case DATE_V: { const Date& d = ValueTo(v); t = Time(d.year, d.month, d.day); } break; case TIME_V: t = ValueTo