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

Refactor CREATE/ALTER/CREATE OR ALTER/RECREATE VIEW and cleanup related to previously refactors

This commit is contained in:
asfernandes 2010-08-02 02:22:26 +00:00
parent e664de5f00
commit ad57aa29a1
29 changed files with 1500 additions and 3570 deletions

View File

@ -2076,6 +2076,16 @@ C --
PARAMETER (GDS__dsql_drop_pack_body_failed = 336397296)
INTEGER*4 GDS__dsql_recreate_pack_body_failed
PARAMETER (GDS__dsql_recreate_pack_body_failed = 336397297)
INTEGER*4 GDS__dsql_create_view_failed
PARAMETER (GDS__dsql_create_view_failed = 336397298)
INTEGER*4 GDS__dsql_alter_view_failed
PARAMETER (GDS__dsql_alter_view_failed = 336397299)
INTEGER*4 GDS__dsql_create_alter_view_failed
PARAMETER (GDS__dsql_create_alter_view_failed = 336397300)
INTEGER*4 GDS__dsql_recreate_view_failed
PARAMETER (GDS__dsql_recreate_view_failed = 336397301)
INTEGER*4 GDS__dsql_drop_view_failed
PARAMETER (GDS__dsql_drop_view_failed = 336397302)
INTEGER*4 GDS__gsec_cant_open_db
PARAMETER (GDS__gsec_cant_open_db = 336723983)
INTEGER*4 GDS__gsec_switches_error

View File

@ -1045,6 +1045,11 @@ const
gds_dsql_create_pack_body_failed = 336397295;
gds_dsql_drop_pack_body_failed = 336397296;
gds_dsql_recreate_pack_body_failed = 336397297;
gds_dsql_create_view_failed = 336397298;
gds_dsql_alter_view_failed = 336397299;
gds_dsql_create_alter_view_failed = 336397300;
gds_dsql_recreate_view_failed = 336397301;
gds_dsql_drop_view_failed = 336397302;
gds_gsec_cant_open_db = 336723983;
gds_gsec_switches_error = 336723984;
gds_gsec_no_op_spec = 336723985;

File diff suppressed because it is too large Load Diff

View File

