8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 12:03:02 +01:00

1. Frontported fix for CORE-1944: Monitoring tables contain wrong data

2. Added new methods to Clumplet classes - date, time and floating point support.

3. Avoid endianess #ifdef's in Clumplet classes.
This commit is contained in:
alexpeshkoff 2008-06-24 13:07:12 +00:00
parent b8be425321
commit 99f17b4d00
8 changed files with 173 additions and 150 deletions

View File

@ -484,18 +484,10 @@ const UCHAR* ClumpletReader::getBytes() const
return getBuffer() + cur_offset + getClumpletSize(true, true, false);
}
SLONG ClumpletReader::getInt() const
SINT64 ClumpletReader::fromVaxInteger(const UCHAR* ptr, size_t length)
{
const UCHAR* ptr = getBytes();
size_t length = getClumpLength();
if (length > 4) {
invalid_structure("length of integer exceeds 4 bytes");
return 0;
}
// This code is taken from gds__vax_integer
SLONG value = 0;
SINT64 value = 0;
int shift = 0;
while (length > 0) {
--length;
@ -506,9 +498,60 @@ SLONG ClumpletReader::getInt() const
return value;
}
SLONG ClumpletReader::getInt() const
{
size_t length = getClumpLength();
if (length > 4) {
invalid_structure("length of integer exceeds 4 bytes");
return 0;
}
return fromVaxInteger(getBytes(), length);
}
double ClumpletReader::getDouble() const
{
if (getClumpLength() != sizeof(double)) {
invalid_structure("length of double must be equal 8 bytes");
return 0;
}
// based on XDR code
union {
double temp_double;
SLONG temp_long[2];
} temp;
fb_assert(sizeof(double) == sizeof(temp));
const UCHAR* ptr = getBytes();
temp.temp_long[FB_LONG_DOUBLE_FIRST] = fromVaxInteger(ptr, sizeof(SLONG));
temp.temp_long[FB_LONG_DOUBLE_SECOND] = fromVaxInteger(ptr + sizeof(SLONG), sizeof(SLONG));
return temp.temp_double;
}
ISC_TIMESTAMP ClumpletReader::getTimeStamp() const
{
ISC_TIMESTAMP value;
if (getClumpLength() != sizeof(ISC_TIMESTAMP)) {
invalid_structure("length of ISC_TIMESTAMP must be equal 8 bytes");
value.timestamp_date = 0;
value.timestamp_time = 0;
return value;
}
const UCHAR* ptr = getBytes();
value.timestamp_date = fromVaxInteger(ptr, sizeof(SLONG));
value.timestamp_time = fromVaxInteger(ptr + sizeof(SLONG), sizeof(SLONG));
return value;
}
SINT64 ClumpletReader::getBigInt() const
{
const UCHAR* ptr = getBytes();
size_t length = getClumpLength();
if (length > 8) {
@ -516,16 +559,7 @@ SINT64 ClumpletReader::getBigInt() const
return 0;
}
// This code is taken from isc_portable_integer
SINT64 value = 0;
int shift = 0;
while (length > 0) {
--length;
value += ((SINT64) *ptr++) << shift;
shift += 8;
}
return value;
return fromVaxInteger(getBytes(), length);
}
string& ClumpletReader::getString(string& str) const

View File

@ -68,6 +68,10 @@ public:
string& getString(string& str) const;
PathName& getPath(PathName& str) const;
const UCHAR* getBytes() const;
double getDouble() const;
ISC_TIMESTAMP getTimeStamp() const;
ISC_TIME getTime() const { return getInt(); }
ISC_DATE getDate() const { return getInt(); }
// Return the tag for buffer (usually structure version)
UCHAR getBufferTag() const;
@ -129,6 +133,8 @@ private:
const UCHAR* static_buffer;
const UCHAR* static_buffer_end;
static SINT64 ClumpletReader::fromVaxInteger(const UCHAR* ptr, size_t length);
};
} // namespace Firebird

View File

@ -121,38 +121,53 @@ void ClumpletWriter::size_overflow()
fatal_exception::raise("Clumplet buffer size limit reached");
}
void ClumpletWriter::toVaxInteger(UCHAR* ptr, size_t length, SINT64 value)
{
int shift = 0;
while (length--) {
*ptr++ = (UCHAR)(value >> shift);
shift += 8;
}
}
void ClumpletWriter::insertInt(UCHAR tag, SLONG value)
{
#if defined(WORDS_BIGENDIAN)
UCHAR bytes[4];
const UCHAR* ptr = reinterpret_cast<UCHAR*>(&value);
bytes[0] = ptr[3];
bytes[1] = ptr[2];
bytes[2] = ptr[1];
bytes[3] = ptr[0];
toVaxInteger(bytes, sizeof(bytes), value);
insertBytesLengthCheck(tag, bytes, sizeof(bytes));
#else
insertBytesLengthCheck(tag, reinterpret_cast<UCHAR*>(&value), sizeof(value));
#endif
}
void ClumpletWriter::insertBigInt(UCHAR tag, SINT64 value)
{
#if defined(WORDS_BIGENDIAN)
UCHAR bytes[8];
const UCHAR* ptr = reinterpret_cast<UCHAR*>(&value);
bytes[0] = ptr[7];
bytes[1] = ptr[6];
bytes[2] = ptr[5];
bytes[3] = ptr[4];
bytes[4] = ptr[3];
bytes[5] = ptr[2];
bytes[6] = ptr[1];
bytes[7] = ptr[0];
toVaxInteger(bytes, sizeof(bytes), value);
insertBytesLengthCheck(tag, bytes, sizeof(bytes));
}
void ClumpletWriter::insertDouble(UCHAR tag, double value)
{
union {
double temp_double;
SLONG temp_long[2];
} temp;
fb_assert(sizeof(double) == sizeof(temp));
temp.temp_double = value;
UCHAR bytes[8];
toVaxInteger(bytes, sizeof(SLONG), temp.temp_long[FB_LONG_DOUBLE_FIRST]);
toVaxInteger(bytes + sizeof(SLONG), sizeof(SLONG), temp.temp_long[FB_LONG_DOUBLE_SECOND]);
insertBytesLengthCheck(tag, bytes, sizeof(bytes));
}
void ClumpletWriter::insertTimeStamp(UCHAR tag, ISC_TIMESTAMP value)
{
UCHAR bytes[8];
toVaxInteger(bytes, sizeof(SLONG), value.timestamp_date);
toVaxInteger(bytes + sizeof(SLONG), sizeof(SLONG), value.timestamp_time);
insertBytesLengthCheck(tag, bytes, sizeof(bytes));
#else
insertBytesLengthCheck(tag, reinterpret_cast<UCHAR*>(&value), sizeof(value));
#endif
}
void ClumpletWriter::insertString(UCHAR tag, const string& str)
@ -266,35 +281,17 @@ void ClumpletWriter::insertBytesLengthCheck(UCHAR tag, const UCHAR* bytes, size_
break;
case 2:
{
USHORT value = static_cast<USHORT>(length);
fb_assert(sizeof(USHORT) == 2);
const UCHAR* ptr = reinterpret_cast<UCHAR*>(&value);
#if defined(WORDS_BIGENDIAN)
UCHAR b[2];
b[0] = ptr[1];
b[1] = ptr[0];
toVaxInteger(b, sizeof(b), length);
dynamic_buffer.insert(cur_offset, b, sizeof(b));
#else
dynamic_buffer.insert(cur_offset, ptr, sizeof(value));
#endif
cur_offset += 2;
}
break;
case 4:
{
ULONG value = static_cast<ULONG>(length);
fb_assert(sizeof(ULONG) == 4);
const UCHAR* ptr = reinterpret_cast<UCHAR*>(&value);
#if defined(WORDS_BIGENDIAN)
UCHAR b[4];
b[0] = ptr[3];
b[1] = ptr[2];
b[2] = ptr[1];
b[3] = ptr[0];
toVaxInteger(b, sizeof(b), length);
dynamic_buffer.insert(cur_offset, b, sizeof(b));
#else
dynamic_buffer.insert(cur_offset, ptr, sizeof(value));
#endif
cur_offset += 4;
}
break;

View File

@ -63,6 +63,10 @@ public:
void insertString(UCHAR tag, const char* str, size_t length);
void insertByte(UCHAR tag, const UCHAR byte);
void insertTag(UCHAR tag);
void insertDouble(UCHAR tag, double value);
void insertTimeStamp(UCHAR tag, ISC_TIMESTAMP value);
void insertTime(UCHAR tag, ISC_TIME value) { insertInt(tag, value); }
void insertDate(UCHAR tag, ISC_DATE value) { insertInt(tag, value); }
void insertEndMarker(UCHAR tag);
// Delete currently selected clumplet from buffer
@ -87,6 +91,7 @@ private:
HalfStaticArray<UCHAR, 128> dynamic_buffer;
void initNewBuffer(UCHAR tag);
static void toVaxInteger(UCHAR* ptr, size_t length, SINT64 value);
};
} // namespace Firebird

