8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 20:43:02 +01:00

First edition of SET BIND statement

This commit is contained in:
AlexPeshkoff 2019-11-07 18:26:38 +03:00 committed by Alexander Peshkov
parent 8086e06ee1
commit e8787500d7
22 changed files with 445 additions and 248 deletions

View File

@ -31,10 +31,14 @@
using namespace Firebird;
ParsedList::ParsedList(PathName list)
ParsedList::ParsedList(const PathName& list)
{
parse(list, " \t,;");
}
void ParsedList::parse(PathName list, const char* sep)
{
list.alltrim(" \t");
const char* sep = " \t,;";
for (;;)
{
@ -54,6 +58,11 @@ ParsedList::ParsedList(PathName list)
}
}
ParsedList::ParsedList(const PathName& list, const char* delimiters)
{
parse(list, delimiters);
}
void ParsedList::makeList(PathName& list) const
{
fb_assert(this->hasData());

View File

@ -37,7 +37,7 @@ namespace Firebird {
class ParsedList : public Firebird::ObjectsArray<Firebird::PathName>
{
public:
explicit ParsedList(Firebird::PathName list);
explicit ParsedList(const Firebird::PathName& list);
ParsedList()
{ }
@ -46,6 +46,8 @@ public:
: Firebird::ObjectsArray<Firebird::PathName>(p)
{ }
ParsedList(const Firebird::PathName& list, const char* delimiters);
// create plane list from this parsed
void makeList(Firebird::PathName& list) const;
@ -55,6 +57,9 @@ public:
// get providers list for particular database amd remove "Loopback" provider from it
static Firebird::PathName getNonLoopbackProviders(const Firebird::PathName& aliasDb);
private:
void parse(Firebird::PathName list, const char* delimiters);
};
} // namespace Firebird

View File

@ -246,6 +246,12 @@ public:
return count++;
}
T& add()
{
ensureCapacity(count + 1);
return *new(&data[count++]) T(); // initialize new empty data member
}
void add(const T* items, const size_type itemsCount)
{
fb_assert(count <= FB_MAX_SIZEOF - itemsCount);

View File

@ -229,7 +229,8 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_INTEGER, "SnapshotsMemSize", (ConfigValue) 65536}, // bytes
{TYPE_INTEGER, "TipCacheBlockSize", (ConfigValue) 4194304}, // bytes
{TYPE_BOOLEAN, "ReadConsistency", (ConfigValue) true},
{TYPE_BOOLEAN, "ClearGTTAtRetaining", (ConfigValue) false}
{TYPE_BOOLEAN, "ClearGTTAtRetaining", (ConfigValue) false},
{TYPE_STRING, "SetBind", (ConfigValue) NULL}
};
/******************************************************************************
@ -930,3 +931,8 @@ bool Config::getClearGTTAtRetaining() const
{
return get<bool>(KEY_CLEAR_GTT_RETAINING);
}
const char* Config::getBind() const
{
return get<const char*>(KEY_SET_BIND);
}

View File

@ -155,6 +155,7 @@ public:
KEY_TIP_CACHE_BLOCK_SIZE,
KEY_READ_CONSISTENCY,
KEY_CLEAR_GTT_RETAINING,
KEY_SET_BIND,
MAX_CONFIG_KEY // keep it last
};
@ -390,6 +391,8 @@ public:
bool getReadConsistency() const;
bool getClearGTTAtRetaining() const;
const char* getBind() const;
};
// Implementation of interface to access master configuration file

View File

@ -29,6 +29,7 @@
#include "../jrd/align.h"
#include "firebird/impl/blr.h"
#include "../jrd/tra.h"
#include "../jrd/Coercion.h"
#include "../jrd/Function.h"
#include "../jrd/Optimizer.h"
#include "../jrd/RecordSourceNodes.h"
@ -8360,14 +8361,39 @@ void SetDecFloatTrapsNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_t
//--------------------
void SetHighPrecBindNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const
void CoercionRule::setRule(TypeClause* from, TypeClause *to)
{
static const USHORT FROM_MASK = FLD_has_len | FLD_has_chset | FLD_has_scale;
static const USHORT TO_MASK = FLD_has_len | FLD_has_chset | FLD_has_scale | FLD_legacy;
fromMask = from->flags & FROM_MASK;
DsqlDescMaker::fromField(&fromDsc, from);
toMask = to->flags & TO_MASK;
DsqlDescMaker::fromField(&toDsc, to);
}
SessionManagementNode* SetBindNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
from->resolve(dsqlScratch);
if (!(to->flags & FLD_legacy))
to->resolve(dsqlScratch);
return SessionManagementNode::dsqlPass(dsqlScratch);
}
void SetBindNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const
{
SET_TDBB(tdbb);
fb_assert(from);
fb_assert(to);
Attachment* const attachment = tdbb->getAttachment();
if (bindInt128)
attachment->att_i128_binding = bind;
else
attachment->att_dec_binding = bind;
CoercionRule& coercion = attachment->att_dest_bind->add();
coercion.setRule(from, to);
}
@ -8456,17 +8482,6 @@ void SetTimeZoneNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** /*tr
//--------------------
void SetTimeZoneBindNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const
{
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
attachment->att_timezone_bind = bind;
}
//--------------------
StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
thread_db* tdbb = JRD_get_thread_data(); // necessary?

View File

@ -1749,13 +1749,13 @@ public:
};
class SetHighPrecBindNode : public SessionManagementNode
class SetBindNode : public SessionManagementNode
{
public:
SetHighPrecBindNode(MemoryPool& pool, bool isInt128)
SetBindNode(MemoryPool& pool)
: SessionManagementNode(pool),
bind(Firebird::NumericBinding::NUM_NATIVE),
bindInt128(isInt128)
from(nullptr),
to(nullptr)
{
}
@ -1764,17 +1764,18 @@ public:
{
SessionManagementNode::internalPrint(printer);
NODE_PRINT(printer, bind.bind);
NODE_PRINT(printer, bind.numScale);
NODE_PRINT(printer, from);
NODE_PRINT(printer, to);
return "SetHighPrecBindNode";
return "SetBindNode";
}
virtual SessionManagementNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
public:
Firebird::NumericBinding bind;
bool bindInt128;
dsql_fld *from;
dsql_fld *to;
};
@ -1814,32 +1815,6 @@ public:
};
class SetTimeZoneBindNode : public SessionManagementNode
{
public:
SetTimeZoneBindNode(MemoryPool& pool, Firebird::TimeZoneUtil::Bind aBind)
: SessionManagementNode(pool),
bind(aBind)
{
}
public:
virtual Firebird::string internalPrint(NodePrinter& printer) const
{
SessionManagementNode::internalPrint(printer);
NODE_PRINT(printer, bind);
return "SetTimeZoneBindNode";
}
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const;
public:
Firebird::TimeZoneUtil::Bind bind;
};
class UpdateOrInsertNode : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_UPDATE_OR_INSERT>
{
public:

View File

@ -325,7 +325,11 @@ enum fld_flags_vals {
FLD_computed = 1,
FLD_national = 2, // field uses NATIONAL character set
FLD_nullable = 4,
FLD_system = 8
FLD_system = 8,
FLD_has_len = 16,
FLD_has_chset = 32,
FLD_has_scale = 64,
FLD_legacy = 128
};
//! Stored Procedure block

View File

@ -203,48 +203,6 @@ void GEN_port(DsqlCompilerScratch* dsqlScratch, dsql_msg* message)
if (fromCharSet != toCharSet)
parameter->par_desc.setTextType(toCharSet);
}
else if (parameter->par_desc.isDecFloat() ||
parameter->par_desc.dsc_dtype == dtype_int128)
{
const NumericBinding& b(parameter->par_desc.dsc_dtype == dtype_int128 ?
tdbb->getAttachment()->att_i128_binding : tdbb->getAttachment()->att_dec_binding);
switch (b.bind)
{
case NumericBinding::NUM_NATIVE:
break;
case NumericBinding::NUM_TEXT:
parameter->par_desc.makeText((parameter->par_desc.dsc_dtype == dtype_dec64 ?
IDecFloat16::STRING_SIZE : parameter->par_desc.dsc_dtype == dtype_dec128 ?
IDecFloat34::STRING_SIZE : IInt128::STRING_SIZE) - 1, ttype_ascii);
break;
case NumericBinding::NUM_DOUBLE:
parameter->par_desc.makeDouble();
break;
case NumericBinding::NUM_INT64:
parameter->par_desc.makeInt64(b.numScale);
break;
}
}
else if (parameter->par_desc.isDateTimeTz())
{
switch (tdbb->getAttachment()->att_timezone_bind)
{
case TimeZoneUtil::BIND_LEGACY:
if (parameter->par_desc.isTime())
parameter->par_desc.makeTime();
else if (parameter->par_desc.isTimeStamp())
parameter->par_desc.makeTimestamp();
else
fb_assert(false);
break;
case TimeZoneUtil::BIND_NATIVE:
break;
default:
fb_assert(false);
}
}
if (parameter->par_desc.dsc_dtype == dtype_text && parameter->par_index != 0)
{
@ -257,6 +215,14 @@ void GEN_port(DsqlCompilerScratch* dsqlScratch, dsql_msg* message)
&parameter->par_desc, parameter->par_desc.dsc_length) + sizeof(USHORT);
}
if (!(dsqlScratch->flags & DsqlCompilerScratch::FLAG_INTERNAL_REQUEST))
{
Attachment* att = tdbb->getAttachment();
if (!att->att_bindings.coerce(&parameter->par_desc))
if (!att->getInitialBindings()->coerce(&parameter->par_desc))
tdbb->getDatabase()->getBindings()->coerce(&parameter->par_desc);
}
const USHORT align = type_alignments[parameter->par_desc.dsc_dtype];
if (align)
offset = FB_ALIGN(offset, align);

View File

@ -65,14 +65,14 @@ using namespace Firebird;
// DsqlDescMaker methods
void DsqlDescMaker::fromElement(dsc* desc, const dsql_fld* field)
void DsqlDescMaker::fromElement(dsc* desc, const TypeClause* field)
{
composeDesc(desc,
field->elementDtype, field->scale, field->subType, field->elementLength,
field->charSetId.value, field->collationId, field->flags & FLD_nullable);
}
void DsqlDescMaker::fromField(dsc* desc, const dsql_fld* field)
void DsqlDescMaker::fromField(dsc* desc, const TypeClause* field)
{
composeDesc(desc,
field->dtype, field->scale, field->subType, field->length,

View File

@ -31,6 +31,7 @@
namespace Jrd {
class dsql_ctx;
class dsql_fld;
class TypeClause;
class dsql_msg;
class dsql_par;
class dsql_req;
@ -57,8 +58,8 @@ namespace Jrd {
class DsqlDescMaker
{
public:
static void fromElement(dsc*, const dsql_fld*);
static void fromField(dsc*, const dsql_fld*);
static void fromElement(dsc*, const TypeClause*);
static void fromField(dsc*, const TypeClause*);
static void fromList(DsqlCompilerScratch*, dsc*,
ValueListNode*, const char*, bool = false);
static void fromNode(DsqlCompilerScratch*, dsc*,

View File

@ -817,7 +817,7 @@ using namespace Firebird;
Jrd::CreateAlterRoleNode* createAlterRoleNode;
Jrd::SetDecFloatRoundNode* setDecFloatRoundNode;
Jrd::SetDecFloatTrapsNode* setDecFloatTrapsNode;
Jrd::SetHighPrecBindNode* setHighPrecBindNode;
Jrd::SetBindNode* setBindNode;
Jrd::SessionResetNode* sessionResetNode;
}
@ -878,12 +878,11 @@ tra_statement
mng_statement
: set_decfloat_round { $$ = $1; }
| set_decfloat_traps { $$ = $1; }
| set_decfloat_bind { $$ = $1; }
| session_statement { $$ = $1; }
| set_role { $$ = $1; }
| session_reset { $$ = $1; }
| set_time_zone { $$ = $1; }
| set_time_zone_bind { $$ = $1; }
| set_bind { $$ = $1; }
;
@ -4616,7 +4615,10 @@ simple_type
{
$$ = $1;
if ($2)
{
$$->charSet = *$2;
$$->flags |= FLD_has_chset;
}
}
;
@ -4822,7 +4824,7 @@ national_character_type
$$ = newNode<dsql_fld>();
$$->dtype = dtype_text;
$$->charLength = (USHORT) $3;
$$->flags |= FLD_national;
$$->flags |= (FLD_national | FLD_has_len);
}
| national_character_keyword
{
@ -4836,7 +4838,7 @@ national_character_type
$$ = newNode<dsql_fld>();
$$->dtype = dtype_varying;
$$->charLength = (USHORT) $4;
$$->flags |= FLD_national;
$$->flags |= (FLD_national | FLD_has_len);
}
;
@ -4851,6 +4853,7 @@ binary_character_type
$$->textType = ttype_binary;
$$->charSetId = CS_BINARY;
$$->subType = fb_text_subtype_binary;
$$->flags |= (FLD_has_len | FLD_has_chset);
}
| binary_character_keyword
{
@ -4861,6 +4864,7 @@ binary_character_type
$$->textType = ttype_binary;
$$->charSetId = CS_BINARY;
$$->subType = fb_text_subtype_binary;
$$->flags |= FLD_has_chset;
}
| varbinary_character_keyword '(' pos_short_integer ')'
{
@ -4871,6 +4875,7 @@ binary_character_type
$$->textType = ttype_binary;
$$->charSetId = CS_BINARY;
$$->subType = fb_text_subtype_binary;
$$->flags |= (FLD_has_len | FLD_has_chset);
}
;
@ -4881,6 +4886,7 @@ character_type
$$ = newNode<dsql_fld>();
$$->dtype = dtype_text;
$$->charLength = (USHORT) $3;
$$->flags |= FLD_has_len;
}
| character_keyword
{
@ -4893,6 +4899,7 @@ character_type
$$ = newNode<dsql_fld>();
$$->dtype = dtype_varying;
$$->charLength = (USHORT) $3;
$$->flags |= FLD_has_len;
}
;
@ -4934,6 +4941,8 @@ decfloat_type
yyabandon(YYPOSNARG(2), -842, isc_decprecision_err); // DecFloat precision must be 16 or 34.
$$ = newNode<dsql_fld>();
if (precision)
$$->flags |= FLD_has_scale;
$$->precision = precision == 0 ? 34 : (USHORT) precision;
$$->dtype = precision == 16 ? dtype_dec64 : dtype_dec128;
$$->length = precision == 16 ? sizeof(Decimal64) : sizeof(Decimal128);
@ -4972,6 +4981,7 @@ prec_scale
| '(' signed_long_integer ')'
{
$$ = newNode<dsql_fld>();
$$->flags |= FLD_has_len;
if ($2 < 1 || $2 > 38)
yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(38));
@ -5028,6 +5038,7 @@ prec_scale
| '(' signed_long_integer ',' signed_long_integer ')'
{
$$ = newNode<dsql_fld>();
$$->flags |= (FLD_has_len | FLD_has_scale);
if ($2 < 1 || $2 > 38)
yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(38));
@ -5272,18 +5283,30 @@ set_decfloat_traps
{ $$ = $5; }
;
%type <setHighPrecBindNode> set_decfloat_bind
set_decfloat_bind
: SET bind_to_type BIND
{ $$ = newNode<SetHighPrecBindNode>($2); }
decfloat_bind_clause($4)
{ $$ = $4; }
%type <setBindNode> set_bind
set_bind
: SET BIND OF set_bind_from
{ $$ = newNode<SetBindNode>(); $$->from = $4; }
TO set_bind_to
{ $$ = $5; $$->to = $7; }
;
%type <boolVal> bind_to_type
bind_to_type
: DECFLOAT { $$ = false; }
| INT128 { $$ = true; }
%type <legacyField> set_bind_from
set_bind_from
: simple_type
;
%type <legacyField> set_bind_to
set_bind_to
: simple_type
{
$$ = $1;
}
| LEGACY
{
$$ = newNode<dsql_fld>();
$$->flags = FLD_legacy;
}
;
%type decfloat_traps_list_opt(<setDecFloatTrapsNode>)
@ -5304,28 +5327,6 @@ decfloat_trap($setDecFloatTrapsNode)
{ $setDecFloatTrapsNode->trap($1); }
;
%type decfloat_bind_clause(<setHighPrecBindNode>)
decfloat_bind_clause($setHighPrecBindNode)
: NATIVE
// do nothing
| character_keyword
{ $setHighPrecBindNode->bind.bind = NumericBinding::NUM_TEXT; }
| DOUBLE PRECISION
{ $setHighPrecBindNode->bind.bind = NumericBinding::NUM_DOUBLE; }
| BIGINT decfloat_scale_clause($setHighPrecBindNode)
{ $setHighPrecBindNode->bind.bind = NumericBinding::NUM_INT64; }
;
%type decfloat_scale_clause(<setHighPrecBindNode>)
decfloat_scale_clause($setHighPrecBindNode)
: // nothing
| ',' signed_long_integer
{
if ($2 > NumericBinding::MAX_SCALE || $2 < 0)
yyabandon(YYPOSNARG(2), -842, isc_scale_nogt); // Scale must be between 0 and precision
$setHighPrecBindNode->bind.numScale = -$2;
}
%type <setSessionNode> session_statement
session_statement
: SET SESSION IDLE TIMEOUT long_integer timepart_sesion_idle_tout
@ -5362,17 +5363,6 @@ set_time_zone_option
| LOCAL { $$ = newNode<SetTimeZoneNode>(); }
;
%type <mngNode> set_time_zone_bind
set_time_zone_bind
: SET TIME ZONE BIND set_time_zone_bind_option { $$ = $5; }
;
%type <mngNode> set_time_zone_bind_option
set_time_zone_bind_option
: LEGACY { $$ = newNode<SetTimeZoneBindNode>(TimeZoneUtil::BIND_LEGACY); }
| NATIVE { $$ = newNode<SetTimeZoneBindNode>(TimeZoneUtil::BIND_NATIVE); }
;
%type tran_option_list_opt(<setTransactionNode>)
tran_option_list_opt($setTransactionNode)
: // nothing

View File

@ -125,11 +125,9 @@
#define isc_dpb_map_attach 90
#define isc_dpb_session_time_zone 91
#define isc_dpb_set_db_replica 92
#define isc_dpb_time_zone_bind 93
#define isc_dpb_decfloat_bind 94
#define isc_dpb_decfloat_round 95
#define isc_dpb_decfloat_traps 96
#define isc_dpb_int128_bind 97
#define isc_dpb_set_bind 93
#define isc_dpb_decfloat_round 94
#define isc_dpb_decfloat_traps 95
/**************************************************/

