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

Added NATIVE binding support

This commit is contained in:
AlexPeshkoff 2019-11-11 17:26:24 +03:00 committed by Alexander Peshkov
parent a6b05a671e
commit 6a4db49be4
6 changed files with 62 additions and 28 deletions

View File

@ -11,15 +11,30 @@
### Syntax is: ### Syntax is:
```sql ```sql
SET BIND OF type1 TO type2; SET BIND OF type-from TO { type-to | LEGACY };
SET BIND OF type NATIVE; SET BIND OF type NATIVE;
``` ```
### Description: ### Description:
Makes it possible to define rules of describing types of returned to the client columns in non-standard way - `type1` is replaced with `type2`, automatic data coercion takes place. Makes it possible to define rules of describing types of returned to the client columns in non-standard way -
`type-from` is replaced with `type-to`, automatic data coercion takes place.
Except SQL-statement there are two more ways to specify data coercion - tag `isc_dpb_bind` in DPB
and `SetBind` parameter in firebird.conf & databases.conf. The later the rule is introduced (.conf->DPB->SQL)
the higher priotiy it has. I.e. one can override any preconfigured settings from SQL statement.
When incomplete type definition is used (i.e. `CHAR` instead `CHAR(n)`) in left part of `SET BIND` coercion
will take place for all `CHAR` columns, not only default `CHAR(1)`.
When incomplete type definiton is used in right side of the statement (TO part) firebird engine will define missing
details about that type automatically based on source column.
Special `TO` part format `LEGACY` is used when datatype, missing in previous FB version, should be represented in
a way, understandable by old client software (may be with some data losses). For example, `NUMERIC(38)` in legacy
form will be represented as `NUMERIC(18)`.
Setting `NATIVE` means `type` will be used as if there were no previous rules for it.
When incomplete type definition is used (i.e. `CHAR` instead `CHAR(n)`) in left part of `SET BIND` coercion will take place for all `CHAR` columns, not only default `CHAR(1)`. When incomplete type definiton is used in right side of the statement firebird engine will define missing parts automatically based on source column.
### Samples: ### Samples:

View File

@ -8361,23 +8361,12 @@ void SetDecFloatTrapsNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_t
//-------------------- //--------------------
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) SessionManagementNode* SetBindNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{ {
static const USHORT NON_FIELD_MASK = FLD_legacy | FLD_native;
from->resolve(dsqlScratch); from->resolve(dsqlScratch);
if (!(to->flags & FLD_legacy)) if (!(to->flags & NON_FIELD_MASK))
to->resolve(dsqlScratch); to->resolve(dsqlScratch);
return SessionManagementNode::dsqlPass(dsqlScratch); return SessionManagementNode::dsqlPass(dsqlScratch);

View File

@ -329,7 +329,8 @@ enum fld_flags_vals {
FLD_has_len = 16, FLD_has_len = 16,
FLD_has_chset = 32, FLD_has_chset = 32,
FLD_has_scale = 64, FLD_has_scale = 64,
FLD_legacy = 128 FLD_legacy = 128,
FLD_native = 256
}; };
//! Stored Procedure block //! Stored Procedure block

View File

@ -5287,8 +5287,8 @@ set_decfloat_traps
set_bind set_bind
: SET BIND OF set_bind_from : SET BIND OF set_bind_from
{ $$ = newNode<SetBindNode>(); $$->from = $4; } { $$ = newNode<SetBindNode>(); $$->from = $4; }
TO set_bind_to set_bind_to
{ $$ = $5; $$->to = $7; } { $$ = $5; $$->to = $6; }
; ;
%type <legacyField> set_bind_from %type <legacyField> set_bind_from
@ -5298,15 +5298,20 @@ set_bind_from
%type <legacyField> set_bind_to %type <legacyField> set_bind_to
set_bind_to set_bind_to
: simple_type : TO simple_type
{ {
$$ = $1; $$ = $2;
} }
| LEGACY | TO LEGACY
{ {
$$ = newNode<dsql_fld>(); $$ = newNode<dsql_fld>();
$$->flags = FLD_legacy; $$->flags = FLD_legacy;
} }
| NATIVE
{
$$ = newNode<dsql_fld>();
$$->flags = FLD_native;
}
; ;
%type decfloat_traps_list_opt(<setDecFloatTrapsNode>) %type decfloat_traps_list_opt(<setDecFloatTrapsNode>)

View File

@ -29,11 +29,15 @@
#include "../jrd/Coercion.h" #include "../jrd/Coercion.h"
#include "../dsql/dsql.h" #include "../dsql/dsql.h"
#include "../dsql/make_proto.h"
#include "../jrd/align.h" #include "../jrd/align.h"
using namespace Jrd; using namespace Jrd;
using namespace Firebird; using namespace Firebird;
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 | FLD_native;
bool CoercionArray::coerce(dsc* d) const bool CoercionArray::coerce(dsc* d) const
{ {
// move down through array to ensure correct order: newer rule overrides older one // move down through array to ensure correct order: newer rule overrides older one
@ -46,7 +50,16 @@ bool CoercionArray::coerce(dsc* d) const
return false; return false;
} }
bool CoercionRule::coerce(dsc* d) const void CoercionRule::setRule(TypeClause* from, TypeClause *to)
{
fromMask = from->flags & FROM_MASK;
DsqlDescMaker::fromField(&fromDsc, from);
toMask = to->flags & TO_MASK;
DsqlDescMaker::fromField(&toDsc, to);
}
bool CoercionRule::match(dsc* d) const
{ {
bool found = false; bool found = false;
@ -75,14 +88,24 @@ bool CoercionRule::coerce(dsc* d) const
} }
} }
if (!found) return found;
}
bool CoercionRule::coerce(dsc* d) const
{
// check does descriptor match FROM clause
if (! match(d))
return false; return false;
// now define output descriptor // native binding - do not touch descriptor at all
// first of all process LEGACY case if (toMask & FLD_native)
return true;
// process legacy case
if (toMask & FLD_legacy) if (toMask & FLD_legacy)
{ {
found = true; bool found = true;
switch(d->dsc_dtype) switch(d->dsc_dtype)
{ {
case dtype_dec64: case dtype_dec64:

View File

@ -50,6 +50,7 @@ public:
void setRule(TypeClause* from, TypeClause *to); void setRule(TypeClause* from, TypeClause *to);
bool coerce(dsc* d) const; bool coerce(dsc* d) const;
bool match(dsc* d) const;
private: private:
dsc fromDsc, toDsc; dsc fromDsc, toDsc;