mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 21:23:03 +01:00
Style.
This commit is contained in:
parent
3359dc0d43
commit
f7bf07d9be
@ -290,8 +290,10 @@ ULONG IntlUtil::cvtAsciiToUtf16(csconvert* obj, ULONG nSrc, const UCHAR* pSrc,
|
|||||||
|
|
||||||
const USHORT* const pStart = pDest;
|
const USHORT* const pStart = pDest;
|
||||||
const UCHAR* const pStart_src = pSrc;
|
const UCHAR* const pStart_src = pSrc;
|
||||||
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc)) {
|
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc))
|
||||||
if (*pSrc > 127) {
|
{
|
||||||
|
if (*pSrc > 127)
|
||||||
|
{
|
||||||
*err_code = CS_BAD_INPUT;
|
*err_code = CS_BAD_INPUT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -336,8 +338,10 @@ ULONG IntlUtil::cvtUtf16ToAscii(csconvert* obj, ULONG nSrc, const UCHAR* ppSrc,
|
|||||||
|
|
||||||
const UCHAR* const pStart = pDest;
|
const UCHAR* const pStart = pDest;
|
||||||
const USHORT* const pStart_src = pSrc;
|
const USHORT* const pStart_src = pSrc;
|
||||||
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc)) {
|
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc))
|
||||||
if (*pSrc > 127) {
|
{
|
||||||
|
if (*pSrc > 127)
|
||||||
|
{
|
||||||
*err_code = CS_CONVERT_ERROR;
|
*err_code = CS_CONVERT_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,8 @@ bool OPT_computable(CompilerScratch* csb, const jrd_nod* node, SSHORT stream,
|
|||||||
case nod_procedure:
|
case nod_procedure:
|
||||||
{
|
{
|
||||||
const jrd_nod* const inputs = node->nod_arg[e_prc_inputs];
|
const jrd_nod* const inputs = node->nod_arg[e_prc_inputs];
|
||||||
if (inputs) {
|
if (inputs)
|
||||||
|
{
|
||||||
fb_assert(inputs->nod_type == nod_asn_list);
|
fb_assert(inputs->nod_type == nod_asn_list);
|
||||||
const jrd_nod* const* ptr = inputs->nod_arg;
|
const jrd_nod* const* ptr = inputs->nod_arg;
|
||||||
for (const jrd_nod* const* const end = ptr + inputs->nod_count; ptr < end; ptr++)
|
for (const jrd_nod* const* const end = ptr + inputs->nod_count; ptr < end; ptr++)
|
||||||
@ -140,13 +141,15 @@ bool OPT_computable(CompilerScratch* csb, const jrd_nod* node, SSHORT stream,
|
|||||||
{
|
{
|
||||||
case nod_field:
|
case nod_field:
|
||||||
n = (USHORT)(IPTR) node->nod_arg[e_fld_stream];
|
n = (USHORT)(IPTR) node->nod_arg[e_fld_stream];
|
||||||
if (allowOnlyCurrentStream) {
|
if (allowOnlyCurrentStream)
|
||||||
|
{
|
||||||
if (n != stream && !(csb->csb_rpt[n].csb_flags & csb_sub_stream))
|
if (n != stream && !(csb->csb_rpt[n].csb_flags & csb_sub_stream))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (n == stream) {
|
if (n == stream) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -239,8 +242,10 @@ bool OPT_computable(CompilerScratch* csb, const jrd_nod* node, SSHORT stream,
|
|||||||
const jrd_nod* const* ptr;
|
const jrd_nod* const* ptr;
|
||||||
const jrd_nod* const* end;
|
const jrd_nod* const* end;
|
||||||
|
|
||||||
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end; ptr++) {
|
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end; ptr++)
|
||||||
if ((*ptr)->nod_type != nod_rse) {
|
{
|
||||||
|
if ((*ptr)->nod_type != nod_rse)
|
||||||
|
{
|
||||||
n = (USHORT)(IPTR) (*ptr)->nod_arg[STREAM_INDEX((*ptr))];
|
n = (USHORT)(IPTR) (*ptr)->nod_arg[STREAM_INDEX((*ptr))];
|
||||||
csb->csb_rpt[n].csb_flags |= (csb_active | csb_sub_stream);
|
csb->csb_rpt[n].csb_flags |= (csb_active | csb_sub_stream);
|
||||||
}
|
}
|
||||||
@ -256,7 +261,8 @@ bool OPT_computable(CompilerScratch* csb, const jrd_nod* node, SSHORT stream,
|
|||||||
|
|
||||||
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end && result; ptr++)
|
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end && result; ptr++)
|
||||||
{
|
{
|
||||||
if ((*ptr)->nod_type != nod_rse) {
|
if ((*ptr)->nod_type != nod_rse)
|
||||||
|
{
|
||||||
if (!OPT_computable(csb, (*ptr), stream, idx_use, allowOnlyCurrentStream)) {
|
if (!OPT_computable(csb, (*ptr), stream, idx_use, allowOnlyCurrentStream)) {
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
@ -617,12 +623,14 @@ double OPT_getRelationCardinality(thread_db* tdbb, jrd_rel* relation, const Form
|
|||||||
**************************************/
|
**************************************/
|
||||||
SET_TDBB(tdbb);
|
SET_TDBB(tdbb);
|
||||||
|
|
||||||
if (relation->isVirtual()) {
|
if (relation->isVirtual())
|
||||||
|
{
|
||||||
// Just a dumb estimation
|
// Just a dumb estimation
|
||||||
return (double) 100;
|
return (double) 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relation->rel_file) {
|
if (relation->rel_file)
|
||||||
|
{
|
||||||
// Is there really no way to do better?
|
// Is there really no way to do better?
|
||||||
// Don't we know the file-size and record-size?
|
// Don't we know the file-size and record-size?
|
||||||
return (double) 10000;
|
return (double) 10000;
|
||||||
@ -711,12 +719,14 @@ VaryingString* OPT_make_alias(thread_db* tdbb, const CompilerScratch* csb,
|
|||||||
const TEXT* q;
|
const TEXT* q;
|
||||||
if (csb_tail->csb_alias)
|
if (csb_tail->csb_alias)
|
||||||
q = (TEXT *) csb_tail->csb_alias->c_str();
|
q = (TEXT *) csb_tail->csb_alias->c_str();
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
q = (csb_tail->csb_relation && csb_tail->csb_relation->rel_name.length() ?
|
q = (csb_tail->csb_relation && csb_tail->csb_relation->rel_name.length() ?
|
||||||
csb_tail->csb_relation->rel_name.c_str() : NULL);
|
csb_tail->csb_relation->rel_name.c_str() : NULL);
|
||||||
}
|
}
|
||||||
// go to the end of the alias and copy it backwards
|
// go to the end of the alias and copy it backwards
|
||||||
if (q) {
|
if (q)
|
||||||
|
{
|
||||||
for (alias_length = 0; *q; alias_length++)
|
for (alias_length = 0; *q; alias_length++)
|
||||||
q++;
|
q++;
|
||||||
while (alias_length--)
|
while (alias_length--)
|
||||||
@ -845,7 +855,8 @@ IndexScratch::IndexScratch(MemoryPool& p, thread_db* tdbb, index_desc* ix,
|
|||||||
// Multipling the selectivity with this cardinality gives the estimated
|
// Multipling the selectivity with this cardinality gives the estimated
|
||||||
// number of index pages that are read for the index retrieval.
|
// number of index pages that are read for the index retrieval.
|
||||||
double factor = 0.5;
|
double factor = 0.5;
|
||||||
if (segments.getCount() >= 2) {
|
if (segments.getCount() >= 2)
|
||||||
|
{
|
||||||
// Compound indexes are generally less compressed.
|
// Compound indexes are generally less compressed.
|
||||||
factor = 0.7;
|
factor = 0.7;
|
||||||
}
|
}
|
||||||
@ -1046,7 +1057,8 @@ void OptimizerRetrieval::findDependentFromStreams(const jrd_nod* node,
|
|||||||
if (node->nod_type == nod_procedure)
|
if (node->nod_type == nod_procedure)
|
||||||
{
|
{
|
||||||
const jrd_nod* const inputs = node->nod_arg[e_prc_inputs];
|
const jrd_nod* const inputs = node->nod_arg[e_prc_inputs];
|
||||||
if (inputs) {
|
if (inputs)
|
||||||
|
{
|
||||||
fb_assert(inputs->nod_type == nod_asn_list);
|
fb_assert(inputs->nod_type == nod_asn_list);
|
||||||
const jrd_nod* const* ptr = inputs->nod_arg;
|
const jrd_nod* const* ptr = inputs->nod_arg;
|
||||||
for (const jrd_nod* const* const end = ptr + inputs->nod_count; ptr < end; ptr++)
|
for (const jrd_nod* const* const end = ptr + inputs->nod_count; ptr < end; ptr++)
|
||||||
@ -1174,7 +1186,8 @@ void OptimizerRetrieval::findDependentFromStreams(const jrd_nod* node,
|
|||||||
|
|
||||||
const jrd_nod* const* ptr;
|
const jrd_nod* const* ptr;
|
||||||
const jrd_nod* const* end;
|
const jrd_nod* const* end;
|
||||||
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end; ptr++) {
|
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end; ptr++)
|
||||||
|
{
|
||||||
if ((*ptr)->nod_type != nod_rse) {
|
if ((*ptr)->nod_type != nod_rse) {
|
||||||
findDependentFromStreams(*ptr, streamList);
|
findDependentFromStreams(*ptr, streamList);
|
||||||
}
|
}
|
||||||
@ -1199,7 +1212,8 @@ VaryingString* OptimizerRetrieval::getAlias()
|
|||||||
* Functional description
|
* Functional description
|
||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
if (!alias) {
|
if (!alias)
|
||||||
|
{
|
||||||
const CompilerScratch::csb_repeat* csb_tail = &csb->csb_rpt[this->stream];
|
const CompilerScratch::csb_repeat* csb_tail = &csb->csb_rpt[this->stream];
|
||||||
alias = OPT_make_alias(tdbb, csb, csb_tail);
|
alias = OPT_make_alias(tdbb, csb, csb_tail);
|
||||||
}
|
}
|
||||||
@ -1234,7 +1248,8 @@ InversionCandidate* OptimizerRetrieval::generateInversion(RecordSource** rsb)
|
|||||||
if (outerFlag) {
|
if (outerFlag) {
|
||||||
tail += optimizer->opt_base_parent_conjuncts;
|
tail += optimizer->opt_base_parent_conjuncts;
|
||||||
}
|
}
|
||||||
for (; tail < opt_end; tail++) {
|
for (; tail < opt_end; tail++)
|
||||||
|
{
|
||||||
if (tail->opt_conjunct_flags & opt_conjunct_matched) {
|
if (tail->opt_conjunct_flags & opt_conjunct_matched) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1256,7 +1271,8 @@ InversionCandidate* OptimizerRetrieval::generateInversion(RecordSource** rsb)
|
|||||||
if (outerFlag) {
|
if (outerFlag) {
|
||||||
tail += optimizer->opt_base_parent_conjuncts;
|
tail += optimizer->opt_base_parent_conjuncts;
|
||||||
}
|
}
|
||||||
for (; tail < opt_end; tail++) {
|
for (; tail < opt_end; tail++)
|
||||||
|
{
|
||||||
if (tail->opt_conjunct_flags & opt_conjunct_matched) {
|
if (tail->opt_conjunct_flags & opt_conjunct_matched) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1264,7 +1280,8 @@ InversionCandidate* OptimizerRetrieval::generateInversion(RecordSource** rsb)
|
|||||||
if (!(tail->opt_conjunct_flags & opt_conjunct_used) && node && (node->nod_type == nod_or))
|
if (!(tail->opt_conjunct_flags & opt_conjunct_used) && node && (node->nod_type == nod_or))
|
||||||
{
|
{
|
||||||
invCandidate = matchOnIndexes(&indexScratches, node, 1);
|
invCandidate = matchOnIndexes(&indexScratches, node, 1);
|
||||||
if (invCandidate) {
|
if (invCandidate)
|
||||||
|
{
|
||||||
invCandidate->boolean = node;
|
invCandidate->boolean = node;
|
||||||
inversions.add(invCandidate);
|
inversions.add(invCandidate);
|
||||||
}
|
}
|
||||||
@ -1280,12 +1297,14 @@ InversionCandidate* OptimizerRetrieval::generateInversion(RecordSource** rsb)
|
|||||||
|
|
||||||
if (invCandidate)
|
if (invCandidate)
|
||||||
{
|
{
|
||||||
if (invCandidate->unique) {
|
if (invCandidate->unique)
|
||||||
|
{
|
||||||
// Set up the unique retrieval cost to be fixed and not dependent on
|
// Set up the unique retrieval cost to be fixed and not dependent on
|
||||||
// possibly outdated statistics
|
// possibly outdated statistics
|
||||||
invCandidate->cost = DEFAULT_INDEX_COST * invCandidate->indexes + 1;
|
invCandidate->cost = DEFAULT_INDEX_COST * invCandidate->indexes + 1;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
// Add the records retrieval cost to the priorly calculated index scan cost
|
// Add the records retrieval cost to the priorly calculated index scan cost
|
||||||
invCandidate->cost += csb->csb_rpt[stream].csb_cardinality * invCandidate->selectivity;
|
invCandidate->cost += csb->csb_rpt[stream].csb_cardinality * invCandidate->selectivity;
|
||||||
}
|
}
|
||||||
@ -1303,8 +1322,10 @@ InversionCandidate* OptimizerRetrieval::generateInversion(RecordSource** rsb)
|
|||||||
// However SortedArray class should be updated to handle join right!
|
// However SortedArray class should be updated to handle join right!
|
||||||
matches.join(invCandidate->matches);
|
matches.join(invCandidate->matches);
|
||||||
tail = optimizer->opt_conjuncts.begin();
|
tail = optimizer->opt_conjuncts.begin();
|
||||||
for (; tail < opt_end; tail++) {
|
for (; tail < opt_end; tail++)
|
||||||
if (!(tail->opt_conjunct_flags & opt_conjunct_used)) {
|
{
|
||||||
|
if (!(tail->opt_conjunct_flags & opt_conjunct_used))
|
||||||
|
{
|
||||||
if (matches.exist(tail->opt_conjunct_node)) {
|
if (matches.exist(tail->opt_conjunct_node)) {
|
||||||
tail->opt_conjunct_flags |= opt_conjunct_matched;
|
tail->opt_conjunct_flags |= opt_conjunct_matched;
|
||||||
}
|
}
|
||||||
@ -1346,7 +1367,8 @@ RecordSource* OptimizerRetrieval::generateNavigation()
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (; i < indexScratches.getCount(); ++i) {
|
for (; i < indexScratches.getCount(); ++i)
|
||||||
|
{
|
||||||
|
|
||||||
index_desc* idx = indexScratches[i].idx;
|
index_desc* idx = indexScratches[i].idx;
|
||||||
|
|
||||||
@ -1451,7 +1473,8 @@ RecordSource* OptimizerRetrieval::generateNavigation()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!usableIndex) {
|
if (!usableIndex)
|
||||||
|
{
|
||||||
// We can't use this index, try next one.
|
// We can't use this index, try next one.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1664,7 +1687,8 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio
|
|||||||
fb_assert(selectivity <= scratch.selectivity);
|
fb_assert(selectivity <= scratch.selectivity);
|
||||||
scratch.selectivity = selectivity;
|
scratch.selectivity = selectivity;
|
||||||
|
|
||||||
if (segment->scanType != segmentScanNone) {
|
if (segment->scanType != segmentScanNone)
|
||||||
|
{
|
||||||
matches.join(segment->matches);
|
matches.join(segment->matches);
|
||||||
scratch.nonFullMatchedSegments = scratch.idx->idx_count - j;
|
scratch.nonFullMatchedSegments = scratch.idx->idx_count - j;
|
||||||
}
|
}
|
||||||
@ -1680,7 +1704,8 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio
|
|||||||
// For a non-unique one, assume 1/10 of the maximum selectivity, so that
|
// For a non-unique one, assume 1/10 of the maximum selectivity, so that
|
||||||
// at least some indexes could be chosen by the optimizer.
|
// at least some indexes could be chosen by the optimizer.
|
||||||
double selectivity = scratch.selectivity;
|
double selectivity = scratch.selectivity;
|
||||||
if (selectivity <= 0) {
|
if (selectivity <= 0)
|
||||||
|
{
|
||||||
if (unique && cardinality)
|
if (unique && cardinality)
|
||||||
selectivity = 1 / cardinality;
|
selectivity = 1 / cardinality;
|
||||||
else
|
else
|
||||||
@ -1703,7 +1728,8 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio
|
|||||||
invCandidate->indexes = 1;
|
invCandidate->indexes = 1;
|
||||||
invCandidate->scratch = &scratch;
|
invCandidate->scratch = &scratch;
|
||||||
invCandidate->matches.join(matches);
|
invCandidate->matches.join(matches);
|
||||||
for (size_t k = 0; k < invCandidate->matches.getCount(); k++) {
|
for (size_t k = 0; k < invCandidate->matches.getCount(); k++)
|
||||||
|
{
|
||||||
findDependentFromStreams(invCandidate->matches[k],
|
findDependentFromStreams(invCandidate->matches[k],
|
||||||
&invCandidate->dependentFromStreams);
|
&invCandidate->dependentFromStreams);
|
||||||
}
|
}
|
||||||
@ -1779,7 +1805,8 @@ jrd_nod* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch) const
|
|||||||
retrieval->irb_lower_count = indexScratch->lowerCount;
|
retrieval->irb_lower_count = indexScratch->lowerCount;
|
||||||
retrieval->irb_upper_count = indexScratch->upperCount;
|
retrieval->irb_upper_count = indexScratch->upperCount;
|
||||||
|
|
||||||
if (idx->idx_flags & idx_descending) {
|
if (idx->idx_flags & idx_descending)
|
||||||
|
{
|
||||||
// switch upper/lower information
|
// switch upper/lower information
|
||||||
upper = retrieval->irb_value;
|
upper = retrieval->irb_value;
|
||||||
lower = retrieval->irb_value + idx->idx_count;
|
lower = retrieval->irb_value + idx->idx_count;
|
||||||
@ -1793,13 +1820,15 @@ jrd_nod* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch) const
|
|||||||
IndexScratchSegment** segment = indexScratch->segments.begin();
|
IndexScratchSegment** segment = indexScratch->segments.begin();
|
||||||
for (i = 0; i < MAX(indexScratch->lowerCount, indexScratch->upperCount); i++)
|
for (i = 0; i < MAX(indexScratch->lowerCount, indexScratch->upperCount); i++)
|
||||||
{
|
{
|
||||||
if (segment[i]->scanType == segmentScanMissing) {
|
if (segment[i]->scanType == segmentScanMissing)
|
||||||
|
{
|
||||||
jrd_nod* value = PAR_make_node(tdbb, 0);
|
jrd_nod* value = PAR_make_node(tdbb, 0);
|
||||||
value->nod_type = nod_null;
|
value->nod_type = nod_null;
|
||||||
*lower++ = *upper++ = value;
|
*lower++ = *upper++ = value;
|
||||||
ignoreNullsOnScan = false;
|
ignoreNullsOnScan = false;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (i < indexScratch->lowerCount) {
|
if (i < indexScratch->lowerCount) {
|
||||||
*lower++ = segment[i]->lowerValue;
|
*lower++ = segment[i]->lowerValue;
|
||||||
}
|
}
|
||||||
@ -1872,11 +1901,14 @@ jrd_nod* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if this is really an equality retrieval
|
// Check to see if this is really an equality retrieval
|
||||||
if (retrieval->irb_lower_count == retrieval->irb_upper_count) {
|
if (retrieval->irb_lower_count == retrieval->irb_upper_count)
|
||||||
|
{
|
||||||
retrieval->irb_generic |= irb_equality;
|
retrieval->irb_generic |= irb_equality;
|
||||||
segment = indexScratch->segments.begin();
|
segment = indexScratch->segments.begin();
|
||||||
for (i = 0; i < retrieval->irb_lower_count; i++) {
|
for (i = 0; i < retrieval->irb_lower_count; i++)
|
||||||
if (segment[i]->lowerValue != segment[i]->upperValue) {
|
{
|
||||||
|
if (segment[i]->lowerValue != segment[i]->upperValue)
|
||||||
|
{
|
||||||
retrieval->irb_generic &= ~irb_equality;
|
retrieval->irb_generic &= ~irb_equality;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1884,12 +1916,14 @@ jrd_nod* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we are matching less than the full index, this is a partial match
|
// If we are matching less than the full index, this is a partial match
|
||||||
if (idx->idx_flags & idx_descending) {
|
if (idx->idx_flags & idx_descending)
|
||||||
|
{
|
||||||
if (retrieval->irb_lower_count < idx->idx_count) {
|
if (retrieval->irb_lower_count < idx->idx_count) {
|
||||||
retrieval->irb_generic |= irb_partial;
|
retrieval->irb_generic |= irb_partial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (retrieval->irb_upper_count < idx->idx_count) {
|
if (retrieval->irb_upper_count < idx->idx_count) {
|
||||||
retrieval->irb_generic |= irb_partial;
|
retrieval->irb_generic |= irb_partial;
|
||||||
}
|
}
|
||||||
@ -1960,9 +1994,11 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
InversionCandidate* invCandidate = NULL;
|
InversionCandidate* invCandidate = NULL;
|
||||||
InversionCandidate** inversion = inversions->begin();
|
InversionCandidate** inversion = inversions->begin();
|
||||||
for (i = 0; i < inversions->getCount(); i++) {
|
for (i = 0; i < inversions->getCount(); i++)
|
||||||
|
{
|
||||||
inversion[i]->used = false;
|
inversion[i]->used = false;
|
||||||
if (inversion[i]->scratch) {
|
if (inversion[i]->scratch)
|
||||||
|
{
|
||||||
if (inversion[i]->scratch->idx->idx_runtime_flags & idx_plan_dont_use) {
|
if (inversion[i]->scratch->idx->idx_runtime_flags & idx_plan_dont_use) {
|
||||||
inversion[i]->used = true;
|
inversion[i]->used = true;
|
||||||
}
|
}
|
||||||
@ -2005,7 +2041,8 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
invCandidate->matchedSegments = currentInv->matchedSegments;
|
invCandidate->matchedSegments = currentInv->matchedSegments;
|
||||||
invCandidate->dependencies = currentInv->dependencies;
|
invCandidate->dependencies = currentInv->dependencies;
|
||||||
matches.clear();
|
matches.clear();
|
||||||
for (size_t j = 0; j < currentInv->matches.getCount(); j++) {
|
for (size_t j = 0; j < currentInv->matches.getCount(); j++)
|
||||||
|
{
|
||||||
if (!matches.exist(currentInv->matches[j])) {
|
if (!matches.exist(currentInv->matches[j])) {
|
||||||
matches.add(currentInv->matches[j]);
|
matches.add(currentInv->matches[j]);
|
||||||
}
|
}
|
||||||
@ -2020,18 +2057,22 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
|
|
||||||
// Look if a match is already used by previous matches.
|
// Look if a match is already used by previous matches.
|
||||||
bool anyMatchAlreadyUsed = false;
|
bool anyMatchAlreadyUsed = false;
|
||||||
for (size_t k = 0; k < currentInv->matches.getCount(); k++) {
|
for (size_t k = 0; k < currentInv->matches.getCount(); k++)
|
||||||
if (matches.exist(currentInv->matches[k])) {
|
{
|
||||||
|
if (matches.exist(currentInv->matches[k]))
|
||||||
|
{
|
||||||
anyMatchAlreadyUsed = true;
|
anyMatchAlreadyUsed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anyMatchAlreadyUsed && !acceptAll) {
|
if (anyMatchAlreadyUsed && !acceptAll)
|
||||||
|
{
|
||||||
currentInv->used = true;
|
currentInv->used = true;
|
||||||
// If a match on this index was already used by another
|
// If a match on this index was already used by another
|
||||||
// index, add also the other matches from this index.
|
// index, add also the other matches from this index.
|
||||||
for (size_t j = 0; j < currentInv->matches.getCount(); j++) {
|
for (size_t j = 0; j < currentInv->matches.getCount(); j++)
|
||||||
|
{
|
||||||
if (!matches.exist(currentInv->matches[j])) {
|
if (!matches.exist(currentInv->matches[j])) {
|
||||||
matches.add(currentInv->matches[j]);
|
matches.add(currentInv->matches[j]);
|
||||||
}
|
}
|
||||||
@ -2041,13 +2082,15 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bestCandidate) {
|
if (!bestCandidate)
|
||||||
|
{
|
||||||
// The first candidate
|
// The first candidate
|
||||||
bestCandidate = currentInv;
|
bestCandidate = currentInv;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (currentInv->unique && !bestCandidate->unique) {
|
if (currentInv->unique && !bestCandidate->unique)
|
||||||
|
{
|
||||||
// A unique full equal match is better than anything else.
|
// A unique full equal match is better than anything else.
|
||||||
bestCandidate = currentInv;
|
bestCandidate = currentInv;
|
||||||
}
|
}
|
||||||
@ -2074,12 +2117,14 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
|
|
||||||
// Do we have very similar costs?
|
// Do we have very similar costs?
|
||||||
double diffCost = currentCandidateCost;
|
double diffCost = currentCandidateCost;
|
||||||
if (!diffCost && !bestCandidateCost) {
|
if (!diffCost && !bestCandidateCost)
|
||||||
|
{
|
||||||
// Two zero costs should be handled as being the same
|
// Two zero costs should be handled as being the same
|
||||||
// (other comparison criterias should be applied, see below).
|
// (other comparison criterias should be applied, see below).
|
||||||
diffCost = 1;
|
diffCost = 1;
|
||||||
}
|
}
|
||||||
else if (diffCost) {
|
else if (diffCost)
|
||||||
|
{
|
||||||
// Calculate the difference.
|
// Calculate the difference.
|
||||||
diffCost = bestCandidateCost / diffCost;
|
diffCost = bestCandidateCost / diffCost;
|
||||||
}
|
}
|
||||||
@ -2092,12 +2137,14 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
// If the "same" costs then compare with the nr of unmatched segments,
|
// If the "same" costs then compare with the nr of unmatched segments,
|
||||||
// how many indexes and matched segments. First compare number of indexes.
|
// how many indexes and matched segments. First compare number of indexes.
|
||||||
int compareSelectivity = (currentInv->indexes - bestCandidate->indexes);
|
int compareSelectivity = (currentInv->indexes - bestCandidate->indexes);
|
||||||
if (compareSelectivity == 0) {
|
if (compareSelectivity == 0)
|
||||||
|
{
|
||||||
// For the same number of indexes compare number of matched segments.
|
// For the same number of indexes compare number of matched segments.
|
||||||
// Note the inverted condition: the more matched segments the better.
|
// Note the inverted condition: the more matched segments the better.
|
||||||
compareSelectivity =
|
compareSelectivity =
|
||||||
(bestCandidate->matchedSegments - currentInv->matchedSegments);
|
(bestCandidate->matchedSegments - currentInv->matchedSegments);
|
||||||
if (compareSelectivity == 0) {
|
if (compareSelectivity == 0)
|
||||||
|
{
|
||||||
// For the same number of matched segments
|
// For the same number of matched segments
|
||||||
// compare ones that aren't full matched
|
// compare ones that aren't full matched
|
||||||
compareSelectivity =
|
compareSelectivity =
|
||||||
@ -2108,7 +2155,8 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
bestCandidate = currentInv;
|
bestCandidate = currentInv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (currentCandidateCost < bestCandidateCost) {
|
else if (currentCandidateCost < bestCandidateCost)
|
||||||
|
{
|
||||||
// How lower the cost the better.
|
// How lower the cost the better.
|
||||||
bestCandidate = currentInv;
|
bestCandidate = currentInv;
|
||||||
}
|
}
|
||||||
@ -2146,7 +2194,8 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
double newTotalSelectivity = 0;
|
double newTotalSelectivity = 0;
|
||||||
double bestSel = bestCandidate->selectivity;
|
double bestSel = bestCandidate->selectivity;
|
||||||
double worstSel = totalSelectivity;
|
double worstSel = totalSelectivity;
|
||||||
if (bestCandidate->selectivity > totalSelectivity) {
|
if (bestCandidate->selectivity > totalSelectivity)
|
||||||
|
{
|
||||||
worstSel = bestCandidate->selectivity;
|
worstSel = bestCandidate->selectivity;
|
||||||
bestSel = totalSelectivity;
|
bestSel = totalSelectivity;
|
||||||
}
|
}
|
||||||
@ -2197,12 +2246,14 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
invCandidate->nonFullMatchedSegments = 0;
|
invCandidate->nonFullMatchedSegments = 0;
|
||||||
invCandidate->matchedSegments = bestCandidate->matchedSegments;
|
invCandidate->matchedSegments = bestCandidate->matchedSegments;
|
||||||
invCandidate->dependencies = bestCandidate->dependencies;
|
invCandidate->dependencies = bestCandidate->dependencies;
|
||||||
for (size_t j = 0; j < bestCandidate->matches.getCount(); j++) {
|
for (size_t j = 0; j < bestCandidate->matches.getCount(); j++)
|
||||||
|
{
|
||||||
if (!matches.exist(bestCandidate->matches[j])) {
|
if (!matches.exist(bestCandidate->matches[j])) {
|
||||||
matches.add(bestCandidate->matches[j]);
|
matches.add(bestCandidate->matches[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bestCandidate->boolean) {
|
if (bestCandidate->boolean)
|
||||||
|
{
|
||||||
if (!matches.exist(bestCandidate->boolean)) {
|
if (!matches.exist(bestCandidate->boolean)) {
|
||||||
matches.add(bestCandidate->boolean);
|
matches.add(bestCandidate->boolean);
|
||||||
}
|
}
|
||||||
@ -2210,11 +2261,13 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!bestCandidate->inversion && bestCandidate->scratch) {
|
if (!bestCandidate->inversion && bestCandidate->scratch)
|
||||||
|
{
|
||||||
invCandidate->inversion = composeInversion(invCandidate->inversion,
|
invCandidate->inversion = composeInversion(invCandidate->inversion,
|
||||||
makeIndexScanNode(bestCandidate->scratch), nod_bit_and);
|
makeIndexScanNode(bestCandidate->scratch), nod_bit_and);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
invCandidate->inversion = composeInversion(invCandidate->inversion,
|
invCandidate->inversion = composeInversion(invCandidate->inversion,
|
||||||
bestCandidate->inversion, nod_bit_and);
|
bestCandidate->inversion, nod_bit_and);
|
||||||
}
|
}
|
||||||
@ -2226,24 +2279,28 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
|
|||||||
invCandidate->matchedSegments =
|
invCandidate->matchedSegments =
|
||||||
MAX(bestCandidate->matchedSegments, invCandidate->matchedSegments);
|
MAX(bestCandidate->matchedSegments, invCandidate->matchedSegments);
|
||||||
invCandidate->dependencies += bestCandidate->dependencies;
|
invCandidate->dependencies += bestCandidate->dependencies;
|
||||||
for (size_t j = 0; j < bestCandidate->matches.getCount(); j++) {
|
for (size_t j = 0; j < bestCandidate->matches.getCount(); j++)
|
||||||
|
{
|
||||||
if (!matches.exist(bestCandidate->matches[j])) {
|
if (!matches.exist(bestCandidate->matches[j])) {
|
||||||
matches.add(bestCandidate->matches[j]);
|
matches.add(bestCandidate->matches[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bestCandidate->boolean) {
|
if (bestCandidate->boolean)
|
||||||
|
{
|
||||||
if (!matches.exist(bestCandidate->boolean)) {
|
if (!matches.exist(bestCandidate->boolean)) {
|
||||||
matches.add(bestCandidate->boolean);
|
matches.add(bestCandidate->boolean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (invCandidate->unique) {
|
if (invCandidate->unique)
|
||||||
|
{
|
||||||
// Single unique full equal match is enough
|
// Single unique full equal match is enough
|
||||||
if (!acceptAll)
|
if (!acceptAll)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
// We're done
|
// We're done
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2400,7 +2457,8 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, jrd_nod* boole
|
|||||||
segment[i]->matches.add(boolean);
|
segment[i]->matches.add(boolean);
|
||||||
// AB: If we have already an exact match don't
|
// AB: If we have already an exact match don't
|
||||||
// override it with worser matches.
|
// override it with worser matches.
|
||||||
if (!(segment[i]->scanType == segmentScanEqual)) {
|
if (!(segment[i]->scanType == segmentScanEqual))
|
||||||
|
{
|
||||||
segment[i]->lowerValue = segment[i]->upperValue = value;
|
segment[i]->lowerValue = segment[i]->upperValue = value;
|
||||||
segment[i]->scanType = segmentScanEquivalent;
|
segment[i]->scanType = segmentScanEquivalent;
|
||||||
segment[i]->excludeLower = false;
|
segment[i]->excludeLower = false;
|
||||||
@ -2519,7 +2577,8 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, jrd_nod* boole
|
|||||||
|
|
||||||
++count;
|
++count;
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0)
|
||||||
|
{
|
||||||
// If this is the first segment, then this index is a candidate.
|
// If this is the first segment, then this index is a candidate.
|
||||||
indexScratch->candidate = true;
|
indexScratch->candidate = true;
|
||||||
}
|
}
|
||||||
@ -2559,7 +2618,8 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
|
|||||||
|
|
||||||
// Copy information from caller
|
// Copy information from caller
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (; i < inputIndexScratches->getCount(); i++) {
|
for (; i < inputIndexScratches->getCount(); i++)
|
||||||
|
{
|
||||||
IndexScratch& scratch = (*inputIndexScratches)[i];
|
IndexScratch& scratch = (*inputIndexScratches)[i];
|
||||||
indexOrScratches.add(scratch);
|
indexOrScratches.add(scratch);
|
||||||
}
|
}
|
||||||
@ -2586,7 +2646,8 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
|
|||||||
indexOrScratches.clear();
|
indexOrScratches.clear();
|
||||||
// Copy information from caller
|
// Copy information from caller
|
||||||
i = 0;
|
i = 0;
|
||||||
for (; i < inputIndexScratches->getCount(); i++) {
|
for (; i < inputIndexScratches->getCount(); i++)
|
||||||
|
{
|
||||||
IndexScratch& scratch = (*inputIndexScratches)[i];
|
IndexScratch& scratch = (*inputIndexScratches)[i];
|
||||||
indexOrScratches.add(scratch);
|
indexOrScratches.add(scratch);
|
||||||
}
|
}
|
||||||
@ -2658,7 +2719,8 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Walk through indexes
|
// Walk through indexes
|
||||||
for (size_t i = 0; i < inputIndexScratches->getCount(); i++) {
|
for (size_t i = 0; i < inputIndexScratches->getCount(); i++)
|
||||||
|
{
|
||||||
IndexScratch& indexScratch = (*inputIndexScratches)[i];
|
IndexScratch& indexScratch = (*inputIndexScratches)[i];
|
||||||
// Try to match the boolean against a index.
|
// Try to match the boolean against a index.
|
||||||
if (!(indexScratch.idx->idx_runtime_flags & idx_plan_dont_use) ||
|
if (!(indexScratch.idx->idx_runtime_flags & idx_plan_dont_use) ||
|
||||||
@ -2695,7 +2757,8 @@ void OptimizerRetrieval::printCandidate(const InversionCandidate* candidate) con
|
|||||||
if (depFromCount >= 1)
|
if (depFromCount >= 1)
|
||||||
{
|
{
|
||||||
fprintf(opt_debug_file, ", dependent from ");
|
fprintf(opt_debug_file, ", dependent from ");
|
||||||
for (int i = 0; i < depFromCount; i++) {
|
for (int i = 0; i < depFromCount; i++)
|
||||||
|
{
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
fprintf(opt_debug_file, "%d", candidate->dependentFromStreams[i]);
|
fprintf(opt_debug_file, "%d", candidate->dependentFromStreams[i]);
|
||||||
}
|
}
|
||||||
@ -2724,7 +2787,8 @@ void OptimizerRetrieval::printCandidates(const InversionCandidateList* inversion
|
|||||||
fprintf(opt_debug_file, " retrieval candidates:\n");
|
fprintf(opt_debug_file, " retrieval candidates:\n");
|
||||||
fclose(opt_debug_file);
|
fclose(opt_debug_file);
|
||||||
const InversionCandidate* const* inversion = inversions->begin();
|
const InversionCandidate* const* inversion = inversions->begin();
|
||||||
for (int i = 0; i < inversions->getCount(); i++) {
|
for (int i = 0; i < inversions->getCount(); i++)
|
||||||
|
{
|
||||||
const InversionCandidate* candidate = inversion[i];
|
const InversionCandidate* candidate = inversion[i];
|
||||||
printCandidate(candidate);
|
printCandidate(candidate);
|
||||||
}
|
}
|
||||||
@ -2742,7 +2806,8 @@ void OptimizerRetrieval::printFinalCandidate(const InversionCandidate* candidate
|
|||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|
||||||
if (candidate) {
|
if (candidate)
|
||||||
|
{
|
||||||
FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
|
FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
|
||||||
fprintf(opt_debug_file, " final candidate: ");
|
fprintf(opt_debug_file, " final candidate: ");
|
||||||
fclose(opt_debug_file);
|
fclose(opt_debug_file);
|
||||||
@ -2814,7 +2879,8 @@ bool OptimizerRetrieval::validateStarts(IndexScratch* indexScratch,
|
|||||||
|
|
||||||
// Every string starts with an empty string so
|
// Every string starts with an empty string so
|
||||||
// don't bother using an index in that case.
|
// don't bother using an index in that case.
|
||||||
if (value->nod_type == nod_literal) {
|
if (value->nod_type == nod_literal)
|
||||||
|
{
|
||||||
const dsc* literal_desc = &((Literal*) value)->lit_desc;
|
const dsc* literal_desc = &((Literal*) value)->lit_desc;
|
||||||
if ((literal_desc->dsc_dtype == dtype_text && literal_desc->dsc_length == 0) ||
|
if ((literal_desc->dsc_dtype == dtype_text && literal_desc->dsc_length == 0) ||
|
||||||
(literal_desc->dsc_dtype == dtype_varying &&
|
(literal_desc->dsc_dtype == dtype_varying &&
|
||||||
@ -2895,8 +2961,7 @@ bool InnerJoinStreamInfo::independent() const
|
|||||||
* streams.
|
* streams.
|
||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
return (indexedRelationships.getCount() == 0) &&
|
return (indexedRelationships.getCount() == 0) && (previousExpectedStreams == 0);
|
||||||
(previousExpectedStreams == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2926,7 +2991,8 @@ OptimizerInnerJoin::OptimizerInnerJoin(MemoryPool& p, OptimizerBlk* opt, const U
|
|||||||
|
|
||||||
innerStreams.grow(streams[0]);
|
innerStreams.grow(streams[0]);
|
||||||
InnerJoinStreamInfo** innerStream = innerStreams.begin();
|
InnerJoinStreamInfo** innerStream = innerStreams.begin();
|
||||||
for (size_t i = 0; i < innerStreams.getCount(); i++) {
|
for (size_t i = 0; i < innerStreams.getCount(); i++)
|
||||||
|
{
|
||||||
innerStream[i] = FB_NEW(p) InnerJoinStreamInfo(p);
|
innerStream[i] = FB_NEW(p) InnerJoinStreamInfo(p);
|
||||||
innerStream[i]->stream = streams[i + 1];
|
innerStream[i]->stream = streams[i + 1];
|
||||||
}
|
}
|
||||||
@ -2947,7 +3013,8 @@ OptimizerInnerJoin::~OptimizerInnerJoin()
|
|||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|
||||||
for (size_t i = 0; i < innerStreams.getCount(); i++) {
|
for (size_t i = 0; i < innerStreams.getCount(); i++)
|
||||||
|
{
|
||||||
for (size_t j = 0; j < innerStreams[i]->indexedRelationships.getCount(); j++) {
|
for (size_t j = 0; j < innerStreams[i]->indexedRelationships.getCount(); j++) {
|
||||||
delete innerStreams[i]->indexedRelationships[j];
|
delete innerStreams[i]->indexedRelationships[j];
|
||||||
}
|
}
|
||||||
@ -2969,10 +3036,12 @@ void OptimizerInnerJoin::calculateCardinalities()
|
|||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|
||||||
for (size_t i = 0; i < innerStreams.getCount(); i++) {
|
for (size_t i = 0; i < innerStreams.getCount(); i++)
|
||||||
|
{
|
||||||
CompilerScratch::csb_repeat* csb_tail = &csb->csb_rpt[innerStreams[i]->stream];
|
CompilerScratch::csb_repeat* csb_tail = &csb->csb_rpt[innerStreams[i]->stream];
|
||||||
fb_assert(csb_tail);
|
fb_assert(csb_tail);
|
||||||
if (!csb_tail->csb_cardinality) {
|
if (!csb_tail->csb_cardinality)
|
||||||
|
{
|
||||||
jrd_rel* relation = csb_tail->csb_relation;
|
jrd_rel* relation = csb_tail->csb_relation;
|
||||||
fb_assert(relation);
|
fb_assert(relation);
|
||||||
const Format* format = CMP_format(tdbb, csb, (USHORT)innerStreams[i]->stream);
|
const Format* format = CMP_format(tdbb, csb, (USHORT)innerStreams[i]->stream);
|
||||||
@ -3022,7 +3091,8 @@ void OptimizerInnerJoin::calculateStreamInfo()
|
|||||||
|
|
||||||
// Find streams that have a indexed relationship to this
|
// Find streams that have a indexed relationship to this
|
||||||
// stream and add the information.
|
// stream and add the information.
|
||||||
for (size_t j = 0; j < innerStreams.getCount(); j++) {
|
for (size_t j = 0; j < innerStreams.getCount(); j++)
|
||||||
|
{
|
||||||
if (innerStreams[j]->stream != innerStreams[i]->stream) {
|
if (innerStreams[j]->stream != innerStreams[i]->stream) {
|
||||||
getIndexedRelationship(innerStreams[i], innerStreams[j]);
|
getIndexedRelationship(innerStreams[i], innerStreams[j]);
|
||||||
}
|
}
|
||||||
@ -3040,7 +3110,8 @@ void OptimizerInnerJoin::calculateStreamInfo()
|
|||||||
for (i = 0; i < innerStreams.getCount(); i++)
|
for (i = 0; i < innerStreams.getCount(); i++)
|
||||||
{
|
{
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (; index < tempStreams.getCount(); index++) {
|
for (; index < tempStreams.getCount(); index++)
|
||||||
|
{
|
||||||
// First those streams which can't be used by other streams
|
// First those streams which can't be used by other streams
|
||||||
// or can't depend on a stream.
|
// or can't depend on a stream.
|
||||||
if (innerStreams[i]->independent() && !tempStreams[index]->independent()) {
|
if (innerStreams[i]->independent() && !tempStreams[index]->independent()) {
|
||||||
@ -3052,7 +3123,8 @@ void OptimizerInnerJoin::calculateStreamInfo()
|
|||||||
if (compare < 0) {
|
if (compare < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (compare == 0) {
|
if (compare == 0)
|
||||||
|
{
|
||||||
// Next those with the cheapest base cost
|
// Next those with the cheapest base cost
|
||||||
if (innerStreams[i]->baseCost < tempStreams[index]->baseCost) {
|
if (innerStreams[i]->baseCost < tempStreams[index]->baseCost) {
|
||||||
break;
|
break;
|
||||||
@ -3089,7 +3161,8 @@ bool OptimizerInnerJoin::cheaperRelationship(IndexRelationship* checkRelationshi
|
|||||||
}
|
}
|
||||||
|
|
||||||
const double compareValue = checkRelationship->cost / withRelationship->cost;
|
const double compareValue = checkRelationship->cost / withRelationship->cost;
|
||||||
if (compareValue >= 0.98 && compareValue <= 1.02) {
|
if (compareValue >= 0.98 && compareValue <= 1.02)
|
||||||
|
{
|
||||||
// cost is nearly the same, now check on cardinality
|
// cost is nearly the same, now check on cardinality
|
||||||
if (checkRelationship->cardinality < withRelationship->cardinality) {
|
if (checkRelationship->cardinality < withRelationship->cardinality) {
|
||||||
return true;
|
return true;
|
||||||
@ -3176,9 +3249,11 @@ int OptimizerInnerJoin::findJoinOrder()
|
|||||||
remainingStreams = 0;
|
remainingStreams = 0;
|
||||||
for (i = 0; i < innerStreams.getCount(); i++)
|
for (i = 0; i < innerStreams.getCount(); i++)
|
||||||
{
|
{
|
||||||
if (!innerStreams[i]->used) {
|
if (!innerStreams[i]->used)
|
||||||
|
{
|
||||||
remainingStreams++;
|
remainingStreams++;
|
||||||
if (innerStreams[i]->independent()) {
|
if (innerStreams[i]->independent())
|
||||||
|
{
|
||||||
if (!optimizer->opt_best_count || innerStreams[i]->baseCost < optimizer->opt_best_cost)
|
if (!optimizer->opt_best_count || innerStreams[i]->baseCost < optimizer->opt_best_cost)
|
||||||
{
|
{
|
||||||
optimizer->opt_streams[0].opt_best_stream = innerStreams[i]->stream;
|
optimizer->opt_streams[0].opt_best_stream = innerStreams[i]->stream;
|
||||||
@ -3192,12 +3267,15 @@ int OptimizerInnerJoin::findJoinOrder()
|
|||||||
if (optimizer->opt_best_count == 0)
|
if (optimizer->opt_best_count == 0)
|
||||||
{
|
{
|
||||||
IndexedRelationships indexedRelationships(pool);
|
IndexedRelationships indexedRelationships(pool);
|
||||||
for (i = 0; i < innerStreams.getCount(); i++) {
|
for (i = 0; i < innerStreams.getCount(); i++)
|
||||||
if (!innerStreams[i]->used) {
|
{
|
||||||
|
if (!innerStreams[i]->used)
|
||||||
|
{
|
||||||
indexedRelationships.clear();
|
indexedRelationships.clear();
|
||||||
findBestOrder(0, innerStreams[i], &indexedRelationships, (double) 0, (double) 1);
|
findBestOrder(0, innerStreams[i], &indexedRelationships, (double) 0, (double) 1);
|
||||||
|
|
||||||
if (plan) {
|
if (plan)
|
||||||
|
{
|
||||||
// If a explicit PLAN was specified we should be ready;
|
// If a explicit PLAN was specified we should be ready;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3210,7 +3288,8 @@ int OptimizerInnerJoin::findJoinOrder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark streams as used
|
// Mark streams as used
|
||||||
for (int stream = 0; stream < optimizer->opt_best_count; stream++) {
|
for (int stream = 0; stream < optimizer->opt_best_count; stream++)
|
||||||
|
{
|
||||||
InnerJoinStreamInfo* streamInfo = getStreamInfo(optimizer->opt_streams[stream].opt_best_stream);
|
InnerJoinStreamInfo* streamInfo = getStreamInfo(optimizer->opt_streams[stream].opt_best_stream);
|
||||||
streamInfo->used = true;
|
streamInfo->used = true;
|
||||||
}
|
}
|
||||||
@ -3260,7 +3339,8 @@ void OptimizerInnerJoin::findBestOrder(int position, InnerJoinStreamInfo* stream
|
|||||||
// Compute delta and total estimate cost to fetch this stream.
|
// Compute delta and total estimate cost to fetch this stream.
|
||||||
double position_cost, position_cardinality, new_cost = 0, new_cardinality = 0;
|
double position_cost, position_cardinality, new_cost = 0, new_cardinality = 0;
|
||||||
|
|
||||||
if (!plan) {
|
if (!plan)
|
||||||
|
{
|
||||||
estimateCost(stream->stream, &position_cost, &position_cardinality);
|
estimateCost(stream->stream, &position_cost, &position_cardinality);
|
||||||
new_cost = cost + cardinality * position_cost;
|
new_cost = cost + cardinality * position_cost;
|
||||||
new_cardinality = position_cardinality * cardinality;
|
new_cardinality = position_cardinality * cardinality;
|
||||||
@ -3312,11 +3392,14 @@ void OptimizerInnerJoin::findBestOrder(int position, InnerJoinStreamInfo* stream
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
IndexRelationship** processRelationship = processList->begin();
|
IndexRelationship** processRelationship = processList->begin();
|
||||||
size_t index;
|
size_t index;
|
||||||
for (index = 0; index < processList->getCount(); index++) {
|
for (index = 0; index < processList->getCount(); index++)
|
||||||
if (relationStreamInfo->stream == processRelationship[index]->stream) {
|
{
|
||||||
|
if (relationStreamInfo->stream == processRelationship[index]->stream)
|
||||||
|
{
|
||||||
// If the cost of this relationship is cheaper then remove the
|
// If the cost of this relationship is cheaper then remove the
|
||||||
// old relationship and add this one.
|
// old relationship and add this one.
|
||||||
if (cheaperRelationship(relationship, processRelationship[index])) {
|
if (cheaperRelationship(relationship, processRelationship[index]))
|
||||||
|
{
|
||||||
processList->remove(index);
|
processList->remove(index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3325,10 +3408,12 @@ void OptimizerInnerJoin::findBestOrder(int position, InnerJoinStreamInfo* stream
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found)
|
||||||
|
{
|
||||||
// Add relationship sorted on cost (cheapest as first)
|
// Add relationship sorted on cost (cheapest as first)
|
||||||
IndexRelationship** relationships = processList->begin();
|
IndexRelationship** relationships = processList->begin();
|
||||||
for (index = 0; index < processList->getCount(); index++) {
|
for (index = 0; index < processList->getCount(); index++)
|
||||||
|
{
|
||||||
if (cheaperRelationship(relationship, relationships[index])) {
|
if (cheaperRelationship(relationship, relationships[index])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3339,22 +3424,27 @@ void OptimizerInnerJoin::findBestOrder(int position, InnerJoinStreamInfo* stream
|
|||||||
}
|
}
|
||||||
|
|
||||||
IndexRelationship** nextRelationship = processList->begin();
|
IndexRelationship** nextRelationship = processList->begin();
|
||||||
for (size_t j = 0; j < processList->getCount(); j++) {
|
for (size_t j = 0; j < processList->getCount(); j++)
|
||||||
|
{
|
||||||
InnerJoinStreamInfo* relationStreamInfo = getStreamInfo(nextRelationship[j]->stream);
|
InnerJoinStreamInfo* relationStreamInfo = getStreamInfo(nextRelationship[j]->stream);
|
||||||
if (!relationStreamInfo->used) {
|
if (!relationStreamInfo->used)
|
||||||
|
{
|
||||||
findBestOrder(position, relationStreamInfo, processList, new_cost, new_cardinality);
|
findBestOrder(position, relationStreamInfo, processList, new_cost, new_cardinality);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plan) {
|
if (plan)
|
||||||
|
{
|
||||||
// If a explicit PLAN was specific pick the next relation.
|
// If a explicit PLAN was specific pick the next relation.
|
||||||
// The order in innerStreams is expected to be exactly the order as
|
// The order in innerStreams is expected to be exactly the order as
|
||||||
// specified in the explicit PLAN.
|
// specified in the explicit PLAN.
|
||||||
for (size_t j = 0; j < innerStreams.getCount(); j++) {
|
for (size_t j = 0; j < innerStreams.getCount(); j++)
|
||||||
|
{
|
||||||
InnerJoinStreamInfo* nextStream = innerStreams[j];
|
InnerJoinStreamInfo* nextStream = innerStreams[j];
|
||||||
if (!nextStream->used) {
|
if (!nextStream->used)
|
||||||
|
{
|
||||||
findBestOrder(position, nextStream, processList, new_cost, new_cardinality);
|
findBestOrder(position, nextStream, processList, new_cost, new_cardinality);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3408,7 +3498,8 @@ void OptimizerInnerJoin::getIndexedRelationship(InnerJoinStreamInfo* baseStream,
|
|||||||
// indexRelationship are kept sorted on cost and unique in the indexRelations array.
|
// indexRelationship are kept sorted on cost and unique in the indexRelations array.
|
||||||
// The unique and cheapest indexed relatioships are on the first position.
|
// The unique and cheapest indexed relatioships are on the first position.
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (; index < baseStream->indexedRelationships.getCount(); index++) {
|
for (; index < baseStream->indexedRelationships.getCount(); index++)
|
||||||
|
{
|
||||||
if (cheaperRelationship(indexRelationship, baseStream->indexedRelationships[index])) {
|
if (cheaperRelationship(indexRelationship, baseStream->indexedRelationships[index])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3435,7 +3526,8 @@ InnerJoinStreamInfo* OptimizerInnerJoin::getStreamInfo(int stream)
|
|||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|
||||||
for (size_t i = 0; i < innerStreams.getCount(); i++) {
|
for (size_t i = 0; i < innerStreams.getCount(); i++)
|
||||||
|
{
|
||||||
if (innerStreams[i]->stream == stream) {
|
if (innerStreams[i]->stream == stream) {
|
||||||
return innerStreams[i];
|
return innerStreams[i];
|
||||||
}
|
}
|
||||||
@ -3461,7 +3553,8 @@ void OptimizerInnerJoin::printBestOrder() const
|
|||||||
|
|
||||||
FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
|
FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
|
||||||
fprintf(opt_debug_file, " best order, streams: ");
|
fprintf(opt_debug_file, " best order, streams: ");
|
||||||
for (int i = 0; i < optimizer->opt_best_count; i++) {
|
for (int i = 0; i < optimizer->opt_best_count; i++)
|
||||||
|
{
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
fprintf(opt_debug_file, "%d", optimizer->opt_streams[i].opt_best_stream);
|
fprintf(opt_debug_file, "%d", optimizer->opt_streams[i].opt_best_stream);
|
||||||
}
|
}
|
||||||
@ -3494,7 +3587,8 @@ void OptimizerInnerJoin::printFoundOrder(int position, double positionCost,
|
|||||||
fprintf(opt_debug_file, ", streams: ", position);
|
fprintf(opt_debug_file, ", streams: ", position);
|
||||||
const OptimizerBlk::opt_stream* tail = optimizer->opt_streams.begin();
|
const OptimizerBlk::opt_stream* tail = optimizer->opt_streams.begin();
|
||||||
const OptimizerBlk::opt_stream* const order_end = tail + position;
|
const OptimizerBlk::opt_stream* const order_end = tail + position;
|
||||||
for (; tail < order_end; tail++) {
|
for (; tail < order_end; tail++)
|
||||||
|
{
|
||||||
if (tail == optimizer->opt_streams.begin()) {
|
if (tail == optimizer->opt_streams.begin()) {
|
||||||
fprintf(opt_debug_file, "%d", tail->opt_stream_number);
|
fprintf(opt_debug_file, "%d", tail->opt_stream_number);
|
||||||
}
|
}
|
||||||
@ -3544,7 +3638,8 @@ void OptimizerInnerJoin::printStartOrder() const
|
|||||||
FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
|
FILE *opt_debug_file = fopen(OPTIMIZER_DEBUG_FILE, "a");
|
||||||
fprintf(opt_debug_file, "Start join order: with stream(baseCost)");
|
fprintf(opt_debug_file, "Start join order: with stream(baseCost)");
|
||||||
bool firstStream = true;
|
bool firstStream = true;
|
||||||
for (int i = 0; i < innerStreams.getCount(); i++) {
|
for (int i = 0; i < innerStreams.getCount(); i++)
|
||||||
|
{
|
||||||
if (!innerStreams[i]->used) {
|
if (!innerStreams[i]->used) {
|
||||||
fprintf(opt_debug_file, ", %d (%1.2f)", innerStreams[i]->stream, innerStreams[i]->baseCost);
|
fprintf(opt_debug_file, ", %d (%1.2f)", innerStreams[i]->stream, innerStreams[i]->baseCost);
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,7 @@ void IDX_check_access(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view, jrd_
|
|||||||
WIN referenced_window(relPages->rel_pg_space_id, -1);
|
WIN referenced_window(relPages->rel_pg_space_id, -1);
|
||||||
|
|
||||||
while (BTR_next_index(tdbb, relation, 0, &idx, &window))
|
while (BTR_next_index(tdbb, relation, 0, &idx, &window))
|
||||||
|
{
|
||||||
if (idx.idx_flags & idx_foreign)
|
if (idx.idx_flags & idx_foreign)
|
||||||
{
|
{
|
||||||
/* find the corresponding primary key index */
|
/* find the corresponding primary key index */
|
||||||
@ -160,6 +161,7 @@ void IDX_check_access(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view, jrd_
|
|||||||
|
|
||||||
CCH_RELEASE(tdbb, &referenced_window);
|
CCH_RELEASE(tdbb, &referenced_window);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -514,7 +516,8 @@ void IDX_create_index(thread_db* tdbb,
|
|||||||
|
|
||||||
BTR_create(tdbb, relation, idx, key_length, sort_handle, selectivity);
|
BTR_create(tdbb, relation, idx, key_length, sort_handle, selectivity);
|
||||||
|
|
||||||
if (ifl_data.ifl_duplicates > 0) {
|
if (ifl_data.ifl_duplicates > 0)
|
||||||
|
{
|
||||||
// we don't need SORT_fini() here, as it's called inside BTR_create()
|
// we don't need SORT_fini() here, as it's called inside BTR_create()
|
||||||
ERR_post(Arg::Gds(isc_no_dup) << Arg::Str(index_name));
|
ERR_post(Arg::Gds(isc_no_dup) << Arg::Str(index_name));
|
||||||
}
|
}
|
||||||
@ -1118,14 +1121,16 @@ static idx_e check_duplicates(thread_db* tdbb,
|
|||||||
|
|
||||||
if (is_fk)
|
if (is_fk)
|
||||||
{
|
{
|
||||||
if (equal_cur && equal_old) {
|
if (equal_cur && equal_old)
|
||||||
|
{
|
||||||
result = idx_e_duplicate;
|
result = idx_e_duplicate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (equal_cur || equal_old) {
|
if (equal_cur || equal_old)
|
||||||
|
{
|
||||||
result = idx_e_duplicate;
|
result = idx_e_duplicate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1729,7 +1734,8 @@ static void signal_index_deletion(thread_db* tdbb, jrd_rel* relation, USHORT id)
|
|||||||
|
|
||||||
/* if one didn't exist, create it */
|
/* if one didn't exist, create it */
|
||||||
|
|
||||||
if (!index_block) {
|
if (!index_block)
|
||||||
|
{
|
||||||
index_block = IDX_create_index_block(tdbb, relation, id);
|
index_block = IDX_create_index_block(tdbb, relation, id);
|
||||||
lock = index_block->idb_lock;
|
lock = index_block->idb_lock;
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,8 @@ CharSetContainer* CharSetContainer::lookupCharset(thread_db* tdbb, USHORT ttype)
|
|||||||
cs = dbb->dbb_charsets[id];
|
cs = dbb->dbb_charsets[id];
|
||||||
|
|
||||||
// allocate a new character set object if we couldn't find one.
|
// allocate a new character set object if we couldn't find one.
|
||||||
if (!cs) {
|
if (!cs)
|
||||||
|
{
|
||||||
SubtypeInfo info;
|
SubtypeInfo info;
|
||||||
|
|
||||||
if (id == CS_UTF16)
|
if (id == CS_UTF16)
|
||||||
@ -536,11 +537,14 @@ int INTL_compare(thread_db* tdbb,
|
|||||||
USHORT compare_type = MAX(t1, t2); /* YYY */
|
USHORT compare_type = MAX(t1, t2); /* YYY */
|
||||||
UCHAR buffer[MAX_KEY];
|
UCHAR buffer[MAX_KEY];
|
||||||
|
|
||||||
if (t1 != t2) {
|
if (t1 != t2)
|
||||||
|
{
|
||||||
CHARSET_ID cs1 = INTL_charset(tdbb, t1);
|
CHARSET_ID cs1 = INTL_charset(tdbb, t1);
|
||||||
CHARSET_ID cs2 = INTL_charset(tdbb, t2);
|
CHARSET_ID cs2 = INTL_charset(tdbb, t2);
|
||||||
if (cs1 != cs2) {
|
if (cs1 != cs2)
|
||||||
if (compare_type != t2) {
|
{
|
||||||
|
if (compare_type != t2)
|
||||||
|
{
|
||||||
/* convert pText2 to pText1's type, if possible */
|
/* convert pText2 to pText1's type, if possible */
|
||||||
/* YYY - should failure to convert really return
|
/* YYY - should failure to convert really return
|
||||||
an error here?
|
an error here?
|
||||||
@ -554,7 +558,8 @@ int INTL_compare(thread_db* tdbb,
|
|||||||
length2 = INTL_convert_bytes(tdbb, cs1, buffer, sizeof(buffer), cs2, p2, length2, err);
|
length2 = INTL_convert_bytes(tdbb, cs1, buffer, sizeof(buffer), cs2, p2, length2, err);
|
||||||
p2 = buffer;
|
p2 = buffer;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/* convert pText1 to pText2's type, if possible */
|
/* convert pText1 to pText2's type, if possible */
|
||||||
|
|
||||||
length1 = INTL_convert_bytes(tdbb, cs2, buffer, sizeof(buffer), cs1, p1, length1, err);
|
length1 = INTL_convert_bytes(tdbb, cs2, buffer, sizeof(buffer), cs1, p1, length1, err);
|
||||||
@ -744,7 +749,8 @@ int INTL_convert_string(dsc* to, const dsc* from, ErrorFunction err)
|
|||||||
from_fill = 0; /* Convert_bytes handles source truncation */
|
from_fill = 0; /* Convert_bytes handles source truncation */
|
||||||
p += to_len;
|
p += to_len;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/* binary string can always be converted TO by byte-copy */
|
/* binary string can always be converted TO by byte-copy */
|
||||||
|
|
||||||
ULONG to_len = MIN(from_len, to_size);
|
ULONG to_len = MIN(from_len, to_size);
|
||||||
@ -775,7 +781,8 @@ int INTL_convert_string(dsc* to, const dsc* from, ErrorFunction err)
|
|||||||
to->dsc_address[to_len] = 0;
|
to->dsc_address[to_len] = 0;
|
||||||
from_fill = 0; /* Convert_bytes handles source truncation */
|
from_fill = 0; /* Convert_bytes handles source truncation */
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/* binary string can always be converted TO by byte-copy */
|
/* binary string can always be converted TO by byte-copy */
|
||||||
|
|
||||||
ULONG to_len = MIN(from_len, to_size);
|
ULONG to_len = MIN(from_len, to_size);
|
||||||
@ -805,7 +812,8 @@ int INTL_convert_string(dsc* to, const dsc* from, ErrorFunction err)
|
|||||||
((vary*) to->dsc_address)->vary_length = to_len;
|
((vary*) to->dsc_address)->vary_length = to_len;
|
||||||
from_fill = 0; /* Convert_bytes handles source truncation */
|
from_fill = 0; /* Convert_bytes handles source truncation */
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
/* binary string can always be converted TO by byte-copy */
|
/* binary string can always be converted TO by byte-copy */
|
||||||
ULONG to_len = MIN(from_len, to_size);
|
ULONG to_len = MIN(from_len, to_size);
|
||||||
if (!toCharSet->wellFormed(to_len, q))
|
if (!toCharSet->wellFormed(to_len, q))
|
||||||
@ -945,7 +953,8 @@ USHORT INTL_key_length(thread_db* tdbb, USHORT idxType, USHORT iLength)
|
|||||||
USHORT key_length;
|
USHORT key_length;
|
||||||
if (ttype <= ttype_last_internal)
|
if (ttype <= ttype_last_internal)
|
||||||
key_length = iLength;
|
key_length = iLength;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
TextType* obj = INTL_texttype_lookup(tdbb, ttype);
|
TextType* obj = INTL_texttype_lookup(tdbb, ttype);
|
||||||
key_length = obj->key_length(iLength);
|
key_length = obj->key_length(iLength);
|
||||||
}
|
}
|
||||||
@ -1216,22 +1225,27 @@ static bool all_spaces(thread_db* tdbb,
|
|||||||
|
|
||||||
// Single-octet character sets are optimized here
|
// Single-octet character sets are optimized here
|
||||||
|
|
||||||
if (obj->getSpaceLength() == 1) {
|
if (obj->getSpaceLength() == 1)
|
||||||
|
{
|
||||||
const BYTE* p = &ptr[offset];
|
const BYTE* p = &ptr[offset];
|
||||||
const BYTE* const end = &ptr[len];
|
const BYTE* const end = &ptr[len];
|
||||||
while (p < end) {
|
while (p < end)
|
||||||
|
{
|
||||||
if (*p++ != *obj->getSpace())
|
if (*p++ != *obj->getSpace())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
const BYTE* p = &ptr[offset];
|
const BYTE* p = &ptr[offset];
|
||||||
const BYTE* const end = &ptr[len];
|
const BYTE* const end = &ptr[len];
|
||||||
const unsigned char* space = obj->getSpace();
|
const unsigned char* space = obj->getSpace();
|
||||||
const unsigned char* const end_space = &space[obj->getSpaceLength()];
|
const unsigned char* const end_space = &space[obj->getSpaceLength()];
|
||||||
while (p < end) {
|
while (p < end)
|
||||||
|
{
|
||||||
space = obj->getSpace();
|
space = obj->getSpace();
|
||||||
while (p < end && space < end_space) {
|
while (p < end && space < end_space)
|
||||||
|
{
|
||||||
if (*p++ != *space++)
|
if (*p++ != *space++)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1303,16 +1317,19 @@ static void pad_spaces(thread_db* tdbb, CHARSET_ID charset, BYTE* ptr, ULONG len
|
|||||||
CharSet* obj = INTL_charset_lookup(tdbb, charset);
|
CharSet* obj = INTL_charset_lookup(tdbb, charset);
|
||||||
|
|
||||||
/* Single-octet character sets are optimized here */
|
/* Single-octet character sets are optimized here */
|
||||||
if (obj->getSpaceLength() == 1) {
|
if (obj->getSpaceLength() == 1)
|
||||||
|
{
|
||||||
const BYTE* const end = &ptr[len];
|
const BYTE* const end = &ptr[len];
|
||||||
while (ptr < end)
|
while (ptr < end)
|
||||||
*ptr++ = *obj->getSpace();
|
*ptr++ = *obj->getSpace();
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
const BYTE* const end = &ptr[len];
|
const BYTE* const end = &ptr[len];
|
||||||
const UCHAR* space = obj->getSpace();
|
const UCHAR* space = obj->getSpace();
|
||||||
const UCHAR* const end_space = &space[obj->getSpaceLength()];
|
const UCHAR* const end_space = &space[obj->getSpaceLength()];
|
||||||
while (ptr < end) {
|
while (ptr < end)
|
||||||
|
{
|
||||||
space = obj->getSpace();
|
space = obj->getSpace();
|
||||||
while (ptr < end && space < end_space) {
|
while (ptr < end && space < end_space) {
|
||||||
*ptr++ = *space++;
|
*ptr++ = *space++;
|
||||||
|
@ -119,9 +119,11 @@ static fss_size_t fss_mbtowc(fss_wchar_t* p, const UCHAR* s, fss_size_t n)
|
|||||||
return -1;
|
return -1;
|
||||||
const int c0 = *s & 0xff;
|
const int c0 = *s & 0xff;
|
||||||
SLONG l = c0;
|
SLONG l = c0;
|
||||||
for (const Byte_Mask_Table* t = tab; t->cmask; t++) {
|
for (const Byte_Mask_Table* t = tab; t->cmask; t++)
|
||||||
|
{
|
||||||
nc++;
|
nc++;
|
||||||
if ((c0 & t->cmask) == t->cval) {
|
if ((c0 & t->cmask) == t->cval)
|
||||||
|
{
|
||||||
l &= t->lmask;
|
l &= t->lmask;
|
||||||
if (l < t->lval)
|
if (l < t->lval)
|
||||||
return -1;
|
return -1;
|
||||||
@ -146,12 +148,15 @@ static fss_size_t fss_wctomb(UCHAR * s, fss_wchar_t wc)
|
|||||||
|
|
||||||
SLONG l = wc;
|
SLONG l = wc;
|
||||||
int nc = 0;
|
int nc = 0;
|
||||||
for (const Byte_Mask_Table* t = tab; t->cmask; t++) {
|
for (const Byte_Mask_Table* t = tab; t->cmask; t++)
|
||||||
|
{
|
||||||
nc++;
|
nc++;
|
||||||
if (l <= t->lmask) {
|
if (l <= t->lmask)
|
||||||
|
{
|
||||||
int c = t->shift;
|
int c = t->shift;
|
||||||
*s = t->cval | (l >> c);
|
*s = t->cval | (l >> c);
|
||||||
while (c > 0) {
|
while (c > 0)
|
||||||
|
{
|
||||||
c -= 6;
|
c -= 6;
|
||||||
s++;
|
s++;
|
||||||
*s = 0x80 | ((l >> c) & 0x3F);
|
*s = 0x80 | ((l >> c) & 0x3F);
|
||||||
@ -216,9 +221,11 @@ static ULONG internal_fss_to_unicode(csconvert* obj,
|
|||||||
|
|
||||||
const UNICODE* const start = dest_ptr;
|
const UNICODE* const start = dest_ptr;
|
||||||
const ULONG src_start = src_len;
|
const ULONG src_start = src_len;
|
||||||
while ((src_len) && (dest_len >= sizeof(*dest_ptr))) {
|
while ((src_len) && (dest_len >= sizeof(*dest_ptr)))
|
||||||
|
{
|
||||||
const fss_size_t res = fss_mbtowc(dest_ptr, src_ptr, src_len);
|
const fss_size_t res = fss_mbtowc(dest_ptr, src_ptr, src_len);
|
||||||
if (res == -1) {
|
if (res == -1)
|
||||||
|
{
|
||||||
*err_code = CS_BAD_INPUT;
|
*err_code = CS_BAD_INPUT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -262,15 +269,18 @@ ULONG internal_unicode_to_fss(csconvert* obj,
|
|||||||
const UNICODE* unicode_str = s;
|
const UNICODE* unicode_str = s;
|
||||||
|
|
||||||
const UCHAR* const start = fss_str;
|
const UCHAR* const start = fss_str;
|
||||||
while ((fss_len) && (unicode_len >= sizeof(*unicode_str))) {
|
while ((fss_len) && (unicode_len >= sizeof(*unicode_str)))
|
||||||
|
{
|
||||||
/* Convert the wide character into temp buffer */
|
/* Convert the wide character into temp buffer */
|
||||||
fss_size_t res = fss_wctomb(tmp_buffer, *unicode_str);
|
fss_size_t res = fss_wctomb(tmp_buffer, *unicode_str);
|
||||||
if (res == -1) {
|
if (res == -1)
|
||||||
|
{
|
||||||
*err_code = CS_BAD_INPUT;
|
*err_code = CS_BAD_INPUT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* will the mb sequence fit into space left? */
|
/* will the mb sequence fit into space left? */
|
||||||
if (ULONG(res) > fss_len) {
|
if (ULONG(res) > fss_len)
|
||||||
|
{
|
||||||
*err_code = CS_TRUNCATION_ERROR;
|
*err_code = CS_TRUNCATION_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -569,7 +579,8 @@ static ULONG internal_str_to_upper(texttype* /*obj*/,
|
|||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
const UCHAR* const pStart = dest;
|
const UCHAR* const pStart = dest;
|
||||||
while (inLen-- && outLen--) {
|
while (inLen-- && outLen--)
|
||||||
|
{
|
||||||
*dest++ = UPPER7(*src);
|
*dest++ = UPPER7(*src);
|
||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
@ -593,7 +604,8 @@ static ULONG internal_str_to_lower(texttype* /*obj*/,
|
|||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
const UCHAR* const pStart = dest;
|
const UCHAR* const pStart = dest;
|
||||||
while (inLen-- && outLen--) {
|
while (inLen-- && outLen--)
|
||||||
|
{
|
||||||
*dest++ = LOWWER7(*src);
|
*dest++ = LOWWER7(*src);
|
||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
@ -830,8 +842,10 @@ static ULONG wc_to_nc(csconvert* obj, ULONG nSrc, const UCHAR* ppSrc,
|
|||||||
const UCHAR* const pStart = pDest;
|
const UCHAR* const pStart = pDest;
|
||||||
const USHORT* const pStart_src = pSrc;
|
const USHORT* const pStart_src = pSrc;
|
||||||
|
|
||||||
while (nDest && nSrc >= sizeof(*pSrc)) {
|
while (nDest && nSrc >= sizeof(*pSrc))
|
||||||
if (*pSrc >= 256) {
|
{
|
||||||
|
if (*pSrc >= 256)
|
||||||
|
{
|
||||||
*err_code = CS_CONVERT_ERROR;
|
*err_code = CS_CONVERT_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -877,7 +891,8 @@ static ULONG mb_to_wc(csconvert* obj, ULONG nSrc, const UCHAR* pSrc,
|
|||||||
|
|
||||||
const USHORT* const pStart = pDest;
|
const USHORT* const pStart = pDest;
|
||||||
const UCHAR* const pStart_src = pSrc;
|
const UCHAR* const pStart_src = pSrc;
|
||||||
while (nDest > 1 && nSrc > 1) {
|
while (nDest > 1 && nSrc > 1)
|
||||||
|
{
|
||||||
*pDest++ = *pSrc * 256 + *(pSrc + 1);
|
*pDest++ = *pSrc * 256 + *(pSrc + 1);
|
||||||
pSrc += 2;
|
pSrc += 2;
|
||||||
nDest -= 2;
|
nDest -= 2;
|
||||||
@ -921,7 +936,8 @@ static ULONG wc_to_mb(csconvert* obj, ULONG nSrc, const UCHAR* ppSrc,
|
|||||||
|
|
||||||
const UCHAR* const pStart = pDest;
|
const UCHAR* const pStart = pDest;
|
||||||
const USHORT* const pStart_src = pSrc;
|
const USHORT* const pStart_src = pSrc;
|
||||||
while (nDest > 1 && nSrc > 1) {
|
while (nDest > 1 && nSrc > 1)
|
||||||
|
{
|
||||||
*pDest++ = *pSrc / 256;
|
*pDest++ = *pSrc / 256;
|
||||||
*pDest++ = *pSrc++ % 256;
|
*pDest++ = *pSrc++ % 256;
|
||||||
nDest -= 2;
|
nDest -= 2;
|
||||||
@ -1247,8 +1263,10 @@ static ULONG cvt_none_to_unicode(csconvert* obj, ULONG nSrc, const UCHAR* pSrc,
|
|||||||
|
|
||||||
const USHORT* const pStart = pDest;
|
const USHORT* const pStart = pDest;
|
||||||
const UCHAR* const pStart_src = pSrc;
|
const UCHAR* const pStart_src = pSrc;
|
||||||
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc)) {
|
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc))
|
||||||
if (*pSrc > 127) {
|
{
|
||||||
|
if (*pSrc > 127)
|
||||||
|
{
|
||||||
*err_code = CS_CONVERT_ERROR;
|
*err_code = CS_CONVERT_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1293,7 +1311,8 @@ static ULONG cvt_unicode_to_unicode(csconvert* obj, ULONG nSrc, const UCHAR* ppS
|
|||||||
|
|
||||||
const USHORT* const pStart = pDest;
|
const USHORT* const pStart = pDest;
|
||||||
const USHORT* const pStart_src = pSrc;
|
const USHORT* const pStart_src = pSrc;
|
||||||
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc)) {
|
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc))
|
||||||
|
{
|
||||||
*pDest++ = *pSrc++;
|
*pDest++ = *pSrc++;
|
||||||
nDest -= sizeof(*pDest);
|
nDest -= sizeof(*pDest);
|
||||||
nSrc -= sizeof(*pSrc);
|
nSrc -= sizeof(*pSrc);
|
||||||
@ -1339,8 +1358,10 @@ static ULONG cvt_utffss_to_ascii(csconvert* obj, ULONG nSrc, const UCHAR* pSrc,
|
|||||||
|
|
||||||
const UCHAR* const pStart = pDest;
|
const UCHAR* const pStart = pDest;
|
||||||
const UCHAR* const pStart_src = pSrc;
|
const UCHAR* const pStart_src = pSrc;
|
||||||
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc)) {
|
while (nDest >= sizeof(*pDest) && nSrc >= sizeof(*pSrc))
|
||||||
if (*pSrc > 127) {
|
{
|
||||||
|
if (*pSrc > 127)
|
||||||
|
{
|
||||||
/* In the cvt_ascii_to_utffss case this should be CS_BAD_INPUT */
|
/* In the cvt_ascii_to_utffss case this should be CS_BAD_INPUT */
|
||||||
/* but not in cvt_none_to_utffss or cvt_utffss_to_ascii */
|
/* but not in cvt_none_to_utffss or cvt_utffss_to_ascii */
|
||||||
*err_code = CS_CONVERT_ERROR;
|
*err_code = CS_CONVERT_ERROR;
|
||||||
|
@ -66,7 +66,7 @@ int CLIB_ROUTINE main( int argc, char** argv)
|
|||||||
// Let's get the root directory from the instance path of this program.
|
// Let's get the root directory from the instance path of this program.
|
||||||
// argv[0] is only _mostly_ guaranteed to give this info,
|
// argv[0] is only _mostly_ guaranteed to give this info,
|
||||||
// so we GetModuleFileName()
|
// so we GetModuleFileName()
|
||||||
USHORT len = GetModuleFileName(NULL, directory, sizeof(directory));
|
const USHORT len = GetModuleFileName(NULL, directory, sizeof(directory));
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return reg_error(GetLastError(), "GetModuleFileName", NULL);
|
return reg_error(GetLastError(), "GetModuleFileName", NULL);
|
||||||
|
|
||||||
|
@ -39,9 +39,7 @@ static void cleanup_key(HKEY, const char*);
|
|||||||
static USHORT remove_subkeys(HKEY, bool, pfnRegError);
|
static USHORT remove_subkeys(HKEY, bool, pfnRegError);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
USHORT REGISTRY_install(HKEY hkey_rootnode,
|
USHORT REGISTRY_install(HKEY hkey_rootnode, const TEXT* directory, pfnRegError err_handler)
|
||||||
const TEXT* directory,
|
|
||||||
pfnRegError err_handler)
|
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -69,7 +67,8 @@ USHORT REGISTRY_install(HKEY hkey_rootnode,
|
|||||||
TEXT path_name[MAXPATHLEN];
|
TEXT path_name[MAXPATHLEN];
|
||||||
TEXT* p;
|
TEXT* p;
|
||||||
USHORT len = GetFullPathName(directory, sizeof(path_name), path_name, &p);
|
USHORT len = GetFullPathName(directory, sizeof(path_name), path_name, &p);
|
||||||
if (len && path_name[len - 1] != '/' && path_name[len - 1] != '\\') {
|
if (len && path_name[len - 1] != '/' && path_name[len - 1] != '\\')
|
||||||
|
{
|
||||||
path_name[len++] = '\\';
|
path_name[len++] = '\\';
|
||||||
path_name[len] = 0;
|
path_name[len] = 0;
|
||||||
}
|
}
|
||||||
@ -196,7 +195,8 @@ static USHORT remove_subkeys(HKEY hkey,
|
|||||||
&n_sub_keys,
|
&n_sub_keys,
|
||||||
&max_sub_key,
|
&max_sub_key,
|
||||||
&i, &i, &i, &i, &i, &last_write_time);
|
&i, &i, &i, &i, &i, &last_write_time);
|
||||||
if (status != ERROR_SUCCESS && status != ERROR_MORE_DATA) {
|
if (status != ERROR_SUCCESS && status != ERROR_MORE_DATA)
|
||||||
|
{
|
||||||
if (silent_flag)
|
if (silent_flag)
|
||||||
return FB_FAILURE;
|
return FB_FAILURE;
|
||||||
return (*err_handler) (status, "RegQueryInfoKey", NULL);
|
return (*err_handler) (status, "RegQueryInfoKey", NULL);
|
||||||
@ -206,7 +206,8 @@ static USHORT remove_subkeys(HKEY hkey,
|
|||||||
(TEXT*) malloc((SLONG) max_sub_key) : buffer;
|
(TEXT*) malloc((SLONG) max_sub_key) : buffer;
|
||||||
|
|
||||||
const TEXT* p = NULL;
|
const TEXT* p = NULL;
|
||||||
for (DWORD i = 0; i < n_sub_keys; i++) {
|
for (DWORD i = 0; i < n_sub_keys; i++)
|
||||||
|
{
|
||||||
DWORD sub_key_len = max_sub_key;
|
DWORD sub_key_len = max_sub_key;
|
||||||
if ((status = RegEnumKeyEx(hkey, i, sub_key, &sub_key_len,
|
if ((status = RegEnumKeyEx(hkey, i, sub_key, &sub_key_len,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
@ -229,7 +230,8 @@ static USHORT remove_subkeys(HKEY hkey,
|
|||||||
RegCloseKey(hkey_sub);
|
RegCloseKey(hkey_sub);
|
||||||
if (ret == FB_FAILURE)
|
if (ret == FB_FAILURE)
|
||||||
return FB_FAILURE;
|
return FB_FAILURE;
|
||||||
if ((status = RegDeleteKey(hkey, sub_key)) != ERROR_SUCCESS) {
|
if ((status = RegDeleteKey(hkey, sub_key)) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
p = "RegDeleteKey";
|
p = "RegDeleteKey";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -238,7 +240,8 @@ static USHORT remove_subkeys(HKEY hkey,
|
|||||||
if (buffer != sub_key)
|
if (buffer != sub_key)
|
||||||
free(sub_key);
|
free(sub_key);
|
||||||
|
|
||||||
if (p) {
|
if (p)
|
||||||
|
{
|
||||||
if (silent_flag)
|
if (silent_flag)
|
||||||
return FB_FAILURE;
|
return FB_FAILURE;
|
||||||
return (*err_handler) (status, p, NULL);
|
return (*err_handler) (status, p, NULL);
|
||||||
|
@ -147,7 +147,8 @@ int main( int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
if ((argv < end) && (!strcmp(*argv, "tips"))) {
|
if ((argv < end) && (!strcmp(*argv, "tips")))
|
||||||
|
{
|
||||||
argv++;
|
argv++;
|
||||||
sw_dump_tips = true;
|
sw_dump_tips = true;
|
||||||
}
|
}
|
||||||
@ -538,7 +539,8 @@ static void dump(FILE* file, rbdb* rbdb, ULONG lower, ULONG upper, UCHAR pg_type
|
|||||||
{
|
{
|
||||||
if (tip[sequence] == lower)
|
if (tip[sequence] == lower)
|
||||||
break;
|
break;
|
||||||
else if (!tip[sequence]) {
|
else if (!tip[sequence])
|
||||||
|
{
|
||||||
sequence = 0;
|
sequence = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -786,7 +788,8 @@ static void get_range(TEXT*** argv, const TEXT* const* const end, ULONG* lower,
|
|||||||
TEXT c = 0;
|
TEXT c = 0;
|
||||||
const TEXT* p;
|
const TEXT* p;
|
||||||
for (p = token->swc_string; *p; p++)
|
for (p = token->swc_string; *p; p++)
|
||||||
if (*p < '0' || *p > '9') {
|
if (*p < '0' || *p > '9')
|
||||||
|
{
|
||||||
c = *p;
|
c = *p;
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
break;
|
break;
|
||||||
@ -847,7 +850,8 @@ static void get_switch( TEXT** argv, swc* token)
|
|||||||
**************************************/
|
**************************************/
|
||||||
token->swc_string = *argv;
|
token->swc_string = *argv;
|
||||||
|
|
||||||
if (*token->swc_string == '-') {
|
if (*token->swc_string == '-')
|
||||||
|
{
|
||||||
token->swc_switch = true;
|
token->swc_switch = true;
|
||||||
token->swc_string++;
|
token->swc_string++;
|
||||||
}
|
}
|
||||||
@ -856,7 +860,8 @@ static void get_switch( TEXT** argv, swc* token)
|
|||||||
|
|
||||||
const int temp = strlen(token->swc_string) - 1;
|
const int temp = strlen(token->swc_string) - 1;
|
||||||
|
|
||||||
if (token->swc_string[temp] == ',') {
|
if (token->swc_string[temp] == ',')
|
||||||
|
{
|
||||||
token->swc_string[temp] = '\0';
|
token->swc_string[temp] = '\0';
|
||||||
//token->swc_comma = true;
|
//token->swc_comma = true;
|
||||||
}
|
}
|
||||||
@ -889,7 +894,8 @@ static header_page* open_database( rbdb* rbdb, ULONG pg_size)
|
|||||||
|
|
||||||
header_page* header = (header_page*) RBDB_read(rbdb, (SLONG) 0);
|
header_page* header = (header_page*) RBDB_read(rbdb, (SLONG) 0);
|
||||||
|
|
||||||
if (header->pag_type != pag_header) {
|
if (header->pag_type != pag_header)
|
||||||
|
{
|
||||||
printf("header page has wrong type, expected %d found %d!\n", pag_header, header->pag_type);
|
printf("header page has wrong type, expected %d found %d!\n", pag_header, header->pag_type);
|
||||||
rbdb->rbdb_valid = false;
|
rbdb->rbdb_valid = false;
|
||||||
}
|
}
|
||||||
@ -904,12 +910,14 @@ static header_page* open_database( rbdb* rbdb, ULONG pg_size)
|
|||||||
rbdb->rbdb_valid = false;
|
rbdb->rbdb_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pg_size && (pg_size != header->hdr_page_size)) {
|
if (pg_size && (pg_size != header->hdr_page_size))
|
||||||
|
{
|
||||||
printf("Using page size %d\n", pg_size);
|
printf("Using page size %d\n", pg_size);
|
||||||
header->hdr_page_size = pg_size;
|
header->hdr_page_size = pg_size;
|
||||||
rbdb->rbdb_valid = false;
|
rbdb->rbdb_valid = false;
|
||||||
}
|
}
|
||||||
else if (!header->hdr_page_size) {
|
else if (!header->hdr_page_size)
|
||||||
|
{
|
||||||
printf("Using page size 1024\n");
|
printf("Using page size 1024\n");
|
||||||
header->hdr_page_size = 1024;
|
header->hdr_page_size = 1024;
|
||||||
rbdb->rbdb_valid = false;
|
rbdb->rbdb_valid = false;
|
||||||
|
@ -76,10 +76,8 @@ ULONG* RMET_tips(TEXT* db_in)
|
|||||||
ULONG* tip = tips;
|
ULONG* tip = tips;
|
||||||
|
|
||||||
FOR X IN RDB$PAGES WITH X.RDB$PAGE_TYPE = pag_transactions
|
FOR X IN RDB$PAGES WITH X.RDB$PAGE_TYPE = pag_transactions
|
||||||
{
|
*tip = X.RDB$PAGE_NUMBER;
|
||||||
*tip = X.RDB$PAGE_NUMBER;
|
tip++;
|
||||||
tip++;
|
|
||||||
}
|
|
||||||
END_FOR
|
END_FOR
|
||||||
ON_ERROR
|
ON_ERROR
|
||||||
isc_print_status(gds__status);
|
isc_print_status(gds__status);
|
||||||
|
Loading…
Reference in New Issue
Block a user