1 /*===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  *
25  */
26 
27 // allow g++ to find INT64_MAX in stdint.h
28 #define __STDC_LIMIT_MACROS
29 
30 #include <ktst/unit_test.hpp>
31 
32 #include <klib/log.h>
33 #include <klib/out.h>
34 #include <klib/rc.h>
35 #include <kfc/ctx.h>
36 #include <kfc/except.h>
37 #include <kfc/xc.h>
38 #include <kfs/directory.h>
39 #include <kdb/manager.h>
40 #include <kdb/table.h>
41 #include <kdb/rowset.h>
42 
43 #include <stdlib.h>
44 #include <time.h>
45 
46 #include <vector>
47 #include <set>
48 #include <algorithm>
49 #include <string>
50 
51 #define ENTRY \
52     HYBRID_FUNC_ENTRY ( rcDB, rcVector, rcValidating ); \
53     m_ctx = ctx
54 
55 #define EXIT \
56     REQUIRE ( ! FAILED () ); \
57     Release()
58 
59 ////// additional REQUIRE macros
60 
61 #define REQUIRE_FAILED() ( REQUIRE ( FAILED () ), CLEAR() )
62 
63 #define REQUIRE_EXPR(expr) \
64         (expr); \
65         REQUIRE ( !FAILED () )
66 
67 #define REQUIRE_EXPR_FAILED(expr) \
68         (expr); \
69         REQUIRE_FAILED()
70 
71 #define THROW_IF_FAILED(msg) \
72         if ( m_ctx -> rc != 0 ) \
73             throw std :: logic_error ( (msg) );
74 
75 TEST_SUITE(KRowSetTestSuite);
76 
vector_inserter(ctx_t ctx,int64_t row_id,void * data)77 void vector_inserter ( ctx_t ctx, int64_t row_id, void *data )
78 {
79     std::vector<int64_t> * rows = (std::vector<int64_t> *) data;
80     rows->push_back ( row_id );
81 }
82 
83 class RowSetFixture
84 {
85 public:
86     const KCtx*         m_ctx;  // points into the test case's local memory
87     KDirectory*         m_wd;
88     KDBManager*         m_mgr;
89     KTable *            m_table;
90     std::string         m_tableName;
91 
RowSetFixture()92     RowSetFixture()
93     : m_ctx(NULL)
94     , m_table(NULL)
95     , m_tableName("")
96     {
97         THROW_ON_RC ( KDirectoryNativeDir ( & m_wd ) );
98         THROW_ON_RC ( KDBManagerMakeUpdate ( & m_mgr, m_wd ) );
99     }
100 
~RowSetFixture()101     virtual ~RowSetFixture()
102     {
103         if ( m_table != NULL && m_tableName != "" )
104             CloseRemoveTable();
105 
106         KDBManagerRelease ( m_mgr );
107         KDirectoryRelease ( m_wd );
108     }
109 
GetTable(const char * name)110     const KTable * GetTable ( const char * name )
111     {
112         if ( m_tableName . empty() )
113             m_tableName = name;
114 
115         if ( m_tableName != name )
116             throw std :: invalid_argument ( "name does not match a name of already create table" );
117 
118         if ( m_table == NULL )
119             CreateTable ();
120 
121         return m_table;
122     }
123 
CloseRemoveTable()124     void CloseRemoveTable ()
125     {
126         KTableRelease ( m_table );
127         m_table = NULL;
128 
129         KDirectoryRemove ( m_wd, true, m_tableName . c_str () );
130         m_tableName = "";
131     }
132 
GenerateId(int64_t range_start,int64_t range_count)133     int64_t GenerateId ( int64_t range_start, int64_t range_count )
134     {
135         if ( range_start == -1 )
136             range_start = 0;
137 
138         if ( range_count == -1 || range_start + range_count < 0 )
139             range_count = INT64_MAX - range_start;
140 
141         int64_t generated_id = ((int64_t)rand() << 32) | rand();
142         generated_id &= INT64_MAX; // make sure it is positive
143 
144         generated_id = generated_id % range_count;
145         generated_id += range_start;
146 
147         return generated_id;
148     }
149 
150     /*
151      * "density" - can is a number between -1 and 8.
152      *   -1 means that most probably each row will go to a separate leaf
153      *   0 means that rows might go to same leaves, but those leaves should still not be dense (and store data in array of ranges, not in bitmap)
154      *   from 1 to 8 change density level:
155      *   - 1 means that every (up to) 8k rows go to a each leaf
156      *   - 8 means that every (up to) 65k rows (maximum rows per leaf) will go to each leaf
157      */
InsertRandomRows(KRowSet * rowset,int num_rows,int density)158     std::set<int64_t> InsertRandomRows ( KRowSet * rowset, int num_rows, int density )
159     {
160         int64_t range_start = 0;
161         int64_t range_count;
162         std::set<int64_t> inserted_rows_set;
163 
164         assert ( num_rows > 0 );
165         assert ( density >= -1 );
166         assert ( density <= 8 );
167 
168         if ( density == -1 )
169             range_count = -1;
170         else if ( density == 0 )
171             range_count = ((num_rows - 1) / 5 + 1) * 65536;
172         else
173         {
174             assert ( num_rows > 8 );
175             range_count = ((num_rows - 1) / (8192 * density) + 1) * 65536;
176         }
177 
178         for ( int i = 0; i < num_rows; ++i )
179         {
180             int64_t row_id = GenerateId ( range_start, range_count );
181             if ( inserted_rows_set.find( row_id ) ==  inserted_rows_set.end() )
182             {
183                 KRowSetAddRowId ( rowset, m_ctx, row_id );
184                 THROW_IF_FAILED ( "Failed to insert a row" );
185                 inserted_rows_set.insert( row_id );
186             }
187             else
188                 --i;
189         }
190 
191         return inserted_rows_set;
192     }
193 
RunChecks(const KRowSet * rowset,std::set<int64_t> & inserted_rows_set)194     void RunChecks ( const KRowSet * rowset, std::set<int64_t> & inserted_rows_set )
195     {
196         RunChecksInt ( rowset, inserted_rows_set );
197     }
198 
SetIntersection(const std::set<int64_t> & set1,const std::set<int64_t> & set2)199     std::set<int64_t> SetIntersection ( const std::set<int64_t>& set1, const std::set<int64_t>& set2 )
200     {
201         std::set<int64_t> result;
202         std::set_intersection(
203                 set1.begin(), set1.end(),
204                 set2.begin(), set2.end(),
205                 std::inserter(result, result.begin())
206         );
207 
208         return result;
209     }
210 
SetUnion(const std::set<int64_t> & set1,const std::set<int64_t> & set2)211     std::set<int64_t> SetUnion ( const std::set<int64_t>& set1, const std::set<int64_t>& set2 )
212     {
213         std::set<int64_t> result;
214         std::set_union(
215                 set1.begin(), set1.end(),
216                 set2.begin(), set2.end(),
217                 std::inserter(result, result.begin())
218         );
219 
220         return result;
221     }
222 
Release()223     virtual void Release()
224     {
225         if (m_ctx != 0)
226         {
227 
228             m_ctx = 0; // a pointer into the caller's local memory
229         }
230     }
231 private:
RunChecksInt(const KRowSet * rowset,std::set<int64_t> & inserted_rows_set)232     void RunChecksInt ( const KRowSet * rowset, std::set<int64_t> & inserted_rows_set )
233     {
234         std::vector<int64_t> inserted_rows;
235         std::vector<int64_t> returned_rows;
236         uint64_t num_rows;
237 
238         KRowSetVisit ( rowset, m_ctx, vector_inserter, (void *)&returned_rows );
239         THROW_IF_FAILED ( "Failed to iterate over rowset" );
240 
241         for (std::set<int64_t>::iterator it = inserted_rows_set.begin(); it != inserted_rows_set.end(); ++it)
242         {
243             bool has_row = KRowSetHasRowId ( rowset, m_ctx, *it );
244             THROW_IF_FAILED ( "Failed to check a row in rowset" );
245             if ( ! has_row )
246                 FAIL("Row is not found in rowset");
247             inserted_rows . push_back ( *it );
248         }
249 
250         num_rows = KRowSetGetNumRowIds( rowset, m_ctx );
251         THROW_IF_FAILED ( "Failed to get number of row ids in rowset" );
252 /*
253         // useful in debugging
254         KOutMsg("Inserted rows: %lu, returned rows: %lu\n", inserted_rows.size(), returned_rows.size() );
255         KOutMsg("inserted:\n");
256         for ( int i = 0; i < inserted_rows.size(); ++i )
257         {
258             KOutMsg ( "%d, ", inserted_rows[i] );
259         }
260         KOutMsg("\n");
261         KOutMsg("returned:\n");
262         for ( int i = 0; i < returned_rows.size(); ++i )
263         {
264             KOutMsg ( "%d, ", returned_rows[i] );
265         }
266         KOutMsg("\n");
267 */
268 
269         if ( inserted_rows.size() != returned_rows.size() )
270             FAIL("inserted_rows.size() != returned_rows.size()");
271         if ( num_rows != returned_rows.size() )
272             FAIL("num_rows != returned_rows.size()");
273         if ( inserted_rows != returned_rows )
274             FAIL("inserted_rows != returned_rows");
275     }
276 
CreateTable()277     void CreateTable ()
278     {
279         THROW_ON_RC ( KDBManagerCreateTable ( m_mgr, & m_table, kcmInit + kcmMD5, m_tableName . c_str() ) );
280     }
281 };
282 
283 
FIXTURE_TEST_CASE(KRowSetScatteredRows,RowSetFixture)284 FIXTURE_TEST_CASE ( KRowSetScatteredRows, RowSetFixture )
285 {
286     ENTRY;
287     KRowSet * rowset;
288     std::set<int64_t> inserted_rows_set;
289     bool has_row;
290 
291     REQUIRE_EXPR ( rowset = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
292 
293     REQUIRE_EXPR ( has_row = KRowSetHasRowId ( rowset, ctx, 1 ) );
294     REQUIRE ( ! has_row );
295 
296     inserted_rows_set = InsertRandomRows ( rowset, 10000, -1 );
297     RunChecks ( rowset, inserted_rows_set );
298 
299     REQUIRE_EXPR ( KRowSetRelease( rowset, ctx ) );
300     EXIT;
301 }
302 
FIXTURE_TEST_CASE(KRowSetDenseRows,RowSetFixture)303 FIXTURE_TEST_CASE ( KRowSetDenseRows, RowSetFixture )
304 {
305     ENTRY;
306     KRowSet * rowset;
307     std::set<int64_t> inserted_rows_set;
308 
309     REQUIRE_EXPR ( rowset = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
310 
311     inserted_rows_set = InsertRandomRows ( rowset, 10000, 1 );
312     RunChecks ( rowset, inserted_rows_set );
313 
314     REQUIRE_EXPR ( KRowSetRelease( rowset, ctx ) );
315     EXIT;
316 }
317 
FIXTURE_TEST_CASE(KRowSetSerialRows,RowSetFixture)318 FIXTURE_TEST_CASE ( KRowSetSerialRows, RowSetFixture )
319 {
320     ENTRY;
321     KRowSet * rowset;
322     std::set<int64_t> inserted_rows_set;
323 
324     REQUIRE_EXPR ( rowset = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
325 
326     for ( int i = 0; i < 20000; ++i )
327     {
328         int64_t row_id = 50000 + i; // row ids will only go to first two leaves
329         REQUIRE_EXPR ( KRowSetAddRowId ( rowset, ctx, row_id) );
330         inserted_rows_set.insert( row_id );
331     }
332     RunChecks ( rowset, inserted_rows_set );
333 
334     REQUIRE_EXPR ( KRowSetRelease( rowset, ctx ) );
335     EXIT;
336 }
337 
FIXTURE_TEST_CASE(KRowSetRowRanges,RowSetFixture)338 FIXTURE_TEST_CASE ( KRowSetRowRanges, RowSetFixture )
339 {
340     ENTRY;
341     KRowSet * rowset;
342     std::set<int64_t> inserted_rows_set;
343 
344     int64_t row_ids[] = { 0, 5, 1, 6, 20, 10, 55, 60, 65, 70, 75, 80, 85, 999,  2001 };
345     uint64_t counts[]  = { 1, 1, 4, 4, 10, 10, 1,  1,  1,  1,  1,  1,  1,  1000, 1000 };
346 
347     REQUIRE_EXPR ( rowset = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
348 
349     for ( size_t i = 0; i < sizeof row_ids / sizeof row_ids[0]; ++i )
350     {
351         int64_t row_id = row_ids[i];
352         uint64_t count = counts[i];
353 
354         REQUIRE_EXPR ( KRowSetAddRowIdRange ( rowset, ctx, row_id, count ) );
355         for ( uint64_t j = 0; j < count; ++j )
356             inserted_rows_set.insert( row_id + j );
357     }
358     RunChecks ( rowset, inserted_rows_set );
359 
360     REQUIRE_EXPR ( KRowSetRelease( rowset, ctx ) );
361     EXIT;
362 }
363 
FIXTURE_TEST_CASE(KRowSetRowRangesOverlapDuplicates,RowSetFixture)364 FIXTURE_TEST_CASE ( KRowSetRowRangesOverlapDuplicates, RowSetFixture )
365 {
366     ENTRY;
367     KRowSet * rowset;
368     std::set<int64_t> inserted_rows_set;
369 
370     int64_t row_ids[] = { 5, 10 };
371     uint64_t counts[]  = { 1, 5    };
372 
373     int64_t overlap_row_ids[] = { 0, 5, 5, 2, 9, 9, 14 };
374     uint64_t overlap_counts[]  = { 6, 1, 2, 6, 2, 10, 2 };
375 
376     REQUIRE_EXPR ( rowset = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
377 
378     for ( size_t i = 0; i < sizeof row_ids / sizeof row_ids[0]; ++i )
379     {
380         int64_t row_id = row_ids[i];
381         uint64_t count = counts[i];
382 
383         REQUIRE_EXPR ( KRowSetAddRowIdRange ( rowset, ctx, row_id, count ) );
384         for ( uint64_t j = 0; j < count; ++j )
385             inserted_rows_set.insert( row_id + j );
386     }
387 
388     for ( size_t i = 0; i < sizeof overlap_row_ids / sizeof overlap_row_ids[0]; ++i )
389     {
390         int64_t row_id = overlap_row_ids[i];
391         uint64_t count = overlap_counts[i];
392 
393         REQUIRE_EXPR ( KRowSetAddRowIdRange ( rowset, ctx, row_id, count ) );
394         for ( uint64_t j = 0; j < count; ++j )
395             inserted_rows_set.insert( row_id + j );
396     }
397     RunChecks ( rowset, inserted_rows_set );
398 
399     REQUIRE_EXPR ( KRowSetRelease( rowset, ctx ) );
400     EXIT;
401 }
402 
FIXTURE_TEST_CASE(KRowSetRowRangesDenseOverlapDuplicates,RowSetFixture)403 FIXTURE_TEST_CASE ( KRowSetRowRangesDenseOverlapDuplicates, RowSetFixture )
404 {
405     ENTRY;
406     KRowSet * rowset;
407     std::set<int64_t> inserted_rows_set;
408 
409     int64_t row_ids[] = { 0, 5, 10, 15, 20, 25, 30, 35, 40, 1000 };
410     uint64_t counts[]  = { 1, 1, 1,  1,  1,  1,  1,  1,  1,  1    };
411 
412     int64_t overlap_row_ids[] = { 500 };
413     uint64_t overlap_counts[]  = { 1000 };
414 
415     REQUIRE_EXPR ( rowset = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
416 
417     for ( size_t i = 0; i < sizeof row_ids / sizeof row_ids[0]; ++i )
418     {
419         int64_t row_id = row_ids[i];
420         uint64_t count = counts[i];
421 
422         REQUIRE_EXPR ( KRowSetAddRowIdRange ( rowset, ctx, row_id, count ) );
423         for ( uint64_t j = 0; j < count; ++j )
424             inserted_rows_set.insert( row_id + j );
425     }
426 
427     for ( size_t i = 0; i < sizeof overlap_row_ids / sizeof overlap_row_ids[0]; ++i )
428     {
429         int64_t row_id = overlap_row_ids[i];
430         uint64_t count = overlap_counts[i];
431 
432         REQUIRE_EXPR ( KRowSetAddRowIdRange ( rowset, ctx, row_id, count ) );
433         for ( uint64_t j = 0; j < count; ++j )
434             inserted_rows_set.insert( row_id + j );
435 
436     }
437     RunChecks ( rowset, inserted_rows_set );
438 
439     REQUIRE_EXPR ( KRowSetRelease( rowset, ctx ) );
440     EXIT;
441 }
442 
FIXTURE_TEST_CASE(KRowSetIterator,RowSetFixture)443 FIXTURE_TEST_CASE ( KRowSetIterator, RowSetFixture )
444 {
445     ENTRY;
446 
447     KRowSet * rowset;
448 
449     int64_t row_id_inserted = 55;
450 
451     REQUIRE_EXPR ( rowset = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
452     REQUIRE_EXPR ( KRowSetAddRowIdRange ( rowset, ctx, row_id_inserted, 1 ) );
453 
454     uint64_t num_rows;
455     REQUIRE_EXPR ( num_rows = KRowSetGetNumRowIds ( rowset, ctx ) );
456     REQUIRE_EQ ( num_rows, (uint64_t)1 );
457 
458     int64_t row_id_retrieved;
459     KRowSetIterator * it;
460     REQUIRE_EXPR ( it = KRowSetMakeIterator ( rowset, ctx ) );
461     REQUIRE_EXPR ( KRowSetRelease( rowset, ctx ) );
462     rowset = NULL;
463 
464     REQUIRE ( KRowSetIteratorIsValid ( it ) );
465     REQUIRE_EXPR ( row_id_retrieved = KRowSetIteratorGetRowId ( it, ctx ) );
466     REQUIRE_EQ ( row_id_inserted, row_id_retrieved );
467 
468     bool has_row;
469     REQUIRE_EXPR ( has_row = KRowSetIteratorNext ( it, ctx ) );
470     REQUIRE ( ! has_row );
471     REQUIRE ( ! KRowSetIteratorIsValid ( it ) );
472     REQUIRE_EXPR_FAILED ( KRowSetIteratorGetRowId ( it, ctx ) );
473     REQUIRE_EXPR_FAILED ( KRowSetIteratorNext ( it, ctx ) );
474 
475 //    // move forward out of boundaries and then move back
476 //    for ( int i = 0; i < move_out_boundaries; ++i )
477 //    {
478 //        REQUIRE_EXPR_FAILED ( KRowSetIteratorNext( it, ctx ) );
479 //        REQUIRE ( !KRowSetIteratorIsValid ( it ) );
480 //    }
481 //    for ( int i = move_out_boundaries - 1; i >= 0; --i )
482 //    {
483 //        rc_t rc = KRowSetIteratorPrev( it );
484 //        if ( i == 0 )
485 //        {
486 //            REQUIRE_RC ( rc );
487 //        }
488 //        else
489 //        {
490 //            REQUIRE_RC_FAIL ( rc );
491 //            REQUIRE ( !KRowSetIteratorIsValid ( it ) );
492 //        }
493 //    }
494 //    REQUIRE ( KRowSetIteratorIsValid ( it ) );
495 //    REQUIRE_RC ( KRowSetIteratorRowId ( it, &row_id_retrieved ) );
496 //    REQUIRE_EQ ( row_id_inserted, row_id_retrieved );
497 //
498 //    // move backward out of boundaries and then move back
499 //    for ( int i = 0; i < move_out_boundaries; ++i )
500 //    {
501 //        REQUIRE_RC_FAIL ( KRowSetIteratorPrev( it ) );
502 //        REQUIRE ( !KRowSetIteratorIsValid ( it ) );
503 //    }
504 //    for ( int i = move_out_boundaries - 1; i >= 0; --i )
505 //    {
506 //        rc_t rc = KRowSetIteratorNext( it );
507 //        if ( i == 0 )
508 //        {
509 //            REQUIRE_RC ( rc );
510 //        }
511 //        else
512 //        {
513 //            REQUIRE_RC_FAIL ( rc );
514 //            REQUIRE ( !KRowSetIteratorIsValid ( it ) );
515 //        }
516 //    }
517 //    REQUIRE ( KRowSetIteratorIsValid ( it ) );
518 //    REQUIRE_RC ( KRowSetIteratorRowId ( it, &row_id_retrieved ) );
519 //    REQUIRE_EQ ( row_id_inserted, row_id_retrieved );
520 
521     REQUIRE_EXPR ( KRowSetIteratorRelease ( it, ctx ) );
522     EXIT;
523 }
524 //
525 //FIXTURE_TEST_CASE ( KRowSetIteratorMoveForwardAndBackward, RowSetFixture )
526 //{
527 //    KRowSet * rowset;
528 //
529 //    int64_t row_ids[] = { 0, 5, 10, 15, 20, 25, 30, 35, 40, 1000, 100000 };
530 //
531 //    rowset = KTableMakeRowSet ( NULL, ctx );
532 //    for ( int i = 0; i < sizeof row_ids / sizeof row_ids[0]; ++i )
533 //    {
534 //        int64_t row_id = row_ids[i];
535 //        bool inserted;
536 //
537 //        REQUIRE_RC ( KRowSetAddRowId ( rowset, row_id, &inserted ) );
538 //        REQUIRE ( inserted );
539 //    }
540 //
541 //    uint64_t num_rows;
542 //    REQUIRE_RC ( KRowSetGetNumRowIds ( rowset, &num_rows ) );
543 //    REQUIRE_EQ ( num_rows, (uint64_t)sizeof row_ids / sizeof row_ids[0] );
544 //
545 //    KRowSetIterator * it;
546 //    REQUIRE_RC ( KRowSetMakeIterator ( rowset, &it ) );
547 //    REQUIRE_RC ( KRowSetRelease( rowset ) );
548 //    rowset = NULL;
549 //
550 //    // move forward
551 //    for ( int i = 0; i < sizeof row_ids / sizeof row_ids[0]; ++i )
552 //    {
553 //        int64_t row_id;
554 //
555 //        if ( i != 0 )
556 //            REQUIRE_RC ( KRowSetIteratorNext( it ) );
557 //
558 //        REQUIRE ( KRowSetIteratorIsValid ( it ) );
559 //        REQUIRE_RC ( KRowSetIteratorRowId ( it, &row_id ) );
560 //        REQUIRE_EQ ( row_id, row_ids[i] );
561 //    }
562 //
563 //    // move backward
564 //    for ( int i = sizeof row_ids / sizeof row_ids[0] - 1; i >= 0; --i )
565 //    {
566 //        int64_t row_id;
567 //
568 //        if ( i != sizeof row_ids / sizeof row_ids[0] - 1 )
569 //            REQUIRE_RC ( KRowSetIteratorPrev( it ) );
570 //
571 //        REQUIRE ( KRowSetIteratorIsValid ( it ) );
572 //        REQUIRE_RC ( KRowSetIteratorRowId ( it, &row_id ) );
573 //        REQUIRE_EQ ( row_id, row_ids[i] );
574 //    }
575 //
576 //    REQUIRE_RC ( KRowSetIteratorRelease ( it ) );
577 //}
578 
FIXTURE_TEST_CASE(KRowSetIteratorOverEmptySet,RowSetFixture)579 FIXTURE_TEST_CASE ( KRowSetIteratorOverEmptySet, RowSetFixture )
580 {
581     ENTRY;
582     KRowSet * rowset;
583     REQUIRE_EXPR ( rowset = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
584 
585     KRowSetIterator * it;
586     REQUIRE_EXPR ( it = KRowSetMakeIterator ( rowset, ctx ) );
587     REQUIRE ( !KRowSetIteratorIsValid ( it ) );
588 
589     REQUIRE_EXPR ( KRowSetIteratorRelease( it, ctx ) );
590     REQUIRE_EXPR ( KRowSetRelease( rowset, ctx ) );
591     EXIT;
592 }
593 
FIXTURE_TEST_CASE(KRowSetIntersectSimpleTest,RowSetFixture)594 FIXTURE_TEST_CASE ( KRowSetIntersectSimpleTest, RowSetFixture )
595 {
596     ENTRY;
597     KRowSet * rowset1;
598     KRowSet * rowset2;
599     std::set<int64_t> inserted_rows_set1;
600     std::set<int64_t> inserted_rows_set2;
601 
602     REQUIRE_EXPR ( rowset1 = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
603     REQUIRE_EXPR ( rowset2 = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
604 
605     for ( int i = 0; i < 5000; ++i )
606     {
607         int64_t row_id = GenerateId ( -1, -1 );
608         if ( inserted_rows_set1.find( row_id ) ==  inserted_rows_set1.end() )
609         {
610             REQUIRE_EXPR ( KRowSetAddRowId ( rowset1, ctx, row_id) );
611             inserted_rows_set1.insert( row_id );
612             // just don't insert a single row to a second rowset, but otherwise keep them equal
613             if ( i != 0 )
614             {
615                 REQUIRE_EXPR ( KRowSetAddRowId ( rowset2, ctx, row_id) );
616                 inserted_rows_set2.insert( row_id );
617             }
618         }
619         else
620             --i;
621     }
622 
623     KRowSet * rowset_result;
624     REQUIRE_EXPR ( rowset_result = KRowSetIntersect ( ctx, rowset1, rowset2 ) );
625 
626     RunChecks ( rowset1, inserted_rows_set1 );
627     RunChecks ( rowset2, inserted_rows_set2 );
628     RunChecks ( rowset_result, inserted_rows_set2 );
629 
630     REQUIRE_EXPR ( KRowSetRelease( rowset1, ctx ) );
631     REQUIRE_EXPR ( KRowSetRelease( rowset2, ctx ) );
632     REQUIRE_EXPR ( KRowSetRelease( rowset_result, ctx ) );
633     EXIT;
634 }
635 
FIXTURE_TEST_CASE(KRowSetIntersectNormalTest,RowSetFixture)636 FIXTURE_TEST_CASE ( KRowSetIntersectNormalTest, RowSetFixture )
637 {
638     ENTRY;
639     // check all 4 combinations of dense/scattered leaves
640     for ( int i = 0; i < 4; ++i )
641     {
642         KRowSet * rowset1;
643         KRowSet * rowset2;
644         KRowSet * rowset_result;
645         std::set<int64_t> inserted_rows_set1;
646         std::set<int64_t> inserted_rows_set2;
647         std::set<int64_t> intersection_set;
648 
649         REQUIRE_EXPR ( rowset1 = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
650         REQUIRE_EXPR ( rowset2 = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
651 
652         inserted_rows_set1 = InsertRandomRows ( rowset1, 5000, (i & 1) ? 8 : 0 );
653         inserted_rows_set2 = InsertRandomRows ( rowset2, 5000, (i & 2) ? 8 : 0 );
654 
655         RunChecks ( rowset1, inserted_rows_set1 );
656         RunChecks ( rowset2, inserted_rows_set2 );
657 
658         REQUIRE_EXPR ( rowset_result = KRowSetIntersect ( ctx, rowset1, rowset2 ) );
659         intersection_set = SetIntersection ( inserted_rows_set1, inserted_rows_set2 );
660 
661         RunChecks ( rowset_result, intersection_set );
662         RunChecks ( rowset1, inserted_rows_set1 );
663         RunChecks ( rowset2, inserted_rows_set2 );
664         REQUIRE_EXPR ( KRowSetRelease( rowset_result, ctx ) );
665 
666         REQUIRE_EXPR ( rowset_result =  KRowSetIntersect ( ctx, rowset2, rowset1 ) );
667         RunChecks ( rowset_result, intersection_set );
668         RunChecks ( rowset1, inserted_rows_set1 );
669         RunChecks ( rowset2, inserted_rows_set2 );
670 
671         REQUIRE_EXPR ( KRowSetRelease( rowset1, ctx ) );
672         REQUIRE_EXPR ( KRowSetRelease( rowset2, ctx ) );
673         REQUIRE_EXPR ( KRowSetRelease( rowset_result, ctx ) );
674     }
675     EXIT;
676 }
677 
FIXTURE_TEST_CASE(KRowSetUnionSimpleTest,RowSetFixture)678 FIXTURE_TEST_CASE ( KRowSetUnionSimpleTest, RowSetFixture )
679 {
680     ENTRY;
681     KRowSet * rowset1;
682     KRowSet * rowset2;
683     std::set<int64_t> inserted_rows_set1;
684     std::set<int64_t> inserted_rows_set2;
685 
686     REQUIRE_EXPR ( rowset1 = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
687     REQUIRE_EXPR ( rowset2 = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
688 
689     for ( int i = 0; i < 5000; ++i )
690     {
691         int64_t row_id = GenerateId ( -1, -1 );
692         if ( inserted_rows_set1.find( row_id ) ==  inserted_rows_set1.end() )
693         {
694             REQUIRE_EXPR ( KRowSetAddRowId ( rowset1, ctx, row_id) );
695             inserted_rows_set1.insert( row_id );
696             // just don't insert a single row to a second rowset, but otherwise keep them equal
697             if ( i != 0 )
698             {
699                 REQUIRE_EXPR ( KRowSetAddRowId ( rowset2, ctx, row_id) );
700                 inserted_rows_set2.insert( row_id );
701             }
702         }
703         else
704             --i;
705     }
706 
707     KRowSet * rowset_result;
708     REQUIRE_EXPR ( rowset_result = KRowSetUnion ( ctx, rowset1, rowset2 ) );
709 
710     RunChecks ( rowset1, inserted_rows_set1 );
711     RunChecks ( rowset2, inserted_rows_set2 );
712     RunChecks ( rowset_result, inserted_rows_set1 );
713 
714     REQUIRE_EXPR ( KRowSetRelease( rowset1, ctx ) );
715     REQUIRE_EXPR ( KRowSetRelease( rowset2, ctx ) );
716     REQUIRE_EXPR ( KRowSetRelease( rowset_result, ctx ) );
717     EXIT;
718 }
719 
FIXTURE_TEST_CASE(KRowSetUnionNormalTest,RowSetFixture)720 FIXTURE_TEST_CASE ( KRowSetUnionNormalTest, RowSetFixture )
721 {
722     ENTRY;
723     // check all 4 combinations of dense/scattered leaves
724     for ( int i = 0; i < 4; ++i )
725     {
726         KRowSet * rowset1;
727         KRowSet * rowset2;
728         KRowSet * rowset_result;
729         std::set<int64_t> inserted_rows_set1;
730         std::set<int64_t> inserted_rows_set2;
731         std::set<int64_t> union_set;
732 
733         REQUIRE_EXPR ( rowset1 = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
734         REQUIRE_EXPR ( rowset2 = KTableMakeRowSet ( GetTable ( GetName() ), ctx ) );
735 
736         inserted_rows_set1 = InsertRandomRows ( rowset1, 5000, (i & 1) ? 8 : 0 );
737         inserted_rows_set2 = InsertRandomRows ( rowset2, 5000, (i & 2) ? 8 : 0 );
738 
739         RunChecks ( rowset1, inserted_rows_set1 );
740         RunChecks ( rowset2, inserted_rows_set2 );
741 
742         REQUIRE_EXPR ( rowset_result = KRowSetUnion ( ctx, rowset1, rowset2 ) );
743         union_set = SetUnion ( inserted_rows_set1, inserted_rows_set2 );
744 
745         RunChecks ( rowset_result, union_set );
746         RunChecks ( rowset1, inserted_rows_set1 );
747         RunChecks ( rowset2, inserted_rows_set2 );
748         REQUIRE_EXPR ( KRowSetRelease( rowset_result, ctx ) );
749 
750         REQUIRE_EXPR ( rowset_result =  KRowSetUnion ( ctx, rowset2, rowset1 ) );
751         RunChecks ( rowset_result, union_set );
752         RunChecks ( rowset1, inserted_rows_set1 );
753         RunChecks ( rowset2, inserted_rows_set2 );
754 
755         REQUIRE_EXPR ( KRowSetRelease( rowset1, ctx ) );
756         REQUIRE_EXPR ( KRowSetRelease( rowset2, ctx ) );
757         REQUIRE_EXPR ( KRowSetRelease( rowset_result, ctx ) );
758     }
759     EXIT;
760 }
761 
762 //////////////////////////////////////////// Main
763 extern "C"
764 {
765 
766 #include <kapp/main.h>
767 #include <kapp/args.h>
768 
KAppVersion(void)769 ver_t CC KAppVersion ( void )
770 {
771     return 0;
772 }
773 
774 
775 const char UsageDefaultName[] = "test-rowset";
776 
UsageSummary(const char * progname)777 rc_t CC UsageSummary ( const char *progname )
778 {
779     return KOutMsg ( "\n"
780                      "Usage:\n"
781                      "  %s [Options] <target>\n"
782                      "\n"
783                      "Summary:\n"
784                      "  test the rowset.\n"
785                      , progname
786         );
787 }
788 
Usage(const Args * args)789 rc_t CC Usage ( const Args *args )
790 {
791     const char * progname = UsageDefaultName;
792     const char * fullpath = UsageDefaultName;
793     rc_t rc;
794 
795     if (args == NULL)
796         rc = RC (rcApp, rcArgv, rcAccessing, rcSelf, rcNull);
797     else
798         rc = ArgsProgram (args, &fullpath, &progname);
799     if (rc)
800         progname = fullpath = UsageDefaultName;
801 
802     UsageSummary (progname);
803 
804     KOutMsg ("Options:\n");
805 
806     HelpOptionsStandard ();
807 
808     HelpVersion (fullpath, KAppVersion());
809 
810     return rc;
811 }
KMain(int argc,char * argv[])812 rc_t CC KMain ( int argc, char *argv [] )
813 {
814     srand ( time(NULL) );
815     return KRowSetTestSuite(argc, argv);
816 }
817 
818 }
819 
820