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

Improvement CORE-5430 - Support for INCREMENT option in identity columns.

This commit is contained in:
Adriano dos Santos Fernandes 2016-12-27 14:51:27 -02:00
parent 94bdb099b5
commit 278c993915
18 changed files with 115 additions and 32 deletions

View File

@ -25,6 +25,9 @@
## Improvements
* [CORE-5430](http://tracker.firebirdsql.org/browse/CORE-5430): Support for INCREMENT option in identity columns
Contributor(s): Adriano dos Santos Fernandes
* [CORE-5119](http://tracker.firebirdsql.org/browse/CORE-5119): Support autocommit mode in SET TRANSACTION statement
Contributor(s): Dmitry Yemanov

View File

@ -11,10 +11,15 @@ Description:
Syntax:
<column definition> ::=
<name> <type> GENERATED BY DEFAULT AS IDENTITY [ (START WITH <value>) ] <constraints>
<name> <type> GENERATED BY DEFAULT AS IDENTITY [ ( <identity column option>... ) ] <constraints>
<identity column option> ::=
START WITH <value> |
INCREMENT [ BY ] <value>
<alter column definition> ::=
<name> RESTART [ WITH <value> ]
<name> RESTART [ WITH <value> ] |
<name> SET INCREMENT [ BY ] <value>
Syntax rules:
- The type of an identity column must be an exact number type with zero scale. That includes:
@ -25,6 +30,7 @@ Notes:
- You cannot alter a identity column to normal column and vice versa.
- Identity columns are implicitly NOT NULL.
- Identity columns don't enforce uniqueness automatically. Use UNIQUE or PRIMARY key for that.
- Increment value cannot be 0.
Implementation:
Two columns have been inserted in RDB$RELATION_FIELDS: RDB$GENERATOR_NAME and RDB$IDENTITY_TYPE.

View File

@ -1948,6 +1948,8 @@ C --
PARAMETER (GDS__dyn_cant_use_in_foreignkey = 336068897)
INTEGER*4 GDS__dyn_defvaldecl_package_func
PARAMETER (GDS__dyn_defvaldecl_package_func = 336068898)
INTEGER*4 GDS__dyn_cant_use_zero_inc_ident
PARAMETER (GDS__dyn_cant_use_zero_inc_ident = 336068904)
INTEGER*4 GDS__gbak_unknown_switch
PARAMETER (GDS__gbak_unknown_switch = 336330753)
INTEGER*4 GDS__gbak_page_size_missing

View File

@ -1943,6 +1943,8 @@ const
gds_dyn_cant_use_in_foreignkey = 336068897;
isc_dyn_defvaldecl_package_func = 336068898;
gds_dyn_defvaldecl_package_func = 336068898;
isc_dyn_cant_use_zero_inc_ident = 336068904;
gds_dyn_cant_use_zero_inc_ident = 336068904;
isc_gbak_unknown_switch = 336330753;
gds_gbak_unknown_switch = 336330753;
isc_gbak_page_size_missing = 336330754;

View File

@ -60,6 +60,11 @@ public:
return nullable;
}
T orElse(T elseValue) const
{
return specified ? value : elseValue;
}
bool operator ==(const BaseNullable<T>& o) const
{
return (!specified && !o.specified) || (specified == o.specified && value == o.value);

View File

@ -6279,6 +6279,13 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
if (clause->identity)
{
if (clause->identity->increment.orElse(1) == 0)
{
status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) <<
Arg::Str(field->fld_name) <<
Arg::Str(name));
}
dsc desc;
MET_get_domain(tdbb, *tdbb->getDefaultPool(), fieldDefinition.fieldSource, &desc, NULL);
@ -6291,7 +6298,9 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence);
CreateAlterSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence,
fb_sysflag_identity_generator, clause->identityStart, 1);
fb_sysflag_identity_generator,
clause->identity->start.orElse(0),
clause->identity->increment.orElse(1));
}
BlrDebugWriter::BlrData defaultValue;
@ -7838,7 +7847,7 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc
}
END_MODIFY
}
else if (clause->identityRestart)
else if (clause->identityRestart || clause->identityIncrement.specified)
{
bool found = false;
AutoRequest request2;
@ -7849,11 +7858,29 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc
{
const SLONG id = GEN.RDB$GENERATOR_ID;
const MetaName genName(RFR.RDB$GENERATOR_NAME);
const SINT64 val = clause->identityRestartValue.specified ?
clause->identityRestartValue.value :
(!GEN.RDB$INITIAL_VALUE.NULL ? GEN.RDB$INITIAL_VALUE : 0);
transaction->getGenIdCache()->put(id, val);
if (clause->identityRestart)
{
const SINT64 val = clause->identityRestartValue.specified ?
clause->identityRestartValue.value :
(!GEN.RDB$INITIAL_VALUE.NULL ? GEN.RDB$INITIAL_VALUE : 0);
transaction->getGenIdCache()->put(id, val);
}
else if (clause->identityIncrement.specified)
{
if (clause->identityIncrement.value == 0)
{
status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_inc_ident) <<
Arg::Str(field->fld_name) <<
Arg::Str(name));
}
MET_update_generator_increment(tdbb, id, clause->identityIncrement.value);
}
else
fb_assert(false);
dsc desc;
desc.makeText((USHORT) genName.length(), ttype_metadata,
(UCHAR*) genName.c_str());

