diff --git a/doc/sql.extensions/README.ddl.txt b/doc/sql.extensions/README.ddl.txt index eae4e98d42..8fca318c3b 100644 --- a/doc/sql.extensions/README.ddl.txt +++ b/doc/sql.extensions/README.ddl.txt @@ -624,3 +624,8 @@ ALTER PACKAGE SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY list is expanded by "OWNER username" clause which allows to set an owner user name for the created database. Only users with administrator rights can use this option. + +28) COLLATE clause can be used as a part of character data type as per SQL standard. +(Dmitry Sibiryakov) + +If is used twice, an error is returned. diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index fd537f4016..b349e8d1f6 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -1119,14 +1119,13 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& //---------------------- -ParameterClause::ParameterClause(MemoryPool& pool, dsql_fld* field, const MetaName& aCollate, +ParameterClause::ParameterClause(MemoryPool& pool, dsql_fld* field, ValueSourceClause* aDefaultClause, ValueExprNode* aParameterExpr) : name(pool, field ? field->fld_name : ""), type(field), defaultClause(aDefaultClause), parameterExpr(aParameterExpr) { - type->collate = aCollate; } string ParameterClause::internalPrint(NodePrinter& printer) const @@ -6454,13 +6453,18 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch computedSource, computedValue); } - field->collate = clause->collate; field->resolve(dsqlScratch); // Generate a domain. storeGlobalField(tdbb, transaction, fieldDefinition.fieldSource, field, computedSource, computedValue); } + else + { + // Resolve possible additional collation for domains. For plain types it is already resolved above. + if (field->collate.hasData()) + DDL_resolve_intl_type(dsqlScratch, field, field->collate); + } if ((relation->rel_flags & REL_external) && (field->dtype == dtype_blob || field->dtype == dtype_array || field->dimensions)) @@ -6473,9 +6477,6 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch Arg::Gds(isc_dsql_type_not_supp_ext_tab) << typeName << name << field->fld_name); } - if (clause->collate.hasData()) - DDL_resolve_intl_type(dsqlScratch, field, clause->collate); - if (clause->identityOptions) { if (clause->identityOptions->increment.value_or(1) == 0) @@ -6519,10 +6520,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch } fieldDefinition.defaultValue = defaultValue; - - if (clause->collate.hasData()) - fieldDefinition.collationId = field->collationId; - + fieldDefinition.collationId = field->collationId; fieldDefinition.store(tdbb, transaction); // Define the field constraints. diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 25bfac0b02..5338d3ca9d 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -171,7 +171,7 @@ public: class ParameterClause : public Printable { public: - ParameterClause(MemoryPool& pool, dsql_fld* field, const MetaName& aCollate, + ParameterClause(MemoryPool& pool, dsql_fld* field, ValueSourceClause* aDefaultClause = NULL, ValueExprNode* aParameterExpr = NULL); public: diff --git a/src/dsql/Parser.h b/src/dsql/Parser.h index 4607f50632..516982d7d0 100644 --- a/src/dsql/Parser.h +++ b/src/dsql/Parser.h @@ -340,6 +340,11 @@ private: return clause.hasData(); } + void setCollate(TypeClause* fld, MetaName* name) + { + if (name) + setClause(fld->collate, "COLLATE", *name); + } void checkTimeDialect(); // start - defined in btyacc_fb.ske diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index 0b6f42eddb..e54f99874e 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -69 shift/reduce conflicts, 22 reduce/reduce conflicts. +71 shift/reduce conflicts, 22 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index aaf8c05b1b..1dd6bddebb 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -1457,7 +1457,7 @@ arg_desc_list($parameters) arg_desc($parameters) : udf_data_type param_mechanism { - $parameters->add(newNode($1, MetaName())); + $parameters->add(newNode($1)); $parameters->back()->udfMechanism = $2; } ; @@ -1480,7 +1480,7 @@ return_value1($function) return_value($function) : udf_data_type return_mechanism { - $function->returnType = newNode($1, MetaName()); + $function->returnType = newNode($1); $function->returnType->udfMechanism = $2; } | PARAMETER pos_short_integer @@ -1748,13 +1748,12 @@ domain_clause { $3->fld_name = *$1; $$ = newNode( - newNode($3, MetaName(), $4)); + newNode($3, $4)); } domain_constraints_opt($5) collate_clause { $$ = $5; - if ($7) - $$->nameType->type->collate = *$7; + setCollate($3, $7); } ; @@ -2356,8 +2355,7 @@ column_def($relationNode) } column_constraint_clause(NOTRIAL($4)) collate_clause { - if ($6) - $4->collate = *$6; + setCollate($2, $6); } | symbol_column_name data_type_or_domain identity_clause { @@ -2370,8 +2368,7 @@ column_def($relationNode) } column_constraint_clause(NOTRIAL($4)) collate_clause { - if ($6) - $4->collate = *$6; + setCollate($2, $6); } | symbol_column_name non_array_type def_computed { @@ -2807,7 +2804,10 @@ input_proc_parameters($parameters) %type input_proc_parameter() input_proc_parameter($parameters) : column_domain_or_non_array_type collate_clause default_par_opt - { $parameters->add(newNode($1, optName($2), $3)); } + { + setCollate($1, $2); + $parameters->add(newNode($1, $3)); + } ; %type output_proc_parameters() @@ -2819,7 +2819,10 @@ output_proc_parameters($parameters) %type output_proc_parameter() output_proc_parameter($parameters) : column_domain_or_non_array_type collate_clause - { $parameters->add(newNode($1, optName($2))); } + { + setCollate($1, $2); + $parameters->add(newNode($1)); + } ; %type column_domain_or_non_array_type @@ -2891,7 +2894,8 @@ function_clause_start RETURNS domain_or_non_array_type collate_clause deterministic_clause_opt { $$ = $2; - $$->returnType = newNode($5, optName($6)); + $$->returnType = newNode($5); + setCollate($5, $6); $$->deterministic = $7; } ; @@ -3230,7 +3234,8 @@ local_declaration_subfunc_start RETURNS domain_or_non_array_type collate_clause deterministic_clause_opt { $$ = $4; - $$->dsqlBlock->returns.add(newNode($7, optName($8))); + setCollate($7, $8); + $$->dsqlBlock->returns.add(newNode($7)); $$->dsqlDeterministic = $9; } ; @@ -3245,8 +3250,10 @@ local_declaration_item var_declaration_item : column_domain_or_non_array_type collate_clause var_declaration_initializer { + // Set collate before node allocation to prevent memory leak on throw + setCollate($1, $2); DeclareVariableNode* node = newNode(); - node->dsqlDef = newNode($1, optName($2), $3); + node->dsqlDef = newNode($1, $3); $$ = node; } ; @@ -3926,7 +3933,10 @@ block_parameters($parameters) %type block_parameter() block_parameter($parameters) : column_domain_or_non_array_type collate_clause '=' parameter - { $parameters->add(newNode($1, optName($2), (ValueSourceClause*) NULL, $4)); } + { + setCollate($1, $2); + $parameters->add(newNode($1, (ValueSourceClause*) NULL, $4)); + } ; // CREATE VIEW @@ -4909,7 +4919,7 @@ array_range %type simple_type simple_type : non_charset_simple_type - | character_type charset_clause + | character_type charset_clause collate_clause { $$ = $1; if ($2) @@ -4917,12 +4927,19 @@ simple_type $$->charSet = *$2; $$->flags |= FLD_has_chset; } + if ($3) + $$->collate = *$3; } ; %type non_charset_simple_type non_charset_simple_type - : national_character_type + : national_character_type collate_clause + { + $$ = $1; + if ($2) + $$->collate = *$2; + } | binary_character_type | numeric_type | float_type