Coding style cleanup, no functional change.
This commit is contained in:
parent
991d9dbf6d
commit
e5022f23b3
|
@ -74,31 +74,32 @@ union value {
|
||||||
*/
|
*/
|
||||||
class Term {
|
class Term {
|
||||||
public:
|
public:
|
||||||
Term(int8 op) : fOp(op), fParent(NULL) {}
|
Term(int8 op) : fOp(op), fParent(NULL) {}
|
||||||
virtual ~Term() {}
|
virtual ~Term() {}
|
||||||
|
|
||||||
int8 Op() const { return fOp; }
|
int8 Op() const { return fOp; }
|
||||||
|
|
||||||
void SetParent(Term* parent) { fParent = parent; }
|
void SetParent(Term* parent) { fParent = parent; }
|
||||||
Term* Parent() const { return fParent; }
|
Term* Parent() const { return fParent; }
|
||||||
|
|
||||||
virtual status_t Match(Inode* inode, const char* attribute = NULL,
|
virtual status_t Match(Inode* inode,
|
||||||
int32 type = 0, const uint8* key = NULL,
|
const char* attribute = NULL,
|
||||||
size_t size = 0) = 0;
|
int32 type = 0, const uint8* key = NULL,
|
||||||
virtual void Complement() = 0;
|
size_t size = 0) = 0;
|
||||||
|
virtual void Complement() = 0;
|
||||||
|
|
||||||
virtual void CalculateScore(Index& index) = 0;
|
virtual void CalculateScore(Index& index) = 0;
|
||||||
virtual int32 Score() const = 0;
|
virtual int32 Score() const = 0;
|
||||||
|
|
||||||
virtual status_t InitCheck() = 0;
|
virtual status_t InitCheck() = 0;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
virtual void PrintToStream() = 0;
|
virtual void PrintToStream() = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int8 fOp;
|
int8 fOp;
|
||||||
Term* fParent;
|
Term* fParent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,51 +116,54 @@ protected:
|
||||||
*/
|
*/
|
||||||
class Equation : public Term {
|
class Equation : public Term {
|
||||||
public:
|
public:
|
||||||
Equation(char** expression);
|
Equation(char** _expression);
|
||||||
virtual ~Equation();
|
virtual ~Equation();
|
||||||
|
|
||||||
virtual status_t InitCheck();
|
virtual status_t InitCheck();
|
||||||
|
|
||||||
status_t ParseQuotedString(char** _start, char** _end);
|
virtual status_t Match(Inode* inode,
|
||||||
char* CopyString(char* start, char* end);
|
const char* attribute = NULL,
|
||||||
|
int32 type = 0, const uint8* key = NULL,
|
||||||
|
size_t size = 0);
|
||||||
|
virtual void Complement();
|
||||||
|
|
||||||
virtual status_t Match(Inode* inode, const char* attribute = NULL,
|
status_t PrepareQuery(Volume* volume, Index& index,
|
||||||
int32 type = 0, const uint8* key = NULL,
|
TreeIterator** iterator,
|
||||||
size_t size = 0);
|
bool queryNonIndexed);
|
||||||
virtual void Complement();
|
status_t GetNextMatching(Volume* volume,
|
||||||
|
TreeIterator* iterator,
|
||||||
|
struct dirent* dirent, size_t bufferSize);
|
||||||
|
|
||||||
status_t PrepareQuery(Volume* volume, Index& index,
|
virtual void CalculateScore(Index &index);
|
||||||
TreeIterator** iterator, bool queryNonIndexed);
|
virtual int32 Score() const { return fScore; }
|
||||||
status_t GetNextMatching(Volume* volume, TreeIterator* iterator,
|
|
||||||
struct dirent* dirent, size_t bufferSize);
|
|
||||||
|
|
||||||
virtual void CalculateScore(Index &index);
|
|
||||||
virtual int32 Score() const { return fScore; }
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
virtual void PrintToStream();
|
virtual void PrintToStream();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Equation(const Equation& other);
|
Equation(const Equation& other);
|
||||||
Equation& operator=(const Equation& other);
|
Equation& operator=(const Equation& other);
|
||||||
// no implementation
|
// no implementation
|
||||||
|
|
||||||
status_t ConvertValue(type_code type);
|
status_t _ParseQuotedString(char** _start, char** _end);
|
||||||
bool CompareTo(const uint8* value, uint16 size);
|
char* _CopyString(char* start, char* end);
|
||||||
uint8* Value() const { return (uint8*)&fValue; }
|
status_t _ConvertValue(type_code type);
|
||||||
status_t MatchEmptyString();
|
bool _CompareTo(const uint8* value, uint16 size);
|
||||||
|
uint8* _Value() const { return (uint8*)&fValue; }
|
||||||
|
status_t _MatchEmptyString();
|
||||||
|
|
||||||
char* fAttribute;
|
private:
|
||||||
char* fString;
|
char* fAttribute;
|
||||||
union value fValue;
|
char* fString;
|
||||||
type_code fType;
|
union value fValue;
|
||||||
size_t fSize;
|
type_code fType;
|
||||||
bool fIsPattern;
|
size_t fSize;
|
||||||
bool fIsSpecialTime;
|
bool fIsPattern;
|
||||||
|
bool fIsSpecialTime;
|
||||||
|
|
||||||
int32 fScore;
|
int32 fScore;
|
||||||
bool fHasIndex;
|
bool fHasIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,40 +172,42 @@ private:
|
||||||
*/
|
*/
|
||||||
class Operator : public Term {
|
class Operator : public Term {
|
||||||
public:
|
public:
|
||||||
Operator(Term* left, int8 op, Term* right);
|
Operator(Term* left, int8 op, Term* right);
|
||||||
virtual ~Operator();
|
virtual ~Operator();
|
||||||
|
|
||||||
Term* Left() const { return fLeft; }
|
Term* Left() const { return fLeft; }
|
||||||
Term* Right() const { return fRight; }
|
Term* Right() const { return fRight; }
|
||||||
|
|
||||||
virtual status_t Match(Inode* inode, const char* attribute = NULL,
|
virtual status_t Match(Inode* inode,
|
||||||
int32 type = 0, const uint8* key = NULL,
|
const char* attribute = NULL,
|
||||||
size_t size = 0);
|
int32 type = 0, const uint8* key = NULL,
|
||||||
virtual void Complement();
|
size_t size = 0);
|
||||||
|
virtual void Complement();
|
||||||
|
|
||||||
virtual void CalculateScore(Index& index);
|
virtual void CalculateScore(Index& index);
|
||||||
virtual int32 Score() const;
|
virtual int32 Score() const;
|
||||||
|
|
||||||
virtual status_t InitCheck();
|
virtual status_t InitCheck();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
virtual void PrintToStream();
|
virtual void PrintToStream();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Operator(const Operator& other);
|
Operator(const Operator& other);
|
||||||
Operator& operator=(const Operator& other);
|
Operator& operator=(const Operator& other);
|
||||||
// no implementation
|
// no implementation
|
||||||
|
|
||||||
Term* fLeft;
|
private:
|
||||||
Term* fRight;
|
Term* fLeft;
|
||||||
|
Term* fRight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
Equation::Equation(char** expr)
|
Equation::Equation(char** _expression)
|
||||||
:
|
:
|
||||||
Term(OP_EQUATION),
|
Term(OP_EQUATION),
|
||||||
fAttribute(NULL),
|
fAttribute(NULL),
|
||||||
|
@ -209,7 +215,7 @@ Equation::Equation(char** expr)
|
||||||
fType(0),
|
fType(0),
|
||||||
fIsPattern(false)
|
fIsPattern(false)
|
||||||
{
|
{
|
||||||
char* string = *expr;
|
char* string = *_expression;
|
||||||
char* start = string;
|
char* start = string;
|
||||||
char* end = NULL;
|
char* end = NULL;
|
||||||
|
|
||||||
|
@ -220,7 +226,7 @@ Equation::Equation(char** expr)
|
||||||
|
|
||||||
if (*start == '"' || *start == '\'') {
|
if (*start == '"' || *start == '\'') {
|
||||||
// string is quoted (start has to be on the beginning of a string)
|
// string is quoted (start has to be on the beginning of a string)
|
||||||
if (ParseQuotedString(&start, &end) < B_OK)
|
if (_ParseQuotedString(&start, &end) < B_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// set string to a valid start of the equation symbol
|
// set string to a valid start of the equation symbol
|
||||||
|
@ -228,7 +234,7 @@ Equation::Equation(char** expr)
|
||||||
skipWhitespace(&string);
|
skipWhitespace(&string);
|
||||||
if (*string != '=' && *string != '<' && *string != '>'
|
if (*string != '=' && *string != '<' && *string != '>'
|
||||||
&& *string != '!') {
|
&& *string != '!') {
|
||||||
*expr = string;
|
*_expression = string;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -274,7 +280,7 @@ Equation::Equation(char** expr)
|
||||||
|
|
||||||
// any invalid characters will be rejected
|
// any invalid characters will be rejected
|
||||||
default:
|
default:
|
||||||
*expr = string;
|
*_expression = string;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,14 +292,14 @@ Equation::Equation(char** expr)
|
||||||
|
|
||||||
// allocate & copy the attribute string
|
// allocate & copy the attribute string
|
||||||
|
|
||||||
fAttribute = CopyString(start, end);
|
fAttribute = _CopyString(start, end);
|
||||||
if (fAttribute == NULL)
|
if (fAttribute == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
start = string;
|
start = string;
|
||||||
if (*start == '"' || *start == '\'') {
|
if (*start == '"' || *start == '\'') {
|
||||||
// string is quoted (start has to be on the beginning of a string)
|
// string is quoted (start has to be on the beginning of a string)
|
||||||
if (ParseQuotedString(&start, &end) < B_OK)
|
if (_ParseQuotedString(&start, &end) < B_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string = end + 2;
|
string = end + 2;
|
||||||
|
@ -306,19 +312,19 @@ Equation::Equation(char** expr)
|
||||||
skipWhitespaceReverse(&end, start);
|
skipWhitespaceReverse(&end, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point, "start" will point to the first character of the value,
|
// At this point, "start" will point to the first character of the value,
|
||||||
// "end" will point to its last character, and "start" to the first non-
|
// "end" will point to its last character, and "start" to the first non-
|
||||||
// whitespace character after the value string
|
// whitespace character after the value string.
|
||||||
|
|
||||||
fString = CopyString(start, end);
|
fString = _CopyString(start, end);
|
||||||
if (fString == NULL)
|
if (fString == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// patterns are only allowed for these operations (and strings)
|
// Patterns are only allowed for these operations (and strings)
|
||||||
if (fOp == OP_EQUAL || fOp == OP_UNEQUAL) {
|
if (fOp == OP_EQUAL || fOp == OP_UNEQUAL) {
|
||||||
fIsPattern = isPattern(fString);
|
fIsPattern = isPattern(fString);
|
||||||
if (fIsPattern && isValidPattern(fString) < B_OK) {
|
if (fIsPattern && isValidPattern(fString) < B_OK) {
|
||||||
// we only want to have valid patterns; setting fString
|
// Only valid patterns are allowed; setting fString
|
||||||
// to NULL will cause InitCheck() to fail
|
// to NULL will cause InitCheck() to fail
|
||||||
free(fString);
|
free(fString);
|
||||||
fString = NULL;
|
fString = NULL;
|
||||||
|
@ -333,7 +339,7 @@ Equation::Equation(char** expr)
|
||||||
// too one day.
|
// too one day.
|
||||||
fIsSpecialTime = !strcmp(fAttribute, "last_modified");
|
fIsSpecialTime = !strcmp(fAttribute, "last_modified");
|
||||||
|
|
||||||
*expr = string;
|
*_expression = string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -354,184 +360,6 @@ Equation::InitCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
Equation::ParseQuotedString(char** _start, char** _end)
|
|
||||||
{
|
|
||||||
char* start = *_start;
|
|
||||||
char quote = *start++;
|
|
||||||
char* end = start;
|
|
||||||
|
|
||||||
for (; *end && *end != quote; end++) {
|
|
||||||
if (*end == '\\')
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
if (*end == '\0')
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
*_start = start;
|
|
||||||
*_end = end - 1;
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char*
|
|
||||||
Equation::CopyString(char* start, char* end)
|
|
||||||
{
|
|
||||||
// end points to the last character of the string - and the length
|
|
||||||
// also has to include the null-termination
|
|
||||||
int32 length = end + 2 - start;
|
|
||||||
// just to make sure; since that's the max. attribute name length and
|
|
||||||
// the max. string in an index, it make sense to have it that way
|
|
||||||
if (length > INODE_FILE_NAME_LENGTH || length <= 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
char* copy = (char*)malloc(length);
|
|
||||||
if (copy == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memcpy(copy, start, length - 1);
|
|
||||||
copy[length - 1] = '\0';
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
Equation::ConvertValue(type_code type)
|
|
||||||
{
|
|
||||||
// Has the type already been converted?
|
|
||||||
if (type == fType)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
char* string = fString;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case B_MIME_STRING_TYPE:
|
|
||||||
type = B_STRING_TYPE;
|
|
||||||
// supposed to fall through
|
|
||||||
case B_STRING_TYPE:
|
|
||||||
strncpy(fValue.String, string, INODE_FILE_NAME_LENGTH);
|
|
||||||
fValue.String[INODE_FILE_NAME_LENGTH - 1] = '\0';
|
|
||||||
fSize = strlen(fValue.String);
|
|
||||||
break;
|
|
||||||
case B_INT32_TYPE:
|
|
||||||
fValue.Int32 = strtol(string, &string, 0);
|
|
||||||
fSize = sizeof(int32);
|
|
||||||
break;
|
|
||||||
case B_UINT32_TYPE:
|
|
||||||
fValue.Int32 = strtoul(string, &string, 0);
|
|
||||||
fSize = sizeof(uint32);
|
|
||||||
break;
|
|
||||||
case B_INT64_TYPE:
|
|
||||||
fValue.Int64 = strtoll(string, &string, 0);
|
|
||||||
fSize = sizeof(int64);
|
|
||||||
break;
|
|
||||||
case B_UINT64_TYPE:
|
|
||||||
fValue.Uint64 = strtoull(string, &string, 0);
|
|
||||||
fSize = sizeof(uint64);
|
|
||||||
break;
|
|
||||||
case B_FLOAT_TYPE:
|
|
||||||
fValue.Float = strtod(string, &string);
|
|
||||||
fSize = sizeof(float);
|
|
||||||
break;
|
|
||||||
case B_DOUBLE_TYPE:
|
|
||||||
fValue.Double = strtod(string, &string);
|
|
||||||
fSize = sizeof(double);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
FATAL(("query value conversion to 0x%x requested!\n", (int)type));
|
|
||||||
// should we fail here or just do a safety int32 conversion?
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
fType = type;
|
|
||||||
|
|
||||||
// patterns are only allowed for string types
|
|
||||||
if (fType != B_STRING_TYPE && fIsPattern)
|
|
||||||
fIsPattern = false;
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Returns true when the key matches the equation. You have to
|
|
||||||
call ConvertValue() before this one.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
Equation::CompareTo(const uint8* value, uint16 size)
|
|
||||||
{
|
|
||||||
int32 compare;
|
|
||||||
|
|
||||||
// fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or
|
|
||||||
// OP_UNEQUAL
|
|
||||||
if (fIsPattern) {
|
|
||||||
// we have already validated the pattern, so we don't check for failing
|
|
||||||
// here - if something is broken, and matchString() returns an error,
|
|
||||||
// we just don't match
|
|
||||||
compare = matchString(fValue.String, (char*)value) == MATCH_OK ? 0 : 1;
|
|
||||||
} else if (fIsSpecialTime) {
|
|
||||||
// the index is a shifted int64 index, but we have to match
|
|
||||||
// against an unshifted value (i.e. the last_modified index)
|
|
||||||
int64 timeValue = *(int64*)value >> INODE_TIME_SHIFT;
|
|
||||||
compare = compareKeys(fType, &timeValue, sizeof(int64), &fValue.Int64,
|
|
||||||
sizeof(int64));
|
|
||||||
} else
|
|
||||||
compare = compareKeys(fType, value, size, Value(), fSize);
|
|
||||||
|
|
||||||
switch (fOp) {
|
|
||||||
case OP_EQUAL:
|
|
||||||
return compare == 0;
|
|
||||||
case OP_UNEQUAL:
|
|
||||||
return compare != 0;
|
|
||||||
case OP_LESS_THAN:
|
|
||||||
return compare < 0;
|
|
||||||
case OP_LESS_THAN_OR_EQUAL:
|
|
||||||
return compare <= 0;
|
|
||||||
case OP_GREATER_THAN:
|
|
||||||
return compare > 0;
|
|
||||||
case OP_GREATER_THAN_OR_EQUAL:
|
|
||||||
return compare >= 0;
|
|
||||||
}
|
|
||||||
FATAL(("Unknown/Unsupported operation: %d\n", fOp));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
Equation::Complement()
|
|
||||||
{
|
|
||||||
D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) {
|
|
||||||
FATAL(("op out of range!"));
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
|
|
||||||
int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL,
|
|
||||||
OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN};
|
|
||||||
fOp = complementOp[fOp - OP_EQUAL];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
Equation::MatchEmptyString()
|
|
||||||
{
|
|
||||||
// There is no matching attribute, we will just bail out if we
|
|
||||||
// already know that our value is not of a string type.
|
|
||||||
// If not, it will be converted to a string - and then be compared with "".
|
|
||||||
// That's why we have to call ConvertValue() here - but it will be
|
|
||||||
// a cheap call for the next time
|
|
||||||
// TODO: Should we do this only for OP_UNEQUAL?
|
|
||||||
if (fType != 0 && fType != B_STRING_TYPE)
|
|
||||||
return NO_MATCH;
|
|
||||||
|
|
||||||
status_t status = ConvertValue(B_STRING_TYPE);
|
|
||||||
if (status == B_OK)
|
|
||||||
status = CompareTo((const uint8*)"", fSize) ? MATCH_OK : NO_MATCH;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Matches the inode's attribute value with the equation.
|
/*! Matches the inode's attribute value with the equation.
|
||||||
Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went
|
Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went
|
||||||
wrong.
|
wrong.
|
||||||
|
@ -550,7 +378,7 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
|
||||||
if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
|
if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
|
||||||
if (key == NULL) {
|
if (key == NULL) {
|
||||||
if (type == B_STRING_TYPE)
|
if (type == B_STRING_TYPE)
|
||||||
return MatchEmptyString();
|
return _MatchEmptyString();
|
||||||
|
|
||||||
return NO_MATCH;
|
return NO_MATCH;
|
||||||
}
|
}
|
||||||
|
@ -623,13 +451,13 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
|
||||||
}
|
}
|
||||||
inode->ReleaseAttribute(attribute);
|
inode->ReleaseAttribute(attribute);
|
||||||
} else
|
} else
|
||||||
return MatchEmptyString();
|
return _MatchEmptyString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prepare own value for use, if it is possible to convert it
|
// prepare own value for use, if it is possible to convert it
|
||||||
status_t status = ConvertValue(type);
|
status_t status = _ConvertValue(type);
|
||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
|
status = _CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
|
||||||
|
|
||||||
if (locked)
|
if (locked)
|
||||||
recursive_lock_unlock(&inode->SmallDataLock());
|
recursive_lock_unlock(&inode->SmallDataLock());
|
||||||
|
@ -639,36 +467,16 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Equation::CalculateScore(Index &index)
|
Equation::Complement()
|
||||||
{
|
{
|
||||||
// As always, these values could be tuned and refined.
|
D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) {
|
||||||
// And the code could also need some real world testing :-)
|
FATAL(("op out of range!"));
|
||||||
|
|
||||||
// do we have to operate on a "foreign" index?
|
|
||||||
if (fOp == OP_UNEQUAL || index.SetTo(fAttribute) < B_OK) {
|
|
||||||
fScore = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
});
|
||||||
|
|
||||||
// if we have a pattern, how much does it help our search?
|
int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL,
|
||||||
if (fIsPattern)
|
OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN};
|
||||||
fScore = getFirstPatternSymbol(fString) << 3;
|
fOp = complementOp[fOp - OP_EQUAL];
|
||||||
else {
|
|
||||||
// Score by operator
|
|
||||||
if (fOp == OP_EQUAL)
|
|
||||||
// higher than pattern="255 chars+*"
|
|
||||||
fScore = 2048;
|
|
||||||
else
|
|
||||||
// the pattern search is regarded cheaper when you have at
|
|
||||||
// least one character to set your index to
|
|
||||||
fScore = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// take index size into account (1024 is the current node size
|
|
||||||
// in our B+trees)
|
|
||||||
// 2048 * 2048 == 4194304 is the maximum score (for an empty
|
|
||||||
// tree, since the header + 1 node are already 2048 bytes)
|
|
||||||
fScore = fScore * ((2048 * 1024LL) / index.Node()->Size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -701,7 +509,7 @@ Equation::PrepareQuery(Volume* /*volume*/, Index& index,
|
||||||
type = index.Type();
|
type = index.Type();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConvertValue(type) < B_OK)
|
if (_ConvertValue(type) < B_OK)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
BPlusTree* tree = index.Node()->Tree();
|
BPlusTree* tree = index.Node()->Tree();
|
||||||
|
@ -753,7 +561,7 @@ Equation::PrepareQuery(Volume* /*volume*/, Index& index,
|
||||||
if (status == B_ENTRY_NOT_FOUND)
|
if (status == B_ENTRY_NOT_FOUND)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
} else {
|
} else {
|
||||||
status = (*iterator)->Find(Value(), keySize);
|
status = (*iterator)->Find(_Value(), keySize);
|
||||||
if (fOp == OP_EQUAL && !fIsPattern)
|
if (fOp == OP_EQUAL && !fIsPattern)
|
||||||
return status;
|
return status;
|
||||||
else if (status == B_ENTRY_NOT_FOUND
|
else if (status == B_ENTRY_NOT_FOUND
|
||||||
|
@ -787,7 +595,7 @@ Equation::GetNextMatching(Volume* volume, TreeIterator* iterator,
|
||||||
// only compare against the index entry when this is the correct
|
// only compare against the index entry when this is the correct
|
||||||
// index for the equation
|
// index for the equation
|
||||||
if (fHasIndex && duplicate < 2
|
if (fHasIndex && duplicate < 2
|
||||||
&& !CompareTo((uint8*)&indexValue, keyLength)) {
|
&& !_CompareTo((uint8*)&indexValue, keyLength)) {
|
||||||
// They aren't equal? Let the operation decide what to do. Since
|
// They aren't equal? Let the operation decide what to do. Since
|
||||||
// we always start at the beginning of the index (or the correct
|
// we always start at the beginning of the index (or the correct
|
||||||
// position), only some needs to be stopped if the entry doesn't
|
// position), only some needs to be stopped if the entry doesn't
|
||||||
|
@ -876,6 +684,204 @@ Equation::GetNextMatching(Volume* volume, TreeIterator* iterator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Equation::CalculateScore(Index &index)
|
||||||
|
{
|
||||||
|
// As always, these values could be tuned and refined.
|
||||||
|
// And the code could also need some real world testing :-)
|
||||||
|
|
||||||
|
// do we have to operate on a "foreign" index?
|
||||||
|
if (fOp == OP_UNEQUAL || index.SetTo(fAttribute) < B_OK) {
|
||||||
|
fScore = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have a pattern, how much does it help our search?
|
||||||
|
if (fIsPattern)
|
||||||
|
fScore = getFirstPatternSymbol(fString) << 3;
|
||||||
|
else {
|
||||||
|
// Score by operator
|
||||||
|
if (fOp == OP_EQUAL)
|
||||||
|
// higher than pattern="255 chars+*"
|
||||||
|
fScore = 2048;
|
||||||
|
else
|
||||||
|
// the pattern search is regarded cheaper when you have at
|
||||||
|
// least one character to set your index to
|
||||||
|
fScore = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// take index size into account (1024 is the current node size
|
||||||
|
// in our B+trees)
|
||||||
|
// 2048 * 2048 == 4194304 is the maximum score (for an empty
|
||||||
|
// tree, since the header + 1 node are already 2048 bytes)
|
||||||
|
fScore = fScore * ((2048 * 1024LL) / index.Node()->Size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Equation::_ParseQuotedString(char** _start, char** _end)
|
||||||
|
{
|
||||||
|
char* start = *_start;
|
||||||
|
char quote = *start++;
|
||||||
|
char* end = start;
|
||||||
|
|
||||||
|
for (; *end && *end != quote; end++) {
|
||||||
|
if (*end == '\\')
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
if (*end == '\0')
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
*_start = start;
|
||||||
|
*_end = end - 1;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char*
|
||||||
|
Equation::_CopyString(char* start, char* end)
|
||||||
|
{
|
||||||
|
// end points to the last character of the string - and the length
|
||||||
|
// also has to include the null-termination
|
||||||
|
int32 length = end + 2 - start;
|
||||||
|
// just to make sure; since that's the max. attribute name length and
|
||||||
|
// the max. string in an index, it make sense to have it that way
|
||||||
|
if (length > INODE_FILE_NAME_LENGTH || length <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char* copy = (char*)malloc(length);
|
||||||
|
if (copy == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(copy, start, length - 1);
|
||||||
|
copy[length - 1] = '\0';
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Equation::_ConvertValue(type_code type)
|
||||||
|
{
|
||||||
|
// Has the type already been converted?
|
||||||
|
if (type == fType)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
char* string = fString;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case B_MIME_STRING_TYPE:
|
||||||
|
type = B_STRING_TYPE;
|
||||||
|
// supposed to fall through
|
||||||
|
case B_STRING_TYPE:
|
||||||
|
strncpy(fValue.String, string, INODE_FILE_NAME_LENGTH);
|
||||||
|
fValue.String[INODE_FILE_NAME_LENGTH - 1] = '\0';
|
||||||
|
fSize = strlen(fValue.String);
|
||||||
|
break;
|
||||||
|
case B_INT32_TYPE:
|
||||||
|
fValue.Int32 = strtol(string, &string, 0);
|
||||||
|
fSize = sizeof(int32);
|
||||||
|
break;
|
||||||
|
case B_UINT32_TYPE:
|
||||||
|
fValue.Int32 = strtoul(string, &string, 0);
|
||||||
|
fSize = sizeof(uint32);
|
||||||
|
break;
|
||||||
|
case B_INT64_TYPE:
|
||||||
|
fValue.Int64 = strtoll(string, &string, 0);
|
||||||
|
fSize = sizeof(int64);
|
||||||
|
break;
|
||||||
|
case B_UINT64_TYPE:
|
||||||
|
fValue.Uint64 = strtoull(string, &string, 0);
|
||||||
|
fSize = sizeof(uint64);
|
||||||
|
break;
|
||||||
|
case B_FLOAT_TYPE:
|
||||||
|
fValue.Float = strtod(string, &string);
|
||||||
|
fSize = sizeof(float);
|
||||||
|
break;
|
||||||
|
case B_DOUBLE_TYPE:
|
||||||
|
fValue.Double = strtod(string, &string);
|
||||||
|
fSize = sizeof(double);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FATAL(("query value conversion to 0x%x requested!\n", (int)type));
|
||||||
|
// should we fail here or just do a safety int32 conversion?
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
fType = type;
|
||||||
|
|
||||||
|
// patterns are only allowed for string types
|
||||||
|
if (fType != B_STRING_TYPE && fIsPattern)
|
||||||
|
fIsPattern = false;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Returns true when the key matches the equation. You have to
|
||||||
|
call ConvertValue() before this one.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
Equation::_CompareTo(const uint8* value, uint16 size)
|
||||||
|
{
|
||||||
|
int32 compare;
|
||||||
|
|
||||||
|
// fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or
|
||||||
|
// OP_UNEQUAL
|
||||||
|
if (fIsPattern) {
|
||||||
|
// we have already validated the pattern, so we don't check for failing
|
||||||
|
// here - if something is broken, and matchString() returns an error,
|
||||||
|
// we just don't match
|
||||||
|
compare = matchString(fValue.String, (char*)value) == MATCH_OK ? 0 : 1;
|
||||||
|
} else if (fIsSpecialTime) {
|
||||||
|
// the index is a shifted int64 index, but we have to match
|
||||||
|
// against an unshifted value (i.e. the last_modified index)
|
||||||
|
int64 timeValue = *(int64*)value >> INODE_TIME_SHIFT;
|
||||||
|
compare = compareKeys(fType, &timeValue, sizeof(int64), &fValue.Int64,
|
||||||
|
sizeof(int64));
|
||||||
|
} else
|
||||||
|
compare = compareKeys(fType, value, size, _Value(), fSize);
|
||||||
|
|
||||||
|
switch (fOp) {
|
||||||
|
case OP_EQUAL:
|
||||||
|
return compare == 0;
|
||||||
|
case OP_UNEQUAL:
|
||||||
|
return compare != 0;
|
||||||
|
case OP_LESS_THAN:
|
||||||
|
return compare < 0;
|
||||||
|
case OP_LESS_THAN_OR_EQUAL:
|
||||||
|
return compare <= 0;
|
||||||
|
case OP_GREATER_THAN:
|
||||||
|
return compare > 0;
|
||||||
|
case OP_GREATER_THAN_OR_EQUAL:
|
||||||
|
return compare >= 0;
|
||||||
|
}
|
||||||
|
FATAL(("Unknown/Unsupported operation: %d\n", fOp));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Equation::_MatchEmptyString()
|
||||||
|
{
|
||||||
|
// There is no matching attribute, we will just bail out if we
|
||||||
|
// already know that our value is not of a string type.
|
||||||
|
// If not, it will be converted to a string - and then be compared with "".
|
||||||
|
// That's why we have to call ConvertValue() here - but it will be
|
||||||
|
// a cheap call for the next time
|
||||||
|
// TODO: Should we do this only for OP_UNEQUAL?
|
||||||
|
if (fType != 0 && fType != B_STRING_TYPE)
|
||||||
|
return NO_MATCH;
|
||||||
|
|
||||||
|
status_t status = _ConvertValue(B_STRING_TYPE);
|
||||||
|
if (status == B_OK)
|
||||||
|
status = _CompareTo((const uint8*)"", fSize) ? MATCH_OK : NO_MATCH;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue