8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 23:23:04 +01:00

Fixed related issues:

CORE-1518 - Adding a non-null restricted column to a populated table renders the table inconsistent
CORE-2696 - "alter table" command can add a field which has "not null" definition
CORE-1748 - Unrestorable backup
CORE-1355 - Zero display instead of NULL
This commit is contained in:
asfernandes 2009-11-18 14:24:47 +00:00
parent 0abb648980
commit 218f419b5c
7 changed files with 326 additions and 95 deletions

View File

@ -95,6 +95,7 @@
#include "../jrd/dpm_proto.h" #include "../jrd/dpm_proto.h"
#include "../jrd/dsc_proto.h" #include "../jrd/dsc_proto.h"
#include "../jrd/err_proto.h" #include "../jrd/err_proto.h"
#include "../jrd/evl_proto.h"
#include "../jrd/exe_proto.h" #include "../jrd/exe_proto.h"
#include "../jrd/ext_proto.h" #include "../jrd/ext_proto.h"
#include "../jrd/gds_proto.h" #include "../jrd/gds_proto.h"
@ -113,6 +114,7 @@
#include "../jrd/scl_proto.h" #include "../jrd/scl_proto.h"
#include "../jrd/sdw_proto.h" #include "../jrd/sdw_proto.h"
#include "../jrd/thread_proto.h" #include "../jrd/thread_proto.h"
#include "../jrd/tra_proto.h"
#include "../jrd/event_proto.h" #include "../jrd/event_proto.h"
#include "../jrd/nbak.h" #include "../jrd/nbak.h"
#include "../jrd/trig.h" #include "../jrd/trig.h"
@ -4776,6 +4778,21 @@ static Format* make_format(thread_db* tdbb, jrd_rel* relation, USHORT* version,
*desc = tfb->tfb_desc; *desc = tfb->tfb_desc;
if (tfb->tfb_flags & TFB_computed) if (tfb->tfb_flags & TFB_computed)
desc->dsc_dtype |= COMPUTED_FLAG; desc->dsc_dtype |= COMPUTED_FLAG;
format->fmt_defaults[tfb->tfb_id] = tfb->tfb_default;
format->fmt_defaults[tfb->tfb_id].vlu_misc = tfb->tfb_default.vlu_misc;
if (tfb->tfb_default.vlu_string)
{
fb_assert(format->fmt_defaults[tfb->tfb_id].vlu_desc.dsc_dtype == dtype_text);
format->fmt_defaults[tfb->tfb_id].vlu_desc.dsc_address =
format->fmt_defaults[tfb->tfb_id].vlu_string->str_data;
}
else
{
format->fmt_defaults[tfb->tfb_id].vlu_desc.dsc_address =
(UCHAR*) &format->fmt_defaults[tfb->tfb_id].vlu_misc;
}
} }
/* Compute the offsets of the various fields */ /* Compute the offsets of the various fields */
@ -4847,18 +4864,19 @@ static Format* make_format(thread_db* tdbb, jrd_rel* relation, USHORT* version,
FMTS.RDB$RELATION_ID = relation->rel_id; FMTS.RDB$RELATION_ID = relation->rel_id;
blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &FMTS.RDB$DESCRIPTOR); blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &FMTS.RDB$DESCRIPTOR);
if (sizeof(Ods::Descriptor) == sizeof(struct dsc) || dbb->dbb_ods_version < ODS_VERSION11) if (dbb->dbb_ods_version < ODS_VERSION11)
{ {
// For ODS10 and earlier put descriptors in their in-memory representation // For ODS10 and earlier put descriptors in their in-memory representation
// This makes 64-bit and 32-bit ODS10 different for the same architecture. // This makes 64-bit and 32-bit ODS10 different for the same architecture.
BLB_put_segment(tdbb, blob, reinterpret_cast<const UCHAR*>(&(format->fmt_desc[0])), BLB_put_segment(tdbb, blob, reinterpret_cast<const UCHAR*>(&(format->fmt_desc[0])),
(USHORT)(format->fmt_count * sizeof(dsc))); (USHORT)(format->fmt_count * sizeof(dsc)));
} }
else { else
{
// Use generic representation of formats with 32-bit offsets // Use generic representation of formats with 32-bit offsets
Firebird::Array<Ods::Descriptor> odsDescs; Firebird::Array<Ods::Descriptor> odsDescs;
Ods::Descriptor *odsDesc = odsDescs.getBuffer(format->fmt_count); Ods::Descriptor* odsDesc = odsDescs.getBuffer(format->fmt_count);
for (Format::fmt_desc_const_iterator desc = format->fmt_desc.begin(); for (Format::fmt_desc_const_iterator desc = format->fmt_desc.begin();
desc < format->fmt_desc.end(); ++desc, ++odsDesc) desc < format->fmt_desc.end(); ++desc, ++odsDesc)
@ -4866,8 +4884,47 @@ static Format* make_format(thread_db* tdbb, jrd_rel* relation, USHORT* version,
*odsDesc = *desc; *odsDesc = *desc;
} }
BLB_put_segment(tdbb, blob, (UCHAR*) odsDescs.begin(), HalfStaticArray<UCHAR, BUFFER_MEDIUM> buffer;
odsDescs.getCount() * sizeof(Ods::Descriptor));
if (dbb->dbb_ods_version >= ODS_VERSION12)
{
buffer.add(UCHAR(format->fmt_count));
buffer.add(UCHAR(format->fmt_count >> 8));
}
buffer.add((UCHAR*) odsDescs.begin(), odsDescs.getCount() * sizeof(Ods::Descriptor));
if (dbb->dbb_ods_version >= ODS_VERSION12)
{
size_t pos = buffer.getCount();
buffer.add(0);
buffer.add(0);
USHORT i = 0, dflCount = 0;
for (Format::fmt_defaults_iterator impure = format->fmt_defaults.begin();
impure != format->fmt_defaults.end(); ++impure, ++i)
{
if (!impure->vlu_desc.isUnknown())
{
dsc desc = impure->vlu_desc;
desc.dsc_address = NULL;
Ods::Descriptor odsDflDesc = desc;
buffer.add(UCHAR(i));
buffer.add(UCHAR(i >> 8));
buffer.add((UCHAR*) &odsDflDesc, sizeof(odsDflDesc));
buffer.add(impure->vlu_desc.dsc_address, impure->vlu_desc.dsc_length);
++dflCount;
}
}
buffer[pos] = UCHAR(dflCount);
buffer[pos + 1] = UCHAR(dflCount >> 8);
}
BLB_put_segment(tdbb, blob, buffer.begin(), buffer.getCount());
} }
BLB_close(tdbb, blob); BLB_close(tdbb, blob);
END_STORE; END_STORE;
@ -4995,7 +5052,24 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work,
{ {
RFR.RDB$FIELD_ID = REL.RDB$FIELD_ID; RFR.RDB$FIELD_ID = REL.RDB$FIELD_ID;
RFR.RDB$FIELD_ID.NULL = FALSE; RFR.RDB$FIELD_ID.NULL = FALSE;
bool notNull = (RFR.RDB$NULL_FLAG.NULL ?
(FLD.RDB$NULL_FLAG.NULL ? false : (bool) FLD.RDB$NULL_FLAG) :
(bool) RFR.RDB$NULL_FLAG);
if (notNull)
{
dsc desc;
desc.makeText(strlen(REL.RDB$RELATION_NAME), CS_METADATA,
(UCHAR*) REL.RDB$RELATION_NAME);
DeferredWork* work = DFW_post_work(transaction,
dfw_check_not_null, &desc, 0);
Array<int>& ids = DFW_get_ids(work);
ids.add(RFR.RDB$FIELD_ID);
}
} }
REL.RDB$FIELD_ID++; REL.RDB$FIELD_ID++;
} }
if (RFR.RDB$UPDATE_FLAG.NULL) if (RFR.RDB$UPDATE_FLAG.NULL)
@ -5039,12 +5113,18 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work,
fb_utils::name_length(RFR.RDB$BASE_FIELD)); fb_utils::name_length(RFR.RDB$BASE_FIELD));
} }
put_summary_blob(tdbb, blob, RSR_missing_value, &FLD.RDB$MISSING_VALUE, transaction); put_summary_blob(tdbb, blob, RSR_missing_value, &FLD.RDB$MISSING_VALUE, transaction);
put_summary_blob(tdbb, blob, RSR_default_value,
(RFR.RDB$DEFAULT_VALUE.isEmpty() ? bid* defaultValue = RFR.RDB$DEFAULT_VALUE.isEmpty() ?
&FLD.RDB$DEFAULT_VALUE : &FLD.RDB$DEFAULT_VALUE : &RFR.RDB$DEFAULT_VALUE;
&RFR.RDB$DEFAULT_VALUE), transaction);
put_summary_blob(tdbb, blob, RSR_default_value, defaultValue, transaction);
put_summary_blob(tdbb, blob, RSR_validation_blr, &FLD.RDB$VALIDATION_BLR, transaction); put_summary_blob(tdbb, blob, RSR_validation_blr, &FLD.RDB$VALIDATION_BLR, transaction);
if (FLD.RDB$NULL_FLAG || RFR.RDB$NULL_FLAG)
bool notNull = (RFR.RDB$NULL_FLAG.NULL ?
(FLD.RDB$NULL_FLAG.NULL ? false : (bool) FLD.RDB$NULL_FLAG) :
(bool) RFR.RDB$NULL_FLAG);
if (notNull)
{ {
put_summary_record(tdbb, blob, RSR_field_not_null, put_summary_record(tdbb, blob, RSR_field_not_null,
nonnull_validation_blr, sizeof(nonnull_validation_blr)); nonnull_validation_blr, sizeof(nonnull_validation_blr));
@ -5061,6 +5141,67 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work,
tfb->tfb_next = stack; tfb->tfb_next = stack;
stack = tfb; stack = tfb;
memset(&tfb->tfb_default, 0, sizeof(tfb->tfb_default));
if (notNull && !defaultValue->isEmpty())
{
Jrd::ContextPoolHolder context(tdbb, dbb->createPool());
jrd_req* defaultRequest = NULL;
try
{
jrd_nod* defaultNode = MET_parse_blob(tdbb, relation, defaultValue,
NULL, &defaultRequest, false);
{ // scope
AutoSetRestore2<jrd_req*, thread_db> autoRequest(tdbb,
&thread_db::getRequest, &thread_db::setRequest, defaultRequest);
defaultRequest->req_timestamp.validate();
TRA_attach_request(transaction, defaultRequest);
dsc* result = EVL_expr(tdbb, defaultNode);
TRA_detach_request(defaultRequest);
if (result)
{
tfb->tfb_default.vlu_desc = *result;
if (result->isText() || result->isBlob())
{
UCHAR* ptr = NULL;
MoveBuffer buffer;
int len = MOV_make_string2(tdbb, result, CS_NONE, &ptr, buffer, true);
VaryingString* newString = FB_NEW_RPT(*dbb->dbb_permanent,
len) VaryingString();
newString->str_length = USHORT(len);
memcpy(newString->str_data, ptr, len);
tfb->tfb_default.vlu_string = newString;
tfb->tfb_default.vlu_desc.dsc_dtype = dtype_text;
tfb->tfb_default.vlu_desc.dsc_length = USHORT(len);
tfb->tfb_default.vlu_desc.dsc_address = newString->str_data;
}
else
{
memcpy(&tfb->tfb_default.vlu_misc, result->dsc_address,
result->dsc_length);
tfb->tfb_default.vlu_desc.dsc_address =
(UCHAR*) &tfb->tfb_default.vlu_misc;
}
}
}
}
catch (const Exception&)
{
if (defaultRequest)
CMP_release(tdbb, defaultRequest);
throw;
}
CMP_release(tdbb, defaultRequest);
}
/* for text data types, grab the CHARACTER_SET and /* for text data types, grab the CHARACTER_SET and
COLLATION to give the type of international text */ COLLATION to give the type of international text */

View File

@ -1247,6 +1247,29 @@ bool EVL_field(jrd_rel* relation, Record* record, USHORT id, dsc* desc)
if (record && record->rec_format && relation) if (record && record->rec_format && relation)
{ {
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
if (dbb->dbb_ods_version >= ODS_VERSION12)
{
while (format &&
(id >= format->fmt_defaults.getCount() ||
format->fmt_defaults[id].vlu_desc.isUnknown()))
{
if (format->fmt_version >= relation->rel_current_format->fmt_version)
{
format = NULL;
break;
}
format = MET_format(tdbb, relation, format->fmt_version + 1);
}
return format && !(*desc = format->fmt_defaults[id].vlu_desc).isUnknown();
}
// Legacy ODS logic
/* A database sweep does not scan a relation's metadata. However /* A database sweep does not scan a relation's metadata. However
* the change to substitute a default value for a missing "not null" * the change to substitute a default value for a missing "not null"
* field makes it necessary to reference the field block. * field makes it necessary to reference the field block.

View File

@ -191,74 +191,6 @@ public:
const size_t asb_delta = ((sizeof(AggregateSort) - sizeof(jrd_nod)) / sizeof (jrd_nod**)); const size_t asb_delta = ((sizeof(AggregateSort) - sizeof(jrd_nod)) / sizeof (jrd_nod**));
// Various structures in the impure area
struct impure_state
{
SSHORT sta_state;
};
struct impure_value
{
dsc vlu_desc;
USHORT vlu_flags; // Computed/invariant flags
VaryingString* vlu_string;
union
{
UCHAR vlu_uchar;
SSHORT vlu_short;
SLONG vlu_long;
SINT64 vlu_int64;
SQUAD vlu_quad;
SLONG vlu_dbkey[2];
float vlu_float;
double vlu_double;
GDS_TIMESTAMP vlu_timestamp;
GDS_TIME vlu_sql_time;
GDS_DATE vlu_sql_date;
bid vlu_bid;
void* vlu_invariant; // Pre-compiled invariant object for nod_like and other string functions
} vlu_misc;
void make_long(const SLONG val, const signed char scale = 0);
void make_int64(const SINT64 val, const signed char scale = 0);
};
// Do not use these methods where dsc_sub_type is not explicitly set to zero.
inline void impure_value::make_long(const SLONG val, const signed char scale)
{
this->vlu_misc.vlu_long = val;
this->vlu_desc.dsc_dtype = dtype_long;
this->vlu_desc.dsc_length = sizeof(SLONG);
this->vlu_desc.dsc_scale = scale;
this->vlu_desc.dsc_sub_type = 0;
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_long);
}
inline void impure_value::make_int64(const SINT64 val, const signed char scale)
{
this->vlu_misc.vlu_int64 = val;
this->vlu_desc.dsc_dtype = dtype_int64;
this->vlu_desc.dsc_length = sizeof(SINT64);
this->vlu_desc.dsc_scale = scale;
this->vlu_desc.dsc_sub_type = 0;
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_int64);
}
struct impure_value_ex : public impure_value
{
SLONG vlux_count;
blb* vlu_blob;
};
const int VLU_computed = 1; // An invariant sub-query has been computed
const int VLU_null = 2; // An invariant sub-query computed to null
const int VLU_checked = 4; // Constraint already checked in first read or assignment to argument/variable
// Inversion (i.e. nod_index) impure area // Inversion (i.e. nod_index) impure area
struct impure_inversion struct impure_inversion

View File

@ -936,16 +936,6 @@ typedef Firebird::HalfStaticArray<UCHAR, 256> MoveBuffer;
} //namespace Jrd } //namespace Jrd
// Random string block -- as long as impure areas don't have
// constructors and destructors, the need this varying string
class VaryingString : public pool_alloc_rpt<SCHAR, type_str>
{
public:
USHORT str_length;
UCHAR str_data[2]; // one byte for ALLOC and one for the NULL
};
// Threading macros // Threading macros
/* Define JRD_get_thread_data off the platform specific version. /* Define JRD_get_thread_data off the platform specific version.

View File

@ -1207,7 +1207,7 @@ Format* MET_format(thread_db* tdbb, jrd_rel* relation, USHORT number)
} }
blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, &X.RDB$DESCRIPTOR); blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, &X.RDB$DESCRIPTOR);
if (sizeof(Ods::Descriptor) == sizeof(struct dsc) || dbb->dbb_ods_version < ODS_VERSION11) if (dbb->dbb_ods_version < ODS_VERSION11)
{ {
// For ODS10 and earlier read descriptors in their in-memory representation // For ODS10 and earlier read descriptors in their in-memory representation
// This makes 64-bit and 32-bit ODS10 different for the same architecture. // This makes 64-bit and 32-bit ODS10 different for the same architecture.
@ -1231,11 +1231,24 @@ Format* MET_format(thread_db* tdbb, jrd_rel* relation, USHORT number)
{ {
// Use generic representation of formats with 32-bit offsets // Use generic representation of formats with 32-bit offsets
const USHORT count = blob->blb_length / sizeof(Ods::Descriptor); HalfStaticArray<UCHAR, BUFFER_MEDIUM> buffer;
BLB_get_data(tdbb, blob, buffer.getBuffer(blob->blb_length), blob->blb_length);
unsigned bufferPos = 0;
USHORT count;
if (dbb->dbb_ods_version >= ODS_VERSION12)
{
count = buffer[0] | (buffer[1] << 8);
bufferPos = 2;
}
else
count = buffer.getCount() / sizeof(Ods::Descriptor);
format = Format::newFormat(*dbb->dbb_permanent, count); format = Format::newFormat(*dbb->dbb_permanent, count);
Firebird::Array<Ods::Descriptor> odsDescs; Firebird::Array<Ods::Descriptor> odsDescs;
Ods::Descriptor *odsDesc = odsDescs.getBuffer(count); Ods::Descriptor* odsDesc = odsDescs.getBuffer(count);
BLB_get_data(tdbb, blob, (UCHAR*) odsDesc, blob->blb_length); memcpy(odsDesc, buffer.begin() + bufferPos, count * sizeof(Ods::Descriptor));
for (Format::fmt_desc_iterator desc = format->fmt_desc.begin(); for (Format::fmt_desc_iterator desc = format->fmt_desc.begin();
desc < format->fmt_desc.end(); ++desc, ++odsDesc) desc < format->fmt_desc.end(); ++desc, ++odsDesc)
@ -1244,6 +1257,40 @@ Format* MET_format(thread_db* tdbb, jrd_rel* relation, USHORT number)
if (odsDesc->dsc_offset) if (odsDesc->dsc_offset)
format->fmt_length = odsDesc->dsc_offset + desc->dsc_length; format->fmt_length = odsDesc->dsc_offset + desc->dsc_length;
} }
if (dbb->dbb_ods_version >= ODS_VERSION12)
{
UCHAR* p = buffer.begin() + bufferPos + count * sizeof(Ods::Descriptor);
count = p[0] | (p[1] << 8);
p += 2;
while (count-- > 0)
{
USHORT offset = p[0] | (p[1] << 8);
p += 2;
Ods::Descriptor* odsDflDesc = (Ods::Descriptor*) p;
p = (UCHAR*) (odsDflDesc + 1);
dsc& desc = format->fmt_defaults[offset].vlu_desc;
desc = *odsDflDesc;
if (desc.dsc_dtype == dtype_text)
{
VaryingString* vluString = FB_NEW_RPT(*dbb->dbb_permanent,
desc.dsc_length) VaryingString();
vluString->str_length = desc.dsc_length;
format->fmt_defaults[offset].vlu_string = vluString;
desc.dsc_address = format->fmt_defaults[offset].vlu_string->str_data;
}
else
desc.dsc_address = (UCHAR*) &format->fmt_defaults[offset].vlu_misc;
memcpy(desc.dsc_address, p, desc.dsc_length);
p += desc.dsc_length;
}
}
} }
END_FOR; END_FOR;

View File

@ -58,9 +58,10 @@ class TemporaryField : public pool_alloc<type_tfb>
{ {
public: public:
TemporaryField* tfb_next; /* next block in chain */ TemporaryField* tfb_next; /* next block in chain */
USHORT tfb_id; /* id of field in relation */ USHORT tfb_id; /* id of field in relation */
USHORT tfb_flags; USHORT tfb_flags;
DSC tfb_desc; dsc tfb_desc;
Jrd::impure_value tfb_default;
}; };
// tfb_flags // tfb_flags

View File

@ -34,11 +34,22 @@
#include "../common/classes/MetaName.h" #include "../common/classes/MetaName.h"
#include "../common/classes/QualifiedName.h" #include "../common/classes/QualifiedName.h"
#include "../jrd/blb.h"
#include "../jrd/dsc.h" #include "../jrd/dsc.h"
#include "../jrd/ExtEngineManager.h" #include "../jrd/ExtEngineManager.h"
#define FLAG_BYTES(n) (((n + BITS_PER_LONG) & ~((ULONG)BITS_PER_LONG - 1)) >> 3) #define FLAG_BYTES(n) (((n + BITS_PER_LONG) & ~((ULONG)BITS_PER_LONG - 1)) >> 3)
// Random string block -- as long as impure areas don't have
// constructors and destructors, the need this varying string
class VaryingString : public pool_alloc_rpt<SCHAR, type_str>
{
public:
USHORT str_length;
UCHAR str_data[2]; // one byte for ALLOC and one for the NULL
};
const UCHAR DEFAULT_DOUBLE = dtype_double; const UCHAR DEFAULT_DOUBLE = dtype_double;
const ULONG MAX_FORMAT_SIZE = 65535; const ULONG MAX_FORMAT_SIZE = 65535;
@ -50,14 +61,96 @@ class jrd_req;
class jrd_tra; class jrd_tra;
class Symbol; class Symbol;
// Various structures in the impure area
struct impure_state
{
SSHORT sta_state;
};
struct impure_value
{
dsc vlu_desc;
USHORT vlu_flags; // Computed/invariant flags
VaryingString* vlu_string;
union
{
UCHAR vlu_uchar;
SSHORT vlu_short;
SLONG vlu_long;
SINT64 vlu_int64;
SQUAD vlu_quad;
SLONG vlu_dbkey[2];
float vlu_float;
double vlu_double;
GDS_TIMESTAMP vlu_timestamp;
GDS_TIME vlu_sql_time;
GDS_DATE vlu_sql_date;
bid vlu_bid;
void* vlu_invariant; // Pre-compiled invariant object for nod_like and other string functions
} vlu_misc;
void make_long(const SLONG val, const signed char scale = 0);
void make_int64(const SINT64 val, const signed char scale = 0);
};
// Do not use these methods where dsc_sub_type is not explicitly set to zero.
inline void impure_value::make_long(const SLONG val, const signed char scale)
{
this->vlu_misc.vlu_long = val;
this->vlu_desc.dsc_dtype = dtype_long;
this->vlu_desc.dsc_length = sizeof(SLONG);
this->vlu_desc.dsc_scale = scale;
this->vlu_desc.dsc_sub_type = 0;
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_long);
}
inline void impure_value::make_int64(const SINT64 val, const signed char scale)
{
this->vlu_misc.vlu_int64 = val;
this->vlu_desc.dsc_dtype = dtype_int64;
this->vlu_desc.dsc_length = sizeof(SINT64);
this->vlu_desc.dsc_scale = scale;
this->vlu_desc.dsc_sub_type = 0;
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_int64);
}
struct impure_value_ex : public impure_value
{
SLONG vlux_count;
blb* vlu_blob;
};
const int VLU_computed = 1; // An invariant sub-query has been computed
const int VLU_null = 2; // An invariant sub-query computed to null
const int VLU_checked = 4; // Constraint already checked in first read or assignment to argument/variable
class Format : public pool_alloc<type_fmt> class Format : public pool_alloc<type_fmt>
{ {
public: public:
Format(MemoryPool& p, int len) Format(MemoryPool& p, int len)
: fmt_count(len), fmt_desc(p, fmt_count) : fmt_count(len), fmt_desc(p, fmt_count), fmt_defaults(p, fmt_count)
{ {
fmt_desc.resize(fmt_count); fmt_desc.resize(fmt_count);
fmt_defaults.resize(fmt_count);
for (fmt_defaults_iterator impure = fmt_defaults.begin();
impure != fmt_defaults.end(); ++impure)
{
memset(&*impure, 0, sizeof(*impure));
}
} }
~Format()
{
for (fmt_defaults_iterator impure = fmt_defaults.begin();
impure != fmt_defaults.end(); ++impure)
{
delete impure->vlu_string;
}
}
static Format* newFormat(MemoryPool& p, int len = 0) static Format* newFormat(MemoryPool& p, int len = 0)
{ {
return FB_NEW(p) Format(p, len); return FB_NEW(p) Format(p, len);
@ -67,8 +160,12 @@ public:
USHORT fmt_count; USHORT fmt_count;
USHORT fmt_version; USHORT fmt_version;
Firebird::Array<dsc> fmt_desc; Firebird::Array<dsc> fmt_desc;
Firebird::Array<impure_value> fmt_defaults;
typedef Firebird::Array<dsc>::iterator fmt_desc_iterator; typedef Firebird::Array<dsc>::iterator fmt_desc_iterator;
typedef Firebird::Array<dsc>::const_iterator fmt_desc_const_iterator; typedef Firebird::Array<dsc>::const_iterator fmt_desc_const_iterator;
typedef Firebird::Array<impure_value>::iterator fmt_defaults_iterator;
}; };