提交 ba4deed0 编写于 作者: C Chris Hajas 提交者: Chris Hajas

Fix stats bucket logic for Double values in UNION queries in Orca

When merging statistics buckets for UNION and UNION ALL queries
involving a column that maps to Double (eg: floats, numeric, time
related types), we could end up in an infinite loop. This occurred if
the bucket boundaries that we compared were within a very small value,
defined in Orca as Epsilon. While we considered that two values were
equal if they were within Epsilon, we didn't when computing whether
datum1 < datum2. Therefore we'd get into a situation where a datum
could be both equal to and less than another datum, which the logic
wasn't able to handle.

The fix is to make sure we have a hard boundary of when we consider a
datum less than another datum by including the epsilon logic in all
datum comparisons. Now, 2 datums are equal if they are within epsilon,
but datum1 is less than datum 2 only if datum1 < datum2 - epsilon.

Also add some tests since we didn't have any tests for types that mapped
to Double.
上级 f4d48358
......@@ -110,7 +110,8 @@ IDatum::StatsAreLessThan(const IDatum *datum) const
CDouble d1 = this->GetDoubleMapping();
CDouble d2 = datum->GetDoubleMapping();
return d1 < d2;
CDouble diff = d2 - d1;
return diff > CStatistics::Epsilon;
}
//---------------------------------------------------------------------------
......
......@@ -53,6 +53,14 @@ public:
static GPOS_RESULT EresUnittest_Basics();
static GPOS_RESULT StatsComparisonDoubleLessThan();
static GPOS_RESULT StatsComparisonDoubleEqualWithinEpsilon();
static GPOS_RESULT StatsComparisonIntLessThan();
static GPOS_RESULT StatsComparisonIntEqual();
}; // class CDatumTest
} // namespace gpnaucrates
......
......@@ -99,6 +99,13 @@ public:
static GPOS_RESULT EresUnittest_CBucketMergeCommutativityUnionAll();
static GPOS_RESULT EresUnittest_CBucketMergeCommutativityDoubleDatum();
static GPOS_RESULT
EresUnittest_CBucketMergeCommutativityDoubleDatumSameLowerBounds();
static GPOS_RESULT
EresUnittest_CBucketMergeCommutativityDoubleDatumSameUpperBounds();
}; // class CBucketTest
} // namespace gpnaucrates
......
......@@ -65,6 +65,9 @@ public:
CWStringDynamic *pstrEncodedValue,
CDouble value);
// helper function to generate a point of double datatype
static CPoint *PpointDouble(CMemoryPool *mp, OID oid, CDouble value);
// helper method to print statistics object
static void PrintStats(CMemoryPool *mp, const CStatistics *stats);
......
......@@ -48,6 +48,8 @@ public:
// merge basic tests
static GPOS_RESULT EresUnittest_MergeUnion();
// merge union test with double values differing by less than epsilon
static GPOS_RESULT EresUnittest_MergeUnionDoubleLessThanEpsilon();
}; // class CHistogramTest
} // namespace gpnaucrates
......
......@@ -614,6 +614,9 @@ public:
CWStringDynamic *pstrEncodedValue,
LINT value);
// Create a datum with a given type and double value
static IDatum *CreateDoubleDatum(CMemoryPool *mp, CMDAccessor *md_accessor,
IMDId *mdid_type, CDouble value);
// create an interval for generic data types
// does not take ownership of mdid_type
static CConstraintInterval *PciGenericInterval(
......
......@@ -3831,6 +3831,39 @@ CTestUtils::CreateGenericDatum(CMemoryPool *mp, CMDAccessor *md_accessor,
return datum;
}
//---------------------------------------------------------------------------
// @function:
// CTestUtils::CreateDoubleDatum
//
// @doc:
// Create a datum with a given type and double value
//
//---------------------------------------------------------------------------
IDatum *
CTestUtils::CreateDoubleDatum(CMemoryPool *mp, CMDAccessor *md_accessor,
IMDId *mdid_type, CDouble value)
{
GPOS_ASSERT(NULL != md_accessor);
GPOS_ASSERT(!mdid_type->Equals(&CMDIdGPDB::m_mdid_numeric));
const IMDType *pmdtype = md_accessor->RetrieveType(mdid_type);
ULONG ulbaSize = 0;
CWStringDynamic *pstrW =
GPOS_NEW(mp) CWStringDynamic(mp, GPOS_WSZ_LIT("AAAABXc="));
BYTE *data = CDXLUtils::DecodeByteArrayFromString(mp, pstrW, &ulbaSize);
CDXLDatumGeneric *dxl_datum = NULL;
dxl_datum = GPOS_NEW(mp) CDXLDatumStatsDoubleMappable(
mp, mdid_type, default_type_modifier, false /*is_const_null*/, data,
ulbaSize, CDouble(value));
IDatum *datum = pmdtype->GetDatumForDXLDatum(mp, dxl_datum);
dxl_datum->Release();
GPOS_DELETE(pstrW);
return datum;
}
//---------------------------------------------------------------------------
// @function:
// CConstraintTest::PciGenericInterval
......@@ -3866,8 +3899,6 @@ CTestUtils::PciGenericInterval(CMemoryPool *mp, CMDAccessor *md_accessor,
return GPOS_NEW(mp)
CConstraintInterval(mp, colref, pdrgprng, false /*is_null*/);
}
//---------------------------------------------------------------------------
// @function:
// CTestUtils::PexprScalarCmpIdentToConstant
......
......@@ -45,7 +45,12 @@
GPOS_RESULT
CDatumTest::EresUnittest()
{
CUnittest rgut[] = {GPOS_UNITTEST_FUNC(CDatumTest::EresUnittest_Basics)};
CUnittest rgut[] = {
GPOS_UNITTEST_FUNC(CDatumTest::EresUnittest_Basics),
GPOS_UNITTEST_FUNC(CDatumTest::StatsComparisonDoubleLessThan),
GPOS_UNITTEST_FUNC(CDatumTest::StatsComparisonDoubleEqualWithinEpsilon),
GPOS_UNITTEST_FUNC(CDatumTest::StatsComparisonIntLessThan),
GPOS_UNITTEST_FUNC(CDatumTest::StatsComparisonIntEqual)};
return CUnittest::EresExecute(rgut, GPOS_ARRAY_SIZE(rgut));
}
......@@ -232,5 +237,178 @@ CDatumTest::CreateGenericDatum(CMemoryPool *mp, BOOL is_null)
);
}
//---------------------------------------------------------------------------
// @function:
// CDatumTest::StatsComparisonDouble
//
// @doc:
// Compare DOUBle statistics that are within a small epsilon and ensure
// StatsAreEqual and StatsAreLessThan do not overlap
//
//---------------------------------------------------------------------------
GPOS_RESULT
CDatumTest::StatsComparisonDoubleEqualWithinEpsilon()
{
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
// setup a file-based provider
CMDProviderMemory *pmdp = CTestUtils::m_pmdpf;
pmdp->AddRef();
CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp);
// install opt context in TLS
CAutoOptCtxt aoc(mp, &mda, NULL, /* pceeval */
CTestUtils::GetCostModel(mp));
// create accesssor
CMDAccessor *md_accessor = COptCtxt::PoctxtFromTLS()->Pmda();
IMDId *mdid1 = GPOS_NEW(mp) CMDIdGPDB(GPDB_FLOAT8);
IDatum *datum1 = CTestUtils::CreateDoubleDatum(mp, md_accessor, mdid1,
CDouble(631.82140500000003));
IMDId *mdid2 = GPOS_NEW(mp) CMDIdGPDB(GPDB_FLOAT8);
IDatum *datum2 = CTestUtils::CreateDoubleDatum(mp, md_accessor, mdid2,
CDouble(631.82140700000002));
BOOL isEqual = datum1->StatsAreEqual(datum2);
BOOL isLessThan = datum1->StatsAreLessThan(datum2);
datum1->Release();
datum2->Release();
if (isEqual || !isLessThan)
{
return GPOS_OK;
}
return GPOS_FAILED;
}
//---------------------------------------------------------------------------
// @function:
// CDatumTest::StatsComparisonDouble
//
// @doc:
// Compare DOUBle statistics and ensure StatsAreEqual and StatsAreLessThan do not overlap
//
//---------------------------------------------------------------------------
GPOS_RESULT
CDatumTest::StatsComparisonDoubleLessThan()
{
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
// setup a file-based provider
CMDProviderMemory *pmdp = CTestUtils::m_pmdpf;
pmdp->AddRef();
CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp);
// install opt context in TLS
CAutoOptCtxt aoc(mp, &mda, NULL, /* pceeval */
CTestUtils::GetCostModel(mp));
// create accesssor
CMDAccessor *md_accessor = COptCtxt::PoctxtFromTLS()->Pmda();
IMDId *mdid1 = GPOS_NEW(mp) CMDIdGPDB(GPDB_FLOAT8);
IDatum *datum1 = CTestUtils::CreateDoubleDatum(mp, md_accessor, mdid1,
CDouble(99.82140500000003));
IMDId *mdid2 = GPOS_NEW(mp) CMDIdGPDB(GPDB_FLOAT8);
IDatum *datum2 = CTestUtils::CreateDoubleDatum(mp, md_accessor, mdid2,
CDouble(100.92140700000002));
BOOL isEqual = datum1->StatsAreEqual(datum2);
BOOL isLessThan = datum1->StatsAreLessThan(datum2);
datum1->Release();
datum2->Release();
if (!isEqual && isLessThan)
{
return GPOS_OK;
}
return GPOS_FAILED;
}
//---------------------------------------------------------------------------
// @function:
// CDatumTest::StatsComparisonIntLessThan
//
// @doc:
// Compare LINT statistics and ensure StatsAreEqual and StatsAreLessThan do not overlap
//
//---------------------------------------------------------------------------
GPOS_RESULT
CDatumTest::StatsComparisonIntLessThan()
{
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
// setup a file-based provider
CMDProviderMemory *pmdp = CTestUtils::m_pmdpf;
pmdp->AddRef();
CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp);
// install opt context in TLS
CAutoOptCtxt aoc(mp, &mda, NULL, /* pceeval */
CTestUtils::GetCostModel(mp));
IDatum *datum1 = GPOS_NEW(mp) CDatumInt4GPDB(CTestUtils::m_sysidDefault,
100 /*val*/, false /*isnull*/);
IDatum *datum2 = GPOS_NEW(mp) CDatumInt4GPDB(CTestUtils::m_sysidDefault,
101 /*val*/, false /*isnull*/);
BOOL isEqual = datum1->StatsAreEqual(datum2);
BOOL isLessThan = datum1->StatsAreLessThan(datum2);
datum1->Release();
datum2->Release();
if (!isEqual && isLessThan)
{
return GPOS_OK;
}
return GPOS_FAILED;
}
//---------------------------------------------------------------------------
// @function:
// CDatumTest::StatsComparisonIntEqual
//
// @doc:
// Compare LINT statistics and ensure StatsAreEqual and StatsAreLessThan do not overlap
//
//---------------------------------------------------------------------------
GPOS_RESULT
CDatumTest::StatsComparisonIntEqual()
{
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
// setup a file-based provider
CMDProviderMemory *pmdp = CTestUtils::m_pmdpf;
pmdp->AddRef();
CMDAccessor mda(mp, CMDCache::Pcache(), CTestUtils::m_sysidDefault, pmdp);
// install opt context in TLS
CAutoOptCtxt aoc(mp, &mda, NULL, /* pceeval */
CTestUtils::GetCostModel(mp));
IDatum *datum1 = GPOS_NEW(mp) CDatumInt4GPDB(CTestUtils::m_sysidDefault,
101 /*val*/, false /*isnull*/);
IDatum *datum2 = GPOS_NEW(mp) CDatumInt4GPDB(CTestUtils::m_sysidDefault,
101 /*val*/, false /*isnull*/);
BOOL isEqual = datum1->StatsAreEqual(datum2);
BOOL isLessThan = datum1->StatsAreLessThan(datum2);
datum1->Release();
datum2->Release();
if (isEqual && !isLessThan)
{
return GPOS_OK;
}
return GPOS_FAILED;
}
// EOF
......@@ -57,6 +57,14 @@ CBucketTest::EresUnittest()
CBucketTest::EresUnittest_CBucketMergeCommutativitySameUpperBounds),
GPOS_UNITTEST_FUNC(
CBucketTest::EresUnittest_CBucketMergeCommutativityUnionAll),
GPOS_UNITTEST_FUNC(
CBucketTest::EresUnittest_CBucketMergeCommutativityDoubleDatum),
GPOS_UNITTEST_FUNC(
CBucketTest::
EresUnittest_CBucketMergeCommutativityDoubleDatumSameLowerBounds),
GPOS_UNITTEST_FUNC(
CBucketTest::
EresUnittest_CBucketMergeCommutativityDoubleDatumSameUpperBounds),
};
CAutoMemoryPool amp;
......@@ -710,4 +718,204 @@ CBucketTest::EresUnittest_CBucketMergeCommutativityUnionAll()
return GPOS_OK;
}
// basic merge commutativity test for double datum
GPOS_RESULT
CBucketTest::EresUnittest_CBucketMergeCommutativityDoubleDatum()
{
// create memory pool
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
// [0.0, 100.0)
CPoint *ppLower1 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(0.0));
CPoint *ppUpper1 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(100.0));
CBucket *bucket1 = GPOS_NEW(mp)
CBucket(ppLower1, ppUpper1, true /* is_lower_closed */,
false /*is_upper_closed*/, CDouble(0.2), CDouble(50));
// [50.0, 150.0)
CPoint *ppLower2 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(50.0));
CPoint *ppUpper2 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(150.0));
CBucket *bucket2 = GPOS_NEW(mp)
CBucket(ppLower2, ppUpper2, true /* is_lower_closed */,
false /*is_upper_closed*/, CDouble(0.2), CDouble(50));
CBucket *bucket1_new1 = NULL;
CBucket *bucket2_new1 = NULL;
CDouble result_rows1(0.0);
CBucket *result1 = bucket1->SplitAndMergeBuckets(
mp, bucket2, 1000, 600, &bucket1_new1, &bucket2_new1, &result_rows1,
false /*is_union_all*/);
CBucket *bucket1_new2 = NULL;
CBucket *bucket2_new2 = NULL;
CDouble result_rows2(0.0);
CBucket *result2 = bucket2->SplitAndMergeBuckets(
mp, bucket1, 600, 1000, &bucket1_new2, &bucket2_new2, &result_rows2,
false /*is_union_all*/);
GPOS_ASSERT(result1->Equals(result2));
if (NULL != bucket1_new1)
{
GPOS_ASSERT(bucket1_new1->Equals(bucket2_new2));
}
else if (NULL != bucket2_new1)
{
GPOS_ASSERT(bucket2_new1->Equals(bucket1_new2));
}
GPOS_DELETE(bucket1);
GPOS_DELETE(bucket2);
GPOS_DELETE(result1);
GPOS_DELETE(result2);
GPOS_DELETE(bucket1_new1);
GPOS_DELETE(bucket2_new1);
GPOS_DELETE(bucket1_new2);
GPOS_DELETE(bucket2_new2);
return GPOS_OK;
}
// merge commutativity test for union when lower bounds have same value but
// one is closed and the other is open for double datum
GPOS_RESULT
CBucketTest::EresUnittest_CBucketMergeCommutativityDoubleDatumSameLowerBounds()
{
// create memory pool
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
// b1 = [0,100)
CPoint *ppLower1 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(0.0));
CPoint *ppUpper1 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(100.0));
CBucket *bucket1 = GPOS_NEW(mp)
CBucket(ppLower1, ppUpper1, true /* is_lower_closed */,
false /*is_upper_closed*/, CDouble(0.2), CDouble(50));
// b2 = (0,50)
CPoint *ppLower2 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(0.0));
CPoint *ppUpper2 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(50.0));
CBucket *bucket2 = GPOS_NEW(mp)
CBucket(ppLower2, ppUpper2, false /* is_lower_closed */,
false /*is_upper_closed*/, CDouble(0.2), CDouble(50));
CBucket *bucket1_new1 = NULL;
CBucket *bucket2_new1 = NULL;
CDouble result_rows1(0.0);
CBucket *result1 = bucket1->SplitAndMergeBuckets(
mp, bucket2, 1000, 600, &bucket1_new1, &bucket2_new1, &result_rows1,
false /*is_union_all*/);
CBucket *bucket1_new2 = NULL;
CBucket *bucket2_new2 = NULL;
CDouble result_rows2(0.0);
CBucket *result2 = bucket2->SplitAndMergeBuckets(
mp, bucket1, 600, 1000, &bucket1_new2, &bucket2_new2, &result_rows2,
false /*is_union_all*/);
GPOS_ASSERT(result1->Equals(result2));
if (NULL != bucket1_new1)
{
GPOS_ASSERT(bucket1_new1->Equals(bucket2_new2));
}
else if (NULL != bucket2_new1)
{
GPOS_ASSERT(bucket2_new1->Equals(bucket1_new2));
}
GPOS_DELETE(bucket1);
GPOS_DELETE(bucket2);
GPOS_DELETE(result1);
GPOS_DELETE(result2);
GPOS_DELETE(bucket1_new1);
GPOS_DELETE(bucket2_new1);
GPOS_DELETE(bucket1_new2);
GPOS_DELETE(bucket2_new2);
return GPOS_OK;
}
// merge commutativity test for union when upper bounds have same value but
// one is closed and the other is open for double datum
GPOS_RESULT
CBucketTest::EresUnittest_CBucketMergeCommutativityDoubleDatumSameUpperBounds()
{
// create memory pool
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
// b1 = [0,100)
CPoint *ppLower1 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(0.0));
CPoint *ppUpper1 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(100.0));
CBucket *bucket1 = GPOS_NEW(mp)
CBucket(ppLower1, ppUpper1, true /* is_lower_closed */,
false /*is_upper_closed*/, CDouble(0.4), CDouble(50));
// b2 = [0,100]
CPoint *ppLower2 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(0.0));
CPoint *ppUpper2 =
CCardinalityTestUtils::PpointDouble(mp, GPDB_FLOAT8, CDouble(100.0));
CBucket *bucket2 = GPOS_NEW(mp)
CBucket(ppLower2, ppUpper2, true /* is_lower_closed */,
true /*is_upper_closed*/, CDouble(0.2), CDouble(50));
CBucket *bucket1_new1 = NULL;
CBucket *bucket2_new1 = NULL;
CDouble result_rows1(0.0);
CBucket *result1 = bucket1->SplitAndMergeBuckets(
mp, bucket2, 1000, 600, &bucket1_new1, &bucket2_new1, &result_rows1,
false /*is_union_all*/);
CBucket *bucket1_new2 = NULL;
CBucket *bucket2_new2 = NULL;
CDouble result_rows2(0.0);
CBucket *result2 = bucket2->SplitAndMergeBuckets(
mp, bucket1, 600, 1000, &bucket1_new2, &bucket2_new2, &result_rows2,
false /*is_union_all*/);
GPOS_ASSERT(result1->Equals(result2));
if (NULL != bucket1_new1)
{
GPOS_ASSERT(bucket1_new1->Equals(bucket2_new2));
}
else if (NULL != bucket2_new1)
{
GPOS_ASSERT(bucket2_new1->Equals(bucket1_new2));
}
GPOS_DELETE(bucket1);
GPOS_DELETE(bucket2);
GPOS_DELETE(result1);
GPOS_DELETE(result2);
GPOS_DELETE(bucket1_new1);
GPOS_DELETE(bucket2_new1);
GPOS_DELETE(bucket1_new2);
GPOS_DELETE(bucket2_new2);
return GPOS_OK;
}
// EOF
......@@ -196,6 +196,19 @@ CCardinalityTestUtils::PpointNumeric(CMemoryPool *mp,
return point;
}
// helper function to generate a point from an encoded value of specific datatype
CPoint *
CCardinalityTestUtils::PpointDouble(CMemoryPool *mp, OID oid, CDouble value)
{
CMDAccessor *md_accessor = COptCtxt::PoctxtFromTLS()->Pmda();
IMDId *mdid = GPOS_NEW(mp) CMDIdGPDB(oid);
IDatum *datum = CTestUtils::CreateDoubleDatum(mp, md_accessor, mdid, value);
CPoint *point = GPOS_NEW(mp) CPoint(datum);
return point;
}
// helper function to print the bucket object
void
CCardinalityTestUtils::PrintBucket(CMemoryPool *mp, const char *pcPrefix,
......
......@@ -39,7 +39,10 @@ CHistogramTest::EresUnittest()
GPOS_UNITTEST_FUNC(CHistogramTest::EresUnittest_CHistogramBool),
GPOS_UNITTEST_FUNC(CHistogramTest::EresUnittest_Skew),
GPOS_UNITTEST_FUNC(CHistogramTest::EresUnittest_CHistogramValid),
GPOS_UNITTEST_FUNC(CHistogramTest::EresUnittest_MergeUnion)};
GPOS_UNITTEST_FUNC(CHistogramTest::EresUnittest_MergeUnion),
GPOS_UNITTEST_FUNC(
CHistogramTest::EresUnittest_MergeUnionDoubleLessThanEpsilon)};
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
......@@ -319,7 +322,7 @@ CHistogramTest::EresUnittest_Skew()
return GPOS_OK;
}
// basis merge commutativity test
// basic merge commutativity test
GPOS_RESULT
CHistogramTest::EresUnittest_MergeUnion()
{
......@@ -375,4 +378,56 @@ CHistogramTest::EresUnittest_MergeUnion()
return GPOS_OK;
}
// merge union test with double values differing by less than epsilon
GPOS_RESULT
CHistogramTest::EresUnittest_MergeUnionDoubleLessThanEpsilon()
{
// create memory pool
CAutoMemoryPool amp;
CMemoryPool *mp = amp.Pmp();
// [631.82140700000002, 631.82140700000002]
CPoint *ppLower1 = CCardinalityTestUtils::PpointDouble(
mp, GPDB_FLOAT8, CDouble(631.82140700000002));
CPoint *ppUpper1 = CCardinalityTestUtils::PpointDouble(
mp, GPDB_FLOAT8, CDouble(631.82140700000002));
CBucket *bucket1 = GPOS_NEW(mp)
CBucket(ppLower1, ppUpper1, true /* is_lower_closed */,
true /*is_upper_closed*/, CDouble(0.2), CDouble(50));
// (631.82140500000003, 645.05197699999997)
CPoint *ppLower2 = CCardinalityTestUtils::PpointDouble(
mp, GPDB_FLOAT8, CDouble(631.82140500000003));
CPoint *ppUpper2 = CCardinalityTestUtils::PpointDouble(
mp, GPDB_FLOAT8, CDouble(645.05197699999997));
CBucket *bucket2 = GPOS_NEW(mp)
CBucket(ppLower2, ppUpper2, false /* is_lower_closed */,
false /*is_upper_closed*/, CDouble(0.2), CDouble(50));
CBucketArray *pdrgppbucket1 = GPOS_NEW(mp) CBucketArray(mp);
pdrgppbucket1->Append(bucket1);
CHistogram *histogram1 = GPOS_NEW(mp) CHistogram(mp, pdrgppbucket1);
CBucketArray *pdrgppbucket2 = GPOS_NEW(mp) CBucketArray(mp);
pdrgppbucket2->Append(bucket2);
CHistogram *histogram2 = GPOS_NEW(mp) CHistogram(mp, pdrgppbucket2);
CDouble output_rows1(0.0);
CHistogram *result1 = histogram1->MakeUnionHistogramNormalize(
1000, histogram2, 600, &output_rows1);
{
CAutoTrace at(mp);
result1->OsPrint(at.Os());
at.Os() << "Result 1: " << output_rows1 << std::endl;
}
GPOS_DELETE(histogram1);
GPOS_DELETE(histogram2);
GPOS_DELETE(result1);
return GPOS_OK;
}
// EOF
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册