View File

@ -84,13 +84,13 @@ CommitNumber ActiveSnapshots::getSnapshotForVersion(CommitNumber version_cn)
// static method
Jrd::Attachment* Jrd::Attachment::create(Database* dbb, const InitialOptions* initialOptions)
Jrd::Attachment* Jrd::Attachment::create(Database* dbb)
{
MemoryPool* const pool = dbb->createPool();
try
{
Attachment* const attachment = FB_NEW_POOL(*pool) Attachment(pool, dbb, initialOptions);
Attachment* const attachment = FB_NEW_POOL(*pool) Attachment(pool, dbb);
pool->setStatsGroup(attachment->att_memory_stats);
return attachment;
}
@ -203,7 +203,7 @@ void Jrd::Attachment::backupStateReadUnLock(thread_db* tdbb)
}
Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb, const InitialOptions* initialOptions)
Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
: att_pool(pool),
att_memory_stats(&dbb->dbb_memory_stats),
att_database(dbb),
@ -233,7 +233,8 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb, const InitialOption
att_ext_parent(NULL),
att_ext_call_depth(0),
att_trace_manager(FB_NEW_POOL(*att_pool) TraceManager(this)),
att_timezone_bind(TimeZoneUtil::BIND_NATIVE),
att_bindings(*pool),
att_dest_bind(&att_bindings),
att_original_timezone(TimeZoneUtil::getSystemTimeZone()),
att_current_timezone(att_original_timezone),
att_utility(UTIL_NONE),
@ -243,21 +244,16 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb, const InitialOption
att_internal(*pool),
att_dyn_req(*pool),
att_dec_status(DecimalStatus::DEFAULT),
att_dec_binding(NumericBinding::DEFAULT),
att_charsets(*pool),
att_charset_ids(*pool),
att_pools(*pool),
att_idle_timeout(0),
att_stmt_timeout(0),
att_batches(*pool)
att_batches(*pool),
att_initial_options(*pool)
{
att_internal.grow(irq_MAX);
att_dyn_req.grow(drq_MAX);
if (initialOptions)
att_initial_options = *initialOptions;
att_initial_options.resetAttachment(this);
}
@ -1089,3 +1085,4 @@ void Attachment::IdleTimer::reset(unsigned int timeout)
check(&s);
m_fireTime = m_expTime;
}