View File

@ -472,8 +472,6 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
reader = dumpData(tdbb, false);
}
reader->rewind();
// Parse the dump
RecordBuffer* buffer = NULL;
Record* record = NULL;
@ -481,7 +479,7 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
int rid = 0;
bool fields_processed = false, allowed = false, our_dbb = false;
while (!reader->isEof())
for (reader->rewind(); !reader->isEof(); reader->moveNext())
{
if (reader->getClumpTag() == TAG_DBB)
{
@ -491,8 +489,6 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
our_dbb = !memcmp(&guid, &dbb->dbb_guid, sizeof(FB_GUID));
reader->moveNext();
if (fields_processed)
{
buffer->store(record);
@ -502,7 +498,6 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
else if (reader->getClumpTag() == TAG_RECORD)
{
rid = reader->getInt();
reader->moveNext();
if (fields_processed)
{
@ -560,8 +555,6 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
const char* source = checkNull(rid, fid, (char*) reader->getBytes(), length);
reader->moveNext();
if (rid == rel_mon_database) // special case for MON$DATABASE
{
if (fid == f_mon_db_name)
@ -571,13 +564,13 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
if (record && allowed && our_dbb)
{
putField(record, fid, source, length);
putField(record, fid, reader, source == NULL);
fields_processed = true;
}
}
else if (record && allowed) // generic logic that covers all other relations
{
putField(record, fid, source, length);
putField(record, fid, reader, source == NULL);
fields_processed = true;
}
}
@ -644,26 +637,26 @@ void DatabaseSnapshot::clearRecord(Record* record)
}
void DatabaseSnapshot::putField(Record* record, int id, const void* source, size_t length)
void DatabaseSnapshot::putField(Record* record, int id, const Firebird::ClumpletReader* reader, bool makeNull)
{
fb_assert(record);
const Format* const format = record->rec_format;
fb_assert(format && id < format->fmt_count);
const dsc desc = format->fmt_desc[id];
UCHAR* const address = record->rec_data + (IPTR) desc.dsc_address;
if (!source)
if (makeNull)
{
SET_NULL(record, id);
return;
}
if (length == sizeof(SINT64) && desc.dsc_dtype == dtype_long)
const dsc desc = format->fmt_desc[id];
UCHAR* const address = record->rec_data + (IPTR) desc.dsc_address;
if (reader->getClumpLength() == sizeof(SINT64) && desc.dsc_dtype == dtype_long)
{
// special case: translate 64-bit global ID into 32-bit local ID
const SINT64 global_id = *(SINT64*) source;
const SINT64 global_id = reader->getBigInt();
SLONG local_id = 0;
if (!idMap.get(global_id, local_id))
{
@ -678,18 +671,18 @@ void DatabaseSnapshot::putField(Record* record, int id, const void* source, size
switch (desc.dsc_dtype) {
case dtype_text:
{
const char* const string = (char*) source;
const char* const string = (char*) reader->getBytes();
const size_t max_length = desc.dsc_length;
length = MIN(length, max_length);
const size_t length = MIN(reader->getClumpLength(), max_length);
memcpy(address, string, length);
memset(address + length, ' ', max_length - length);
}
break;
case dtype_varying:
{
const char* const string = (char*) source;
const char* const string = (char*) reader->getBytes();
const size_t max_length = desc.dsc_length - sizeof(USHORT);
length = MIN(length, max_length);
const size_t length = MIN(reader->getClumpLength(), max_length);
vary* varying = (vary*) address;
varying->vary_length = length;
memcpy(varying->vary_string, string, length);
@ -697,30 +690,30 @@ void DatabaseSnapshot::putField(Record* record, int id, const void* source, size
break;
case dtype_short:
*(SSHORT*) address = *(SSHORT*) source;
*(SSHORT*) address = reader->getBigInt();
break;
case dtype_long:
*(SLONG*) address = *(SLONG*) source;
*(SLONG*) address = reader->getBigInt();
break;
case dtype_int64:
*(SINT64*) address = *(SINT64*) source;
*(SINT64*) address = reader->getBigInt();
break;
case dtype_real:
*(float*) address = *(float*) source;
*(float*) address = reader->getDouble();
break;
case dtype_double:
*(double*) address = *(double*) source;
*(double*) address = reader->getDouble();
break;
case dtype_sql_date:
*(ISC_DATE*) address = *(ISC_DATE*) source;
*(ISC_DATE*) address = reader->getDate();
break;
case dtype_sql_time:
*(ISC_TIME*) address = *(ISC_TIME*) source;
*(ISC_TIME*) address = reader->getTime();
break;
case dtype_timestamp:
*(ISC_TIMESTAMP*) address = *(ISC_TIMESTAMP*) source;
*(ISC_TIMESTAMP*) address = reader->getTimeStamp();
break;
case dtype_blob:
@ -755,9 +748,9 @@ void DatabaseSnapshot::putField(Record* record, int id, const void* source, size
blb* blob = BLB_create2(tdbb, tdbb->getTransaction(), &blob_id,
bpb.getCount(), bpb.begin());
length = MIN(length, MAX_USHORT);
const size_t length = MIN(reader->getClumpLength(), MAX_USHORT);
BLB_put_segment(tdbb, blob, (const UCHAR*) source, length);
BLB_put_segment(tdbb, blob, reader->getBytes(), length);
BLB_close(tdbb, blob);
*(bid*) address = blob_id;
@ -996,9 +989,7 @@ void DatabaseSnapshot::putDatabase(const Database* database,
temp = (database->dbb_flags & DBB_no_reserve) ? 0 : 1;
writer.insertInt(f_mon_db_res_space, temp);
// creation date
writer.insertBytes(f_mon_db_created,
(UCHAR*) &database->dbb_creation_date.value(),
sizeof(ISC_TIMESTAMP));
writer.insertTimeStamp(f_mon_db_created, database->dbb_creation_date.value());
// database size
writer.insertBigInt(f_mon_db_pages, PageSpace::actAlloc(database));
@ -1078,9 +1069,7 @@ void DatabaseSnapshot::putAttachment(const Attachment* attachment,
// charset
writer.insertInt(f_mon_att_charset_id, attachment->att_charset);
// timestamp
writer.insertBytes(f_mon_att_timestamp,
(UCHAR*) &attachment->att_timestamp.value(),
sizeof(ISC_TIMESTAMP));
writer.insertTimeStamp(f_mon_att_timestamp, attachment->att_timestamp.value());
// garbage collection flag
temp = (attachment->att_flags & ATT_no_cleanup) ? 0 : 1;
writer.insertInt(f_mon_att_gc, temp);
@ -1110,9 +1099,7 @@ void DatabaseSnapshot::putTransaction(const jrd_tra* transaction,
temp = transaction->tra_requests ? mon_state_active : mon_state_idle;
writer.insertInt(f_mon_tra_state, temp);
// timestamp
writer.insertBytes(f_mon_tra_timestamp,
(UCHAR*) &transaction->tra_timestamp.value(),
sizeof(ISC_TIMESTAMP));
writer.insertTimeStamp(f_mon_tra_timestamp, transaction->tra_timestamp.value());
// top transaction
writer.insertInt(f_mon_tra_top, transaction->tra_top);
// oldest transaction
@ -1173,17 +1160,13 @@ void DatabaseSnapshot::putRequest(const jrd_req* request,
const int tra_id = request->req_transaction ?
request->req_transaction->tra_number : 0;
writer.insertInt(f_mon_stmt_tra_id, tra_id);
writer.insertBytes(f_mon_stmt_timestamp,
(UCHAR*) &request->req_timestamp.value(),
sizeof(ISC_TIMESTAMP));
writer.insertTimeStamp(f_mon_stmt_timestamp, request->req_timestamp.value());
}
else {
writer.insertInt(f_mon_stmt_state, mon_state_idle);
writer.insertInt(f_mon_stmt_tra_id, 0);
ISC_TIMESTAMP empty = {0, 0};
writer.insertBytes(f_mon_stmt_timestamp,
(UCHAR*) &empty,
sizeof(ISC_TIMESTAMP));
writer.insertTimeStamp(f_mon_stmt_timestamp, empty);
}
// sql text
writer.insertString(f_mon_stmt_sql_text, request->req_sql_text);
@ -1238,9 +1221,7 @@ void DatabaseSnapshot::putCall(const jrd_req* request,
writer.insertInt(f_mon_call_type, 0);
}
// timestamp
writer.insertBytes(f_mon_call_timestamp,
(const UCHAR*) &request->req_timestamp.value(),
sizeof(ISC_TIMESTAMP));
writer.insertTimeStamp(f_mon_call_timestamp, request->req_timestamp.value());
// source line/column
writer.insertInt(f_mon_call_src_line, request->req_src_line);
writer.insertInt(f_mon_call_src_column, request->req_src_column);

View File

@ -115,7 +115,7 @@ protected:
private:
RecordBuffer* allocBuffer(thread_db*, MemoryPool&, int);
void clearRecord(Record*);
void putField(Record*, int, const void*, size_t);
void putField(Record*, int, const Firebird::ClumpletReader*, bool);
static Firebird::ClumpletReader* dumpData(thread_db*, bool);
static const char* checkNull(int, int, const char*, size_t);

View File

@ -805,6 +805,43 @@ void GDS_breakpoint(int);
#define CONST64(a) (a##LL)
#endif
// 30 Dec 2002. Nickolay Samofatov
// This needs to be checked for all supported platforms
// The simpliest way to check it is to issue from correct client:
// declare external function abs2 double precision
// returns double precision by value
// entry_point 'IB_UDF_abs' module_name 'ib_udf';
// select abs2(2.0 / 3.0) from rdb$database;
// It will return big strange value in case of invalid define
// ASF: Currently, all little-endian are FB_SWAP_DOUBLE and big-endian aren't.
// AP: Define it for your hardware correctly in case your CPU do not follow mentioned rule.
// The follwoing lines are kept for reference only.
//#if defined(i386) || defined(I386) || defined(_M_IX86) || defined(AMD64) || defined(ARM) || defined(MIPSEL) || defined(DARWIN64) || defined(IA64)
//#define FB_SWAP_DOUBLE 1
//#elif defined(sparc) || defined(PowerPC) || defined(PPC) || defined(__ppc__) || defined(HPUX) || defined(MIPS) || defined(__ppc64__)
//#define FB_SWAP_DOUBLE 0
//#else
//#error "Define FB_SWAP_DOUBLE for your platform correctly !"
//#endif
#ifndef FB_SWAP_DOUBLE
#ifdef WORDS_BIGENDIAN
#define FB_SWAP_DOUBLE 0
#else
#define FB_SWAP_DOUBLE 1
#endif
#endif
// Commonly used indices to access parts of double in correct order.
#if FB_SWAP_DOUBLE
#define FB_LONG_DOUBLE_FIRST 1
#define FB_LONG_DOUBLE_SECOND 0
#else
#define FB_LONG_DOUBLE_FIRST 0
#define FB_LONG_DOUBLE_SECOND 1
#endif
/* switch name and state table. This structure should be used in all
* command line tools to facilitate parsing options.*/

View File

@ -33,43 +33,6 @@
#include "../remote/xdr_proto.h"
#include "../jrd/gds_proto.h"
// 30 Dec 2002. Nickolay Samofatov
// This needs to be checked for all supported platforms
// The simpliest way to check it is to issue from correct client:
// declare external function abs2 double precision
// returns double precision by value
// entry_point 'IB_UDF_abs' module_name 'ib_udf';
// select abs2(2.0 / 3.0) from rdb$database;
// It will return big strange value in case of invalid define
/*
// ASF: Currently, all little-endian are FB_SWAP_DOUBLE and big-endian aren't.
// AP: Left this lines as a reference in case some CPU in the future do not follow mentioned rule.
#if defined(i386) || defined(I386) || defined(_M_IX86) || defined(AMD64) || defined(ARM) || defined(MIPSEL) || defined(DARWIN64) || defined(IA64)
#define FB_SWAP_DOUBLE 1
#elif defined(sparc) || defined(PowerPC) || defined(PPC) || defined(__ppc__) || defined(HPUX) || defined(MIPS) || defined(__ppc64__)
#define FB_SWAP_DOUBLE 0
#else
#error "Define FB_SWAP_DOUBLE for your platform correctly !"
#endif
*/
#ifndef FB_SWAP_DOUBLE
#ifdef WORDS_BIGENDIAN
#define FB_SWAP_DOUBLE 0
#else
#define FB_SWAP_DOUBLE 1
#endif
#endif
#if FB_SWAP_DOUBLE
#define FB_LONG_DOUBLE_FIRST 1
#define FB_LONG_DOUBLE_SECOND 0
#else
#define FB_LONG_DOUBLE_FIRST 0
#define FB_LONG_DOUBLE_SECOND 1
#endif
#ifdef BURP
#include "../burp/misc_proto.h" /* Was "../burp/misc_pro.h" -Jeevan */
inline UCHAR* XDR_ALLOC(ULONG size) {