mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 21:23:04 +01:00
Improve gbak performance over network using batch interface
This commit is contained in:
parent
0a1b23004e
commit
520a28fc19
@ -1089,7 +1089,7 @@ void put_array( burp_fld* field, burp_rel* relation, ISC_QUAD* blob_id)
|
||||
lstring xdr_slice;
|
||||
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
|
||||
xdr_slice.lstr_address = slice;
|
||||
return_length = CAN_slice(&xdr_buffer, &xdr_slice, TRUE, /*blr_length,*/ blr_buffer);
|
||||
return_length = CAN_slice(&xdr_buffer, &xdr_slice, true, blr_buffer);
|
||||
put(tdgbl, att_xdr_array);
|
||||
put(tdgbl, (UCHAR) (return_length));
|
||||
put(tdgbl, (UCHAR) (return_length >> 8));
|
||||
@ -1684,7 +1684,7 @@ void put_data(burp_rel* relation)
|
||||
const UCHAR* p;
|
||||
if (tdgbl->gbl_sw_transportable)
|
||||
{
|
||||
record_length = CAN_encode_decode(relation, &xdr_buffer, buffer, TRUE);
|
||||
record_length = CAN_encode_decode(relation, &xdr_buffer, buffer, true);
|
||||
put_int32(att_xdr_length, record_length);
|
||||
p = xdr_buffer.lstr_address;
|
||||
}
|
||||
|
@ -664,12 +664,14 @@ struct burp_fld
|
||||
SSHORT fld_type;
|
||||
SSHORT fld_sub_type;
|
||||
FLD_LENGTH fld_length;
|
||||
FLD_LENGTH fld_total_len; // including additional 2 bytes for VARYING CHAR
|
||||
SSHORT fld_scale;
|
||||
SSHORT fld_position;
|
||||
SSHORT fld_parameter;
|
||||
SSHORT fld_missing_parameter;
|
||||
SSHORT fld_id;
|
||||
RCRD_OFFSET fld_offset;
|
||||
RCRD_OFFSET fld_missing_offset;
|
||||
RCRD_OFFSET fld_old_offset;
|
||||
SSHORT fld_number;
|
||||
SSHORT fld_system_flag;
|
||||
@ -698,6 +700,8 @@ struct burp_fld
|
||||
ISC_QUAD fld_default_source;
|
||||
SSHORT fld_character_set_id;
|
||||
SSHORT fld_collation_id;
|
||||
RCRD_OFFSET fld_sql;
|
||||
RCRD_OFFSET fld_null;
|
||||
};
|
||||
|
||||
enum fld_flags_vals {
|
||||
@ -958,6 +962,7 @@ public:
|
||||
bool gbl_sw_deactivate_indexes;
|
||||
bool gbl_sw_kill;
|
||||
USHORT gbl_sw_blk_factor;
|
||||
USHORT gbl_dialect;
|
||||
const SCHAR* gbl_sw_fix_fss_data;
|
||||
USHORT gbl_sw_fix_fss_data_id;
|
||||
const SCHAR* gbl_sw_fix_fss_metadata;
|
||||
@ -976,6 +981,7 @@ public:
|
||||
burp_fil* gbl_sw_files;
|
||||
burp_fil* gbl_sw_backup_files;
|
||||
gfld* gbl_global_fields;
|
||||
unsigned gbl_network_protocol;
|
||||
burp_act* action;
|
||||
ULONG io_buffer_size;
|
||||
redirect_vals sw_redirect;
|
||||
|
@ -24,8 +24,8 @@
|
||||
#ifndef BURP_CANON_PROTO_H
|
||||
#define BURP_CANON_PROTO_H
|
||||
|
||||
ULONG CAN_encode_decode (burp_rel*, lstring*, UCHAR*, int);
|
||||
ULONG CAN_slice (lstring*, lstring*, int, /*USHORT,*/ UCHAR*);
|
||||
ULONG CAN_encode_decode (burp_rel* relation, lstring* buffer, UCHAR* data, bool direction, bool useMissingOffset = false);
|
||||
ULONG CAN_slice (lstring* buffer, lstring* slice, bool direction, UCHAR* sdl);
|
||||
|
||||
#endif // BURP_CANON_PROTO_H
|
||||
|
||||
|
@ -63,7 +63,7 @@ static xdr_t::xdr_ops burp_ops =
|
||||
const int increment = 1024;
|
||||
|
||||
|
||||
ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool_t direction)
|
||||
ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool direction, bool useMissingOffset)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -203,17 +203,21 @@ ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool_t
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
UCHAR* p = data + offset;
|
||||
UCHAR* p = data + field->fld_missing_offset;
|
||||
if (!useMissingOffset)
|
||||
{
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
p = data + offset;
|
||||
offset += sizeof(SSHORT);
|
||||
}
|
||||
if (!xdr_short(xdrs, (SSHORT*) p))
|
||||
return FALSE;
|
||||
offset += sizeof(SSHORT);
|
||||
}
|
||||
return (xdrs->x_private - xdrs->x_base);
|
||||
}
|
||||
|
||||
|
||||
ULONG CAN_slice(lstring* buffer, lstring* slice, bool_t direction, /*USHORT sdl_length,*/ UCHAR* sdl)
|
||||
ULONG CAN_slice(lstring* buffer, lstring* slice, bool direction, UCHAR* sdl)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
|
@ -30,6 +30,10 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_CTYPE_H
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#include "../burp/burp.h"
|
||||
#include "../jrd/align.h"
|
||||
#include "../jrd/flags.h"
|
||||
@ -55,6 +59,7 @@
|
||||
#include "memory_routines.h"
|
||||
#include "../burp/OdsDetection.h"
|
||||
#include "../auth/trusted/AuthSspi.h"
|
||||
#include "../common/dsc_proto.h"
|
||||
|
||||
using MsgFormat::SafeArg;
|
||||
using Firebird::FbLocalStatus;
|
||||
@ -111,12 +116,14 @@ void fix_security_class_name(BurpGlobals* tdgbl, TEXT* sec_class, bool is_field)
|
||||
// returned value is not checked by the caller!
|
||||
bool get_acl(BurpGlobals* tdgbl, const TEXT*, ISC_QUAD*, ISC_QUAD*);
|
||||
void get_array(BurpGlobals* tdgbl, burp_rel*, UCHAR*);
|
||||
void get_blob(BurpGlobals* tdgbl, const burp_fld*, UCHAR*);
|
||||
void get_blob(BurpGlobals* tdgbl, Firebird::IBatch* batch, const burp_fld*, UCHAR*);
|
||||
void get_blob_old(BurpGlobals* tdgbl, const burp_fld*, UCHAR*);
|
||||
void get_blr_blob(BurpGlobals* tdgbl, ISC_QUAD&, bool);
|
||||
bool get_character_set(BurpGlobals* tdgbl);
|
||||
bool get_chk_constraint(BurpGlobals* tdgbl);
|
||||
bool get_collation(BurpGlobals* tdgbl);
|
||||
rec_type get_data(BurpGlobals* tdgbl, burp_rel*, bool);
|
||||
rec_type get_data_old(BurpGlobals* tdgbl, burp_rel*);
|
||||
bool get_exception(BurpGlobals* tdgbl);
|
||||
burp_fld* get_field(BurpGlobals* tdgbl, burp_rel*);
|
||||
bool get_field_dimensions(BurpGlobals* tdgbl);
|
||||
@ -930,7 +937,8 @@ void create_database(BurpGlobals* tdgbl, const TEXT* file_name)
|
||||
// When we restore backup files that came from prior
|
||||
// to V6, we force the SQL database dialect to 1
|
||||
|
||||
dpb.insertByte(isc_dpb_sql_dialect, SQL_dialect_flag ? SQL_dialect : SQL_DIALECT_V5);
|
||||
tdgbl->gbl_dialect = SQL_dialect_flag ? SQL_dialect : SQL_DIALECT_V5;
|
||||
dpb.insertByte(isc_dpb_sql_dialect, tdgbl->gbl_dialect);
|
||||
|
||||
// start database up shut down,
|
||||
// use single-user mode to avoid conflicts during restore process
|
||||
@ -956,6 +964,14 @@ void create_database(BurpGlobals* tdgbl, const TEXT* file_name)
|
||||
// msg 33 failed to create database %s
|
||||
}
|
||||
|
||||
tdgbl->gbl_network_protocol = DB->getRemoteProtocolVersion(&status_vector);
|
||||
// treat errors as old provider missing new calls
|
||||
if (status_vector->hasData())
|
||||
{
|
||||
status_vector->init();
|
||||
tdgbl->gbl_network_protocol = 1;
|
||||
}
|
||||
|
||||
if (tdgbl->gbl_sw_version && !tdgbl->uSvc->isService())
|
||||
{
|
||||
BURP_print(false, 139, file_name);
|
||||
@ -1759,7 +1775,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
||||
get_block(tdgbl, p, lcount);
|
||||
|
||||
if (tdgbl->gbl_sw_transportable)
|
||||
CAN_slice (&xdr_buffer, &xdr_slice, FALSE, /*blr_length,*/ blr_buffer);
|
||||
CAN_slice (&xdr_buffer, &xdr_slice, false, blr_buffer);
|
||||
}
|
||||
|
||||
DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer,
|
||||
@ -1885,7 +1901,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
||||
get_block(tdgbl, p, lcount);
|
||||
|
||||
if (tdgbl->gbl_sw_transportable)
|
||||
CAN_slice (&xdr_buffer, &xdr_slice, FALSE, /*blr_length,*/ blr_buffer);
|
||||
CAN_slice (&xdr_buffer, &xdr_slice, false, blr_buffer);
|
||||
|
||||
|
||||
DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer,
|
||||
@ -1908,7 +1924,108 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
||||
BURP_free (xdr_buffer.lstr_address);
|
||||
}
|
||||
|
||||
void get_blob(BurpGlobals* tdgbl, const burp_fld* fields, UCHAR* record_buffer)
|
||||
void get_blob(BurpGlobals* tdgbl, Firebird::IBatch* batch, const burp_fld* fields, UCHAR* record_buffer)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* g e t _ b l o b
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Read blob attributes and copy data from input file to nice,
|
||||
* shiny, new blob.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
// Pick up attributes
|
||||
|
||||
ULONG segments = 0;
|
||||
USHORT field_number = MAX_USHORT;
|
||||
USHORT max_segment = 0;
|
||||
UCHAR blob_type = 0;
|
||||
|
||||
att_type attribute;
|
||||
scan_attr_t scan_next_attr;
|
||||
skip_init(&scan_next_attr);
|
||||
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_blob_data)
|
||||
{
|
||||
switch (attribute)
|
||||
{
|
||||
case att_blob_field_number:
|
||||
field_number = (USHORT) get_int32(tdgbl);
|
||||
break;
|
||||
|
||||
case att_blob_max_segment:
|
||||
max_segment = (USHORT) get_int32(tdgbl);
|
||||
break;
|
||||
|
||||
case att_blob_number_segments:
|
||||
segments = get_int32(tdgbl);
|
||||
break;
|
||||
|
||||
case att_blob_type:
|
||||
blob_type = (UCHAR) get_int32(tdgbl);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 64);
|
||||
// msg 64 blob
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the field associated with the blob
|
||||
const burp_fld* field;
|
||||
for (field = fields; field; field = field->fld_next)
|
||||
{
|
||||
if (field->fld_number == field_number)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!field)
|
||||
{
|
||||
BURP_error_redirect(NULL, 36);
|
||||
// msg 36 Can't find field for blob
|
||||
}
|
||||
|
||||
// Create new blob
|
||||
|
||||
ISC_QUAD* blob_id = (ISC_QUAD*) ((UCHAR*) record_buffer + field->fld_offset);
|
||||
const UCHAR blob_desc[] = {isc_bpb_version1, isc_bpb_type, 1, blob_type};
|
||||
|
||||
BlobBuffer local_buffer;
|
||||
UCHAR* const buffer = local_buffer.getBuffer(max_segment);
|
||||
|
||||
FbLocalStatus status_vector;
|
||||
bool first = true;
|
||||
|
||||
// Eat up blob segments
|
||||
|
||||
for (; segments > 0; --segments )
|
||||
{
|
||||
USHORT length = get(tdgbl);
|
||||
length |= get(tdgbl) << 8;
|
||||
if (length)
|
||||
{
|
||||
get_block(tdgbl, buffer, length);
|
||||
}
|
||||
|
||||
if (first)
|
||||
batch->addBlob(&status_vector, length, buffer, blob_id, sizeof(blob_desc), blob_desc);
|
||||
else
|
||||
batch->appendBlobData(&status_vector, length, buffer);
|
||||
if (status_vector->hasData())
|
||||
{
|
||||
BURP_error_redirect(&status_vector, 38); // !!!!!!!!! new message
|
||||
// msg 38 isc_put_segment failed
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void get_blob_old(BurpGlobals* tdgbl, const burp_fld* fields, UCHAR* record_buffer)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -2710,14 +2827,507 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
|
||||
* Write data records for a relation.
|
||||
*
|
||||
**************************************/
|
||||
Firebird::IRequest* req_handle = 0;
|
||||
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
|
||||
ULONG records = 0;
|
||||
rec_type record;
|
||||
burp_fld* field;
|
||||
|
||||
// If we're only doing meta-data, ignore data records
|
||||
|
||||
if (tdgbl->gbl_sw_meta || skip_relation)
|
||||
return ignore_data(tdgbl, relation);
|
||||
|
||||
// For old versions and embedded connections switch to old style method
|
||||
// Avoid if possible switch to old style when system domains are used in a table
|
||||
|
||||
if (tdgbl->gbl_network_protocol == 0)
|
||||
{
|
||||
bool sysDomFlag = false;
|
||||
for (field = relation->rel_fields; field && (!sysDomFlag); field = field->fld_next)
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
|
||||
const char* dom = field->fld_source;
|
||||
if (strncmp(dom, "RDB$", 4) != 0)
|
||||
continue;
|
||||
|
||||
for (dom += 4; *dom; ++dom)
|
||||
{
|
||||
#ifdef HAVE_CTYPE_H
|
||||
if (!isdigit(*dom))
|
||||
#else
|
||||
if (*dom < '0' || *dom > '9')
|
||||
#endif
|
||||
{
|
||||
sysDomFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sysDomFlag)
|
||||
return get_data_old(tdgbl, relation);
|
||||
}
|
||||
else if (tdgbl->gbl_network_protocol < 16)
|
||||
return get_data_old(tdgbl, relation);
|
||||
|
||||
// Number of fields in a message
|
||||
|
||||
unsigned count = 0;
|
||||
for (field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (!(field->fld_flags & FLD_computed))
|
||||
++count;
|
||||
}
|
||||
|
||||
// Time to generate SQL and message metadata to store data. Whoppee.
|
||||
|
||||
try
|
||||
{
|
||||
Firebird::string sqlStatement;
|
||||
sqlStatement.printf("insert into %s(", relation->rel_name);
|
||||
|
||||
Firebird::RefPtr<Firebird::IMetadataBuilder> builder(Firebird::REF_NO_INCR,
|
||||
Firebird::MasterInterfacePtr()->getMetadataBuilder(fbStatus, count));
|
||||
if (fbStatus->hasData())
|
||||
general_on_error();
|
||||
|
||||
RCRD_OFFSET offset = 0;
|
||||
count = 0;
|
||||
for (field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
|
||||
USHORT dtype = field->fld_type;
|
||||
|
||||
// arrays are of various fld_types but are really blobs
|
||||
|
||||
if (field->fld_flags & FLD_array)
|
||||
dtype = blr_blob;
|
||||
|
||||
DSC desc;
|
||||
if (!DSC_make_descriptor(&desc, dtype, field->fld_scale, field->fld_length,
|
||||
field->fld_sub_type, field->fld_character_set_id, field->fld_collation_id))
|
||||
{
|
||||
BURP_error(26, true, SafeArg() << dtype);
|
||||
// msg 26 datatype %ld not understood
|
||||
}
|
||||
|
||||
SSHORT alignment = type_alignments[desc.dsc_dtype];
|
||||
if (alignment)
|
||||
offset = FB_ALIGN(offset, alignment);
|
||||
field->fld_offset = offset;
|
||||
offset += field->fld_total_len = desc.dsc_length;
|
||||
|
||||
SLONG sqlLength, sqlSubType, sqlScale, sqlType;
|
||||
desc.getSqlInfo(&sqlLength, &sqlSubType, &sqlScale, &sqlType);
|
||||
SLONG characterSetId = field->fld_character_set_id;
|
||||
|
||||
if (tdgbl->gbl_sw_fix_fss_data && field->fld_character_set_id == CS_UNICODE_FSS &&
|
||||
((sqlType == SQL_BLOB && field->fld_sub_type == isc_blob_text && !(field->fld_flags & FLD_array)) ||
|
||||
sqlType == SQL_TEXT || sqlType == SQL_VARYING))
|
||||
{
|
||||
characterSetId = tdgbl->gbl_sw_fix_fss_data_id;
|
||||
}
|
||||
else if (field->fld_flags & FLD_array)
|
||||
{
|
||||
sqlType = SQL_QUAD;
|
||||
sqlScale = 0;
|
||||
}
|
||||
|
||||
builder->setType(&tdgbl->throwStatus, count, sqlType);
|
||||
builder->setSubType(&tdgbl->throwStatus, count, sqlSubType);
|
||||
builder->setLength(&tdgbl->throwStatus, count, sqlLength);
|
||||
builder->setScale(&tdgbl->throwStatus, count, sqlScale);
|
||||
builder->setCharSet(&tdgbl->throwStatus, count, characterSetId);
|
||||
|
||||
sqlStatement += field->fld_name;
|
||||
sqlStatement += ", ";
|
||||
|
||||
field->fld_parameter = count++;
|
||||
}
|
||||
|
||||
fb_assert(sqlStatement.end()[-2] == ',');
|
||||
sqlStatement.end()[-2] = ')';
|
||||
|
||||
Firebird::RefPtr<Firebird::IMessageMetadata> meta(Firebird::REF_NO_INCR,
|
||||
builder->getMetadata(&tdgbl->throwStatus));
|
||||
builder = nullptr;
|
||||
|
||||
sqlStatement += "values (";
|
||||
|
||||
count = 0;
|
||||
for (field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
field->fld_missing_parameter = count;
|
||||
field->fld_missing_offset = offset;
|
||||
offset += sizeof(SSHORT);
|
||||
|
||||
field->fld_sql = meta->getOffset(&tdgbl->throwStatus, count);
|
||||
field->fld_null = meta->getNullOffset(&tdgbl->throwStatus, count);
|
||||
|
||||
if (tdgbl->gbl_sw_transportable)
|
||||
{
|
||||
field->fld_offset = field->fld_sql;
|
||||
field->fld_missing_offset = field->fld_null;
|
||||
}
|
||||
|
||||
sqlStatement += "?, ";
|
||||
++count;
|
||||
}
|
||||
|
||||
fb_assert(sqlStatement.end()[-2] == ',');
|
||||
sqlStatement.end()[-2] = ')';
|
||||
|
||||
RCRD_LENGTH length = offset;
|
||||
|
||||
// Create batch
|
||||
|
||||
const int GBAK_BATCH_STEP = 1000;
|
||||
Firebird::AutoDispose<Firebird::IXpbBuilder> pb(Firebird::UtilInterfacePtr()->
|
||||
getXpbBuilder(&tdgbl->throwStatus, Firebird::IXpbBuilder::BATCH, NULL, 0));
|
||||
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_MULTIERROR, 1);
|
||||
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_BLOB_POLICY, Firebird::IBatch::BLOB_ID_ENGINE);
|
||||
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_DETAILED_ERRORS, GBAK_BATCH_STEP);
|
||||
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_BUFFER_BYTES_SIZE, 0);
|
||||
|
||||
Firebird::RefPtr<Firebird::IBatch> batch(DB->
|
||||
createBatch(fbStatus, gds_trans, sqlStatement.length(), sqlStatement.c_str(), tdgbl->gbl_dialect,
|
||||
meta, pb->getBufferLength(&tdgbl->throwStatus), pb->getBuffer(&tdgbl->throwStatus)));
|
||||
if (fbStatus->hasData())
|
||||
{
|
||||
// Possible reason of fail - use of keywords as fields in old backup
|
||||
// Try to roll back to use of old version (fieldnames independent)
|
||||
BURP_print(false, 27/*, sqlStatement.c_str()*/); // msg 27 isc_compile_request failed !!!!!!!! new WARNING
|
||||
BURP_print_warning(fbStatus);
|
||||
return get_data_old(tdgbl, relation);
|
||||
}
|
||||
|
||||
UCHAR* buffer = NULL;
|
||||
Firebird::Array<UCHAR> requestBuffer;
|
||||
|
||||
BURP_verbose (124, relation->rel_name); // msg 124 restoring data for relation %s
|
||||
|
||||
lstring data;
|
||||
data.lstr_allocated = 0;
|
||||
data.lstr_address = NULL;
|
||||
Firebird::Array<UCHAR> dataBuffer;
|
||||
RCRD_LENGTH old_length = 0;
|
||||
|
||||
Firebird::Array<UCHAR> sqlBuffer;
|
||||
UCHAR* sql = sqlBuffer.getBuffer(meta->getMessageLength(&tdgbl->throwStatus));
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (get(tdgbl) != att_data_length)
|
||||
BURP_error_redirect(NULL, 39); // msg 39 expected record length
|
||||
RCRD_LENGTH len = get_int32(tdgbl);
|
||||
|
||||
if (!tdgbl->gbl_sw_transportable && len != length)
|
||||
{
|
||||
#ifdef sparc
|
||||
if (!old_length)
|
||||
old_length = recompute_length(tdgbl, relation);
|
||||
#endif
|
||||
if (len != old_length)
|
||||
{
|
||||
BURP_error(40, true, SafeArg() << length << len);
|
||||
// msg 40 wrong length record, expected %ld encountered %ld
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
buffer = requestBuffer.getBuffer(MAX (length, len));
|
||||
|
||||
UCHAR* p;
|
||||
if (tdgbl->gbl_sw_transportable)
|
||||
{
|
||||
if (get(tdgbl) != att_xdr_length)
|
||||
{
|
||||
BURP_error_redirect(NULL, 55);
|
||||
// msg 55 Expected XDR record length
|
||||
}
|
||||
else
|
||||
{
|
||||
data.lstr_length = len = get_int32(tdgbl);
|
||||
if (len > data.lstr_allocated)
|
||||
{
|
||||
data.lstr_allocated = len;
|
||||
data.lstr_address = dataBuffer.getBuffer(data.lstr_allocated);
|
||||
}
|
||||
p = data.lstr_address;
|
||||
}
|
||||
}
|
||||
else
|
||||
p = buffer;
|
||||
|
||||
if (get(tdgbl) != att_data_data)
|
||||
BURP_error_redirect(NULL, 41); // msg 41 expected data attribute
|
||||
|
||||
if (tdgbl->gbl_sw_compress)
|
||||
decompress (tdgbl, p, len);
|
||||
else
|
||||
{
|
||||
get_block(tdgbl, p, len);
|
||||
}
|
||||
|
||||
if (old_length)
|
||||
realign (tdgbl, buffer, relation);
|
||||
|
||||
if (tdgbl->gbl_sw_transportable)
|
||||
{
|
||||
buffer = sql;
|
||||
CAN_encode_decode (relation, &data, buffer, false, true);
|
||||
}
|
||||
|
||||
if ((++records % tdgbl->verboseInterval) == 0)
|
||||
BURP_verbose(107, SafeArg() << records);
|
||||
|
||||
for (field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (!(field->fld_flags & FLD_computed))
|
||||
{
|
||||
if (field->fld_type == blr_blob || (field->fld_flags & FLD_array))
|
||||
{
|
||||
ISC_QUAD* blob_id = (ISC_QUAD*) &buffer[field->fld_offset];
|
||||
blob_id->gds_quad_high = 0;
|
||||
blob_id->gds_quad_low = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get_record(&record, tdgbl);
|
||||
while (record == rec_blob || record == rec_array)
|
||||
{
|
||||
if (record == rec_blob)
|
||||
get_blob (tdgbl, batch, relation->rel_fields, buffer);
|
||||
else if (record == rec_array)
|
||||
get_array (tdgbl, relation, buffer);
|
||||
get_record(&record, tdgbl);
|
||||
}
|
||||
|
||||
if (!tdgbl->gbl_sw_transportable)
|
||||
{
|
||||
for (field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
|
||||
// convert record to SQL format
|
||||
|
||||
memcpy(&sql[field->fld_sql], &buffer[field->fld_offset], field->fld_total_len);
|
||||
memcpy(&sql[field->fld_null], &buffer[field->fld_missing_offset], sizeof(SSHORT));
|
||||
}
|
||||
}
|
||||
|
||||
batch->add(&tdgbl->throwStatus, 1, sql);
|
||||
if ((records % 1000 != 0) && (record == rec_data))
|
||||
continue;
|
||||
|
||||
Firebird::AutoDispose<Firebird::IBatchCompletionState> cs(batch->execute(&tdgbl->throwStatus, gds_trans));
|
||||
if (tdgbl->throwStatus->getState() && Firebird::IStatus::STATE_WARNINGS)
|
||||
BURP_print_warning(&tdgbl->throwStatus);
|
||||
|
||||
for (unsigned pos = 0; pos = cs->findError(&tdgbl->throwStatus, pos),
|
||||
pos != Firebird::IBatchCompletionState::NO_MORE_ERRORS; ++pos)
|
||||
{
|
||||
Firebird::LocalStatus status_vector;
|
||||
cs->getStatus(&tdgbl->throwStatus, &status_vector, pos);
|
||||
ISC_STATUS code = status_vector.getErrors()[1];
|
||||
|
||||
if (code == isc_not_valid)
|
||||
{
|
||||
if (tdgbl->gbl_sw_incremental)
|
||||
{
|
||||
BURP_print (false, 138, relation->rel_name);
|
||||
// msg 138 validation error on field in relation %s
|
||||
BURP_print_status (false, &status_vector);
|
||||
}
|
||||
else
|
||||
BURP_error_redirect(&status_vector, 47);
|
||||
// msg 47 warning -- record could not be restored
|
||||
}
|
||||
else if (code == isc_malformed_string)
|
||||
{
|
||||
if (tdgbl->gbl_sw_incremental)
|
||||
{
|
||||
// msg 114 restore failed for record in relation %s
|
||||
BURP_print(false, 114, relation->rel_name);
|
||||
|
||||
BURP_print_status(false, &status_vector);
|
||||
BURP_print(false, 342); // isc_gbak_invalid_data
|
||||
}
|
||||
else
|
||||
BURP_error_redirect(&status_vector, 342); // isc_gbak_invalid_data
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tdgbl->gbl_sw_incremental)
|
||||
{
|
||||
BURP_print (false, 114, relation->rel_name);
|
||||
// msg 114 restore failed for record in relation %s
|
||||
BURP_print_status (false, &status_vector);
|
||||
}
|
||||
else
|
||||
BURP_error_redirect(&status_vector, 48);
|
||||
// msg 48 isc_send failed
|
||||
}
|
||||
|
||||
records--;
|
||||
}
|
||||
|
||||
if (record != rec_data)
|
||||
break;
|
||||
} // while (true)
|
||||
}
|
||||
catch(const Firebird::FbException& ex)
|
||||
{
|
||||
BURP_print_status (true, ex.getStatus());
|
||||
BURP_abort();
|
||||
}
|
||||
|
||||
if (tdgbl->gbl_sw_incremental)
|
||||
{
|
||||
BURP_verbose (72, relation->rel_name);
|
||||
// msg 72 committing data for relation %s
|
||||
COMMIT
|
||||
// existing ON_ERROR continues past error, beck
|
||||
ON_ERROR
|
||||
|
||||
// Fix for bug_no 8055:
|
||||
// don't throw away the database just because an index
|
||||
// could not be made
|
||||
|
||||
// don't bring the database on-line
|
||||
tdgbl->flag_on_line = false;
|
||||
ISC_STATUS error_code;
|
||||
while (error_code = tdgbl->status_vector[1])
|
||||
{
|
||||
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
|
||||
Firebird::IRequest* req_handle = 0;
|
||||
|
||||
switch (error_code)
|
||||
{
|
||||
case isc_sort_mem_err:
|
||||
case isc_no_dup:
|
||||
strcpy(index_name, (TEXT *)tdgbl->status_vector[3]);
|
||||
BURP_print_status(false, &tdgbl->status_vector);
|
||||
FOR (REQUEST_HANDLE req_handle)
|
||||
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ index_name
|
||||
MODIFY IDX USING
|
||||
IDX.RDB$INDEX_INACTIVE = TRUE;
|
||||
BURP_print(false, 240, index_name);
|
||||
// msg 240 Index \"%s\" failed to activate because:
|
||||
if ( error_code == isc_no_dup )
|
||||
{
|
||||
BURP_print(false, 241);
|
||||
// msg 241 The unique index has duplicate values or NULLs
|
||||
BURP_print(false, 242);
|
||||
// msg 242 Delete or Update duplicate values or NULLs, and activate index with
|
||||
}
|
||||
else
|
||||
{
|
||||
BURP_print(false, 244);
|
||||
// msg 244 Not enough disk space to create the sort file for an index
|
||||
BURP_print(false, 245);
|
||||
// msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with
|
||||
}
|
||||
BURP_print(false, 243, index_name);
|
||||
// msg 243 ALTER INDEX \"%s\" ACTIVE
|
||||
END_MODIFY;
|
||||
END_FOR;
|
||||
// commit one more time
|
||||
COMMIT
|
||||
ON_ERROR
|
||||
continue;
|
||||
END_ERROR
|
||||
break;
|
||||
default:
|
||||
BURP_print (false, 69, relation->rel_name);
|
||||
// msg 69 commit failed on relation %s
|
||||
BURP_print_status (false, &tdgbl->status_vector);
|
||||
ROLLBACK;
|
||||
ON_ERROR
|
||||
general_on_error ();
|
||||
END_ERROR;
|
||||
break;
|
||||
} // end of switch
|
||||
} // end of while
|
||||
END_ERROR;
|
||||
|
||||
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
|
||||
if (gds_status->hasData())
|
||||
EXEC SQL SET TRANSACTION;
|
||||
}
|
||||
BURP_verbose (107, SafeArg() << records);
|
||||
// msg 107 %ld records restored
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
// We have a corrupt backup, save the restore process from becoming useless.
|
||||
void fix_exception(BurpGlobals* tdgbl, const char* exc_name, scan_attr_t& scan_next_attr,
|
||||
const att_type attribute, att_type& failed_attrib, UCHAR*& msg_ptr, ULONG& l2, bool& msg_seen)
|
||||
{
|
||||
if (msg_seen && (tdgbl->RESTORE_format == 7 || tdgbl->RESTORE_format == 8))
|
||||
{
|
||||
if (!failed_attrib)
|
||||
{
|
||||
failed_attrib = attribute;
|
||||
BURP_print(false, 313, SafeArg() << failed_attrib << exc_name);
|
||||
}
|
||||
|
||||
// Notice we use 1021 instead of 1023 because this is the maximum length
|
||||
// for this field in v2.0 and v2.1 and they produce the corrupt backups.
|
||||
const unsigned int FIELD_LIMIT = 1021;
|
||||
|
||||
if (FIELD_LIMIT < l2 + 1) // not enough space
|
||||
{
|
||||
bad_attribute(scan_next_attr, failed_attrib, 287);
|
||||
return;
|
||||
}
|
||||
const unsigned int remaining = FIELD_LIMIT - l2;
|
||||
|
||||
*msg_ptr++ = char(attribute); // (1)
|
||||
|
||||
UCHAR* rc_ptr = get_block(tdgbl, msg_ptr, MIN(remaining - 1, 255));
|
||||
if (remaining > 1 && rc_ptr == msg_ptr) // we couldn't read anything
|
||||
{
|
||||
bad_attribute(scan_next_attr, failed_attrib, 287);
|
||||
return;
|
||||
}
|
||||
|
||||
l2 += rc_ptr - msg_ptr + 1; // + 1 because (1)
|
||||
msg_ptr = rc_ptr;
|
||||
*msg_ptr = 0;
|
||||
|
||||
if (l2 == FIELD_LIMIT)
|
||||
msg_seen = false;
|
||||
}
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 287); // msg 287 exception
|
||||
}
|
||||
|
||||
rec_type get_data_old(BurpGlobals* tdgbl, burp_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* g e t _ d a t a
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Write data records for a relation.
|
||||
*
|
||||
**************************************/
|
||||
Firebird::IRequest* req_handle = 0;
|
||||
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
|
||||
|
||||
// Start by counting the interesting fields
|
||||
|
||||
RCRD_OFFSET offset = 0;
|
||||
@ -2734,8 +3344,7 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
|
||||
}
|
||||
}
|
||||
|
||||
if (tdgbl->RESTORE_format >= 2)
|
||||
count += count;
|
||||
count += count;
|
||||
|
||||
// Time to generate blr to store data. Whoppee.
|
||||
|
||||
@ -2846,19 +3455,16 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
|
||||
offset += length;
|
||||
}
|
||||
|
||||
// If this is format version 2, build fields for null flags
|
||||
|
||||
if (tdgbl->RESTORE_format >= 2)
|
||||
for (field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
add_byte(blr, blr_short);
|
||||
add_byte(blr, 0);
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
field->fld_missing_parameter = count++;
|
||||
offset += sizeof(SSHORT);
|
||||
}
|
||||
for (field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
add_byte(blr, blr_short);
|
||||
add_byte(blr, 0);
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
field->fld_missing_parameter = count++;
|
||||
offset += sizeof(SSHORT);
|
||||
}
|
||||
|
||||
length = offset;
|
||||
|
||||
@ -2878,19 +3484,12 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
add_byte(blr, blr_assignment);
|
||||
if (tdgbl->RESTORE_format >= 2)
|
||||
{
|
||||
add_byte(blr, blr_parameter2);
|
||||
add_byte(blr, 0);
|
||||
add_word(blr, field->fld_parameter);
|
||||
add_word(blr, field->fld_missing_parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_byte(blr, blr_parameter);
|
||||
add_byte(blr, 0);
|
||||
add_word(blr, field->fld_parameter);
|
||||
}
|
||||
|
||||
add_byte(blr, blr_parameter2);
|
||||
add_byte(blr, 0);
|
||||
add_word(blr, field->fld_parameter);
|
||||
add_word(blr, field->fld_missing_parameter);
|
||||
|
||||
add_byte(blr, blr_field);
|
||||
add_byte(blr, 0);
|
||||
add_string(blr, field->fld_name);
|
||||
@ -2995,7 +3594,7 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
|
||||
realign (tdgbl, (UCHAR*) buffer, relation);
|
||||
|
||||
if (tdgbl->gbl_sw_transportable)
|
||||
CAN_encode_decode (relation, &data, (UCHAR *)buffer, FALSE);
|
||||
CAN_encode_decode (relation, &data, (UCHAR *)buffer, false);
|
||||
|
||||
records++;
|
||||
|
||||
@ -3019,7 +3618,7 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
|
||||
while (record == rec_blob || record == rec_array)
|
||||
{
|
||||
if (record == rec_blob)
|
||||
get_blob (tdgbl, relation->rel_fields, (UCHAR *) buffer);
|
||||
get_blob_old (tdgbl, relation->rel_fields, (UCHAR *) buffer);
|
||||
else if (record == rec_array)
|
||||
get_array (tdgbl, relation, (UCHAR *) buffer);
|
||||
get_record(&record, tdgbl);
|
||||
@ -3164,49 +3763,6 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
|
||||
return record;
|
||||
}
|
||||
|
||||
// We have a corrupt backup, save the restore process from becoming useless.
|
||||
void fix_exception(BurpGlobals* tdgbl, const char* exc_name, scan_attr_t& scan_next_attr,
|
||||
const att_type attribute, att_type& failed_attrib, UCHAR*& msg_ptr, ULONG& l2, bool& msg_seen)
|
||||
{
|
||||
if (msg_seen && (tdgbl->RESTORE_format == 7 || tdgbl->RESTORE_format == 8))
|
||||
{
|
||||
if (!failed_attrib)
|
||||
{
|
||||
failed_attrib = attribute;
|
||||
BURP_print(false, 313, SafeArg() << failed_attrib << exc_name);
|
||||
}
|
||||
|
||||
// Notice we use 1021 instead of 1023 because this is the maximum length
|
||||
// for this field in v2.0 and v2.1 and they produce the corrupt backups.
|
||||
const unsigned int FIELD_LIMIT = 1021;
|
||||
|
||||
if (FIELD_LIMIT < l2 + 1) // not enough space
|
||||
{
|
||||
bad_attribute(scan_next_attr, failed_attrib, 287);
|
||||
return;
|
||||
}
|
||||
const unsigned int remaining = FIELD_LIMIT - l2;
|
||||
|
||||
*msg_ptr++ = char(attribute); // (1)
|
||||
|
||||
UCHAR* rc_ptr = get_block(tdgbl, msg_ptr, MIN(remaining - 1, 255));
|
||||
if (remaining > 1 && rc_ptr == msg_ptr) // we couldn't read anything
|
||||
{
|
||||
bad_attribute(scan_next_attr, failed_attrib, 287);
|
||||
return;
|
||||
}
|
||||
|
||||
l2 += rc_ptr - msg_ptr + 1; // + 1 because (1)
|
||||
msg_ptr = rc_ptr;
|
||||
*msg_ptr = 0;
|
||||
|
||||
if (l2 == FIELD_LIMIT)
|
||||
msg_seen = false;
|
||||
}
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 287); // msg 287 exception
|
||||
}
|
||||
|
||||
bool get_exception(BurpGlobals* tdgbl)
|
||||
{
|
||||
/**************************************
|
||||
@ -3597,6 +4153,7 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation)
|
||||
|
||||
case att_field_source:
|
||||
GET_TEXT(X.RDB$FIELD_SOURCE);
|
||||
strcpy(field->fld_source, X.RDB$FIELD_SOURCE);
|
||||
break;
|
||||
|
||||
case att_field_security_class:
|
||||
@ -3799,6 +4356,7 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation)
|
||||
|
||||
case att_field_source:
|
||||
GET_TEXT(X.RDB$FIELD_SOURCE);
|
||||
strcpy(field->fld_source, X.RDB$FIELD_SOURCE);
|
||||
break;
|
||||
|
||||
case att_field_security_class:
|
||||
@ -9671,19 +10229,14 @@ void realign(BurpGlobals* tdgbl, UCHAR* buffer, const burp_rel* relation)
|
||||
}
|
||||
}
|
||||
|
||||
// If this is format version 2 or greater, build fields for null flags
|
||||
|
||||
if (tdgbl->RESTORE_format >= 2)
|
||||
for (const burp_fld* field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
for (const burp_fld* field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
p = FB_ALIGN(p, sizeof(SSHORT));
|
||||
q = FB_ALIGN(q, sizeof(SSHORT));
|
||||
*p++ = *q++;
|
||||
*p++ = *q++;
|
||||
}
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
p = FB_ALIGN(p, sizeof(SSHORT));
|
||||
q = FB_ALIGN(q, sizeof(SSHORT));
|
||||
*p++ = *q++;
|
||||
*p++ = *q++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9733,17 +10286,12 @@ USHORT recompute_length(BurpGlobals* tdgbl, burp_rel* relation)
|
||||
offset += length;
|
||||
}
|
||||
|
||||
// If this is format version 2, build fields for null flags
|
||||
|
||||
if (tdgbl->RESTORE_format >= 2)
|
||||
for (const burp_fld* field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
for (const burp_fld* field = relation->rel_fields; field; field = field->fld_next)
|
||||
{
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
offset += sizeof(SSHORT);
|
||||
}
|
||||
if (field->fld_flags & FLD_computed)
|
||||
continue;
|
||||
offset = FB_ALIGN(offset, sizeof(SSHORT));
|
||||
offset += sizeof(SSHORT);
|
||||
}
|
||||
|
||||
return offset;
|
||||
@ -9777,9 +10325,9 @@ bool restore(BurpGlobals* tdgbl, const TEXT* file_name, const TEXT* database_nam
|
||||
|
||||
// restore only from those backup files created by current or previous GBAK
|
||||
|
||||
if (tdgbl->RESTORE_format < 1 || tdgbl->RESTORE_format > ATT_BACKUP_FORMAT)
|
||||
if (tdgbl->RESTORE_format < 2 || tdgbl->RESTORE_format > ATT_BACKUP_FORMAT)
|
||||
{
|
||||
BURP_error(344, true, SafeArg() << tdgbl->RESTORE_format << 1 << ATT_BACKUP_FORMAT);
|
||||
BURP_error(344, true, SafeArg() << tdgbl->RESTORE_format << 2 << ATT_BACKUP_FORMAT);
|
||||
// msg 44 Expected backup version @2..@3. Found @1
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ bool BlobWrapper::getSegment(FB_SIZE_T len, void* buffer, FB_SIZE_T& real_len)
|
||||
if (!m_blob || m_direction != dir_read)
|
||||
return false;
|
||||
|
||||
if (!len || !buffer)
|
||||
if (len && !buffer)
|
||||
return false;
|
||||
|
||||
unsigned ilen = len > SEGMENT_LIMIT ? SEGMENT_LIMIT : static_cast<unsigned>(len);
|
||||
|
@ -168,6 +168,16 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <typename ID>
|
||||
class AutoDispose : public AutoPtr<ID, SimpleDispose<ID> >
|
||||
{
|
||||
public:
|
||||
AutoDispose(ID* v = nullptr)
|
||||
: AutoPtr<ID, SimpleDispose<ID> >(v)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class AutoSetRestore
|
||||
{
|
||||
|
@ -140,7 +140,6 @@ DsqlBatch::DsqlBatch(dsql_req* req, const dsql_msg* /*message*/, IMessageMetadat
|
||||
switch (t)
|
||||
{
|
||||
case SQL_BLOB:
|
||||
case SQL_ARRAY:
|
||||
{
|
||||
BlobMeta bm;
|
||||
bm.offset = m_meta->getOffset(&st, i);
|
||||
@ -264,6 +263,7 @@ void DsqlBatch::add(thread_db* tdbb, ULONG count, const void* inBuffer)
|
||||
return;
|
||||
m_messages.align(m_alignment);
|
||||
m_messages.put(inBuffer, (count - 1) * m_alignedMessage + m_messageSize);
|
||||
DEB_BATCH(fprintf(stderr, "Put to batch %d messages\n", count));
|
||||
}
|
||||
|
||||
void DsqlBatch::blobCheckMeta()
|
||||
@ -413,6 +413,7 @@ void DsqlBatch::addBlobStream(thread_db* tdbb, unsigned length, const void* inBu
|
||||
m_lastBlob = MAX_ULONG;
|
||||
|
||||
// store stream for further processing
|
||||
DEB_BATCH(fprintf(stderr, "Store stream %d\n", length));
|
||||
fb_assert(m_blobs.getSize() % BLOB_STREAM_ALIGN == 0);
|
||||
m_blobs.put(inBuffer, length);
|
||||
}
|
||||
@ -533,13 +534,13 @@ private:
|
||||
|
||||
// parse blob header
|
||||
fb_assert(intptr_t(flow.data) % BLOB_STREAM_ALIGN == 0);
|
||||
ISC_QUAD* batchBlobId = reinterpret_cast<ISC_QUAD*>(flow.data);
|
||||
ISC_QUAD batchBlobId = *reinterpret_cast<ISC_QUAD*>(flow.data);
|
||||
ULONG* blobSize = reinterpret_cast<ULONG*>(flow.data + sizeof(ISC_QUAD));
|
||||
ULONG* bpbSize = reinterpret_cast<ULONG*>(flow.data + sizeof(ISC_QUAD) + sizeof(ULONG));
|
||||
flow.newHdr(*blobSize);
|
||||
ULONG currentBpbSize = *bpbSize;
|
||||
|
||||
if (batchBlobId->gds_quad_high == 0 && batchBlobId->gds_quad_low == 0)
|
||||
if (batchBlobId.gds_quad_high == 0 && batchBlobId.gds_quad_low == 0)
|
||||
{
|
||||
// Sanity check
|
||||
if (*bpbSize)
|
||||
@ -585,7 +586,8 @@ private:
|
||||
bid engineBlobId;
|
||||
blob = blb::create2(tdbb, transaction, &engineBlobId, bpb->getCount(),
|
||||
bpb->begin(), true);
|
||||
registerBlob(reinterpret_cast<ISC_QUAD*>(&engineBlobId), batchBlobId);
|
||||
//DEB_BATCH(fprintf(stderr, "B-ID: (%x,%x)\n", batchBlobId.gds_quad_high, batchBlobId.gds_quad_low));
|
||||
registerBlob(reinterpret_cast<ISC_QUAD*>(&engineBlobId), &batchBlobId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -696,6 +698,9 @@ private:
|
||||
continue;
|
||||
|
||||
ISC_QUAD* id = reinterpret_cast<ISC_QUAD*>(&data[m_blobMeta[i].offset]);
|
||||
if (id->gds_quad_high == 0 && id->gds_quad_low == 0)
|
||||
continue;
|
||||
|
||||
ISC_QUAD newId;
|
||||
if (!m_blobMap.get(*id, newId))
|
||||
{
|
||||
@ -713,9 +718,9 @@ private:
|
||||
remains -= m_messageSize;
|
||||
|
||||
UCHAR* msgBuffer = m_request->req_msg_buffers[message->msg_buffer_number];
|
||||
DEB_BATCH(fprintf(stderr, "\n\n+++ Send\n\n"));
|
||||
try
|
||||
{
|
||||
// runsend data to request and collect stats
|
||||
ULONG before = req->req_records_inserted + req->req_records_updated +
|
||||
req->req_records_deleted;
|
||||
EXE_send(tdbb, req, message->msg_number, message->msg_length, msgBuffer);
|
||||
@ -747,6 +752,15 @@ private:
|
||||
m_messages.remained(remains, alignedData - data);
|
||||
}
|
||||
|
||||
DEB_BATCH(fprintf(stderr, "Sent %d messages\n", completionState->getSize(tdbb->tdbb_status_vector)));
|
||||
|
||||
// make sure all blobs were used in messages
|
||||
if (m_blobMap.count())
|
||||
{
|
||||
DEB_BATCH(fprintf(stderr, "BLOBs %d were not used in messages\n", m_blobMap.count()));
|
||||
ERR_post_warning(Arg::Warning(isc_random) << "m_blobMap.count() BLOBs were not used in messages"); // !!!!!!! new warning
|
||||
}
|
||||
|
||||
// reset to initial state
|
||||
cancel(tdbb);
|
||||
|
||||
@ -756,14 +770,11 @@ private:
|
||||
void DsqlBatch::cancel(thread_db* tdbb)
|
||||
{
|
||||
m_messages.clear();
|
||||
if (m_blobMeta.hasData())
|
||||
{
|
||||
m_blobs.clear();
|
||||
m_setBlobSize = false;
|
||||
m_lastBlob = MAX_ULONG;
|
||||
memset(&m_genId, 0, sizeof(m_genId));
|
||||
m_blobMap.clear();
|
||||
}
|
||||
m_blobs.clear();
|
||||
m_setBlobSize = false;
|
||||
m_lastBlob = MAX_ULONG;
|
||||
memset(&m_genId, 0, sizeof(m_genId));
|
||||
m_blobMap.clear();
|
||||
}
|
||||
|
||||
void DsqlBatch::genBlobId(ISC_QUAD* blobId)
|
||||
@ -805,7 +816,7 @@ void DsqlBatch::DataCache::put3(const void* data, ULONG dataSize, ULONG offset)
|
||||
|
||||
void DsqlBatch::DataCache::put(const void* d, ULONG dataSize)
|
||||
{
|
||||
if (m_used + m_cache.getCount() + dataSize > m_limit)
|
||||
if (m_limit && (m_used + m_cache.getCount() + dataSize > m_limit))
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
|
||||
Arg::Gds(isc_batch_too_big));
|
||||
|
@ -107,7 +107,7 @@ private:
|
||||
{
|
||||
public:
|
||||
DataCache(MemoryPool& p)
|
||||
: PermanentStorage(p),
|
||||
: PermanentStorage(p), m_cache(getPool()),
|
||||
m_used(0), m_got(0), m_limit(0), m_shift(0), m_cacheCapacity(0)
|
||||
{ }
|
||||
|
||||
|
@ -599,6 +599,8 @@ version: // 3.0 => 4.0
|
||||
// Batch API
|
||||
Batch createBatch(Status status, Transaction transaction, uint stmtLength, const string sqlStmt,
|
||||
uint dialect, MessageMetadata inMetadata, uint parLength, const uchar* par);
|
||||
|
||||
uint getRemoteProtocolVersion(Status status);
|
||||
/*
|
||||
Pipe createPipe(Status status, uint stmtLength, const string sqlStmt, uint dialect,
|
||||
Transaction transaction, MessageMetadata inMetadata, void* inBuffer,
|
||||
|
@ -2122,6 +2122,7 @@ namespace Firebird
|
||||
unsigned (CLOOP_CARG *getStatementTimeout)(IAttachment* self, IStatus* status) throw();
|
||||
void (CLOOP_CARG *setStatementTimeout)(IAttachment* self, IStatus* status, unsigned timeOut) throw();
|
||||
IBatch* (CLOOP_CARG *createBatch)(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) throw();
|
||||
unsigned (CLOOP_CARG *getRemoteProtocolVersion)(IAttachment* self, IStatus* status) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -2340,6 +2341,20 @@ namespace Firebird
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> unsigned getRemoteProtocolVersion(StatusType* status)
|
||||
{
|
||||
if (cloopVTable->version < 4)
|
||||
{
|
||||
StatusType::setVersionError(status, "IAttachment", cloopVTable->version, 4);
|
||||
StatusType::checkException(status);
|
||||
return 0;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getRemoteProtocolVersion(this, status);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class IService : public IReferenceCounted
|
||||
@ -9800,6 +9815,7 @@ namespace Firebird
|
||||
this->getStatementTimeout = &Name::cloopgetStatementTimeoutDispatcher;
|
||||
this->setStatementTimeout = &Name::cloopsetStatementTimeoutDispatcher;
|
||||
this->createBatch = &Name::cloopcreateBatchDispatcher;
|
||||
this->getRemoteProtocolVersion = &Name::cloopgetRemoteProtocolVersionDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
@ -10141,6 +10157,21 @@ namespace Firebird
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned CLOOP_CARG cloopgetRemoteProtocolVersionDispatcher(IAttachment* self, IStatus* status) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getRemoteProtocolVersion(&status2);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
return static_cast<unsigned>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
|
||||
{
|
||||
try
|
||||
@ -10203,6 +10234,7 @@ namespace Firebird
|
||||
virtual unsigned getStatementTimeout(StatusType* status) = 0;
|
||||
virtual void setStatementTimeout(StatusType* status, unsigned timeOut) = 0;
|
||||
virtual IBatch* createBatch(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) = 0;
|
||||
virtual unsigned getRemoteProtocolVersion(StatusType* status) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
|
@ -396,6 +396,7 @@ public:
|
||||
Firebird::IBatch* createBatch(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* transaction,
|
||||
unsigned stmtLength, const char* sqlStmt, unsigned dialect,
|
||||
Firebird::IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par);
|
||||
unsigned int getRemoteProtocolVersion(Firebird::CheckStatusWrapper* status);
|
||||
|
||||
public:
|
||||
explicit JAttachment(StableAttachmentPart* js);
|
||||
|
@ -2250,7 +2250,7 @@ bool BTR_types_comparable(const dsc& target, const dsc& source)
|
||||
return (source.dsc_dtype <= dtype_long || source.dsc_dtype == dtype_int64);
|
||||
|
||||
if (DTYPE_IS_NUMERIC(target.dsc_dtype))
|
||||
return (source.dsc_dtype <= dtype_double || source.dsc_dtype == dtype_int64); //!!!!!!!!
|
||||
return (source.dsc_dtype <= dtype_double || source.dsc_dtype == dtype_int64);
|
||||
|
||||
if (target.dsc_dtype == dtype_sql_date)
|
||||
return (source.dsc_dtype <= dtype_sql_date || source.dsc_dtype == dtype_timestamp);
|
||||
|
@ -148,6 +148,7 @@ enum db_info_types
|
||||
fb_info_ses_idle_timeout_run = 131,
|
||||
|
||||
fb_info_conn_flags = 132,
|
||||
fb_info_protocol_version = 133,
|
||||
|
||||
fb_info_crypt_key = 133,
|
||||
fb_info_crypt_state = 134,
|
||||
|
@ -4827,6 +4827,12 @@ IBatch* JAttachment::createBatch(CheckStatusWrapper* status, ITransaction* trans
|
||||
}
|
||||
|
||||
|
||||
unsigned int JAttachment::getRemoteProtocolVersion(Firebird::CheckStatusWrapper* status)
|
||||
{
|
||||
return 0; // protocol == 0, i.e. no network, i.e. embedded connection
|
||||
}
|
||||
|
||||
|
||||
int JResultSet::fetchNext(CheckStatusWrapper* user_status, void* buffer)
|
||||
{
|
||||
try
|
||||
|
@ -371,6 +371,7 @@ private:
|
||||
// working with blob stream buffer
|
||||
void newBlob()
|
||||
{
|
||||
setBlobAlignment();
|
||||
alignBlobBuffer(blobAlign);
|
||||
|
||||
fb_assert(blobStream - blobStreamBuffer <= blobBufferSize);
|
||||
@ -384,6 +385,8 @@ private:
|
||||
|
||||
void alignBlobBuffer(unsigned alignment, ULONG* bs = NULL)
|
||||
{
|
||||
fb_assert(alignment);
|
||||
|
||||
FB_UINT64 zeroFill = 0;
|
||||
UCHAR* newPointer = FB_ALIGN(blobStream, alignment);
|
||||
ULONG align = FB_ALIGN(blobStream, alignment) - blobStream;
|
||||
@ -464,6 +467,7 @@ private:
|
||||
|
||||
void flashBatch()
|
||||
{
|
||||
setBlobAlignment();
|
||||
alignBlobBuffer(blobAlign);
|
||||
ULONG size = blobStream - blobStreamBuffer;
|
||||
if (size)
|
||||
@ -472,6 +476,12 @@ private:
|
||||
blobStream = blobStreamBuffer;
|
||||
}
|
||||
|
||||
if (messageStream)
|
||||
{
|
||||
sendMessagePacket(messageStream, messageStreamBuffer);
|
||||
messageStream = 0;
|
||||
}
|
||||
|
||||
batchActive = false;
|
||||
}
|
||||
|
||||
@ -760,6 +770,11 @@ public:
|
||||
unsigned stmtLength, const char* sqlStmt, unsigned dialect,
|
||||
IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par);
|
||||
|
||||
unsigned getRemoteProtocolVersion(CheckStatusWrapper* status)
|
||||
{
|
||||
return rdb->rdb_port->port_protocol & FB_PROTOCOL_MASK;
|
||||
}
|
||||
|
||||
public:
|
||||
Attachment(Rdb* handle, const PathName& path)
|
||||
: rdb(handle), dbPath(getPool(), path)
|
||||
|
@ -48,7 +48,6 @@ USHORT MERGE_database_info(const UCHAR* in,
|
||||
USHORT base_level,
|
||||
const UCHAR* version,
|
||||
const UCHAR* id)
|
||||
//ULONG mask Was always zero
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
|
@ -893,7 +893,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
|
||||
|
||||
while (count--)
|
||||
{
|
||||
DEB_BATCH(fprintf(stderr, "BatRem: xdr packed msg\n"));
|
||||
DEB_RBATCH(fprintf(stderr, "BatRem: xdr packed msg\n"));
|
||||
if (!xdr_packed_message(xdrs, message, statement->rsr_format))
|
||||
return P_FALSE(xdrs, p);
|
||||
message->msg_address += statement->rsr_batch_size;
|
||||
@ -912,7 +912,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
|
||||
MAP(xdr_short, reinterpret_cast<SSHORT&>(b->p_batch_transaction));
|
||||
|
||||
if (xdrs->x_op != XDR_FREE)
|
||||
DEB_BATCH(fprintf(stderr, "BatRem: xdr execute\n"));
|
||||
DEB_RBATCH(fprintf(stderr, "BatRem: xdr execute\n"));
|
||||
|
||||
return P_TRUE(xdrs, p);
|
||||
}
|
||||
@ -931,7 +931,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
|
||||
|
||||
rem_port* port = (rem_port*) xdrs->x_public;
|
||||
SSHORT statement_id = b->p_batch_statement;
|
||||
DEB_BATCH(fprintf(stderr, "BatRem: xdr CS %d\n", statement_id));
|
||||
DEB_RBATCH(fprintf(stderr, "BatRem: xdr CS %d\n", statement_id));
|
||||
Rsr* statement;
|
||||
|
||||
if (statement_id >= 0)
|
||||
@ -961,12 +961,12 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
|
||||
|
||||
if ((xdrs->x_op == XDR_DECODE) && (!b->p_batch_updates))
|
||||
{
|
||||
DEB_BATCH(fprintf(stderr, "BatRem: xdr reccount=%d\n", b->p_batch_reccount));
|
||||
DEB_RBATCH(fprintf(stderr, "BatRem: xdr reccount=%d\n", b->p_batch_reccount));
|
||||
statement->rsr_batch_cs->regSize(b->p_batch_reccount);
|
||||
}
|
||||
|
||||
// Process update counters
|
||||
DEB_BATCH(fprintf(stderr, "BatRem: xdr up %d\n", b->p_batch_updates));
|
||||
DEB_RBATCH(fprintf(stderr, "BatRem: xdr up %d\n", b->p_batch_updates));
|
||||
for (unsigned i = 0; i < b->p_batch_updates; ++i)
|
||||
{
|
||||
SLONG v;
|
||||
@ -988,7 +988,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
|
||||
// Process status vectors
|
||||
ULONG pos = 0u;
|
||||
LocalStatus to;
|
||||
DEB_BATCH(fprintf(stderr, "BatRem: xdr sv %d\n", b->p_batch_vectors));
|
||||
DEB_RBATCH(fprintf(stderr, "BatRem: xdr sv %d\n", b->p_batch_vectors));
|
||||
|
||||
for (unsigned i = 0; i < b->p_batch_vectors; ++i, ++pos)
|
||||
{
|
||||
@ -1026,7 +1026,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
|
||||
|
||||
// Process status-less errors
|
||||
pos = 0u;
|
||||
DEB_BATCH(fprintf(stderr, "BatRem: xdr err %d\n", b->p_batch_errors));
|
||||
DEB_RBATCH(fprintf(stderr, "BatRem: xdr err %d\n", b->p_batch_errors));
|
||||
|
||||
for (unsigned i = 0; i < b->p_batch_errors; ++i, ++pos)
|
||||
{
|
||||
@ -1059,7 +1059,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
|
||||
MAP(xdr_short, reinterpret_cast<SSHORT&>(b->p_batch_statement));
|
||||
|
||||
if (xdrs->x_op != XDR_FREE)
|
||||
DEB_BATCH(fprintf(stderr, "BatRem: xdr release\n"));
|
||||
DEB_RBATCH(fprintf(stderr, "BatRem: xdr release\n"));
|
||||
|
||||
return P_TRUE(xdrs, p);
|
||||
}
|
||||
|
@ -64,7 +64,7 @@
|
||||
//#define COMPRESS_DEBUG 1
|
||||
#endif // WIRE_COMPRESS_SUPPORT
|
||||
|
||||
#define DEB_BATCH(x)
|
||||
#define DEB_RBATCH(x)
|
||||
|
||||
#define REM_SEND_OFFSET(bs) (0)
|
||||
#define REM_RECV_OFFSET(bs) (bs)
|
||||
|
@ -510,6 +510,7 @@ public:
|
||||
YBatch* createBatch(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* transaction,
|
||||
unsigned stmtLength, const char* sqlStmt, unsigned dialect,
|
||||
Firebird::IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par);
|
||||
unsigned int getRemoteProtocolVersion(Firebird::CheckStatusWrapper* status);
|
||||
|
||||
public:
|
||||
Firebird::IProvider* provider;
|
||||
|
@ -5931,6 +5931,22 @@ YBatch* YAttachment::createBatch(CheckStatusWrapper* status, ITransaction* trans
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int YAttachment::getRemoteProtocolVersion(CheckStatusWrapper* status)
|
||||
{
|
||||
try
|
||||
{
|
||||
YEntry<YAttachment> entry(status, this);
|
||||
|
||||
return entry.next()->getRemoteProtocolVersion(status);
|
||||
}
|
||||
catch (const Exception& e)
|
||||
{
|
||||
e.stuffException(status);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user