View File

@ -32,6 +32,7 @@
#include "../jrd/PreparedStatement.h"
#include "../jrd/RandomGenerator.h"
#include "../jrd/RuntimeStatistics.h"
#include "../jrd/Coercion.h"
#include "../common/classes/ByteChunk.h"
#include "../common/classes/GenericMap.h"
@ -92,6 +93,7 @@ namespace Jrd
class Validation;
class Applier;
struct DSqlCacheItem
{
DSqlCacheItem(MemoryPool& pool)
@ -363,28 +365,35 @@ public:
class InitialOptions
{
public:
InitialOptions(const DatabaseOptions& options);
InitialOptions()
InitialOptions(MemoryPool& p)
: bindings(p)
{
}
public:
void setInitialOptions(thread_db* tdbb, const DatabaseOptions& options);
static void setBind(thread_db* tdbb, const Firebird::PathName& bind, CoercionArray* target);
void resetAttachment(Attachment* attachment) const;
CoercionArray *getBindings()
{
return &bindings;
}
const CoercionArray *getBindings() const
{
return &bindings;
}
private:
void setBinding(Firebird::string option, Firebird::NumericBinding& bind);
Firebird::DecimalStatus decFloatStatus = Firebird::DecimalStatus::DEFAULT;
Firebird::NumericBinding decFloatBinding = Firebird::NumericBinding::DEFAULT;
Firebird::NumericBinding int128Binding = Firebird::NumericBinding::DEFAULT;
CoercionArray bindings;
Firebird::TimeZoneUtil::Bind timeZoneBind = Firebird::TimeZoneUtil::BIND_NATIVE;
USHORT originalTimeZone = Firebird::TimeZoneUtil::GMT_ZONE;
};
public:
static Attachment* create(Database* dbb, const InitialOptions* initialOptions);
static Attachment* create(Database* dbb);
static void destroy(Attachment* const attachment);
MemoryPool* const att_pool; // Memory pool
@ -454,7 +463,8 @@ public:
ULONG att_ext_call_depth; // external connection call depth, 0 for user attachment
TraceManager* att_trace_manager; // Trace API manager
Firebird::TimeZoneUtil::Bind att_timezone_bind;
CoercionArray att_bindings;
CoercionArray* att_dest_bind;
USHORT att_original_timezone;
USHORT att_current_timezone;
@ -479,8 +489,6 @@ public:
Firebird::Array<JrdStatement*> att_dyn_req; // internal dyn statements
Firebird::ICryptKeyCallback* att_crypt_callback; // callback for DB crypt
Firebird::DecimalStatus att_dec_status; // error handling and rounding
Firebird::NumericBinding att_dec_binding; // use legacy datatype for DecFloat in outer world
Firebird::NumericBinding att_i128_binding; // use legacy datatype for INT128 in outer world
jrd_req* findSystemRequest(thread_db* tdbb, USHORT id, USHORT which);
@ -620,8 +628,15 @@ public:
return att_user;
}
void setInitialOptions(thread_db* tdbb, DatabaseOptions& options, bool newDb);
const CoercionArray* getInitialBindings() const
{
return att_initial_options.getBindings();
}
private:
Attachment(MemoryPool* pool, Database* dbb, const InitialOptions* initialOptions);
Attachment(MemoryPool* pool, Database* dbb);
~Attachment();
class IdleTimer FB_FINAL :

