diff --git a/src/jrd/SimilarToMatcher.h b/src/jrd/SimilarToMatcher.h new file mode 100644 index 0000000000..3c81151493 --- /dev/null +++ b/src/jrd/SimilarToMatcher.h @@ -0,0 +1,1317 @@ +/* + * PROGRAM: JRD International support + * MODULE: SimilarToMatcher.h + * DESCRIPTION: SIMILAR TO predicate + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Adriano dos Santos Fernandes + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2007 Adriano dos Santos Fernandes + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#ifndef JRD_SIMILAR_TO_EVALUATOR_H +#define JRD_SIMILAR_TO_EVALUATOR_H + +// #define DEBUG_SIMILAR + + +namespace Firebird +{ + +template +class SimilarToMatcher : public PatternMatcher +{ +private: + // This class is based on work of Zafir Anjum + // http://www.codeguru.com/Cpp/Cpp/string/regex/article.php/c2791 + // which has been derived from work by Henry Spencer. + // + // The original copyright notice follows: + // + // Copyright (c) 1986, 1993, 1995 by University of Toronto. + // Written by Henry Spencer. Not derived from licensed software. + // + // Permission is granted to anyone to use this software for any + // purpose on any computer system, and to redistribute it in any way, + // subject to the following restrictions: + // + // 1. The author is not responsible for the consequences of use of + // this software, no matter how awful, even if they arise + // from defects in it. + // + // 2. The origin of this software must not be misrepresented, either + // by explicit claim or by omission. + // + // 3. Altered versions must be plainly marked as such, and must not + // be misrepresented (by explicit claim or omission) as being + // the original software. + // + // 4. This notice must not be removed or altered. + class Evaluator : private StaticAllocator + { + public: + Evaluator(MemoryPool& pool, TextType* textType, + const UCHAR* patternStr, SLONG patternLen, + CharType escapeChar, bool useEscape); + + bool getResult(); + bool processNextChunk(const UCHAR* data, SLONG dataLen); + void reset(); + + private: + enum Op + { + opRepeat, + opBranch, + opStart, + opEnd, + opRef, + opNothing, + opAny, + opAnyOf, + opAnyBut, + opExactly + }; + + struct Node + { + Node(Op aOp, const CharType* aStr = NULL, SLONG aLen = 0) + : op(aOp), + str(aStr), + len(aLen), + str2(NULL), + len2(0), + ref(0) + { + } + + Node(Op aOp, SLONG aLen1, SLONG aLen2, int aRef) + : op(aOp), + str(NULL), + len(aLen1), + str2(NULL), + len2(aLen2), + ref(aRef) + { + } + + Node(Op aOp, int aRef) + : op(aOp), + str(NULL), + len(0), + str2(NULL), + len2(0), + ref(aRef) + { + } + + Node(const Node& node) + : op(node.op), + str(node.str), + len(node.len), + str2(node.str2), + len2(node.len2), + ref(node.ref) + { + } + + Op op; + const CharType* str; + SLONG len; + const UCHAR* str2; + SLONG len2; + int ref; + }; + + // Struct used to evaluate expressions without recursion. + // Represents local variables to implement a "virtual stack". + struct Scope + { + Scope(int ai, int aLimit) + : i(ai), + limit(aLimit), + save(NULL), + j(0), + flag(false) + { + } + + // variables used in the recursive commented out function + int i; + int limit; + const CharType* save; + int j; + bool flag; // aux. variable to make non-recursive logic + }; + + static const int FLAG_NOT_EMPTY = 1; // known never to match empty string + static const int FLAG_EXACTLY = 2; // non-escaped string + + private: + void parseExpr(int* flagp); + void parseTerm(int* flagp); + void parseFactor(int* flagp); + void parsePrimary(int* flagp); + bool isRep(CharType c) const; + + CharType canonicalChar(int ch) const + { + return *reinterpret_cast(textType->getCanonicalChar(ch)); + } + +#ifdef DEBUG_SIMILAR + void dump() const; +#endif + + private: + bool match(); + + private: + static SLONG notInSet(const CharType* str, SLONG strLen, + const CharType* set, SLONG setLen); + + private: + TextType* textType; + CharType escapeChar; + bool useEscape; + HalfStaticArray buffer; + const UCHAR* originalPatternStr; + SLONG originalPatternLen; + StrConverter patternCvt; + CharSet* charSet; + Array nodes; + Array scopes; + const CharType* patternStart; + const CharType* patternEnd; + const CharType* patternPos; + const CharType* bufferStart; + const CharType* bufferEnd; + const CharType* bufferPos; + CharType metaCharacters[15]; + }; + +public: + SimilarToMatcher(MemoryPool& pool, TextType* ttype, const UCHAR* str, + SLONG str_len, CharType escape, bool use_escape) + : PatternMatcher(pool, ttype), + evaluator(pool, ttype, str, str_len, escape, use_escape) + { + } + + void reset() + { + evaluator.reset(); + } + + bool result() + { + return evaluator.getResult(); + } + + bool process(const UCHAR* str, SLONG length) + { + return evaluator.processNextChunk(str, length); + } + + static SimilarToMatcher* create(MemoryPool& pool, TextType* ttype, + const UCHAR* str, SLONG length, const UCHAR* escape, SLONG escape_length) + { + StrConverter cvt_escape(pool, ttype, escape, escape_length); + + return FB_NEW(pool) SimilarToMatcher(pool, ttype, + str, length, + (escape ? *reinterpret_cast(escape) : 0), escape_length != 0); + } + + static bool evaluate(MemoryPool& pool, TextType* ttype, const UCHAR* s, SLONG sl, + const UCHAR* p, SLONG pl, const UCHAR* escape, SLONG escape_length) + { + StrConverter cvt_escape(pool, ttype, escape, escape_length); + + Evaluator evaluator(pool, ttype, + p, pl, + (escape ? *reinterpret_cast(escape) : 0), escape_length != 0); + evaluator.processNextChunk(s, sl); + return evaluator.getResult(); + } + +private: + Evaluator evaluator; +}; + + +template +SimilarToMatcher::Evaluator::Evaluator( + MemoryPool& pool, TextType* textType, + const UCHAR* patternStr, SLONG patternLen, + CharType escapeChar, bool useEscape) + : StaticAllocator(pool), + textType(textType), + escapeChar(escapeChar), + useEscape(useEscape), + buffer(pool), + originalPatternStr(patternStr), + originalPatternLen(patternLen), + patternCvt(pool, textType, patternStr, patternLen), + charSet(textType->getCharSet()), + nodes(pool), + scopes(pool) +{ + fb_assert(patternLen % sizeof(CharType) == 0); + patternLen /= sizeof(CharType); + + CharType* p = metaCharacters; + *p++ = canonicalChar(TextType::CHAR_CIRCUMFLEX); + *p++ = canonicalChar(TextType::CHAR_MINUS); + *p++ = canonicalChar(TextType::CHAR_UNDERLINE); + *p++ = canonicalChar(TextType::CHAR_PERCENT); + *p++ = canonicalChar(TextType::CHAR_OPEN_BRACKET); + *p++ = canonicalChar(TextType::CHAR_CLOSE_BRACKET); + *p++ = canonicalChar(TextType::CHAR_OPEN_PAREN); + *p++ = canonicalChar(TextType::CHAR_CLOSE_PAREN); + *p++ = canonicalChar(TextType::CHAR_OPEN_BRACE); + *p++ = canonicalChar(TextType::CHAR_CLOSE_BRACE); + *p++ = canonicalChar(TextType::CHAR_VERTICAL_BAR); + *p++ = canonicalChar(TextType::CHAR_QUESTION_MARK); + *p++ = canonicalChar(TextType::CHAR_PLUS); + *p++ = canonicalChar(TextType::CHAR_ASTERISK); + if (useEscape) + *p++ = escapeChar; + else + *p++ = canonicalChar(TextType::CHAR_ASTERISK); // just repeat something + fb_assert(p - metaCharacters == FB_NELEM(metaCharacters)); + + patternStart = patternPos = (const CharType*) patternStr; + patternEnd = patternStart + patternLen; + + nodes.push(Node(opStart)); + + int flags; + parseExpr(&flags); + + nodes.push(Node(opEnd)); + +#ifdef DEBUG_SIMILAR + dump(); +#endif + + // Check for proper termination. + if (patternPos < patternEnd) + status_exception::raise(isc_invalid_similar_pattern, 0); + + reset(); +} + + +template +bool SimilarToMatcher::Evaluator::getResult() +{ + const UCHAR* str = buffer.begin(); + SLONG len = buffer.getCount(); + + // note that StrConverter changes str and len variables + StrConverter cvt(pool, textType, str, len); + fb_assert(len % sizeof(CharType) == 0); + + bufferStart = bufferPos = (const CharType*) str; + bufferEnd = bufferStart + len / sizeof(CharType); + + return match(); +} + + +template +bool SimilarToMatcher::Evaluator::processNextChunk(const UCHAR* data, SLONG dataLen) +{ + ULONG pos = buffer.getCount(); + memcpy(buffer.getBuffer(pos + dataLen) + pos, data, dataLen); + return true; +} + + +template +void SimilarToMatcher::Evaluator::reset() +{ + buffer.shrink(0); + scopes.shrink(0); +} + + +template +void SimilarToMatcher::Evaluator::parseExpr(int* flagp) +{ + *flagp = FLAG_NOT_EMPTY; + + bool first = true; + Array refs; + int start; + + while (first || (patternPos < patternEnd && *patternPos == canonicalChar(TextType::CHAR_VERTICAL_BAR))) + { + if (first) + first = false; + else + ++patternPos; + + start = nodes.getCount(); + nodes.push(Node(opBranch)); + + int flags; + parseTerm(&flags); + *flagp &= ~(~flags & FLAG_NOT_EMPTY); + *flagp |= flags; + + refs.push(nodes.getCount()); + nodes.push(Node(opRef)); + + nodes[start].ref = nodes.getCount() - start; + } + + nodes[start].ref = 0; + + for (Array::iterator i = refs.begin(); i != refs.end(); ++i) + nodes[*i].ref = nodes.getCount() - *i; +} + + +template +void SimilarToMatcher::Evaluator::parseTerm(int* flagp) +{ + *flagp = 0; + + bool first = true; + CharType c; + int flags; + + while ((patternPos < patternEnd) && + (c = *patternPos) != canonicalChar(TextType::CHAR_VERTICAL_BAR) && + c != canonicalChar(TextType::CHAR_CLOSE_PAREN)) + { + parseFactor(&flags); + + *flagp |= flags & FLAG_NOT_EMPTY; + + if (first) + { + *flagp |= flags; + first = false; + } + } + + if (first) + nodes.push(Node(opNothing)); +} + + +template +void SimilarToMatcher::Evaluator::parseFactor(int* flagp) +{ + int atomPos = nodes.getCount(); + + int flags; + parsePrimary(&flags); + + CharType op; + + if (patternPos >= patternEnd || !isRep((op = *patternPos))) + { + *flagp = flags; + return; + } + + if (!(flags & FLAG_NOT_EMPTY) && op != canonicalChar(TextType::CHAR_QUESTION_MARK)) + status_exception::raise(isc_invalid_similar_pattern, 0); + + // If the last primary is a string, split the last character + if (flags & FLAG_EXACTLY) + { + fb_assert(nodes.back().op == opExactly); + + if (nodes.back().len > 1) + { + Node last = nodes.back(); + last.str += nodes.back().len - 1; + last.len = 1; + + --nodes.back().len; + atomPos = nodes.getCount(); + nodes.push(last); + } + } + + fb_assert( + op == canonicalChar(TextType::CHAR_ASTERISK) || + op == canonicalChar(TextType::CHAR_PLUS) || + op == canonicalChar(TextType::CHAR_QUESTION_MARK) || + op == canonicalChar(TextType::CHAR_OPEN_BRACE)); + + if (op == canonicalChar(TextType::CHAR_ASTERISK)) + { + *flagp = 0; + nodes.insert(atomPos, Node(opBranch, nodes.getCount() - atomPos + 2)); + nodes.push(Node(opRef, atomPos - nodes.getCount())); + nodes.push(Node(opBranch)); + } + else if (op == canonicalChar(TextType::CHAR_PLUS)) + { + *flagp = FLAG_NOT_EMPTY; + nodes.push(Node(opBranch, 2)); + nodes.push(Node(opRef, atomPos - nodes.getCount())); + nodes.push(Node(opBranch)); + } + else if (op == canonicalChar(TextType::CHAR_QUESTION_MARK)) + { + *flagp = 0; + nodes.insert(atomPos, Node(opBranch, nodes.getCount() - atomPos + 1)); + nodes.push(Node(opBranch)); + } + else if (op == canonicalChar(TextType::CHAR_OPEN_BRACE)) + { + ++patternPos; + + UCharBuffer dummy; + const UCHAR* p = originalPatternStr + + charSet->substring( + originalPatternLen, originalPatternStr, + originalPatternLen, dummy.getBuffer(originalPatternLen), + 1, patternPos - patternStart); + ULONG size = 0; + bool comma = false; + string s1, s2; + bool ok; + + while ((ok = IntlUtil::readOneChar(charSet, &p, originalPatternStr + originalPatternLen, &size))) + { + if (*patternPos == canonicalChar(TextType::CHAR_CLOSE_BRACE)) + { + if (s1.isEmpty() || (comma && s2.isEmpty())) + status_exception::raise(isc_invalid_similar_pattern, 0); + break; + } + else if (*patternPos == canonicalChar(TextType::CHAR_COMMA)) + { + if (comma) + status_exception::raise(isc_invalid_similar_pattern, 0); + comma = true; + } + else + { + ULONG ch = 0; + charSet->getConvToUnicode().convert(size, p, sizeof(ch), reinterpret_cast(&ch)); + + if (ch >= '0' && ch <= '9') + { + if (comma) + s2 += (char) ch; + else + s1 += (char) ch; + } + else + status_exception::raise(isc_invalid_similar_pattern, 0); + } + + ++patternPos; + } + + if (!ok || s1.length() > 9 || s2.length() > 9) + status_exception::raise(isc_invalid_similar_pattern, 0); + + int n1 = atoi(s1.c_str()); + int n2 = comma ? atoi(s2.c_str()) : INT_MAX; + + if (n2 < n1) + status_exception::raise(isc_invalid_similar_pattern, 0); + + *flagp = n1 == 0 ? 0 : FLAG_NOT_EMPTY; + + nodes.insert(atomPos, Node(opRepeat, n1, n2, nodes.getCount() - atomPos)); + } + + ++patternPos; + + if (patternPos < patternEnd && isRep(*patternPos)) + status_exception::raise(isc_invalid_similar_pattern, 0); +} + + +template +void SimilarToMatcher::Evaluator::parsePrimary(int* flagp) +{ + *flagp = 0; + + CharType op = *patternPos++; + + if (op == canonicalChar(TextType::CHAR_UNDERLINE)) + { + nodes.push(Node(opAny)); + *flagp |= FLAG_NOT_EMPTY; + } + else if (op == canonicalChar(TextType::CHAR_PERCENT)) + { + nodes.push(Node(opBranch, 3)); + nodes.push(Node(opAny)); + nodes.push(Node(opRef, -2)); + nodes.push(Node(opBranch)); + + *flagp = 0; + return; + } + else if (op == canonicalChar(TextType::CHAR_OPEN_BRACKET)) + { + if (*patternPos == canonicalChar(TextType::CHAR_CIRCUMFLEX)) + { + ++patternPos; + nodes.push(Node(opAnyBut)); + } + else + nodes.push(Node(opAnyOf)); + + HalfStaticArray charsBuffer; + HalfStaticArray rangeBuffer; + + do + { + if (patternPos >= patternEnd) + status_exception::raise(isc_invalid_similar_pattern, 0); + + bool range = false; + bool colon = false; + + if (useEscape && *patternPos == escapeChar) + { + if (++patternPos >= patternEnd) + status_exception::raise(isc_escape_invalid, 0); + + if (*patternPos != escapeChar && + notInSet(patternPos, 1, metaCharacters, FB_NELEM(metaCharacters)) != 0) + { + status_exception::raise(isc_escape_invalid, 0); + } + + if (patternPos + 1 < patternEnd) + range = (patternPos[1] == canonicalChar(TextType::CHAR_MINUS)); + } + else + { + if (*patternPos == canonicalChar(TextType::CHAR_COLON)) + colon = true; + else if (patternPos + 1 < patternEnd) + range = (patternPos[1] == canonicalChar(TextType::CHAR_MINUS)); + } + + if (colon) + { + const CharType* start = ++patternPos; + + while (patternPos < patternEnd && *patternPos != canonicalChar(TextType::CHAR_COLON)) + ++patternPos; + + if (patternPos >= patternEnd) + status_exception::raise(isc_invalid_similar_pattern, 0); + + SLONG len = patternPos++ - start; + + typedef const UCHAR* (TextType::*GetCanonicalFunc)(int*) const; + + static const GetCanonicalFunc alNum[] = {&TextType::getCanonicalUpperLetters, + &TextType::getCanonicalLowerLetters, &TextType::getCanonicalNumbers, NULL}; + static const GetCanonicalFunc alpha[] = {&TextType::getCanonicalUpperLetters, + &TextType::getCanonicalLowerLetters, NULL}; + static const GetCanonicalFunc digit[] = {&TextType::getCanonicalNumbers, NULL}; + static const GetCanonicalFunc lower[] = {&TextType::getCanonicalLowerLetters, NULL}; + static const GetCanonicalFunc space[] = {&TextType::getCanonicalSpace, NULL}; + static const GetCanonicalFunc upper[] = {&TextType::getCanonicalUpperLetters, NULL}; + static const GetCanonicalFunc whitespace[] = {&TextType::getCanonicalWhiteSpaces, NULL}; + + struct + { + const char* name; + const GetCanonicalFunc* funcs; + } static const classes[] = + { + {"ALNUM", alNum}, + {"ALPHA", alpha}, + {"DIGIT", digit}, + {"LOWER", lower}, + {"SPACE", space}, + {"UPPER", upper}, + {"WHITESPACE", whitespace} + }; + + UCharBuffer className; + + className.getBuffer(len); + className.resize(charSet->substring( + originalPatternLen, originalPatternStr, + className.getCapacity(), className.begin(), + start - patternStart, len)); + + int classN; + UCharBuffer buffer, buffer2; + + for (classN = 0; classN < FB_NELEM(classes); ++classN) + { + string s = IntlUtil::convertAsciiToUtf16(classes[classN].name); + charSet->getConvFromUnicode().convert( + s.length(), (const UCHAR*) s.c_str(), buffer); + + if (textType->compare(className.getCount(), className.begin(), + buffer.getCount(), buffer.begin()) == 0) + { + for (const GetCanonicalFunc* func = classes[classN].funcs; *func; ++func) + { + int count; + const CharType* canonic = (const CharType*) (textType->**func)(&count); + charsBuffer.push(canonic, count); + } + + break; + } + } + + if (classN >= FB_NELEM(classes)) + status_exception::raise(isc_invalid_similar_pattern, 0); + } + else + { + charsBuffer.push(*patternPos++); + + if (range) + { + --patternPos; // go back to first char + + UCHAR c[sizeof(ULONG)]; + ULONG len = charSet->substring( + originalPatternLen, originalPatternStr, + sizeof(c), c, patternPos - patternStart, 1); + + int previousRangeBufferCount = rangeBuffer.getCount(); + rangeBuffer.push(len); + memcpy(rangeBuffer.getBuffer(rangeBuffer.getCount() + len) + + rangeBuffer.getCount() - len, &c, len); + + ++patternPos; // character + ++patternPos; // minus + + if (patternPos >= patternEnd) + status_exception::raise(isc_invalid_similar_pattern, 0); + + if (useEscape && *patternPos == escapeChar) + { + if (++patternPos >= patternEnd) + status_exception::raise(isc_escape_invalid, 0); + + if (*patternPos != escapeChar && + notInSet(patternPos, 1, metaCharacters, FB_NELEM(metaCharacters)) != 0) + { + status_exception::raise(isc_escape_invalid, 0); + } + } + + len = charSet->substring( + originalPatternLen, originalPatternStr, + sizeof(c), c, patternPos - patternStart, 1); + + if (textType->compare(rangeBuffer[previousRangeBufferCount], + &rangeBuffer[previousRangeBufferCount + 1], len, c) <= 0) + { + rangeBuffer.push(len); + memcpy(rangeBuffer.getBuffer( + rangeBuffer.getCount() + len) + rangeBuffer.getCount() - len, + &c, len); + + charsBuffer.push(*patternPos); + } + else + { + rangeBuffer.shrink(previousRangeBufferCount); + charsBuffer.pop(); + } + + ++patternPos; + } + } + + if (patternPos >= patternEnd) + status_exception::raise(isc_invalid_similar_pattern, 0); + } while (*patternPos != canonicalChar(TextType::CHAR_CLOSE_BRACKET)); + + Node& node = nodes.back(); + + CharType* p = (CharType*) alloc(charsBuffer.getCount() * sizeof(CharType)); + memcpy(p, charsBuffer.begin(), charsBuffer.getCount() * sizeof(CharType)); + node.str = p; + + node.len = charsBuffer.getCount(); + + if (rangeBuffer.getCount() > 0) + { + UCHAR* p = (UCHAR*) alloc(rangeBuffer.getCount()); + memcpy(p, rangeBuffer.begin(), rangeBuffer.getCount()); + node.str2 = p; + } + + node.len2 = rangeBuffer.getCount(); + + ++patternPos; + *flagp |= FLAG_NOT_EMPTY; + } + else if (op == canonicalChar(TextType::CHAR_OPEN_PAREN)) + { + int flags; + parseExpr(&flags); + + if (patternPos >= patternEnd || *patternPos++ != canonicalChar(TextType::CHAR_CLOSE_PAREN)) + status_exception::raise(isc_invalid_similar_pattern, 0); + + *flagp |= flags & FLAG_NOT_EMPTY; + } + else if (useEscape && op == escapeChar) + { + if (patternPos >= patternEnd) + status_exception::raise(isc_escape_invalid, 0); + + if (*patternPos != escapeChar && + notInSet(patternPos, 1, metaCharacters, FB_NELEM(metaCharacters)) != 0) + { + status_exception::raise(isc_escape_invalid, 0); + } + + nodes.push(Node(opExactly, patternPos++, 1)); + *flagp |= FLAG_NOT_EMPTY; + } + else + { + --patternPos; + + SLONG len = notInSet(patternPos, patternEnd - patternPos, + metaCharacters, FB_NELEM(metaCharacters)); + + if (len == 0) + status_exception::raise(isc_invalid_similar_pattern, 0); + + *flagp |= FLAG_NOT_EMPTY | FLAG_EXACTLY; + + nodes.push(Node(opExactly, patternPos, len)); + patternPos += len; + } +} + + +template +bool SimilarToMatcher::Evaluator::isRep(CharType c) const +{ + return (c == canonicalChar(TextType::CHAR_ASTERISK) || + c == canonicalChar(TextType::CHAR_PLUS) || + c == canonicalChar(TextType::CHAR_QUESTION_MARK) || + c == canonicalChar(TextType::CHAR_OPEN_BRACE)); +} + + +#ifdef DEBUG_SIMILAR +template +void SimilarToMatcher::Evaluator::dump() const +{ + string text; + + for (unsigned i = 0; i < nodes.getCount(); ++i) + { + string type; + + switch (nodes[i].op) + { + case opRepeat: + type.printf("opRepeat(%d, %d, %d)", nodes[i].len, nodes[i].len2, nodes[i].ref); + break; + + case opBranch: + type.printf("opBranch(%d)", i + nodes[i].ref); + break; + + case opStart: + type = "opStart"; + break; + + case opEnd: + type = "opEnd"; + break; + + case opRef: + type.printf("opRef(%d)", i + nodes[i].ref); + break; + + case opNothing: + type = "opNothing"; + break; + + case opAny: + type = "opAny"; + break; + + case opAnyOf: + type.printf("opAnyOf(%.*s, %d, %.*s, %d)", + nodes[i].len, nodes[i].str, nodes[i].len, + nodes[i].len2, nodes[i].str2, nodes[i].len2); + break; + + case opAnyBut: + type.printf("opAnyBut(%.*s, %d, %.*s, %d)", + nodes[i].len, nodes[i].str, nodes[i].len, + nodes[i].len2, nodes[i].str2, nodes[i].len2); + break; + + case opExactly: + type.printf("opExactly(%.*s, %d)", nodes[i].len, nodes[i].str, nodes[i].len); + break; + + default: + type = "unknown"; + break; + } + + string s; + s.printf("%s%d:%s", (i > 0 ? ", " : ""), i, type.c_str()); + + text += s; + } + + gds__log("%s", text.c_str()); +} +#endif // DEBUG_SIMILAR + + +template +bool SimilarToMatcher::Evaluator::match() +{ + // This function should do exactly what this commented out function + // do but without recursion, which turns the code useless. + // + /*** + template + bool SimilarToMatcher::Evaluator::match(int limit = nodes.getCount(), int start = 0) + { + for (int i = start; i < limit; ++i) + { + Node* node = &nodes[i]; + + switch (node->op) + { + case opRepeat: + { + int j; + + for (j = 0; j < node->len; ++j) + { + if (!match(i + 1 + node->ref, i + 1)) + return false; + } + + for (j = node->len; j < node->len2; ++j) + { + const CharType* save = bufferPos; + + if (match(limit, i + 1 + node->ref)) + return true; + + bufferPos = save; + + if (!match(i + 1 + node->ref, i + 1)) + return false; + } + + ++i; + break; + } + + case opBranch: + { + const CharType* save = bufferPos; + + while (true) + { + if (match(limit, i + 1)) + return true; + + bufferPos = save; + + if (node->ref == 0) + return false; + + i += node->ref; + node = &nodes[i]; + + if (node->ref == 0) + break; + } + + break; + } + + case opStart: + if (bufferPos != bufferStart) + return false; + break; + + case opEnd: + if (bufferPos != bufferEnd) + return false; + break; + + case opRef: + if (node->ref == 1) // avoid recursion + break; + return match(limit, i + node->ref); + + case opNothing: + break; + + case opAny: + if (bufferPos >= bufferEnd) + return false; + ++bufferPos; + break; + + case opAnyOf: + case opAnyBut: + if (bufferPos >= bufferEnd) + return false; + else + { + const int pos = notInSet(bufferPos, 1, node->str, node->len); + + if (node->op == opAnyBut && pos == 0) + return false; + + if (node->op == opAnyOf && pos != 0) + { + const UCHAR* end = node->str2 + node->len2; + const UCHAR* p = node->str2; + + while (p < end) + { + UCHAR c[sizeof(ULONG)]; + ULONG len = charSet->substring( + buffer.getCount(), buffer.begin(), + sizeof(c), c, bufferPos - bufferStart, 1); + + if (textType->compare(len, c, p[0], p + 1) >= 0 && + textType->compare(len, c, p[1 + p[0]], p + 2 + p[0]) <= 0) + { + break; + } + + p += 2 + p[0] + p[1 + p[0]]; + } + + if (node->len2 == 0 || + (node->op == opAnyOf && p >= end) || (node->op == opAnyBut && p < end)) + { + return false; + } + } + } + + ++bufferPos; + break; + + case opExactly: + if (node->len > bufferEnd - bufferPos || + memcmp(node->str, bufferPos, node->len) != 0) + { + return false; + } + bufferPos += node->len; + break; + + default: + fb_assert(false); + return false; + } + } + + return true; + } + ***/ + // + // state description + // ---------------------- + // 0 recursing + // 1 iteration (for) + // 2 returning + + int start = 0; + int state = 0; + int limit = nodes.getCount(); + bool ret = true; + + do + { + if (state == 0) + { + scopes.push(Scope(start, limit)); + state = 1; + } + + Scope* scope; + + while (state != 0 && scopes.getCount() != 0 && + (scope = &scopes.back())->i < scope->limit) + { + const Node* node = &nodes[scope->i]; + + switch (node->op) + { + case opRepeat: + fb_assert(state == 1 || state == 2); + + if (state == 2) + { + if (scope->j < node->len) + { + if (!ret) + break; + } + else if (scope->j < node->len2) + { + if ((!scope->flag && ret) || (scope->flag && !ret)) + break; + + if (!scope->flag) + { + bufferPos = scope->save; + + scope->flag = true; + start = scope->i + 1; + limit = scope->i + 1 + node->ref; + state = 0; + + break; + } + } + ++scope->j; + } + + if (scope->j < node->len) + { + start = scope->i + 1; + limit = scope->i + 1 + node->ref; + state = 0; + } + else if (scope->j < node->len2) + { + scope->save = bufferPos; + scope->flag = false; + start = scope->i + 1 + node->ref; + limit = scope->limit; + state = 0; + } + else + { + scope->i += node->ref; + state = 1; + } + + break; + + case opBranch: + if (state == 1) + { + scope->save = bufferPos; + start = scope->i + 1; + limit = scope->limit; + state = 0; + } + else + { + fb_assert(state == 2); + + while (state == 2) + { + if (ret) + break; + + bufferPos = scope->save; + + if (node->ref == 0) + { + ret = false; + break; + } + + scope->i += node->ref; + node = &nodes[scope->i]; + + if (node->ref == 0) + state = 1; + } + } + break; + + case opStart: + fb_assert(state == 1); + if (bufferPos != bufferStart) + { + ret = false; + state = 2; + } + break; + + case opEnd: + fb_assert(state == 1); + if (bufferPos != bufferEnd) + { + ret = false; + state = 2; + } + break; + + case opRef: + fb_assert(state == 1 || state == 2); + if (state == 1) + { + if (node->ref != 1) + { + state = 0; + start = scope->i + node->ref; + limit = scope->limit; + } + } + break; + + case opNothing: + break; + + case opAny: + fb_assert(state == 1); + if (bufferPos >= bufferEnd) + { + ret = false; + state = 2; + } + else + ++bufferPos; + break; + + case opAnyOf: + case opAnyBut: + fb_assert(state == 1); + if (bufferPos >= bufferEnd) + { + ret = false; + state = 2; + } + else + { + const int pos = notInSet(bufferPos, 1, node->str, node->len); + + if (node->op == opAnyBut && pos == 0) + { + ret = false; + state = 2; + } + else if (node->op == opAnyOf && pos != 0) + { + const UCHAR* end = node->str2 + node->len2; + const UCHAR* p = node->str2; + + while (p < end) + { + UCHAR c[sizeof(ULONG)]; + ULONG len = charSet->substring( + buffer.getCount(), buffer.begin(), + sizeof(c), c, bufferPos - bufferStart, 1); + + if (textType->compare(len, c, p[0], p + 1) >= 0 && + textType->compare(len, c, p[1 + p[0]], p + 2 + p[0]) <= 0) + { + break; + } + + p += 2 + p[0] + p[1 + p[0]]; + } + + if (node->len2 == 0 || + (node->op == opAnyOf && p >= end) || (node->op == opAnyBut && p < end)) + { + ret = false; + state = 2; + } + } + } + + if (state == 1) + ++bufferPos; + break; + + case opExactly: + fb_assert(state == 1); + if (node->len > bufferEnd - bufferPos || + memcmp(node->str, bufferPos, node->len) != 0) + { + ret = false; + state = 2; + } + else + bufferPos += node->len; + break; + + default: + fb_assert(false); + return false; + } + + if (state == 1) + { + ++scope->i; + if (scope->i >= scope->limit) + { + ret = true; + state = 2; + } + } + + if (state == 2) + scopes.pop(); + } + } while (scopes.getCount() != 0); + + return ret; +} + + +// Returns the number of characters up to first one present in set. +template +SLONG SimilarToMatcher::Evaluator::notInSet( + const CharType* str, SLONG strLen, const CharType* set, SLONG setLen) +{ + for (const CharType* begin = str; str - begin < strLen; ++str) + { + for (const CharType* p = set; p - set < setLen; ++p) + { + if (*p == *str) + return str - begin; + } + } + + return strLen; +} + +} // namespace Firebird + + +#endif // JRD_SIMILAR_TO_EVALUATOR_H diff --git a/src/jrd/req.h b/src/jrd/req.h index 219044705b..28302d102b 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -33,6 +33,7 @@ #include "../jrd/exe.h" #include "../jrd/RecordNumber.h" +#include "../common/classes/stack.h" #include "../common/classes/timestamp.h" @@ -108,8 +109,9 @@ const USHORT rpb_gc_active = 256; /* garbage collecting dead record version */ /* Stream flags */ -const USHORT RPB_s_refetch = 0x1; /* re-fetch required due to sort */ -const USHORT RPB_s_update = 0x2; /* input stream fetched for update */ +const USHORT RPB_s_refetch = 0x1; // re-fetch required due to sort +const USHORT RPB_s_update = 0x2; // input stream fetched for update +const USHORT RPB_s_no_data = 0x4; // nobody is going to access the data #define SET_NULL(record, id) record->rec_data [id >> 3] |= (1 << (id & 7)) #define CLEAR_NULL(record, id) record->rec_data [id >> 3] &= ~(1 << (id & 7)) @@ -190,7 +192,7 @@ public: req_blobs(pool), req_external(*pool), req_access(*pool), req_resources(*pool), req_trg_name(*pool), req_fors(*pool), req_exec_sta(*pool), req_invariants(*pool), req_timestamp(true), req_sql_text(*pool), req_domain_validation(NULL), - req_map_field_info(*pool) + req_map_field_info(*pool), req_map_item_info(*pool), req_auto_trans(*pool) {} Attachment* req_attachment; // database attachment @@ -256,6 +258,8 @@ public: dsc* req_domain_validation; // Current VALUE for constraint validation MapFieldInfo req_map_field_info; // Map field name to field info + MapItemInfo req_map_item_info; // Map item to item info + Firebird::Stack req_auto_trans; // Autonomous transactions enum req_ta { // order should be maintained because the numbers are stored in BLR diff --git a/src/jrd/rlck.cpp b/src/jrd/rlck.cpp index 3f7f5ace20..ff11090e2b 100644 --- a/src/jrd/rlck.cpp +++ b/src/jrd/rlck.cpp @@ -26,28 +26,18 @@ #include "firebird.h" #include "../jrd/common.h" -#include "../jrd/jrd.h" #include "../jrd/tra.h" #include "../jrd/lck.h" -#include "../jrd/req.h" -#include "gen/iberror.h" -#include "../jrd/all.h" #include "../jrd/err_proto.h" -#include "../jrd/isc_proto.h" - #include "../jrd/lck_proto.h" #include "../jrd/rlck_proto.h" -#include "../jrd/thd.h" -#include "../jrd/vio_proto.h" using namespace Jrd; -static Lock* allocate_relation_lock(MemoryPool*, jrd_rel*); - - Lock* RLCK_reserve_relation(thread_db* tdbb, - jrd_tra* transaction, - jrd_rel* relation, bool write_flag, bool error_flag) + jrd_tra* transaction, + jrd_rel* relation, + bool write_flag) { /************************************** * @@ -60,15 +50,19 @@ Lock* RLCK_reserve_relation(thread_db* tdbb, * is already locked at a lower level, upgrade the lock. * **************************************/ + SET_TDBB(tdbb); + if (transaction->tra_flags & TRA_system) return NULL; if (write_flag && (tdbb->getDatabase()->dbb_flags & DBB_read_only)) ERR_post(isc_read_only_database, 0); if (write_flag && (transaction->tra_flags & TRA_readonly)) ERR_post(isc_read_only_trans, 0); - Lock* lock = RLCK_transaction_relation_lock(transaction, relation); - -/* Next, figure out what kind of lock we need */ + + Lock* lock = RLCK_transaction_relation_lock(tdbb, transaction, relation); + + // Next, figure out what kind of lock we need + USHORT level; if (transaction->tra_flags & TRA_degree3) { if (write_flag) @@ -83,38 +77,30 @@ Lock* RLCK_reserve_relation(thread_db* tdbb, level = LCK_none; } -/* If the lock is already "good enough", we're done */ + // If the lock is already "good enough", we're done if (level <= lock->lck_logical) return lock; - /* Nobody activates it. Same in FB1. - if (transaction->tra_flags & TRA_reserving) - { - ERR_post(isc_unres_rel, isc_arg_string, - relation->rel_name.c_str(), 0); - } - */ + // Get lock -/* get lock */ USHORT result; if (lock->lck_logical) - result = LCK_convert_non_blocking(NULL, lock, level, + result = LCK_convert_non_blocking(tdbb, lock, level, transaction->getLockWait()); else - result = LCK_lock_non_blocking(NULL, lock, level, + result = LCK_lock_non_blocking(tdbb, lock, level, transaction->getLockWait()); - if (result) - return lock; - else { - if (error_flag) - ERR_punt(); - return NULL; - } + if (!result) + ERR_punt(); + + return lock; } -Lock* RLCK_transaction_relation_lock(jrd_tra* transaction, jrd_rel* relation) +Lock* RLCK_transaction_relation_lock(thread_db* tdbb, + jrd_tra* transaction, + jrd_rel* relation) { /************************************** * @@ -127,6 +113,8 @@ Lock* RLCK_transaction_relation_lock(jrd_tra* transaction, jrd_rel* relation) * a transaction. * **************************************/ + SET_TDBB(tdbb); + Lock* lock; vec* vector = transaction->tra_relation_locks; if (vector && @@ -139,53 +127,28 @@ Lock* RLCK_transaction_relation_lock(jrd_tra* transaction, jrd_rel* relation) vector = transaction->tra_relation_locks = vec::newVector(*transaction->tra_pool, transaction->tra_relation_locks, relation->rel_id + 1); - - if ( (lock = (*vector)[relation->rel_id]) ) - return lock; - lock = allocate_relation_lock(transaction->tra_pool, relation); - lock->lck_owner = transaction; -/* for relations locked within a transaction, add a second level of - compatibility within the intra-process lock manager which specifies - that relation locks are incompatible with locks taken out by other - transactions, if a transaction is specified */ - lock->lck_compatible2 = transaction; - (*vector)[relation->rel_id] = lock; - - return lock; -} - - -static Lock* allocate_relation_lock(MemoryPool* pool, jrd_rel* relation) -{ -/************************************** - * - * a l l o c a t e _ r e l a t i o n _ l o c k - * - ************************************** - * - * Functional description - * Allocate a lock block for a relation lock. - * - **************************************/ - thread_db* tdbb = JRD_get_thread_data(); - Database* dbb = tdbb->getDatabase(); - - SSHORT relLockLen = relation->getRelLockKeyLength(); - - Lock* lock = FB_NEW_RPT(*pool, relLockLen) Lock(); - lock->lck_dbb = dbb; + const SSHORT relLockLen = relation->getRelLockKeyLength(); + lock = FB_NEW_RPT(*transaction->tra_pool, relLockLen) Lock(); + lock->lck_dbb = tdbb->tdbb_database; lock->lck_length = relLockLen; relation->getRelLockKey(tdbb, &lock->lck_key.lck_string[0]); lock->lck_type = LCK_relation; lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type); - lock->lck_parent = dbb->dbb_lock; -/* enter all relation locks into the intra-process lock manager and treat - them as compatible within the attachment according to IPLM rules */ - lock->lck_compatible = tdbb->getAttachment(); -/* the lck_object is used here to find the relation - block from the lock block */ + lock->lck_parent = tdbb->tdbb_database->dbb_lock; + // the lck_object is used here to find the relation + // block from the lock block lock->lck_object = relation; + // enter all relation locks into the intra-process lock manager and treat + // them as compatible within the attachment according to IPLM rules + lock->lck_compatible = tdbb->tdbb_attachment; + // for relations locked within a transaction, add a second level of + // compatibility within the intra-process lock manager which specifies + // that relation locks are incompatible with locks taken out by other + // transactions, if a transaction is specified + lock->lck_compatible2 = transaction; + + (*vector)[relation->rel_id] = lock; + return lock; } - diff --git a/src/jrd/rlck_proto.h b/src/jrd/rlck_proto.h index d9c3bd6afd..b21753fa3c 100644 --- a/src/jrd/rlck_proto.h +++ b/src/jrd/rlck_proto.h @@ -34,8 +34,9 @@ namespace Jrd { } Jrd::Lock* RLCK_reserve_relation(Jrd::thread_db*, Jrd::jrd_tra*, - Jrd::jrd_rel*, bool, bool); -Jrd::Lock* RLCK_transaction_relation_lock(Jrd::jrd_tra*, Jrd::jrd_rel*); + Jrd::jrd_rel*, bool); +Jrd::Lock* RLCK_transaction_relation_lock(Jrd::thread_db*, Jrd::jrd_tra*, + Jrd::jrd_rel*); #endif // JRD_RLCK_PROTO_H diff --git a/src/jrd/rse.cpp b/src/jrd/rse.cpp index a4388aaf81..156757718d 100644 --- a/src/jrd/rse.cpp +++ b/src/jrd/rse.cpp @@ -311,7 +311,7 @@ bool RSE_get_record(thread_db* tdbb, RecordSource* rsb, RSE_GET_MODE mode) ERR_post(isc_record_lock_not_supp, 0); } - RLCK_reserve_relation(tdbb, transaction, relation, true, true); + RLCK_reserve_relation(tdbb, transaction, relation, true); // Fetch next record if current was deleted before being locked if (!VIO_writelock(tdbb, org_rpb, rsb, transaction)) { @@ -419,7 +419,7 @@ void RSE_open(thread_db* tdbb, RecordSource* rsb) } RLCK_reserve_relation(tdbb, request->req_transaction, - rpb->rpb_relation, false, true); + rpb->rpb_relation, false); rpb->rpb_number.setValue(BOF_NUMBER); return; @@ -648,23 +648,25 @@ static SSHORT compare(thread_db* tdbb, jrd_nod* node1, jrd_nod* node2) const dsc* desc1 = EVL_expr(tdbb, *ptr1); const ULONG flags = request->req_flags; const dsc* desc2 = EVL_expr(tdbb, *ptr2); - if (flags & req_null) { + if (flags & req_null) + { if (!(request->req_flags & req_null)) { return -1; } - else { - // AB: When both expression evaluated NULL then - // we return 0 ( (NULL = NULL) = true). - // - // Currently this (0 and higher) isn't used by the - // MERGE procedure, but when we allow MERGE to - // handle outer-joins we must not forget this one !!! - return 0; - } + + // AB: When both expression evaluated NULL then + // we return 0 ( (NULL = NULL) = true). + // + // Currently this (0 and higher) isn't used by the + // MERGE procedure, but when we allow MERGE to + // handle outer-joins we must not forget this one !!! + return 0; } - else if (request->req_flags & req_null) { + + if (request->req_flags & req_null) { return 1; } + // AB: MOV_compare can't handle NULL parameters // therefore check before passing all null flags. const SSHORT result = MOV_compare(desc1, desc2); @@ -690,10 +692,12 @@ static SSHORT compare_longs(const SLONG* p, const SLONG* q, USHORT count) * **************************************/ for (; count; p++, q++, --count) + { if (*p > *q) return 1; - else if (*p < *q) + if (*p < *q) return -1; + } return 0; } @@ -803,11 +807,9 @@ static bool fetch_left(thread_db* tdbb, RecordSource* rsb, IRSB impure, RSE_GET_ { if (mode == RSE_get_backward) return false; - else - { - if (!rsb->rsb_arg[RSB_LEFT_inner_streams]) - return false; - } + + if (!rsb->rsb_left_inner_streams) + return false; /* We have a full outer join. Open up the inner stream one more time. */ @@ -821,7 +823,7 @@ static bool fetch_left(thread_db* tdbb, RecordSource* rsb, IRSB impure, RSE_GET_ /* check if the outer record qualifies for the boolean */ if (rsb->rsb_arg[RSB_LEFT_boolean] && - !EVL_boolean(tdbb, rsb->rsb_arg[RSB_LEFT_boolean])) + !EVL_boolean(tdbb, (jrd_nod*) rsb->rsb_arg[RSB_LEFT_boolean])) { /* The boolean pertaining to the left sub-stream is false so just join sub-stream to a null valued right sub-stream */ @@ -839,7 +841,7 @@ static bool fetch_left(thread_db* tdbb, RecordSource* rsb, IRSB impure, RSE_GET_ while (get_record(tdbb, rsb->rsb_arg[RSB_LEFT_inner], NULL, mode)) { if (!rsb->rsb_arg[RSB_LEFT_inner_boolean] || - EVL_boolean(tdbb, rsb->rsb_arg[RSB_LEFT_inner_boolean])) + EVL_boolean(tdbb, (jrd_nod*) rsb->rsb_arg[RSB_LEFT_inner_boolean])) { impure->irsb_flags |= irsb_joined; return true; @@ -876,8 +878,8 @@ static bool fetch_left(thread_db* tdbb, RecordSource* rsb, IRSB impure, RSE_GET_ if (!get_record(tdbb, full, NULL, mode)) { if (mode == RSE_get_forward) return false; - else - goto return_to_outer; + + goto return_to_outer; } RSE_open(tdbb, rsb->rsb_arg[RSB_LEFT_outer]); @@ -885,24 +887,19 @@ static bool fetch_left(thread_db* tdbb, RecordSource* rsb, IRSB impure, RSE_GET_ get_record(tdbb, rsb->rsb_arg[RSB_LEFT_outer], NULL, mode)) { - if ( - (!rsb->rsb_arg[RSB_LEFT_boolean] - || EVL_boolean(tdbb, - rsb-> - rsb_arg[RSB_LEFT_boolean])) - && (!rsb->rsb_arg[RSB_LEFT_inner_boolean] - || EVL_boolean(tdbb, - rsb->rsb_arg - [RSB_LEFT_inner_boolean])) - && (full == rsb->rsb_arg[RSB_LEFT_inner] - || EVL_boolean(tdbb, - rsb-> - rsb_arg - [RSB_LEFT_inner]->rsb_arg - [0]))) - { - break; - } + if ( + (!rsb->rsb_arg[RSB_LEFT_boolean] + || EVL_boolean(tdbb, + (jrd_nod*) rsb->rsb_arg[RSB_LEFT_boolean])) + && (!rsb->rsb_arg[RSB_LEFT_inner_boolean] + || EVL_boolean(tdbb, + (jrd_nod*) rsb->rsb_arg[RSB_LEFT_inner_boolean])) + && (full == rsb->rsb_arg[RSB_LEFT_inner] + || EVL_boolean(tdbb, + (jrd_nod*) rsb->rsb_arg[RSB_LEFT_inner]->rsb_arg[0]))) + { + break; + } } RSE_close(tdbb, rsb->rsb_arg[RSB_LEFT_outer]); } while (found); @@ -911,8 +908,8 @@ static bool fetch_left(thread_db* tdbb, RecordSource* rsb, IRSB impure, RSE_GET_ { if (mode == RSE_get_forward) return false; - else - goto return_to_outer; + + goto return_to_outer; } join_to_nulls(tdbb, rsb, rsb->rsb_left_inner_streams); @@ -1311,7 +1308,7 @@ static bool get_merge_join( /* Map data into target records and do comparison */ map_sort_data(tdbb, request, map, get_merge_data(tdbb, mfb, record)); - const int result = compare(tdbb, highest_ptr[1], ptr[1]); + const int result = compare(tdbb, (jrd_nod*) highest_ptr[1], (jrd_nod*) ptr[1]); if (ptr != highest_ptr) { if (((result > 0) && (impure->irsb_flags & irsb_backwards)) || @@ -1333,7 +1330,7 @@ static bool get_merge_join( if (highest_ptr != ptr) { int result; - while (result = compare(tdbb, highest_ptr[1], ptr[1])) + while (result = compare(tdbb, (jrd_nod*) highest_ptr[1], (jrd_nod*) ptr[1])) { if (((result > 0) && (impure->irsb_flags & irsb_backwards)) @@ -1928,7 +1925,7 @@ static bool get_record(thread_db* tdbb, #ifdef SCROLLABLE_CURSORS if (impure->irsb_flags & irsb_bof) { - rpb->rpb_number = -1; + rpb->rpb_number.setValue(BOF_NUMBER); } #endif if (!NAV_get_record(tdbb, rsb, (IRSB_NAV) impure, rpb, mode)) @@ -2733,14 +2730,20 @@ static void map_sort_data(thread_db* tdbb, jrd_req* request, SortMap* map, UCHAR const SSHORT id = item->smb_field_id; if (id < 0) { - if (id == SMB_TRANS_ID) + switch (id) + { + case SMB_TRANS_ID: rpb->rpb_transaction_nr = *reinterpret_cast(from.dsc_address); - else if (id == SMB_DBKEY) + break; + case SMB_DBKEY: rpb->rpb_number.setValue(*reinterpret_cast(from.dsc_address)); - else if (id == SMB_DBKEY_VALID) + break; + case SMB_DBKEY_VALID: rpb->rpb_number.setValid(*from.dsc_address != 0); - else + break; + default: fb_assert(false); + } rpb->rpb_stream_flags |= RPB_s_refetch; continue; } @@ -2969,14 +2972,20 @@ static void open_sort(thread_db* tdbb, RecordSource* rsb, irsb_sort* impure, FB_ from = &temp; record_param* rpb = &request->req_rpb[item->smb_stream]; if (item->smb_field_id < 0) { - if (item->smb_field_id == SMB_TRANS_ID) + switch (item->smb_field_id) + { + case SMB_TRANS_ID: *reinterpret_cast(to.dsc_address) = rpb->rpb_transaction_nr; - else if (item->smb_field_id == SMB_DBKEY) + break; + case SMB_DBKEY: *reinterpret_cast(to.dsc_address) = rpb->rpb_number.getValue(); - else if (item->smb_field_id == SMB_DBKEY_VALID) + break; + case SMB_DBKEY_VALID: *to.dsc_address = (UCHAR) rpb->rpb_number.isValid(); - else + break; + default: fb_assert(false); + } continue; } if (!EVL_field @@ -3702,31 +3711,29 @@ bool RSBRecurse::get(thread_db* tdbb, RecordSource* rsb, irsb_recurse* irsb) { return false; } - else + + RSE_close(tdbb, *rsb_ptr); + delete[] irsb->irsb_data; + + char* tmp = irsb->irsb_stack; + memcpy(irsb, tmp, inner_size); + + char* p = tmp + inner_size; + RecordSource** ptr = rsb->rsb_arg + rsb->rsb_count + 1; + const RecordSource* const* end = ptr + streams; + for (; ptr < end; ptr++) { - RSE_close(tdbb, *rsb_ptr); - delete[] irsb->irsb_data; + record_param* rpb = request->req_rpb + (USHORT)(U_IPTR) *ptr; + Record* rec = rpb->rpb_record; + memmove(rpb, p, sizeof(record_param)); + p += sizeof(record_param); - char* tmp = irsb->irsb_stack; - memcpy(irsb, tmp, inner_size); - - char* p = tmp + inner_size; - RecordSource** ptr = rsb->rsb_arg + rsb->rsb_count + 1; - const RecordSource* const* end = ptr + streams; - for (; ptr < end; ptr++) - { - record_param* rpb = request->req_rpb + (USHORT)(U_IPTR) *ptr; - Record* rec = rpb->rpb_record; - memmove(rpb, p, sizeof(record_param)); - p += sizeof(record_param); - - if (!rpb->rpb_record) { - rpb->rpb_record = rec; - } - fb_assert(rpb->rpb_record == rec); + if (!rpb->rpb_record) { + rpb->rpb_record = rec; } - delete[] tmp; + fb_assert(rpb->rpb_record == rec); } + delete[] tmp; if (irsb->irsb_level > 1) { diff --git a/src/jrd/sch.cpp b/src/jrd/sch.cpp index 4d7bd36207..636ebd43d8 100644 --- a/src/jrd/sch.cpp +++ b/src/jrd/sch.cpp @@ -28,7 +28,7 @@ #include #include #include "../jrd/common.h" -#include "../jrd/thd.h" +#include "../jrd/ThreadStart.h" #include "../jrd/isc.h" #include "../jrd/ibase.h" #include "../jrd/gds_proto.h" @@ -46,84 +46,109 @@ #endif -/* must be careful with alignment on structures like this that are - not run through the ALL routine */ - struct thread { - struct thread *thread_next; /* Next thread to be scheduled */ - struct thread *thread_prior; /* Prior thread */ - event_t thread_stall[1]; /* Generic event to stall thread */ - FB_THREAD_ID thread_id; /* Current thread id */ - USHORT thread_count; /* AST disable count */ - USHORT thread_flags; /* Flags */ + thread* thread_next; // Next thread to be scheduled + thread* thread_prior; // Prior thread + event_t thread_stall; // Generic event to stall thread + FB_THREAD_ID thread_id; // Current thread ID + USHORT thread_count; // AST disable count + USHORT thread_flags; // Flags }; typedef thread *THREAD; // thread_flags -const USHORT THREAD_hiber = 1; /* Thread is hibernating */ -const USHORT THREAD_ast_disabled = 2; /* Disable AST delivery */ -const USHORT THREAD_ast_active = 4; /* Disable AST preemption while AST active */ -const USHORT THREAD_ast_pending = 8; /* AST waiting to be delivered */ +const USHORT THREAD_hiber = 1; // Thread is hibernating +const USHORT THREAD_ast_disabled = 2; // Disable AST delivery +const USHORT THREAD_ast_active = 4; // Disable AST preemption while AST active +const USHORT THREAD_ast_pending = 8; // AST waiting to be delivered -static THREAD alloc_thread(void); -static bool ast_enable(void); -static void ast_disable(void); -static void cleanup(void *); +static THREAD alloc_thread(); +static bool ast_enable(); +static void ast_disable(); static void mutex_bugcheck(const TEXT*, int); -static bool schedule(void); +static void schedule(); static bool schedule_active(bool); static void stall(THREAD); static void stall_ast(THREAD); -static void sch_mutex_lock(Firebird::Mutex&); -static void sch_mutex_unlock(Firebird::Mutex&); static THREAD free_threads = NULL; static THREAD active_thread = NULL; static THREAD ast_thread = NULL; static Firebird::Mutex thread_mutex; -volatile static bool init_flag = false; -static USHORT enabled = FALSE; +namespace { -#ifdef VMS -int API_ROUTINE gds__ast_active(void) +class SchedulerInit { -/************************************** - * - * g d s _ $ a s t _ a c t i v e - * - ************************************** - * - * Functional description - * An asynchronous operation has completed, wake somebody - * up, if necessary. - * - **************************************/ +public: + SchedulerInit() + {} - return THREAD_ast_active(); -} + ~SchedulerInit() + { +#ifdef SUPERCLIENT + // Loop through the list of active threads and free the events + THREAD temp_thread = active_thread; + if (temp_thread) { + while (temp_thread != temp_thread->thread_prior) + temp_thread = temp_thread->thread_prior; -void API_ROUTINE gds__completion_ast(int *arg) -{ -/************************************** - * - * g d s _ $ c o m p l e t i o n _ a s t - * - ************************************** - * - * Functional description - * An asynchronous operation has completed, wake somebody - * up, if necessary. - * - **************************************/ + do { + ISC_event_fini(&temp_thread->thread_stall); + // the thread structures are freed as a part of the + // gds_alloc cleanup, so do not worry about them here + } while (temp_thread->thread_next != temp_thread && + (temp_thread = temp_thread->thread_next)); + } - THREAD_completion_ast(); - sys$wake(0, 0); -} + // Loop through the list of free threads and free the events + + if ( (temp_thread = free_threads) ) { + while (temp_thread != temp_thread->thread_prior) + temp_thread = temp_thread->thread_prior; + + do { + ISC_event_fini(&temp_thread->thread_stall); + // the thread structures are freed as a part of the + // gds_alloc cleanup, so do not worry about them here + } while (temp_thread->thread_next != temp_thread && + (temp_thread = temp_thread->thread_next)); + } #endif + } +}; + +} // namespace + +static SchedulerInit initHolder; + + +static inline void sch_mutex_lock() +{ + try + { + thread_mutex.enter(); + } + catch (const Firebird::system_call_failed& e) + { + mutex_bugcheck("mutex lock", e.getErrorCode()); + } +} + +static inline void sch_mutex_unlock() +{ + try + { + thread_mutex.leave(); + } + catch (const Firebird::system_call_failed& e) + { + mutex_bugcheck("mutex unlock", e.getErrorCode()); + } +} int API_ROUTINE gds__thread_enable(int enable_flag) @@ -139,16 +164,11 @@ int API_ROUTINE gds__thread_enable(int enable_flag) * **************************************/ - if (enable_flag) { - enabled = TRUE; - SCH_init(); - } - - return enabled; + return true; } -void API_ROUTINE gds__thread_enter(void) +void API_ROUTINE gds__thread_enter() { /************************************** * @@ -165,7 +185,7 @@ void API_ROUTINE gds__thread_enter(void) } -void API_ROUTINE gds__thread_exit(void) +void API_ROUTINE gds__thread_exit() { /************************************** * @@ -182,74 +202,6 @@ void API_ROUTINE gds__thread_exit(void) } -#ifdef VMS -int API_ROUTINE gds__thread_wait(FPTR_INT entrypoint, SLONG arg) -{ -/************************************** - * - * g d s _ $ t h r e a d _ w a i t - * - ************************************** - * - * Functional description - * Stall a thread with a callback to determine runnability. - * - **************************************/ - - return thread_wait(entrypoint, arg); -} -#endif - - -void SCH_abort(void) -{ -/************************************** - * - * S C H _ a b o r t - * - ************************************** - * - * Functional description - * Try to abort the current thread. If the thread is active, - * unlink it. - * - **************************************/ - -/* If threading isn't active, don't sweat it */ - - if (!active_thread) - return; - -/* See if we can find thread. If not, don't worry about it */ - - const FB_THREAD_ID id = ThreadData::getId(); - THREAD thread; - for (THREAD* ptr = &active_thread; thread = *ptr; ptr = &thread->thread_next) - { - if (thread->thread_id == id) - break; - if (thread->thread_next == active_thread) - return; - } - -/* If we're the active thread, do a normal thread exit */ - - if (thread == active_thread) { - SCH_exit(); - return; - } - -/* We're on the list but not active. Remove from list */ - - sch_mutex_lock(thread_mutex); - thread->thread_prior->thread_next = thread->thread_next; - thread->thread_next->thread_prior = thread->thread_prior; - thread->thread_next = free_threads; - free_threads = thread; - sch_mutex_unlock(thread_mutex); -} - - void SCH_ast(enum ast_t action) { /************************************** @@ -266,28 +218,28 @@ void SCH_ast(enum ast_t action) * In case you're wondering: AST = Asynchronous System Trap * **************************************/ - if (!ast_thread && !(action == AST_alloc || action == AST_disable || - action == AST_enable)) + if (!ast_thread && + !(action == AST_alloc || action == AST_disable || action == AST_enable)) { - /* Better be an AST thread before we do anything to it! */ - fb_assert(FALSE); + // Better be an AST thread before we do anything to it! + fb_assert(false); return; } if (ast_thread && action == AST_check) + { if (!(ast_thread->thread_flags & THREAD_ast_pending) || ast_thread->thread_count > 1) { return; } + } - if (!init_flag) - SCH_init(); - - sch_mutex_lock(thread_mutex); + sch_mutex_lock(); switch (action) { - /* Check into thread scheduler as AST thread */ + + // Check into thread scheduler as AST thread case AST_alloc: ast_thread = alloc_thread(); @@ -296,10 +248,10 @@ void SCH_ast(enum ast_t action) break; case AST_init: - ast_thread->thread_id = ThreadData::getId(); + ast_thread->thread_id = getThreadId(); break; - /* Check out of thread scheduler as AST thread */ + // Check out of thread scheduler as AST thread case AST_fini: ast_thread->thread_next = free_threads; @@ -307,20 +259,19 @@ void SCH_ast(enum ast_t action) ast_thread = NULL; break; - /* Disable AST delivery if not an AST thread */ + // Disable AST delivery if not an AST thread case AST_disable: ast_disable(); break; - /* Reenable AST delivery if not an AST thread */ + // Reenable AST delivery if not an AST thread case AST_enable: ast_enable(); break; - /* Active thread allows a pending AST to be delivered - and waits */ + // Active thread allows a pending AST to be delivered and waits case AST_check: if (ast_enable()) @@ -329,7 +280,7 @@ void SCH_ast(enum ast_t action) ast_disable(); break; - /* Request AST delivery and prevent thread scheduling */ + // Request AST delivery and prevent thread scheduling case AST_enter: if (ast_thread->thread_flags & THREAD_ast_disabled) { @@ -339,28 +290,28 @@ void SCH_ast(enum ast_t action) ast_thread->thread_flags |= THREAD_ast_active; break; - /* AST delivery complete; resume thread scheduling */ + // AST delivery complete; resume thread scheduling case AST_exit: ast_thread->thread_flags &= ~(THREAD_ast_active | THREAD_ast_pending); if (active_thread) - ISC_event_post(active_thread->thread_stall); + ISC_event_post(&active_thread->thread_stall); - /* Post non-active threads that have requested AST disabling */ + // Post non-active threads that have requested AST disabling for (THREAD thread = ast_thread->thread_next; thread != ast_thread; thread = thread->thread_next) { - ISC_event_post(thread->thread_stall); + ISC_event_post(&thread->thread_stall); } break; } - sch_mutex_unlock(thread_mutex); + sch_mutex_unlock(); } -THREAD SCH_current_thread(void) +THREAD SCH_current_thread() { /************************************** * @@ -378,7 +329,7 @@ THREAD SCH_current_thread(void) } -void SCH_enter(void) +void SCH_enter() { /************************************** * @@ -392,36 +343,20 @@ void SCH_enter(void) * **************************************/ -/* Special case single thread case */ - -#ifndef MULTI_THREAD - if (free_threads) { - THREAD thread = active_thread = free_threads; - free_threads = NULL; - thread->thread_next = thread->thread_prior = thread; - thread->thread_flags = 0; - thread->thread_id = ThreadData::getId(); + if (ast_thread && ast_thread->thread_id == getThreadId()) return; - } -#endif - if (!init_flag) { - SCH_init(); - } - -/* Get mutex on scheduler data structures to prevent tragic misunderstandings */ - - sch_mutex_lock(thread_mutex); + sch_mutex_lock(); THREAD thread = alloc_thread(); - thread->thread_id = ThreadData::getId(); + thread->thread_id = getThreadId(); -/* Link thread block into circular list of active threads */ + // Link thread block into circular list of active threads if (active_thread) { - /* The calling thread should NOT be the active_thread - This is to prevent deadlock by the same thread */ + // The calling thread should NOT be the active_thread. + // This is to prevent deadlock by the same thread. fb_assert(thread->thread_id != active_thread->thread_id); thread->thread_next = active_thread; @@ -442,11 +377,11 @@ void SCH_enter(void) } stall(thread); - sch_mutex_unlock(thread_mutex); + sch_mutex_unlock(); } -void SCH_exit(void) +void SCH_exit() { /************************************** * @@ -459,16 +394,24 @@ void SCH_exit(void) * scheduler, and release thread block. * **************************************/ - SCH_validate(); -#ifndef MULTI_THREAD - free_threads = active_thread; - active_thread = NULL; - free_threads->thread_next = NULL; -#else - sch_mutex_lock(thread_mutex); + if (ast_thread && ast_thread->thread_id == getThreadId()) + return; - ast_enable(); /* Reenable AST delivery */ + // Validate thread + + if (!active_thread) { + gds__log("Thread validation: not entered"); + fb_assert(false); + } + else if (active_thread->thread_id != getThreadId()) { + gds__log("Thread validation: wrong thread"); + fb_assert(false); + } + + sch_mutex_lock(); + + ast_enable(); // Reenable AST delivery THREAD thread = active_thread; @@ -477,7 +420,7 @@ void SCH_exit(void) // handler there calls THREAD_EXIT without preceding THREAD_ENTER // in this case (during shutdown of CACHE_WRITER or CACHE_READER) if (!thread) { - sch_mutex_unlock(thread_mutex); + sch_mutex_unlock(); return; } @@ -496,12 +439,11 @@ void SCH_exit(void) free_threads = thread; schedule(); - sch_mutex_unlock(thread_mutex); -#endif + sch_mutex_unlock(); } -void SCH_hiber(void) +void SCH_hiber() { /************************************** * @@ -518,46 +460,7 @@ void SCH_hiber(void) schedule_active(true); } -#ifdef MULTI_THREAD -static Firebird::Mutex scheduler_init_lock; -#endif - -void SCH_init(void) -{ -/************************************** - * - * S C H _ i n i t - * - ************************************** - * - * Functional description - * Initialize the thread scheduler. - * - **************************************/ - if (init_flag) - return; - -#ifdef MULTI_THREAD - scheduler_init_lock.enter(); - - try { - if (!init_flag) { -#endif - gds__register_cleanup(cleanup, 0); - init_flag = true; -#ifdef MULTI_THREAD - } - } - catch (const Firebird::Exception&) { - scheduler_init_lock.leave(); - throw; - } - scheduler_init_lock.leave(); -#endif -} - - -bool SCH_schedule(void) +bool SCH_schedule() { /************************************** * @@ -570,11 +473,12 @@ bool SCH_schedule(void) * If a context switch actually happened, return true. * **************************************/ + return schedule_active(false); } -bool SCH_thread_enter_check(void) +bool SCH_thread_enter_check() { /************************************** * @@ -588,8 +492,9 @@ bool SCH_thread_enter_check(void) * **************************************/ -/* if active thread is not null and thread_id matches the we are the - active thread */ + // If active thread is not null and thread_id matches + // then we are the active thread + sch_mutex_lock(thread_mutex); const bool ret = ((active_thread) && (active_thread->thread_id == ThreadData::getId())); sch_mutex_unlock(thread_mutex); @@ -598,38 +503,6 @@ bool SCH_thread_enter_check(void) } -bool SCH_validate(void) -{ -/************************************** - * - * S C H _ v a l i d a t e - * - ************************************** - * - * Functional description - * Check integrity of thread system (assume thread is entered). - * - **************************************/ - - if (!init_flag || !active_thread) { - gds__log("SCH_validate -- not entered"); - // CVC: No need to replace by fb_utils::readenv() I think. - if (getenv("ISC_PUNT")) - abort(); - return false; - } - -#ifdef MULTI_THREAD - if (active_thread->thread_id != ThreadData::getId()) { - gds__log("SCH_validate -- wrong thread"); - return false; - } -#endif - - return true; -} - - void SCH_wake(THREAD thread) { /************************************** @@ -643,11 +516,11 @@ void SCH_wake(THREAD thread) * **************************************/ thread->thread_flags &= ~THREAD_hiber; - ISC_event_post(thread->thread_stall); + ISC_event_post(&thread->thread_stall); } -static THREAD alloc_thread(void) +static THREAD alloc_thread() { /************************************** * @@ -660,31 +533,31 @@ static THREAD alloc_thread(void) * **************************************/ -/* Find a useable thread block. If there isn't one, allocate one */ + // Find a useable thread block. If there isn't one, allocate one. THREAD thread = free_threads; if (thread) free_threads = thread->thread_next; else { thread = (THREAD) gds__alloc((SLONG) sizeof(struct thread)); - /* FREE: unknown */ - if (!thread) /* NOMEM: bugcheck */ - mutex_bugcheck("Out of memory", 0); /* no real error handling */ + if (!thread) + mutex_bugcheck("Out of memory", 0); // no real error handling #ifdef DEBUG_GDS_ALLOC - /* There is one thread structure allocated per thread, and this - * is never freed except by process exit - */ + // There is one thread structure allocated per thread, and this + // is never freed except by process exit gds_alloc_flag_unfreed((void *) thread); #endif - ISC_event_init(thread->thread_stall, 0, 0); + ISC_event_init(&thread->thread_stall, 0, 0); } - thread->thread_flags = thread->thread_count = 0; + thread->thread_flags = 0; + thread->thread_count = 0; + return thread; } -static bool ast_enable(void) +static bool ast_enable() { /************************************** * @@ -701,7 +574,7 @@ static bool ast_enable(void) return false; if (ast_thread->thread_flags & THREAD_ast_active && - ast_thread->thread_id == ThreadData::getId()) + ast_thread->thread_id == getThreadId()) { return false; } @@ -710,7 +583,7 @@ static bool ast_enable(void) ast_thread->thread_flags &= ~THREAD_ast_disabled; if (ast_thread->thread_flags & THREAD_ast_pending) { ast_thread->thread_flags |= THREAD_ast_active; - ISC_event_post(ast_thread->thread_stall); + ISC_event_post(&ast_thread->thread_stall); return true; } } @@ -719,7 +592,7 @@ static bool ast_enable(void) } -static void ast_disable(void) +static void ast_disable() { /************************************** * @@ -737,11 +610,11 @@ static void ast_disable(void) return; if (ast_thread->thread_flags & THREAD_ast_active) { - if (ast_thread->thread_id == ThreadData::getId()) + if (ast_thread->thread_id == getThreadId()) return; else { - if (active_thread - && active_thread->thread_id == ThreadData::getId()) + if (active_thread && + active_thread->thread_id == getThreadId()) { stall(active_thread); return; @@ -760,75 +633,6 @@ static void ast_disable(void) } -static void cleanup(void *arg) -{ -/************************************** - * - * c l e a n u p - * - ************************************** - * - * Functional description - * Exit handler for image exit. - * - **************************************/ - if (!init_flag) - return; - -/* this is added to make sure that we release the memory - * we have allocated for the thread event handler through - * ISC_event_handle () (CreateEvent) */ - -#ifdef SUPERCLIENT -/* use locks */ - thread_mutex.enter(); - - if (!init_flag) - return; - -/* loop through the list of active threads and free the events */ - THREAD temp_thread = active_thread; - if (temp_thread) { - /* reach to the starting of the list */ - while (temp_thread != temp_thread->thread_prior) - temp_thread = temp_thread->thread_prior; - /* now we are at the begining of the list. Now start freeing the - * EVENT structures and move to the next */ - do { - ISC_event_fini(temp_thread->thread_stall); - /* the thread structures are freed as a part of the - * gds_alloc cleanup, so do not worry about them here - */ - } while (temp_thread->thread_next != temp_thread - && (temp_thread = temp_thread->thread_next)); - - } - -/* loop through the list of free threads and free the events */ - if (temp_thread = free_threads) { - /* reach to the starting of the list */ - while (temp_thread != temp_thread->thread_prior) - temp_thread = temp_thread->thread_prior; - /* now we are at the begining of the list. Now start freeing the - * EVENT structures and move to the next */ - do { - ISC_event_fini(temp_thread->thread_stall); - /* the thread structures are freed as a part of the - * gds_alloc cleanup, so do not worry about them here - */ - } while (temp_thread->thread_next != temp_thread - && (temp_thread = temp_thread->thread_next)); - - - } - - thread_mutex.leave(); -#endif /* SUPERCLIENT */ - - init_flag = false; -} - - static void mutex_bugcheck(const TEXT* string, int mutex_state) { /************************************** @@ -852,8 +656,7 @@ static void mutex_bugcheck(const TEXT* string, int mutex_state) } -// CVC: Nobody checks the result from this function. -static bool schedule(void) +static void schedule() { /************************************** * @@ -868,22 +671,20 @@ static bool schedule(void) * **************************************/ if (!active_thread) - return false; + return; THREAD thread = active_thread; - for (;;) { + while (true) { thread = thread->thread_next; if (!(thread->thread_flags & THREAD_hiber)) break; if (thread == active_thread) - return false; + return; } active_thread = thread; - ISC_event_post(active_thread->thread_stall); - - return true; + ISC_event_post(&active_thread->thread_stall); } @@ -900,16 +701,13 @@ static bool schedule_active(bool hiber_flag) * If a context switch actually happened, return true. * **************************************/ -#ifndef MULTI_THREAD - return false; -#else if (!active_thread) return false; - sch_mutex_lock(thread_mutex); + sch_mutex_lock(); -/* Take this opportunity to check for pending ASTs - and deliver them. */ + // Take this opportunity to check for pending ASTs + // and deliver them if (ast_enable()) stall(active_thread); @@ -929,10 +727,9 @@ static bool schedule_active(bool hiber_flag) ret = true; } - sch_mutex_unlock(thread_mutex); + sch_mutex_unlock(); return ret; -#endif } @@ -951,23 +748,23 @@ static void stall(THREAD thread) if (thread != active_thread || thread->thread_flags & THREAD_hiber || (ast_thread && ast_thread->thread_flags & THREAD_ast_active)) { - for (;;) { - SLONG value = ISC_event_clear(thread->thread_stall); - if (thread == active_thread - && !(thread->thread_flags & THREAD_hiber) - && (!ast_thread - || !(ast_thread->thread_flags & THREAD_ast_active))) + while (true) { + const SLONG value = ISC_event_clear(&thread->thread_stall); + if (thread == active_thread && + !(thread->thread_flags & THREAD_hiber) && + (!ast_thread || + !(ast_thread->thread_flags & THREAD_ast_active))) { break; } - sch_mutex_unlock(thread_mutex); - event_t* ptr = thread->thread_stall; - ISC_event_wait(1, &ptr, &value, 0, 0, 0); - sch_mutex_lock(thread_mutex); + sch_mutex_unlock(); + event_t* ptr = &thread->thread_stall; + ISC_event_wait(1, &ptr, &value, 0); + sch_mutex_lock(); } } -/* Explicitly disable AST delivery for active thread */ + // Explicitly disable AST delivery for active thread ast_disable(); } @@ -990,85 +787,42 @@ static void stall_ast(THREAD thread) **************************************/ if (thread == ast_thread) { if (ast_thread->thread_flags & THREAD_ast_disabled) - for (;;) { - SLONG value = ISC_event_clear(thread->thread_stall); + while (true) { + const SLONG value = ISC_event_clear(&thread->thread_stall); if (!(ast_thread->thread_flags & THREAD_ast_disabled)) break; - sch_mutex_unlock(thread_mutex); - event_t* ptr = thread->thread_stall; - ISC_event_wait(1, &ptr, &value, 0, 0, 0); - sch_mutex_lock(thread_mutex); + sch_mutex_unlock(); + event_t* ptr = &thread->thread_stall; + ISC_event_wait(1, &ptr, &value, 0); + sch_mutex_lock(); } } else { - /* Link thread block into ast thread queue */ + // Link thread block into ast thread queue thread->thread_next = ast_thread->thread_next; thread->thread_prior = ast_thread; ast_thread->thread_next->thread_prior = thread; ast_thread->thread_next = thread; - /* Wait for AST delivery to complete */ + // Wait for AST delivery to complete if (ast_thread->thread_flags & THREAD_ast_active) - for (;;) { - SLONG value = ISC_event_clear(thread->thread_stall); + { + while (true) { + const SLONG value = ISC_event_clear(&thread->thread_stall); if (!(ast_thread->thread_flags & THREAD_ast_active)) break; - sch_mutex_unlock(thread_mutex); - event_t* ptr = thread->thread_stall; - ISC_event_wait(1, &ptr, &value, 0, 0, 0); - sch_mutex_lock(thread_mutex); + sch_mutex_unlock(); + event_t* ptr = &thread->thread_stall; + ISC_event_wait(1, &ptr, &value, 0); + sch_mutex_lock(); } - /* Unlink thread block from ast thread queue */ + } + + // Unlink thread block from ast thread queue thread->thread_prior->thread_next = thread->thread_next; thread->thread_next->thread_prior = thread->thread_prior; } } - - -static void sch_mutex_lock(Firebird::Mutex& mtx) -{ -/************************************** - * - * s c h _ m u t e x _ l o c k - * - ************************************** - * - * Functional description - * Enters mutex, on error bugcheks. - * - **************************************/ - try - { - mtx.enter(); - } - catch (const Firebird::system_call_failed& e) - { - mutex_bugcheck("mutex lock", e.getErrorCode()); - } -} - - -static void sch_mutex_unlock(Firebird::Mutex& mtx) -{ -/************************************** - * - * s c h _ m u t e x _ u n l o c k - * - ************************************** - * - * Functional description - * Leaves mutex, on error bugcheks. - * - **************************************/ - try - { - mtx.leave(); - } - catch (const Firebird::system_call_failed& e) - { - mutex_bugcheck("mutex unlock", e.getErrorCode()); - } -} diff --git a/src/jrd/sch_proto.h b/src/jrd/sch_proto.h index a896b1ff84..f53566b14d 100644 --- a/src/jrd/sch_proto.h +++ b/src/jrd/sch_proto.h @@ -43,31 +43,20 @@ enum ast_t }; int API_ROUTINE gds__thread_enable(int); -void API_ROUTINE gds__thread_enter(void); -void API_ROUTINE gds__thread_exit(void); -#ifdef VMS -int API_ROUTINE gds__ast_active(void); -void API_ROUTINE gds__completion_ast(void); -int API_ROUTINE gds__thread_wait(int (*)(), SLONG); -#endif // VMS +void API_ROUTINE gds__thread_enter(); +void API_ROUTINE gds__thread_exit(); } // extern "C" struct thread; -void SCH_abort(void); - -extern "C" void SCH_ast(enum ast_t); - -thread* SCH_current_thread(void); -void SCH_enter(void); -void SCH_exit(void); -void SCH_hiber(void); -void SCH_init(void); -bool SCH_schedule(void); -bool SCH_thread_enter_check(void); -bool SCH_validate(void); +thread* SCH_current_thread(); +void SCH_enter(); +void SCH_exit(); +void SCH_hiber(); +bool SCH_schedule(); +bool SCH_thread_enter_check(); void SCH_wake(thread*); diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index a8684a68c9..d46076ddf2 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -66,11 +66,7 @@ #include "../common/config/config.h" -#ifdef VMS -const int UIC_BASE = 8; -#else const int UIC_BASE = 10; -#endif const SLONG BLOB_BUFFER_SIZE = 4096; /* used to read in acl blob */ @@ -125,7 +121,7 @@ void SCL_check_access(const SecurityClass* s_class, const Firebird::MetaName& prc_name, SecurityClass::flags_t mask, const TEXT* type, - const Firebird::MetaName& name) + const char* name) { /************************************** * @@ -149,12 +145,6 @@ void SCL_check_access(const SecurityClass* s_class, 0); } - // Don't run internal handles thru the security gauntlet. - if (JRD_get_thread_security_disabled()) - { - return; - } - const Attachment* const attachment = tdbb->getAttachment(); // Allow the database owner to back up a database even if he does not have @@ -165,6 +155,13 @@ void SCL_check_access(const SecurityClass* s_class, return; } + // Allow the locksmith any access to database + + if (attachment->locksmith()) + { + return; + } + bool denied_db = false; const SecurityClass* const att_class = attachment->att_security_class; @@ -208,12 +205,45 @@ void SCL_check_access(const SecurityClass* s_class, ERR_post(isc_no_priv, isc_arg_string, names->p_names_string, isc_arg_string, type, - isc_arg_string, ERR_cstring(name.c_str()), + isc_arg_string, ERR_cstring(name), 0); } } +void SCL_check_access(const SecurityClass* s_class, + SLONG view_id, + const Firebird::MetaName& trg_name, + const Firebird::MetaName& prc_name, + SecurityClass::flags_t mask, + const TEXT* type, + const Firebird::MetaName& name, + const Firebird::MetaName& r_name) +{ +/************************************** + * + * S C L _ c h e c k _ a c c e s s + * + ************************************** + * + * Functional description + * Check security class for desired permission. + * Alternate entrypoint. + * + **************************************/ + Firebird::string fullFieldName(name.c_str()); + if (r_name.hasData()) + { + fullFieldName = r_name.c_str(); + fullFieldName += '.'; + fullFieldName += name.c_str(); + } + + SCL_check_access(s_class, view_id, trg_name, prc_name, + mask, type, fullFieldName.c_str()); +} + + void SCL_check_index(thread_db* tdbb, const Firebird::MetaName& index_name, UCHAR index_id, SecurityClass::flags_t mask) { @@ -318,14 +348,18 @@ void SCL_check_index(thread_db* tdbb, const Firebird::MetaName& index_name, UCHA WITH RF.RDB$RELATION_NAME EQ reln_name.c_str() AND ISEG.RDB$INDEX_NAME EQ idx_name_ptr->c_str() + Firebird::string fullFieldName(reln_name.c_str()); + fullFieldName += '.'; + fullFieldName += RF.RDB$FIELD_NAME; + fullFieldName.rtrim(); if (!RF.RDB$SECURITY_CLASS.NULL) { s_class = SCL_get_class(RF.RDB$SECURITY_CLASS); - SCL_check_access(s_class, 0, NULL, NULL, mask, - object_column, RF.RDB$FIELD_NAME); + SCL_check_access(s_class, 0, NULL, NULL, mask, + object_column, fullFieldName); } else { SCL_check_access(default_s_class, 0, NULL, NULL, mask, - object_column, RF.RDB$FIELD_NAME); + object_column, fullFieldName); } END_FOR; @@ -634,7 +668,7 @@ void SCL_init(bool create, AND RR.RDB$ROLE_NAME EQ UU.RDB$RELATION_NAME AND UU.RDB$OBJECT_TYPE EQ obj_sql_role AND (UU.RDB$USER EQ login_name - OR UU.RDB$USER EQ "PUBLIC") + OR UU.RDB$USER EQ "PUBLIC") AND UU.RDB$USER_TYPE EQ obj_user AND UU.RDB$PRIVILEGE EQ "M" @@ -649,6 +683,26 @@ void SCL_init(bool create, if (!REQUEST (irq_verify_role_name)) REQUEST (irq_verify_role_name) = request; + if (!found && (tempId.usr_flags & USR_trole)) + { + jrd_req* request = CMP_find_request (tdbb, irq_verify_trusted_role, IRQ_REQUESTS); + + FOR (REQUEST_HANDLE request) FIRST 1 RR IN RDB$ROLES + WITH RR.RDB$ROLE_NAME EQ sql_role + AND RR.RDB$SYSTEM_FLAG NOT MISSING + + if (!REQUEST (irq_verify_trusted_role)) + REQUEST (irq_verify_trusted_role) = request; + + if (RR.RDB$SYSTEM_FLAG & ROLE_FLAG_MAY_TRUST) + found = true; + + END_FOR; + + if (!REQUEST (irq_verify_trusted_role)) + REQUEST (irq_verify_trusted_role) = request; + } + if (!found) { role_name = NULL_ROLE; @@ -669,10 +723,11 @@ void SCL_init(bool create, user->usr_sql_role_name = role_name.c_str(); tdbb->getAttachment()->att_user = user; - jrd_req* handle = NULL; - jrd_req* handle1 = NULL; - if (!create) { + jrd_req* handle = NULL; + jrd_req* handle1 = NULL; + jrd_req* handle2 = NULL; + FOR(REQUEST_HANDLE handle) X IN RDB$DATABASE if (!X.RDB$SECURITY_CLASS.NULL) @@ -698,6 +753,17 @@ void SCL_init(bool create, } END_FOR; CMP_release(tdbb, handle1); + + FOR(REQUEST_HANDLE handle2) R IN RDB$ROLES + WITH R.RDB$ROLE_NAME EQ role_name.c_str() + + if (!R.RDB$SYSTEM_FLAG.NULL) + { + if (R.RDB$SYSTEM_FLAG & ROLE_FLAG_DBO) + user->usr_flags |= USR_dba; + } + END_FOR; + CMP_release(tdbb, handle2); } else { user->usr_flags |= USR_owner; diff --git a/src/jrd/scl.h b/src/jrd/scl.h index 1fa6720fa8..cca7ac12e5 100644 --- a/src/jrd/scl.h +++ b/src/jrd/scl.h @@ -59,6 +59,8 @@ const SecurityClass::flags_t SCL_execute = 8192; const USHORT USR_locksmith = 1; /* User has great karma */ const USHORT USR_dba = 2; /* User has DBA privileges */ const USHORT USR_owner = 4; /* User owns database */ +const USHORT USR_trole = 8; /* Role was set by trusted auth */ + class UserId { @@ -75,7 +77,7 @@ public: bool locksmith() const { - return usr_flags & (USR_locksmith | USR_owner); + return usr_flags & (USR_locksmith | USR_owner | USR_dba); } UserId() : usr_user_id(0), usr_group_id(0), diff --git a/src/jrd/scl_proto.h b/src/jrd/scl_proto.h index 231edacbf4..d747d8f9d5 100644 --- a/src/jrd/scl_proto.h +++ b/src/jrd/scl_proto.h @@ -35,7 +35,31 @@ struct dsc; void SCL_check_access(const Jrd::SecurityClass*, SLONG, const Firebird::MetaName&, const Firebird::MetaName&, Jrd::SecurityClass::flags_t, - const TEXT*, const Firebird::MetaName&); + const TEXT*, const char*); +void SCL_check_access(const Jrd::SecurityClass*, SLONG, const Firebird::MetaName&, + const Firebird::MetaName&, Jrd::SecurityClass::flags_t, + const TEXT*, const Firebird::MetaName&, const Firebird::MetaName&); +inline void SCL_check_access(const Jrd::SecurityClass* s_class, + SLONG view_id, + const Firebird::MetaName& trg_name, + const Firebird::MetaName& prc_name, + Jrd::SecurityClass::flags_t mask, + const TEXT* type, + const Firebird::string& name) +{ + SCL_check_access(s_class, view_id, trg_name, prc_name, mask, type, name.c_str()); +} +inline void SCL_check_access(const Jrd::SecurityClass* s_class, + SLONG view_id, + const Firebird::MetaName& trg_name, + const Firebird::MetaName& prc_name, + Jrd::SecurityClass::flags_t mask, + const TEXT* type, + const Firebird::MetaName& name) +{ + SCL_check_access(s_class, view_id, trg_name, prc_name, mask, type, name.c_str()); +} + void SCL_check_index(Jrd::thread_db*, const Firebird::MetaName&, UCHAR, Jrd::SecurityClass::flags_t); void SCL_check_procedure(const dsc*, Jrd::SecurityClass::flags_t); void SCL_check_relation(const dsc*, Jrd::SecurityClass::flags_t); diff --git a/src/jrd/sdl.cpp b/src/jrd/sdl.cpp index 058a533829..73b92f55a0 100644 --- a/src/jrd/sdl.cpp +++ b/src/jrd/sdl.cpp @@ -25,9 +25,7 @@ #include #include "../jrd/common.h" #include -#ifndef REQUESTER #include "../jrd/jrd.h" -#endif #include "../jrd/ibase.h" #include "../jrd/val.h" #include "../jrd/sdl.h" @@ -979,20 +977,11 @@ static const UCHAR* sdl_desc(const UCHAR* ptr, DSC* desc) break; case blr_double: -#ifndef VMS case blr_d_float: -#endif desc->dsc_dtype = dtype_double; desc->dsc_length = sizeof(double); break; -#ifdef VMS - case blr_d_float: - desc->dsc_dtype = dtype_d_float; - desc->dsc_length = sizeof(double); - break; -#endif - case blr_timestamp: desc->dsc_dtype = dtype_timestamp; desc->dsc_length = sizeof(ISC_QUAD); diff --git a/src/jrd/sdw.cpp b/src/jrd/sdw.cpp index 03c6450f17..12e1eba761 100644 --- a/src/jrd/sdw.cpp +++ b/src/jrd/sdw.cpp @@ -346,7 +346,6 @@ void SDW_check(void) lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type); lock->lck_parent = dbb->dbb_lock; - lock->lck_owner = tdbb->getAttachment(); LCK_lock(tdbb, lock, LCK_EX, LCK_NO_WAIT); if (lock->lck_physical == LCK_EX) { @@ -652,10 +651,7 @@ bool SDW_lck_update(SLONG sdw_update_flags) } if (!sdw_update_flags) { - if (LCK_read_data(lock)) - return false; - else - return true; + return !LCK_read_data(lock); } if (LCK_read_data(lock)) @@ -750,7 +746,6 @@ bool SDW_rollover_to_shadow(jrd_file* file, const bool inAst) update_lock->lck_owner_handle = LCK_get_owner_handle(tdbb, update_lock->lck_type); update_lock->lck_parent = dbb->dbb_lock; - update_lock->lck_owner = tdbb->getAttachment(); SLONG sdw_update_flags = SDW_rollover; @@ -952,8 +947,8 @@ void SDW_start(const TEXT* file_name, { if (shadow && (shadow->sdw_flags & SDW_rollover)) return; - else - ERR_post(isc_shadow_accessed, 0); + + ERR_post(isc_shadow_accessed, 0); } // Verify shadow file path against DatabaseAccess entry of firebird.conf @@ -1118,12 +1113,9 @@ int SDW_start_shadowing(void* ast_object) if (lock->lck_physical != LCK_SR) return 0; - ISC_ast_enter(); - /* Since this routine will be called asynchronously, we must establish a thread context. */ - thread_db thd_context, *tdbb; - JRD_set_thread_data(tdbb, thd_context); + ThreadContextHolder tdbb; tdbb->setDatabase(new_dbb); tdbb->tdbb_quantum = QUANTUM; @@ -1136,11 +1128,6 @@ int SDW_start_shadowing(void* ast_object) LCK_release(tdbb, lock); -/* Restore the prior thread context */ - - JRD_restore_thread_data(); - - ISC_ast_exit(); return 0; } diff --git a/src/jrd/sha.cpp b/src/jrd/sha.cpp index d59c28a81c..8483a98f52 100644 --- a/src/jrd/sha.cpp +++ b/src/jrd/sha.cpp @@ -86,6 +86,7 @@ void sha_final(unsigned char [SHA_DIGESTSIZE], SHA_INFO *); #define f3(x,y,z) ((x & y) | (x & z) | (y & z)) #define f4(x,y,z) (x ^ y ^ z) + /* SHA constants */ #define CONST1 0x5a827999L @@ -133,7 +134,7 @@ void sha_final(unsigned char [SHA_DIGESTSIZE], SHA_INFO *); static void sha_transform(SHA_INFO *sha_info) { int i; - LONG T, W[80]; + LONG W[80]; const BYTE* dp = sha_info->data; @@ -148,17 +149,17 @@ nether regions of the anatomy... #if (SHA_BYTE_ORDER == 1234) #define SWAP_DONE for (i = 0; i < 16; ++i) { - T = *((LONG *) dp); - dp += 4; - W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | - ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); + const LONG T = *((LONG *) dp); + dp += 4; + W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | + ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); } #endif /* SHA_BYTE_ORDER == 1234 */ #if (SHA_BYTE_ORDER == 4321) #define SWAP_DONE for (i = 0; i < 16; ++i) { - T = *((LONG *) dp); + const LONG T = *((LONG *) dp); dp += 4; W[i] = T32(T); } @@ -167,7 +168,7 @@ nether regions of the anatomy... #if (SHA_BYTE_ORDER == 12345678) #define SWAP_DONE for (i = 0; i < 16; i += 2) { - T = *((LONG *) dp); + LONG T = *((LONG *) dp); dp += 8; W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); @@ -180,7 +181,7 @@ nether regions of the anatomy... #if (SHA_BYTE_ORDER == 87654321) #define SWAP_DONE for (i = 0; i < 16; i += 2) { - T = *((LONG *) dp); + const LONG T = *((LONG *) dp); dp += 8; W[i] = T32(T >> 32); W[i + 1] = T32(T); @@ -203,6 +204,7 @@ nether regions of the anatomy... LONG D = sha_info->digest[3]; LONG E = sha_info->digest[4]; const LONG* WP = W; + LONG T; #ifdef UNRAVEL FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); @@ -338,7 +340,7 @@ void sha_final(unsigned char digest[SHA_DIGESTSIZE], SHA_INFO *sha_info) digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff); } -char conv_bin2ascii(ULONG l) +inline char conv_bin2ascii(ULONG l) { return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[l & 0x3f]; } diff --git a/src/jrd/shut.cpp b/src/jrd/shut.cpp index 01c8225c35..60dafe3697 100644 --- a/src/jrd/shut.cpp +++ b/src/jrd/shut.cpp @@ -118,16 +118,15 @@ bool SHUT_blocking_ast(Database* dbb) if ((flag & isc_dpb_shut_force) && !delay) return shutdown_locks(dbb, flag); - else { - if (flag & isc_dpb_shut_attachment) - dbb->dbb_ast_flags |= DBB_shut_attach; - if (flag & isc_dpb_shut_force) - dbb->dbb_ast_flags |= DBB_shut_force; - if (flag & isc_dpb_shut_transaction) - dbb->dbb_ast_flags |= DBB_shut_tran; - dbb->dbb_shutdown_delay = delay; // not tested anywhere - return false; - } + + if (flag & isc_dpb_shut_attachment) + dbb->dbb_ast_flags |= DBB_shut_attach; + if (flag & isc_dpb_shut_force) + dbb->dbb_ast_flags |= DBB_shut_force; + if (flag & isc_dpb_shut_transaction) + dbb->dbb_ast_flags |= DBB_shut_tran; + dbb->dbb_shutdown_delay = delay; // not tested anywhere + return false; } diff --git a/src/jrd/sort.cpp b/src/jrd/sort.cpp index 9bb0d071e7..b0ec517202 100644 --- a/src/jrd/sort.cpp +++ b/src/jrd/sort.cpp @@ -74,10 +74,6 @@ const ULONG IO_RETRY = 20; const USHORT RUN_GROUP = 8; const USHORT MAX_MERGE_LEVEL = 2; -#ifdef VMS -double MTH$CVT_D_G(), MTH$CVT_G_D(); -#endif - using namespace Jrd; // The sort buffer size should be just under a multiple of the @@ -96,7 +92,7 @@ const ULONG MAX_SORT_BUFFER_SIZE = SORT_BUFFER_CHUNK_SIZE * 32; // offset in array of pointers to back record pointer (sr_bckptr) #define BACK_OFFSET (-static_cast(SIZEOF_SR_BCKPTR / sizeof(SLONG*))) -#define DIFF_LONGS(a, b) ((a) - (b)) +//#define DIFF_LONGS(a, b) ((a) - (b)) #define SWAP_LONGS(a, b, t) {t = a; a = b; b = t;} // Compare p and q both SORTP pointers for l 32-bit longwords @@ -126,7 +122,7 @@ static ULONG high_key[] = { #ifdef SCROLLABLE_CURSORS static sort_record* get_merge(merge_control*, sort_context*, RSE_GET_MODE); #else -static void diddle_key(UCHAR *, sort_context*, bool); +static void diddle_key(UCHAR*, sort_context*, bool); static sort_record* get_merge(merge_control*, sort_context*); #endif @@ -195,17 +191,18 @@ void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction) case SKD_varying: if (direction) { - if (!(scb->scb_flags & scb_sorted)) { - *((USHORT *) (record + key->skd_vary_offset)) = - ((vary*) p)->vary_length; + USHORT& vlen = ((vary*) p)->vary_length; + if (!(scb->scb_flags & scb_sorted)) + { + *((USHORT *) (record + key->skd_vary_offset)) = vlen; const UCHAR fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; - UCHAR* fill_pos = p + sizeof(USHORT) + ((vary*) p)->vary_length; - const USHORT fill = n - sizeof(USHORT) - ((vary*) p)->vary_length; + UCHAR* fill_pos = p + sizeof(USHORT) + vlen; + const USHORT fill = n - sizeof(USHORT) - vlen; if (fill) memset(fill_pos, fill_char, fill); } - ((vary*) p)->vary_length = 0; + vlen = 0; } break; @@ -213,7 +210,7 @@ void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction) if (direction) { const UCHAR fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; if (!(scb->scb_flags & scb_sorted)) { - const USHORT l = strlen(p); + const USHORT l = strlen(reinterpret_cast(p)); *((USHORT *) (record + key->skd_vary_offset)) = l; UCHAR* fill_pos = p + l; const USHORT fill = n - l; @@ -294,13 +291,10 @@ void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction) * direction - true for SORT_put() and false for SORT_get() * **************************************/ - UCHAR c1, c2, fill_char, *fill_pos; - USHORT w, l, fill; + UCHAR c1, fill_char, *fill_pos; + USHORT fill; SSHORT longs, flag; ULONG lw; -#ifdef VMS - double *dp; -#endif const sort_key_def* key = scb->scb_description; for (const sort_key_def* const end = key + scb->scb_keys; key < end; key++) @@ -332,31 +326,31 @@ void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction) // record and zap it so that it doesn't interfere with collation if (key->skd_dtype == SKD_varying && direction) { + USHORT& vlen = ((vary*) p)->vary_length; if (!(scb->scb_flags & scb_sorted)) { - *((USHORT *) (record + key->skd_vary_offset)) = l = - ((vary*) p)->vary_length; + *((USHORT*) (record + key->skd_vary_offset)) = vlen; fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; - fill_pos = p + sizeof(USHORT) + l; - fill = n - sizeof(USHORT) - l; + fill_pos = p + sizeof(USHORT) + vlen; + fill = n - sizeof(USHORT) - vlen; if (fill) memset(fill_pos, fill_char, fill); } - ((vary*) p)->vary_length = 0; + vlen = 0; } if (key->skd_dtype == SKD_cstring && direction) { fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; if (!(scb->scb_flags & scb_sorted)) { - *((USHORT *) (record + key->skd_vary_offset)) = l = - strlen(p); + const USHORT l = strlen(reinterpret_cast(p)); + *((USHORT*) (record + key->skd_vary_offset)) = l; fill_pos = p + l; fill = n - l; if (fill) memset(fill_pos, fill_char, fill); } else { - l = *((USHORT *) (record + key->skd_vary_offset)); + USHORT l = *((USHORT*) (record + key->skd_vary_offset)); *(p + l) = fill_char; } } @@ -428,47 +422,40 @@ void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction) break; #else // IEEE -#ifdef VMS - case SKD_d_float: - dp = (double *) p; - if (direction) - *dp = MTH$CVT_D_G(dp); - -#endif case SKD_double: w = wp[2]; wp[2] = wp[3]; wp[3] = w; -#ifndef VMS case SKD_d_float: -#endif case SKD_float: if (!direction) - if (complement) { + { + if (complement) + { if (p[3] & 1 << 7) complement = !complement; else p[3] ^= 1 << 7; } - else { + else + { if (p[3] & 1 << 7) p[3] ^= 1 << 7; else complement = !complement; } + } w = wp[0]; wp[0] = wp[1]; wp[1] = w; if (direction) + { if (p[3] & 1 << 7) complement = !complement; else p[3] ^= 1 << 7; -#ifdef VMS - else if (key->skd_dtype == SKD_d_float) - *dp = MTH$CVT_G_D(dp); -#endif + } break; #endif // IEEE @@ -476,10 +463,13 @@ void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction) fb_assert(false); break; } + if (complement && n) - do + { + do { *p++ ^= -1; - while (--n); + } while (--n); + } // Flatter but don't complement control info for non-fixed // data types when restoring the data @@ -491,7 +481,7 @@ void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction) if (key->skd_dtype == SKD_cstring && !direction) { p = (BLOB_PTR *) record + key->skd_offset; - l = *((USHORT *) (record + key->skd_vary_offset)); + USHORT l = *((USHORT *) (record + key->skd_vary_offset)); *(p + l) = 0; } } @@ -601,7 +591,7 @@ void SORT_get(thread_db* tdbb, } if (record) - SORT_diddle_key((UCHAR *) record->sort_record_key, scb, false); + SORT_diddle_key((UCHAR*) record->sort_record_key, scb, false); *record_address = (ULONG *) record; @@ -646,7 +636,7 @@ void SORT_get(thread_db* tdbb, *record_address = (ULONG *) record; if (record) { - diddle_key((UCHAR *) record->sort_record_key, scb, false); + diddle_key((UCHAR*) record->sort_record_key, scb, false); } tdbb->bumpStats(RuntimeStatistics::SORT_GETS); @@ -819,10 +809,10 @@ void SORT_put(thread_db* tdbb, sort_context* scb, ULONG ** record_address) if (record != (SR *) scb->scb_end_memory) { #ifdef SCROLLABLE_CURSORS - SORT_diddle_key((UCHAR *) (record->sr_sort_record.sort_record_key), + SORT_diddle_key((UCHAR*) (record->sr_sort_record.sort_record_key), scb, true); #else - diddle_key((UCHAR *) (record->sr_sort_record.sort_record_key), scb, + diddle_key((UCHAR*) (record->sr_sort_record.sort_record_key), scb, true); #endif } @@ -958,9 +948,9 @@ void SORT_sort(thread_db* tdbb, sort_context* scb) if (scb->scb_last_record != (SR *) scb->scb_end_memory) { #ifdef SCROLLABLE_CURSORS - SORT_diddle_key((UCHAR *) KEYOF(scb->scb_last_record), scb, true); + SORT_diddle_key((UCHAR*) KEYOF(scb->scb_last_record), scb, true); #else - diddle_key((UCHAR *) KEYOF(scb->scb_last_record), scb, true); + diddle_key((UCHAR*) KEYOF(scb->scb_last_record), scb, true); #endif } @@ -1213,7 +1203,7 @@ FB_UINT64 SORT_write_block(ISC_STATUS* status_vector, #ifndef SCROLLABLE_CURSORS #ifdef WORDS_BIGENDIAN -static void diddle_key(UCHAR * record, sort_context* scb, bool direction) +static void diddle_key(UCHAR* record, sort_context* scb, bool direction) { /************************************** * @@ -1229,7 +1219,7 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) * **************************************/ UCHAR *fill_pos, fill_char; - USHORT l, fill, flag; + USHORT fill, flag; for (sort_key_def* key = scb->scb_description, *end = key + scb->scb_keys; key < end; key++) @@ -1249,18 +1239,19 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) // record and zap it so that it doesn't interfere with collation case SKD_varying: - if (direction) { - if (!(scb->scb_flags & scb_sorted)) { - *((USHORT *) (record + key->skd_vary_offset)) = - ((vary*) p)->vary_length; - fill_char = - (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; - fill_pos = p + sizeof(USHORT) + ((vary*) p)->vary_length; - fill = n - sizeof(USHORT) - ((vary*) p)->vary_length; + if (direction) + { + USHORT& vlen = ((vary*) p)->vary_length; + if (!(scb->scb_flags & scb_sorted)) + { + *((USHORT *) (record + key->skd_vary_offset)) = vlen; + fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; + fill_pos = p + sizeof(USHORT) + vlen; + fill = n - sizeof(USHORT) - vlen; if (fill) memset(fill_pos, fill_char, fill); } - ((vary*) p)->vary_length = 0; + vlen = 0; } break; @@ -1268,15 +1259,15 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) if (direction) { fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; if (!(scb->scb_flags & scb_sorted)) { - *((USHORT *) (record + key->skd_vary_offset)) = l = - strlen((char*)p); + const USHORT l = strlen(reinterpret_cast(p)); + *((USHORT *) (record + key->skd_vary_offset)) = l; fill_pos = p + l; fill = n - l; if (fill) memset(fill_pos, fill_char, fill); } else { - l = *((USHORT *) (record + key->skd_vary_offset)); + USHORT l = *((USHORT *) (record + key->skd_vary_offset)); *(p + l) = fill_char; } } @@ -1285,12 +1276,7 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) case SKD_text: break; -#ifndef VMS case SKD_d_float: -#else - Deliberate_compile_error++; - Fix for any VMS port. -#endif case SKD_float: case SKD_double: flag = (direction || !complement) @@ -1330,7 +1316,7 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) if (key->skd_dtype == SKD_cstring && !direction) { p = record + key->skd_offset; - l = *((USHORT *) (record + key->skd_vary_offset)); + USHORT l = *((USHORT *) (record + key->skd_vary_offset)); *(p + l) = 0; } } @@ -1338,7 +1324,7 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) #else -static void diddle_key(UCHAR * record, sort_context* scb, bool direction) +static void diddle_key(UCHAR* record, sort_context* scb, bool direction) { /************************************** * @@ -1354,12 +1340,9 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) * **************************************/ UCHAR c1, fill_char, *fill_pos; - USHORT l, fill; + USHORT fill; SSHORT longs, flag; ULONG lw; -#ifdef VMS - double *dp; -#endif #ifndef IEEE USHORT w; #endif @@ -1394,31 +1377,31 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) // record and zap it so that it doesn't interfere with collation if (key->skd_dtype == SKD_varying && direction) { + USHORT& vlen = ((vary*) p)->vary_length; if (!(scb->scb_flags & scb_sorted)) { - *((USHORT *) (record + key->skd_vary_offset)) = l = - ((vary*) p)->vary_length; + *((USHORT *) (record + key->skd_vary_offset)) = vlen; fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; - fill_pos = p + sizeof(USHORT) + l; - fill = n - sizeof(USHORT) - l; + fill_pos = p + sizeof(USHORT) + vlen; + fill = n - sizeof(USHORT) - vlen; if (fill) memset(fill_pos, fill_char, fill); } - ((vary*) p)->vary_length = 0; + vlen = 0; } if (key->skd_dtype == SKD_cstring && direction) { fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE; if (!(scb->scb_flags & scb_sorted)) { - *((USHORT *) (record + key->skd_vary_offset)) = l = - strlen(reinterpret_cast(p)); + const USHORT l = strlen(reinterpret_cast(p)); + *((USHORT *) (record + key->skd_vary_offset)) = l; fill_pos = p + l; fill = n - l; if (fill) memset(fill_pos, fill_char, fill); } else { - l = *((USHORT *) (record + key->skd_vary_offset)); + USHORT l = *((USHORT *) (record + key->skd_vary_offset)); *(p + l) = fill_char; } } @@ -1488,47 +1471,40 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) break; #else // IEEE -#ifdef VMS - case SKD_d_float: - dp = (double *) p; - if (direction) - *dp = MTH$CVT_D_G(dp); - -#endif case SKD_double: w = wp[2]; wp[2] = wp[3]; wp[3] = w; -#ifndef VMS case SKD_d_float: -#endif case SKD_float: if (!direction) - if (complement) { + { + if (complement) + { if (p[3] & 1 << 7) complement = !complement; else p[3] ^= 1 << 7; } - else { + else + { if (p[3] & 1 << 7) p[3] ^= 1 << 7; else complement = !complement; } + } w = wp[0]; wp[0] = wp[1]; wp[1] = w; if (direction) + { if (p[3] & 1 << 7) complement = !complement; else p[3] ^= 1 << 7; -#ifdef VMS - else if (key->skd_dtype == SKD_d_float) - *dp = MTH$CVT_G_D(dp); -#endif + } break; #endif // IEEE @@ -1546,12 +1522,12 @@ static void diddle_key(UCHAR * record, sort_context* scb, bool direction) if (key->skd_dtype == SKD_varying && !direction) { p = (BLOB_PTR *) record + key->skd_offset; - ((vary*) p)->vary_length = *((USHORT *) (record + key->skd_vary_offset)); + ((vary*) p)->vary_length = *((USHORT*) (record + key->skd_vary_offset)); } if (key->skd_dtype == SKD_cstring && !direction) { p = (BLOB_PTR *) record + key->skd_offset; - l = *((USHORT *) (record + key->skd_vary_offset)); + USHORT l = *((USHORT *) (record + key->skd_vary_offset)); *(p + l) = 0; } } @@ -1682,7 +1658,8 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb #ifdef SCROLLABLE_CURSORS if (mode == RSE_get_forward) { - run->run_record = NEXT_RUN_RECORD(run->run_record); + run->run_record = + reinterpret_cast(NEXT_RUN_RECORD(run->run_record)); #endif if ((record = (sort_record*) run->run_record) < @@ -1710,9 +1687,10 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb #else } else { - run->run_record = PREV_RUN_RECORD(run->run_record); + run->run_record = + reinterpret_cast(PREV_RUN_RECORD(run->run_record)); if ((record = (sort_record*) run->run_record) >= - run->run_buffer) + reinterpret_cast(run->run_buffer)) { ++run->run_records; continue; @@ -1742,7 +1720,7 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb else run->run_seek -= l; - SORT_read_block(scb->scb_status_vector, run->run_sfb, + SORT_read_block(scb->scb_status_vector, scb->scb_space, run->run_seek, (UCHAR*) run->run_buffer, l); run->run_cached = l; @@ -1757,7 +1735,7 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb #ifdef SCROLLABLE_CURSORS } else { - record = PREV_RUN_RECORD(run->run_end_buffer); + record = reinterpret_cast(PREV_RUN_RECORD(run->run_end_buffer)); ++run->run_records; } @@ -1828,11 +1806,11 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb if (l == 0 && scb->scb_dup_callback) { #ifdef SCROLLABLE_CURSORS - SORT_diddle_key((UCHAR *) merge->mrg_record_a, scb, false); - SORT_diddle_key((UCHAR *) merge->mrg_record_b, scb, false); + SORT_diddle_key((UCHAR*) merge->mrg_record_a, scb, false); + SORT_diddle_key((UCHAR*) merge->mrg_record_b, scb, false); #else - diddle_key((UCHAR *) merge->mrg_record_a, scb, false); - diddle_key((UCHAR *) merge->mrg_record_b, scb, false); + diddle_key((UCHAR*) merge->mrg_record_a, scb, false); + diddle_key((UCHAR*) merge->mrg_record_b, scb, false); #endif if ((*scb->scb_dup_callback) ((const UCHAR*) merge->mrg_record_a, (const UCHAR*) merge->mrg_record_b, @@ -1840,18 +1818,18 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb { merge->mrg_record_a = NULL; #ifdef SCROLLABLE_CURSORS - SORT_diddle_key((UCHAR *) merge->mrg_record_b, scb, true); + SORT_diddle_key((UCHAR*) merge->mrg_record_b, scb, true); #else - diddle_key((UCHAR *) merge->mrg_record_b, scb, true); + diddle_key((UCHAR*) merge->mrg_record_b, scb, true); #endif continue; } #ifdef SCROLLABLE_CURSORS - SORT_diddle_key((UCHAR *) merge->mrg_record_a, scb, true); - SORT_diddle_key((UCHAR *) merge->mrg_record_b, scb, true); + SORT_diddle_key((UCHAR*) merge->mrg_record_a, scb, true); + SORT_diddle_key((UCHAR*) merge->mrg_record_b, scb, true); #else - diddle_key((UCHAR *) merge->mrg_record_a, scb, true); - diddle_key((UCHAR *) merge->mrg_record_b, scb, true); + diddle_key((UCHAR*) merge->mrg_record_a, scb, true); + diddle_key((UCHAR*) merge->mrg_record_b, scb, true); #endif } @@ -1951,9 +1929,6 @@ static bool local_fini(sort_context* scb, Attachment* att) * Finish sort, and release all resources. * **************************************/ - ULONG** merge_buf; - sort_context** ptr; - bool found_it = true; if (att) { @@ -1968,12 +1943,16 @@ static bool local_fini(sort_context* scb, Attachment* att) // Start by unlinking from que, if present if (att) - for (ptr = &att->att_active_sorts; *ptr; ptr = &(*ptr)->scb_next) + { + for (sort_context** ptr = &att->att_active_sorts; *ptr; ptr = &(*ptr)->scb_next) + { if (*ptr == scb) { *ptr = scb->scb_next; found_it = true; break; } + } + } // *NO*. I won't free it if it's not in // the pointer list that has been passed @@ -1988,6 +1967,7 @@ static bool local_fini(sort_context* scb, Attachment* att) // Get rid of extra merge space + ULONG** merge_buf; while ( (merge_buf = (ULONG **) scb->scb_merge_space) ) { scb->scb_merge_space = *merge_buf; delete merge_buf; @@ -2537,7 +2517,8 @@ static ULONG order(sort_context* scb) // scb_next_pointer points to the end of pointer memory or the beginning of // records - while (ptr < scb->scb_next_pointer) { + while (ptr < scb->scb_next_pointer) + { // If the next pointer is null, it's record has been eliminated as a // duplicate. This is the only easy case. @@ -2796,7 +2777,8 @@ static void sort(sort_context* scb) // Scream through and correct any out of order pairs // hvlad: don't compare user keys against high_key - while (j < (SORTP **) scb->scb_next_pointer - 1) { + while (j < (SORTP **) scb->scb_next_pointer - 1) + { SORTP** i = j; j++; if (**i >= **j) { @@ -2831,7 +2813,8 @@ static void sort(sort_context* scb) j = reinterpret_cast(scb->scb_first_pointer + 1); // hvlad: don't compare user keys against high_key - while (j < ((SORTP **) scb->scb_next_pointer) - 1) { + while (j < ((SORTP **) scb->scb_next_pointer) - 1) + { SORTP** i = j; j++; if (**i != **j) @@ -2841,13 +2824,14 @@ static void sort(sort_context* scb) ULONG l = scb->scb_unique_length; DO_32_COMPARE(p, q, l); - if (l == 0) { + if (l == 0) + { #ifdef SCROLLABLE_CURSORS - SORT_diddle_key((UCHAR *) * i, scb, false); - SORT_diddle_key((UCHAR *) * j, scb, false); + SORT_diddle_key((UCHAR*) *i, scb, false); + SORT_diddle_key((UCHAR*) *j, scb, false); #else - diddle_key((UCHAR *) * i, scb, false); - diddle_key((UCHAR *) * j, scb, false); + diddle_key((UCHAR*) *i, scb, false); + diddle_key((UCHAR*) *j, scb, false); #endif if ((*scb->scb_dup_callback) ((const UCHAR*) *i, (const UCHAR*) *j, scb->scb_dup_callback_arg)) { @@ -2856,11 +2840,11 @@ static void sort(sort_context* scb) } else #ifdef SCROLLABLE_CURSORS - SORT_diddle_key((UCHAR *) * i, scb, true); - SORT_diddle_key((UCHAR *) * j, scb, true); + SORT_diddle_key((UCHAR*) *i, scb, true); + SORT_diddle_key((UCHAR*) *j, scb, true); #else - diddle_key((UCHAR *) * i, scb, true); - diddle_key((UCHAR *) * j, scb, true); + diddle_key((UCHAR*) *i, scb, true); + diddle_key((UCHAR*) *j, scb, true); #endif } } diff --git a/src/jrd/sort.h b/src/jrd/sort.h index e27393ebf8..8c3071c5ec 100644 --- a/src/jrd/sort.h +++ b/src/jrd/sort.h @@ -244,7 +244,7 @@ struct sort_context sort_record** scb_first_pointer; /* Memory for sort */ sort_record** scb_next_pointer; /* Address for next pointer */ #ifdef SCROLLABLE_CURSORS - SORTP **scb_last_pointer; /* Address for last pointer in block */ + sort_record** scb_last_pointer; /* Address for last pointer in block */ #endif //USHORT scb_length; // Record length. Unused. USHORT scb_longs; /* Length of record in longwords */ diff --git a/src/jrd/sort_proto.h b/src/jrd/sort_proto.h index 4f9a30fead..4cbd03580c 100644 --- a/src/jrd/sort_proto.h +++ b/src/jrd/sort_proto.h @@ -33,7 +33,7 @@ namespace Jrd { #ifdef SCROLLABLE_CURSORS void SORT_diddle_key(UCHAR *, Jrd::sort_context*, bool); -void SORT_get(Jrd::thread_db*, Jrd::sort_context*, ULONG **, RSE_GET_MODE); +void SORT_get(Jrd::thread_db*, Jrd::sort_context*, ULONG **, Jrd::rse_get_mode); void SORT_read_block(ISC_STATUS*, TempSpace*, FB_UINT64, BLOB_PTR *, ULONG); #else void SORT_get(Jrd::thread_db*, Jrd::sort_context*, ULONG **); diff --git a/src/jrd/sqz.cpp b/src/jrd/sqz.cpp index 3692aa8dd4..da6cd9e1f7 100644 --- a/src/jrd/sqz.cpp +++ b/src/jrd/sqz.cpp @@ -171,6 +171,7 @@ USHORT SQZ_compress_length(DataComprControl* dcc, const SCHAR* input, int space) while (true) { const SCHAR* control = dcc->dcc_string; while (control < dcc->dcc_end) + { if (--space <= 0) return input - start; else if ((length = *control++) & 128) { @@ -185,6 +186,7 @@ USHORT SQZ_compress_length(DataComprControl* dcc, const SCHAR* input, int space) } input += length; } + } if (!(dcc = dcc->dcc_next)) BUGCHECK(178); /* msg 178 record length inconsistent */ } diff --git a/src/jrd/svc.cpp b/src/jrd/svc.cpp index e54f1922b1..506a5afbfb 100644 --- a/src/jrd/svc.cpp +++ b/src/jrd/svc.cpp @@ -33,13 +33,13 @@ #include "firebird.h" #include #include -//#include "../common/classes/timestamp.h" #include "../jrd/common.h" #include "../jrd/thd.h" #include "../jrd/file_params.h" #include #include "../jrd/jrd.h" #include "../jrd/svc.h" +#include "../jrd/constants.h" #include "../jrd/jrd_pwd.h" #include "../alice/aliceswi.h" #include "../burp/burpswi.h" @@ -65,6 +65,7 @@ #include "../common/classes/ClumpletWriter.h" #include "../jrd/ibase.h" #include "../common/utils_proto.h" +#include "../utilities/common/cmd_util_proto.h" #include "../jrd/scl.h" #ifdef SERVER_SHUTDOWN @@ -101,12 +102,8 @@ const int SVC_user_none = 0; #if !defined(WIN_NT) # include -# ifndef VMS -# include -# include -# else -# include -# endif +# include +# include # include #else # include @@ -116,10 +113,6 @@ const int SVC_user_none = 0; # include #endif -#ifdef VMS -#define waitpid(x, y, z) wait (y) -#endif - #define statistics stat const int GET_LINE = 1; @@ -128,166 +121,6 @@ const int GET_BINARY = 4; const TEXT SVC_TRMNTR = '\377'; -namespace Jrd { - Service::Service(serv_entry *se, Firebird::MemoryPool& p) : - svc_parsed_sw(p), - svc_handle(0), svc_status(svc_status_array), svc_input(0), svc_output(0), - svc_stdout_head(0), svc_stdout_tail(0), svc_stdout(0), svc_argv(p), svc_argc(0), - svc_service(se), svc_resp_buf(0), svc_resp_ptr(0), svc_resp_buf_len(0), - svc_resp_len(0), svc_flags(0), svc_user_flag(0), svc_spb_version(0), svc_do_shutdown(false), - svc_username(p), svc_enc_password(p), -#ifdef TRUSTED_SERVICES - svc_trusted_login(p), -#endif - svc_switches(p), svc_perm_sw(p) - - { - memset(svc_status_array, 0, sizeof svc_status_array); - } - - Service::~Service() - { - // If we forked an executable, close down it's pipes -#ifndef SERVICE_THREAD - if (svc_flags & SVC_forked) - { -#ifndef WIN_NT - if (svc_input) - { - fclose(svc_input); - } - if (svc_output) - { - fclose(svc_output); - } -#endif //WIN_NT - } -#else //SERVICE_THREAD - if (svc_stdout) - { - gds__free(svc_stdout); - } -#endif //SERVICE_THREAD - - if (svc_resp_buf) - { - gds__free(svc_resp_buf); - } - -#ifdef WIN_NT - CloseHandle((HANDLE) svc_handle); -#endif - } - - void Service::parseSwitches() - { - svc_parsed_sw = svc_switches; - svc_parsed_sw.trim(); - svc_argc = 2; - - if (svc_parsed_sw.isEmpty()) - { - svc_argv.getBuffer(svc_argc + 1)[1] = 0; - return; - } - - bool inStr = false; - for (size_t i = 0; i < svc_parsed_sw.length(); ++i) - { - - switch (svc_parsed_sw[i]) - { - case SVC_TRMNTR: - svc_parsed_sw.erase(i, 1); - if (inStr) - { - if (i < svc_parsed_sw.length() && svc_parsed_sw[i] != SVC_TRMNTR) - { - inStr = false; - --i; - } - } - else - { - inStr = true; - --i; - } - break; - - case ' ': - if (!inStr) - { - ++svc_argc; - svc_parsed_sw[i] = 0; - } - break; - } - } - - const char** argv = svc_argv.getBuffer(svc_argc + 1); - argv++; // leave space for argv[0] - *argv++ = svc_parsed_sw.c_str(); - for (const char *p = svc_parsed_sw.begin(); - p < svc_parsed_sw.end(); ++p) - { - if (!*p) - { - *argv++ = p + 1; - } - } - *argv = 0; - } -} //namespace - -using namespace Jrd; - -#ifdef SERVICE_THREAD - -void Service::svc_started() -{ - if (!(svc_flags & SVC_evnt_fired)) { - svc_flags |= SVC_evnt_fired; - svcStart.release(); - } -} - -#endif /* SERVICE_THREAD */ - -/* This checks if the service has forked a process. If not, - it will post the isc_svcnoexe error. */ - -static inline void is_service_running(const Service* service) -{ - if (!(service->svc_flags & SVC_forked)) { - THREAD_ENTER(); - ERR_post (isc_svcnoexe, isc_arg_string, - service->svc_service->serv_name, 0); - } -} - -static inline void need_admin_privs(ISC_STATUS** status, const char* message) -{ - ISC_STATUS* stat = *status; - *stat++ = isc_insufficient_svc_privileges; - *stat++ = isc_arg_string; - *stat++ = (ISC_STATUS)(U_IPTR) ERR_string(message, strlen(message)); - *stat++ = isc_arg_end; - *status = stat; -} - -bool ck_space_for_numeric(char*& info, const char* const end) -{ - if ((info + 1 + sizeof (ULONG)) > end) - { - if (info < end) - *info++ = isc_info_truncated; - THREAD_ENTER(); - return false; - } - return true; -} - - /* Option block for service parameter block */ // What's the point of defining spb if a char* var will have the same name, Borland??? // It was easier to rename this struct. @@ -300,14 +133,17 @@ struct Serv_param_block { Firebird::string spb_command_line; Firebird::string spb_network_protocol; Firebird::string spb_remote_address; -#ifdef TRUSTED_SERVICES Firebird::string spb_trusted_login; -#endif + bool spb_trusted_role; USHORT spb_version; - Serv_param_block() : spb_version(0) { } + Serv_param_block() : + spb_trusted_role(false), + spb_version(0) + { } }; +using namespace Jrd; static const TEXT* error_string(const TEXT* data, USHORT length); static const TEXT* error_string(const Firebird::string& s); @@ -324,24 +160,237 @@ static void get_action_svc_data(const Firebird::ClumpletReader&, static bool get_action_svc_parameter(UCHAR tag, const in_sw_tab_t*, Firebird::string&); -#ifdef SERVICE_THREAD static UCHAR service_dequeue_byte(Service*); static void service_enqueue_byte(UCHAR, Service*); static USHORT service_add_one(USHORT i); static USHORT service_empty(Service* service); static USHORT service_full(Service* service); static void service_fork(ThreadEntryPoint*, Service*); -#else -#ifndef WIN_NT -static void timeout_handler(void* service); -#endif -static void cleanup(Service* service); -static void service_fork(TEXT*, Service*); -static void io_error(const TEXT*, SLONG, const TEXT*, ISC_STATUS); -#endif static void service_get(Service*, SCHAR *, USHORT, USHORT, USHORT, USHORT *); static void service_put(Service*, const SCHAR*, USHORT); +Service::Service(serv_entry* se, Firebird::MemoryPool& p) : + Firebird::UtilSvc(p), + svc_parsed_sw(getPool()), + svc_handle(0), svc_status(svc_status_array), svc_input(0), svc_output(0), + svc_stdout_head(0), svc_stdout_tail(0), svc_stdout(0), + svc_service(se), svc_resp_buf(0), svc_resp_ptr(0), svc_resp_buf_len(0), + svc_resp_len(0), svc_flags(0), svc_user_flag(0), svc_spb_version(0), svc_do_shutdown(false), + svc_username(getPool()), svc_enc_password(getPool()), + svc_trusted_login(getPool()), + svc_switches(getPool()), svc_perm_sw(getPool()) +{ + memset(svc_status_array, 0, sizeof svc_status_array); +} + +Service::~Service() +{ + if (svc_stdout) + { + gds__free(svc_stdout); + } + + if (svc_resp_buf) + { + gds__free(svc_resp_buf); + } + +#ifdef WIN_NT + CloseHandle((HANDLE) svc_handle); +#endif +} + +void Service::parseSwitches() +{ + svc_parsed_sw = svc_switches; + svc_parsed_sw.trim(); + argv.clear(); + argv.push("service"); // why not use it for argv[0] + + if (svc_parsed_sw.isEmpty()) + { + return; + } + + bool inStr = false; + for (size_t i = 0; i < svc_parsed_sw.length(); ++i) + { + switch (svc_parsed_sw[i]) + { + case SVC_TRMNTR: + svc_parsed_sw.erase(i, 1); + if (inStr) + { + if (i < svc_parsed_sw.length() && svc_parsed_sw[i] != SVC_TRMNTR) + { + inStr = false; + --i; + } + } + else + { + inStr = true; + --i; + } + break; + + case ' ': + if (!inStr) + { + svc_parsed_sw[i] = 0; + } + break; + } + } + + argv.push(svc_parsed_sw.c_str()); + + for (const char* p = svc_parsed_sw.begin(); + p < svc_parsed_sw.end(); ++p) + { + if (!*p) + { + argv.push(p + 1); + } + } +} + +void Service::printf(const SCHAR* format, ...) +{ + // Ensure that service is not detached. + if (svc_flags & SVC_detached) + { + return; + } + + Firebird::string buf; + va_list arglist; + va_start(arglist, format); + buf.vprintf(format, arglist); + va_end(arglist); + + for (size_t n = 0; n < buf.length() && !(svc_flags & SVC_detached); ++n) + { + service_enqueue_byte(buf[n], this); + } +} + +bool Service::isService() +{ + return true; +} + +void Service::started() +{ + if (!(svc_flags & SVC_evnt_fired)) + { + svc_flags |= SVC_evnt_fired; + svcStart.release(); + } +} + +void Service::finish() +{ + SVC_finish(this, SVC_finished); +} + +void Service::putLine(char tag, const char* val) +{ + size_t len = strlen(val); + len &= 0xFFFF; + SVC_putc(this, tag); + SVC_putc(this, len); + SVC_putc(this, len >> 8); + + for (size_t i = 0; i < len; i++) + { + SVC_putc(this, val[i]); + } +} + +void Service::putSLong(char tag, SLONG val) +{ + SVC_putc(this, tag); + SVC_putc(this, val); + SVC_putc(this, val >> 8); + SVC_putc(this, val >> 16); + SVC_putc(this, val >> 24); +} + +void Service::putChar(char tag, char val) +{ + SVC_putc(this, tag); + SVC_putc(this, val); +} + +void Service::stuffStatus(const ISC_STATUS* status_vector) +{ + if (status_vector != svc_status) + { + ISC_STATUS* status = svc_status; + int i = 0; + + while (*status && (++i < ISC_STATUS_LENGTH)) + { + status++; + } + + for (int j = 0; status_vector[j] && (i < ISC_STATUS_LENGTH); j++, i++) + { + *status++ = status_vector[j]; + } + } +} + +void Service::stuffStatus(const USHORT facility, const USHORT errcode, const MsgFormat::SafeArg& args) +{ + CMD_UTIL_put_svc_status(svc_status, facility, errcode, args); +} + +void Service::hidePasswd(ArgvType&, int) +{ + // no action +} + +ISC_STATUS* Service::getStatus() +{ + return svc_status; +} + +void Service::checkService() +{ + // no action +} + +void Service::svc_started() +{ + if (this) // !!!!!!! temporary requirement to build + started(); +} + +static inline void need_admin_privs(ISC_STATUS** status, const char* message) +{ + ISC_STATUS* stat = *status; + *stat++ = isc_insufficient_svc_privileges; + *stat++ = isc_arg_string; + *stat++ = (ISC_STATUS)(U_IPTR) ERR_string(message, strlen(message)); + *stat++ = isc_arg_end; + *status = stat; +} + +bool ck_space_for_numeric(char*& info, const char* const end) +{ + if ((info + 1 + sizeof(ULONG)) > end) + { + if (info < end) + *info++ = isc_info_truncated; + THREAD_ENTER(); + return false; + } + return true; +} + + #ifdef DEBUG THREAD_ENTRY_DECLARE test_thread(THREAD_ENTRY_PARAM); void test_cmd(USHORT, SCHAR *, TEXT **); @@ -362,7 +411,7 @@ const char* const SPB_SEC_USERNAME = "isc_spb_sec_username"; static Firebird::Mutex svc_mutex, thd_mutex; /* Service Functions */ -#if defined(SERVICE_THREAD) && !defined(BOOT_BUILD) +#if !defined(BOOT_BUILD) #include "../burp/burp_proto.h" #include "../alice/alice_proto.h" int main_lock_print(); @@ -380,7 +429,7 @@ THREAD_ENTRY_DECLARE main_gstat(THREAD_ENTRY_PARAM arg); #define MAIN_GSEC NULL #endif -#if defined(SERVICE_THREAD) && !defined(EMBEDDED) && !defined(BOOT_BUILD) +#if !defined(EMBEDDED) && !defined(BOOT_BUILD) #include "../utilities/gsec/gsec_proto.h" #define MAIN_GSEC GSEC_main #else @@ -445,46 +494,45 @@ void SVC_STATUS_ARG(ISC_STATUS*& status, const char* value) static serv_entry services[] = { - { isc_action_max, "print_cache", "-svc", "bin/fb_cache_print", NULL, 0 }, - { isc_action_max, "print_locks", "-svc", "bin/fb_lock_print", NULL, 0 }, - { isc_action_max, "start_cache", "-svc", "bin/fb_cache_manager", NULL, 0 }, - { isc_action_max, "analyze_database", "-svc", "bin/gstat", NULL, 0 }, - { isc_action_max, "backup", "-svc -b", "bin/gbak", MAIN_GBAK, 0 }, - { isc_action_max, "create", "-svc -c", "bin/gbak", MAIN_GBAK, 0 }, - { isc_action_max, "restore", "-svc -r", "bin/gbak", MAIN_GBAK, 0 }, - { isc_action_max, "gdef", "-svc", "bin/gdef", NULL, 0 }, - { isc_action_max, "gsec", "-svc", "bin/gsec", NULL, 0 }, - { isc_action_max, "disable_journal", "-svc -disable", "bin/gjrn", NULL, 0 }, - { isc_action_max, "dump_journal", "-svc -online_dump", "bin/gjrn", NULL, 0 }, - { isc_action_max, "enable_journal", "-svc -enable", "bin/gjrn", NULL, 0 }, - { isc_action_max, "monitor_journal", "-svc -console", "bin/gjrn", NULL, 0 }, - { isc_action_max, "query_server", NULL, NULL, NULL, 0 }, - { isc_action_max, "start_journal", "-svc -server", "bin/gjrn", NULL, 0 }, - { isc_action_max, "stop_cache", "-svc -shut -cache", "bin/gfix", NULL, 0 }, - { isc_action_max, "stop_journal", "-svc -console", "bin/gjrn", NULL, 0 }, - { isc_action_max, "anonymous", NULL, NULL, NULL, 0 }, + { isc_action_max, "print_cache", "", NULL }, + { isc_action_max, "print_locks", "", NULL }, + { isc_action_max, "start_cache", "", NULL }, + { isc_action_max, "analyze_database", "", MAIN_GFIX }, + { isc_action_max, "backup", "-b", MAIN_GBAK }, + { isc_action_max, "create", "-c", MAIN_GBAK }, + { isc_action_max, "restore", "-r", MAIN_GBAK }, + { isc_action_max, "gdef", "-svc", NULL }, + { isc_action_max, "gsec", "-svc", MAIN_GSEC }, + { isc_action_max, "disable_journal", "-disable", NULL }, + { isc_action_max, "dump_journal", "-online_dump", NULL }, + { isc_action_max, "enable_journal", "-enable", NULL }, + { isc_action_max, "monitor_journal", "-console", NULL }, + { isc_action_max, "query_server", NULL, NULL }, + { isc_action_max, "start_journal", "-server", NULL }, + { isc_action_max, "stop_cache", "-shut -cache", MAIN_GFIX }, + { isc_action_max, "stop_journal", "-console", NULL }, + { isc_action_max, "anonymous", NULL, NULL }, -/* NEW VERSION 2 calls, the name field MUST be different from those names above - */ - { isc_action_max, "service_mgr", NULL, NULL, NULL, 0 }, - { isc_action_svc_backup, "Backup Database", NULL, "bin/gbak", MAIN_GBAK, 0 }, - { isc_action_svc_restore, "Restore Database", NULL, "bin/gbak", MAIN_GBAK, 0 }, - { isc_action_svc_repair, "Repair Database", NULL, "bin/gfix", MAIN_GFIX, 0 }, - { isc_action_svc_add_user, "Add User", NULL, "bin/gsec", MAIN_GSEC, 0 }, - { isc_action_svc_delete_user, "Delete User", NULL, "bin/gsec", MAIN_GSEC, 0 }, - { isc_action_svc_modify_user, "Modify User", NULL, "bin/gsec", MAIN_GSEC, 0 }, - { isc_action_svc_display_user, "Display User", NULL, "bin/gsec", MAIN_GSEC, 0 }, - { isc_action_svc_properties, "Database Properties", NULL, "bin/gfix", MAIN_GFIX, 0 }, - { isc_action_svc_lock_stats, "Lock Stats", NULL, "bin/fb_lock_print", TEST_THREAD, 0 }, - { isc_action_svc_db_stats, "Database Stats", NULL, "bin/gstat", MAIN_GSTAT, 0 }, - { isc_action_svc_get_fb_log, "Get Log File", NULL, NULL, SVC_read_fb_log, 0 }, + // NEW VERSION 2 calls, the name field MUST be different from those names above + { isc_action_max, "service_mgr", NULL, NULL }, + { isc_action_svc_backup, "Backup Database", NULL, MAIN_GBAK }, + { isc_action_svc_restore, "Restore Database", NULL, MAIN_GBAK }, + { isc_action_svc_repair, "Repair Database", NULL, MAIN_GFIX }, + { isc_action_svc_add_user, "Add User", NULL, MAIN_GSEC }, + { isc_action_svc_delete_user, "Delete User", NULL, MAIN_GSEC }, + { isc_action_svc_modify_user, "Modify User", NULL, MAIN_GSEC }, + { isc_action_svc_display_user, "Display User", NULL, MAIN_GSEC }, + { isc_action_svc_properties, "Database Properties", NULL, MAIN_GFIX }, + { isc_action_svc_lock_stats, "Lock Stats", NULL, TEST_THREAD }, + { isc_action_svc_db_stats, "Database Stats", NULL, MAIN_GSTAT }, + { isc_action_svc_get_fb_log, "Get Log File", NULL, SVC_read_fb_log }, /* actions with no names are undocumented */ - { isc_action_svc_set_config, NULL, NULL, NULL, TEST_THREAD, 0 }, - { isc_action_svc_default_config, NULL, NULL, NULL, TEST_THREAD, 0 }, - { isc_action_svc_set_env, NULL, NULL, NULL, TEST_THREAD, 0 }, - { isc_action_svc_set_env_lock, NULL, NULL, NULL, TEST_THREAD, 0 }, - { isc_action_svc_set_env_msg, NULL, NULL, NULL, TEST_THREAD, 0 }, - { 0, NULL, NULL, NULL, NULL, 0 } + { isc_action_svc_set_config, NULL, NULL, TEST_THREAD }, + { isc_action_svc_default_config, NULL, NULL, TEST_THREAD }, + { isc_action_svc_set_env, NULL, NULL, TEST_THREAD }, + { isc_action_svc_set_env_lock, NULL, NULL, TEST_THREAD }, + { isc_action_svc_set_env_msg, NULL, NULL, TEST_THREAD }, + { 0, NULL, NULL, NULL } }; /* The SERVER_CAPABILITIES_FLAG is used to mark architectural @@ -558,25 +606,6 @@ Service* SVC_attach(USHORT service_length, Firebird::ClumpletWriter spb(Firebird::ClumpletReader::SpbAttach, MAX_DPB_SIZE, reinterpret_cast(spb_data), spb_length, isc_spb_current_version); -/* Insert internal switch SERVICE_THD_PARAM in the service parameter block. */ - /* dimitr: it looks that we shouldn't execute the below code - if the first switch of the command line is "-svc_re", - but I couldn't find where such a switch is specified - by any of the client tools, so it seems that in fact - it's not used at all. Hence I ignore this situation. */ - if (spb.find(isc_spb_command_line)) { - Firebird::string cl; - spb.getString(cl); - if (cl.substr(0, 5) == "-svc ") - cl.erase(0, 5); - else if (cl.substr(0, 9) == "-svc_thd ") - cl.erase(0, 9); - cl.insert(0, ' '); - cl.insert(0, SERVICE_THD_PARAM); - spb.deleteClumplet(); - spb.insertString(isc_spb_command_line, cl); - } - /* Process the service parameter block. */ Serv_param_block options; get_options(spb, &options); @@ -587,13 +616,11 @@ Service* SVC_attach(USHORT service_length, user_flag = SVC_user_none; } else { -#ifdef TRUSTED_SERVICES if (options.spb_trusted_login.hasData()) { options.spb_user_name = options.spb_trusted_login; } else -#endif { if (!options.spb_user_name.hasData()) { @@ -626,11 +653,13 @@ Service* SVC_attach(USHORT service_length, } /* Check that the validated user has the authority to access this service */ - if (fb_utils::stricmp(options.spb_user_name.c_str(), SYSDBA_USER_NAME)) + if (fb_utils::stricmp(options.spb_user_name.c_str(), SYSDBA_USER_NAME) && + !options.spb_trusted_role) { user_flag = SVC_user_any; } - else { + else + { user_flag = SVC_user_dba | SVC_user_any; } } @@ -647,21 +676,17 @@ Service* SVC_attach(USHORT service_length, we cannot use the JRD allocator. */ service = FB_NEW(*getDefaultMemoryPool()) Service(serv, *getDefaultMemoryPool()); - service->svc_flags = - (serv->serv_executable ? SVC_forked : 0) | (switches.hasData() ? SVC_cmd_line : 0); + service->svc_flags = switches.hasData() ? SVC_cmd_line : 0; service->svc_perm_sw = switches; service->svc_user_flag = user_flag; -#ifdef SERVICE_THREAD service->svc_stdout_head = 1; service->svc_stdout_tail = SVC_STDOUT_BUFFER_SIZE; service->svc_stdout = NULL; -#endif service->svc_spb_version = options.spb_version; service->svc_username = options.spb_user_name; -#ifdef TRUSTED_SERVICES service->svc_trusted_login = options.spb_trusted_login; -#endif + service->svc_trusted_role = options.spb_trusted_role; /* The password will be issued to the service threads on NT since * there is no OS authentication. If the password is not yet @@ -681,33 +706,12 @@ Service* SVC_attach(USHORT service_length, service->svc_enc_password.erase(0, 2); } -/* If an executable is defined for the service, try to fork a new process. +/* If an executable is defined for the service, try to fork a new thread. * Only do this if we are working with a version 1 service */ -#ifndef SERVICE_THREAD - if (serv->serv_executable && options.spb_version == isc_spb_version1) -#else if (serv->serv_thd && options.spb_version == isc_spb_version1) -#endif { -#ifndef SERVICE_THREAD - TEXT service_path[MAXPATHLEN]; - gds__prefix(service_path, serv->serv_executable); - service_fork(service_path, service); -#else - /* if service is single threaded, only call if not currently running */ - if (serv->serv_in_use == NULL) { /* No worry for multi-threading */ - service_fork(serv->serv_thd, service); - } - else if (!*(serv->serv_in_use)) { - *(serv->serv_in_use) = true; - service_fork(serv->serv_thd, service); - } - else { - ERR_post(isc_service_att_err, isc_arg_gds, - isc_svc_in_use, isc_arg_string, serv->serv_name, 0); - } -#endif + service_fork(serv->serv_thd, service); } } // try @@ -755,19 +759,12 @@ void SVC_detach(Service* service) } #endif /* SERVER_SHUTDOWN */ -#ifdef SERVICE_THREAD /* Mark service as detached. */ /* If service thread is finished, cleanup memory being used by service. */ SVC_finish(service, SVC_detached); -#else - -/* Go ahead and cleanup memory being used by service */ - cleanup(service); - -#endif } @@ -792,51 +789,6 @@ void SVC_shutdown_init(shutdown_fct_t fptr, #endif // SERVER_SHUTDOWN -#ifdef SERVICE_THREAD -void SVC_fprintf(Service* service, const SCHAR* format, ...) -{ -/************************************** - * - * S V C _ f p r i n t f - * - **************************************/ -/* Ensure that service is not detached. */ - if (!(service->svc_flags & SVC_detached)) { - va_list arglist; - char buf[1000]; - ULONG i = 0; - - va_start(arglist, format); - // CVC: No bounds checking on "buf"; we assume everything fits in it. - // Where is that limit documented??? I changed to vsnprintf - //n = vsprintf(buf, format, arglist); - int n = VSNPRINTF(buf, sizeof(buf), format, arglist); - va_end(arglist); - // Nothing is said if this answer generated by service_enqueue_bytes - // should be null terminated always. Given the old code that called - // vsprintf, it's clear that '\0' was't sent, so in the new code, - // n is adjusted in case of insufficient buffer to behave the same. - // Changed ULONG to int, since this is the official type of the - // printf family and makes negative test natural. - // We could send a truncated answer in this case, since vsnprintf - // returns negative when buffer is not enough. Since the old code - // didn't send anything after an error, enable this to test if sending - // a partial result would crash the receiver. Failure may happen before - // reaching end of buffer for other reasons, so we might transfer trash. - //if (n < 0) - //{ - // n = sizeof(buf) - 1; - // buf[n] = 0; - //} - while (n > 0 && !(service->svc_flags & SVC_detached)) { - service_enqueue_byte(buf[i], service); - n--; - i++; - } - } -} - - void SVC_putc(Service* service, const UCHAR ch) { /************************************** @@ -857,11 +809,10 @@ void SVC_putc(Service* service, const UCHAR ch) int SVC_output(Service* output_data, const UCHAR* output_buf) { - SVC_fprintf(output_data, "%s", output_buf); + output_data->output(reinterpret_cast(output_buf)); return 0; } -#endif /*SERVICE_THREAD*/ ISC_STATUS SVC_query2(Service* service, @@ -1286,12 +1237,18 @@ ISC_STATUS SVC_query2(Service* service, break; } - if (item == isc_info_svc_line) + switch (item) + { + case isc_info_svc_line: get_flags = GET_LINE; - else if (item == isc_info_svc_to_eof) + break; + case isc_info_svc_to_eof: get_flags = GET_EOF; - else + break; + default: get_flags = GET_BINARY; + break; + } service_get(service, info + 3, end - (info + 5), get_flags, timeout, &length); @@ -1757,9 +1714,10 @@ void SVC_query(Service* service, if (!length && !(service->svc_flags & SVC_finished)) *info++ = isc_info_data_not_ready; else - if (item == isc_info_svc_to_eof && - !(service->svc_flags & SVC_finished)) + { + if (item == isc_info_svc_to_eof && !(service->svc_flags & SVC_finished)) *info++ = isc_info_truncated; + } } break; } @@ -1808,8 +1766,10 @@ void* SVC_start(Service* service, USHORT spb_length, const SCHAR* spb_data) const UCHAR svc_id = spb.getClumpTag(); serv_entry* serv; for (serv = services; serv->serv_action; serv++) + { if (serv->serv_action == svc_id) break; + } if (!serv->serv_name) ERR_post(isc_service_att_err, isc_arg_gds, isc_service_not_supported, 0); @@ -1870,20 +1830,23 @@ void* SVC_start(Service* service, USHORT spb_length, const SCHAR* spb_data) /* add the username and password to the end of svc_switches if needed */ if (service->svc_switches.hasData()) { -#ifdef TRUSTED_SERVICES if (service->svc_trusted_login.hasData()) { - service->svc_switches += ' '; + service->svc_switches += " -"; service->svc_switches += TRUSTED_USER_SWITCH; service->svc_switches += ' '; service->svc_switches += service->svc_username; + if (service->svc_trusted_role) + { + service->svc_switches += " -"; + service->svc_switches += TRUSTED_ROLE_SWITCH; + } } else -#endif { if (service->svc_username.hasData()) { - service->svc_switches += ' '; + service->svc_switches += " -"; service->svc_switches += USERNAME_SWITCH; service->svc_switches += ' '; service->svc_switches += service->svc_username; @@ -1891,7 +1854,7 @@ void* SVC_start(Service* service, USHORT spb_length, const SCHAR* spb_data) if (service->svc_enc_password.hasData()) { - service->svc_switches += ' '; + service->svc_switches += " -"; service->svc_switches += PASSWORD_SWITCH; service->svc_switches += ' '; service->svc_switches += service->svc_enc_password; @@ -1913,20 +1876,9 @@ void* SVC_start(Service* service, USHORT spb_length, const SCHAR* spb_data) ERR_post(isc_adm_task_denied, 0); } -#ifndef SERVICE_THREAD - TEXT service_path[MAXPATHLEN]; - - if (serv->serv_executable) { - gds__prefix(service_path, serv->serv_executable); - service->svc_flags = SVC_forked; - service_fork(service_path, service); - } - -#else /* Break up the command line into individual arguments. */ service->parseSwitches(); - service->svc_argv[0] = (TEXT *)(serv->serv_thd); /* * the service block can be reused hence free a memory from the @@ -1979,7 +1931,6 @@ void* SVC_start(Service* service, USHORT spb_length, const SCHAR* spb_data) 0); } -#endif /* SERVICE_THREAD */ return reinterpret_cast(reserved); } @@ -2000,34 +1951,25 @@ THREAD_ENTRY_DECLARE SVC_read_fb_log(THREAD_ENTRY_PARAM arg) **************************************/ bool svc_started = false; Service* service = (Service*)arg; -#ifdef SERVICE_THREAD ISC_STATUS *status = service->svc_status; *status++ = isc_arg_gds; -#endif TEXT name[MAXPATHLEN]; gds__prefix(name, LOGFILE); FILE* file = fopen(name, "r"); if (file != NULL) { -#ifdef SERVICE_THREAD *status++ = FB_SUCCESS; *status++ = isc_arg_end; -#endif service->svc_started(); svc_started = true; TEXT buffer[100]; while (!feof(file) && !ferror(file)) { fgets(buffer, sizeof(buffer), file); -#ifdef SERVICE_THREAD - SVC_fprintf(service, "%s", buffer); -#else - service_put(service, buffer, sizeof(buffer)); -#endif + service->output(buffer); } } if (!file || file && ferror(file)) { -#ifdef SERVICE_THREAD *status++ = isc_sys_request; if (!file) { SVC_STATUS_ARG(status, "fopen"); @@ -2038,7 +1980,6 @@ THREAD_ENTRY_DECLARE SVC_read_fb_log(THREAD_ENTRY_PARAM arg) *status++ = SYS_ARG; *status++ = errno; *status++ = isc_arg_end; -#endif if (!svc_started) { service->svc_started(); @@ -2048,11 +1989,7 @@ THREAD_ENTRY_DECLARE SVC_read_fb_log(THREAD_ENTRY_PARAM arg) if (file) fclose(file); -#ifdef SERVICE_THREAD SVC_finish(service, SVC_finished); -#else - cleanup(service); -#endif return (FINI_OK); } @@ -2096,11 +2033,13 @@ static void get_options(Firebird::ClumpletReader& spb, spb.getString(options->spb_password_enc); break; -#ifdef TRUSTED_SERVICES case isc_spb_trusted_auth: spb.getString(options->spb_trusted_login); break; -#endif + + case isc_spb_trusted_role: + options->spb_trusted_role = true; + break; case isc_spb_command_line: spb.getString(options->spb_command_line); @@ -2140,29 +2079,6 @@ static void get_options(Firebird::ClumpletReader& spb, } -#ifndef SERVICE_THREAD -static void io_error(const TEXT* string, - SLONG status, - const TEXT* filename, ISC_STATUS operation) -{ -/************************************** - * - * i o _ e r r o r - * - ************************************** - * - * Functional description - * Report an I/O error. - * - **************************************/ - - ERR_post(isc_io_error, isc_arg_string, string, isc_arg_string, filename, - isc_arg_gds, operation, SYS_ERR, status, 0); -} -#endif - - -#ifdef SERVICE_THREAD static USHORT service_add_one(USHORT i) { /************************************** @@ -2210,10 +2126,10 @@ static USHORT service_full(Service* service) if (service_add_one(service_add_one(service->svc_stdout_tail)) == service->svc_stdout_head) { - return (1); + return 1; } - else - return (0); + + return 0; } @@ -2231,7 +2147,7 @@ static UCHAR service_dequeue_byte(Service* service) const UCHAR ch = service->svc_stdout[service->svc_stdout_head]; service->svc_stdout_head = service_add_one(service->svc_stdout_head); - return (ch); + return ch; } @@ -2258,7 +2174,7 @@ static void service_enqueue_byte(UCHAR ch, Service* service) } -static void service_fork(ThreadEntryPoint* service_executable, Service* service) +static void service_fork(ThreadEntryPoint* service_thread, Service* service) { /************************************** * @@ -2274,11 +2190,13 @@ static void service_fork(ThreadEntryPoint* service_executable, Service* service) // Break up the command line into individual arguments. service->parseSwitches(); - USHORT argc = service->svc_argc; - service->svc_argv[0] = (TEXT *)(service_executable); + if (service->svc_service && service->svc_service->serv_name) + { + service->argv[0] = service->svc_service->serv_name; + } THREAD_EXIT(); - gds__thread_start(service_executable, + gds__thread_start(service_thread, service, THREAD_medium, 0, (void*)&service->svc_handle); THREAD_ENTER(); } @@ -2327,7 +2245,8 @@ static void service_get(Service* service, return; } - while (!service_empty(service) && length > 0) { + while (!service_empty(service) && length > 0) + { const int ch = service_dequeue_byte(service); length--; @@ -2339,8 +2258,8 @@ static void service_get(Service* service, buffer[(*return_length)++] = ' '; return; } - else - buffer[(*return_length)++] = ch; + + buffer[(*return_length)++] = ch; } if (service_empty(service) && (service->svc_flags & SVC_finished)) @@ -2365,278 +2284,6 @@ static void service_put(Service* service, const SCHAR* buffer, USHORT length) /* Nothing */ } -#endif /* SERVICE_THREAD */ - - -#ifndef SERVICE_THREAD - -#ifdef WIN_NT - -static void service_fork(TEXT* service_path, Service* service) -{ -/************************************** - * - * s e r v i c e _ f o r k ( W I N _ N T ) - * - ************************************** - * - * Functional description - * Startup a service. Just a stub. - * - **************************************/ - ERR_post(isc_service_att_err, isc_arg_gds, isc_service_not_supported, 0); -} - -static void service_get( - Service* service, - SCHAR * buffer, - USHORT length, - USHORT flags, USHORT timeout, USHORT * return_length) -{ -/************************************** - * - * s e r v i c e _ g e t ( W I N _ N T ) - * - ************************************** - * - * Functional description - * Get input from a service. - * Just a stub - * - **************************************/ -} - -static void service_put(Service* service, const SCHAR* buffer, USHORT length) -{ -/************************************** - * - * s e r v i c e _ p u t ( W I N _ N T ) - * - ************************************** - * - * Functional description - * Send output to a service. - * Just a stub - * - **************************************/ -} - -#else - -static void service_fork(TEXT* service_path, Service* service) -{ -/************************************** - * - * s e r v i c e _ f o r k ( G E N E R I C ) - * - ************************************** - * - * Functional description - * Startup a service. - * - **************************************/ - int pair1[2], pair2[2]; - - if (pipe(pair1) < 0 || pipe(pair2) < 0) - io_error("pipe", errno, "", isc_io_create_err); - -/* Probe service executable to see it if plausibly exists. */ - - struct stat stat_buf; - if (statistics(service_path, &stat_buf) == -1) - io_error("stat", errno, service_path, isc_io_access_err); - -/* Break up the command line into individual arguments. */ - service->parseSwitches(); - const char **argv = &service->svc_argv[0]; - *argv = service_path; - -/* At last we can fork the sub-process. If the fork succeeds, repeat - it so that we don't have defunct processes hanging around. */ - - THREAD_EXIT(); - - int pid; - - switch (pid = vfork()) { - case -1: - THREAD_ENTER(); - ERR_post(isc_sys_request, isc_arg_string, "vfork", SYS_ERR, errno, 0); - break; - - case 0: - if (vfork() != 0) - _exit(FINI_OK); - - close(pair1[0]); - close(pair2[1]); - if (pair2[0] != 0) { - close(0); - dup(pair2[0]); - close(pair2[0]); - } - if (pair1[1] != 1) { - close(1); - dup(pair1[1]); - close(pair1[1]); - } - close(2); - dup(1); -#ifdef DEV_BUILD - { - char buf[2 * MAXPATHLEN]; - const char** s = argv; - - strcpy (buf, "service_fork:"); - while (*s != (char *)0) - { - strcat(buf, " "); - strcat(buf, *s); - s++; - } - gds__log(buf); - } -#endif - execvp(argv[0], const_cast(argv)); - _exit(FINI_ERROR); - } - - close(pair1[1]); - close(pair2[0]); - - waitpid(pid, NULL, 0); - - THREAD_ENTER(); - - if (!(service->svc_input = fdopen(pair1[0], "r")) || - !(service->svc_output = fdopen(pair2[1], "w"))) - { - io_error("fdopen", errno, "service path", isc_io_access_err); - } -} - - -static void service_get( - Service* service, - SCHAR * buffer, - USHORT length, - USHORT flags, USHORT timeout, USHORT * return_length) -{ -/************************************** - * - * s e r v i c e _ g e t ( G E N E R I C ) - * - ************************************** - * - * Functional description - * Get input from a service. It is assumed - * that we have checked out of the scheduler. - * - **************************************/ - struct itimerval sv_timr; - struct sigaction sv_hndlr; - - is_service_running(service); - - errno = 0; - service->svc_flags &= ~SVC_timeout; - SCHAR* buf = buffer; - - SSHORT iter = 0; - if (timeout) { - ISC_set_timer((SLONG) (timeout * 100000), timeout_handler, service, - (SLONG*)&sv_timr, (void**)&sv_hndlr); - iter = timeout * 10; - } - - while (!timeout || iter) { - const int c = getc((FILE *) service->svc_input); - if (c != EOF) { - *buf++ = (flags & GET_LINE) && (c == '\n') ? ' ' : c; - if (!(--length)) - break; - if (((flags & GET_LINE) && c == '\n') || - (!(flags & GET_BINARY) && c == '\001')) - { - break; - } - } - else if (!errno) { - service->svc_flags |= SVC_finished; - break; - } - else if (SYSCALL_INTERRUPTED(errno)) { - if (timeout) - --iter; - } - else { - const int errno_save = errno; - if (timeout) - ISC_reset_timer(timeout_handler, service, (SLONG*)&sv_timr, - (void**)&sv_hndlr); - io_error("getc", errno_save, "service pipe", isc_io_read_err); - } - } - - if (timeout) { - ISC_reset_timer(timeout_handler, service, (SLONG*)&sv_timr, (void**)&sv_hndlr); - if (!iter) - service->svc_flags |= SVC_timeout; - } - - *return_length = buf - buffer; -} - - -static void service_put(Service* service, const SCHAR* buffer, USHORT length) -{ -/************************************** - * - * s e r v i c e _ p u t ( G E N E R I C ) - * - ************************************** - * - * Functional description - * Send output to a service. It is assumed - * that we have checked out of the scheduler. - * - **************************************/ - - is_service_running(service); - - while (length--) { - if (putc(*buffer, (FILE *) service->svc_output) != EOF) - buffer++; - else if (SYSCALL_INTERRUPTED(errno)) { - rewind((FILE *) service->svc_output); - length++; - } - else - io_error("putc", errno, "service pipe", isc_io_write_err); - } - - if (fflush((FILE *) service->svc_output) == EOF) - io_error("fflush", errno, "service pipe", isc_io_write_err); -} - - -static void timeout_handler(void* service) -{ -/************************************** - * - * t i m e o u t _ h a n d l e r - * - ************************************** - * - * Functional description - * Called when no input has been received - * through a pipe for a specificed period - * of time. - * - **************************************/ -} -#endif // !WIN_NT -#endif // SERVICE_THREAD static void cleanup(Service* service) @@ -2683,11 +2330,6 @@ void SVC_finish(Service* service, USHORT flag) } else if (service->svc_flags & SVC_finished) { - if (service->svc_service && service->svc_service->serv_in_use) - { - *(service->svc_service->serv_in_use) = false; - } - service->svc_flags &= ~SVC_thd_running; #ifdef WIN_NT @@ -2719,7 +2361,7 @@ static const TEXT* error_string(const TEXT* data, USHORT length) return ERR_string(data, length); data = "(null string)"; - return ERR_string(data, strlen(data)); + return ERR_string(data, strlen(data)); // Maybe it's enough with the static string? } @@ -2752,9 +2394,6 @@ static void conv_switches(Firebird::ClumpletReader& spb, Firebird::string& switc return; } - sw.insert(0, ' '); - sw.insert(0, SERVICE_THD_PARAM); - switches = sw; return; } @@ -2812,30 +2451,31 @@ static bool process_switches(Firebird::ClumpletReader& spb, { case isc_action_svc_delete_user: case isc_action_svc_display_user: - if (!found) { + if (!found) + { if (!get_action_svc_parameter(svc_action, gsec_action_in_sw_table, switches)) { return false; } - else { - if (spb.isEof() && svc_action == isc_action_svc_display_user) - { - // in case of "display all users" the spb buffer contains - // nothing but isc_action_svc_display_user or isc_spb_dbname - break; - } - if (spb.getClumpTag() != isc_spb_sec_username && - spb.getClumpTag() != isc_spb_dbname) - { - // unexpected item in service parameter block, expected @1 - ERR_post(isc_unexp_spb_form, isc_arg_string, - error_string(SPB_SEC_USERNAME, - strlen(SPB_SEC_USERNAME)), - 0); - } - found = true; + if (spb.isEof() && svc_action == isc_action_svc_display_user) + { + // in case of "display all users" the spb buffer contains + // nothing but isc_action_svc_display_user or isc_spb_dbname + break; } + + if (spb.getClumpTag() != isc_spb_sec_username && + spb.getClumpTag() != isc_spb_dbname) + { + // unexpected item in service parameter block, expected @1 + ERR_post(isc_unexp_spb_form, isc_arg_string, + error_string(SPB_SEC_USERNAME, + strlen(SPB_SEC_USERNAME)), + 0); + } + + found = true; } switch (spb.getClumpTag()) @@ -2853,27 +2493,26 @@ static bool process_switches(Firebird::ClumpletReader& spb, default: return false; - break; } break; case isc_action_svc_add_user: case isc_action_svc_modify_user: - if (!found) { + if (!found) + { if (!get_action_svc_parameter(svc_action, gsec_action_in_sw_table, switches)) { return false; } - else { - if (spb.getClumpTag() != isc_spb_sec_username) { - // unexpected item in service parameter block, expected @1 - ERR_post(isc_unexp_spb_form, isc_arg_string, - error_string(SPB_SEC_USERNAME, - strlen(SPB_SEC_USERNAME)), - 0); - } - found = true; + + if (spb.getClumpTag() != isc_spb_sec_username) { + // unexpected item in service parameter block, expected @1 + ERR_post(isc_unexp_spb_form, isc_arg_string, + error_string(SPB_SEC_USERNAME, + strlen(SPB_SEC_USERNAME)), + 0); } + found = true; } switch (spb.getClumpTag()) @@ -2905,7 +2544,6 @@ static bool process_switches(Firebird::ClumpletReader& spb, default: return false; - break; } break; @@ -2928,7 +2566,6 @@ static bool process_switches(Firebird::ClumpletReader& spb, default: return false; - break; } break; @@ -2977,7 +2614,6 @@ static bool process_switches(Firebird::ClumpletReader& spb, break; default: return false; - break; } break; @@ -3018,12 +2654,10 @@ static bool process_switches(Firebird::ClumpletReader& spb, break; default: return false; - break; } break; default: return false; - break; } spb.moveNext(); diff --git a/src/jrd/svc.h b/src/jrd/svc.h index 3df617a59b..10855a280c 100644 --- a/src/jrd/svc.h +++ b/src/jrd/svc.h @@ -38,6 +38,7 @@ #include "../include/fb_blk.h" #include "../common/classes/array.h" #include "../common/classes/SafeArg.h" +#include "../common/UtilSvc.h" void SVC_STATUS_ARG(ISC_STATUS*& status, const MsgFormat::safe_cell& value); void SVC_STATUS_ARG(ISC_STATUS*& status, const char* value); @@ -74,20 +75,6 @@ const USHORT isc_action_max = 14; //define isc_info_max 67 -/* switches for username and password used when a username and/or password - * is specified by the client application - */ -#define USERNAME_SWITCH "-USER" -#define PASSWORD_SWITCH "-PASSWORD" -#ifdef SERVICE_THREAD -#define SERVICE_THD_PARAM "-svc_thd" -#else -#define SERVICE_THD_PARAM "-svc" -#endif -#ifdef TRUSTED_SERVICES -#define TRUSTED_USER_SWITCH "-TRUSTED_SVC" -#endif - /* Macro used to store services thread specific data */ /* Currently we store empty string, see bug #10394 */ // BRS 01/07/2004 commented @@ -105,11 +92,11 @@ const USHORT isc_action_max = 14; struct serv_entry; // forward decl. /* Service manager block */ -class Service : public pool_alloc +class Service : public Firebird::UtilSvc, public LocalType { private: ISC_STATUS_ARRAY svc_status_array; - Firebird::string svc_parsed_sw; // Here point elements of svc_argv + Firebird::string svc_parsed_sw; // Here point elements of argv public: Service(serv_entry *se, Firebird::MemoryPool& p); @@ -122,8 +109,6 @@ public: ULONG svc_stdout_head; ULONG svc_stdout_tail; UCHAR* svc_stdout; - Firebird::HalfStaticArray svc_argv; - ULONG svc_argc; Firebird::Semaphore svcStart; serv_entry* svc_service; UCHAR* svc_resp_buf; @@ -136,40 +121,42 @@ public: bool svc_do_shutdown; Firebird::string svc_username; Firebird::string svc_enc_password; -#ifdef TRUSTED_SERVICES Firebird::string svc_trusted_login; -#endif + bool svc_trusted_role; Firebird::string svc_switches; // Full set of switches Firebird::string svc_perm_sw; // Switches, taken from services table // and/or passed using spb_command_line void svc_started(); - void parseSwitches(); // Create svc_argv, svc_argc and svc_parsed_sw + void parseSwitches(); // Create argv, argc and svc_parsed_sw + + // utilities interface with service +public: + virtual void printf(const SCHAR* format, ...); + virtual bool isService(); + virtual void started(); + virtual void finish(); + virtual void putLine(char, const char*); + virtual void putSLong(char, SLONG); + virtual void putChar(char, char); + virtual void stuffStatus(const ISC_STATUS*); + virtual void stuffStatus(const USHORT, const USHORT, const MsgFormat::SafeArg&); + virtual void hidePasswd(ArgvType&, int); + virtual ISC_STATUS* getStatus(); + virtual void checkService(); }; /* Bitmask values for the svc_flags variable */ //const int SVC_eof = 1; const int SVC_timeout = 2; -const int SVC_forked = 4; +//const int SVC_forked = 4; const int SVC_detached = 8; const int SVC_finished = 16; const int SVC_thd_running = 32; const int SVC_evnt_fired = 64; const int SVC_cmd_line = 128; -// Method used to signify that the service started has done basic -// initialization and can be considered a successful startup. - -#ifndef SERVICE_THREAD - -inline void Service::svc_started() -{ - // null definition, no overhead. -} - -#endif /* SERVICE_THREAD */ - typedef int (*pfn_svc_output)(Service*, const UCHAR*); struct serv_entry @@ -177,9 +164,7 @@ struct serv_entry USHORT serv_action; const TEXT* serv_name; const TEXT* serv_std_switches; - const TEXT* serv_executable; ThreadEntryPoint* serv_thd; - bool* serv_in_use; }; } //namespace Jrd diff --git a/src/jrd/svc_proto.h b/src/jrd/svc_proto.h index df10bf02ee..0d8be07294 100644 --- a/src/jrd/svc_proto.h +++ b/src/jrd/svc_proto.h @@ -24,7 +24,7 @@ #ifndef JRD_SVC_PROTO_H #define JRD_SVC_PROTO_H -#include "../jrd/thd.h" +#include "../jrd/ThreadStart.h" namespace Jrd { class Service; @@ -34,7 +34,6 @@ namespace Jrd { extern "C" { Jrd::Service* SVC_attach(USHORT, const TEXT*, USHORT, const SCHAR*); void SVC_detach(Jrd::Service*); -void SVC_fprintf(Jrd::Service*, const SCHAR*, ...); void SVC_putc(Jrd::Service*, const UCHAR); void SVC_query(Jrd::Service*, USHORT, const SCHAR*, USHORT, const SCHAR*, USHORT, SCHAR*); @@ -43,7 +42,6 @@ ISC_STATUS SVC_query2(Jrd::Service*, Jrd::thread_db*, USHORT, const SCHAR*, void* SVC_start(Jrd::Service*, USHORT, const SCHAR*); void SVC_finish(Jrd::Service*, USHORT); THREAD_ENTRY_DECLARE SVC_read_fb_log(THREAD_ENTRY_PARAM); -int SVC_output(Jrd::Service*, const UCHAR*); #ifdef SERVER_SHUTDOWN typedef void (*shutdown_fct_t) (ULONG); diff --git a/src/jrd/sym.cpp b/src/jrd/sym.cpp deleted file mode 100644 index 25533d00f3..0000000000 --- a/src/jrd/sym.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * PROGRAM: JRD access method - * MODULE: hsh.cpp - * DESCRIPTION: Hash table and symbol manager - * - * The contents of this file are subject to the Interbase Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy - * of the License at http://www.Inprise.com/IPL.html - * - * Software distributed under the License is distributed on an - * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express - * or implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code was created by Inprise Corporation - * and its predecessors. Portions created by Inprise Corporation are - * Copyright (C) Inprise Corporation. - * - * All Rights Reserved. - * Contributor(s): ______________________________________. - */ - -#include "firebird.h" -#include -#include "../jrd/common.h" -#include "../jrd/jrd.h" -#include "../jrd/val.h" -#include "../jrd/err_proto.h" -#include "../jrd/sym.h" -#include "../jrd/thd.h" - - -using namespace Jrd; - -namespace { - SSHORT hash_func(const Firebird::MetaName&); -} - -void Symbol::insert() -{ -/************************************** - * - * S Y M _ i n s e r t - * - ************************************** - * - * Functional description - * Insert a symbol into the hash table. - * - **************************************/ - Database* dbb = GET_DBB(); - - const int h = hash_func(sym_string); - - for (Symbol* old = dbb->dbb_hash_table[h]; old; old = old->sym_collision) - { - if (sym_string == old->sym_string) - { - sym_homonym = old->sym_homonym; - old->sym_homonym = this; - return; - } - } - - sym_collision = dbb->dbb_hash_table[h]; - dbb->dbb_hash_table[h] = this; -} - - -Symbol* Symbol::lookup(const Firebird::MetaName& string) -{ -/************************************** - * - * S Y M _ l o o k u p - * - ************************************** - * - * Functional description - * Perform a string lookup against hash table. - * - **************************************/ - Database* dbb = GET_DBB(); - - for (Symbol* symbol = dbb->dbb_hash_table[hash_func(string)]; symbol; - symbol = symbol->sym_collision) - { - if (string == symbol->sym_string) - return symbol; - } - - return NULL; -} - - -void Symbol::remove() -{ -/************************************** - * - * S Y M _ r e m o v e - * - ************************************** - * - * Functional description - * Remove a symbol from the hash table. - * - **************************************/ - Database* dbb = GET_DBB(); - - const int h = hash_func(sym_string); - - for (Symbol** next = &dbb->dbb_hash_table[h]; *next; - next = &(*next)->sym_collision) - { - if (this == *next) { - Symbol* homonym = sym_homonym; - if (homonym) { - homonym->sym_collision = sym_collision; - *next = homonym; - return; - } - else { - *next = sym_collision; - return; - } - } - else { - for (Symbol** ptr = &(*next)->sym_homonym; *ptr; - ptr = &(*ptr)->sym_homonym) - { - if (this == *ptr) { - *ptr = sym_homonym; - return; - } - } - } - } - - BUGCHECK(164); /* msg 164 failed to remove symbol from hash table */ -} - -namespace { - -SSHORT hash_func(const Firebird::MetaName& str) -{ -/************************************** - * - * h a s h - * - ************************************** - * - * Functional description - * Returns the hash function of a string. - * - **************************************/ - -/* It is OK to not Internationalize this function as it is for - internal optimization of symbol lookup */ - - int value = 0; - - for (const char *s = str.c_str(); *s; s++) - { - value = (value << 1) + UPPER7(*s); - } - - return ((value >= 0) ? value : -value) % HASH_SIZE; -} - -} //noname namespace diff --git a/src/jrd/sym.h b/src/jrd/sym.h deleted file mode 100644 index 65220f4b23..0000000000 --- a/src/jrd/sym.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * PROGRAM: JRD Access Method - * MODULE: sym.h - * DESCRIPTION: Header file for sym.cpp - * - * The contents of this file are subject to the Interbase Public - * License Version 1.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy - * of the License at http://www.Inprise.com/IPL.html - * - * Software distributed under the License is distributed on an - * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express - * or implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code was created by Inprise Corporation - * and its predecessors. Portions created by Inprise Corporation are - * Copyright (C) Inprise Corporation. - * - * All Rights Reserved. - * Contributor(s): ______________________________________. - */ - -#ifndef JRD_SYM_H -#define JRD_SYM_H - -#include "../common/classes/MetaName.h" - -namespace Jrd { -/* symbol definitions */ - -class UserFunction; - -// This "Symbol" became a mere container for UDFs. DSQL has another Symbol class. - -class Symbol : public pool_alloc -{ -private: - Symbol* sym_collision; // collision pointer - -public: - //enum sym_t { - //rel, // relation block - //fld, // field block - //fun // UDF function block - //prc, // stored procedure block - //sql, // SQL request cache block - //blr, // BLR request cache block - //label // CVC: I need to track labels if LEAVE is implemented. - //}; - Firebird::MetaName sym_string; // symbol value - //sym_t sym_type; // symbol type - UserFunction* sym_object; // pointer to UDF object - Symbol* sym_homonym; // homonym pointer - -public: - explicit Symbol(MemoryPool& p, const Firebird::MetaName& val, //sym_t type, - UserFunction* object) - : sym_collision(0), sym_string(p, val), //sym_type(type), - sym_object(object), sym_homonym(0) { } - void insert(); - static Symbol* lookup(const Firebird::MetaName&); - void remove(); -}; - -} //namespace Jrd - - -#endif // JRD_SYM_H -