DdlNodes.epp (Firebird-3.0.2.32703-0.tar.bz2) | : | DdlNodes.epp (Firebird-3.0.4.33054-0.tar.bz2) | ||
---|---|---|---|---|
skipping to change at line 51 | skipping to change at line 51 | |||
#include "../jrd/ResultSet.h" | #include "../jrd/ResultSet.h" | |||
#include "../jrd/UserManagement.h" | #include "../jrd/UserManagement.h" | |||
#include "../jrd/blb_proto.h" | #include "../jrd/blb_proto.h" | |||
#include "../jrd/cmp_proto.h" | #include "../jrd/cmp_proto.h" | |||
#include "../jrd/dfw_proto.h" | #include "../jrd/dfw_proto.h" | |||
#include "../jrd/dpm_proto.h" | #include "../jrd/dpm_proto.h" | |||
#include "../jrd/dyn_ut_proto.h" | #include "../jrd/dyn_ut_proto.h" | |||
#include "../jrd/exe_proto.h" | #include "../jrd/exe_proto.h" | |||
#include "../jrd/intl_proto.h" | #include "../jrd/intl_proto.h" | |||
#include "../common/isc_f_proto.h" | #include "../common/isc_f_proto.h" | |||
#include "../jrd/lck_proto.h" | ||||
#include "../jrd/met_proto.h" | #include "../jrd/met_proto.h" | |||
#include "../jrd/scl_proto.h" | #include "../jrd/scl_proto.h" | |||
#include "../jrd/vio_proto.h" | #include "../jrd/vio_proto.h" | |||
#include "../dsql/ddl_proto.h" | #include "../dsql/ddl_proto.h" | |||
#include "../dsql/errd_proto.h" | #include "../dsql/errd_proto.h" | |||
#include "../dsql/gen_proto.h" | #include "../dsql/gen_proto.h" | |||
#include "../dsql/make_proto.h" | #include "../dsql/make_proto.h" | |||
#include "../dsql/metd_proto.h" | #include "../dsql/metd_proto.h" | |||
#include "../dsql/pass1_proto.h" | #include "../dsql/pass1_proto.h" | |||
#include "../utilities/gsec/gsec.h" | #include "../utilities/gsec/gsec.h" | |||
skipping to change at line 88 | skipping to change at line 89 | |||
static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction, | static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction, | |||
const MetaName& relationName, const MetaName& constraintName, const MetaN ame& indexName); | const MetaName& relationName, const MetaName& constraintName, const MetaN ame& indexName); | |||
static void defineFile(thread_db* tdbb, jrd_tra* transaction, SLONG shadowNumber , bool manualShadow, | static void defineFile(thread_db* tdbb, jrd_tra* transaction, SLONG shadowNumber , bool manualShadow, | |||
bool conditionalShadow, SLONG& dbAlloc, | bool conditionalShadow, SLONG& dbAlloc, | |||
const PathName& name, SLONG start, SLONG length); | const PathName& name, SLONG start, SLONG length); | |||
static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& r elationName, | static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& r elationName, | |||
const MetaName& fieldName); | const MetaName& fieldName); | |||
static bool isItSqlRole(thread_db* tdbb, jrd_tra* transaction, const MetaName& i nputName, | static bool isItSqlRole(thread_db* tdbb, jrd_tra* transaction, const MetaName& i nputName, | |||
MetaName& outputName); | MetaName& outputName); | |||
static MetaName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, | static MetaName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, | |||
const MetaName& indexName); | const MetaName& indexName, bool& systemIndex); | |||
static const char* getRelationScopeName(const rel_t type); | static const char* getRelationScopeName(const rel_t type); | |||
static void makeRelationScopeName(string& to, const MetaName& name, const rel_t type); | static void makeRelationScopeName(string& to, const MetaName& name, const rel_t type); | |||
static void checkRelationType(const rel_t type, const MetaName& name); | static void checkRelationType(const rel_t type, const MetaName& name); | |||
static void checkFkPairTypes(const rel_t masterType, const MetaName& masterName, | static void checkFkPairTypes(const rel_t masterType, const MetaName& masterName, | |||
const rel_t childType, const MetaName& childName); | const rel_t childType, const MetaName& childName); | |||
static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction, | static void modifyLocalFieldPosition(thread_db* tdbb, jrd_tra* transaction, | |||
const MetaName& relationName, const MetaName& fieldName, USHORT newPositi on); | const MetaName& relationName, const MetaName& fieldName, USHORT newPositi on); | |||
static rel_t relationType(SSHORT relationTypeNull, SSHORT relationType); | static rel_t relationType(SSHORT relationTypeNull, SSHORT relationType); | |||
static void saveField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, const M etaName& fieldName); | static void saveField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, const M etaName& fieldName); | |||
static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, | static void saveRelation(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, | |||
skipping to change at line 325 | skipping to change at line 326 | |||
// Define a COMPUTED BY clause, for a field or an index. | // Define a COMPUTED BY clause, for a field or an index. | |||
void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relati on, dsql_fld* field, | void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode* relati on, dsql_fld* field, | |||
ValueSourceClause* clause, string& source, BlrDebugWriter::BlrData& value ) | ValueSourceClause* clause, string& source, BlrDebugWriter::BlrData& value ) | |||
{ | { | |||
// Get the table node and set up correct context. | // Get the table node and set up correct context. | |||
dsqlScratch->resetContextStack(); | dsqlScratch->resetContextStack(); | |||
// Save the size of the field if it is specified. | // Save the size of the field if it is specified. | |||
dsc saveDesc; | dsc saveDesc; | |||
saveDesc.dsc_dtype = 0; | saveDesc.dsc_dtype = 0; | |||
bool saveCharSetIdSpecified; | ||||
if (field && field->dtype) | if (field && field->dtype) | |||
{ | { | |||
fb_assert(field->dtype <= MAX_UCHAR); | fb_assert(field->dtype <= MAX_UCHAR); | |||
saveDesc.dsc_dtype = (UCHAR) field->dtype; | saveDesc.dsc_dtype = (UCHAR) field->dtype; | |||
saveDesc.dsc_length = field->length; | saveDesc.dsc_length = field->length; | |||
fb_assert(field->scale <= MAX_SCHAR); | fb_assert(field->scale <= MAX_SCHAR); | |||
saveDesc.dsc_scale = (SCHAR) field->scale; | saveDesc.dsc_scale = (SCHAR) field->scale; | |||
saveDesc.dsc_sub_type = field->subType; | saveDesc.dsc_sub_type = field->subType; | |||
saveCharSetIdSpecified = field->charSetId.specified; | ||||
field->dtype = 0; | field->dtype = 0; | |||
field->length = 0; | field->length = 0; | |||
field->scale = 0; | field->scale = 0; | |||
field->subType = 0; | field->subType = 0; | |||
} | } | |||
PASS1_make_context(dsqlScratch, relation); | PASS1_make_context(dsqlScratch, relation); | |||
ValueExprNode* input = Node::doDsqlPass(dsqlScratch, clause->value); | ValueExprNode* input = Node::doDsqlPass(dsqlScratch, clause->value); | |||
skipping to change at line 369 | skipping to change at line 372 | |||
if (saveDesc.dsc_dtype) | if (saveDesc.dsc_dtype) | |||
{ | { | |||
// Restore the field size/type overrides. | // Restore the field size/type overrides. | |||
field->dtype = saveDesc.dsc_dtype; | field->dtype = saveDesc.dsc_dtype; | |||
field->length = saveDesc.dsc_length; | field->length = saveDesc.dsc_length; | |||
field->scale = saveDesc.dsc_scale; | field->scale = saveDesc.dsc_scale; | |||
if (field->dtype <= dtype_any_text) | if (field->dtype <= dtype_any_text) | |||
{ | { | |||
field->charSetId = DSC_GET_CHARSET(&saveDesc); | field->charSetId = DSC_GET_CHARSET(&saveDesc); | |||
field->charSetId.specified = saveCharSetIdSpecified; | ||||
field->collationId = DSC_GET_COLLATE(&saveDesc); | field->collationId = DSC_GET_COLLATE(&saveDesc); | |||
} | } | |||
else | else | |||
field->subType = saveDesc.dsc_sub_type; | field->subType = saveDesc.dsc_sub_type; | |||
} | } | |||
else if (field) | else if (field) | |||
{ | { | |||
// Use size calculated. | // Use size calculated. | |||
field->dtype = desc.dsc_dtype; | field->dtype = desc.dsc_dtype; | |||
field->length = desc.dsc_length; | field->length = desc.dsc_length; | |||
skipping to change at line 390 | skipping to change at line 394 | |||
if (field->dtype <= dtype_any_text) | if (field->dtype <= dtype_any_text) | |||
{ | { | |||
field->charSetId = DSC_GET_CHARSET(&desc); | field->charSetId = DSC_GET_CHARSET(&desc); | |||
field->collationId = DSC_GET_COLLATE(&desc); | field->collationId = DSC_GET_COLLATE(&desc); | |||
} | } | |||
else | else | |||
field->subType = desc.dsc_sub_type; | field->subType = desc.dsc_sub_type; | |||
} | } | |||
if (field && field->precision == 0 && field->scale != 0) | if (field) | |||
{ | field->setExactPrecision(); | |||
switch (field->dtype) | ||||
{ | ||||
case dtype_short: | ||||
field->precision = 4; | ||||
break; | ||||
case dtype_long: | ||||
field->precision = 9; | ||||
break; | ||||
case dtype_int64: | ||||
field->precision = 18; | ||||
break; | ||||
default: | ||||
fb_assert(!DTYPE_IS_EXACT(field->dtype)); | ||||
} | ||||
} | ||||
dsqlScratch->resetContextStack(); | dsqlScratch->resetContextStack(); | |||
// Generate the source text. | // Generate the source text. | |||
source = clause->source; | source = clause->source; | |||
value.assign(dsqlScratch->getBlrData()); | value.assign(dsqlScratch->getBlrData()); | |||
} | } | |||
// Delete a record from RDB$RELATION_CONSTRAINTS based on a constraint name. | // Delete a record from RDB$RELATION_CONSTRAINTS based on a constraint name. | |||
skipping to change at line 552 | skipping to change at line 538 | |||
// Make string with relation name and type of its temporary scope. | // Make string with relation name and type of its temporary scope. | |||
static void makeRelationScopeName(string& to, const MetaName& name, const rel_t type) | static void makeRelationScopeName(string& to, const MetaName& name, const rel_t type) | |||
{ | { | |||
const char* scope = getRelationScopeName(type); | const char* scope = getRelationScopeName(type); | |||
to.printf(scope, name.c_str()); | to.printf(scope, name.c_str()); | |||
} | } | |||
// Get relation name of an index. | // Get relation name of an index. | |||
static MetaName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, | static MetaName getIndexRelationName(thread_db* tdbb, jrd_tra* transaction, | |||
const MetaName& indexName) | const MetaName& indexName, bool& systemIndex) | |||
{ | { | |||
systemIndex = false; | ||||
AutoCacheRequest request(tdbb, drq_l_index_relname, DYN_REQUESTS); | AutoCacheRequest request(tdbb, drq_l_index_relname, DYN_REQUESTS); | |||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | |||
IDX IN RDB$INDICES | IDX IN RDB$INDICES | |||
WITH IDX.RDB$INDEX_NAME EQ indexName.c_str() | WITH IDX.RDB$INDEX_NAME EQ indexName.c_str() | |||
{ | { | |||
systemIndex = IDX.RDB$SYSTEM_FLAG == 1; | ||||
return IDX.RDB$RELATION_NAME; | return IDX.RDB$RELATION_NAME; | |||
} | } | |||
END_FOR | END_FOR | |||
// msg 48: "Index not found" | // msg 48: "Index not found" | |||
status_exception::raise(Arg::PrivateDyn(48)); | status_exception::raise(Arg::PrivateDyn(48)); | |||
return ""; // silence warning | return ""; // silence warning | |||
} | } | |||
// Get relation name of an trigger. | // Get relation name of an trigger. | |||
skipping to change at line 816 | skipping to change at line 805 | |||
{ | { | |||
fieldSubTypeNull = FALSE; | fieldSubTypeNull = FALSE; | |||
fieldSubType = type->subType; | fieldSubType = type->subType; | |||
fieldScaleNull = FALSE; | fieldScaleNull = FALSE; | |||
fieldScale = 0; | fieldScale = 0; | |||
if (type->subType == isc_blob_text) | if (type->subType == isc_blob_text) | |||
{ | { | |||
characterSetIdNull = FALSE; | characterSetIdNull = FALSE; | |||
characterSetId = type->charSetId; | characterSetId = type->charSetId.value; | |||
collationIdNull = FALSE; | collationIdNull = FALSE; | |||
collationId = type->collationId; | collationId = type->collationId; | |||
} | } | |||
if (type->segLength != 0) | if (type->segLength != 0) | |||
{ | { | |||
segmentLengthNull = FALSE; | segmentLengthNull = FALSE; | |||
segmentLength = type->segLength; | segmentLength = type->segLength; | |||
} | } | |||
skipping to change at line 843 | skipping to change at line 832 | |||
fieldScaleNull = FALSE; | fieldScaleNull = FALSE; | |||
fieldScale = 0; | fieldScale = 0; | |||
if (type->charLength != 0) | if (type->charLength != 0) | |||
{ | { | |||
characterLengthNull = FALSE; | characterLengthNull = FALSE; | |||
characterLength = type->charLength; | characterLength = type->charLength; | |||
} | } | |||
characterSetIdNull = FALSE; | characterSetIdNull = FALSE; | |||
characterSetId = type->charSetId; | characterSetId = type->charSetId.value; | |||
collationIdNull = FALSE; | collationIdNull = FALSE; | |||
collationId = type->collationId; | collationId = type->collationId; | |||
} | } | |||
else | else | |||
{ | { | |||
fieldScaleNull = FALSE; | fieldScaleNull = FALSE; | |||
fieldScale = type->scale; | fieldScale = type->scale; | |||
if (DTYPE_IS_EXACT(type->dtype)) | if (DTYPE_IS_EXACT(type->dtype)) | |||
skipping to change at line 1285 | skipping to change at line 1274 | |||
case obj_exception: | case obj_exception: | |||
SCL_check_exception(tdbb, objName.identifier, SCL_alter); | SCL_check_exception(tdbb, objName.identifier, SCL_alter); | |||
break; | break; | |||
case obj_generator: | case obj_generator: | |||
SCL_check_generator(tdbb, objName.identifier, SCL_alter); | SCL_check_generator(tdbb, objName.identifier, SCL_alter); | |||
break; | break; | |||
case obj_index: | case obj_index: | |||
relationName = getIndexRelationName(tdbb, transaction, ob | bool systemIndex; | |||
jName.identifier); | relationName = getIndexRelationName(tdbb, transaction, ob | |||
jName.identifier, systemIndex); | ||||
dscName.makeText(relationName.length(), CS_METADATA, (UCH AR*) relationName.c_str()); | dscName.makeText(relationName.length(), CS_METADATA, (UCH AR*) relationName.c_str()); | |||
SCL_check_relation(tdbb, &dscName, SCL_alter); | SCL_check_relation(tdbb, &dscName, SCL_alter, systemIndex ); | |||
break; | break; | |||
case obj_sql_role: | case obj_sql_role: | |||
SCL_check_role(tdbb, objName.identifier, SCL_alter); | SCL_check_role(tdbb, objName.identifier, SCL_alter); | |||
break; | break; | |||
case obj_charset: | case obj_charset: | |||
SCL_check_charset(tdbb, objName.identifier, SCL_alter); | SCL_check_charset(tdbb, objName.identifier, SCL_alter); | |||
break; | break; | |||
skipping to change at line 1788 | skipping to change at line 1778 | |||
FUN.RDB$MODULE_NAME.NULL = TRUE; | FUN.RDB$MODULE_NAME.NULL = TRUE; | |||
FUN.RDB$ENTRYPOINT.NULL = TRUE; | FUN.RDB$ENTRYPOINT.NULL = TRUE; | |||
FUN.RDB$VALID_BLR.NULL = TRUE; | FUN.RDB$VALID_BLR.NULL = TRUE; | |||
FUN.RDB$FUNCTION_SOURCE.NULL = !(source.hasData() && (external || package.isEmpty())); | FUN.RDB$FUNCTION_SOURCE.NULL = !(source.hasData() && (external || package.isEmpty())); | |||
if (!FUN.RDB$FUNCTION_SOURCE.NULL) | if (!FUN.RDB$FUNCTION_SOURCE.NULL) | |||
attachment->storeMetaDataBlob(tdbb, trans action, &FUN.RDB$FUNCTION_SOURCE, source); | attachment->storeMetaDataBlob(tdbb, trans action, &FUN.RDB$FUNCTION_SOURCE, source); | |||
FUN.RDB$DETERMINISTIC_FLAG.NULL = FALSE; | FUN.RDB$DETERMINISTIC_FLAG.NULL = FALSE; | |||
FUN.RDB$DETERMINISTIC_FLAG = deterministic ? TRUE : FALSE; | FUN.RDB$DETERMINISTIC_FLAG = deterministic ? TRUE : FALSE; | |||
FUN.RDB$RETURN_ARGUMENT = 0; | ||||
FUN.RDB$LEGACY_FLAG.NULL = FALSE; | ||||
FUN.RDB$LEGACY_FLAG = isUdf() ? TRUE : FALSE; | ||||
if (isUdf()) | if (isUdf()) | |||
{ | { | |||
dsql_fld* field = returnType ? returnType ->type : NULL; | dsql_fld* field = returnType ? returnType ->type : NULL; | |||
if (field) | if (field) | |||
{ | { | |||
// CVC: This is case of "returns <type> [by value|reference]". | // CVC: This is case of "returns <type> [by value|reference]". | |||
// Some data types can not be ret urned as value. | // Some data types can not be ret urned as value. | |||
skipping to change at line 1982 | skipping to change at line 1976 | |||
ARG.RDB$NULL_FLAG.NULL = TRUE; | ARG.RDB$NULL_FLAG.NULL = TRUE; | |||
ARG.RDB$RELATION_NAME.NULL = TRUE; | ARG.RDB$RELATION_NAME.NULL = TRUE; | |||
ARG.RDB$FIELD_NAME.NULL = TRUE; | ARG.RDB$FIELD_NAME.NULL = TRUE; | |||
ARG.RDB$FIELD_SOURCE.NULL = TRUE; | ARG.RDB$FIELD_SOURCE.NULL = TRUE; | |||
ARG.RDB$DEFAULT_VALUE.NULL = TRUE; | ARG.RDB$DEFAULT_VALUE.NULL = TRUE; | |||
ARG.RDB$DEFAULT_SOURCE.NULL = TRUE; | ARG.RDB$DEFAULT_SOURCE.NULL = TRUE; | |||
ARG.RDB$MECHANISM.NULL = TRUE; | ARG.RDB$MECHANISM.NULL = TRUE; | |||
ARG.RDB$FIELD_TYPE.NULL = TRUE; | ARG.RDB$FIELD_TYPE.NULL = TRUE; | |||
ARG.RDB$FIELD_LENGTH.NULL = TRUE; | ARG.RDB$FIELD_LENGTH.NULL = TRUE; | |||
ARG.RDB$FIELD_SUB_TYPE.NULL = TRUE; | ||||
ARG.RDB$FIELD_PRECISION.NULL = TRUE; | ARG.RDB$FIELD_PRECISION.NULL = TRUE; | |||
ARG.RDB$FIELD_SCALE.NULL = TRUE; | ARG.RDB$FIELD_SCALE.NULL = TRUE; | |||
ARG.RDB$CHARACTER_SET_ID.NULL = TRUE; | ARG.RDB$CHARACTER_SET_ID.NULL = TRUE; | |||
ARG.RDB$CHARACTER_LENGTH.NULL = TRUE; | ||||
ARG.RDB$COLLATION_ID.NULL = TRUE; | ARG.RDB$COLLATION_ID.NULL = TRUE; | |||
ARG.RDB$ARGUMENT_MECHANISM.NULL = TRUE; | ARG.RDB$ARGUMENT_MECHANISM.NULL = TRUE; | |||
if (!isUdf()) | if (!isUdf()) | |||
{ | { | |||
ARG.RDB$ARGUMENT_MECHANISM.NULL = FALSE; | ARG.RDB$ARGUMENT_MECHANISM.NULL = FALSE; | |||
ARG.RDB$ARGUMENT_MECHANISM = (USHORT) (type->fullDomain | | type->typeOfName.isEmpty() ? | ARG.RDB$ARGUMENT_MECHANISM = (USHORT) (type->fullDomain | | type->typeOfName.isEmpty() ? | |||
prm_mech_normal : prm_mech_type_of); | prm_mech_normal : prm_mech_type_of); | |||
} | } | |||
skipping to change at line 3430 | skipping to change at line 3426 | |||
Arg::Gds(isc_dsql_command_err) << | Arg::Gds(isc_dsql_command_err) << | |||
Arg::Gds(isc_dsql_incompatible_trigger_type)); | Arg::Gds(isc_dsql_incompatible_trigger_type)); | |||
} | } | |||
} | } | |||
return DdlNode::dsqlPass(dsqlScratch); | return DdlNode::dsqlPass(dsqlScratch); | |||
} | } | |||
bool CreateAlterTriggerNode::checkPermission(thread_db* tdbb, jrd_tra* transacti on) | bool CreateAlterTriggerNode::checkPermission(thread_db* tdbb, jrd_tra* transacti on) | |||
{ | { | |||
if (!create) | ||||
{ | ||||
AutoRequest requestHandle; | ||||
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) | ||||
TRG IN RDB$TRIGGERS | ||||
WITH TRG.RDB$TRIGGER_NAME EQ name.c_str() | ||||
{ | ||||
if (!type.specified && !TRG.RDB$TRIGGER_TYPE.NULL) | ||||
type = TRG.RDB$TRIGGER_TYPE; | ||||
if (relationName.isEmpty() && !TRG.RDB$RELATION_NAME.NULL | ||||
) | ||||
relationName = TRG.RDB$RELATION_NAME; | ||||
} | ||||
END_FOR | ||||
if (!type.specified) | ||||
status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) | ||||
<< Arg::Str(name)); | ||||
} | ||||
if (relationName.hasData()) | if (relationName.hasData()) | |||
{ | { | |||
dsc dscName; | dsc dscName; | |||
dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) rel ationName.c_str()); | dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) rel ationName.c_str()); | |||
SCL_check_relation(tdbb, &dscName, SCL_alter); | SCL_check_relation(tdbb, &dscName, SCL_alter); | |||
} | } | |||
else | else | |||
SCL_check_database(tdbb, SCL_alter); | SCL_check_database(tdbb, SCL_alter); | |||
return true; | return true; | |||
skipping to change at line 3454 | skipping to change at line 3470 | |||
{ | { | |||
fb_assert(create || alter); | fb_assert(create || alter); | |||
Attachment* const attachment = transaction->getAttachment(); | Attachment* const attachment = transaction->getAttachment(); | |||
source.ltrim("\n\r\t "); | source.ltrim("\n\r\t "); | |||
// run all statements under savepoint control | // run all statements under savepoint control | |||
AutoSavePoint savePoint(tdbb, transaction); | AutoSavePoint savePoint(tdbb, transaction); | |||
if (!create) | ||||
{ | ||||
AutoRequest requestHandle; | ||||
FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) | ||||
TRG IN RDB$TRIGGERS | ||||
WITH TRG.RDB$TRIGGER_NAME EQ name.c_str() | ||||
{ | ||||
if (!type.specified && !TRG.RDB$TRIGGER_TYPE.NULL) | ||||
type = TRG.RDB$TRIGGER_TYPE; | ||||
if (relationName.isEmpty() && !TRG.RDB$RELATION_NAME.NULL | ||||
) | ||||
relationName = TRG.RDB$RELATION_NAME; | ||||
} | ||||
END_FOR | ||||
if (!type.specified) | ||||
status_exception::raise(Arg::Gds(isc_dyn_trig_not_found) | ||||
<< Arg::Str(name)); | ||||
} | ||||
compile(tdbb, dsqlScratch); | compile(tdbb, dsqlScratch); | |||
blrData = dsqlScratch->getBlrData(); | blrData = dsqlScratch->getBlrData(); | |||
debugData = dsqlScratch->getDebugData(); | debugData = dsqlScratch->getDebugData(); | |||
if (alter) | if (alter) | |||
{ | { | |||
if (!modify(tdbb, dsqlScratch, transaction)) | if (!modify(tdbb, dsqlScratch, transaction)) | |||
{ | { | |||
if (create) // create or alter | if (create) // create or alter | |||
skipping to change at line 4889 | skipping to change at line 4885 | |||
// Not valid for domains, but may be impo rtant for a future refactor. | // Not valid for domains, but may be impo rtant for a future refactor. | |||
case dtype_cstring: | case dtype_cstring: | |||
--typeLength; | --typeLength; | |||
break; | break; | |||
default: | default: | |||
break; | break; | |||
} | } | |||
DSC_make_descriptor(&newDom.dyn_dsc, blr_dtypes[t ype->dtype], type->scale, | DSC_make_descriptor(&newDom.dyn_dsc, blr_dtypes[t ype->dtype], type->scale, | |||
typeLength, type->subType, type->charSetI d, type->collationId); | typeLength, type->subType, type->charSetI d.value, type->collationId); | |||
newDom.dyn_fld_name = name; | newDom.dyn_fld_name = name; | |||
newDom.dyn_charbytelen = typeLength; | newDom.dyn_charbytelen = typeLength; | |||
newDom.dyn_dtype = blr_dtypes[type->dtype]; | newDom.dyn_dtype = blr_dtypes[type->dtype]; | |||
newDom.dyn_precision = type->precision; | newDom.dyn_precision = type->precision; | |||
newDom.dyn_sub_type = type->subType; | newDom.dyn_sub_type = type->subType; | |||
newDom.dyn_charlen = type->charLength; | newDom.dyn_charlen = type->charLength; | |||
newDom.dyn_collation = type->collationId; | newDom.dyn_collation = type->collationId; | |||
newDom.dyn_null_flag = type->notNull; | newDom.dyn_null_flag = type->notNull; | |||
skipping to change at line 8659 | skipping to change at line 8655 | |||
{ | { | |||
newField.charSetId = desc.getCharSet(); | newField.charSetId = desc.getCharSet(); | |||
newField.collationId = desc.getCollation(); | newField.collationId = desc.getCollation(); | |||
} | } | |||
if (desc.isText()) | if (desc.isText()) | |||
{ | { | |||
const USHORT adjust = | const USHORT adjust = | |||
(desc.dsc_dtype == dtype_varying) ? sizeo f(USHORT) : 0; | (desc.dsc_dtype == dtype_varying) ? sizeo f(USHORT) : 0; | |||
const USHORT bpc = | const USHORT bpc = | |||
METD_get_charset_bpc(dsqlScratch->getTran saction(), newField.charSetId); | METD_get_charset_bpc(dsqlScratch->getTran saction(), newField.charSetId.value); | |||
newField.charLength = (newField.length - adjust) / bpc; | newField.charLength = (newField.length - adjust) / bpc; | |||
} | } | |||
else | else | |||
newField.subType = desc.dsc_sub_type; | newField.subType = desc.dsc_sub_type; | |||
newField.setExactPrecision(); | ||||
if (relField) // modifying a view | if (relField) // modifying a view | |||
{ | { | |||
AutoRequest request2; | AutoRequest request2; | |||
FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE tr ansaction) | FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE tr ansaction) | |||
RFL IN RDB$RELATION_FIELDS CROSS | RFL IN RDB$RELATION_FIELDS CROSS | |||
FLD IN RDB$FIELDS | FLD IN RDB$FIELDS | |||
WITH RFL.RDB$FIELD_NAME EQ fieldStr AND | WITH RFL.RDB$FIELD_NAME EQ fieldStr AND | |||
RFL.RDB$RELATION_NAME EQ name.c_ str() AND | RFL.RDB$RELATION_NAME EQ name.c_ str() AND | |||
RFL.RDB$BASE_FIELD MISSING AND | RFL.RDB$BASE_FIELD MISSING AND | |||
skipping to change at line 9381 | skipping to change at line 9379 | |||
NODE_PRINT(printer, computed); | NODE_PRINT(printer, computed); | |||
return "CreateIndexNode"; | return "CreateIndexNode"; | |||
} | } | |||
bool CreateIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | bool CreateIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | |||
{ | { | |||
dsc dscName; | dsc dscName; | |||
const MetaName &relationName = relation->dsqlName; | const MetaName &relationName = relation->dsqlName; | |||
dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationNam e.c_str()); | dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationNam e.c_str()); | |||
SCL_check_relation(tdbb, &dscName, SCL_alter); | SCL_check_relation(tdbb, &dscName, SCL_alter, false); | |||
return true; | return true; | |||
} | } | |||
// Define an index. | // Define an index. | |||
void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) | void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) | |||
{ | { | |||
Attachment* const attachment = transaction->tra_attachment; | Attachment* const attachment = transaction->tra_attachment; | |||
// run all statements under savepoint control | // run all statements under savepoint control | |||
AutoSavePoint savePoint(tdbb, transaction); | AutoSavePoint savePoint(tdbb, transaction); | |||
skipping to change at line 9447 | skipping to change at line 9445 | |||
DdlNode::internalPrint(printer); | DdlNode::internalPrint(printer); | |||
NODE_PRINT(printer, name); | NODE_PRINT(printer, name); | |||
NODE_PRINT(printer, active); | NODE_PRINT(printer, active); | |||
return "AlterIndexNode"; | return "AlterIndexNode"; | |||
} | } | |||
bool AlterIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | bool AlterIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | |||
{ | { | |||
MetaName relationName = getIndexRelationName(tdbb, transaction, name); | bool systemIndex; | |||
MetaName relationName = getIndexRelationName(tdbb, transaction, name, sys | ||||
temIndex); | ||||
dsc dscName; | dsc dscName; | |||
dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationNam e.c_str()); | dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationNam e.c_str()); | |||
SCL_check_relation(tdbb, &dscName, SCL_alter); | SCL_check_relation(tdbb, &dscName, SCL_alter, systemIndex); | |||
return true; | return true; | |||
} | } | |||
void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) | void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) | |||
{ | { | |||
// run all statements under savepoint control | // run all statements under savepoint control | |||
AutoSavePoint savePoint(tdbb, transaction); | AutoSavePoint savePoint(tdbb, transaction); | |||
AutoCacheRequest request(tdbb, drq_m_index, DYN_REQUESTS); | AutoCacheRequest request(tdbb, drq_m_index, DYN_REQUESTS); | |||
bool found = false; | bool found = false; | |||
skipping to change at line 9507 | skipping to change at line 9506 | |||
{ | { | |||
DdlNode::internalPrint(printer); | DdlNode::internalPrint(printer); | |||
NODE_PRINT(printer, name); | NODE_PRINT(printer, name); | |||
return "SetStatisticsNode"; | return "SetStatisticsNode"; | |||
} | } | |||
bool SetStatisticsNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | bool SetStatisticsNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | |||
{ | { | |||
MetaName relationName = getIndexRelationName(tdbb, transaction, name); | bool systemIndex; | |||
MetaName relationName = getIndexRelationName(tdbb, transaction, name, sys | ||||
temIndex); | ||||
dsc dscName; | dsc dscName; | |||
dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationNam e.c_str()); | dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationNam e.c_str()); | |||
SCL_check_relation(tdbb, &dscName, SCL_alter, false); | SCL_check_relation(tdbb, &dscName, SCL_alter, false); | |||
return true; | return true; | |||
} | } | |||
void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc h, jrd_tra* transaction) | void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc h, jrd_tra* transaction) | |||
{ | { | |||
skipping to change at line 9586 | skipping to change at line 9586 | |||
{ | { | |||
DdlNode::internalPrint(printer); | DdlNode::internalPrint(printer); | |||
NODE_PRINT(printer, name); | NODE_PRINT(printer, name); | |||
return "DropIndexNode"; | return "DropIndexNode"; | |||
} | } | |||
bool DropIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | bool DropIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | |||
{ | { | |||
MetaName relationName = getIndexRelationName(tdbb, transaction, name); | bool systemIndex; | |||
MetaName relationName = getIndexRelationName(tdbb, transaction, name, sys | ||||
temIndex); | ||||
dsc dscName; | dsc dscName; | |||
dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationNam e.c_str()); | dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*) relationNam e.c_str()); | |||
SCL_check_relation(tdbb, &dscName, SCL_alter); | SCL_check_relation(tdbb, &dscName, SCL_alter, systemIndex); | |||
return true; | return true; | |||
} | } | |||
void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, j rd_tra* transaction) | void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, j rd_tra* transaction) | |||
{ | { | |||
// run all statements under savepoint control | // run all statements under savepoint control | |||
AutoSavePoint savePoint(tdbb, transaction); | AutoSavePoint savePoint(tdbb, transaction); | |||
AutoCacheRequest request(tdbb, drq_e_indices, DYN_REQUESTS); | AutoCacheRequest request(tdbb, drq_e_indices, DYN_REQUESTS); | |||
bool found = false; | bool found = false; | |||
skipping to change at line 10012 | skipping to change at line 10013 | |||
return "MappingNode"; | return "MappingNode"; | |||
} | } | |||
void MappingNode::validateAdmin() | void MappingNode::validateAdmin() | |||
{ | { | |||
if (to && (*to != ADMIN_ROLE)) | if (to && (*to != ADMIN_ROLE)) | |||
Arg::Gds(isc_alter_role).raise(); | Arg::Gds(isc_alter_role).raise(); | |||
} | } | |||
// add some item to DDL in "double quotes" | // add some item to DDL in quotes | |||
void MappingNode::addItem(string& ddl, const char* text) | void MappingNode::addItem(string& ddl, const char* text, char quote) | |||
{ | { | |||
ddl += '"'; | ddl += quote; | |||
char c; | char c; | |||
while (c = *text++) | while ((c = *text++)) | |||
{ | { | |||
ddl += c; | ddl += c; | |||
if (c == '"') | if (c == quote) | |||
ddl += c; | ddl += c; | |||
} | } | |||
ddl += '"'; | ddl += quote; | |||
} | } | |||
bool MappingNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | bool MappingNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | |||
{ | { | |||
//DDL_TODO | //DDL_TODO | |||
return false; | return false; | |||
} | } | |||
void MappingNode::runInSecurityDb(SecDbContext* secDbContext) | void MappingNode::runInSecurityDb(SecDbContext* secDbContext) | |||
{ | { | |||
skipping to change at line 10100 | skipping to change at line 10101 | |||
if (fromType) | if (fromType) | |||
{ | { | |||
ddl += "FROM "; | ddl += "FROM "; | |||
if (!from) | if (!from) | |||
ddl += "ANY "; | ddl += "ANY "; | |||
addItem(ddl, fromType->c_str()); | addItem(ddl, fromType->c_str()); | |||
ddl += ' '; | ddl += ' '; | |||
if (from) | if (from) | |||
{ | { | |||
addItem(ddl, from->getString().c_str()); | addItem(ddl, from->getString().c_str(), '\''); | |||
ddl += ' '; | ddl += ' '; | |||
} | } | |||
} | } | |||
ddl += "TO "; | ddl += "TO "; | |||
ddl += (role ? "ROLE" : "USER"); | ddl += (role ? "ROLE" : "USER"); | |||
if (to) | if (to) | |||
{ | { | |||
ddl += ' '; | ddl += ' '; | |||
addItem(ddl, to->c_str()); | addItem(ddl, to->c_str()); | |||
skipping to change at line 10128 | skipping to change at line 10129 | |||
if (statusWrapper.getState() & IStatus::STATE_ERRORS) | if (statusWrapper.getState() & IStatus::STATE_ERRORS) | |||
{ | { | |||
try | try | |||
{ | { | |||
// try direct access to rdb$auth_mapping table in secure db | // try direct access to rdb$auth_mapping table in secure db | |||
LocalStatus s2; | LocalStatus s2; | |||
CheckStatusWrapper statusWrapper2(&s2); | CheckStatusWrapper statusWrapper2(&s2); | |||
// check presence of such record in the table | // check presence of such record in the table | |||
Message msgCheck; | Message msgCheck; | |||
Field<Varying> nm(msgCheck, 1); | Field<Varying> nm(msgCheck, MAX_SQL_IDENTIFIER_LEN); | |||
nm = name.c_str(); | nm = name.c_str(); | |||
Message result; | Message result; | |||
Field<ISC_INT64> cnt(result); | Field<ISC_INT64> cnt(result); | |||
const char* checkSql = "select count(*) from RDB$AUTH_MAP PING where RDB$MAP_NAME = ?"; | const char* checkSql = "select count(*) from RDB$AUTH_MAP PING where RDB$MAP_NAME = ?"; | |||
secDbContext->att->execute(&statusWrapper2, secDbContext- >tra, 0, checkSql, SQL_DIALECT_V6, | secDbContext->att->execute(&statusWrapper2, secDbContext- >tra, 0, checkSql, SQL_DIALECT_V6, | |||
msgCheck.getMetadata(), msgCheck.getBuffer(), res ult.getMetadata(), result.getBuffer()); | msgCheck.getMetadata(), msgCheck.getBuffer(), res ult.getMetadata(), result.getBuffer()); | |||
check(&statusWrapper2); | check(&statusWrapper2); | |||
skipping to change at line 10875 | skipping to change at line 10876 | |||
} | } | |||
} | } | |||
else | else | |||
privs += i->first; | privs += i->first; | |||
} | } | |||
if (privs.hasData()) | if (privs.hasData()) | |||
grantRevoke(tdbb, transaction, object, user, privs.c_str(), NULL, option); | grantRevoke(tdbb, transaction, object, user, privs.c_str(), NULL, option); | |||
} | } | |||
static bool checkObjectExist(thread_db* tdbb, jrd_tra* transaction, const MetaNa | ||||
me& name, int type) | ||||
{ | ||||
bool rc = false; | ||||
switch (type) | ||||
{ | ||||
case obj_procedure: | ||||
{ | ||||
AutoCacheRequest request(tdbb, drq_proc_exist, DYN_REQUES | ||||
TS); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction | ||||
) | ||||
X IN RDB$PROCEDURES | ||||
WITH X.RDB$PROCEDURE_NAME EQ name.c_str() AND X.R | ||||
DB$PACKAGE_NAME MISSING | ||||
{ | ||||
rc = true; | ||||
} | ||||
END_FOR | ||||
break; | ||||
} | ||||
case obj_udf: | ||||
{ | ||||
AutoCacheRequest request(tdbb, drq_udf_exist, DYN_REQUEST | ||||
S); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction | ||||
) | ||||
X IN RDB$FUNCTIONS | ||||
WITH X.RDB$FUNCTION_NAME EQ name.c_str() AND X.RD | ||||
B$PACKAGE_NAME MISSING | ||||
{ | ||||
rc = true; | ||||
} | ||||
END_FOR | ||||
break; | ||||
} | ||||
case obj_package_header: | ||||
{ | ||||
AutoCacheRequest request(tdbb, drq_package_exist, DYN_REQ | ||||
UESTS); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction | ||||
) | ||||
X IN RDB$PACKAGES | ||||
WITH X.RDB$PACKAGE_NAME EQ name.c_str() | ||||
{ | ||||
rc = true; | ||||
} | ||||
END_FOR | ||||
break; | ||||
} | ||||
case obj_trigger: | ||||
{ | ||||
AutoCacheRequest request(tdbb, drq_trigger_exist, DYN_REQ | ||||
UESTS); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction | ||||
) | ||||
X IN RDB$TRIGGERS | ||||
WITH X.RDB$TRIGGER_NAME EQ name.c_str() | ||||
{ | ||||
rc = true; | ||||
} | ||||
END_FOR | ||||
break; | ||||
} | ||||
case obj_relation: | ||||
case obj_view: | ||||
{ | ||||
AutoCacheRequest request(tdbb, drq_rel_exist, DYN_REQUEST | ||||
S); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction | ||||
) | ||||
X IN RDB$RELATIONS | ||||
WITH X.RDB$RELATION_NAME EQ name.c_str() | ||||
{ | ||||
rc = (type != obj_view) || (X.RDB$RELATION_TYPE | ||||
== rel_view); | ||||
} | ||||
END_FOR | ||||
break; | ||||
} | ||||
case obj_exception: | ||||
{ | ||||
AutoCacheRequest request(tdbb, drq_exception_exist, DYN_R | ||||
EQUESTS); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction | ||||
) | ||||
X IN RDB$EXCEPTIONS | ||||
WITH X.RDB$EXCEPTION_NAME EQ name.c_str() | ||||
{ | ||||
rc = true; | ||||
} | ||||
END_FOR | ||||
break; | ||||
} | ||||
case obj_generator: | ||||
{ | ||||
AutoCacheRequest request(tdbb, drq_generator_exist, DYN_R | ||||
EQUESTS); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction | ||||
) | ||||
X IN RDB$GENERATORS | ||||
WITH X.RDB$GENERATOR_NAME EQ name.c_str() | ||||
{ | ||||
rc = true; | ||||
} | ||||
END_FOR | ||||
break; | ||||
} | ||||
} | ||||
return rc; | ||||
} | ||||
static bool checkFieldExist(thread_db* tdbb, jrd_tra* transaction, const MetaNam | ||||
e& relation, const MetaName& field) | ||||
{ | ||||
bool rc = false; | ||||
AutoCacheRequest request(tdbb, drq_rel_field_exist, DYN_REQUESTS); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | ||||
X IN RDB$RELATION_FIELDS | ||||
WITH X.RDB$RELATION_NAME EQ relation.c_str() AND | ||||
X.RDB$FIELD_NAME EQ field.c_str() | ||||
{ | ||||
rc = true; | ||||
} | ||||
END_FOR | ||||
return rc; | ||||
} | ||||
// Execute SQL grant/revoke operation. | // Execute SQL grant/revoke operation. | |||
void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G ranteeClause* object, | void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G ranteeClause* object, | |||
const GranteeClause* userNod, const char* privs, | const GranteeClause* userNod, const char* privs, | |||
const MetaName& field, int options) | const MetaName& field, int options) | |||
{ | { | |||
SSHORT userType = userNod->first; | SSHORT userType = userNod->first; | |||
MetaName user(userNod->second); | MetaName user(userNod->second); | |||
MetaName dummyName; | MetaName dummyName; | |||
const SSHORT objType = object ? object->first : obj_type_MAX; | const SSHORT objType = object ? object->first : obj_type_MAX; | |||
bool crdb = false; | const MetaName objName(object ? object->second : ""); | |||
bool crdb = false; | ||||
char privileges[16]; | char privileges[16]; | |||
strcpy(privileges, privs ? privs : ""); | strcpy(privileges, privs ? privs : ""); | |||
if (strcmp(privileges, "A") == 0) | if (strcmp(privileges, "A") == 0) | |||
strcpy(privileges, ALL_PRIVILEGES); | strcpy(privileges, ALL_PRIVILEGES); | |||
char* cPtr = strchr(privileges, 'C'); | char* cPtr = strchr(privileges, 'C'); | |||
if (objType == obj_database && cPtr) | if (objType == obj_database && cPtr) | |||
{ | { | |||
skipping to change at line 10912 | skipping to change at line 11027 | |||
{ | { | |||
(Arg::Gds(isc_wish_list) << Arg::Gds(isc_random) << | (Arg::Gds(isc_wish_list) << Arg::Gds(isc_random) << | |||
"Only grants to USER or ROLE are supported for C REATE DATABASE").raise(); | "Only grants to USER or ROLE are supported for C REATE DATABASE").raise(); | |||
} | } | |||
crdb = true; | crdb = true; | |||
size_t len = strlen(cPtr); | size_t len = strlen(cPtr); | |||
memmove(cPtr, cPtr + 1, len); | memmove(cPtr, cPtr + 1, len); | |||
} | } | |||
// Check if grant object exists | ||||
switch (userType) | switch (userType) | |||
{ | { | |||
case obj_user_or_role: | case obj_user_or_role: | |||
// This test may become obsolete as we now allow explicit ROLE keyword. | // This test may become obsolete as we now allow explicit ROLE keyword. | |||
if (isItSqlRole(tdbb, transaction, user, dummyName)) | if (isItSqlRole(tdbb, transaction, user, dummyName)) | |||
{ | { | |||
userType = obj_sql_role; | userType = obj_sql_role; | |||
if (user == NULL_ROLE) | if (user == NULL_ROLE) | |||
{ | { | |||
// msg 195: keyword NONE could not be use d as SQL role name. | // msg 195: keyword NONE could not be use d as SQL role name. | |||
status_exception::raise(Arg::PrivateDyn(1 95) << user.c_str()); | status_exception::raise(Arg::PrivateDyn(1 95) << user.c_str()); | |||
} | } | |||
} | } | |||
else | else | |||
{ | ||||
userType = obj_user; | userType = obj_user; | |||
} | ||||
break; | break; | |||
case obj_user: | case obj_user: | |||
// We may grant privilege to non existing user | ||||
break; | ||||
case obj_udf: | ||||
if (!checkObjectExist(tdbb, transaction, user, userType)) | ||||
status_exception::raise(Arg::PrivateDyn(301) << u | ||||
ser.c_str()); // Function @1 does not exist | ||||
break; | ||||
case obj_procedure: | ||||
if (!checkObjectExist(tdbb, transaction, user, userType)) | ||||
status_exception::raise(Arg::PrivateDyn(302) << u | ||||
ser.c_str()); // Procedure @1 does not exist | ||||
break; | ||||
case obj_package_header: | ||||
if (!checkObjectExist(tdbb, transaction, user, userType)) | ||||
status_exception::raise(Arg::PrivateDyn(303) << u | ||||
ser.c_str()); // Package @1 does not exist | ||||
break; | ||||
case obj_trigger: | ||||
if (!checkObjectExist(tdbb, transaction, user, userType)) | ||||
status_exception::raise(Arg::PrivateDyn(304) << u | ||||
ser.c_str()); // Trigger @1 does not exist | ||||
break; | ||||
case obj_view: | ||||
if (!checkObjectExist(tdbb, transaction, user, userType)) | ||||
status_exception::raise(Arg::PrivateDyn(305) << u | ||||
ser.c_str()); // View @1 does not exist | ||||
break; | break; | |||
case obj_sql_role: | case obj_sql_role: | |||
if ((!crdb) && (!isItSqlRole(tdbb, transaction, user, dum myName))) | if ((!crdb) && (!isItSqlRole(tdbb, transaction, user, dum myName))) | |||
{ | { | |||
// msg 188: Role doesn't exist. | // msg 188: Role doesn't exist. | |||
status_exception::raise(Arg::PrivateDyn(188) << u ser.c_str()); | status_exception::raise(Arg::PrivateDyn(188) << u ser.c_str()); | |||
} | } | |||
if (user == NULL_ROLE) | if (user == NULL_ROLE) | |||
{ | { | |||
// msg 195: keyword NONE could not be used as SQL role name. | // msg 195: keyword NONE could not be used as SQL role name. | |||
status_exception::raise(Arg::PrivateDyn(195) << u ser.c_str()); | status_exception::raise(Arg::PrivateDyn(195) << u ser.c_str()); | |||
} | } | |||
break; | break; | |||
} | } | |||
// Check if grant subject exists | ||||
switch (objType) | ||||
{ | ||||
case obj_view: | ||||
if (!checkObjectExist(tdbb, transaction, objName, objType | ||||
)) | ||||
status_exception::raise(Arg::PrivateDyn(305) << o | ||||
bjName.c_str()); // View @1 does not exist | ||||
break; | ||||
case obj_relation: | ||||
if (!checkObjectExist(tdbb, transaction, objName, objType | ||||
)) | ||||
status_exception::raise(Arg::PrivateDyn(306) << o | ||||
bjName.c_str()); // Table @1 does not exist | ||||
if (field.hasData() && !checkFieldExist(tdbb, transaction | ||||
, objName, field)) | ||||
status_exception::raise(Arg::PrivateDyn(309) << f | ||||
ield.c_str() << objName.c_str()); // Field @1 of table @2 does not exist | ||||
break; | ||||
case obj_trigger: | ||||
if (!checkObjectExist(tdbb, transaction, objName, objType | ||||
)) | ||||
status_exception::raise(Arg::PrivateDyn(304) << o | ||||
bjName.c_str()); // Trigger @1 does not exist | ||||
break; | ||||
case obj_procedure: | ||||
if (!checkObjectExist(tdbb, transaction, objName, objType | ||||
)) | ||||
status_exception::raise(Arg::PrivateDyn(302) << o | ||||
bjName.c_str()); // Procedure @1 does not exist | ||||
break; | ||||
case obj_exception: | ||||
if (!checkObjectExist(tdbb, transaction, objName, objType | ||||
)) | ||||
status_exception::raise(Arg::PrivateDyn(307) << o | ||||
bjName.c_str()); // Exception @1 does not exist | ||||
break; | ||||
case obj_generator: | ||||
if (!checkObjectExist(tdbb, transaction, objName, objType | ||||
)) | ||||
status_exception::raise(Arg::PrivateDyn(308) << o | ||||
bjName.c_str()); // Generator/Sequence @1 does not exist | ||||
break; | ||||
case obj_udf: | ||||
if (!checkObjectExist(tdbb, transaction, objName, objType | ||||
)) | ||||
status_exception::raise(Arg::PrivateDyn(301) << o | ||||
bjName.c_str()); // Function @1 does not exist | ||||
break; | ||||
case obj_package_header: | ||||
if (!checkObjectExist(tdbb, transaction, objName, objType | ||||
)) | ||||
status_exception::raise(Arg::PrivateDyn(303) << o | ||||
bjName.c_str()); // Package @1 does not exist | ||||
break; | ||||
case obj_sql_role: | ||||
if (!isItSqlRole(tdbb, transaction, objName, dummyName)) | ||||
status_exception::raise(Arg::PrivateDyn(188) << o | ||||
bjName.c_str()); // Role doesn't exist. | ||||
break; | ||||
default: | ||||
fb_assert(object == NULL || objType >= obj_database); | ||||
} | ||||
if (options == 1) // with grant option | if (options == 1) // with grant option | |||
{ | { | |||
switch (userType) | switch (userType) | |||
{ | { | |||
case obj_procedure: | case obj_procedure: | |||
ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("procedures")); | ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("procedures")); | |||
break; | break; | |||
case obj_trigger: | case obj_trigger: | |||
ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("triggers")); | ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("triggers")); | |||
break; | break; | |||
case obj_view: | case obj_view: | |||
ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("views")); | ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("views")); | |||
break; | break; | |||
case obj_udf: | ||||
ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << | ||||
Arg::Str("functions")); | ||||
break; | ||||
case obj_package_header: | ||||
ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << | ||||
Arg::Str("packages")); | ||||
break; | ||||
default: | default: | |||
break; | break; | |||
} | } | |||
} | } | |||
MetaName grantorRevoker(grantor ? | MetaName grantorRevoker(grantor ? | |||
*grantor : tdbb->getAttachment()->att_user->usr_user_name); | *grantor : tdbb->getAttachment()->att_user->usr_user_name); | |||
if (grantor && !tdbb->getAttachment()->locksmith()) | if (grantor && !tdbb->getAttachment()->locksmith()) | |||
status_exception::raise(Arg::PrivateDyn(252) << SYSDBA_USER_NAME) ; | status_exception::raise(Arg::PrivateDyn(252) << SYSDBA_USER_NAME) ; | |||
skipping to change at line 11003 | skipping to change at line 11206 | |||
else | else | |||
all.badGrantor = true; | all.badGrantor = true; | |||
} | } | |||
END_FOR | END_FOR | |||
createDbJobs.push(all); | createDbJobs.push(all); | |||
return; | return; | |||
} | } | |||
const MetaName objName(object->second); | ||||
if (objType == obj_sql_role && objName == NULL_ROLE) | if (objType == obj_sql_role && objName == NULL_ROLE) | |||
{ | { | |||
if (isGrant) | if (isGrant) | |||
{ | { | |||
// msg 195: keyword NONE could not be used as SQL role na me. | // msg 195: keyword NONE could not be used as SQL role na me. | |||
status_exception::raise(Arg::PrivateDyn(195) << objName.c _str()); | status_exception::raise(Arg::PrivateDyn(195) << objName.c _str()); | |||
} | } | |||
else | else | |||
{ | { | |||
///CVC: Make this a warning in the future. | ///CVC: Make this a warning in the future. | |||
skipping to change at line 11090 | skipping to change at line 11291 | |||
// some kind of grant privileges on the base tabl e(s)/view(s). If the | // some kind of grant privileges on the base tabl e(s)/view(s). If the | |||
// grantor is the owner of the view, then we have to explicitely check | // grantor is the owner of the view, then we have to explicitely check | |||
// this because the owner of a view by default ha s grant privileges on | // this because the owner of a view by default ha s grant privileges on | |||
// his own view. If the grantor is not the owner of the view, then the | // his own view. If the grantor is not the owner of the view, then the | |||
// base table/view grant privilege checks were ma de when the grantor | // base table/view grant privilege checks were ma de when the grantor | |||
// got its grant privilege on the view and no fur ther checks are | // got its grant privilege on the view and no fur ther checks are | |||
// necessary. | // necessary. | |||
// As long as only locksmith can use GRANTED BY, no need specially checking | // As long as only locksmith can use GRANTED BY, no need specially checking | |||
// for privileges of current user. AP-2008 | // for privileges of current user. AP-2008 | |||
if (objType == 0) | switch (objType) | |||
{ | ||||
// Relation or view because we cannot dis | ||||
tinguish at this point. | ||||
checkGrantorCanGrant(tdbb, transaction, | ||||
tdbb->getAttachment()->att_user-> | ||||
usr_user_name.c_str(), priv, objName, | ||||
field, true); | ||||
} | ||||
else if (objType >= obj_database) | ||||
{ | { | |||
checkGrantorCanGrantDdl(tdbb, transaction | case obj_relation: | |||
, | { | |||
tdbb->getAttachment()->att_user-> | // Relation or view because we ca | |||
usr_user_name.c_str(), priv, objName); | nnot distinguish at this point. | |||
checkGrantorCanGrantRelation(tdbb | ||||
, transaction, | ||||
tdbb->getAttachment()->at | ||||
t_user->usr_user_name.c_str(), priv, objName, | ||||
field, true); | ||||
break; | ||||
} | ||||
case obj_exception: | ||||
case obj_generator: | ||||
{ | ||||
checkGrantorCanGrantObject(tdbb, | ||||
transaction, | ||||
tdbb->getAttachment()->at | ||||
t_user->usr_user_name.c_str(), priv, objName, objType); | ||||
break; | ||||
} | ||||
default: | ||||
if (objType >= obj_database) | ||||
{ | ||||
checkGrantorCanGrantDdl(t | ||||
dbb, transaction, | ||||
tdbb->getAttachme | ||||
nt()->att_user->usr_user_name.c_str(), priv, objName); | ||||
} | ||||
// Prevent silent eating checks. In this | ||||
case we can remove RDB$TRIGGER_9 (trigger1) | ||||
// but add every object type above in swi | ||||
tch | ||||
// else | ||||
// fb_assert(false); | ||||
} | } | |||
} | } | |||
storePrivilege(tdbb, transaction, objName, user, field, p r, userType, objType, | storePrivilege(tdbb, transaction, objName, user, field, p r, userType, objType, | |||
options, grantorRevoker); | options, grantorRevoker); | |||
} | } | |||
} | } | |||
else // REVOKE | else // REVOKE | |||
{ | { | |||
AutoCacheRequest request(tdbb, (field.hasData() ? drq_e_grant1 : drq_e_grant2), DYN_REQUESTS); | AutoCacheRequest request(tdbb, (field.hasData() ? drq_e_grant1 : drq_e_grant2), DYN_REQUESTS); | |||
skipping to change at line 11133 | skipping to change at line 11352 | |||
PRIV.RDB$PRIVILEGE EQ priv AND | PRIV.RDB$PRIVILEGE EQ priv AND | |||
PRIV.RDB$USER = user.c_str() AND | PRIV.RDB$USER = user.c_str() AND | |||
PRIV.RDB$USER_TYPE = userType AN D | PRIV.RDB$USER_TYPE = userType AN D | |||
PRIV.RDB$FIELD_NAME EQ field.c_s tr() AND | PRIV.RDB$FIELD_NAME EQ field.c_s tr() AND | |||
PRIV.RDB$GRANTOR NOT MISSING | PRIV.RDB$GRANTOR NOT MISSING | |||
{ | { | |||
if (grantorRevoker == PRIV.RDB$GRANTOR) | if (grantorRevoker == PRIV.RDB$GRANTOR) | |||
{ | { | |||
ERASE PRIV; | ERASE PRIV; | |||
grantErased = true; | grantErased = true; | |||
if (options) | ||||
{ | ||||
// Add the privilege with | ||||
out the grant option. There is a modify trigger on the | ||||
// rdb$user_privileges wh | ||||
ich disallows the table from being updated. It would have | ||||
// to be changed such tha | ||||
t only the grant_option field can be updated. | ||||
storePrivilege(tdbb, tran | ||||
saction, objName, user, field, pr, userType, objType, | ||||
0, grantorRevoker | ||||
); | ||||
} | ||||
} | } | |||
else | else | |||
badGrantor = true; | badGrantor = true; | |||
} | } | |||
END_FOR | END_FOR | |||
} | } | |||
else | else | |||
{ | { | |||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE tra nsaction) | FOR(REQUEST_HANDLE request TRANSACTION_HANDLE tra nsaction) | |||
PRIV IN RDB$USER_PRIVILEGES | PRIV IN RDB$USER_PRIVILEGES | |||
skipping to change at line 11158 | skipping to change at line 11386 | |||
PRIV.RDB$GRANTOR NOT MISSING | PRIV.RDB$GRANTOR NOT MISSING | |||
{ | { | |||
// Revoking a permission at the table lev el implies revoking the perm. on all | // Revoking a permission at the table lev el implies revoking the perm. on all | |||
// columns. So for all fields in this tab le which have been granted the | // columns. So for all fields in this tab le which have been granted the | |||
// privilege, we erase the entries from R DB$USER_PRIVILEGES. | // privilege, we erase the entries from R DB$USER_PRIVILEGES. | |||
if (grantorRevoker == PRIV.RDB$GRANTOR) | if (grantorRevoker == PRIV.RDB$GRANTOR) | |||
{ | { | |||
ERASE PRIV; | ERASE PRIV; | |||
grantErased = true; | grantErased = true; | |||
if (options) | ||||
{ | ||||
// Add the privilege with | ||||
out the grant option. There is a modify trigger on the | ||||
// rdb$user_privileges wh | ||||
ich disallows the table from being updated. It would have | ||||
// to be changed such tha | ||||
t only the grant_option field can be updated. | ||||
MetaName newField = PRIV. | ||||
RDB$FIELD_NAME.NULL ? "" : PRIV.RDB$FIELD_NAME; | ||||
storePrivilege(tdbb, tran | ||||
saction, objName, user, newField, pr, userType, objType, | ||||
0, grantorRevoker | ||||
); | ||||
} | ||||
} | } | |||
else | else | |||
badGrantor = true; | badGrantor = true; | |||
} | } | |||
END_FOR | END_FOR | |||
} | } | |||
if (options && grantErased) | ||||
{ | ||||
// Add the privilege without the grant option. Th | ||||
ere is a modify trigger on the | ||||
// rdb$user_privileges which disallows the table | ||||
from being updated. It would have | ||||
// to be changed such that only the grant_option | ||||
field can be updated. | ||||
storePrivilege(tdbb, transaction, objName, user, | ||||
field, pr, userType, objType, | ||||
0, grantorRevoker); | ||||
} | ||||
if (badGrantor && !grantErased) | if (badGrantor && !grantErased) | |||
{ | { | |||
// msg 246: @1 is not grantor of @2 on @3 to @4. | // msg 246: @1 is not grantor of @2 on @3 to @4. | |||
status_exception::raise(Arg::PrivateDyn(246) << | status_exception::raise(Arg::PrivateDyn(246) << | |||
grantorRevoker.c_str() << privilegeName(p riv[0]) << objName.c_str() << | grantorRevoker.c_str() << privilegeName(p riv[0]) << objName.c_str() << | |||
user.c_str()); | user.c_str()); | |||
} | } | |||
if (!grantErased) | if (!grantErased) | |||
{ | { | |||
// msg 247: Warning: @1 on @2 is not granted to @ 3. | // msg 247: Warning: @1 on @2 is not granted to @ 3. | |||
ERR_post_warning( | ERR_post_warning( | |||
Arg::Warning(isc_dyn_miss_priv_warning) < < | Arg::Warning(isc_dyn_miss_priv_warning) < < | |||
Arg::Str(privilegeName(priv[0])) << Arg:: Str(objName) << Arg::Str(user)); | Arg::Str(privilegeName(priv[0])) << Arg:: Str(objName) << Arg::Str(user)); | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
// Check if the grantor has grant privilege on the relation/field. | // Check if the grantor has grant privilege on the relation/field. | |||
void GrantRevokeNode::checkGrantorCanGrant(thread_db* tdbb, jrd_tra* transaction , | void GrantRevokeNode::checkGrantorCanGrantRelation(thread_db* tdbb, jrd_tra* tra nsaction, | |||
const char* grantor, const char* privilege, const MetaName& relationName, | const char* grantor, const char* privilege, const MetaName& relationName, | |||
const MetaName& fieldName, bool topLevel) | const MetaName& fieldName, bool topLevel) | |||
{ | { | |||
// Verify that the input relation exists. | // Verify that the input relation exists. | |||
AutoCacheRequest request(tdbb, drq_gcg4, DYN_REQUESTS); | AutoCacheRequest request(tdbb, drq_gcg4, DYN_REQUESTS); | |||
bool sqlRelation = false; | bool sqlRelation = false; | |||
bool relationExists = false; | bool relationExists = false; | |||
skipping to change at line 11379 | skipping to change at line 11607 | |||
G_VIEW IN RDB$VIEW_RELATIONS WITH | G_VIEW IN RDB$VIEW_RELATIONS WITH | |||
G_FLD.RDB$RELATION_NAME = relationName.c_str() AND | G_FLD.RDB$RELATION_NAME = relationName.c_str() AND | |||
G_FLD.RDB$BASE_FIELD NOT MISSING AND | G_FLD.RDB$BASE_FIELD NOT MISSING AND | |||
G_VIEW.RDB$VIEW_NAME EQ G_FLD.RDB$RELATION_NAME AND | G_VIEW.RDB$VIEW_NAME EQ G_FLD.RDB$RELATION_NAME AND | |||
G_VIEW.RDB$VIEW_CONTEXT EQ G_FLD.RDB$VIEW_CONTEXT | G_VIEW.RDB$VIEW_CONTEXT EQ G_FLD.RDB$VIEW_CONTEXT | |||
{ | { | |||
if (fieldName.hasData()) | if (fieldName.hasData()) | |||
{ | { | |||
if (fieldName == G_FLD.RDB$FIELD_NAME) | if (fieldName == G_FLD.RDB$FIELD_NAME) | |||
{ | { | |||
checkGrantorCanGrant(tdbb, transaction, grantor, privilege, | checkGrantorCanGrantRelation(tdbb, transaction, g rantor, privilege, | |||
G_VIEW.RDB$RELATION_NAME, G_FLD.RDB$BASE_ FIELD, false); | G_VIEW.RDB$RELATION_NAME, G_FLD.RDB$BASE_ FIELD, false); | |||
} | } | |||
} | } | |||
else | else | |||
{ | { | |||
checkGrantorCanGrant(tdbb, transaction, grantor, privileg e, | checkGrantorCanGrantRelation(tdbb, transaction, grantor, privilege, | |||
G_VIEW.RDB$RELATION_NAME, G_FLD.RDB$BASE_FIELD, f alse); | G_VIEW.RDB$RELATION_NAME, G_FLD.RDB$BASE_FIELD, f alse); | |||
} | } | |||
} | } | |||
END_FOR | END_FOR | |||
} | } | |||
// Check if the grantor has admin privilege on the role. | // Check if the grantor has admin privilege on the role. | |||
void GrantRevokeNode::checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transac tion, | void GrantRevokeNode::checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transac tion, | |||
const MetaName& grantor, const MetaName& roleName) | const MetaName& grantor, const MetaName& roleName) | |||
{ | { | |||
skipping to change at line 11457 | skipping to change at line 11685 | |||
bool grantable = false; | bool grantable = false; | |||
FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | |||
PRV IN RDB$USER_PRIVILEGES | PRV IN RDB$USER_PRIVILEGES | |||
WITH PRV.RDB$USER = UPPERCASE(grantor.c_str()) AND | WITH PRV.RDB$USER = UPPERCASE(grantor.c_str()) AND | |||
PRV.RDB$USER_TYPE = obj_user AND | PRV.RDB$USER_TYPE = obj_user AND | |||
PRV.RDB$RELATION_NAME EQ objName.c_str() AND | PRV.RDB$RELATION_NAME EQ objName.c_str() AND | |||
PRV.RDB$OBJECT_TYPE >= obj_database AND | PRV.RDB$OBJECT_TYPE >= obj_database AND | |||
PRV.RDB$PRIVILEGE EQ privilege | PRV.RDB$PRIVILEGE EQ privilege | |||
{ | { | |||
grantable = PRV.RDB$GRANT_OPTION == 1; | if (PRV.RDB$GRANT_OPTION == 1) | |||
grantable = true; | ||||
} | } | |||
END_FOR | END_FOR | |||
if (!grantable) | if (!grantable) | |||
{ | { | |||
// no .. privilege with grant option on DDL .. | // no @1 privilege with grant option on DDL @2 | |||
status_exception::raise(Arg::PrivateDyn(174) << privilege << objN | status_exception::raise(Arg::PrivateDyn(299) << privilege << objN | |||
ame.c_str()); | ame.c_str()); | |||
} | ||||
} | ||||
// Check if the grantor has grant option on generator privilege | ||||
void GrantRevokeNode::checkGrantorCanGrantObject(thread_db* tdbb, jrd_tra* trans | ||||
action, const char* grantor, | ||||
const char* privilege, const Firebird::MetaName& objName, SSHORT | ||||
objType) | ||||
{ | ||||
if (tdbb->getAttachment()->locksmith()) | ||||
return; | ||||
AutoCacheRequest request(tdbb, drq_l_grant_object, DYN_REQUESTS); | ||||
bool grantable = false; | ||||
FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | ||||
PRV IN RDB$USER_PRIVILEGES | ||||
WITH (PRV.RDB$USER = UPPERCASE(grantor) AND PRV.RDB$USER_TYPE = o | ||||
bj_user) AND | ||||
PRV.RDB$RELATION_NAME EQ objName.c_str() AND | ||||
PRV.RDB$OBJECT_TYPE >= obj_database AND | ||||
PRV.RDB$PRIVILEGE EQ privilege | ||||
{ | ||||
if (PRV.RDB$GRANT_OPTION == 1) | ||||
grantable = true; | ||||
} | ||||
END_FOR | ||||
if (!grantable) | ||||
{ | ||||
// no @1 privilege with grant option on object @2 | ||||
status_exception::raise(Arg::PrivateDyn(300) << privilege << objN | ||||
ame.c_str()); | ||||
} | } | |||
} | } | |||
void GrantRevokeNode::storePrivilege(thread_db* tdbb, jrd_tra* transaction, cons t MetaName& object, | void GrantRevokeNode::storePrivilege(thread_db* tdbb, jrd_tra* transaction, cons t MetaName& object, | |||
const MetaName& user, const MetaName& field, const TEXT* privilege, SSHOR T userType, | const MetaName& user, const MetaName& field, const TEXT* privilege, SSHOR T userType, | |||
SSHORT objType, int option, const MetaName& grantor) | SSHORT objType, int option, const MetaName& grantor) | |||
{ | { | |||
AutoCacheRequest request(tdbb, drq_s_grant, DYN_REQUESTS); | AutoCacheRequest request(tdbb, drq_s_grant, DYN_REQUESTS); | |||
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | |||
skipping to change at line 11560 | skipping to change at line 11818 | |||
return "AlterDatabaseNode"; | return "AlterDatabaseNode"; | |||
} | } | |||
bool AlterDatabaseNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | bool AlterDatabaseNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) | |||
{ | { | |||
SCL_check_database(tdbb, SCL_alter); | SCL_check_database(tdbb, SCL_alter); | |||
return true; | return true; | |||
} | } | |||
void AlterDatabaseNode::checkClauses(thread_db* tdbb) | ||||
{ | ||||
if (clauses & CLAUSE_END_BACKUP) | ||||
{ | ||||
// msg 298: Incompatible ALTER DATABASE clauses: '@1' and '@2' | ||||
if (clauses & CLAUSE_BEGIN_BACKUP) | ||||
(Arg::PrivateDyn(298) << Arg::Str("BEGIN BACKUP") << Arg: | ||||
:Str("END BACKUP")).raise(); | ||||
if (differenceFile.hasData()) | ||||
(Arg::PrivateDyn(298) << Arg::Str("END BACKUP") << Arg::S | ||||
tr("ADD DIFFERENCE FILE")).raise(); | ||||
if (clauses & CLAUSE_DROP_DIFFERENCE) | ||||
(Arg::PrivateDyn(298) << Arg::Str("END BACKUP") << Arg::S | ||||
tr("DROP DIFFERENCE FILE")).raise(); | ||||
} | ||||
if ((clauses & CLAUSE_DROP_DIFFERENCE) && differenceFile.hasData()) | ||||
{ | ||||
// msg 298: Incompatible ALTER DATABASE clauses: '@1' and '@2' | ||||
(Arg::PrivateDyn(298) << Arg::Str("ADD DIFFERENCE FILE") << Arg:: | ||||
Str("DROP DIFFERENCE FILE")).raise(); | ||||
} | ||||
} | ||||
void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc h, | void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc h, | |||
jrd_tra* transaction) | jrd_tra* transaction) | |||
{ | { | |||
checkClauses(tdbb); | ||||
// Take a LCK_alter_database lock to prevent altering of the database fro | ||||
m | ||||
// parallel transactions | ||||
if (!transaction->tra_alter_db_lock) | ||||
{ | ||||
Lock* lock = FB_NEW_RPT(*transaction->tra_pool, 0) Lock(tdbb, 0, | ||||
LCK_alter_database); | ||||
lock->lck_data = transaction->tra_number; | ||||
if (LCK_lock(tdbb, lock, LCK_write, transaction->getLockWait())) | ||||
transaction->tra_alter_db_lock = lock; | ||||
else | ||||
{ | ||||
const TraNumber conflict_trans = LCK_read_data(tdbb, lock | ||||
); | ||||
delete lock; | ||||
// msg 297: Concurrent ALTER DATABASE is not supported | ||||
Arg::PrivateDyn status(297); | ||||
if (conflict_trans) | ||||
status << Arg::Gds(isc_concurrent_transaction) << | ||||
Arg::Num(conflict_trans); | ||||
status_exception::raise(status); | ||||
} | ||||
} | ||||
// run all statements under savepoint control | // run all statements under savepoint control | |||
AutoSavePoint savePoint(tdbb, transaction); | AutoSavePoint savePoint(tdbb, transaction); | |||
Attachment* const attachment = transaction->tra_attachment; | if (clauses & CLAUSE_DROP_DIFFERENCE) | |||
dsql_dbb* dbb = transaction->getDsqlAttachment(); | changeBackupMode(tdbb, transaction, CLAUSE_DROP_DIFFERENCE); | |||
SLONG dbAlloc = PageSpace::maxAlloc(tdbb->getDatabase()); | SLONG dbAlloc = PageSpace::maxAlloc(tdbb->getDatabase()); | |||
SLONG start = create ? createLength + 1 : 0; | SLONG start = create ? createLength + 1 : 0; | |||
AutoCacheRequest request(tdbb, drq_m_database, DYN_REQUESTS); | for (NestConst<DbFileClause>* i = files.begin(); i != files.end(); ++i) | |||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | ||||
DBB IN RDB$DATABASE | ||||
{ | { | |||
MODIFY DBB USING | DbFileClause* file = *i; | |||
if (clauses & CLAUSE_DROP_DIFFERENCE) | ||||
changeBackupMode(tdbb, transaction, CLAUSE_DROP_D | ||||
IFFERENCE); | ||||
for (NestConst<DbFileClause>* i = files.begin(); i != fil | start = MAX(start, file->start); | |||
es.end(); ++i) | defineFile(tdbb, transaction, 0, false, false, dbAlloc, | |||
{ | file->name.c_str(), start, file->length); | |||
DbFileClause* file = *i; | start += file->length; | |||
} | ||||
start = MAX(start, file->start); | if (differenceFile.hasData()) | |||
defineFile(tdbb, transaction, 0, false, false, db | defineDifference(tdbb, transaction, differenceFile.c_str()); | |||
Alloc, | ||||
file->name.c_str(), start, file->length); | if (clauses & CLAUSE_BEGIN_BACKUP) | |||
start += file->length; | changeBackupMode(tdbb, transaction, CLAUSE_BEGIN_BACKUP); | |||
} | ||||
if (differenceFile.hasData()) | if (clauses & CLAUSE_END_BACKUP) | |||
defineDifference(tdbb, transaction, differenceFil | changeBackupMode(tdbb, transaction, CLAUSE_END_BACKUP); | |||
e.c_str()); | ||||
if (setDefaultCharSet.hasData() || setDefaultCollation.hasData() || linge | ||||
r >= 0) | ||||
{ | ||||
AutoCacheRequest request(tdbb, drq_m_database, DYN_REQUESTS); | ||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) | ||||
DBB IN RDB$DATABASE | ||||
{ | ||||
MODIFY DBB USING | ||||
if (setDefaultCharSet.hasData()) | if (setDefaultCharSet.hasData()) | |||
{ | { | |||
if (!METD_get_charset(transaction, setDefaultChar Set.length(), | if (!METD_get_charset(transaction, setDefaultChar Set.length(), | |||
setDefaultCharSet.c_str())) | setDefaultCharSet.c_str())) | |||
{ | { | |||
// specified character set not found | // specified character set not found | |||
status_exception::raise(Arg::Gds(isc_char set_not_found) << setDefaultCharSet); | status_exception::raise(Arg::Gds(isc_char set_not_found) << setDefaultCharSet); | |||
} | } | |||
DBB.RDB$CHARACTER_SET_NAME.NULL = FALSE; | DBB.RDB$CHARACTER_SET_NAME.NULL = FALSE; | |||
strcpy(DBB.RDB$CHARACTER_SET_NAME, setDefaultChar Set.c_str()); | strcpy(DBB.RDB$CHARACTER_SET_NAME, setDefaultChar Set.c_str()); | |||
dsql_dbb* dbb = transaction->getDsqlAttachment(); | ||||
dbb->dbb_dfl_charset = ""; // reset in the c ache | dbb->dbb_dfl_charset = ""; // reset in the c ache | |||
} | } | |||
if (!DBB.RDB$CHARACTER_SET_NAME.NULL && setDefaultCollati on.hasData()) | if (!DBB.RDB$CHARACTER_SET_NAME.NULL && setDefaultCollati on.hasData()) | |||
{ | { | |||
AlterCharSetNode alterCharSetNode(getPool(), setD efaultCharSet, setDefaultCollation); | AlterCharSetNode alterCharSetNode(getPool(), setD efaultCharSet, setDefaultCollation); | |||
alterCharSetNode.execute(tdbb, dsqlScratch, trans action); | alterCharSetNode.execute(tdbb, dsqlScratch, trans action); | |||
} | } | |||
if (linger >= 0) | if (linger >= 0) | |||
{ | { | |||
DBB.RDB$LINGER.NULL = FALSE; | DBB.RDB$LINGER.NULL = FALSE; | |||
DBB.RDB$LINGER = linger; | DBB.RDB$LINGER = linger; | |||
} | } | |||
if (clauses & CLAUSE_BEGIN_BACKUP) | END_MODIFY | |||
changeBackupMode(tdbb, transaction, CLAUSE_BEGIN_ | } | |||
BACKUP); | END_FOR | |||
if (clauses & CLAUSE_END_BACKUP) | ||||
changeBackupMode(tdbb, transaction, CLAUSE_END_BA | ||||
CKUP); | ||||
END_MODIFY | ||||
} | } | |||
END_FOR | ||||
// Allow update above to work as a lock, preventing altering of the datab | // Load crypt plugin if it (by a miracle) wasn't already loaded yet | |||
ase from parallel transactions | ||||
// Moreover, it should load crypt plugin if it (by a miracle) wasn't alre | ||||
ady loaded yet | ||||
if (clauses & CLAUSE_CRYPT) | if (clauses & CLAUSE_CRYPT) | |||
{ | { | |||
Database* const db = tdbb->getDatabase(); | Database* const db = tdbb->getDatabase(); | |||
db->dbb_crypto_manager->prepareChangeCryptState(tdbb, cryptPlugin , keyName); | db->dbb_crypto_manager->prepareChangeCryptState(tdbb, cryptPlugin , keyName); | |||
DFW_post_work(transaction, dfw_db_crypt, cryptPlugin.c_str(), 0); | DFW_post_work(transaction, dfw_db_crypt, cryptPlugin.c_str(), 0); | |||
} | } | |||
savePoint.release(); // everything is ok | savePoint.release(); // everything is ok | |||
} | } | |||
End of changes. 66 change blocks. | ||||
142 lines changed or deleted | 515 lines changed or added |