149
src/jrd/Coercion.cpp Normal file
View File

@ -0,0 +1,149 @@
/*
* PROGRAM: JRD access method
* MODULE: Coercion.cpp
* DESCRIPTION: Automatically coercing user datatypes
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2019 Alex Peshkov <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#include "firebird.h"
#include "../jrd/Coercion.h"
#include "../dsql/dsql.h"
#include "../jrd/align.h"
using namespace Jrd;
using namespace Firebird;
bool CoercionArray::coerce(dsc* d) const
{
// move down through array to ensure correct order: newer rule overrides older one
for (unsigned n = getCount(); n--;)
{
if (getElement(n).coerce(d))
return true;
}
return false;
}
bool CoercionRule::coerce(dsc* d) const
{
bool found = false;
// check for exact match (taking flags into an account)
if ((!found) &&
(d->dsc_dtype == fromDsc.dsc_dtype) &&
((d->dsc_length == fromDsc.dsc_length) || (!(fromMask & FLD_has_len))) &&
((d->getCharSet() == fromDsc.getCharSet()) || (!(fromMask & FLD_has_chset))) &&
((d->dsc_scale == fromDsc.dsc_scale) || (!(fromMask & FLD_has_scale))))
{
found = true;
}
// check for inexact datatype match when FLD_has_len is not set
if ((!found) && (!(fromMask & FLD_has_len)))
{
switch(fromDsc.dsc_dtype)
{
case dtype_dec64:
case dtype_dec128:
if (d->dsc_dtype == dtype_dec64 || d->dsc_dtype == dtype_dec128)
{
found = true;
break;
}
}
}
if (!found)
return false;
// now define output descriptor
// first of all process LEGACY case
if (toMask & FLD_legacy)
{
found = true;
switch(d->dsc_dtype)
{
case dtype_dec64:
case dtype_dec128:
d->dsc_dtype = dtype_double;
d->dsc_length = 8;
break;
case dtype_sql_time_tz:
d->dsc_dtype = dtype_sql_time;
d->dsc_length = 4;
break;
case dtype_timestamp_tz:
d->dsc_dtype = dtype_timestamp;
d->dsc_length = 8;
break;
case dtype_int128:
d->dsc_dtype = dtype_int64;
d->dsc_length = 8;
break;
case dtype_boolean:
d->dsc_dtype = dtype_text;
d->dsc_length = 5;
break;
default:
found = false;
break;
}
return found;
}
// Final pass - order is important
// length
if (toMask & FLD_has_len)
d->dsc_length = toDsc.dsc_length;
else
{
if (!type_lengths[toDsc.dsc_dtype])
{
fb_assert(toDsc.isText());
d->dsc_length = d->getStringLength();
}
else
d->dsc_length = type_lengths[toDsc.dsc_dtype];
}
// scale
if (toMask & FLD_has_scale)
d->dsc_scale = toDsc.dsc_scale;
else if (!(DTYPE_IS_EXACT(d->dsc_dtype) && DTYPE_IS_EXACT(toDsc.dsc_dtype)))
d->dsc_scale = 0;
// type
d->dsc_dtype = toDsc.dsc_dtype;
d->dsc_sub_type = toDsc.dsc_sub_type;
// charset
if (toMask & FLD_has_chset)
d->setTextType(toDsc.getTextType());
return true;
}

72
src/jrd/Coercion.h Normal file
View File

@ -0,0 +1,72 @@
/*
* PROGRAM: JRD access method
* MODULE: Coercion.h
* DESCRIPTION: Automatically coercing user datatypes
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2019 Alex Peshkov <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#ifndef JRD_COERCION_H
#define JRD_COERCION_H
#include "firebird.h"
#include "../common/classes/array.h"
#include "../common/dsc.h"
namespace Jrd
{
class thread_db;
class TypeClause;
class CoercionRule
{
public:
CoercionRule()
: fromMask(0), toMask(0)
{
fromDsc.clear();
toDsc.clear();
}
void setRule(TypeClause* from, TypeClause *to);
bool coerce(dsc* d) const;
private:
dsc fromDsc, toDsc;
USHORT fromMask, toMask;
};
class CoercionArray : public Firebird::HalfStaticArray<CoercionRule, 4>
{
public:
CoercionArray(MemoryPool& p)
: Firebird::HalfStaticArray<CoercionRule, 4>(p)
{
}
bool coerce(dsc* d) const;
};
} // namespace Jrd
#endif // JRD_COERCION_H

View File

@ -922,7 +922,7 @@ namespace Jrd {
UserId user;
user.setUserName("Database Crypter");
Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb, nullptr);
Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb);
RefPtr<SysStableAttachment> sAtt(FB_NEW SysStableAttachment(attachment));
attachment->setStable(sAtt);
attachment->att_filename = dbb.dbb_filename;

View File

@ -61,6 +61,7 @@
#include "../jrd/RuntimeStatistics.h"
#include "../jrd/event_proto.h"
#include "../jrd/ExtEngineManager.h"
#include "../jrd/Coercion.h"
#include "../lock/lock_proto.h"
#include "../common/config/config.h"
#include "../common/classes/SyncObject.h"
@ -439,6 +440,7 @@ public:
FB_UINT64 dbb_repl_sequence; // replication sequence
ReplicaMode dbb_replica_mode; // replica access mode
CoercionArray dbb_bindings; // preconfigured datatype coercions
// returns true if primary file is located on raw device
bool onRawDevice() const;
@ -503,7 +505,8 @@ private:
dbb_linger_end(0),
dbb_plugin_config(pConf),
dbb_repl_sequence(0),
dbb_replica_mode(REPLICA_NONE)
dbb_replica_mode(REPLICA_NONE),
dbb_bindings(*p)
{
dbb_pools.add(p);
}
@ -541,6 +544,17 @@ public:
FB_UINT64 getReplSequence(thread_db* tdbb);
void setReplSequence(thread_db* tdbb, FB_UINT64 sequence);
CoercionArray *getBindings()
{
return &dbb_bindings;
}
const CoercionArray *getBindings() const
{
return &dbb_bindings;
}
private:
//static int blockingAstSharedCounter(void*);
static int blocking_ast_sweep(void* ast_object);

View File

@ -2959,7 +2959,7 @@ void BufferControl::cache_writer(BufferControl* bcb)
UserId user;
user.setUserName("Cache Writer");
Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb, nullptr);
Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb);
RefPtr<SysStableAttachment> sAtt(FB_NEW SysStableAttachment(attachment));
attachment->setStable(sAtt);
attachment->att_filename = dbb->dbb_filename;

View File

@ -127,6 +127,7 @@
#include "../common/classes/fb_tls.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/RefMutex.h"
#include "../common/classes/ParsedList.h"
#include "../common/utils_proto.h"
#include "../jrd/DebugInterface.h"
#include "../jrd/CryptoManager.h"
@ -1016,11 +1017,9 @@ namespace Jrd
PathName dpb_org_filename;
string dpb_config;
string dpb_session_tz;
string dpb_time_zone_bind;
string dpb_decfloat_bind;
PathName dpb_set_bind;
string dpb_decfloat_round;
string dpb_decfloat_traps;
string dpb_int128_bind;
public:
static const ULONG DPB_FLAGS_MASK = DBB_damaged;
@ -1063,63 +1062,40 @@ namespace Jrd
}
};
void Attachment::InitialOptions::setBinding(string option, NumericBinding& bind)
void Attachment::setInitialOptions(thread_db* tdbb, DatabaseOptions& options, bool newDb)
{
option.lower();
if (option == "native")
bind = NumericBinding::DEFAULT;
else if (option == "char" || option == "character")
bind = NumericBinding(NumericBinding::NUM_TEXT);
else if (option == "double" || option == "double precision")
bind = NumericBinding(NumericBinding::NUM_DOUBLE);
else if (option == "bigint")
bind = NumericBinding(NumericBinding::NUM_INT64);
else if (option.substr(0, 7) == "bigint,")
if (newDb)
{
const char* p = option.c_str() + 7;
while (*p == ' ')
++p;
const char* start = p;
int scale = 0;
while (*p >= '0' && *p <= '9')
{
scale = scale * 10 + (*p - '0');
++p;
}
if (*p != '\0' || p - start == 0 || p - start > 2 || scale > NumericBinding::MAX_SCALE)
(Arg::Gds(isc_invalid_decfloat_bind) << option).raise();
bind = NumericBinding(NumericBinding::NUM_INT64, static_cast<SCHAR>(-scale));
Database* dbb = tdbb->getDatabase();
if (dbb->dbb_config->getBind())
InitialOptions::setBind(tdbb, dbb->dbb_config->getBind(), dbb->getBindings());
}
else
(Arg::Gds(isc_invalid_decfloat_bind) << option).raise();
att_initial_options.setInitialOptions(tdbb, options);
att_initial_options.resetAttachment(this);
}
Attachment::InitialOptions::InitialOptions(const DatabaseOptions& options)
void Attachment::InitialOptions::setBind(thread_db* tdbb, const PathName& bind, CoercionArray* target)
{
if (options.dpb_time_zone_bind.hasData())
if (bind.hasData())
{
auto option = options.dpb_time_zone_bind;
option.lower();
ParsedList rules(bind, ";,");
Attachment* att = tdbb->getAttachment();
AutoSetRestore<CoercionArray*> defSet(&att->att_dest_bind, target);
if (option == "legacy")
timeZoneBind = TimeZoneUtil::BIND_LEGACY;
else if (option == "native")
timeZoneBind = TimeZoneUtil::BIND_NATIVE;
else
(Arg::Gds(isc_invalid_time_zone_bind) << option).raise();
for (unsigned i = 0; i < rules.getCount(); ++i)
{
rules[i].insert(0, "SET BIND OF ");
AutoPreparedStatement ps(att->prepareStatement(tdbb, nullptr, rules[i].ToString()));
ps->execute(tdbb, nullptr);
}
}
}
if (options.dpb_decfloat_bind.hasData())
setBinding(options.dpb_decfloat_bind, decFloatBinding);
if (options.dpb_int128_bind.hasData())
setBinding(options.dpb_int128_bind, int128Binding);
void Attachment::InitialOptions::setInitialOptions(thread_db* tdbb, const DatabaseOptions& options)
{
setBind(tdbb, options.dpb_set_bind, getBindings());
if (options.dpb_decfloat_round.hasData())
{
@ -1177,12 +1153,12 @@ namespace Jrd
{
// reset DecFloat options
attachment->att_dec_status = decFloatStatus;
attachment->att_dec_binding = decFloatBinding;
attachment->att_i128_binding = int128Binding;
// reset time zone options
attachment->att_timezone_bind = timeZoneBind;
attachment->att_current_timezone = attachment->att_original_timezone = originalTimeZone;
// reset bindings
attachment->att_bindings.clear();
}
} // namespace Jrd
@ -1682,9 +1658,11 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
TRA_init(attachment);
bool newDb = false;
if (dbb->dbb_flags & DBB_new)
{
// If we're a not a secondary attachment, initialize some stuff
newDb = true;
// NS: Use alias as database ID only if accessing database using file name is not possible.
//
@ -2075,6 +2053,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
CCH_init2(tdbb);
VIO_init(tdbb);
attachment->setInitialOptions(tdbb, options, newDb);
CCH_release_exclusive(tdbb);
@ -3008,6 +2987,8 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
Monitoring::publishAttachment(tdbb);
attachment->setInitialOptions(tdbb, options, true);
CCH_release_exclusive(tdbb);
// Figure out what character set & collation this attachment prefers
@ -6968,16 +6949,8 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
dpb_replica_mode = (ReplicaMode) rdr.getInt();
break;
case isc_dpb_time_zone_bind:
rdr.getString(dpb_time_zone_bind);
break;
case isc_dpb_decfloat_bind:
rdr.getString(dpb_decfloat_bind);
break;
case isc_dpb_int128_bind:
rdr.getString(dpb_int128_bind);
case isc_dpb_set_bind:
rdr.getPath(dpb_set_bind);
break;
case isc_dpb_decfloat_round:
@ -7213,8 +7186,7 @@ static JAttachment* create_attachment(const PathName& alias_name,
status_exception::raise(Arg::Gds(isc_att_shutdown));
}
Attachment::InitialOptions initialOptions(options);
attachment = Attachment::create(dbb, &initialOptions);
attachment = Attachment::create(dbb);
attachment->att_next = dbb->dbb_attachments;
dbb->dbb_attachments = attachment;
}

View File

@ -4737,7 +4737,7 @@ void Database::garbage_collector(Database* dbb)
UserId user;
user.setUserName("Garbage Collector");
Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb, nullptr);
Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb);
RefPtr<SysStableAttachment> sAtt(FB_NEW SysStableAttachment(attachment));
attachment->setStable(sAtt);
attachment->att_filename = dbb->dbb_filename;