View File

@ -1304,6 +1304,16 @@ public:
NestConst<BoolSourceClause> check;
};
struct IdentityOptions
{
IdentityOptions(MemoryPool&)
{
}
Nullable<SINT64> start;
Nullable<SLONG> increment;
};
struct AddColumnClause : public Clause
{
explicit AddColumnClause(MemoryPool& p)
@ -1313,8 +1323,7 @@ public:
constraints(p),
collate(p),
computed(NULL),
identity(false),
identityStart(0),
identity(NULL),
notNullSpecified(false)
{
}
@ -1324,8 +1333,7 @@ public:
Firebird::ObjectsArray<AddConstraintClause> constraints;
Firebird::MetaName collate;
NestConst<ValueSourceClause> computed;
bool identity;
SINT64 identityStart;
NestConst<IdentityOptions> identity;
bool notNullSpecified;
};
@ -1385,6 +1393,7 @@ public:
bool dropDefault;
bool identityRestart;
Nullable<SINT64> identityRestartValue;
Nullable<SINT64> identityIncrement;
NestConst<ValueSourceClause> computed;
};

View File

@ -698,9 +698,9 @@ public:
const bool dialect1;
GeneratorItem generator;
NestConst<ValueExprNode> arg;
SLONG step;
private:
SLONG step;
bool sysGen;
const bool implicit;
const bool identity;

View File

@ -6839,17 +6839,13 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb)
if (generatorName.hasData())
{
// Make a gen_id(<generator name>, 1) expression.
// Make a (next value for <generator name>) expression.
LiteralNode* literal = FB_NEW_POOL(csb->csb_pool) LiteralNode(csb->csb_pool);
SLONG* increment = FB_NEW_POOL(csb->csb_pool) SLONG(1);
literal->litDesc.makeLong(0, increment);
GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool)
GenIdNode(csb->csb_pool, (csb->blrVersion == 4), generatorName, literal, false, true);
GenIdNode* const genNode = FB_NEW_POOL(csb->csb_pool) GenIdNode(
csb->csb_pool, (csb->blrVersion == 4), generatorName, NULL, true, true);
bool sysGen = false;
if (!MET_load_generator(tdbb, genNode->generator, &sysGen))
if (!MET_load_generator(tdbb, genNode->generator, &sysGen, &genNode->step))
PAR_error(csb, Arg::Gds(isc_gennotdef) << Arg::Str(generatorName));
if (sysGen)

View File

