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:
parent
a6b05a671e
commit
6a4db49be4
@ -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:
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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>)
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user