diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index 480f6a2a49..1768e8016e 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -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 diff --git a/lang_helpers/gds_codes.pas b/lang_helpers/gds_codes.pas index 6b7cec5432..1f6926a32f 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -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; diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 9ceeb3a464..26ecea59b5 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -75,8 +75,9 @@ static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName, const MetaName& fieldName, USHORT newPosition, USHORT existingPosition); static rel_t relationType(SSHORT relationTypeNull, SSHORT relationType); +static void saveField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, const MetaName& fieldName); static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - const dsql_str* relationName, bool creating); + const MetaName& relationName, bool view, bool creating); static void updateRdbFields(const TypeClause& type, SSHORT& fieldType, SSHORT& fieldLength, @@ -435,13 +436,27 @@ static rel_t relationType(SSHORT relationTypeNull, SSHORT relationType) return relationTypeNull ? rel_persistent : rel_t(relationType); } +// 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. +static void saveField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, const MetaName& fieldName) +{ + 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 = fieldName.c_str(); + field->fld_next = relation->rel_fields; + relation->rel_fields = field; +} + // 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. static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, - const dsql_str* relationName, bool creating) + const MetaName& relationName, bool view, bool creating) { - //// TODO: Verify "creating" usage when using this function for views. - DsqlCompiledStatement* statement = dsqlScratch->getStatement(); if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_METADATA_SAVED) @@ -451,14 +466,15 @@ static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, dsql_rel* relation; - if (!creating) + if (!view && !creating) relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, relationName); else { MemoryPool& pool = *tdbb->getDefaultPool(); relation = FB_NEW(pool) dsql_rel(pool); - relation->rel_name = relationName->str_data; - relation->rel_flags = REL_creating; + relation->rel_name = relationName; + if (!view) + relation->rel_flags = REL_creating; } dsqlScratch->relation = relation; @@ -511,8 +527,11 @@ static void updateRdbFields(const TypeClause& type, fieldScaleNull = FALSE; fieldScale = 0; - characterLengthNull = FALSE; - characterLength = type.charLength; + if (type.charLength != 0) + { + characterLengthNull = FALSE; + characterLength = type.charLength; + } characterSetIdNull = FALSE; characterSetId = type.charSetId; @@ -815,6 +834,11 @@ void TypeClause::resolve(DsqlCompilerScratch* dsqlScratch, bool modifying) DDL_resolve_intl_type2(dsqlScratch, legacyField, (collate.isEmpty() ? NULL : MAKE_cstring(collate.c_str())), modifying); + setup(dsqlScratch); +} + +void TypeClause::setup(DsqlCompilerScratch* dsqlScratch) +{ type = legacyField->fld_dtype; length = legacyField->fld_length; scale = legacyField->fld_scale; @@ -2655,7 +2679,7 @@ void TriggerDefinition::store(thread_db* tdbb, jrd_tra* transaction) if (name.isEmpty()) DYN_UTIL_generate_trigger_name(tdbb, transaction, name); - AutoCacheRequest requestHandle(tdbb, drq_s_triggers2, DYN_REQUESTS); + AutoCacheRequest requestHandle(tdbb, drq_s_triggers, DYN_REQUESTS); STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) TRG IN RDB$TRIGGERS @@ -3403,7 +3427,8 @@ void DropCollationNode::execute(thread_db* tdbb, jrd_tra* transaction) AutoCacheRequest request2(tdbb, drq_l_rfld_coll, DYN_REQUESTS); FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - RF IN RDB$RELATION_FIELDS CROSS F IN RDB$FIELDS + RF IN RDB$RELATION_FIELDS + CROSS F IN RDB$FIELDS WITH RF.RDB$FIELD_SOURCE EQ F.RDB$FIELD_NAME AND F.RDB$CHARACTER_SET_ID EQ COLL.RDB$CHARACTER_SET_ID AND RF.RDB$COLLATION_ID EQ COLL.RDB$COLLATION_ID @@ -4205,7 +4230,7 @@ void AlterDomainNode::execute(thread_db* tdbb, jrd_tra* transaction) FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) RFR IN RDB$RELATION_FIELDS WITH RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME AND - RFR.RDB$GENERATOR_NAME NOT MISSING + RFR.RDB$GENERATOR_NAME NOT MISSING { // Domain @1 must be of exact number type with zero scale because it's used // in an identity column. @@ -4673,6 +4698,175 @@ bool DropSequenceNode::deleteGenerator(thread_db* tdbb, jrd_tra* transaction, co //---------------------- +void RelationNode::FieldDefinition::modify(thread_db* tdbb, jrd_tra* transaction) +{ + Attachment* attachment = transaction->tra_attachment; + + AutoRequest request; + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + RFR IN RDB$RELATION_FIELDS + WITH RFR.RDB$RELATION_NAME EQ relationName.c_str() AND + RFR.RDB$FIELD_NAME EQ name.c_str() + { + // ASF: This is prepared only to modify view fields! + + MODIFY RFR + strcpy(RFR.RDB$FIELD_SOURCE, fieldSource.c_str()); + + RFR.RDB$COLLATION_ID.NULL = TRUE; + RFR.RDB$GENERATOR_NAME.NULL = TRUE; + RFR.RDB$IDENTITY_TYPE.NULL = TRUE; + RFR.RDB$NULL_FLAG.NULL = TRUE; + RFR.RDB$DEFAULT_SOURCE.NULL = TRUE; + RFR.RDB$DEFAULT_VALUE.NULL = TRUE; + RFR.RDB$FIELD_POSITION.NULL = TRUE; + + RFR.RDB$VIEW_CONTEXT.NULL = TRUE; + RFR.RDB$BASE_FIELD.NULL = TRUE; + ///RFR.RDB$UPDATE_FLAG.NULL = TRUE; + + if (collationId.specified) + { + RFR.RDB$COLLATION_ID.NULL = FALSE; + RFR.RDB$COLLATION_ID = collationId.value; + } + + SLONG fieldPos = -1; + + if (position.specified) + fieldPos = position.value; + else + { + DYN_UTIL_generate_field_position(tdbb, NULL, name, &fieldPos); + if (fieldPos >= 0) + ++fieldPos; + } + + if (fieldPos >= 0) + { + RFR.RDB$FIELD_POSITION.NULL = FALSE; + RFR.RDB$FIELD_POSITION = SSHORT(fieldPos); + } + + if (baseField.hasData()) + { + RFR.RDB$BASE_FIELD.NULL = FALSE; + strcpy(RFR.RDB$BASE_FIELD, baseField.c_str()); + } + + if (viewContext.specified) + { + fb_assert(baseField.hasData()); + + RFR.RDB$VIEW_CONTEXT.NULL = FALSE; + RFR.RDB$VIEW_CONTEXT = viewContext.value; + + DYN_UTIL_find_field_source(tdbb, transaction, relationName, viewContext.value, + baseField.c_str(), RFR.RDB$FIELD_SOURCE); + } + END_MODIFY + } + END_FOR +} + +void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) +{ + Attachment* attachment = transaction->tra_attachment; + + AutoCacheRequest request(tdbb, drq_s_lfields, DYN_REQUESTS); + + STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + RFR IN RDB$RELATION_FIELDS + { + strcpy(RFR.RDB$FIELD_NAME, name.c_str()); + strcpy(RFR.RDB$RELATION_NAME, relationName.c_str()); + strcpy(RFR.RDB$FIELD_SOURCE, fieldSource.c_str()); + RFR.RDB$SYSTEM_FLAG = 0; + + RFR.RDB$COLLATION_ID.NULL = TRUE; + RFR.RDB$GENERATOR_NAME.NULL = TRUE; + RFR.RDB$IDENTITY_TYPE.NULL = TRUE; + RFR.RDB$NULL_FLAG.NULL = TRUE; + RFR.RDB$DEFAULT_SOURCE.NULL = TRUE; + RFR.RDB$DEFAULT_VALUE.NULL = TRUE; + RFR.RDB$FIELD_POSITION.NULL = TRUE; + + RFR.RDB$VIEW_CONTEXT.NULL = TRUE; + RFR.RDB$BASE_FIELD.NULL = TRUE; + ///RFR.RDB$UPDATE_FLAG.NULL = TRUE; + + if (collationId.specified) + { + RFR.RDB$COLLATION_ID.NULL = FALSE; + RFR.RDB$COLLATION_ID = collationId.value; + } + + if (identitySequence.hasData()) + { + RFR.RDB$GENERATOR_NAME.NULL = FALSE; + strcpy(RFR.RDB$GENERATOR_NAME, identitySequence.c_str()); + + RFR.RDB$IDENTITY_TYPE.NULL = FALSE; + RFR.RDB$IDENTITY_TYPE = IDENT_TYPE_BY_DEFAULT; + } + + if (notNullFlag.specified) + { + RFR.RDB$NULL_FLAG.NULL = FALSE; + RFR.RDB$NULL_FLAG = notNullFlag.value; + } + + if (defaultSource.hasData()) + { + RFR.RDB$DEFAULT_SOURCE.NULL = FALSE; + attachment->storeMetaDataBlob(tdbb, transaction, &RFR.RDB$DEFAULT_SOURCE, + defaultSource); + } + + if (defaultValue.length > 0) + { + RFR.RDB$DEFAULT_VALUE.NULL = FALSE; + attachment->storeBinaryBlob(tdbb, transaction, &RFR.RDB$DEFAULT_VALUE, defaultValue); + } + + SLONG fieldPos = -1; + + if (position.specified) + fieldPos = position.value; + else + { + DYN_UTIL_generate_field_position(tdbb, NULL, name, &fieldPos); + if (fieldPos >= 0) + ++fieldPos; + } + + if (fieldPos >= 0) + { + RFR.RDB$FIELD_POSITION.NULL = FALSE; + RFR.RDB$FIELD_POSITION = SSHORT(fieldPos); + } + + if (baseField.hasData()) + { + RFR.RDB$BASE_FIELD.NULL = FALSE; + strcpy(RFR.RDB$BASE_FIELD, baseField.c_str()); + } + + if (viewContext.specified) + { + fb_assert(baseField.hasData()); + + RFR.RDB$VIEW_CONTEXT.NULL = FALSE; + RFR.RDB$VIEW_CONTEXT = viewContext.value; + + DYN_UTIL_find_field_source(tdbb, transaction, relationName, viewContext.value, + baseField.c_str(), RFR.RDB$FIELD_SOURCE); + } + } + END_STORE +} + // Delete local field. // // The rules for dropping a regular column: @@ -4828,6 +5022,29 @@ void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, } } +void RelationNode::storePrivileges(thread_db* tdbb, jrd_tra* transaction) +{ + Attachment* attachment = transaction->tra_attachment; + + AutoCacheRequest request(tdbb, drq_s_usr_prvs, DYN_REQUESTS); + + for (const TEXT* p = ALL_PRIVILEGES; *p; ++p) + { + STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$USER_PRIVILEGES + { + strcpy(X.RDB$RELATION_NAME, name.c_str()); + strcpy(X.RDB$USER, attachment->att_user->usr_user_name.c_str()); + X.RDB$USER_TYPE = obj_user; + X.RDB$OBJECT_TYPE = obj_relation; + X.RDB$PRIVILEGE[0] = *p; + X.RDB$PRIVILEGE[1] = 0; + X.RDB$GRANT_OPTION = 1; + } + END_STORE + } +} + void RelationNode::defineField(thread_db* tdbb, jrd_tra* transaction, const dsql_nod* element, SSHORT position, const dsql_nod* pkCols) { @@ -4887,156 +5104,108 @@ void RelationNode::defineField(thread_db* tdbb, jrd_tra* transaction, const dsql } } - AutoCacheRequest request(tdbb, drq_s_lfields2, DYN_REQUESTS); + FieldDefinition fieldDefinition(*tdbb->getDefaultPool()); + fieldDefinition.relationName = name; + fieldDefinition.name = field->fld_name; + fieldDefinition.notNullFlag = notNullFlag; - STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - RFR IN RDB$RELATION_FIELDS + if (position >= 0) + fieldDefinition.position = position; + + const dsql_nod* domainNode = element->nod_arg[Dsql::e_dfl_domain]; + + if (domainNode) { - const dsql_nod* domainNode = element->nod_arg[Dsql::e_dfl_domain]; - MetaName fieldSource; + const dsql_nod* node1 = domainNode->nod_arg[Dsql::e_dom_name]; + const dsql_str* domainName = (dsql_str*) node1->nod_arg[Dsql::e_fln_name]; - if (domainNode) + // Get the domain information. + if (!METD_get_domain(transaction, field, domainName->str_data)) { - const dsql_nod* node1 = domainNode->nod_arg[Dsql::e_dom_name]; - const dsql_str* domainName = (dsql_str*) node1->nod_arg[Dsql::e_fln_name]; - - // Get the domain information. - if (!METD_get_domain(transaction, field, domainName->str_data)) - { - // Specified domain or source field does not exist - status_exception::raise( - Arg::Gds(isc_sqlerr) << Arg::Num(-607) << - Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_domain_not_found) << domainName->str_data); - } - - fieldSource = domainName->str_data; - } - else - { - string computedSource; - BlrWriter::BlrData computedValue; - - if (element->nod_arg[e_dfl_computed]) - { - field->fld_flags |= FLD_computed; - - defineComputed(tdbb, field, element->nod_arg[e_dfl_computed], - computedSource, computedValue); - } - - TypeClause fieldType(field, NULL); // Don't use the collate in the generated domain. - fieldType.resolve(dsqlScratch); - - // Generate a domain. - storeGlobalField(tdbb, transaction, fieldSource, fieldType, - computedSource, computedValue); - } - - if ((relation->rel_flags & REL_external) && - (field->fld_dtype == dtype_blob || field->fld_dtype == dtype_array || - field->fld_dimensions)) - { - const char* typeName = (field->fld_dtype == dtype_blob ? "BLOB" : "ARRAY"); - + // Specified domain or source field does not exist status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-607) << Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_dsql_type_not_supp_ext_tab) << typeName << name << field->fld_name); + Arg::Gds(isc_dsql_domain_not_found) << domainName->str_data); } - strcpy(RFR.RDB$FIELD_NAME, field->fld_name.c_str()); - strcpy(RFR.RDB$FIELD_SOURCE, fieldSource.c_str()); - strcpy(RFR.RDB$RELATION_NAME, name.c_str()); - RFR.RDB$SYSTEM_FLAG = 0; + fieldDefinition.fieldSource = domainName->str_data; + } + else + { + string computedSource; + BlrWriter::BlrData computedValue; - RFR.RDB$NULL_FLAG.NULL = TRUE; - RFR.RDB$BASE_FIELD.NULL = TRUE; - RFR.RDB$UPDATE_FLAG.NULL = TRUE; - RFR.RDB$FIELD_POSITION.NULL = TRUE; - RFR.RDB$VIEW_CONTEXT.NULL = TRUE; - RFR.RDB$DEFAULT_VALUE.NULL = TRUE; - RFR.RDB$DEFAULT_SOURCE.NULL = TRUE; - RFR.RDB$COLLATION_ID.NULL = TRUE; - RFR.RDB$GENERATOR_NAME.NULL = TRUE; - RFR.RDB$IDENTITY_TYPE.NULL = TRUE; - - if (element->nod_arg[Dsql::e_dfl_collate]) + if (element->nod_arg[e_dfl_computed]) { - DDL_resolve_intl_type(dsqlScratch, field, (dsql_str*) element->nod_arg[Dsql::e_dfl_collate]); + field->fld_flags |= FLD_computed; - RFR.RDB$COLLATION_ID.NULL = FALSE; - RFR.RDB$COLLATION_ID = SSHORT(field->fld_collation_id); + defineComputed(tdbb, field, element->nod_arg[e_dfl_computed], + computedSource, computedValue); } - if (element->nod_arg[Dsql::e_dfl_identity]) + TypeClause fieldType(field, NULL); // Don't use the collate in the generated domain. + fieldType.resolve(dsqlScratch); + + // Generate a domain. + storeGlobalField(tdbb, transaction, fieldDefinition.fieldSource, fieldType, + computedSource, computedValue); + } + + if ((relation->rel_flags & REL_external) && + (field->fld_dtype == dtype_blob || field->fld_dtype == dtype_array || + field->fld_dimensions)) + { + const char* typeName = (field->fld_dtype == dtype_blob ? "BLOB" : "ARRAY"); + + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_dsql_type_not_supp_ext_tab) << typeName << name << field->fld_name); + } + + if (element->nod_arg[Dsql::e_dfl_collate]) + DDL_resolve_intl_type(dsqlScratch, field, (dsql_str*) element->nod_arg[Dsql::e_dfl_collate]); + + if (element->nod_arg[Dsql::e_dfl_identity]) + { + dsc desc; + MET_get_domain(tdbb, fieldDefinition.fieldSource, &desc, NULL); + + if (!desc.isExact() || desc.dsc_scale != 0) { - dsc desc; - MET_get_domain(tdbb, fieldSource, &desc, NULL); - - if (!desc.isExact() || desc.dsc_scale != 0) - { - // Identity column @1 of table @2 must be exact numeric with zero scale. - status_exception::raise( - Arg::Gds(ENCODE_ISC_MSG(273, DYN_MSG_FAC)) << field->fld_name << name); - } - - MetaName sequenceName; - DYN_UTIL_generate_generator_name(tdbb, sequenceName); - - CreateSequenceNode::store(tdbb, transaction, sequenceName, - fb_sysflag_identity_generator); - - RFR.RDB$GENERATOR_NAME.NULL = FALSE; - strcpy(RFR.RDB$GENERATOR_NAME, sequenceName.c_str()); - - RFR.RDB$IDENTITY_TYPE.NULL = FALSE; - RFR.RDB$IDENTITY_TYPE = IDENT_TYPE_BY_DEFAULT; + // Identity column @1 of table @2 must be exact numeric with zero scale. + status_exception::raise( + Arg::Gds(ENCODE_ISC_MSG(273, DYN_MSG_FAC)) << field->fld_name << name); } - if (notNullFlag) + DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence); + + CreateSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence, + fb_sysflag_identity_generator); + } + + BlrWriter::BlrData defaultValue; + + if (element->nod_arg[Dsql::e_dfl_default]) + { + if (defineDefault(tdbb, field, element->nod_arg[Dsql::e_dfl_default], + fieldDefinition.defaultSource, defaultValue) && + notNullFlag) { - RFR.RDB$NULL_FLAG.NULL = FALSE; - RFR.RDB$NULL_FLAG = TRUE; - } - - if (element->nod_arg[Dsql::e_dfl_default]) - { - string defaultSource; - BlrWriter::BlrData defaultValue; - - if (defineDefault(tdbb, field, element->nod_arg[Dsql::e_dfl_default], defaultSource, - defaultValue) && - notNullFlag) - { - status_exception::raise( - Arg::Gds(isc_sqlerr) << Arg::Num(-204) << - Arg::Gds(isc_bad_default_value) << - Arg::Gds(isc_invalid_clause) << "default null not null"); - } - - RFR.RDB$DEFAULT_SOURCE.NULL = FALSE; - attachment->storeMetaDataBlob(tdbb, transaction, &RFR.RDB$DEFAULT_SOURCE, defaultSource); - - RFR.RDB$DEFAULT_VALUE.NULL = FALSE; - attachment->storeBinaryBlob(tdbb, transaction, &RFR.RDB$DEFAULT_VALUE, defaultValue); - } - - if (position == -1) - { - SLONG fieldPos = -1; - DYN_UTIL_generate_field_position(tdbb, NULL, name, &fieldPos); - if (fieldPos >= 0) - position = SSHORT(fieldPos + 1); - } - - if (position >= 0) - { - RFR.RDB$FIELD_POSITION.NULL = FALSE; - RFR.RDB$FIELD_POSITION = position; + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-204) << + Arg::Gds(isc_bad_default_value) << + Arg::Gds(isc_invalid_clause) << "default null not null"); } } - END_STORE + + fieldDefinition.defaultValue = defaultValue; + + if (element->nod_arg[Dsql::e_dfl_collate]) + fieldDefinition.collationId = field->fld_collation_id; + + fieldDefinition.store(tdbb, transaction); // Define the field constraints. for (ObjectsArray::iterator constraint(constraints.begin()); @@ -5130,7 +5299,7 @@ void RelationNode::defineComputed(thread_db* tdbb, dsql_fld* field, dsql_nod* no if (field->fld_dtype <= dtype_any_text) { field->fld_character_set_id = DSC_GET_CHARSET(&desc); - field->fld_collation_id= DSC_GET_COLLATE(&desc); + field->fld_collation_id = DSC_GET_COLLATE(&desc); } else field->fld_sub_type = desc.dsc_sub_type; @@ -5639,9 +5808,7 @@ void RelationNode::defineCheckConstraint(Constraint& constraint, dsql_nod* node) void RelationNode::defineCheckConstraintTrigger(Constraint& constraint, dsql_nod* node, FB_UINT64 triggerType) { - // See hack at pass1_field. - AutoSetRestore2 autoDdlNode(dsqlScratch->getStatement(), - &DsqlCompiledStatement::getDdlNode, &DsqlCompiledStatement::setDdlNode, node); + AutoSetRestore autoCheckConstraintTrigger(&dsqlScratch->checkConstraintTrigger, true); Constraint::BlrWriter& blrWriter = constraint.blrWritersHolder.add(); blrWriter.init(dsqlScratch); @@ -6085,7 +6252,7 @@ void CreateRelationNode::execute(thread_db* tdbb, jrd_tra* transaction) { Attachment* attachment = transaction->tra_attachment; - saveRelation(tdbb, dsqlScratch, MAKE_cstring(name.c_str()), true); + saveRelation(tdbb, dsqlScratch, name, false, true); if (externalFile) { @@ -6145,23 +6312,7 @@ void CreateRelationNode::execute(thread_db* tdbb, jrd_tra* transaction) } END_STORE - for (const TEXT* p = ALL_PRIVILEGES; *p; ++p) - { - request.reset(tdbb, drq_s_usr_prvs, DYN_REQUESTS); - - STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) - X IN RDB$USER_PRIVILEGES - { - strcpy(X.RDB$RELATION_NAME, name.c_str()); - strcpy(X.RDB$USER, attachment->att_user->usr_user_name.c_str()); - X.RDB$USER_TYPE = obj_user; - X.RDB$OBJECT_TYPE = obj_relation; - X.RDB$PRIVILEGE[0] = *p; - X.RDB$PRIVILEGE[1] = 0; - X.RDB$GRANT_OPTION = 1; - } - END_STORE - } + storePrivileges(tdbb, transaction); ObjectsArray constraints; const dsql_nod* pkCols = findPkColumns(); @@ -6241,7 +6392,7 @@ void AlterRelationNode::execute(thread_db* tdbb, jrd_tra* transaction) { Attachment* attachment = transaction->tra_attachment; - saveRelation(tdbb, dsqlScratch, MAKE_cstring(name.c_str()), false); + saveRelation(tdbb, dsqlScratch, name, false, false); if (!dsqlScratch->relation) { @@ -7076,8 +7227,7 @@ void DropRelationNode::print(string& text, Array& /*nodes*/) const void DropRelationNode::execute(thread_db* tdbb, jrd_tra* transaction) { - AutoPtr nameStr(MAKE_string(name.c_str(), name.length())); - const dsql_rel* relation = METD_get_relation(transaction, dsqlScratch, nameStr); + const dsql_rel* relation = METD_get_relation(transaction, dsqlScratch, name); if (!relation && silent) return; @@ -7141,6 +7291,927 @@ void RecreateRelationNode::execute(thread_db* tdbb, jrd_tra* transaction) //---------------------- +void CreateAlterViewNode::print(string& text, Array& /*nodes*/) const +{ + text.printf( + "CreateAlterViewNode\n" + " name: '%s'\n", + name.c_str()); +} + +void CreateAlterViewNode::execute(thread_db* tdbb, jrd_tra* transaction) +{ + Attachment* attachment = transaction->tra_attachment; + + const dsql_rel* modifyingView = NULL; + + if (alter) + { + modifyingView = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, name); + + if (!modifyingView && !create) + status_exception::raise(Arg::Gds(isc_dyn_view_not_found) << name); + } + + saveRelation(tdbb, dsqlScratch, name, true, modifyingView == NULL); + + // run all statements under savepoint control + AutoSavePoint savePoint(tdbb, transaction); + + const int ddlTriggerAction = (modifyingView ? DDL_TRIGGER_ALTER_VIEW : DDL_TRIGGER_CREATE_VIEW); + + executeDdlTrigger(tdbb, transaction, DTW_BEFORE, ddlTriggerAction, name); + + if (!modifyingView) + DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_relation); + + // 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; + selectExpr->nod_flags |= NOD_SELECT_VIEW_FIELDS; + dsql_nod* rse = PASS1_rse(dsqlScratch, selectExpr, NULL); + + dsqlScratch->getBlrData().clear(); + dsqlScratch->appendUChar(dsqlScratch->isVersion4() ? blr_version4 : blr_version5); + + // 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->appendUChar(blr_eoc); + + // Store the blr and source string for the view definition. + + if (modifyingView) + { + AutoCacheRequest request(tdbb, drq_m_view, DYN_REQUESTS); + bool found = false; + + FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + REL IN RDB$RELATIONS + WITH REL.RDB$RELATION_NAME EQ name.c_str() AND + REL.RDB$VIEW_BLR NOT MISSING + { + found = true; + + MODIFY REL + attachment->storeMetaDataBlob(tdbb, transaction, &REL.RDB$VIEW_SOURCE, source); + attachment->storeBinaryBlob(tdbb, transaction, &REL.RDB$VIEW_BLR, + dsqlScratch->getBlrData()); + END_MODIFY + } + END_FOR + + if (!found) + status_exception::raise(Arg::Gds(isc_dyn_view_not_found) << name); + + AutoRequest request2; + + FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + VR IN RDB$VIEW_RELATIONS + WITH VR.RDB$VIEW_NAME EQ name.c_str() + { + ERASE VR; + } + END_FOR + + request2.reset(); + + FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + TRG IN RDB$TRIGGERS + WITH TRG.RDB$RELATION_NAME EQ name.c_str() AND + TRG.RDB$SYSTEM_FLAG EQ fb_sysflag_view_check + { + ERASE TRG; + } + END_FOR + } + else + { + AutoCacheRequest request(tdbb, drq_s_rels, DYN_REQUESTS); + + STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + REL IN RDB$RELATIONS + { + strcpy(REL.RDB$RELATION_NAME, name.c_str()); + REL.RDB$SYSTEM_FLAG = 0; + REL.RDB$FLAGS = REL_sql; + REL.RDB$RELATION_TYPE = SSHORT(rel_view); + + attachment->storeMetaDataBlob(tdbb, transaction, &REL.RDB$VIEW_SOURCE, source); + attachment->storeBinaryBlob(tdbb, transaction, &REL.RDB$VIEW_BLR, dsqlScratch->getBlrData()); + } + END_STORE + + storePrivileges(tdbb, transaction); + } + + // Define the view source relations from the statement contexts and union contexts. + + while (dsqlScratch->derivedContext.hasData()) + dsqlScratch->context->push(dsqlScratch->derivedContext.pop()); + + while (dsqlScratch->unionContext.hasData()) + dsqlScratch->context->push(dsqlScratch->unionContext.pop()); + + AutoCacheRequest request(tdbb, drq_s_view_rels, DYN_REQUESTS); + + 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) + { + const MetaName& refName = relation ? relation->rel_name : procedure->prc_name.identifier; + const char* contextName = context->ctx_alias ? context->ctx_alias : refName.c_str(); + + ViewContextType ctxType; + if (relation) + { + if (!(relation->rel_flags & REL_view)) + ctxType = VCT_TABLE; + else + ctxType = VCT_VIEW; + } + else //if (procedure) + ctxType = VCT_PROCEDURE; + + STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + VRL IN RDB$VIEW_RELATIONS + { + strcpy(VRL.RDB$VIEW_NAME, name.c_str()); + strcpy(VRL.RDB$RELATION_NAME, refName.c_str()); + VRL.RDB$CONTEXT_TYPE = SSHORT(ctxType); + VRL.RDB$VIEW_CONTEXT = context->ctx_context; + strcpy(VRL.RDB$CONTEXT_NAME, contextName); + + if (procedure && procedure->prc_name.package.hasData()) + { + VRL.RDB$PACKAGE_NAME.NULL = FALSE; + strcpy(VRL.RDB$PACKAGE_NAME, procedure->prc_name.package.c_str()); + } + else + VRL.RDB$PACKAGE_NAME.NULL = TRUE; + } + END_STORE + } + } + + // Check privileges on base tables and views. + + request.reset(tdbb, drq_l_view_rels, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + VRL IN RDB$VIEW_RELATIONS CROSS + PREL IN RDB$RELATIONS OVER RDB$RELATION_NAME + WITH VRL.RDB$PACKAGE_NAME MISSING AND + VRL.RDB$VIEW_NAME EQ name.c_str() + { + // CVC: This never matches so it causes unnecessary calls to verify, + // so I included a call to strip trailing blanks. + fb_utils::exact_name_limit(PREL.RDB$OWNER_NAME, sizeof(PREL.RDB$OWNER_NAME)); + + if (attachment->att_user->usr_user_name != PREL.RDB$OWNER_NAME) + { + SecurityClass::flags_t priv; + + // I think this should be the responsability of DFW or the user will find ways to + // circumvent DYN. + if (!DYN_UTIL_get_prot(tdbb, transaction, PREL.RDB$RELATION_NAME, "", &priv)) + { + // ASF: DYN_UTIL_get_prot will throw instead of return false. + fb_assert(false); + } + + if (!(priv & SCL_read)) + { + // msg 32: no permission for %s access to %s %s + status_exception::raise( + Arg::Gds(isc_no_priv) << Arg::Str("SELECT") << // Non-Translatable + // Remember, a view may be based on a view. + "TABLE/VIEW" << // Non-Translatable + // We want to print the name of the base table or view. + MetaName(PREL.RDB$RELATION_NAME)); + } + } + } + END_FOR + + // 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; + + if (viewFields) + { + ptr = viewFields->nod_arg; + end = ptr + viewFields->nod_count; + } + + // 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[Dsql::e_rse_items]; + dsql_nod** itemsPtr = items->nod_arg; + SortedArray modifiedFields; + bool updatable = true; + SSHORT position = 0; + + for (const dsql_nod* const* const itemsEnd = itemsPtr + items->nod_count; + itemsPtr < itemsEnd; ++itemsPtr, ++position) + { + dsql_nod* fieldNode = *itemsPtr; + + // Determine the proper field name, replacing the default if necessary. + + const dsql_nod* nameNode = fieldNode; + const dsql_str* aliasName = NULL; + + while (nameNode->nod_type == Dsql::nod_alias || + nameNode->nod_type == Dsql::nod_derived_field || + nameNode->nod_type == Dsql::nod_map) + { + switch (nameNode->nod_type) + { + case Dsql::nod_alias: + if (!aliasName) + aliasName = (dsql_str*) nameNode->nod_arg[Dsql::e_alias_alias]; + nameNode = nameNode->nod_arg[Dsql::e_alias_value]; + break; + + case Dsql::nod_derived_field: + if (!aliasName) + aliasName = (dsql_str*) nameNode->nod_arg[Dsql::e_derived_field_name]; + nameNode = nameNode->nod_arg[Dsql::e_derived_field_value]; + break; + + case Dsql::nod_map: + { + const dsql_map* map = (dsql_map*) nameNode->nod_arg[Dsql::e_map_map]; + nameNode = map->map_node; + break; + } + + default: + break; + } + } + + const dsql_fld* nameField = NULL; + + if (nameNode->nod_type == Dsql::nod_field) + nameField = (dsql_fld*) nameNode->nod_arg[Dsql::e_fld_field]; + + const TEXT* fieldStr = NULL; + + if (aliasName) + fieldStr = aliasName->str_data; + else if (nameField) + fieldStr = nameField->fld_name.c_str(); + + // Check if this is a field or an expression. + + if (fieldNode->nod_type == Dsql::nod_alias) + fieldNode = fieldNode->nod_arg[Dsql::e_alias_value]; + + dsql_fld* field = NULL; + const dsql_ctx* context = NULL; + + if (fieldNode->nod_type == Dsql::nod_field) + { + field = (dsql_fld*) fieldNode->nod_arg[Dsql::e_fld_field]; + context = (dsql_ctx*) fieldNode->nod_arg[Dsql::e_fld_context]; + } + else + updatable = false; + + // If this is an expression, check to make sure there is a name specified. + + if (!ptr && !fieldStr) + { + // must specify field name for view select expression + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + 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* fieldName = (dsql_str*) (*ptr)->nod_arg[1]; + fieldStr = fieldName->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* relField = NULL; + + if (modifyingView) // if we're modifying a view + { + for (relField = modifyingView->rel_fields; relField; relField = relField->fld_next) + { + if (relField->fld_name == fieldStr) + { + if (modifiedFields.exist(relField)) + { + // column @1 appears more than once in ALTER VIEW + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-104) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_dsql_col_more_than_once_view) << Arg::Str(fieldStr)); + } + + modifiedFields.add(relField); + break; + } + } + } + + FieldDefinition fieldDefinition(*tdbb->getDefaultPool()); + fieldDefinition.relationName = name; + fieldDefinition.name = fieldStr; + fieldDefinition.position = position; + + // 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) + { + TypeClause fieldType(field, NULL); + fieldType.resolve(dsqlScratch); + + fieldDefinition.viewContext = context->ctx_context; + fieldDefinition.baseField = field->fld_name; + + if (field->fld_dtype <= dtype_any_text) + fieldDefinition.collationId = field->fld_collation_id; + + if (relField) // modifying a view + { + // We're now modifying a field and it will be based on another one. So if the old + // field was an expression, delete it now. + + AutoRequest request2; + + FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + RFL IN RDB$RELATION_FIELDS CROSS + FLD IN RDB$FIELDS + WITH RFL.RDB$FIELD_NAME EQ fieldStr AND + RFL.RDB$RELATION_NAME EQ name.c_str() AND + RFL.RDB$BASE_FIELD MISSING AND + FLD.RDB$FIELD_NAME EQ RFL.RDB$FIELD_SOURCE + { + bool wasInternalDomain = fb_utils::implicit_domain(FLD.RDB$FIELD_NAME); + fb_assert(wasInternalDomain); + + if (wasInternalDomain) + ERASE FLD; + } + END_FOR + + fieldDefinition.modify(tdbb, transaction); + } + else + fieldDefinition.store(tdbb, transaction); + } + else + { + dsqlScratch->getBlrData().clear(); + dsqlScratch->appendUChar(dsqlScratch->isVersion4() ? blr_version4 : blr_version5); + GEN_expr(dsqlScratch, fieldNode); + dsqlScratch->appendUChar(blr_eoc); + + // Get the type of the expression. + dsc desc; + MAKE_desc(dsqlScratch, &desc, fieldNode, NULL); + + dsql_fld newField(*tdbb->getDefaultPool()); + newField.fld_dtype = desc.dsc_dtype; + newField.fld_length = desc.dsc_length; + newField.fld_scale = desc.dsc_scale; + + if (desc.isText() || (desc.isBlob() && desc.getBlobSubType() == isc_blob_text)) + { + newField.fld_character_set_id = desc.getCharSet(); + newField.fld_collation_id = desc.getTextType(); + } + + if (desc.isText()) + { + newField.fld_character_length = newField.fld_length; + newField.fld_length *= METD_get_charset_bpc( + dsqlScratch->getTransaction(), newField.fld_character_set_id); + } + else + newField.fld_sub_type = desc.dsc_sub_type; + + TypeClause fieldType(&newField, NULL); + fieldType.setup(dsqlScratch); + + if (relField) // modifying a view + { + AutoRequest request2; + + FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + RFL IN RDB$RELATION_FIELDS CROSS + FLD IN RDB$FIELDS + WITH RFL.RDB$FIELD_NAME EQ fieldStr AND + RFL.RDB$RELATION_NAME EQ name.c_str() AND + RFL.RDB$BASE_FIELD MISSING AND + FLD.RDB$FIELD_NAME EQ RFL.RDB$FIELD_SOURCE + { + bool wasInternalDomain = fb_utils::implicit_domain(FLD.RDB$FIELD_NAME); + fb_assert(wasInternalDomain); + + if (wasInternalDomain) + { + fieldDefinition.fieldSource = FLD.RDB$FIELD_NAME; + + MODIFY FLD + updateRdbFields(fieldType, + FLD.RDB$FIELD_TYPE, + FLD.RDB$FIELD_LENGTH, + FLD.RDB$FIELD_SUB_TYPE.NULL, FLD.RDB$FIELD_SUB_TYPE, + FLD.RDB$FIELD_SCALE.NULL, FLD.RDB$FIELD_SCALE, + FLD.RDB$CHARACTER_SET_ID.NULL, FLD.RDB$CHARACTER_SET_ID, + FLD.RDB$CHARACTER_LENGTH.NULL, FLD.RDB$CHARACTER_LENGTH, + FLD.RDB$FIELD_PRECISION.NULL, FLD.RDB$FIELD_PRECISION, + FLD.RDB$COLLATION_ID.NULL, FLD.RDB$COLLATION_ID, + FLD.RDB$SEGMENT_LENGTH.NULL, FLD.RDB$SEGMENT_LENGTH); + + FLD.RDB$COMPUTED_BLR.NULL = FALSE; + attachment->storeBinaryBlob(tdbb, transaction, &FLD.RDB$COMPUTED_BLR, + dsqlScratch->getBlrData()); + END_MODIFY + } + } + END_FOR + + if (fieldDefinition.fieldSource.isEmpty()) + { + storeGlobalField(tdbb, transaction, fieldDefinition.fieldSource, fieldType, + "", dsqlScratch->getBlrData()); + } + + fieldDefinition.modify(tdbb, transaction); + } + else + { + storeGlobalField(tdbb, transaction, fieldDefinition.fieldSource, fieldType, + "", dsqlScratch->getBlrData()); + + fieldDefinition.store(tdbb, transaction); + } + } + + if (fieldStr) + saveField(tdbb, dsqlScratch, fieldStr); + } + + // 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 + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_num_field_err)); + } + + if (modifyingView) // modifying a view + { + // Delete the old fields not present in the new definition. + for (dsql_fld* relField = modifyingView->rel_fields; relField; relField = relField->fld_next) + { + if (!modifiedFields.exist(relField)) + deleteLocalField(tdbb, transaction, name, relField->fld_name); + } + } + + // Setup to define triggers for WITH CHECK OPTION. + + if (withCheckOption) + { + if (!updatable) + { + // Only simple column names permitted for VIEW WITH CHECK OPTION + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_col_name_err)); + } + + dsql_nod* querySpec = selectExpr->nod_arg[Dsql::e_sel_query_spec]; + + if (querySpec->nod_type == Dsql::nod_list) + { + // Only one table allowed for VIEW WITH CHECK OPTION + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_table_view_err)); + } + + if (querySpec->nod_arg[Dsql::e_qry_from]->nod_count != 1) + { + // Only one table allowed for VIEW WITH CHECK OPTION + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_table_view_err)); + } + + if (!querySpec->nod_arg[Dsql::e_qry_where]) + { + // No where clause for VIEW WITH CHECK OPTION + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_where_err)); + } + + if (querySpec->nod_arg[Dsql::e_qry_distinct] || querySpec->nod_arg[Dsql::e_qry_group] || + querySpec->nod_arg[Dsql::e_qry_having]) + { + // DISTINCT, GROUP or HAVING not permitted for VIEW WITH CHECK OPTION + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_distinct_err)); + } + + createCheckTriggers(tdbb, transaction, items); + } + + DDL_reset_context_stack(dsqlScratch); + + executeDdlTrigger(tdbb, transaction, DTW_AFTER, ddlTriggerAction, name); + + savePoint.release(); // everything is ok + + // Update DSQL cache + METD_drop_relation(transaction, name); + MET_dsql_cache_release(tdbb, SYM_relation, name); +} + +// Generate triggers to implement the WITH CHECK OPTION clause for a VIEW. +void CreateAlterViewNode::createCheckTriggers(thread_db* tdbb, jrd_tra* transaction, dsql_nod* items) +{ + // Specify that the trigger should abort if the condition is not met. + dsql_nod* actionNode = MAKE_node(Dsql::nod_list, 1); + actionNode->nod_arg[0] = MAKE_node(Dsql::nod_gdscode, 1); + actionNode->nod_arg[0]->nod_arg[0] = (dsql_nod*) MAKE_cstring("check_constraint"); + + // Create the UPDATE trigger. + + dsql_nod* baseAndNode = NULL; + dsql_nod* baseRelation = NULL; + defineUpdateAction(dsqlScratch, &baseAndNode, &baseRelation, items); + fb_assert(baseAndNode); + fb_assert(baseRelation); + + dsql_nod* rse = MAKE_node(Dsql::nod_rse, e_rse_count); + rse->nod_arg[e_rse_boolean] = baseAndNode; + dsql_nod* temp = MAKE_node(Dsql::nod_list, 1); + rse->nod_arg[e_rse_streams] = temp; + temp->nod_arg[0] = baseRelation; + + createCheckTrigger(tdbb, dsqlScratch, rse, items, actionNode, PRE_MODIFY_TRIGGER); + createCheckTrigger(tdbb, dsqlScratch, NULL, items, actionNode, PRE_STORE_TRIGGER); +} + +// Define a trigger for a VIEW WITH CHECK OPTION. +void CreateAlterViewNode::createCheckTrigger(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, + dsql_nod* rse, dsql_nod* items, dsql_nod* actions, TriggerType triggerType) +{ + AutoSetRestore autoCheckConstraintTrigger(&dsqlScratch->checkConstraintTrigger, true); + + const dsql_nod* querySpec = selectExpr->nod_arg[Dsql::e_sel_query_spec]; + dsql_nod* relationNode = dsqlNode; + + // Generate the trigger blr. + + dsqlScratch->getBlrData().clear(); + dsqlScratch->getDebugData().clear(); + dsqlScratch->appendUChar(dsqlScratch->isVersion4() ? blr_version4 : blr_version5); + + 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* savContext = NULL; + dsql_ctx* context = NULL; + + 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(); + savContext = FB_NEW(pool) dsql_ctx(pool); + *savContext = *context; + } + } + + DDL_reset_context_stack(dsqlScratch); + + dsql_nod* tempAlias = relationNode->nod_arg[Dsql::e_rln_alias]; + + relationNode->nod_arg[Dsql::e_rln_alias] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT); + dsql_ctx* oldContext = PASS1_make_context(dsqlScratch, relationNode); + oldContext->ctx_flags |= CTX_system; + + relationNode->nod_arg[Dsql::e_rln_alias] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT); + dsql_ctx* newContext = PASS1_make_context(dsqlScratch, relationNode); + newContext->ctx_flags |= CTX_system; + + relationNode->nod_arg[Dsql::e_rln_alias] = tempAlias; + + if (savContext) + { + savContext->ctx_context = dsqlScratch->contextNumber++; + context->ctx_scope_level = dsqlScratch->scopeLevel; + dsqlScratch->context->push(savContext); + } + + // Generate the condition for firing the trigger. + + dsql_nod* condition; + + if (triggerType == PRE_MODIFY_TRIGGER) + { + dsqlScratch->appendUChar(blr_for); + + dsql_nod* temp = rse->nod_arg[Dsql::e_rse_streams]; + temp->nod_arg[0] = PASS1_node(dsqlScratch, temp->nod_arg[0]); + temp = rse->nod_arg[Dsql::e_rse_boolean]; + + rse->nod_arg[Dsql::e_rse_boolean] = PASS1_node(dsqlScratch, temp); + GEN_expr(dsqlScratch, rse); + + condition = replaceFieldNames(querySpec->nod_arg[Dsql::e_qry_where], items, + viewFields, false, NEW_CONTEXT); + } + else if (triggerType == PRE_STORE_TRIGGER) + { + condition = replaceFieldNames(querySpec->nod_arg[Dsql::e_qry_where], items, + viewFields, 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** 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->appendUChar(blr_eoc); + + DDL_reset_context_stack(dsqlScratch); + + TriggerDefinition trigger(*tdbb->getDefaultPool()); + trigger.systemFlag = fb_sysflag_view_check; + trigger.relationName = name; + trigger.type = triggerType; + trigger.blrData = dsqlScratch->getBlrData(); + trigger.store(tdbb, dsqlScratch->getTransaction()); +} + +// 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. +void CreateAlterViewNode::defineUpdateAction(DsqlCompilerScratch* dsqlScratch, + dsql_nod** baseAndNode, dsql_nod** baseRelation, dsql_nod* items) +{ + // Check whether this is an updatable view definition. + + dsql_nod* querySpec = NULL; + dsql_nod* fromList = NULL; + + if (!(querySpec = selectExpr->nod_arg[Dsql::e_sel_query_spec]) || + !(fromList = querySpec->nod_arg[Dsql::e_qry_from]) || + fromList->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* relationNode = MAKE_node(Dsql::nod_relation_name, (int) Dsql::e_rln_count); + relationNode->nod_arg[Dsql::e_rln_name] = fromList->nod_arg[0]->nod_arg[Dsql::e_rln_name]; + relationNode->nod_arg[Dsql::e_rln_alias] = (dsql_nod*) MAKE_cstring(TEMP_CONTEXT); + *baseRelation = relationNode; + + // 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* valuesNode = viewFields; + dsql_nod* fieldsNode = querySpec->nod_arg[Dsql::e_qry_list]; + + if (!fieldsNode) + { + const dsql_rel* relation = METD_get_relation(dsqlScratch->getTransaction(), + dsqlScratch, name); + DsqlNodStack field_stack; + + for (const dsql_fld* field = relation->rel_fields; field; field = field->fld_next) + { + if (!(field->fld_flags & FLD_computed)) + field_stack.push(MAKE_field_name(field->fld_name.c_str())); + } + + fieldsNode = MAKE_list(field_stack); + } + + if (!valuesNode) + valuesNode = fieldsNode; + + // Generate the list of assignments to fields in the base relation. + + dsql_nod** ptr = fieldsNode->nod_arg; + const dsql_nod* const* const end = ptr + fieldsNode->nod_count; + dsql_nod** ptr2 = valuesNode->nod_arg; + const dsql_nod* const* const end2 = ptr2 + valuesNode->nod_count; + dsql_nod* andNode = MAKE_node(Dsql::nod_and, 2); + int andArg = 0; + + for (; (ptr < end) && (ptr2 < end2); ptr++, ptr2++) + { + dsql_nod* fieldNode = *ptr; + if (fieldNode->nod_type == Dsql::nod_alias) + fieldNode = fieldNode->nod_arg[Dsql::e_alias_value]; + + // Generate the actual comparisons. + + if (fieldNode->nod_type == Dsql::nod_field_name) + { + fieldNode->nod_arg[Dsql::e_fln_context] = (dsql_nod*) MAKE_cstring(TEMP_CONTEXT); + + dsql_nod* oldValueNode = MAKE_node(Dsql::nod_field_name, (int) Dsql::e_fln_count); + oldValueNode->nod_arg[Dsql::e_fln_name] = (*ptr2)->nod_arg[Dsql::e_fln_name]; + oldValueNode->nod_arg[Dsql::e_fln_context] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT); + + dsql_nod* eqlNode = MAKE_node(Dsql::nod_eql, 2); + eqlNode->nod_arg[0] = oldValueNode; + eqlNode->nod_arg[1] = fieldNode; + + dsql_nod* nullNode1 = MAKE_node(Dsql::nod_missing, 1); + nullNode1->nod_arg[0] = oldValueNode; + dsql_nod* nullNode2 = MAKE_node(Dsql::nod_missing, 1); + nullNode2->nod_arg[0] = fieldNode; + + dsql_nod* andNode2 = MAKE_node(Dsql::nod_and, 2); + andNode2->nod_arg[0] = nullNode1; + andNode2->nod_arg[1] = nullNode2; + + dsql_nod* orNode = MAKE_node(Dsql::nod_or, 2); + orNode->nod_arg[0] = eqlNode; + orNode->nod_arg[1] = andNode2; + + if (andArg <= 1) + andNode->nod_arg[andArg++] = orNode; + else + { + dsql_nod* oldAnd = andNode; + andNode = MAKE_node(Dsql::nod_and, (int) 2); + andNode->nod_arg[0] = oldAnd; + andNode->nod_arg[1] = orNode; + } + } + } + + if (andArg <= 1) + { + andNode->nod_arg[andArg] = replaceFieldNames(querySpec->nod_arg[Dsql::e_qry_where], + items, NULL, false, TEMP_CONTEXT); + } + else + { + dsql_nod* oldAnd = andNode; + andNode = MAKE_node(Dsql::nod_and, 2); + andNode->nod_arg[0] = oldAnd; + andNode->nod_arg[1] = replaceFieldNames(querySpec->nod_arg[Dsql::e_qry_where], + items, NULL, false, TEMP_CONTEXT); + } + + *baseAndNode = andNode; +} + +// Given an input node tree, find any field name nodes and replace them according to the mapping +// provided. This is used to create view WITH CHECK OPTION. +dsql_nod* CreateAlterViewNode::replaceFieldNames(dsql_nod* input, dsql_nod* searchFields, + dsql_nod* replaceFields, bool nullThem, const char* contextName) +{ + if (!input || input->getType() != dsql_type_nod) + return input; + + const dsql_nod* const* const endo = input->nod_arg + input->nod_count; + + for (dsql_nod** ptr = input->nod_arg; ptr < endo; ++ptr) + { + if ((*ptr)->nod_type == Dsql::nod_select_expr) + { + // No subqueries permitted for VIEW WITH CHECK OPTION + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_subquery_err)); + } + + if ((*ptr)->nod_type == Dsql::nod_field_name) + { + // Found a field node, check if it needs to be replaced. + + const dsql_str* fieldName = (dsql_str*) (*ptr)->nod_arg[Dsql::e_fln_name]; + dsql_nod** search = searchFields->nod_arg; + const dsql_nod* const* const end = search + searchFields->nod_count; + dsql_nod** replace = NULL; + + if (replaceFields) + replace = replaceFields->nod_arg; + + bool found = false; + + for (; search < end; ++search, replaceFields ? ++replace : NULL) + { + const dsql_str* replaceName = NULL; + if (replaceFields) + replaceName = (dsql_str*) (*replace)->nod_arg[Dsql::e_fln_name]; + + const dsql_nod* fieldNode = *search; + const dsql_fld* field = (dsql_fld*) fieldNode->nod_arg[Dsql::e_fld_field]; + + if (field->fld_name == fieldName->str_data) + { + found = true; + + if (replaceFields) + (*ptr)->nod_arg[e_fln_name] = (*replace)->nod_arg[Dsql::e_fln_name]; + + (*ptr)->nod_arg[Dsql::e_fln_context] = (dsql_nod*) MAKE_cstring(contextName); + + } + + if (nullThem && replaceFields && + strcmp(fieldName->str_data, replaceName->str_data) == 0) + { + found = true; + } + } + + if (nullThem && !found) + (*ptr) = MAKE_node(Dsql::nod_null, 0); + } + else + { + // Recursively go through the input tree looking for field name nodes. + replaceFieldNames(*ptr, searchFields, replaceFields, nullThem, contextName); + } + } + + return input; +} + + +//---------------------- + + // Store an index. void CreateIndexNode::store(thread_db* tdbb, jrd_tra* transaction, MetaName& name, Definition& definition, MetaName* referredIndexName) diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 5089936938..9ac5a06f23 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -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 collationId; + Nullable notNullFlag; + Nullable position; + Firebird::string defaultSource; + Firebird::ByteChunk defaultValue; + Nullable 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& 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: diff --git a/src/dsql/ddl.cpp b/src/dsql/ddl.cpp index dfe2c96626..c5c6d973a5 100644 --- a/src/dsql/ddl.cpp +++ b/src/dsql/ddl.cpp @@ -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(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 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) { /************************************** diff --git a/src/dsql/dsql.h b/src/dsql/dsql.h index 087b787058..a96b4d3f90 100644 --- a/src/dsql/dsql.h +++ b/src/dsql/dsql.h @@ -207,7 +207,32 @@ class dsql_fld : public pool_alloc { 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: diff --git a/src/dsql/metd.epp b/src/dsql/metd.epp index 7f427d5f0f..cbe5b8da7d 100644 --- a/src/dsql/metd.epp +++ b/src/dsql/metd.epp @@ -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 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; } diff --git a/src/dsql/metd_proto.h b/src/dsql/metd_proto.h index f5f937bdde..bb6bb36f9f 100644 --- a/src/dsql/metd_proto.h +++ b/src/dsql/metd_proto.h @@ -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); diff --git a/src/dsql/node.h b/src/dsql/node.h index 19dadad443..0b46adcc28 100644 --- a/src/dsql/node.h +++ b/src/dsql/node.h @@ -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, diff --git a/src/dsql/parse.y b/src/dsql/parse.y index e80374deab..5639e41297 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -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 case_abbreviation case_expression case_operand case_result case_specification %type cast_specification char_length_expression character_keyword character_type -%type charset_clause check_constraint check_opt close_cursor col_opt collate_clause +%type charset_clause check_constraint close_cursor col_opt collate_clause %type column_constraint column_constraint_clause %type column_constraint_def column_constraint_list column_def +%type check_opt %type column_list column_name column_parens column_parens_opt column_select %type 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 unsigned_short_integer %type valid_symbol_name value value_list value_list_opt var_decl_opt var_declaration_item -%type variable variable_list varying_keyword version_mode view_clause +%type variable variable_list varying_keyword version_mode +%type view_clause %type when_operand where_clause while window_partition_opt %type 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; } + ; diff --git a/src/dsql/pass1.cpp b/src/dsql/pass1.cpp index 588dc1ab9f..5dbb161f91 100644 --- a/src/dsql/pass1.cpp +++ b/src/dsql/pass1.cpp @@ -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; diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index 52327173f6..a2a13cc203 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -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}, diff --git a/src/include/gen/iberror.h b/src/include/gen/iberror.h index 8c086d520f..2c889042b7 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -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 diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index 06702f5ca4..1267b46411 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -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 */ diff --git a/src/include/gen/sql_code.h b/src/include/gen/sql_code.h index ff478d101b..9b62c4f663 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -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 */ diff --git a/src/include/gen/sql_state.h b/src/include/gen/sql_state.h index 1e5b668634..b47b763b96 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -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 diff --git a/src/jrd/drq.h b/src/jrd/drq.h index 6b22b51309..b1a6f0346e 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -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 diff --git a/src/jrd/dyn.epp b/src/jrd/dyn.epp index 5c4f86813f..db9fdfd633 100644 --- a/src/jrd/dyn.epp +++ b/src/jrd/dyn.epp @@ -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; diff --git a/src/jrd/dyn_def.epp b/src/jrd/dyn_def.epp index cce1a89fbd..98bfa94cc7 100644 --- a/src/jrd/dyn_def.epp +++ b/src/jrd/dyn_def.epp @@ -575,14 +575,8 @@ void DYN_define_function_arg(Global* gbl, const UCHAR** ptr, Firebird::MetaName* } -void DYN_define_index(Global* gbl, - const UCHAR** ptr, - const Firebird::MetaName* relation_name, - UCHAR index_type, - Firebird::MetaName* new_index_name, - Firebird::MetaName* referred_index_name, - Firebird::MetaName* cnst_name, - UCHAR* ri_actionP) +void DYN_define_index(Global* gbl, const UCHAR** ptr, const Firebird::MetaName* relation_name, + UCHAR index_type) { /************************************** * @@ -599,9 +593,6 @@ void DYN_define_index(Global* gbl, UCHAR verb; Firebird::MetaName trigger_name; - if (ri_actionP) - *ri_actionP = 0; - GET_STRING(ptr, index_name); if (index_name.isEmpty()) @@ -625,9 +616,6 @@ void DYN_define_index(Global* gbl, CreateIndexNode::Definition definition; definition.type = index_type; - if (new_index_name) - *new_index_name = index_name; - if (relation_name) definition.relation = *relation_name; else if (*(*ptr)++ == isc_dyn_rel_name) @@ -666,126 +654,12 @@ void DYN_define_index(Global* gbl, DYN_put_text_blob(gbl, ptr, &definition.expressionSource); break; - // for foreign keys, point to the corresponding relation - - case isc_dyn_idx_foreign_key: - GET_STRING(ptr, definition.refRelation); - break; - - case isc_dyn_idx_ref_column: - { - MetaName& str = definition.refColumns.add(); - GET_STRING(ptr, str); - break; - } - - case isc_dyn_foreign_key_delete: - fb_assert(ri_actionP != NULL); - switch (verb = *(*ptr)++) - { - case isc_dyn_foreign_key_cascade: - *ri_actionP |= FOR_KEY_DEL_CASCADE; - if ((verb = *(*ptr)++) == isc_dyn_def_trigger) - { - DYN_define_trigger(gbl, ptr, relation_name, &trigger_name, true); - fb_assert(cnst_name); - DYN_UTIL_store_check_constraints(tdbb, gbl->gbl_transaction, *cnst_name, trigger_name); - } - else - DYN_unsupported_verb(); - break; - - case isc_dyn_foreign_key_null: - *ri_actionP |= FOR_KEY_DEL_NULL; - if ((verb = *(*ptr)++) == isc_dyn_def_trigger) - { - DYN_define_trigger(gbl, ptr, relation_name, &trigger_name, true); - fb_assert(cnst_name); - DYN_UTIL_store_check_constraints(tdbb, gbl->gbl_transaction, *cnst_name, trigger_name); - } - else - DYN_unsupported_verb(); - break; - - case isc_dyn_foreign_key_default: - *ri_actionP |= FOR_KEY_DEL_DEFAULT; - if ((verb = *(*ptr)++) == isc_dyn_def_trigger) - { - DYN_define_trigger(gbl, ptr, relation_name, &trigger_name, true); - fb_assert(cnst_name); - DYN_UTIL_store_check_constraints(tdbb, gbl->gbl_transaction, *cnst_name, trigger_name); - } - else - DYN_unsupported_verb(); - break; - - case isc_dyn_foreign_key_none: - *ri_actionP |= FOR_KEY_DEL_NONE; - break; - - default: - fb_assert(0); // should not come here - DYN_unsupported_verb(); - } - break; - - case isc_dyn_foreign_key_update: - fb_assert(ri_actionP != NULL); - switch (verb = *(*ptr)++) - { - case isc_dyn_foreign_key_cascade: - *ri_actionP |= FOR_KEY_UPD_CASCADE; - if ((verb = *(*ptr)++) == isc_dyn_def_trigger) - { - DYN_define_trigger(gbl, ptr, relation_name, &trigger_name, true); - fb_assert(cnst_name); - DYN_UTIL_store_check_constraints(tdbb, gbl->gbl_transaction, *cnst_name, trigger_name); - } - else - DYN_unsupported_verb(); - break; - - case isc_dyn_foreign_key_null: - *ri_actionP |= FOR_KEY_UPD_NULL; - if ((verb = *(*ptr)++) == isc_dyn_def_trigger) - { - DYN_define_trigger(gbl, ptr, relation_name, &trigger_name, true); - fb_assert(cnst_name); - DYN_UTIL_store_check_constraints(tdbb, gbl->gbl_transaction, *cnst_name, trigger_name); - } - else - DYN_unsupported_verb(); - break; - - case isc_dyn_foreign_key_default: - *ri_actionP |= FOR_KEY_UPD_DEFAULT; - if ((verb = *(*ptr)++) == isc_dyn_def_trigger) - { - DYN_define_trigger(gbl, ptr, relation_name, &trigger_name, true); - fb_assert(cnst_name); - DYN_UTIL_store_check_constraints(tdbb, gbl->gbl_transaction, *cnst_name, trigger_name); - } - else - DYN_unsupported_verb(); - break; - - case isc_dyn_foreign_key_none: - *ri_actionP |= FOR_KEY_UPD_NONE; - break; - - default: - fb_assert(0); // should not come here - DYN_unsupported_verb(); - } - break; - default: DYN_unsupported_verb(); } } - CreateIndexNode::store(tdbb, gbl->gbl_transaction, index_name, definition, - referred_index_name); + CreateIndexNode::store(tdbb, gbl->gbl_transaction, index_name, definition); } catch (const Exception& ex) { @@ -798,576 +672,6 @@ void DYN_define_index(Global* gbl, } -void DYN_define_local_field(Global* gbl, - const UCHAR** ptr, - const Firebird::MetaName* relation_name, - Firebird::MetaName* field_name) -{ -/************************************** - * - * D Y N _ d e f i n e _ l o c a l _ f i e l d - * - ************************************** - * - * Functional description - * Execute a dynamic ddl statement. - * - **************************************/ - UCHAR verb; - USHORT dtype, length, clength, precision; - SSHORT stype, scale; - SSHORT charset_id; - SLONG fld_pos; - - thread_db* tdbb = JRD_get_thread_data(); - - Firebird::MetaName local_field_name; - GET_STRING(ptr, local_field_name); - - SSHORT id = -1; - - try { - - AutoCacheRequest request(tdbb, drq_s_lfields, DYN_REQUESTS); - id = drq_s_lfields; - - bool lflag, sflag, slflag, scflag, clflag, prflag; - scflag = lflag = sflag = slflag = clflag = prflag = false; - bool charset_id_flag = false; - const UCHAR* blr = NULL; - const UCHAR* source = NULL; - Firebird::MetaName relation_buffer; - - STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) - RFR IN RDB$RELATION_FIELDS - { - strcpy(RFR.RDB$FIELD_NAME, local_field_name.c_str()); - strcpy(RFR.RDB$FIELD_SOURCE, RFR.RDB$FIELD_NAME); - if (field_name) { - *field_name = RFR.RDB$FIELD_NAME; - } - RFR.RDB$RELATION_NAME.NULL = TRUE; - if (relation_name) - { - strcpy(RFR.RDB$RELATION_NAME, relation_name->c_str()); - RFR.RDB$RELATION_NAME.NULL = FALSE; - } - RFR.RDB$SYSTEM_FLAG = 0; - RFR.RDB$SYSTEM_FLAG.NULL = FALSE; - RFR.RDB$NULL_FLAG.NULL = TRUE; - RFR.RDB$BASE_FIELD.NULL = TRUE; - RFR.RDB$UPDATE_FLAG.NULL = TRUE; - RFR.RDB$FIELD_POSITION.NULL = TRUE; - RFR.RDB$VIEW_CONTEXT.NULL = TRUE; - RFR.RDB$QUERY_NAME.NULL = TRUE; - RFR.RDB$QUERY_HEADER.NULL = TRUE; - RFR.RDB$SECURITY_CLASS.NULL = TRUE; - RFR.RDB$DEFAULT_VALUE.NULL = TRUE; - RFR.RDB$DEFAULT_SOURCE.NULL = TRUE; - RFR.RDB$EDIT_STRING.NULL = TRUE; - RFR.RDB$COLLATION_ID.NULL = TRUE; - RFR.RDB$GENERATOR_NAME.NULL = TRUE; - RFR.RDB$IDENTITY_TYPE.NULL = TRUE; - - bool has_default = false; - - while ((verb = *(*ptr)++) != isc_dyn_end) - { - switch (verb) - { - case isc_dyn_rel_name: - GET_STRING(ptr, relation_buffer); - relation_name = &relation_buffer; - strcpy(RFR.RDB$RELATION_NAME, relation_name->c_str()); - RFR.RDB$RELATION_NAME.NULL = FALSE; - break; - - case isc_dyn_fld_source: - GET_STRING(ptr, RFR.RDB$FIELD_SOURCE); - break; - - case isc_dyn_fld_base_fld: - GET_STRING(ptr, RFR.RDB$BASE_FIELD); - RFR.RDB$BASE_FIELD.NULL = FALSE; - break; - - case isc_dyn_fld_query_name: - GET_STRING(ptr, RFR.RDB$QUERY_NAME); - RFR.RDB$QUERY_NAME.NULL = FALSE; - break; - - case isc_dyn_fld_query_header: - DYN_put_blr_blob(gbl, ptr, &RFR.RDB$QUERY_HEADER); - RFR.RDB$QUERY_HEADER.NULL = FALSE; - break; - - case isc_dyn_fld_edit_string: - GET_STRING(ptr, RFR.RDB$EDIT_STRING); - RFR.RDB$EDIT_STRING.NULL = FALSE; - break; - - case isc_dyn_fld_position: - RFR.RDB$FIELD_POSITION = (SSHORT)DYN_get_number(ptr); - RFR.RDB$FIELD_POSITION.NULL = FALSE; - break; - - case isc_dyn_system_flag: - RFR.RDB$SYSTEM_FLAG = (SSHORT)DYN_get_number(ptr); - RFR.RDB$SYSTEM_FLAG.NULL = FALSE; - break; - - case isc_dyn_fld_update_flag: - case isc_dyn_update_flag: - RFR.RDB$UPDATE_FLAG = (SSHORT)DYN_get_number(ptr); - RFR.RDB$UPDATE_FLAG.NULL = FALSE; - break; - - case isc_dyn_view_context: - RFR.RDB$VIEW_CONTEXT = (SSHORT)DYN_get_number(ptr); - RFR.RDB$VIEW_CONTEXT.NULL = FALSE; - break; - - case isc_dyn_security_class: - GET_STRING(ptr, RFR.RDB$SECURITY_CLASS); - RFR.RDB$SECURITY_CLASS.NULL = FALSE; - break; - - case isc_dyn_fld_computed_blr: - DYN_UTIL_generate_field_name(tdbb, gbl, RFR.RDB$FIELD_SOURCE); - blr = *ptr; - DYN_skip_attribute(ptr); - break; - - case isc_dyn_fld_computed_source: - source = *ptr; - DYN_skip_attribute(ptr); - break; - - case isc_dyn_fld_default_value: - has_default = true; - RFR.RDB$DEFAULT_VALUE.NULL = FALSE; - DYN_put_blr_blob(gbl, ptr, &RFR.RDB$DEFAULT_VALUE); - break; - - case isc_dyn_fld_default_source: - has_default = true; - RFR.RDB$DEFAULT_SOURCE.NULL = FALSE; - DYN_put_text_blob(gbl, ptr, &RFR.RDB$DEFAULT_SOURCE); - break; - - case isc_dyn_fld_identity: - { - MetaName sequenceName; - DYN_UTIL_generate_generator_name(tdbb, sequenceName); - - CreateSequenceNode::store(tdbb, gbl->gbl_transaction, sequenceName, - fb_sysflag_identity_generator); - - strcpy(RFR.RDB$GENERATOR_NAME, sequenceName.c_str()); - RFR.RDB$GENERATOR_NAME.NULL = FALSE; - - RFR.RDB$IDENTITY_TYPE = IDENT_TYPE_BY_DEFAULT; - RFR.RDB$IDENTITY_TYPE.NULL = FALSE; - break; - } - - case isc_dyn_fld_not_null: - RFR.RDB$NULL_FLAG.NULL = FALSE; - RFR.RDB$NULL_FLAG = TRUE; - break; - - case isc_dyn_fld_type: - dtype = (USHORT)DYN_get_number(ptr); - break; - - case isc_dyn_fld_length: - length = (USHORT)DYN_get_number(ptr); - lflag = true; - break; - - case isc_dyn_fld_sub_type: - stype = (SSHORT)DYN_get_number(ptr); - sflag = true; - break; - - case isc_dyn_fld_char_length: - clength = (USHORT)DYN_get_number(ptr); - clflag = true; - break; - - case isc_dyn_fld_segment_length: - stype = (SSHORT)DYN_get_number(ptr); - slflag = true; - break; - - case isc_dyn_fld_scale: - scale = (SSHORT)DYN_get_number(ptr); - scflag = true; - break; - - case isc_dyn_fld_precision: - precision = (USHORT)DYN_get_number(ptr); - prflag = true; - break; - - case isc_dyn_fld_character_set: - charset_id = (SSHORT)DYN_get_number(ptr); - charset_id_flag = true; - break; - - case isc_dyn_fld_collation: - RFR.RDB$COLLATION_ID.NULL = FALSE; - RFR.RDB$COLLATION_ID = (SSHORT)DYN_get_number(ptr); - break; - - default: - { - MetaNameProxy tmp(RFR.RDB$FIELD_SOURCE); - DYN_execute(gbl, ptr, relation_name, &tmp, NULL, NULL, NULL); - } - } - } - - if (has_default && DYN_UTIL_is_array(tdbb, gbl, RFR.RDB$FIELD_SOURCE)) - { - DYN_error_punt(false, 226, RFR.RDB$FIELD_SOURCE); - // msg 226: "Default value is not allowed for array type in domain %s" - } - - if (!RFR.RDB$GENERATOR_NAME.NULL) - { - dsc desc; - MET_get_domain(tdbb, RFR.RDB$FIELD_SOURCE, &desc, NULL); - - if (!desc.isExact() || desc.dsc_scale != 0) - { - // Identity column @1 of table @2 must be exact numeric with zero scale. - DYN_error_punt(false, 273, - SafeArg() << local_field_name.c_str() << relation_name->c_str()); - } - } - - if (RFR.RDB$FIELD_POSITION.NULL == TRUE) - { - fld_pos = -1; - fb_assert(relation_name); - DYN_UTIL_generate_field_position(tdbb, gbl, *relation_name, &fld_pos); - - if (fld_pos >= 0) - { - RFR.RDB$FIELD_POSITION = (SSHORT)++fld_pos; - RFR.RDB$FIELD_POSITION.NULL = FALSE; - } - } - - if (blr) - { - const SSHORT old_id = id; - AutoCacheRequest request2(tdbb, drq_s_gfields2, DYN_REQUESTS); - id = drq_s_gfields2; - - STORE(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction) - FLD IN RDB$FIELDS - { - FLD.RDB$SYSTEM_FLAG = 0; - FLD.RDB$SYSTEM_FLAG.NULL = FALSE; - strcpy(FLD.RDB$FIELD_NAME, RFR.RDB$FIELD_SOURCE); - DYN_put_blr_blob(gbl, &blr, &FLD.RDB$COMPUTED_BLR); - if (source) { - DYN_put_text_blob(gbl, &source, &FLD.RDB$COMPUTED_SOURCE); - } - FLD.RDB$FIELD_TYPE = dtype; - FLD.RDB$FIELD_TYPE.NULL = FALSE; - if (lflag) - { - FLD.RDB$FIELD_LENGTH = length; - FLD.RDB$FIELD_LENGTH.NULL = FALSE; - } - else - FLD.RDB$FIELD_LENGTH.NULL = TRUE; - if (sflag) - { - FLD.RDB$FIELD_SUB_TYPE = stype; - FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE; - } - else - FLD.RDB$FIELD_SUB_TYPE.NULL = TRUE; - if (clflag) - { - FLD.RDB$CHARACTER_LENGTH = clength; - FLD.RDB$CHARACTER_LENGTH.NULL = FALSE; - } - else - FLD.RDB$CHARACTER_LENGTH.NULL = TRUE; - if (slflag) - { - FLD.RDB$SEGMENT_LENGTH = stype; - FLD.RDB$SEGMENT_LENGTH.NULL = FALSE; - } - else - FLD.RDB$SEGMENT_LENGTH.NULL = TRUE; - if (scflag) - { - FLD.RDB$FIELD_SCALE = scale; - FLD.RDB$FIELD_SCALE.NULL = FALSE; - } - else - FLD.RDB$FIELD_SCALE.NULL = TRUE; - if (prflag) - { - FLD.RDB$FIELD_PRECISION = precision; - FLD.RDB$FIELD_PRECISION.NULL = FALSE; - } - else - FLD.RDB$FIELD_PRECISION.NULL = TRUE; - if (charset_id_flag) - { - FLD.RDB$CHARACTER_SET_ID = charset_id; - FLD.RDB$CHARACTER_SET_ID.NULL = FALSE; - } - else - FLD.RDB$CHARACTER_SET_ID.NULL = TRUE; - } - END_STORE - - id = old_id; - } - - if (!RFR.RDB$VIEW_CONTEXT.NULL) - { - fb_assert(relation_name); - DYN_UTIL_find_field_source(tdbb, gbl, *relation_name, RFR.RDB$VIEW_CONTEXT, - RFR.RDB$BASE_FIELD, RFR.RDB$FIELD_SOURCE); - } - } - END_STORE - - } // try - catch (const Firebird::Exception& ex) - { - Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); - if (id == drq_s_lfields) - { - DYN_error_punt(true, 23); - // msg 23: "STORE RDB$RELATION_FIELDS failed" - } - else - { - DYN_error_punt(true, 22); - // msg 22: "STORE RDB$FIELDS failed" - } - } -} - - -void DYN_define_view(Global* gbl, const UCHAR** ptr) -{ -/************************************** - * - * D Y N _ d e f i n e _ v i e w - * - ************************************** - * - * Functional description - * Execute a dynamic ddl statement. - * - **************************************/ - Firebird::MetaName relation_name, owner_name; - Firebird::MetaName field_name; // unused, only passed empty to DYN_execute again. - - thread_db* tdbb = JRD_get_thread_data(); - Jrd::Attachment* attachment = tdbb->getAttachment(); - - GET_STRING(ptr, relation_name); - - DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_BEFORE, - DDL_TRIGGER_CREATE_VIEW, relation_name, gbl->sqlText); - - SSHORT id = -1; - - Firebird::PathName Path, Name; - - try { - - id = drq_l_rel_name; - DYN_UTIL_check_unique_name(tdbb, gbl->gbl_transaction, relation_name, obj_relation); - bool sql_prot = false; - rel_t rel_type = rel_persistent; - - AutoCacheRequest request(tdbb, drq_s_rels, DYN_REQUESTS); - id = drq_s_rels; - - STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) - REL IN RDB$RELATIONS - { - strcpy(REL.RDB$RELATION_NAME, relation_name.c_str()); - REL.RDB$SYSTEM_FLAG = 0; - REL.RDB$SYSTEM_FLAG.NULL = FALSE; - REL.RDB$VIEW_BLR.NULL = TRUE; - REL.RDB$VIEW_SOURCE.NULL = TRUE; - REL.RDB$SECURITY_CLASS.NULL = TRUE; - REL.RDB$EXTERNAL_FILE.NULL = TRUE; - REL.RDB$FLAGS = 0; - REL.RDB$FLAGS.NULL = FALSE; - REL.RDB$RELATION_TYPE.NULL = FALSE; - - 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_sql_object: - REL.RDB$FLAGS |= REL_sql; - break; - - case isc_dyn_view_blr: - REL.RDB$VIEW_BLR.NULL = FALSE; - rel_type = rel_view; - DYN_put_blr_blob(gbl, ptr, &REL.RDB$VIEW_BLR); - break; - - case isc_dyn_view_source: - DYN_put_text_blob(gbl, ptr, &REL.RDB$VIEW_SOURCE); - REL.RDB$VIEW_SOURCE.NULL = FALSE; - break; - - case isc_dyn_security_class: - GET_STRING(ptr, REL.RDB$SECURITY_CLASS); - REL.RDB$SECURITY_CLASS.NULL = FALSE; - break; - - case isc_dyn_rel_sql_protection: - REL.RDB$FLAGS |= REL_sql; - sql_prot = (bool) DYN_get_number(ptr); - break; - - default: - --(*ptr); - { - const MetaName tmp(REL.RDB$RELATION_NAME); - DYN_execute(gbl, ptr, &tmp, &field_name, NULL, NULL, NULL); - } - } - } // while - - // The relation type cannot be determined definitely inside the above loop, - // because there are many DYN codes that affect it. - REL.RDB$RELATION_TYPE = rel_type; - - if (sql_prot) - { - owner_name = attachment->att_user->usr_user_name; - - if (rel_type == rel_view) - { - const SSHORT old_id2 = id; - AutoCacheRequest request2(tdbb, drq_l_view_rels, DYN_REQUESTS); - id = drq_l_view_rels; - - FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction) - VRL IN RDB$VIEW_RELATIONS CROSS - PREL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH - VRL.RDB$PACKAGE_NAME MISSING AND - VRL.RDB$VIEW_NAME EQ relation_name.c_str() - { - // CVC: This never matches so it causes unnecessary calls to verify, - // so I included a call to strip trailing blanks. - fb_utils::exact_name_limit(PREL.RDB$OWNER_NAME, sizeof(PREL.RDB$OWNER_NAME)); - if (owner_name != PREL.RDB$OWNER_NAME) - { - SecurityClass::flags_t priv; - if (!DYN_UTIL_get_prot(tdbb, gbl, PREL.RDB$RELATION_NAME, "", &priv)) - { - // I think this should be the responsability of DFW - // or the user will find ways to circumvent DYN. - DYN_error_punt(true, 115); - // msg 115: "CREATE VIEW failed" - } - - if (!(priv & SCL_read)) - { - ERR_post_nothrow(Arg::Gds(isc_no_priv) << Arg::Str("SELECT") << // Non-Translatable - // Remember, a view may be based on a view. - Arg::Str("TABLE/VIEW") << // Non-Translatable - // We want to print the name of the base table or view. - Arg::Str(PREL.RDB$RELATION_NAME)); - // msg 32: no permission for %s access to %s %s - DYN_error_punt(true, 115); - // msg 115: "CREATE VIEW failed" - } - } - } - END_FOR - - id = old_id2; - } - } - } - END_STORE - - if (sql_prot) - { - for (const TEXT* p = ALL_PRIVILEGES; *p; p++) - { - request.reset(tdbb, drq_s_usr_prvs, DYN_REQUESTS); - id = drq_s_usr_prvs; - - STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) - X IN RDB$USER_PRIVILEGES - { - strcpy(X.RDB$RELATION_NAME, relation_name.c_str()); - strcpy(X.RDB$USER, owner_name.c_str()); - X.RDB$USER_TYPE = obj_user; - X.RDB$OBJECT_TYPE = obj_relation; - X.RDB$PRIVILEGE[0] = *p; - X.RDB$PRIVILEGE[1] = 0; - X.RDB$GRANT_OPTION = 1; - } - END_STORE - } - } - - } - catch (const Firebird::Exception& ex) - { - Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); - if (id == drq_s_rels) - { - DYN_error_punt(true, 24); - // msg 24: "STORE RDB$RELATIONS failed" - } - else if (id == drq_s_usr_prvs) - { - DYN_error_punt(true, 25); - // msg 25: "STORE RDB$USER_PRIVILEGES failed defining a relation" - } - - switch (id) - { - case drq_l_rel_name: - DYN_error_punt(true, 24); // msg 24: "STORE RDB$RELATIONS failed" - break; - case drq_l_view_rels: - DYN_error_punt(true, 115); // msg 115: "CREATE VIEW failed" - break; - } - - // Control should never reach this point, because id should - // always have one of the values test-for above. - fb_assert(false); - DYN_error_punt(true, 0); - } - - DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_AFTER, - DDL_TRIGGER_CREATE_VIEW, relation_name, gbl->sqlText); -} - - void DYN_define_role( Global* gbl, const UCHAR** ptr) { /************************************** @@ -1461,338 +765,6 @@ do_error_punt_9: } -void DYN_define_sql_field(Global* gbl, - const UCHAR** ptr, - const Firebird::MetaName* relation_name, - Firebird::MetaName* field_name) -{ -/************************************** - * - * D Y N _ d e f i n e _ s q l _ f i e l d - * - ************************************** - * - * Functional description - * Define a local, SQL field. This will require generation of - * an global field name. - * - **************************************/ - UCHAR verb; - USHORT dtype; - SLONG fld_pos; - - thread_db* tdbb = JRD_get_thread_data(); - - Firebird::MetaName sql_field_name; - GET_STRING(ptr, sql_field_name); - - SSHORT id = -1; - - try { - - AutoCacheRequest request(tdbb, drq_s_sql_lfld, DYN_REQUESTS); - id = drq_s_sql_lfld; - - STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) - RFR IN RDB$RELATION_FIELDS - { - strcpy(RFR.RDB$FIELD_NAME, sql_field_name.c_str()); - if (field_name) - *field_name = RFR.RDB$FIELD_NAME; - if (relation_name) - strcpy(RFR.RDB$RELATION_NAME, relation_name->c_str()); - RFR.RDB$SYSTEM_FLAG = 0; - RFR.RDB$SYSTEM_FLAG.NULL = FALSE; - RFR.RDB$QUERY_NAME.NULL = TRUE; - RFR.RDB$QUERY_HEADER.NULL = TRUE; - RFR.RDB$EDIT_STRING.NULL = TRUE; - RFR.RDB$FIELD_POSITION.NULL = TRUE; - RFR.RDB$VIEW_CONTEXT.NULL = TRUE; - RFR.RDB$BASE_FIELD.NULL = TRUE; - RFR.RDB$UPDATE_FLAG.NULL = TRUE; - RFR.RDB$NULL_FLAG.NULL = TRUE; - RFR.RDB$DEFAULT_SOURCE.NULL = TRUE; - RFR.RDB$DEFAULT_VALUE.NULL = TRUE; - RFR.RDB$COLLATION_ID.NULL = TRUE; - RFR.RDB$GENERATOR_NAME.NULL = TRUE; - RFR.RDB$IDENTITY_TYPE.NULL = TRUE; - - const SSHORT old_id = id; - AutoCacheRequest request2(tdbb, drq_s_sql_gfld, DYN_REQUESTS); - id = drq_s_sql_gfld; - - 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; - - bool has_dimensions = false; - bool has_default = false; - - DYN_UTIL_generate_field_name(tdbb, gbl, RFR.RDB$FIELD_SOURCE); - strcpy(FLD.RDB$FIELD_NAME, RFR.RDB$FIELD_SOURCE); - - while ((verb = *(*ptr)++) != isc_dyn_end) - { - switch (verb) - { - case isc_dyn_rel_name: - GET_STRING(ptr, RFR.RDB$RELATION_NAME); - break; - - case isc_dyn_fld_query_name: - GET_STRING(ptr, RFR.RDB$QUERY_NAME); - RFR.RDB$QUERY_NAME.NULL = FALSE; - break; - - case isc_dyn_fld_edit_string: - GET_STRING(ptr, RFR.RDB$EDIT_STRING); - RFR.RDB$EDIT_STRING.NULL = FALSE; - break; - - case isc_dyn_fld_position: - RFR.RDB$FIELD_POSITION = DYN_get_number(ptr); - RFR.RDB$FIELD_POSITION.NULL = FALSE; - break; - - case isc_dyn_view_context: - RFR.RDB$VIEW_CONTEXT = DYN_get_number(ptr); - RFR.RDB$VIEW_CONTEXT.NULL = FALSE; - break; - - case isc_dyn_system_flag: - RFR.RDB$SYSTEM_FLAG = FLD.RDB$SYSTEM_FLAG = DYN_get_number(ptr); - RFR.RDB$SYSTEM_FLAG.NULL = FLD.RDB$SYSTEM_FLAG.NULL = FALSE; - break; - - case isc_dyn_update_flag: - RFR.RDB$UPDATE_FLAG = DYN_get_number(ptr); - RFR.RDB$UPDATE_FLAG.NULL = FALSE; - break; - - case isc_dyn_fld_length: - FLD.RDB$FIELD_LENGTH = DYN_get_number(ptr); - break; - - case isc_dyn_fld_computed_blr: - FLD.RDB$COMPUTED_BLR.NULL = FALSE; - DYN_put_blr_blob(gbl, ptr, &FLD.RDB$COMPUTED_BLR); - break; - - case isc_dyn_fld_computed_source: - FLD.RDB$COMPUTED_SOURCE.NULL = FALSE; - DYN_put_text_blob(gbl, ptr, &FLD.RDB$COMPUTED_SOURCE); - break; - - case isc_dyn_fld_default_value: - if (has_dimensions) - { - DYN_error_punt(false, 225, sql_field_name.c_str()); - // msg 225: "Default value is not allowed for array type in field %s" - } - has_default = true; - RFR.RDB$DEFAULT_VALUE.NULL = FALSE; - DYN_put_blr_blob(gbl, ptr, &RFR.RDB$DEFAULT_VALUE); - break; - - case isc_dyn_fld_default_source: - if (has_dimensions) - { - DYN_error_punt(false, 225, sql_field_name.c_str()); - // msg 225: "Default value is not allowed for array type in field %s" - } - has_default = true; - RFR.RDB$DEFAULT_SOURCE.NULL = FALSE; - DYN_put_text_blob(gbl, ptr, &RFR.RDB$DEFAULT_SOURCE); - break; - - case isc_dyn_fld_validation_blr: - FLD.RDB$VALIDATION_BLR.NULL = FALSE; - DYN_put_blr_blob(gbl, ptr, &FLD.RDB$VALIDATION_BLR); - break; - - case isc_dyn_fld_identity: - { - MetaName sequenceName; - DYN_UTIL_generate_generator_name(tdbb, sequenceName); - - CreateSequenceNode::store(tdbb, gbl->gbl_transaction, sequenceName, - fb_sysflag_identity_generator); - - strcpy(RFR.RDB$GENERATOR_NAME, sequenceName.c_str()); - RFR.RDB$GENERATOR_NAME.NULL = FALSE; - - RFR.RDB$IDENTITY_TYPE = IDENT_TYPE_BY_DEFAULT; - RFR.RDB$IDENTITY_TYPE.NULL = FALSE; - break; - } - - case isc_dyn_fld_not_null: - RFR.RDB$NULL_FLAG.NULL = FALSE; - RFR.RDB$NULL_FLAG = TRUE; - break; - - case isc_dyn_fld_query_header: - DYN_put_blr_blob(gbl, ptr, &RFR.RDB$QUERY_HEADER); - RFR.RDB$QUERY_HEADER.NULL = FALSE; - break; - - case isc_dyn_fld_type: - FLD.RDB$FIELD_TYPE = dtype = DYN_get_number(ptr); - switch (dtype) - { - case blr_short: - FLD.RDB$FIELD_LENGTH = 2; - break; - - case blr_long: - case blr_float: - case blr_sql_date: - case blr_sql_time: - FLD.RDB$FIELD_LENGTH = 4; - break; - - case blr_int64: - case blr_quad: - case blr_timestamp: - case blr_double: - case blr_d_float: - FLD.RDB$FIELD_LENGTH = 8; - break; - - default: - if (dtype == blr_blob) - FLD.RDB$FIELD_LENGTH = 8; - break; - } - break; - - case isc_dyn_fld_scale: - FLD.RDB$FIELD_SCALE = DYN_get_number(ptr); - FLD.RDB$FIELD_SCALE.NULL = FALSE; - break; - - case isc_dyn_fld_precision: - FLD.RDB$FIELD_PRECISION = DYN_get_number(ptr); - FLD.RDB$FIELD_PRECISION.NULL = FALSE; - break; - - case isc_dyn_fld_sub_type: - FLD.RDB$FIELD_SUB_TYPE = DYN_get_number(ptr); - FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE; - break; - - case isc_dyn_fld_char_length: - FLD.RDB$CHARACTER_LENGTH = DYN_get_number(ptr); - FLD.RDB$CHARACTER_LENGTH.NULL = FALSE; - break; - - case isc_dyn_fld_character_set: - FLD.RDB$CHARACTER_SET_ID = DYN_get_number(ptr); - FLD.RDB$CHARACTER_SET_ID.NULL = FALSE; - break; - - case isc_dyn_fld_collation: - // Note: the global field's collation is not set, just - // the local field. There is no full "domain" - // created for the local field. - // This is the same decision for items like NULL_FLAG - RFR.RDB$COLLATION_ID = DYN_get_number(ptr); - RFR.RDB$COLLATION_ID.NULL = FALSE; - break; - - case isc_dyn_fld_dimensions: - if (has_default) - { - DYN_error_punt(false, 225, sql_field_name.c_str()); - // msg 225: "Default value is not allowed for array type in field %s" - } - has_dimensions = true; - FLD.RDB$DIMENSIONS = DYN_get_number(ptr); - FLD.RDB$DIMENSIONS.NULL = FALSE; - break; - - case isc_dyn_fld_segment_length: - FLD.RDB$SEGMENT_LENGTH = DYN_get_number(ptr); - FLD.RDB$SEGMENT_LENGTH.NULL = FALSE; - break; - - default: - --(*ptr); - { - MetaNameProxy tmp(RFR.RDB$FIELD_SOURCE); - DYN_execute(gbl, ptr, relation_name, &tmp, NULL, NULL, NULL); - } - } - } - - if (!RFR.RDB$GENERATOR_NAME.NULL) - { - bool exact = FLD.RDB$FIELD_TYPE == blr_short || FLD.RDB$FIELD_TYPE == blr_long || - FLD.RDB$FIELD_TYPE == blr_int64; - - if (!exact || FLD.RDB$FIELD_SCALE != 0) - { - // Identity column @1 of table @2 must be exact numeric with zero scale. - DYN_error_punt(false, 273, - SafeArg() << sql_field_name.c_str() << relation_name->c_str()); - } - } - - if (RFR.RDB$FIELD_POSITION.NULL == TRUE) - { - fld_pos = -1; - fb_assert(relation_name); - DYN_UTIL_generate_field_position(tdbb, gbl, *relation_name, &fld_pos); - - if (fld_pos >= 0) - { - RFR.RDB$FIELD_POSITION = ++fld_pos; - RFR.RDB$FIELD_POSITION.NULL = FALSE; - } - } - } - END_STORE - - id = old_id; - } - END_STORE - - } - catch (const Firebird::Exception& ex) - { - Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); - if (id == drq_s_sql_lfld) - { - DYN_error_punt(true, 29); - // msg 29: "STORE RDB$RELATION_FIELDS failed" - } - else - { - DYN_error_punt(true, 28); - // msg 28: "STORE RDB$FIELDS failed" - } - } -} - - void DYN_define_shadow( Global* gbl, const UCHAR** ptr) { /************************************** @@ -1855,294 +827,6 @@ void DYN_define_shadow( Global* gbl, const UCHAR** ptr) } -//// TODO: remove this function after rework on constraints and views triggers -void DYN_define_trigger(Global* gbl, - const UCHAR** ptr, - const Firebird::MetaName* relation_name, - Firebird::MetaName* trigger_name, - const bool ignore_perm) -{ -/************************************** - * - * D Y N _ d e f i n e _ t r i g g e r - * - ************************************** - * - * Functional description - * Define a trigger for a relation. - * - * - * if the ignore_perm flag is true, then this trigger must be defined - * now (and fired at run time) without making SQL permissions checks. - * In particular, one should not need control permissions on the table - * to define this trigger. Currently used to define triggers for - * cascading referential interity. - * - **************************************/ - - thread_db* tdbb = JRD_get_thread_data(); - - Firebird::MetaName t; - - GET_STRING(ptr, t); - if (t.isEmpty()) - DYN_UTIL_generate_trigger_name(tdbb, gbl->gbl_transaction, t); - - if (trigger_name) - *trigger_name = t; - - AutoCacheRequest request(tdbb, drq_s_triggers, DYN_REQUESTS); - - bool b_ending_store = false; - const UCHAR* debug_info_ptr = NULL; - - try { - - STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) - X IN RDB$TRIGGERS - { - X.RDB$TRIGGER_TYPE.NULL = TRUE; - X.RDB$TRIGGER_SEQUENCE = 0; - X.RDB$TRIGGER_SEQUENCE.NULL = FALSE; - X.RDB$TRIGGER_INACTIVE = 0; - X.RDB$TRIGGER_INACTIVE.NULL = FALSE; - X.RDB$SYSTEM_FLAG = 0; - X.RDB$SYSTEM_FLAG.NULL = FALSE; - // ODS_12_0 - X.RDB$ENTRYPOINT.NULL = TRUE; - X.RDB$ENGINE_NAME.NULL = TRUE; - - // Currently, we make no difference between ignoring permissions in - // order to define this trigger and ignoring permissions checks when the - // trigger fires. The RDB$FLAGS is used to indicate permissions checks - // when the trigger fires. Later, if we need to make a difference - // between these, then the caller should pass the required value - // of RDB$FLAGS as an extra argument to this func. - - X.RDB$FLAGS = ignore_perm ? TRG_ignore_perm : 0; - X.RDB$FLAGS.NULL = FALSE; - if (relation_name) - { - strcpy(X.RDB$RELATION_NAME, relation_name->c_str()); - X.RDB$RELATION_NAME.NULL = FALSE; - } - else - X.RDB$RELATION_NAME.NULL = TRUE; - X.RDB$TRIGGER_BLR.NULL = TRUE; - X.RDB$TRIGGER_SOURCE.NULL = TRUE; - strcpy(X.RDB$TRIGGER_NAME, t.c_str()); - - UCHAR verb; - while ((verb = *(*ptr)++) != isc_dyn_end) - { - switch (verb) - { - case isc_dyn_trg_type: - X.RDB$TRIGGER_TYPE = DYN_get_number(ptr); - X.RDB$TRIGGER_TYPE.NULL = FALSE; - break; - - case isc_dyn_sql_object: - X.RDB$FLAGS |= TRG_sql; - X.RDB$FLAGS.NULL = FALSE; - break; - - case isc_dyn_trg_sequence: - X.RDB$TRIGGER_SEQUENCE = DYN_get_number(ptr); - X.RDB$TRIGGER_SEQUENCE.NULL = FALSE; - break; - - case isc_dyn_trg_inactive: - X.RDB$TRIGGER_INACTIVE = DYN_get_number(ptr); - X.RDB$TRIGGER_INACTIVE.NULL = FALSE; - break; - - case isc_dyn_rel_name: - GET_STRING(ptr, X.RDB$RELATION_NAME); - X.RDB$RELATION_NAME.NULL = FALSE; - break; - - case isc_dyn_trg_blr: - { - const UCHAR* blr = *ptr; - DYN_skip_attribute(ptr); - DYN_put_blr_blob(gbl, &blr, &X.RDB$TRIGGER_BLR); - X.RDB$TRIGGER_BLR.NULL = FALSE; - break; - } - - case isc_dyn_trg_source: - { - const UCHAR* source = *ptr; - DYN_skip_attribute(ptr); - DYN_put_text_blob(gbl, &source, &X.RDB$TRIGGER_SOURCE); - X.RDB$TRIGGER_SOURCE.NULL = FALSE; - break; - } - - case isc_dyn_system_flag: - X.RDB$SYSTEM_FLAG = DYN_get_number(ptr); - X.RDB$SYSTEM_FLAG.NULL = FALSE; - // fb_assert(!ignore_perm || ignore_perm && - // X.RDB$SYSTEM_FLAG == fb_sysflag_referential_constraint); - break; - - case isc_dyn_debug_info: - debug_info_ptr = *ptr; - DYN_skip_attribute(ptr); - break; - - case isc_dyn_func_entry_point: - // ODS_12_0 - GET_STRING(ptr, X.RDB$ENTRYPOINT); - X.RDB$ENTRYPOINT.NULL = FALSE; - break; - - case isc_dyn_def_engine: - // ODS_12_0 - GET_STRING(ptr, X.RDB$ENGINE_NAME); - X.RDB$ENGINE_NAME.NULL = FALSE; - break; - - default: - --(*ptr); - { - const MetaName tmp(X.RDB$RELATION_NAME); - DYN_execute(gbl, ptr, &tmp, NULL, &t, NULL, NULL); - } - } - } - - if (X.RDB$RELATION_NAME.NULL && !tdbb->getAttachment()->locksmith()) - ERR_post(Arg::Gds(isc_adm_task_denied)); - - X.RDB$VALID_BLR = TRUE; - X.RDB$VALID_BLR.NULL = FALSE; - - if (debug_info_ptr) - { - X.RDB$DEBUG_INFO.NULL = FALSE; - DYN_put_blr_blob(gbl, &debug_info_ptr, &X.RDB$DEBUG_INFO); - } - else - X.RDB$DEBUG_INFO.NULL = TRUE; - - b_ending_store = true; - - // the END_STORE_SPECIAL adds the foll. lines of code to the END_STORE - // if (ignore_perm) - // request->getStatement()->flags |= JrdStatement::FLAG_IGNORE_PERM; - // after the request is compiled and before the request is sent. - // It makes the current request (to define the trigger) go through - // without checking any permissions lower in the engine - } - END_STORE_SPECIAL - - if (ignore_perm) - request->getStatement()->flags &= ~JrdStatement::FLAG_IGNORE_PERM; - - } - catch (const Firebird::Exception& ex) - { - Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); - if (b_ending_store) - { - DYN_error_punt(true, 31); - // msg 31: "DEFINE TRIGGER failed" - } - throw; - } -} - - -void DYN_define_view_relation( Global* gbl, const UCHAR** ptr, const Firebird::MetaName* view) -{ -/************************************** - * - * D Y N _ d e f i n e _ v i e w _ r e l a t i o n - * - ************************************** - * - * Functional description - * Store a RDB$VIEW_RELATION record. - * - **************************************/ - - thread_db* tdbb = JRD_get_thread_data(); - - fb_assert(view); - - AutoCacheRequest request(tdbb, drq_s_view_rels, DYN_REQUESTS); - SSHORT id = drq_s_view_rels; - - bool b_ending_store = false; - - try - { - STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction) - VRL IN RDB$VIEW_RELATIONS - { - strcpy(VRL.RDB$VIEW_NAME, view->c_str()); - GET_STRING(ptr, VRL.RDB$RELATION_NAME); - VRL.RDB$CONTEXT_NAME.NULL = TRUE; - VRL.RDB$VIEW_CONTEXT.NULL = TRUE; - VRL.RDB$CONTEXT_TYPE.NULL = TRUE; - VRL.RDB$PACKAGE_NAME.NULL = TRUE; - - UCHAR verb; - while ((verb = *(*ptr)++) != isc_dyn_end) - { - switch (verb) - { - case isc_dyn_view_context: - VRL.RDB$VIEW_CONTEXT = DYN_get_number(ptr); - VRL.RDB$VIEW_CONTEXT.NULL = FALSE; - break; - - case isc_dyn_view_context_name: - GET_STRING(ptr, VRL.RDB$CONTEXT_NAME); - VRL.RDB$CONTEXT_NAME.NULL = FALSE; - break; - - case isc_dyn_view_context_type: - VRL.RDB$CONTEXT_TYPE = DYN_get_number(ptr); - VRL.RDB$CONTEXT_TYPE.NULL = FALSE; - break; - - case isc_dyn_pkg_name: - GET_STRING(ptr, VRL.RDB$PACKAGE_NAME); - VRL.RDB$PACKAGE_NAME.NULL = FALSE; - break; - - default: - --(*ptr); - { - const MetaName tmp(VRL.RDB$RELATION_NAME); - DYN_execute(gbl, ptr, &tmp, NULL, NULL, NULL, NULL); - } - } - } - - b_ending_store = true; - } - END_STORE - } - catch (const Firebird::Exception& ex) - { - Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); - if (b_ending_store) - { - if (id == drq_s_view_rels) - { - DYN_error_punt(true, 34); - // msg 34: "STORE RDB$VIEW_RELATIONS failed" - } - } - throw; - } -} - - bool is_it_user_name(Global* gbl, const Firebird::MetaName& role_name, thread_db* tdbb) { /************************************** diff --git a/src/jrd/dyn_del.epp b/src/jrd/dyn_del.epp index 72a4c2f3db..524f81493b 100644 --- a/src/jrd/dyn_del.epp +++ b/src/jrd/dyn_del.epp @@ -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) { /************************************** diff --git a/src/jrd/dyn_df_proto.h b/src/jrd/dyn_df_proto.h index 1d0de57f42..c3ffbbf2d7 100644 --- a/src/jrd/dyn_df_proto.h +++ b/src/jrd/dyn_df_proto.h @@ -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 diff --git a/src/jrd/dyn_dl_proto.h b/src/jrd/dyn_dl_proto.h index 44d91c9e84..8bfac9d049 100644 --- a/src/jrd/dyn_dl_proto.h +++ b/src/jrd/dyn_dl_proto.h @@ -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**); diff --git a/src/jrd/dyn_md_proto.h b/src/jrd/dyn_md_proto.h index 863743c8b2..384feb3ea2 100644 --- a/src/jrd/dyn_md_proto.h +++ b/src/jrd/dyn_md_proto.h @@ -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 diff --git a/src/jrd/dyn_mod.epp b/src/jrd/dyn_mod.epp index 781091708a..109ae6dc49 100644 --- a/src/jrd/dyn_mod.epp +++ b/src/jrd/dyn_mod.epp @@ -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 // ************************************* diff --git a/src/jrd/dyn_ut_proto.h b/src/jrd/dyn_ut_proto.h index 1e6bbbbd35..263b220270 100644 --- a/src/jrd/dyn_ut_proto.h +++ b/src/jrd/dyn_ut_proto.h @@ -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&); diff --git a/src/jrd/dyn_util.epp b/src/jrd/dyn_util.epp index 8e3cb72d9d..9c7c5066c8 100644 --- a/src/jrd/dyn_util.epp +++ b/src/jrd/dyn_util.epp @@ -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); } diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index f67640af3d..6ac53db3df 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -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) -- diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index e886259fe2..1510a5b7a0 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -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); diff --git a/src/msgs/system_errors2.sql b/src/msgs/system_errors2.sql index 5b99c0d333..ea3a98c437 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -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)