@ -68,6 +68,7 @@ public:
public:
void resolve(DsqlCompilerScratch* dsqlScratch, bool modifying = false);
void setup(DsqlCompilerScratch* dsqlScratch);
public:
virtual void print(Firebird::string& text) const;
@ -961,6 +962,36 @@ public:
class RelationNode : public DdlNode
{
public:
class FieldDefinition
{
public:
FieldDefinition(MemoryPool& p)
: name(p),
relationName(p),
fieldSource(p),
identitySequence(p),
defaultSource(p),
baseField(p)
{
}
void modify(thread_db* tdbb, jrd_tra* transaction);
void store(thread_db* tdbb, jrd_tra* transaction);
public:
Firebird::MetaName name;
Firebird::MetaName relationName;
Firebird::MetaName fieldSource;
Firebird::MetaName identitySequence;
Nullable<USHORT> collationId;
Nullable<bool> notNullFlag;
Nullable<USHORT> position;
Firebird::string defaultSource;
Firebird::ByteChunk defaultValue;
Nullable<USHORT> viewContext;
Firebird::MetaName baseField;
};
struct Constraint : public PermanentStorage
{
enum Type { TYPE_CHECK, TYPE_NOT_NULL, TYPE_PK, TYPE_UNIQUE, TYPE_FK };
@ -1039,6 +1070,7 @@ public:
const Firebird::MetaName& relationName, const Firebird::MetaName& fieldName);
protected:
void storePrivileges(thread_db* tdbb, jrd_tra* transaction);
void defineField(thread_db* tdbb, jrd_tra* transaction, const dsql_nod* element,
SSHORT position, const dsql_nod* pkcols);
void defineComputed(thread_db* tdbb, dsql_fld* field, dsql_nod* node,
@ -1159,10 +1191,10 @@ class RecreateRelationNode : public DdlNode
{
public:
explicit RecreateRelationNode(MemoryPool& p, const Firebird::string& sqlText,
CreateRelationNode* aCreateNode)
RelationNode* aCreateNode, bool view)
: DdlNode(p, sqlText),
createNode(aCreateNode),
dropNode(p, sqlText, createNode->name, false)
dropNode(p, sqlText, createNode->name, view)
{
dropNode.silent = true;
}
@ -1174,17 +1206,67 @@ public:
protected:
virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector)
{
statusVector << Firebird::Arg::Gds(isc_dsql_recreate_table_failed) << createNode->name;
ISC_STATUS code = dropNode.view ?
isc_dsql_recreate_table_failed : isc_dsql_recreate_table_failed;
statusVector << Firebird::Arg::Gds(code) << createNode->name;
}
virtual DdlNode* internalDsqlPass();
private:
CreateRelationNode* createNode;
RelationNode* createNode;
DropRelationNode dropNode;
};
class CreateAlterViewNode : public RelationNode
{
public:
explicit CreateAlterViewNode(MemoryPool& p, const Firebird::string& sqlText,
dsql_nod* aDsqlNode, dsql_nod* aViewFields, dsql_nod* aSelectExpr)
: RelationNode(p, sqlText, aDsqlNode),
create(true),
alter(false),
viewFields(aViewFields),
selectExpr(aSelectExpr),
source(p),
withCheckOption(false)
{
}
public:
virtual void print(Firebird::string& text, Firebird::Array<dsql_nod*>& nodes) const;
virtual void execute(thread_db* tdbb, jrd_tra* transaction);
protected:
virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector)
{
statusVector <<
Firebird::Arg::Gds(createAlterCode(create, alter,
isc_dsql_create_view_failed, isc_dsql_alter_view_failed,
isc_dsql_create_alter_view_failed)) <<
name;
}
private:
void createCheckTriggers(thread_db* tdbb, jrd_tra* transaction, dsql_nod* items);
void createCheckTrigger(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
dsql_nod* rse, dsql_nod* items, dsql_nod* actions, TriggerType triggerType);
void defineUpdateAction(DsqlCompilerScratch* dsqlScratch, dsql_nod** baseAndNode,
dsql_nod** baseRelation, dsql_nod* items);
static dsql_nod* replaceFieldNames(dsql_nod* input, dsql_nod* searchFields,
dsql_nod* replaceFields, bool nullThem, const char* contextName);
public:
bool create;
bool alter;
dsql_nod* viewFields;
dsql_nod* selectExpr;
Firebird::string source;
bool withCheckOption;
};
class CreateIndexNode
{
public:

View File

@ -113,7 +113,6 @@ using namespace Firebird;
static void assign_field_length(dsql_fld*, USHORT);
static void create_view_triggers(DsqlCompilerScratch*, dsql_nod*, dsql_nod*);
static void define_computed(DsqlCompilerScratch*, dsql_nod*, dsql_fld*, dsql_nod*);
static void define_database(DsqlCompilerScratch*);
static void define_filter(DsqlCompilerScratch*);
@ -122,10 +121,6 @@ static void define_role(DsqlCompilerScratch*);
static void define_index(DsqlCompilerScratch*);
static void define_shadow(DsqlCompilerScratch*);
static void define_udf(DsqlCompilerScratch*);
static void define_update_action(DsqlCompilerScratch*, dsql_nod**, dsql_nod**, dsql_nod*);
static void define_view(DsqlCompilerScratch*, NOD_TYPE);
static void define_view_trigger(DsqlCompilerScratch*, dsql_nod*, dsql_nod*, dsql_nod*);
static void delete_relation_view(DsqlCompilerScratch*, dsql_nod*, bool);
static void generate_dyn(DsqlCompilerScratch*, dsql_nod*);
static void grant_revoke(DsqlCompilerScratch*);
static void modify_database(DsqlCompilerScratch*);
@ -139,11 +134,8 @@ static char modify_privileges(DsqlCompilerScratch*, NOD_TYPE, SSHORT, const dsql
static void modify_udf(DsqlCompilerScratch*);
static void modify_map(DsqlCompilerScratch*);
static void process_role_nm_list(DsqlCompilerScratch*, SSHORT, const dsql_nod*, const dsql_nod*, NOD_TYPE, const dsql_nod*);
static void put_descriptor(DsqlCompilerScratch*, const dsc*);
static void put_field(DsqlCompilerScratch*, dsql_fld*, bool);
static dsql_nod* replace_field_names(dsql_nod*, dsql_nod*, dsql_nod*, bool, const char*);
static void save_field(DsqlCompilerScratch*, const SCHAR*);
static void save_relation(DsqlCompilerScratch*, const dsql_str*);
static void set_statistics(DsqlCompilerScratch*);
static void define_user(DsqlCompilerScratch*, UCHAR);
static void put_grantor(DsqlCompilerScratch* dsqlScratch, const dsql_nod* grantor);
@ -189,14 +181,6 @@ void DDL_execute(dsql_req* request)
switch (type)
{
case nod_mod_view:
case nod_replace_view:
case nod_redef_view:
string = (dsql_str*) statement->getDdlNode()->nod_arg[e_alt_name];
sym_type = SYM_relation;
METD_drop_relation(request->getTransaction(), string->str_data);
break;
case nod_del_udf:
case nod_mod_udf:
// Signal UDF for obsolescence
@ -329,7 +313,7 @@ void DDL_resolve_intl_type2(DsqlCompilerScratch* dsqlScratch,
if (field->fld_type_of_table)
{
dsql_rel* relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch,
field->fld_type_of_table);
field->fld_type_of_table->str_data);
const dsql_fld* fld = NULL;
if (relation)
@ -633,61 +617,6 @@ static void assign_field_length(dsql_fld* field, USHORT bytes_per_char)
}
static void create_view_triggers(DsqlCompilerScratch* dsqlScratch, dsql_nod* element, dsql_nod* items)
{
/**************************************
*
* c r e a t e _ v i e w _ t r i g g e r s
*
**************************************
*
* Function
* Generate triggers to implement the WITH CHECK OPTION
* clause for a VIEW
*
**************************************/
dsql_nod* ddl_node = dsqlScratch->getStatement()->getDdlNode();
if (!element->nod_arg[e_cnstr_table]) {
element->nod_arg[e_cnstr_table] = ddl_node->nod_arg[e_drl_name];
}
// specify that the trigger should abort if the condition is not met
dsql_nod* list_node = MAKE_node(nod_list, 1);
element->nod_arg[e_cnstr_actions] = list_node;
list_node->nod_arg[0] = MAKE_node(nod_gdscode, 1);
dsql_nod** errorcode_node = &list_node->nod_arg[0]->nod_arg[0];
*errorcode_node = (dsql_nod*) MAKE_cstring("check_constraint");
// create the UPDATE trigger
element->nod_arg[e_cnstr_type] = MAKE_const_slong(PRE_MODIFY_TRIGGER);
dsql_nod* base_and_node = 0;
dsql_nod* base_relation = 0;
define_update_action(dsqlScratch, &base_and_node, &base_relation, items);
fb_assert(base_and_node);
fb_assert(base_relation);
dsql_nod* rse = MAKE_node(nod_rse, e_rse_count);
rse->nod_arg[e_rse_boolean] = base_and_node;
dsql_nod* temp = MAKE_node(nod_list, 1);
rse->nod_arg[e_rse_streams] = temp;
temp->nod_arg[0] = base_relation;
define_view_trigger(dsqlScratch, element, rse, items);
// create the INSERT trigger
element->nod_arg[e_cnstr_type] = MAKE_const_slong(PRE_STORE_TRIGGER);
define_view_trigger(dsqlScratch, element, NULL, items);
dsqlScratch->appendUChar(isc_dyn_end); // For triggers definition
}
static void define_computed(DsqlCompilerScratch* dsqlScratch,
dsql_nod* relation_node,
dsql_fld* field,
@ -1240,745 +1169,6 @@ static void define_udf(DsqlCompilerScratch* dsqlScratch)
}
static void define_update_action(DsqlCompilerScratch* dsqlScratch,
dsql_nod** base_and_node, dsql_nod** base_relation, dsql_nod* items)
{
/**************************************
*
* d e f i n e _ u p d a t e _ a c t i o n
*
**************************************
*
* Function
* Define an action statement which, given a view
* definition, will map an update to a record from
* a view of a single relation into the
* base relation.
*
**************************************/
dsql_nod* ddl_node = dsqlScratch->getStatement()->getDdlNode();
// check whether this is an updatable view definition
dsql_nod* select_node = NULL;
dsql_nod* select_expr = NULL;
dsql_nod* from_list = NULL;
if ((ddl_node->nod_type != nod_def_view && ddl_node->nod_type != nod_redef_view &&
ddl_node->nod_type != nod_replace_view && ddl_node->nod_type != nod_mod_view) ||
!(select_node = ddl_node->nod_arg[e_view_select]) ||
!(select_expr = select_node->nod_arg[e_sel_query_spec]) ||
!(from_list = select_expr->nod_arg[e_qry_from]) ||
from_list->nod_count != 1)
{
// The caller seems throwing proper errors for all the above conditions.
// But just in case it doesn't, here we have the final attempt to prevent the bad things.
fb_assert(false);
}
// use the relation referenced in the select statement for rse
dsql_nod* relation_node = MAKE_node(nod_relation_name, (int) e_rln_count);
relation_node->nod_arg[e_rln_name] = from_list->nod_arg[0]->nod_arg[e_rln_name];
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(TEMP_CONTEXT);
*base_relation = relation_node;
// get the list of values and fields to compare to -- if there is
// no list of fields, get all fields in the base relation that
// are not computed
dsql_nod* values_node = ddl_node->nod_arg[e_view_fields];
dsql_nod* fields_node = select_expr->nod_arg[e_qry_list];
if (!fields_node)
{
const dsql_str* rel_name = reinterpret_cast<const dsql_str*>(relation_node->nod_arg[e_rln_name]);
const dsql_rel* relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, rel_name);
DsqlNodStack field_stack;
for (const dsql_fld* field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
field_stack.push(MAKE_field_name(field->fld_name.c_str()));
}
fields_node = MAKE_list(field_stack);
}
if (!values_node)
values_node = fields_node;
// generate the list of assignments to fields in the base relation
dsql_nod** ptr = fields_node->nod_arg;
const dsql_nod* const* const end = ptr + fields_node->nod_count;
dsql_nod** ptr2 = values_node->nod_arg;
const dsql_nod* const* const end2 = ptr2 + values_node->nod_count;
dsql_nod* and_node = MAKE_node(nod_and, (int) 2);
int and_arg = 0;
for (; (ptr < end) && (ptr2 < end2); ptr++, ptr2++)
{
dsql_nod* field_node = *ptr;
if (field_node->nod_type == nod_alias)
field_node = field_node->nod_arg[e_alias_value];
// generate the actual comparisons
if (field_node->nod_type == nod_field_name)
{
field_node->nod_arg[e_fln_context] = (dsql_nod*) MAKE_cstring(TEMP_CONTEXT);
// CVC: This code serves no purpose.
//dsql_nod* value_node = MAKE_node(nod_field_name, (int) e_fln_count);
//value_node->nod_arg[e_fln_name] = (*ptr2)->nod_arg[e_fln_name];
//value_node->nod_arg[e_fln_context] =
// (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
dsql_nod* old_value_node = MAKE_node(nod_field_name, (int) e_fln_count);
old_value_node->nod_arg[e_fln_name] = (*ptr2)->nod_arg[e_fln_name];
old_value_node->nod_arg[e_fln_context] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT);
dsql_nod* eql_node = MAKE_node(nod_eql, (int) 2);
eql_node->nod_arg[0] = old_value_node;
eql_node->nod_arg[1] = field_node;
dsql_nod* anull_node = MAKE_node(nod_missing, 1);
anull_node->nod_arg[0] = old_value_node;
dsql_nod* bnull_node = MAKE_node(nod_missing, 1);
bnull_node->nod_arg[0] = field_node;
dsql_nod* iand_node = MAKE_node(nod_and, (int) 2);
iand_node->nod_arg[0] = anull_node;
iand_node->nod_arg[1] = bnull_node;
dsql_nod* or_node = MAKE_node(nod_or, (int) 2);
or_node->nod_arg[0] = eql_node;
or_node->nod_arg[1] = iand_node;
if (and_arg <= 1)
and_node->nod_arg[and_arg++] = or_node;
else
{
dsql_nod* old_and = and_node;
and_node = MAKE_node(nod_and, (int) 2);
and_node->nod_arg[0] = old_and;
and_node->nod_arg[1] = or_node;
}
}
}
if (and_arg <= 1)
{
and_node->nod_arg[and_arg] =
replace_field_names(select_expr->nod_arg[e_qry_where], items, NULL, false, TEMP_CONTEXT);
}
else
{
dsql_nod* old_and = and_node;
and_node = MAKE_node(nod_and, (int) 2);
and_node->nod_arg[0] = old_and;
and_node->nod_arg[1] =
replace_field_names(select_expr->nod_arg[e_qry_where], items, NULL, false, TEMP_CONTEXT);
}
*base_and_node = and_node;
}
static void define_view(DsqlCompilerScratch* dsqlScratch, NOD_TYPE op)
{
/**************************************
*
* d e f i n e _ v i e w
*
**************************************
*
* Function
* Create the ddl to define a view, using a SELECT
* statement as the source of the view.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data(); // not used
DsqlCompiledStatement* statement = dsqlScratch->getStatement();
dsql_nod* node = statement->getDdlNode();
const dsql_str* view_name = (dsql_str*) node->nod_arg[e_view_name];
const dsql_rel* view_relation = NULL;
switch (op)
{
case nod_replace_view:
if (METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, view_name))
define_view(dsqlScratch, nod_mod_view);
else
define_view(dsqlScratch, nod_def_view);
return;
case nod_def_view:
case nod_redef_view:
dsqlScratch->appendNullString(isc_dyn_def_view, view_name->str_data);
dsqlScratch->appendNumber(isc_dyn_rel_sql_protection, 1);
save_relation(dsqlScratch, view_name);
break;
default: // op == nod_mod_view
dsqlScratch->appendNullString(isc_dyn_mod_view, view_name->str_data);
view_relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, view_name);
if (!view_relation)
{
post_607(Arg::Gds(isc_dsql_view_not_found) << Arg::Str(view_name->str_data));
}
}
// compile the SELECT statement into a record selection expression,
// making sure to bump the context number since view contexts start
// at 1 (except for computed fields) -- note that calling PASS1_rse
// directly rather than PASS1_statement saves the context stack
DDL_reset_context_stack(dsqlScratch);
dsqlScratch->contextNumber++;
dsql_nod* select_expr = node->nod_arg[e_view_select];
select_expr->nod_flags |= NOD_SELECT_VIEW_FIELDS;
dsql_nod* rse = PASS1_rse(dsqlScratch, select_expr, NULL);
// store the blr and source string for the view definition
dsqlScratch->beginBlr(isc_dyn_view_blr);
// ASF: Call GEN_hidden_variables could be a optimization for views to not have
// blr_dcl_variables inside RSE loops, but this is currently not possible because it will
// mix the variables from view fields and view body.
GEN_expr(dsqlScratch, rse);
dsqlScratch->endBlr();
// Store source for view. gdef -e cannot cope with it.
// We need to add something to rdb$views to indicate source type.
// Source will be for documentation purposes.
const dsql_str* source = (dsql_str*) node->nod_arg[e_view_source];
fb_assert(source->str_length <= MAX_USHORT);
dsqlScratch->appendString(isc_dyn_view_source, source->str_data, source->str_length);
// define the view source relations from the statement contexts & union contexts
while (dsqlScratch->derivedContext.hasData())
{
dsqlScratch->context->push(dsqlScratch->derivedContext.pop());
}
while (dsqlScratch->unionContext.hasData())
{
dsqlScratch->context->push(dsqlScratch->unionContext.pop());
}
for (DsqlContextStack::iterator temp(*dsqlScratch->context); temp.hasData(); ++temp)
{
const dsql_ctx* context = temp.object();
const dsql_rel* relation = context->ctx_relation;
const dsql_prc* procedure = context->ctx_procedure;
if (relation || procedure)
{
// ASF: Check disabled as seems to not be reason to prevent
// procedure usage in view. 2007-11-28
/*
if (procedure)
{
// Disallow procedure-based views
ERRD_post(Arg::Gds(isc_wish_list));
}
*/
const MetaName& name = relation ? relation->rel_name : procedure->prc_name.identifier;
dsqlScratch->appendString(isc_dyn_view_relation, name);
dsqlScratch->appendNumber(isc_dyn_view_context, context->ctx_context);
const char* str = context->ctx_alias ? context->ctx_alias : name.c_str();
const USHORT len = context->ctx_alias ? strlen(str) : name.length();
dsqlScratch->appendString(isc_dyn_view_context_name, str, len);
ViewContextType ctxType;
if (relation)
{
if (!(relation->rel_flags & REL_view))
ctxType = VCT_TABLE;
else
ctxType = VCT_VIEW;
}
else //if (procedure)
{
ctxType = VCT_PROCEDURE;
if (procedure->prc_name.package.hasData())
dsqlScratch->appendString(isc_dyn_pkg_name, procedure->prc_name.package);
}
dsqlScratch->appendNumber(isc_dyn_view_context_type, (SSHORT) ctxType);
dsqlScratch->appendUChar(isc_dyn_end);
}
}
// if there are field names defined for the view, match them in order
// with the items from the SELECT. Otherwise use all the fields from
// the rse node that was created from the select expression
const dsql_nod* const* ptr = NULL;
const dsql_nod* const* end = NULL;
const dsql_nod* view_fields = node->nod_arg[e_view_fields];
if (view_fields != NULL)
{
ptr = view_fields->nod_arg;
end = ptr + view_fields->nod_count;
}
const TEXT* field_string;
bool updatable = true;
SSHORT position = 0;
// go through the fields list, defining or modifying the local fields;
// if an expression is specified rather than a field, define
// a global field for the computed value as well
dsql_nod* items = rse->nod_arg[e_rse_items];
dsql_nod** i_ptr = items->nod_arg;
SortedArray<dsql_fld*> modified_fields;
for (const dsql_nod* const* const i_end = i_ptr + items->nod_count;
i_ptr < i_end; i_ptr++, position++)
{
dsql_nod* field_node = *i_ptr;
// determine the proper field name, replacing the default if necessary
const dsql_nod* name_node = field_node;
const dsql_str* alias_name = NULL;
while (name_node->nod_type == nod_alias ||
name_node->nod_type == nod_derived_field ||
name_node->nod_type == nod_map)
{
switch (name_node->nod_type)
{
case nod_alias:
if (!alias_name)
{
alias_name = (dsql_str*) name_node->nod_arg[e_alias_alias];
}
name_node = name_node->nod_arg[e_alias_value];
break;
case nod_derived_field:
if (!alias_name)
{
alias_name = (dsql_str*) name_node->nod_arg[e_derived_field_name];
}
name_node = name_node->nod_arg[e_derived_field_value];
break;
case nod_map:
{
const dsql_map* map = (dsql_map*) name_node->nod_arg[e_map_map];
name_node = map->map_node;
}
break;
default:
break;
}
}
const dsql_fld* name_field = NULL;
if (name_node->nod_type == nod_field)
name_field = (dsql_fld*) name_node->nod_arg[e_fld_field];
if (alias_name)
field_string = alias_name->str_data;
else if (name_field)
field_string = name_field->fld_name.c_str();
else
field_string = NULL;
// check if this is a field or an expression
if (field_node->nod_type == nod_alias)
field_node = field_node->nod_arg[e_alias_value];
const dsql_fld* field = NULL;
const dsql_ctx* context = NULL;
if (field_node->nod_type == nod_field)
{
field = (dsql_fld*) field_node->nod_arg[e_fld_field];
context = (dsql_ctx*) field_node->nod_arg[e_fld_context];
}
else
{
updatable = false;
}
// if this is an expression, check to make sure there is a name specified
if (!ptr && !field_string)
{
// must specify field name for view select expression
post_607(Arg::Gds(isc_specify_field_err));
}
// CVC: Small modification here to catch any mismatch between number of
// explicit field names in a view and number of fields in the select expression,
// see comment below. This closes Firebird Bug #223059.
if (ptr)
{
if (ptr < end)
{
const dsql_str* field_name = (dsql_str*) (*ptr)->nod_arg[1];
field_string = field_name->str_data;
}
ptr++;
}
// if not an expression, point to the proper base relation field,
// else make up an SQL field with generated global field for calculations
dsql_fld* rel_field = NULL;
if (view_relation) // if we're modifying a view
{
for (rel_field = view_relation->rel_fields; rel_field; rel_field = rel_field->fld_next)
{
if (rel_field->fld_name == field_string)
{
if (modified_fields.exist(rel_field))
{
// column @1 appears more than once in ALTER VIEW
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
Arg::Gds(isc_dsql_command_err) <<
Arg::Gds(isc_dsql_col_more_than_once_view) << Arg::Str(field_string));
}
modified_fields.add(rel_field);
break;
}
}
}
// CVC: Not sure if something should be done now that isc_dyn_view_context is used here,
// but if alter view is going to work, maybe we need here the context type and package, too.
if (field)
{
if (rel_field) // modifying a view
{
dsqlScratch->appendNullString(isc_dyn_mod_sql_fld, field_string);
dsqlScratch->appendUChar(isc_dyn_del_computed);
}
else
dsqlScratch->appendNullString(isc_dyn_def_local_fld, field_string);
dsqlScratch->appendString(isc_dyn_fld_base_fld, field->fld_name);
if (field->fld_dtype <= dtype_any_text)
dsqlScratch->appendNumber(isc_dyn_fld_collation, field->fld_collation_id);
dsqlScratch->appendNumber(isc_dyn_view_context, context->ctx_context);
}
else
{
if (rel_field) // modifying a view
{
dsqlScratch->appendNullString(isc_dyn_mod_sql_fld, field_string);
dsqlScratch->appendNullString(isc_dyn_fld_base_fld, "");
}
else
dsqlScratch->appendNullString(isc_dyn_def_sql_fld, field_string);
MAKE_desc(dsqlScratch, &field_node->nod_desc, field_node, NULL);
put_descriptor(dsqlScratch, &field_node->nod_desc);
dsqlScratch->beginBlr(isc_dyn_fld_computed_blr);
GEN_expr(dsqlScratch, field_node);
dsqlScratch->endBlr();
dsqlScratch->appendNumber(isc_dyn_view_context, (SSHORT) 0);
}
if (field_string)
save_field(dsqlScratch, field_string);
dsqlScratch->appendNumber(isc_dyn_fld_position, position);
dsqlScratch->appendUChar(isc_dyn_end);
}
// CVC: This message was not catching the case when
// #fields < items in select list, see comment above.
if (ptr != end)
{
// number of fields does not match select list
post_607(Arg::Gds(isc_num_field_err));
}
if (view_relation) // modifying a view
{
// delete the old fields not present in the new definition
for (dsql_fld* rel_field = view_relation->rel_fields; rel_field; rel_field = rel_field->fld_next)
{
if (!modified_fields.exist(rel_field))
{
dsqlScratch->appendString(isc_dyn_delete_local_fld, rel_field->fld_name);
dsqlScratch->appendUChar(isc_dyn_end);
}
}
}
// setup to define triggers for WITH CHECK OPTION
dsql_nod* check = node->nod_arg[e_view_check];
if (check)
{
if (!updatable)
{
// Only simple column names permitted for VIEW WITH CHECK OPTION
post_607(Arg::Gds(isc_col_name_err));
}
select_expr = select_expr->nod_arg[e_sel_query_spec];
if (select_expr->nod_type == nod_list)
{
// Only one table allowed for VIEW WITH CHECK OPTION
post_607(Arg::Gds(isc_table_view_err));
}
if (select_expr->nod_arg[e_qry_from]->nod_count != 1)
{
// Only one table allowed for VIEW WITH CHECK OPTION
post_607(Arg::Gds(isc_table_view_err));
}
if (!select_expr->nod_arg[e_qry_where])
{
// No where clause for VIEW WITH CHECK OPTION
post_607(Arg::Gds(isc_where_err));
}
if (select_expr->nod_arg[e_qry_distinct] || select_expr->nod_arg[e_qry_group] ||
select_expr->nod_arg[e_qry_having])
{
// DISTINCT, GROUP or HAVING not permitted for VIEW WITH CHECK OPTION
post_607(Arg::Gds(isc_distinct_err));
}
dsql_nod* relation_node = MAKE_node(nod_relation_name, e_rln_count);
// Warning: implicit const_cast
relation_node->nod_arg[e_rln_name] = (dsql_nod*) view_name;
check->nod_arg[e_cnstr_table] = relation_node;
check->nod_arg[e_cnstr_source] = (dsql_nod*) source;
// the condition for the trigger is the converse of the selection
// criteria for the view, suitably fixed up so that the fields in
// the view are referenced
check->nod_arg[e_cnstr_condition] = select_expr->nod_arg[e_qry_where];
// Define the triggers
create_view_triggers(dsqlScratch, check, rse->nod_arg[e_rse_items]);
}
dsqlScratch->appendUChar(isc_dyn_end);
DDL_reset_context_stack(dsqlScratch);
}
static void define_view_trigger(DsqlCompilerScratch* dsqlScratch, dsql_nod* node, dsql_nod* rse,
dsql_nod* items)
{
/**************************************
*
* d e f i n e _ v i e w _ t r i g g e r
*
**************************************
*
* Function
* Create the ddl to define a trigger for a VIEW WITH CHECK OPTION.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
DsqlCompiledStatement* statement = dsqlScratch->getStatement();
dsql_nod* const saved_ddl_node = statement->getDdlNode();
dsql_nod* select_expr = saved_ddl_node->nod_arg[e_view_select];
select_expr = select_expr->nod_arg[e_sel_query_spec];
dsql_nod* view_fields = saved_ddl_node->nod_arg[e_view_fields];
// make the "define trigger" node the current statement ddl node so
// that generating of BLR will be appropriate for trigger
statement->setDdlNode(node);
dsql_nod* relation_node = NULL;
if (node->nod_type == nod_def_constraint)
{
dsqlScratch->appendString(isc_dyn_def_trigger, "", 0);
relation_node = node->nod_arg[e_cnstr_table];
const dsql_str* relation_name = (dsql_str*) relation_node->nod_arg[e_rln_name];
fb_assert(relation_name->str_length <= MAX_USHORT);
dsqlScratch->appendString(isc_dyn_rel_name, relation_name->str_data, relation_name->str_length);
}
else
{
return;
}
dsqlScratch->appendNumber(isc_dyn_trg_sequence, 0);
const dsql_nod* constant = node->nod_arg[e_cnstr_type];
USHORT trig_type;
if (constant)
{
trig_type = (USHORT) constant->getSlong();
dsqlScratch->appendNumber(isc_dyn_trg_type, trig_type);
}
else
{
// If we don't have a trigger type assigned, then this is just a template
// definition for use with domains. The real triggers are defined when
// the domain is used.
trig_type = 0;
}
dsqlScratch->appendUChar(isc_dyn_sql_object);
// generate the trigger blr
if (node->nod_arg[e_cnstr_condition] && node->nod_arg[e_cnstr_actions])
{
dsqlScratch->beginBlr(isc_dyn_trg_blr);
dsqlScratch->appendUChar(blr_begin);
// create the "OLD" and "NEW" contexts for the trigger --
// the new one could be a dummy place holder to avoid resolving
// fields to that context but prevent relations referenced in
// the trigger actions from referencing the predefined "1" context
dsql_ctx* sav_context = 0;
dsql_ctx* context = 0;
if (dsqlScratch->contextNumber)
{
// If an alias is specified for the single base table involved,
// save and then add the context
context = dsqlScratch->context->object();
if (context->ctx_alias)
{
MemoryPool& pool = *tdbb->getDefaultPool();
sav_context = FB_NEW(pool) dsql_ctx(pool);
*sav_context = *context;
}
}
DDL_reset_context_stack(dsqlScratch);
dsql_nod* temp_alias = relation_node->nod_arg[e_rln_alias];
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT);
dsql_ctx* oldContext = PASS1_make_context(dsqlScratch, relation_node);
oldContext->ctx_flags |= CTX_system;
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
dsql_ctx* newContext = PASS1_make_context(dsqlScratch, relation_node);
newContext->ctx_flags |= CTX_system;
relation_node->nod_arg[e_rln_alias] = temp_alias;
if (sav_context)
{
sav_context->ctx_context = dsqlScratch->contextNumber++;
context->ctx_scope_level = dsqlScratch->scopeLevel;
dsqlScratch->context->push(sav_context);
}
// generate the condition for firing the trigger
dsql_nod* condition;
if (trig_type == PRE_MODIFY_TRIGGER)
{
dsqlScratch->appendUChar(blr_for);
dsql_nod* temp = rse->nod_arg[e_rse_streams];
temp->nod_arg[0] = PASS1_node(dsqlScratch, temp->nod_arg[0]);
temp = rse->nod_arg[e_rse_boolean];
rse->nod_arg[e_rse_boolean] = PASS1_node(dsqlScratch, temp);
GEN_expr(dsqlScratch, rse);
condition = replace_field_names(select_expr->nod_arg[e_qry_where], items,
view_fields, false, NEW_CONTEXT);
}
else if (trig_type == PRE_STORE_TRIGGER)
{
condition = replace_field_names(select_expr->nod_arg[e_qry_where], items,
view_fields, true, NEW_CONTEXT);
}
else {
fb_assert(false);
}
dsqlScratch->appendUChar(blr_if);
GEN_expr(dsqlScratch, PASS1_node(dsqlScratch, condition));
dsqlScratch->appendUChar(blr_begin);
dsqlScratch->appendUChar(blr_end);
// generate the action statements for the trigger
dsql_nod* actions = node->nod_arg[e_cnstr_actions];
dsql_nod** ptr = actions->nod_arg;
for (const dsql_nod* const* const end = ptr + actions->nod_count; ptr < end; ptr++)
{
GEN_statement(dsqlScratch, PASS1_statement(dsqlScratch, *ptr));
}
dsqlScratch->appendUChar(blr_end); // of begin
dsqlScratch->endBlr();
}
dsqlScratch->appendNumber(isc_dyn_system_flag, fb_sysflag_view_check);
dsqlScratch->appendUChar(isc_dyn_end);
// the statement type may have been set incorrectly when parsing
// the trigger actions, so reset it to reflect the fact that this
// is a data definition statement; also reset the ddl node
statement->setType(DsqlCompiledStatement::TYPE_DDL);
statement->setDdlNode(saved_ddl_node);
DDL_reset_context_stack(dsqlScratch);
}
static void delete_relation_view (DsqlCompilerScratch* dsqlScratch, dsql_nod* node, bool silent_deletion)
{
/**************************************
*
* d e l e t e _ r e l a t i o n _ v i e w
*
**************************************
*
* Function
* Check that DROP VIEW is dropping a view.
* Do nothing and don't throw error if the view doesn't exist
* and silent_deletion is true.
* CVC: Created this function to not clutter generate_dyn().
*
**************************************/
const dsql_str* string = (dsql_str*) node->nod_arg[e_alt_name];
fb_assert (string);
const dsql_rel* relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, string);
// node->nod_type == nod_del_view, nod_redef_view
if (!relation && !silent_deletion || relation && !(relation->rel_flags & REL_view))
post_607(Arg::Gds(isc_dsql_view_not_found) << Arg::Str(string->str_data));
if (relation)
{
dsqlScratch->appendNullString(isc_dyn_delete_rel, string->str_data);
dsqlScratch->appendUChar(isc_dyn_end);
}
}
static void generate_dyn(DsqlCompilerScratch* dsqlScratch, dsql_nod* node)
{
/**************************************
@ -2000,19 +1190,6 @@ static void generate_dyn(DsqlCompilerScratch* dsqlScratch, dsql_nod* node)
define_index(dsqlScratch);
break;
case nod_def_view:
case nod_mod_view:
case nod_replace_view:
define_view(dsqlScratch, node->nod_type);
break;
case nod_redef_view:
dsqlScratch->appendUChar(isc_dyn_begin);
delete_relation_view(dsqlScratch, node, true); // silent.
define_view(dsqlScratch, node->nod_type);
dsqlScratch->appendUChar(isc_dyn_end);
break;
case nod_del_index:
string = (dsql_str*) node->nod_arg[0];
dsqlScratch->appendNullString(isc_dyn_delete_idx, string->str_data);
@ -2716,49 +1893,6 @@ static void put_grantor(DsqlCompilerScratch* dsqlScratch, const dsql_nod* granto
}
static void put_descriptor(DsqlCompilerScratch* dsqlScratch, const dsc* desc)
{
/**************************************
*
* p u t _ d e s c r i p t o r
*
**************************************
*
* Function
* Write out field description in ddl, given the
* input descriptor.
*
**************************************/
dsqlScratch->appendNumber(isc_dyn_fld_type, blr_dtypes[desc->dsc_dtype]);
if (desc->dsc_dtype == dtype_varying) {
dsqlScratch->appendNumber(isc_dyn_fld_length, (SSHORT) (desc->dsc_length - sizeof(USHORT)));
}
else {
dsqlScratch->appendNumber(isc_dyn_fld_length, desc->dsc_length);
}
if (desc->dsc_dtype <= dtype_any_text)
{
dsqlScratch->appendNumber(isc_dyn_fld_character_set, DSC_GET_CHARSET(desc));
dsqlScratch->appendNumber(isc_dyn_fld_collation, DSC_GET_COLLATE(desc));
}
else if (desc->dsc_dtype == dtype_blob)
{
dsqlScratch->appendNumber(isc_dyn_fld_sub_type, desc->dsc_sub_type);
if (desc->dsc_sub_type == isc_blob_text)
{
dsqlScratch->appendNumber(isc_dyn_fld_character_set, desc->dsc_scale);
dsqlScratch->appendNumber(isc_dyn_fld_collation, desc->dsc_flags >> 8); // BLOB collation
}
}
else
{
dsqlScratch->appendNumber(isc_dyn_fld_sub_type, desc->dsc_sub_type);
dsqlScratch->appendNumber(isc_dyn_fld_scale, desc->dsc_scale);
}
}
static void put_field( DsqlCompilerScratch* dsqlScratch, dsql_fld* field, bool udf_flag)
{
/**************************************
@ -2958,72 +2092,6 @@ void DDL_reset_context_stack(DsqlCompilerScratch* dsqlScratch)
}
static void save_field(DsqlCompilerScratch* dsqlScratch, const TEXT* field_name)
{
/**************************************
*
* s a v e _ f i e l d
*
**************************************
*
* Function
* Save the name of a field in the relation or view currently
* being defined. This is done to support definition
* of triggers which will depend on the metadata created
* in this statement.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
dsql_rel* relation = dsqlScratch->relation;
if (!relation) {
return;
}
MemoryPool& p = relation->rel_flags & REL_new_relation ?
*tdbb->getDefaultPool() : dsqlScratch->getAttachment()->dbb_pool;
dsql_fld* field = FB_NEW(p) dsql_fld(p);
field->fld_name = field_name;
field->fld_next = relation->rel_fields;
relation->rel_fields = field;
}
static void save_relation(DsqlCompilerScratch* dsqlScratch, const dsql_str* relation_name)
{
/**************************************
*
* s a v e _ r e l a t i o n
*
**************************************
*
* Function
* Save the name of the relation or view currently
* being defined. This is done to support definition
* of triggers which will depend on the metadata created
* in this statement.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
DsqlCompiledStatement* statement = dsqlScratch->getStatement();
if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_METADATA_SAVED)
return;
dsqlScratch->flags |= DsqlCompilerScratch::FLAG_METADATA_SAVED;
const dsql_nod* ddl_node = statement->getDdlNode();
dsql_rel* relation;
MemoryPool& pool = *tdbb->getDefaultPool();
relation = FB_NEW(pool) dsql_rel(pool);
relation->rel_name = relation_name->str_data;
dsqlScratch->relation = relation;
}
static void set_statistics(DsqlCompilerScratch* dsqlScratch)
{
/**************************************

View File

@ -207,7 +207,32 @@ class dsql_fld : public pool_alloc<dsql_type_fld>
{
public:
explicit dsql_fld(MemoryPool& p)
: fld_type_of_name(p),
: fld_next(NULL),
fld_relation(NULL),
fld_procedure(NULL),
fld_ranges(NULL),
fld_character_set(NULL),
fld_sub_type_name(NULL),
fld_flags(0),
fld_id(0),
fld_dtype(0),
fld_length(0),
fld_element_dtype(0),
fld_element_length(0),
fld_scale(0),
fld_sub_type(0),
fld_precision(0),
fld_character_length(0),
fld_seg_length(0),
fld_dimensions(0),
fld_character_set_id(0),
fld_collation_id(0),
fld_ttype(0),
fld_type_of_name(p),
fld_type_of_table(NULL),
fld_explicit_collation(false),
fld_not_nullable(false),
fld_full_domain(false),
fld_name(p),
fld_source(p)
{
@ -215,7 +240,7 @@ public:
dsql_fld* fld_next; // Next field in relation
dsql_rel* fld_relation; // Parent relation
class dsql_prc* fld_procedure; // Parent procedure
dsql_prc* fld_procedure; // Parent procedure
dsql_nod* fld_ranges; // ranges for multi dimension array
dsql_nod* fld_character_set; // null means not specified
dsql_nod* fld_sub_type_name; // Subtype name for later resolution
@ -610,6 +635,7 @@ public:
recursiveCtx(0),
recursiveCtxId(0),
processingWindow(false),
checkConstraintTrigger(false),
ctes(p),
cteAliases(p),
currCteAlias(NULL),
@ -748,6 +774,7 @@ public:
class dsql_ctx* recursiveCtx; // context of recursive CTE
USHORT recursiveCtxId; // id of recursive union stream context
bool processingWindow; // processing window functions
bool checkConstraintTrigger; // compiling a check constraint trigger
dsc domainValue; // VALUE in the context of domain's check constraint
private:

View File

@ -1312,7 +1312,8 @@ dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra
}
dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch, const dsql_str* name)
dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScratch,
const MetaName& name)
{
/**************************************
*
@ -1330,21 +1331,18 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
validateTransaction(transaction);
dsql_dbb* dbb = transaction->getDsqlAttachment();
MetaName metaName(name->str_data, name->str_length);
// See if the relation is the one currently being defined in this statement
dsql_rel* temp = dsqlScratch->relation;
if (temp != NULL && temp->rel_name == name->str_data)
{
if (temp != NULL && temp->rel_name == name)
return temp;
}
// Start by seeing if symbol is already defined
if (dbb->dbb_relations.get(metaName, temp) && !(temp->rel_flags & REL_dropped))
if (dbb->dbb_relations.get(name, temp) && !(temp->rel_flags & REL_dropped))
{
if (MET_dsql_cache_use(tdbb, SYM_relation, metaName))
if (MET_dsql_cache_use(tdbb, SYM_relation, name))
temp->rel_flags |= REL_dropped;
else
return temp;
@ -1361,7 +1359,7 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
FOR(REQUEST_HANDLE handle1 TRANSACTION_HANDLE transaction)
REL IN RDB$RELATIONS
CROSS RFR IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME
WITH REL.RDB$RELATION_NAME EQ name->str_data
WITH REL.RDB$RELATION_NAME EQ name.c_str()
AND (REL.RDB$RELATION_ID MISSING OR RFR.RDB$FIELD_ID MISSING)
{
permanent = false;
@ -1377,7 +1375,7 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
AutoCacheRequest handle2(tdbb, irq_relation, IRQ_REQUESTS);
FOR(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction)
X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ name->str_data
X IN RDB$RELATIONS WITH X.RDB$RELATION_NAME EQ name.c_str()
{
fb_utils::exact_name(X.RDB$OWNER_NAME);
@ -1395,7 +1393,7 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
if (relation)
{
relation->rel_name = name->str_data;
relation->rel_name = name;
relation->rel_owner = X.RDB$OWNER_NAME;
if (!(relation->rel_dbkey_length = X.RDB$DBKEY_LENGTH))
relation->rel_dbkey_length = 8;
@ -1421,7 +1419,7 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
FLX IN RDB$FIELDS CROSS
RFR IN RDB$RELATION_FIELDS
WITH FLX.RDB$FIELD_NAME EQ RFR.RDB$FIELD_SOURCE
AND RFR.RDB$RELATION_NAME EQ name->str_data
AND RFR.RDB$RELATION_NAME EQ name.c_str()
SORTED BY RFR.RDB$FIELD_POSITION
{
// allocate the field block
@ -1492,7 +1490,7 @@ dsql_rel* METD_get_relation(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
}
END_FOR
if (dbb->dbb_relations.get(metaName, temp) && !(temp->rel_flags & REL_dropped))
if (dbb->dbb_relations.get(name, temp) && !(temp->rel_flags & REL_dropped))
{
free_relation(relation);
return temp;
@ -1594,9 +1592,7 @@ dsql_rel* METD_get_view_base(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra
fb_utils::exact_name(X.RDB$CONTEXT_NAME);
fb_utils::exact_name(X.RDB$RELATION_NAME);
dsql_str* relation_name = MAKE_string(X.RDB$RELATION_NAME, strlen(X.RDB$RELATION_NAME));
relation = METD_get_relation(transaction, dsqlScratch, relation_name);
delete relation_name;
relation = METD_get_relation(transaction, dsqlScratch, X.RDB$RELATION_NAME);
Array<MetaName> ambiguities;
MetaNamePairMap currentAux;
@ -1706,9 +1702,7 @@ dsql_rel* METD_get_view_relation(jrd_tra* transaction, DsqlCompilerScratch* dsql
if (!strcmp(X.RDB$RELATION_NAME, relation_or_alias) ||
!strcmp(X.RDB$CONTEXT_NAME, relation_or_alias))
{
dsql_str* relation_name = MAKE_string(X.RDB$RELATION_NAME, strlen(X.RDB$RELATION_NAME));
relation = METD_get_relation(transaction, dsqlScratch, relation_name);
delete relation_name;
relation = METD_get_relation(transaction, dsqlScratch, X.RDB$RELATION_NAME);
return relation;
}

View File

@ -66,7 +66,7 @@ Jrd::dsql_udf* METD_get_function(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*,
Jrd::dsql_nod* METD_get_primary_key(Jrd::jrd_tra*, const Jrd::dsql_str*);
Jrd::dsql_prc* METD_get_procedure(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::dsql_str*,
const Jrd::dsql_str*);
Jrd::dsql_rel* METD_get_relation(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Jrd::dsql_str*);
Jrd::dsql_rel* METD_get_relation(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const Firebird::MetaName&);
bool METD_get_type(Jrd::jrd_tra*, const Jrd::dsql_str*, const char*, SSHORT*);
Jrd::dsql_rel* METD_get_view_base(Jrd::jrd_tra*, Jrd::DsqlCompilerScratch*, const char* view_name,
Jrd::MetaNamePairMap& fields);

View File

@ -68,7 +68,6 @@ enum nod_t
nod_del_field,
nod_def_index,
nod_del_index,
nod_def_view,
nod_def_constraint,
nod_del_generator,
nod_def_filter,
@ -232,9 +231,6 @@ enum nod_t
nod_searched_case, // searched CASE function
nod_simple_case, // simple CASE function
nod_coalesce, // COALESCE function
nod_mod_view, // ALTER VIEW
nod_replace_view, // CREATE OR ALTER VIEW
nod_redef_view, // allows silent creation/overwriting of a view
nod_for_update, // FOR UPDATE clause
nod_label, // label support
nod_exec_into, // EXECUTE STATEMENT INTO
@ -588,17 +584,6 @@ enum node_args {
e_dfl_identity,
e_dfl_count,
e_view_name = 0, // nod_def_view
e_view_fields,
e_view_select,
e_view_check,
e_view_source,
e_view_count,
e_alt_name = 0, // nod_mod_relation
e_alt_ops,
e_alt_count,
e_grant_privs = 0, // nod_grant
e_grant_table,
e_grant_users,

View File

@ -638,6 +638,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
Jrd::CreateAlterPackageNode::Item packageItem;
Jrd::CreatePackageBodyNode* createPackageBodyNode;
Jrd::CreateRelationNode* createRelationNode;
Jrd::CreateAlterViewNode* createAlterViewNode;
Jrd::ExecBlockNode* execBlockNode;
Jrd::AggNode* aggNode;
Jrd::SysFuncCallNode* sysFuncCallNode;
@ -662,9 +663,10 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type <legacyNode> case_abbreviation case_expression case_operand case_result case_specification
%type <legacyNode> cast_specification char_length_expression character_keyword character_type
%type <legacyNode> charset_clause check_constraint check_opt close_cursor col_opt collate_clause
%type <legacyNode> charset_clause check_constraint close_cursor col_opt collate_clause
%type <legacyNode> column_constraint column_constraint_clause
%type <legacyNode> column_constraint_def column_constraint_list column_def
%type <boolVal> check_opt
%type <legacyNode> column_list column_name column_parens column_parens_opt column_select
%type <legacyNode> column_singleton commit comparison_predicate complex_proc_statement
@ -805,7 +807,8 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%type <int32Val> unsigned_short_integer
%type <legacyNode> valid_symbol_name value value_list value_list_opt var_decl_opt var_declaration_item
%type <legacyNode> variable variable_list varying_keyword version_mode view_clause
%type <legacyNode> variable variable_list varying_keyword version_mode
%type <createAlterViewNode> view_clause
%type <legacyNode> when_operand where_clause while window_partition_opt
%type <legacyNode> with_clause with_item with_list
@ -1224,7 +1227,7 @@ create_clause : EXCEPTION exception_clause
| TRIGGER trigger_clause
{ $$ = makeClassNode($2); }
| VIEW view_clause
{ $$ = $2; }
{ $$ = makeClassNode($2); }
| GENERATOR generator_clause
{ $$ = makeClassNode($2); }
| SEQUENCE generator_clause
@ -1679,7 +1682,10 @@ table_clause
rtable_clause
: table_clause
{ $$ = makeClassNode(FB_NEW(getPool()) RecreateRelationNode(getPool(), compilingText, $1)); }
{
$$ = makeClassNode(FB_NEW(getPool()) RecreateRelationNode(
getPool(), compilingText, $1, false));
}
;
gtt_table_clause
@ -1697,7 +1703,10 @@ gtt_table_clause
gtt_recreate_clause
: gtt_table_clause
{ $$ = makeClassNode(FB_NEW(getPool()) RecreateRelationNode(getPool(), compilingText, $1)); }
{
$$ = makeClassNode(FB_NEW(getPool()) RecreateRelationNode(
getPool(), compilingText, $1, false));
}
;
gtt_scope
@ -2737,26 +2746,41 @@ block_parameter($parameters)
// CREATE VIEW
view_clause : symbol_view_name column_parens_opt AS begin_string select_expr
check_opt end_trigger
{ $$ = make_node (nod_def_view, (int) e_view_count, $1, $2, $5, $6, $7); }
;
view_clause
: simple_table_name column_parens_opt AS begin_string select_expr check_opt end_trigger
{
CreateAlterViewNode* node = FB_NEW(getPool()) CreateAlterViewNode(getPool(),
compilingText, $1, $2, $5);
node->source = toString($7);
node->withCheckOption = $6;
$$ = node;
}
;
rview_clause
: view_clause
{
$$ = makeClassNode(FB_NEW(getPool()) RecreateRelationNode(
getPool(), compilingText, $1, true));
}
;
rview_clause : symbol_view_name column_parens_opt AS begin_string select_expr
check_opt end_trigger
{ $$ = make_node (nod_redef_view, (int) e_view_count, $1, $2, $5, $6, $7); }
;
replace_view_clause
: view_clause
{
$1->alter = true;
$$ = makeClassNode($1);
}
;
replace_view_clause : symbol_view_name column_parens_opt AS begin_string select_expr
check_opt end_trigger
{ $$ = make_node (nod_replace_view, (int) e_view_count, $1, $2, $5, $6, $7); }
;
alter_view_clause : symbol_view_name column_parens_opt AS begin_string select_expr
check_opt end_trigger
{ $$ = make_node (nod_mod_view, (int) e_view_count, $1, $2, $5, $6, $7); }
;
alter_view_clause
: view_clause
{
$1->alter = true;
$1->create = false;
$$ = makeClassNode($1);
}
;
// these rules will capture the input string for storage in metadata
@ -2794,12 +2818,12 @@ end_default :
}
;
check_opt : WITH CHECK OPTION
{ $$ = make_node (nod_def_constraint, (int) e_cnstr_count,
NULL, NULL, NULL, NULL, NULL); }
|
{ $$ = 0; }
;
check_opt
:
{ $$ = false; }
| WITH CHECK OPTION
{ $$ = true; }
;

View File

@ -237,7 +237,7 @@ static dsql_nod* pass1_update(DsqlCompilerScratch*, dsql_nod*, bool);
static dsql_nod* pass1_update_or_insert(DsqlCompilerScratch*, dsql_nod*);
static dsql_nod* pass1_variable(DsqlCompilerScratch*, dsql_nod*);
static void remap_streams_to_parent_context(dsql_nod*, dsql_ctx*);
static dsql_fld* resolve_context(DsqlCompilerScratch*, const dsql_str*, dsql_ctx*, bool, bool);
static dsql_fld* resolve_context(DsqlCompilerScratch*, const dsql_str*, dsql_ctx*, bool);
static dsql_nod* resolve_using_field(DsqlCompilerScratch* dsqlScratch, dsql_str* name, DsqlNodStack& stack,
const dsql_nod* flawedNode, const TEXT* side, dsql_ctx*& ctx);
static void set_parameters_name(dsql_nod*, const dsql_nod*);
@ -1096,7 +1096,9 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, const dsql_nod* r
}
else
{
relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, relation_name);
relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch,
relation_name->str_data);
if (!relation && (relation_node->nod_type == nod_rel_proc_name))
{
procedure = METD_get_procedure(dsqlScratch->getTransaction(), dsqlScratch,
@ -1887,10 +1889,6 @@ dsql_nod* PASS1_statement(DsqlCompilerScratch* dsqlScratch, dsql_nod* input)
case nod_def_index:
case nod_mod_index:
case nod_del_index:
case nod_def_view:
case nod_redef_view:
case nod_mod_view:
case nod_replace_view:
case nod_def_constraint:
case nod_grant:
case nod_revoke:
@ -5040,16 +5038,6 @@ static dsql_nod* pass1_field(DsqlCompilerScratch* dsqlScratch, dsql_nod* input,
DEV_BLKCHK(dsqlScratch, dsql_type_req);
DEV_BLKCHK(input, dsql_type_nod);
// CVC: This shameful hack added to allow CHECK constraint implementation via triggers
// to be able to work.
bool is_check_constraint = false;
{ // scope block
const dsql_nod* ddl_node = dsqlScratch->getStatement()->getDdlNode();
if (ddl_node && ddl_node->nod_type == nod_def_constraint) {
is_check_constraint = true;
}
} // end scope block
// handle an array element.
dsql_nod* indices;
if (input->nod_type == nod_array)
@ -5165,8 +5153,7 @@ static dsql_nod* pass1_field(DsqlCompilerScratch* dsqlScratch, dsql_nod* input,
continue;
}
dsql_fld* field = resolve_context(dsqlScratch, qualifier, context, is_check_constraint,
resolve_by_alias);
dsql_fld* field = resolve_context(dsqlScratch, qualifier, context, resolve_by_alias);
// AB: When there's no relation and no procedure then we have a derived table.
const bool is_derived_table =
@ -5355,12 +5342,10 @@ static dsql_nod* pass1_field(DsqlCompilerScratch* dsqlScratch, dsql_nod* input,
if (node)
break;
if (resolve_by_alias && !is_check_constraint && relaxedAliasChecking) {
if (resolve_by_alias && !dsqlScratch->checkConstraintTrigger && relaxedAliasChecking)
resolve_by_alias = false;
}
else {
else
break;
}
}
// CVC: We can't return blindly if this is a check constraint, because there's
@ -9185,7 +9170,7 @@ static void remap_streams_to_parent_context( dsql_nod* input, dsql_ctx* parent_c
**/
static dsql_fld* resolve_context( DsqlCompilerScratch* dsqlScratch, const dsql_str* qualifier,
dsql_ctx* context, bool isCheckConstraint, bool resolveByAlias)
dsql_ctx* context, bool resolveByAlias)
{
// CVC: Warning: the second param, "name" was is not used anymore and
// therefore it was removed. Thus, the local variable "table_name"
@ -9220,7 +9205,7 @@ static dsql_fld* resolve_context( DsqlCompilerScratch* dsqlScratch, const dsql_s
// the qualifier present.
// An exception is a check-constraint that is allowed to reference fields
// without the qualifier.
if (!isCheckConstraint && (context->ctx_flags & CTX_system) && !qualifier) {
if (!dsqlScratch->checkConstraintTrigger && (context->ctx_flags & CTX_system) && !qualifier) {
return NULL;
}
@ -9232,7 +9217,7 @@ static dsql_fld* resolve_context( DsqlCompilerScratch* dsqlScratch, const dsql_s
// contains the "NEW" alias. This is because it is possible
// to reference a field by the complete table-name as alias
// (see EMPLOYEE table in examples for a example).
if (isCheckConstraint && table_name)
if (dsqlScratch->checkConstraintTrigger && table_name)
{
// If a qualifier is present and it's equal to the alias then we've already the right table-name
if (!(qualifier && !strcmp(qualifier->str_data, table_name)))
@ -9952,18 +9937,6 @@ void DSQL_pretty(const dsql_nod* node, int column)
case nod_def_index:
verb = "define index";
break;
case nod_def_view:
verb = "define view";
break;
case nod_redef_view:
verb = "redefine view";
break;
case nod_mod_view:
verb = "modify view";
break;
case nod_replace_view:
verb = "replace view";
break;
case nod_delete:
verb = "delete";
break;

View File

@ -1034,6 +1034,11 @@ static const struct {
{"dsql_create_pack_body_failed", 336397295},
{"dsql_drop_pack_body_failed", 336397296},
{"dsql_recreate_pack_body_failed", 336397297},
{"dsql_create_view_failed", 336397298},
{"dsql_alter_view_failed", 336397299},
{"dsql_create_alter_view_failed", 336397300},
{"dsql_recreate_view_failed", 336397301},
{"dsql_drop_view_failed", 336397302},
{"gsec_cant_open_db", 336723983},
{"gsec_switches_error", 336723984},
{"gsec_no_op_spec", 336723985},

View File

@ -1068,6 +1068,11 @@ const ISC_STATUS isc_dsql_recreate_pack_failed = 336397294L;
const ISC_STATUS isc_dsql_create_pack_body_failed = 336397295L;
const ISC_STATUS isc_dsql_drop_pack_body_failed = 336397296L;
const ISC_STATUS isc_dsql_recreate_pack_body_failed = 336397297L;
const ISC_STATUS isc_dsql_create_view_failed = 336397298L;
const ISC_STATUS isc_dsql_alter_view_failed = 336397299L;
const ISC_STATUS isc_dsql_create_alter_view_failed = 336397300L;
const ISC_STATUS isc_dsql_recreate_view_failed = 336397301L;
const ISC_STATUS isc_dsql_drop_view_failed = 336397302L;
const ISC_STATUS isc_gsec_cant_open_db = 336723983L;
const ISC_STATUS isc_gsec_switches_error = 336723984L;
const ISC_STATUS isc_gsec_no_op_spec = 336723985L;
@ -1168,7 +1173,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 = 1112;
const ISC_STATUS isc_err_max = 1117;
#else /* c definitions */
@ -2206,6 +2211,11 @@ const ISC_STATUS isc_err_max = 1112;
#define isc_dsql_create_pack_body_failed 336397295L
#define isc_dsql_drop_pack_body_failed 336397296L
#define isc_dsql_recreate_pack_body_failed 336397297L
#define isc_dsql_create_view_failed 336397298L
#define isc_dsql_alter_view_failed 336397299L
#define isc_dsql_create_alter_view_failed 336397300L
#define isc_dsql_recreate_view_failed 336397301L
#define isc_dsql_drop_view_failed 336397302L
#define isc_gsec_cant_open_db 336723983L
#define isc_gsec_switches_error 336723984L
#define isc_gsec_no_op_spec 336723985L
@ -2306,7 +2316,7 @@ const ISC_STATUS isc_err_max = 1112;
#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 1112
#define isc_err_max 1117
#endif

View File

@ -1037,6 +1037,11 @@ Data source : @4"}, /* eds_statement */
{336397295, "CREATE PACKAGE BODY @1 failed"}, /* dsql_create_pack_body_failed */
{336397296, "DROP PACKAGE BODY @1 failed"}, /* dsql_drop_pack_body_failed */
{336397297, "RECREATE PACKAGE BODY @1 failed"}, /* dsql_recreate_pack_body_failed */
{336397298, "CREATE VIEW @1 failed"}, /* dsql_create_view_failed */
{336397299, "ALTER VIEW @1 failed"}, /* dsql_alter_view_failed */
{336397300, "CREATE OR ALTER VIEW @1 failed"}, /* dsql_create_alter_view_failed */
{336397301, "RECREATE VIEW @1 failed"}, /* dsql_recreate_view_failed */
{336397302, "DROP VIEW @1 failed"}, /* dsql_drop_view_failed */
{336723983, "unable to open database"}, /* gsec_cant_open_db */
{336723984, "error in switch specifications"}, /* gsec_switches_error */
{336723985, "no operation specified"}, /* gsec_no_op_spec */

View File

@ -1033,6 +1033,11 @@ static const struct {
{336397295, -901}, /* 1007 dsql_create_pack_body_failed */
{336397296, -901}, /* 1008 dsql_drop_pack_body_failed */
{336397297, -901}, /* 1009 dsql_recreate_pack_body_failed */
{336397298, -901}, /* 1010 dsql_create_view_failed */
{336397299, -901}, /* 1011 dsql_alter_view_failed */
{336397300, -901}, /* 1012 dsql_create_alter_view_failed */
{336397301, -901}, /* 1013 dsql_recreate_view_failed */
{336397302, -901}, /* 1014 dsql_drop_view_failed */
{336723983, -901}, /* 15 gsec_cant_open_db */
{336723984, -901}, /* 16 gsec_switches_error */
{336723985, -901}, /* 17 gsec_no_op_spec */

View File

@ -1033,6 +1033,11 @@ static const struct {
{336397295, "42000"}, // 1007 dsql_create_pack_body_failed
{336397296, "42000"}, // 1008 dsql_drop_pack_body_failed
{336397297, "42000"}, // 1009 dsql_recreate_pack_body_failed
{336397298, "42000"}, // 1010 dsql_create_view_failed
{336397299, "42000"}, // 1011 dsql_alter_view_failed
{336397300, "42000"}, // 1012 dsql_create_alter_view_failed
{336397301, "42000"}, // 1013 dsql_recreate_view_failed
{336397302, "42000"}, // 1014 dsql_drop_view_failed
{336723983, "00000"}, // 15 gsec_cant_open_db
{336723984, "00000"}, // 16 gsec_switches_error
{336723985, "00000"}, // 17 gsec_no_op_spec

View File

@ -74,7 +74,6 @@ enum drq_type_t
drq_l_rel_name, // lookup relation name
drq_l_view_rels, // lookup relations in view
drq_s_usr_prvs, // store user privileges
drq_s_sql_lfld, // store sql fields
drq_s_sql_gfld, // store sql fields
drq_s_triggers, // store triggers
drq_s_view_rels, // store view relations
@ -184,7 +183,6 @@ enum drq_type_t
drq_s_prm_src2,
drq_m_prcs2,
drq_e_prms2,
drq_s_triggers2,
drq_m_trigger2,
drq_e_prcs2,
drq_e_prc_prvs,
@ -230,7 +228,6 @@ enum drq_type_t
drq_m_fld, // create domain field
drq_s_fld_dym, // store field dymension
drq_m_fld2, // alter domain
drq_s_lfields2, // store local fields
drq_c_unq_nam2, // check for unique field names
drq_s_rels2, // store relations

View File

@ -378,32 +378,6 @@ void DYN_execute(Global* gbl,
DYN_modify_database(gbl, ptr);
break;
case isc_dyn_def_view:
DYN_define_view(gbl, ptr);
break;
case isc_dyn_mod_view:
DYN_modify_view(gbl, ptr);
break;
case isc_dyn_delete_rel: // Temporary hack for views.
{
thread_db* tdbb = JRD_get_thread_data();
MetaName relationName;
GET_STRING(ptr, relationName);
DropRelationNode::erase(tdbb, gbl->gbl_transaction, relationName, true, gbl->sqlText);
while (*(*ptr)++ != isc_dyn_end)
{
--(*ptr);
DYN_execute(gbl, ptr, &relationName, NULL, NULL, NULL, NULL);
}
break;
}
case isc_dyn_def_filter:
DYN_define_filter(gbl, ptr);
break;
@ -444,28 +418,8 @@ void DYN_execute(Global* gbl,
DYN_delete_shadow(gbl, ptr);
break;
case isc_dyn_def_trigger:
DYN_define_trigger(gbl, ptr, relation_name, NULL, false);
break;
case isc_dyn_def_local_fld:
DYN_define_local_field(gbl, ptr, relation_name, field_name);
break;
case isc_dyn_delete_local_fld:
DYN_delete_local_field(gbl, ptr, relation_name); //, field_name);
break;
case isc_dyn_mod_sql_fld:
DYN_modify_sql_field(gbl, ptr, relation_name);
break;
case isc_dyn_def_sql_fld:
DYN_define_sql_field(gbl, ptr, relation_name, field_name);
break;
case isc_dyn_def_idx:
DYN_define_index(gbl, ptr, relation_name, verb, NULL, NULL, NULL, NULL);
DYN_define_index(gbl, ptr, relation_name, verb);
break;
case isc_dyn_mod_idx:
@ -476,10 +430,6 @@ void DYN_execute(Global* gbl,
DYN_delete_index(gbl, ptr);
break;
case isc_dyn_view_relation:
DYN_define_view_relation(gbl, ptr, relation_name);
break;
case isc_dyn_mapping:
DYN_modify_mapping(gbl, ptr);
break;

File diff suppressed because it is too large Load Diff

View File

@ -256,64 +256,6 @@ void DYN_delete_index( Global* gbl, const UCHAR** ptr)
}
void DYN_delete_local_field(Global* gbl, const UCHAR** ptr, const Firebird::MetaName* relation_name)
//Firebird::MetaName* field_name) // Obtained from the stream
{
/**************************************
*
* D Y N _ d e l e t e _ l o c a l _ f i e l d
*
**************************************
*
* Functional description
* Execute a dynamic ddl 'delete local field'
* statement.
*
* The rules for dropping a regular column:
*
* 1. the column is not referenced in any views.
* 2. the column is not part of any user defined indexes.
* 3. the column is not used in any SQL statements inside of store
* procedures or triggers
* 4. the column is not part of any check-constraints
*
* The rules for dropping a column that was created as primary key:
*
* 1. the column is not defined as any foreign keys
* 2. the column is not defined as part of compound primary keys
*
* The rules for dropping a column that was created as foreign key:
*
* 1. the column is not defined as a compound foreign key. A
* compound foreign key is a foreign key consisted of more
* than one columns.
*
* The RI enforcement for dropping primary key column is done by system
* triggers and the RI enforcement for dropping foreign key column is
* done by code and system triggers. See the functional description of
* delete_f_key_constraint function for detail.
*
**************************************/
Firebird::MetaName tbl_nm, col_nm;
thread_db* tdbb = JRD_get_thread_data();
GET_STRING(ptr, col_nm);
if (relation_name)
tbl_nm = *relation_name;
else if (*(*ptr)++ != isc_dyn_rel_name)
{
DYN_error_punt(false, 51);
// msg 51: "No relation specified in ERASE RFR"
}
else
GET_STRING(ptr, tbl_nm);
RelationNode::deleteLocalField(tdbb, gbl->gbl_transaction, tbl_nm, col_nm);
}
void DYN_delete_role( Global* gbl, const UCHAR** ptr)
{
/**************************************

View File

@ -28,15 +28,9 @@ void DYN_define_file(Jrd::Global*, const UCHAR**, SLONG, SLONG*, USHORT);
void DYN_define_filter(Jrd::Global*, const UCHAR**);
void DYN_define_function(Jrd::Global*, const UCHAR**);
void DYN_define_function_arg(Jrd::Global*, const UCHAR**, Firebird::MetaName*);
void DYN_define_index(Jrd::Global*, const UCHAR**, const Firebird::MetaName*, UCHAR,
Firebird::MetaName*, Firebird::MetaName*, Firebird::MetaName*, UCHAR*);
void DYN_define_local_field(Jrd::Global*, const UCHAR**, const Firebird::MetaName*, Firebird::MetaName*);
void DYN_define_view(Jrd::Global*, const UCHAR**);
void DYN_define_index(Jrd::Global*, const UCHAR**, const Firebird::MetaName*, UCHAR);
void DYN_define_role(Jrd::Global*, const UCHAR**);
void DYN_define_shadow(Jrd::Global*, const UCHAR**);
void DYN_define_sql_field(Jrd::Global*, const UCHAR**, const Firebird::MetaName*, Firebird::MetaName*);
void DYN_define_trigger(Jrd::Global*, const UCHAR**, const Firebird::MetaName*, Firebird::MetaName*, const bool);
void DYN_define_view_relation(Jrd::Global*, const UCHAR**, const Firebird::MetaName*);
void DYN_define_difference(Jrd::Global*, const UCHAR**);
#endif // JRD_DYN_DF_PROTO_H

View File

@ -27,7 +27,6 @@
void DYN_delete_filter(Jrd::Global*, const UCHAR**);
void DYN_delete_generator(Jrd::Global*, const UCHAR**);
void DYN_delete_index(Jrd::Global*, const UCHAR**);
void DYN_delete_local_field(Jrd::Global*, const UCHAR**, const Firebird::MetaName*);
void DYN_delete_role(Jrd::Global*, const UCHAR**);
void DYN_delete_shadow(Jrd::Global*, const UCHAR**);

View File

@ -27,9 +27,6 @@
void DYN_modify_database(Jrd::Global*, const UCHAR**);
void DYN_modify_function(Jrd::Global*, const UCHAR**);
void DYN_modify_index(Jrd::Global*, const UCHAR**);
void DYN_modify_trigger_msg(Jrd::Global*, const UCHAR**, Firebird::MetaName*);
void DYN_modify_sql_field(Jrd::Global*, const UCHAR**, const Firebird::MetaName*);
void DYN_modify_view(Jrd::Global*, const UCHAR**);
void DYN_modify_mapping(Jrd::Global*, const UCHAR**);
#endif // JRD_DYN_MD_PROTO_H

View File

@ -354,128 +354,6 @@ void DYN_modify_index( Global* gbl, const UCHAR** ptr)
}
void DYN_modify_view( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ m o d i f y _ v i e w
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
MetaName view_name;
GET_STRING(ptr, view_name);
bool found = false;
try {
AutoCacheRequest request(tdbb, drq_m_view, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
REL IN RDB$RELATIONS
WITH REL.RDB$RELATION_NAME EQ view_name.c_str()
AND REL.RDB$VIEW_BLR NOT MISSING
{
found = true;
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_BEFORE,
DDL_TRIGGER_ALTER_VIEW, view_name, gbl->sqlText);
MODIFY REL
REL.RDB$SYSTEM_FLAG = 0;
REL.RDB$SYSTEM_FLAG.NULL = FALSE;
REL.RDB$VIEW_BLR.NULL = TRUE;
REL.RDB$VIEW_SOURCE.NULL = TRUE;
AutoRequest request2;
FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
VR IN RDB$VIEW_RELATIONS
WITH VR.RDB$VIEW_NAME EQ view_name.c_str()
{
ERASE VR;
}
END_FOR
request2.reset();
FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
TRG IN RDB$TRIGGERS
WITH TRG.RDB$RELATION_NAME EQ view_name.c_str() AND
TRG.RDB$SYSTEM_FLAG EQ fb_sysflag_view_check
{
ERASE TRG;
}
END_FOR
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_system_flag:
REL.RDB$SYSTEM_FLAG = DYN_get_number(ptr);
REL.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
case isc_dyn_view_blr:
if (DYN_put_blr_blob(gbl, ptr, &REL.RDB$VIEW_BLR))
REL.RDB$VIEW_BLR.NULL = FALSE;
else
REL.RDB$VIEW_BLR.NULL = TRUE;
break;
case isc_dyn_view_source:
if (DYN_put_text_blob(gbl, ptr, &REL.RDB$VIEW_SOURCE))
REL.RDB$VIEW_SOURCE.NULL = FALSE;
else
REL.RDB$VIEW_SOURCE.NULL = TRUE;
break;
case isc_dyn_security_class:
GET_STRING(ptr, REL.RDB$SECURITY_CLASS);
REL.RDB$SECURITY_CLASS.NULL = FALSE;
break;
default:
--(*ptr);
{
const MetaName tmp(REL.RDB$RELATION_NAME);
DYN_execute(gbl, ptr, &tmp, NULL, NULL, NULL, NULL);
}
}
}
END_MODIFY
}
END_FOR
} // try
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_error_punt(true, 99);
// msg 99: "MODIFY RDB$RELATIONS failed"
}
if (found)
{
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_AFTER,
DDL_TRIGGER_ALTER_VIEW, view_name, gbl->sqlText);
}
else
{
DYN_error_punt(false, 54, view_name.c_str());
// msg 54: "View %s not found"
}
}
static void change_backup_mode( Global* gbl, UCHAR verb)
{
/**************************************
@ -599,793 +477,6 @@ static void change_backup_mode( Global* gbl, UCHAR verb)
}
void DYN_modify_sql_field(Global* gbl, const UCHAR** ptr, const MetaName* relation_name)
{
/**************************************
*
* D Y N _ m o d i f y _ s q l _ f i e l d
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement
* to modify the datatype of a field.
*
* If there are dependencies on the field, abort the operation
* unless the dependency is an index. In this case, rebuild the
* index once the operation has completed.
*
* If the original datatype of the field was a domain:
* if the new type is a domain, just make the change to the new domain
* if it exists
*
* if the new type is a base type, just make the change
*
* If the original datatype of the field was a base type:
* if the new type is a base type, just make the change
*
* if the new type is a domain, make the change to the field
* definition and remove the entry for RDB$FIELD_SOURCE from the original
* field. In other words ... clean up after ourselves
*
* The following conversions are not allowed:
* Blob to anything
* Array to anything
* Date to anything
* Char to any numeric
* Varchar to any numeric
* Anything to Blob
* Anything to Array
*
* The following operations return a warning
* Decreasing the length of a char (varchar) field
*
* CVC: This is a misleading comment. There's no code that
* produces a warning. This condition raises an error, too.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
dyn_fld orig_fld, new_fld, dom_fld;
try {
GET_STRING(ptr, orig_fld.dyn_fld_name);
// Check to see if the field being altered is involved in any type of dependency.
// If there is a dependency, call DYN_error_punt (inside the function).
fb_assert(relation_name);
// ASF: check disabled to allow change of field type to be used
// with TYPE OF COLUMN table.column feature.
//check_sptrig_dependency(tdbb, gbl, *relation_name,
// orig_fld.dyn_fld_name);
AutoRequest request;
bool found = false;
bool dtype, scale, prec, subtype, charlen, collation, fldlen, nullflg, charset;
dtype = scale = prec = subtype = charlen = collation = fldlen = nullflg = charset = false;
int field_adjusted_count = 0;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
RFR IN RDB$RELATION_FIELDS CROSS
REL IN RDB$RELATIONS WITH
REL.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME AND
RFR.RDB$RELATION_NAME = relation_name->c_str() AND
RFR.RDB$FIELD_NAME = orig_fld.dyn_fld_name.c_str()
{
found = true;
bool is_view = !REL.RDB$VIEW_BLR.NULL;
bool has_dimensions = false;
bool update_domain = false;
bool domain_has_default = false;
bool domain_is_computed = false;
SSHORT fld_position = 0;
bool fld_position_change = false;
SSHORT view_context = 0;
bool view_context_change = false;
MetaName fld_base_field;
bool fld_base_field_change = false;
bool orig_computed = false;
AutoRequest request2;
FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE
{
// Get information about the original field type. If a conversion
// can not be at any time made between the two datatypes, error.
DSC_make_descriptor(&orig_fld.dyn_dsc,
FLD.RDB$FIELD_TYPE,
FLD.RDB$FIELD_SCALE,
FLD.RDB$FIELD_LENGTH,
FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$CHARACTER_SET_ID,
FLD.RDB$COLLATION_ID);
orig_fld.dyn_charbytelen = FLD.RDB$FIELD_LENGTH;
orig_fld.dyn_dtype = FLD.RDB$FIELD_TYPE;
orig_fld.dyn_precision = FLD.RDB$FIELD_PRECISION;
orig_fld.dyn_sub_type = FLD.RDB$FIELD_SUB_TYPE;
orig_fld.dyn_charlen = FLD.RDB$CHARACTER_LENGTH;
orig_fld.dyn_collation = FLD.RDB$COLLATION_ID;
orig_fld.dyn_null_flag = FLD.RDB$NULL_FLAG != 0;
orig_fld.dyn_fld_source = RFR.RDB$FIELD_SOURCE;
orig_computed = !FLD.RDB$COMPUTED_BLR.NULL;
// If the original field type is an array, force its blr type to blr_blob
if (FLD.RDB$DIMENSIONS != 0)
{
orig_fld.dyn_dtype = blr_blob;
has_dimensions = true;
}
domain_has_default = !FLD.RDB$DEFAULT_VALUE.NULL;
domain_is_computed = !FLD.RDB$COMPUTED_BLR.NULL;
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_fld_source:
GET_STRING(ptr, dom_fld.dyn_fld_source);
if (fb_utils::implicit_domain(dom_fld.dyn_fld_source.c_str()))
{
DYN_error_punt(false, 224, SafeArg() << dom_fld.dyn_fld_source.c_str() <<
orig_fld.dyn_fld_name.c_str());
// msg 224: "Cannot use the internal domain %s as new type for field %s".
}
AlterDomainNode::getDomainType(tdbb, gbl->gbl_transaction, dom_fld);
update_domain = true;
break;
case isc_dyn_rel_name:
GET_STRING(ptr, new_fld.dyn_rel_name);
break;
case isc_dyn_fld_length:
fldlen = true;
new_fld.dyn_dsc.dsc_length = DYN_get_number(ptr);
if (++field_adjusted_count > 2)
{
DYN_error_punt(false, 149, orig_fld.dyn_fld_name.c_str());
// msg 149: "Only one data type change to the field %s allowed at a time"
}
switch (new_fld.dyn_dtype)
{
case blr_text:
case blr_text2:
case blr_varying:
case blr_varying2:
case blr_cstring:
case blr_cstring2:
new_fld.dyn_charbytelen = new_fld.dyn_dsc.dsc_length;
break;
default:
new_fld.dyn_charbytelen = 0; // It won't be used, anyway.
break;
}
break;
case isc_dyn_fld_type:
dtype = true;
new_fld.dyn_dtype = DYN_get_number(ptr);
if (++field_adjusted_count > 2)
{
DYN_error_punt(false, 149, orig_fld.dyn_fld_name.c_str());
// msg 149: "Only one data type change to the field %s allowed at a time"
}
switch (new_fld.dyn_dtype)
{
case blr_text:
case blr_text2:
case blr_varying:
case blr_varying2:
case blr_cstring:
case blr_cstring2:
if (new_fld.dyn_dsc.dsc_length && !new_fld.dyn_charbytelen)
new_fld.dyn_charbytelen = new_fld.dyn_dsc.dsc_length;
new_fld.dyn_dsc.dsc_length = DSC_string_length (&new_fld.dyn_dsc);
break;
case blr_short:
new_fld.dyn_dsc.dsc_length = 2;
break;
case blr_long:
case blr_float:
new_fld.dyn_dsc.dsc_length = 4;
break;
case blr_int64:
case blr_sql_time:
case blr_sql_date:
case blr_timestamp:
case blr_double:
case blr_d_float:
new_fld.dyn_dsc.dsc_length = 8;
break;
default:
break;
}
break;
case isc_dyn_fld_scale:
scale = true;
new_fld.dyn_dsc.dsc_scale = DYN_get_number(ptr);
break;
case isc_dyn_fld_precision:
prec = true;
new_fld.dyn_precision = DYN_get_number(ptr);
break;
case isc_dyn_fld_sub_type:
subtype = true;
new_fld.dyn_sub_type = DYN_get_number(ptr);
break;
case isc_dyn_fld_char_length:
charlen = true;
new_fld.dyn_charlen = DYN_get_number(ptr);
break;
case isc_dyn_fld_collation:
collation = true;
new_fld.dyn_collation = DYN_get_number(ptr);
break;
case isc_dyn_fld_character_set:
charset = true;
new_fld.dyn_charset = DYN_get_number(ptr);
break;
case isc_dyn_fld_not_null:
nullflg = true;
new_fld.dyn_null_flag = true;
break;
case isc_dyn_fld_dimensions:
new_fld.dyn_dtype = blr_blob;
break;
case isc_dyn_fld_position:
fld_position = DYN_get_number(ptr);
fld_position_change = true;
break;
case isc_dyn_fld_base_fld:
GET_STRING(ptr, fld_base_field);
fld_base_field_change = true;
break;
case isc_dyn_view_context:
view_context = DYN_get_number(ptr);
view_context_change = true;
break;
case isc_dyn_fld_computed_blr:
domain_is_computed = true;
new_fld.dyn_computed_val = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_fld_computed_source:
new_fld.dyn_computed_src = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_del_computed:
domain_is_computed = false;
new_fld.dyn_drop_computed = true;
break;
case isc_dyn_del_default:
new_fld.dyn_drop_default = true;
break;
case isc_dyn_fld_default_value:
if (!RFR.RDB$GENERATOR_NAME.NULL)
{
// msg 275: Identity column @1 of table @2 cannot have default value
DYN_error_punt(false, 275,
SafeArg() << orig_fld.dyn_fld_name.c_str() << relation_name->c_str());
}
if (has_dimensions)
{
DYN_error_punt(false, 225, orig_fld.dyn_fld_name.c_str());
// msg 225: "Default value is not allowed for array type in field %s"
}
new_fld.dyn_default_val = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_fld_default_source:
if (has_dimensions)
{
DYN_error_punt(false, 225, orig_fld.dyn_fld_name.c_str());
// msg 225: "Default value is not allowed for array type in field %s"
}
new_fld.dyn_default_src = *ptr;
DYN_skip_attribute(ptr);
break;
// These should only be defined for BLOB types and should not come through with
// any other types. BLOB types are detected above
case isc_dyn_fld_segment_length:
DYN_get_number(ptr);
break;
default:
--(*ptr);
{
MetaNameProxy tmp(RFR.RDB$FIELD_SOURCE);
DYN_execute(gbl, ptr, relation_name, &tmp, NULL, NULL, NULL);
}
}
}
if (fld_base_field_change && view_context_change)
{
fb_assert(is_view);
if (fld_base_field.hasData())
{
char field_name[MAX_SQL_IDENTIFIER_SIZE];
DYN_UTIL_find_field_source(tdbb, gbl, RFR.RDB$RELATION_NAME, view_context,
fld_base_field.c_str(), field_name);
dom_fld.dyn_fld_source = field_name;
update_domain = true;
}
else
DYN_UTIL_generate_field_name(tdbb, gbl, new_fld.dyn_fld_source);
}
}
END_FOR // FLD in RDB$FIELDS
if (!is_view &&
((new_fld.dyn_computed_val && !orig_computed) ||
(!new_fld.dyn_computed_val && orig_computed)))
{
// Cannot add or remove COMPUTED from column @1
DYN_error_punt(false, 249, SafeArg() << orig_fld.dyn_fld_name.c_str());
}
const bool sourceIsInternalDomain =
fb_utils::implicit_domain(orig_fld.dyn_fld_source.c_str()) && RFR.RDB$BASE_FIELD.NULL;
const bool changeComputed = new_fld.dyn_computed_val || new_fld.dyn_drop_computed;
// Now that we have all of the information needed, let's check to see
// if the field type can be modified
if (update_domain)
{
// a1. Internal domain -> domain.
// a2. Domain -> domain.
/* CVC: Since AlterDomainNode::getDomainType() called above already called
// DSC_make_descriptor, there's no point in calling it again, since it will increment
// AGAIN the length of varchar fields! This bug detected thanks to new check field
// dyn_charbytelen.
DSC_make_descriptor(&dom_fld.dyn_dsc,
dom_fld.dyn_dtype,
dom_fld.dyn_dsc.dsc_scale,
dom_fld.dyn_dsc.dsc_length,
dom_fld.dyn_sub_type,
dom_fld.dyn_charset, dom_fld.dyn_collation);
*/
if (!domain_is_computed && !is_view)
{
if (!RFR.RDB$GENERATOR_NAME.NULL)
{
if (!dom_fld.dyn_dsc.isExact() || dom_fld.dyn_dsc.dsc_scale != 0)
{
// Identity column @1 of table @2 must be exact numeric with zero scale.
DYN_error_punt(false, 273,
SafeArg() << orig_fld.dyn_fld_name.c_str() << relation_name->c_str());
}
}
AlterDomainNode::checkUpdate(orig_fld, dom_fld);
}
// If the original definition was a base field type, remove the entries from RDB$FIELDS
if (sourceIsInternalDomain)
{
request2.reset();
// a1. Internal domain -> domain.
FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS
WITH FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE
{
ERASE FLD;
}
END_FOR
}
MODIFY RFR USING
strcpy(RFR.RDB$FIELD_SOURCE, dom_fld.dyn_fld_source.c_str());
RFR.RDB$FIELD_SOURCE.NULL = FALSE;
if (domain_is_computed)
{
RFR.RDB$UPDATE_FLAG.NULL = FALSE;
RFR.RDB$UPDATE_FLAG = 1;
}
RFR.RDB$COLLATION_ID.NULL = TRUE; // CORE-2426
END_MODIFY
request2.reset();
FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
PRM IN RDB$PROCEDURE_PARAMETERS
WITH PRM.RDB$RELATION_NAME = relation_name->c_str() AND
PRM.RDB$FIELD_NAME = orig_fld.dyn_fld_name.c_str()
{
MODIFY PRM USING
strcpy(PRM.RDB$FIELD_SOURCE, dom_fld.dyn_fld_source.c_str());
END_MODIFY
}
END_FOR
}
else
{
// b1. Domain -> internal domain.
// b2. Internal domain -> internal domain.
const UCHAR* defVal = new_fld.dyn_default_val;
const UCHAR* defSrc = new_fld.dyn_default_src;
const bool dropDefault = new_fld.dyn_drop_default;
const bool changeDefault = defVal || defSrc || dropDefault;
// If we are altering only the default, we need the old field settings.
if (changeDefault && !new_fld.dyn_dsc.dsc_dtype)
{
new_fld = orig_fld;
// We already called DSC_make_descriptor on orig_fld, so fix new_fld.
switch (new_fld.dyn_dtype)
{
case blr_text:
case blr_varying:
case blr_cstring:
new_fld.dyn_dsc.dsc_length = DSC_string_length(&orig_fld.dyn_dsc);
break;
}
}
DSC_make_descriptor(&new_fld.dyn_dsc,
new_fld.dyn_dtype,
new_fld.dyn_dsc.dsc_scale,
new_fld.dyn_dsc.dsc_length,
new_fld.dyn_sub_type,
new_fld.dyn_charset, new_fld.dyn_collation);
if (!changeComputed && !orig_computed && !is_view)
{
AlterDomainNode::checkUpdate(orig_fld, new_fld);
if (!RFR.RDB$GENERATOR_NAME.NULL)
{
if (!new_fld.dyn_dsc.isExact() || new_fld.dyn_dsc.dsc_scale != 0)
{
// Identity column @1 of table @2 must be exact numeric with zero scale.
DYN_error_punt(false, 273,
SafeArg() << orig_fld.dyn_fld_name.c_str() << relation_name->c_str());
}
}
}
// Check to see if the original data type for the field was based on a domain. If it
// was (and now it isn't), remove the domain information and replace it with a generated
// field name for RDB$FIELDS
if (!changeDefault && !sourceIsInternalDomain)
{
// b1. Domain -> internal domain. Not for changing DEFAULT value.
MODIFY RFR USING
DYN_UTIL_generate_field_name(tdbb, gbl, RFR.RDB$FIELD_SOURCE);
new_fld.dyn_fld_source = RFR.RDB$FIELD_SOURCE;
END_MODIFY
request2.reset();
STORE(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS
FLD.RDB$SYSTEM_FLAG = 0;
FLD.RDB$SYSTEM_FLAG.NULL = FALSE;
FLD.RDB$FIELD_SCALE.NULL = TRUE;
FLD.RDB$FIELD_PRECISION.NULL = TRUE;
FLD.RDB$FIELD_SUB_TYPE.NULL = TRUE;
FLD.RDB$SEGMENT_LENGTH.NULL = TRUE;
FLD.RDB$COMPUTED_BLR.NULL = TRUE;
FLD.RDB$COMPUTED_SOURCE.NULL = TRUE;
FLD.RDB$DEFAULT_VALUE.NULL = TRUE;
FLD.RDB$DEFAULT_SOURCE.NULL = TRUE;
FLD.RDB$VALIDATION_BLR.NULL = TRUE;
FLD.RDB$VALIDATION_SOURCE.NULL = TRUE;
FLD.RDB$NULL_FLAG.NULL = TRUE;
FLD.RDB$EDIT_STRING.NULL = TRUE;
FLD.RDB$DIMENSIONS.NULL = TRUE;
FLD.RDB$CHARACTER_LENGTH.NULL = TRUE;
FLD.RDB$CHARACTER_SET_ID.NULL = TRUE;
FLD.RDB$COLLATION_ID.NULL = TRUE;
if (dtype)
{
FLD.RDB$FIELD_TYPE = new_fld.dyn_dtype;
FLD.RDB$FIELD_TYPE.NULL = FALSE;
}
if (scale)
{
FLD.RDB$FIELD_SCALE = new_fld.dyn_dsc.dsc_scale;
FLD.RDB$FIELD_SCALE.NULL = FALSE;
}
if (prec)
{
FLD.RDB$FIELD_PRECISION = new_fld.dyn_precision;
FLD.RDB$FIELD_PRECISION.NULL = FALSE;
}
if (subtype)
{
FLD.RDB$FIELD_SUB_TYPE = new_fld.dyn_sub_type;
FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE;
}
if (charlen)
{
FLD.RDB$CHARACTER_LENGTH = new_fld.dyn_charlen;
FLD.RDB$CHARACTER_LENGTH.NULL = FALSE;
}
if (charset)
{
FLD.RDB$CHARACTER_SET_ID = new_fld.dyn_charset;
FLD.RDB$CHARACTER_SET_ID.NULL = FALSE;
}
if (collation)
{
FLD.RDB$COLLATION_ID = new_fld.dyn_collation;
FLD.RDB$COLLATION_ID.NULL = FALSE;
}
if (fldlen)
{
// CVC: Rescue from the wrong field_length with a helper.
if (new_fld.dyn_dsc.dsc_dtype <= dtype_varying && new_fld.dyn_charbytelen)
FLD.RDB$FIELD_LENGTH = new_fld.dyn_charbytelen;
else
FLD.RDB$FIELD_LENGTH = new_fld.dyn_dsc.dsc_length;
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
}
if (new_fld.dyn_computed_val)
{
DYN_put_blr_blob(gbl, &new_fld.dyn_computed_val, &FLD.RDB$COMPUTED_BLR);
FLD.RDB$COMPUTED_BLR.NULL = FALSE;
}
if (new_fld.dyn_computed_src)
{
DYN_put_text_blob(gbl, &new_fld.dyn_computed_src, &FLD.RDB$COMPUTED_SOURCE);
FLD.RDB$COMPUTED_SOURCE.NULL = FALSE;
}
// Copy the field name into RDB$FIELDS
strcpy(FLD.RDB$FIELD_NAME, new_fld.dyn_fld_source.c_str());
END_STORE
request2.reset();
FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
PRM IN RDB$PROCEDURE_PARAMETERS
WITH PRM.RDB$RELATION_NAME = relation_name->c_str() AND
PRM.RDB$FIELD_NAME = orig_fld.dyn_fld_name.c_str()
{
MODIFY PRM USING
strcpy(PRM.RDB$FIELD_SOURCE, new_fld.dyn_fld_source.c_str());
END_MODIFY
}
END_FOR
}
else if (changeDefault)
{
MODIFY RFR USING
if (dropDefault)
{
if (RFR.RDB$DEFAULT_VALUE.NULL)
{
if (sourceIsInternalDomain || !domain_has_default)
{
DYN_error_punt(false, 229, orig_fld.dyn_fld_name.c_str());
// msg 229: "Local column %s doesn't have a default"
}
else if (domain_has_default)
{
DYN_error_punt(false, 230, SafeArg() << orig_fld.dyn_fld_name.c_str() <<
orig_fld.dyn_fld_source.c_str());
// msg 230: "Local column %s default belongs to domain %s"
}
}
else
{
RFR.RDB$DEFAULT_VALUE.NULL = TRUE;
RFR.RDB$DEFAULT_SOURCE.NULL = TRUE;
}
}
else
{
if (domain_is_computed)
{
DYN_error_punt(false, 233, orig_fld.dyn_fld_name.c_str());
// msg 233: "Local column %s is computed, cannot set a default value"
}
if (defVal)
{
const UCHAR* p = defVal;
if (DYN_put_blr_blob(gbl, &p, &RFR.RDB$DEFAULT_VALUE))
RFR.RDB$DEFAULT_VALUE.NULL = FALSE;
}
if (defSrc)
{
const UCHAR* p = defSrc;
if (DYN_put_text_blob(gbl, &p, &RFR.RDB$DEFAULT_SOURCE))
RFR.RDB$DEFAULT_SOURCE.NULL = FALSE;
}
}
END_MODIFY
}
else //if (sourceIsInternalDomain)
{
// The original and new definitions are both base types.
// b2. Internal domain -> internal domain.
// Modify in place, since there cannot be other fields using it.
//if (!sourceIsInternalDomain)
// DYN_UTIL_copy_domain(tdbb, gbl, orig_fld.dyn_fld_source, new_fld.dyn_fld_source);
request2.reset();
FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE
{
MODIFY FLD USING
if (dtype)
{
FLD.RDB$FIELD_TYPE = new_fld.dyn_dtype;
FLD.RDB$FIELD_TYPE.NULL = FALSE;
}
if (scale)
{
FLD.RDB$FIELD_SCALE = new_fld.dyn_dsc.dsc_scale;
FLD.RDB$FIELD_SCALE.NULL = FALSE;
}
if (prec)
{
FLD.RDB$FIELD_PRECISION = new_fld.dyn_precision;
FLD.RDB$FIELD_PRECISION.NULL = FALSE;
}
if (subtype)
{
FLD.RDB$FIELD_SUB_TYPE = new_fld.dyn_sub_type;
FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE;
}
if (charlen)
{
FLD.RDB$CHARACTER_LENGTH = new_fld.dyn_charlen;
FLD.RDB$CHARACTER_LENGTH.NULL = FALSE;
}
if (charset)
{
FLD.RDB$CHARACTER_SET_ID = new_fld.dyn_charset;
FLD.RDB$CHARACTER_SET_ID.NULL = FALSE;
}
if (collation)
{
FLD.RDB$COLLATION_ID = new_fld.dyn_collation;
FLD.RDB$COLLATION_ID.NULL = FALSE;
}
if (fldlen)
{
// CVC: Rescue from the wrong field_length with a helper.
if (new_fld.dyn_dsc.dsc_dtype <= dtype_varying && new_fld.dyn_charbytelen)
FLD.RDB$FIELD_LENGTH = new_fld.dyn_charbytelen;
else
FLD.RDB$FIELD_LENGTH = new_fld.dyn_dsc.dsc_length;
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
}
if (changeComputed)
{
FLD.RDB$DEFAULT_SOURCE.NULL = TRUE;
FLD.RDB$DEFAULT_VALUE.NULL = TRUE;
if (new_fld.dyn_computed_val)
{
DYN_put_blr_blob(gbl, &new_fld.dyn_computed_val, &FLD.RDB$COMPUTED_BLR);
FLD.RDB$COMPUTED_BLR.NULL = FALSE;
}
if (new_fld.dyn_computed_src)
{
DYN_put_text_blob(gbl, &new_fld.dyn_computed_src, &FLD.RDB$COMPUTED_SOURCE);
FLD.RDB$COMPUTED_SOURCE.NULL = FALSE;
}
}
END_MODIFY
}
END_FOR // FLD in RDB$FIELDS
if (domain_is_computed)
{
MODIFY RFR USING
RFR.RDB$UPDATE_FLAG.NULL = FALSE;
RFR.RDB$UPDATE_FLAG = 1;
END_MODIFY
}
}
} // else not a domain
if (fld_position_change || view_context_change || fld_base_field_change)
{
MODIFY RFR USING
if (fld_position_change)
RFR.RDB$FIELD_POSITION = fld_position;
if (view_context_change)
RFR.RDB$VIEW_CONTEXT = view_context;
if (fld_base_field_change)
{
RFR.RDB$BASE_FIELD.NULL = fld_base_field.isEmpty();
strcpy(RFR.RDB$BASE_FIELD, fld_base_field.c_str());
}
END_MODIFY
}
}
END_FOR // RFR IN RDB$RELATION_FIELDS
if (!found)
{
DYN_error_punt(false, 176, SafeArg() << orig_fld.dyn_fld_name.c_str() <<
relation_name->c_str());
// msg 176: "column %s does not exist in table/view %s"
}
// Update any indices that exist
AlterDomainNode::modifyLocalFieldIndex(tdbb, gbl->gbl_transaction, *relation_name,
orig_fld.dyn_fld_name, orig_fld.dyn_fld_name);
}
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_error_punt(true, 95);
// msg 95: "MODIFY RDB$RELATION_FIELDS failed"
}
}
// *************************************
// D Y N _ m o d i f y _ m a p p i n g
// *************************************

View File

@ -32,10 +32,10 @@ namespace Jrd
void DYN_UTIL_store_check_constraints(Jrd::thread_db*, Jrd::jrd_tra*,
const Firebird::MetaName&, const Firebird::MetaName&);
bool DYN_UTIL_find_field_source(Jrd::thread_db* tdbb, Jrd::Global* gbl,
bool DYN_UTIL_find_field_source(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction,
const Firebird::MetaName& view_name, USHORT context, const TEXT* local_name,
TEXT* output_field_name);
bool DYN_UTIL_get_prot(Jrd::thread_db*, Jrd::Global*, const SCHAR*,
bool DYN_UTIL_get_prot(Jrd::thread_db*, Jrd::jrd_tra*, const SCHAR*,
const SCHAR*, Jrd::SecurityClass::flags_t*);
void DYN_UTIL_generate_generator_name(Jrd::thread_db*, Firebird::MetaName&);
void DYN_UTIL_generate_trigger_name(Jrd::thread_db*, Jrd::jrd_tra*, Firebird::MetaName&);

View File

@ -558,7 +558,7 @@ void DYN_UTIL_generate_trigger_name(thread_db* tdbb, jrd_tra* /*transaction*/, M
bool DYN_UTIL_find_field_source(thread_db* tdbb,
Global* gbl,
jrd_tra* transaction,
const Firebird::MetaName& view_name,
USHORT context,
const TEXT* local_name,
@ -588,7 +588,7 @@ bool DYN_UTIL_find_field_source(thread_db* tdbb,
try {
AutoCacheRequest request(tdbb, drq_l_fld_src2, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
VRL IN RDB$VIEW_RELATIONS CROSS
RFR IN RDB$RELATION_FIELDS OVER RDB$RELATION_NAME
WITH VRL.RDB$VIEW_NAME EQ view_name.c_str() AND
@ -607,7 +607,7 @@ bool DYN_UTIL_find_field_source(thread_db* tdbb,
{
request.reset(tdbb, drq_l_fld_src3, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
VRL IN RDB$VIEW_RELATIONS CROSS
PPR IN RDB$PROCEDURE_PARAMETERS
WITH VRL.RDB$RELATION_NAME EQ PPR.RDB$PROCEDURE_NAME AND
@ -636,11 +636,8 @@ bool DYN_UTIL_find_field_source(thread_db* tdbb,
}
bool DYN_UTIL_get_prot(thread_db* tdbb,
Global* gbl,
const SCHAR* rname,
const SCHAR* fname,
SecurityClass::flags_t* prot_mask)
bool DYN_UTIL_get_prot(thread_db* tdbb, jrd_tra* transaction, const SCHAR* rname,
const SCHAR* fname, SecurityClass::flags_t* prot_mask)
{
/**************************************
*
@ -668,7 +665,7 @@ bool DYN_UTIL_get_prot(thread_db* tdbb,
gds__vtov(rname, in_msg.relation_name, sizeof(in_msg.relation_name));
gds__vtov(fname, in_msg.field_name, sizeof(in_msg.field_name));
EXE_start(tdbb, request, gbl->gbl_transaction);
EXE_start(tdbb, request, transaction);
EXE_send(tdbb, request, 0, sizeof(in_msg), (UCHAR*) &in_msg);
EXE_receive(tdbb, request, 1, sizeof(SecurityClass::flags_t), (UCHAR*) prot_mask);
}

View File

@ -20,7 +20,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM
('1996-11-07 13:39:40', 'INSTALL', 10, 1)
('1996-11-07 13:38:41', 'TEST', 11, 4)
('2009-01-03 09:06:33', 'GBAK', 12, 350)
('2010-07-25 22:43:00', 'SQLERR', 13, 1010)
('2010-08-01 13:05:00', 'SQLERR', 13, 1015)
('1996-11-07 13:38:42', 'SQLWARN', 14, 613)
('2006-09-10 03:04:31', 'JRD_BUGCHK', 15, 307)
--

View File

@ -2462,6 +2462,11 @@ ERROR: Backup incomplete', NULL, NULL);
('dsql_create_pack_body_failed', 'getMainErrorCode', 'PackageNodes.h', NULL, 13, 1007, NULL, 'CREATE PACKAGE BODY @1 failed', NULL, NULL);
('dsql_drop_pack_body_failed', 'getMainErrorCode', 'PackageNodes.h', NULL, 13, 1008, NULL, 'DROP PACKAGE BODY @1 failed', NULL, NULL);
('dsql_recreate_pack_body_failed', 'getMainErrorCode', 'PackageNodes.h', NULL, 13, 1009, NULL, 'RECREATE PACKAGE BODY @1 failed', NULL, NULL);
('dsql_create_view_failed', 'getMainErrorCode', 'DdlNodes.h', NULL, 13, 1010, NULL, 'CREATE VIEW @1 failed', NULL, NULL);
('dsql_alter_view_failed', 'getMainErrorCode', 'DdlNodes.h', NULL, 13, 1011, NULL, 'ALTER VIEW @1 failed', NULL, NULL);
('dsql_create_alter_view_failed', 'getMainErrorCode', 'DdlNodes.h', NULL, 13, 1012, NULL, 'CREATE OR ALTER VIEW @1 failed', NULL, NULL);
('dsql_recreate_view_failed', 'getMainErrorCode', 'DdlNodes.h', NULL, 13, 1013, NULL, 'RECREATE VIEW @1 failed', NULL, NULL);
('dsql_drop_view_failed', 'getMainErrorCode', 'DdlNodes.h', NULL, 13, 1014, NULL, 'DROP VIEW @1 failed', NULL, NULL);
-- SQLWARN
(NULL, NULL, NULL, NULL, 14, 100, NULL, 'Row not found for fetch, update or delete, or the result of a query is an empty table.', NULL, NULL);
(NULL, NULL, NULL, NULL, 14, 101, NULL, 'segment buffer length shorter than expected', NULL, NULL);

View File

@ -1026,6 +1026,11 @@ COMMIT WORK;
(-901, '42', '000', 13, 1007, 'dsql_create_pack_body_failed', NULL, NULL);
(-901, '42', '000', 13, 1008, 'dsql_drop_pack_body_failed', NULL, NULL);
(-901, '42', '000', 13, 1009, 'dsql_recreate_pack_body_failed', NULL, NULL);
(-901, '42', '000', 13, 1010, 'dsql_create_view_failed', NULL, NULL);
(-901, '42', '000', 13, 1011, 'dsql_alter_view_failed', NULL, NULL);
(-901, '42', '000', 13, 1012, 'dsql_create_alter_view_failed', NULL, NULL);
(-901, '42', '000', 13, 1013, 'dsql_recreate_view_failed', NULL, NULL);
(-901, '42', '000', 13, 1014, 'dsql_drop_view_failed', NULL, NULL);
-- GSEC
(-901, '00', '000', 18, 15, 'gsec_cant_open_db', NULL, NULL)
(-901, '00', '000', 18, 16, 'gsec_switches_error', NULL, NULL)