"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/dsql/DdlNodes.epp" between
Firebird-3.0.2.32703-0.tar.bz2 and Firebird-3.0.4.33054-0.tar.bz2

About: Firebird is a relational database offering many ANSI SQL standard features.

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

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)