@ -722,6 +722,7 @@ using namespace Firebird;
Jrd::RelationNode::AddColumnClause* addColumnClause;
Jrd::RelationNode::RefActionClause* refActionClause;
Jrd::RelationNode::IndexConstraintClause* indexConstraintClause;
Jrd::RelationNode::IdentityOptions* identityOptions;
Jrd::CreateRelationNode* createRelationNode;
Jrd::CreateAlterViewNode* createAlterViewNode;
Jrd::CreateIndexNode* createIndexNode;
@ -2148,8 +2149,7 @@ column_def($relationNode)
newNode<RelationNode::AddColumnClause>();
clause->field = $2;
clause->field->fld_name = *$1;
clause->identity = true;
clause->identityStart = $3;
clause->identity = $3;
$relationNode->clauses.add(clause);
}
column_constraint_clause(NOTRIAL($<addColumnClause>4)) collate_clause
@ -2177,15 +2177,32 @@ column_def($relationNode)
}
;
%type <int64Val> identity_clause
%type <identityOptions> identity_clause
identity_clause
: GENERATED BY DEFAULT AS IDENTITY identity_clause_options { $$ = $6; }
: GENERATED BY DEFAULT AS IDENTITY
{ $$ = newNode<RelationNode::IdentityOptions>(); }
identity_clause_options_opt($6)
{ $$ = $6; }
;
%type <int64Val> identity_clause_options
identity_clause_options
: /* nothing */ { $$ = 0; }
| '(' START WITH sequence_value ')' { $$ = $4; }
%type identity_clause_options_opt(<identityOptions>)
identity_clause_options_opt($identityOptions)
: // nothing
| '(' identity_clause_options($identityOptions) ')'
;
%type identity_clause_options(<identityOptions>)
identity_clause_options($identityOptions)
: identity_clause_options identity_clause_option($identityOptions)
| identity_clause_option($identityOptions)
;
%type identity_clause_option(<identityOptions>)
identity_clause_option($identityOptions)
: START WITH sequence_value
{ setClause($identityOptions->start, "START WITH", $3); }
| INCREMENT by_noise signed_long_integer
{ setClause($identityOptions->increment, "INCREMENT BY", $3); }
;
// value does allow parens around it, but there is a problem getting the source text.
@ -3919,6 +3936,14 @@ alter_op($relationNode)
clause->identityRestartValue = $4;
$relationNode->clauses.add(clause);
}
| col_opt symbol_column_name SET INCREMENT by_noise signed_long_integer
{
RelationNode::AlterColTypeClause* clause = newNode<RelationNode::AlterColTypeClause>();
clause->field = newNode<dsql_fld>();
clause->field->fld_name = *$2;
clause->identityIncrement = $6;
$relationNode->clauses.add(clause);
}
| ALTER SQL SECURITY DEFINER
{
RelationNode::AlterSqlSecurityClause* clause =

View File

@ -970,6 +970,7 @@ static const struct {
{"dyn_cant_use_zero_increment", 336068896},
{"dyn_cant_use_in_foreignkey", 336068897},
{"dyn_defvaldecl_package_func", 336068898},
{"dyn_cant_use_zero_inc_ident", 336068904},
{"gbak_unknown_switch", 336330753},
{"gbak_page_size_missing", 336330754},
{"gbak_page_size_toobig", 336330755},

View File

@ -1004,6 +1004,7 @@ const ISC_STATUS isc_dyn_cant_modify_sysobj = 336068895L;
const ISC_STATUS isc_dyn_cant_use_zero_increment = 336068896L;
const ISC_STATUS isc_dyn_cant_use_in_foreignkey = 336068897L;
const ISC_STATUS isc_dyn_defvaldecl_package_func = 336068898L;
const ISC_STATUS isc_dyn_cant_use_zero_inc_ident = 336068904L;
const ISC_STATUS isc_gbak_unknown_switch = 336330753L;
const ISC_STATUS isc_gbak_page_size_missing = 336330754L;
const ISC_STATUS isc_gbak_page_size_toobig = 336330755L;
@ -1334,7 +1335,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1278;
const ISC_STATUS isc_err_max = 1279;
#else /* c definitions */
@ -2308,6 +2309,7 @@ const ISC_STATUS isc_err_max = 1278;
#define isc_dyn_cant_use_zero_increment 336068896L
#define isc_dyn_cant_use_in_foreignkey 336068897L
#define isc_dyn_defvaldecl_package_func 336068898L
#define isc_dyn_cant_use_zero_inc_ident 336068904L
#define isc_gbak_unknown_switch 336330753L
#define isc_gbak_page_size_missing 336330754L
#define isc_gbak_page_size_toobig 336330755L
@ -2638,7 +2640,7 @@ const ISC_STATUS isc_err_max = 1278;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1278
#define isc_err_max 1279
#endif

View File

@ -973,6 +973,7 @@ Data source : @4"}, /* eds_statement */
{336068896, "INCREMENT BY 0 is an illegal option for sequence @1"}, /* dyn_cant_use_zero_increment */
{336068897, "Can't use @1 in FOREIGN KEY constraint"}, /* dyn_cant_use_in_foreignkey */
{336068898, "Default values for parameters are allowed only in declaration of packaged function @1.@2"}, /* dyn_defvaldecl_package_func */
{336068904, "INCREMENT BY 0 is an illegal option for identity column @1 of table @2"}, /* dyn_cant_use_zero_inc_ident */
{336330753, "found unknown switch"}, /* gbak_unknown_switch */
{336330754, "page size parameter missing"}, /* gbak_page_size_missing */
{336330755, "Page size specified (@1) greater than limit (32768 bytes)"}, /* gbak_page_size_toobig */

View File

@ -969,6 +969,7 @@ static const struct {
{336068896, -901}, /* 288 dyn_cant_use_zero_increment */
{336068897, -901}, /* 289 dyn_cant_use_in_foreignkey */
{336068898, -901}, /* 290 dyn_defvaldecl_package_func */
{336068904, -901}, /* 296 dyn_cant_use_zero_inc_ident */
{336330753, -901}, /* 1 gbak_unknown_switch */
{336330754, -901}, /* 2 gbak_page_size_missing */
{336330755, -901}, /* 3 gbak_page_size_toobig */

View File

@ -969,6 +969,7 @@ static const struct {
{336068896, "42000"}, // 288 dyn_cant_use_zero_increment
{336068897, "42000"}, // 289 dyn_cant_use_in_foreignkey
{336068898, "42000"}, // 290 dyn_defvaldecl_package_func
{336068904, "42000"}, // 296 dyn_cant_use_zero_inc_ident
{336330753, "00000"}, // 1 gbak_unknown_switch
{336330754, "00000"}, // 2 gbak_page_size_missing
{336330755, "00000"}, // 3 gbak_page_size_toobig

View File

@ -6,7 +6,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM
('2015-01-07 18:01:51', 'GFIX', 3, 134)
('1996-11-07 13:39:40', 'GPRE', 4, 1)
('2016-02-23 00:00:00', 'DSQL', 7, 40)
('2016-05-30 17:56:47', 'DYN', 8, 296)
('2016-12-27 12:30:00', 'DYN', 8, 297)
('1996-11-07 13:39:40', 'INSTALL', 10, 1)
('1996-11-07 13:38:41', 'TEST', 11, 4)
('2015-07-23 14:20:00', 'GBAK', 12, 370)

View File

@ -1992,6 +1992,7 @@ COMMIT WORK;
(NULL, 'CreateAlterRoleNode::execute', 'DdlNodes.epp', NULL, 8, 293, NULL, 'DROP SYSTEM PRIVILEGES should not be used in CREATE ROLE operator', NULL, NULL);
(NULL, 'CreateAlterRoleNode::execute', 'DdlNodes.epp', NULL, 8, 294, NULL, 'Access to SYSTEM PRIVILEGES in ROLES denied to @1', NULL, NULL);
(NULL, 'grant/revoke', 'DdlNode.epp', NULL, 8, 295, NULL, 'Only @1, DB owner @2 or user with privilege USE_GRANTED_BY_CLAUSE can use GRANTED BY clause', NULL, NULL);
('dyn_cant_use_zero_inc_ident', NULL, 'DdlNodes.epp', NULL, 8, 296, NULL, 'INCREMENT BY 0 is an illegal option for identity column @1 of table @2', NULL, NULL);
COMMIT WORK;
-- TEST
(NULL, 'main', 'test.c', NULL, 11, 0, NULL, 'This is a modified text message', NULL, NULL);

View File

@ -958,6 +958,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-901, '42', '000', 8, 288, 'dyn_cant_use_zero_increment', NULL, NULL)
(-901, '42', '000', 8, 289, 'dyn_cant_use_in_foreignkey', NULL, NULL)
(-901, '42', '000', 8, 290, 'dyn_defvaldecl_package_func', NULL, NULL)
(-901, '42', '000', 8, 296, 'dyn_cant_use_zero_inc_ident', NULL, NULL)
-- GBAK
(-901, '00', '000', 12, 1, 'gbak_unknown_switch', NULL, NULL)
(-901, '00', '000', 12, 2, 'gbak_page_size_missing', NULL, NULL)