AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdlib.h>5#include <string.h>6#include <stdint.h>7 8/* Wrapper for the static function provided by the module */9extern void test_statInit(sqlite3_context*, int, sqlite3_value**);10 11static int register_stat_init(sqlite3 *db){12 /* Register the test wrapper as a scalar SQL function with 4 args */13 return sqlite3_create_function(db, "stat_init_test", 4, SQLITE_UTF8, 0,14 test_statInit, 0, 0);15}16 17/* Helper: run SELECT stat_init_test(N,K,C,L) and return the blob size. 18 Returns SQLITE_OK on success and sets *pSize>0. */19static int get_stat_init_blob_size(sqlite3 *db, int N, int K, sqlite3_int64 C,20 int L, int *pSize){21 int rc;22 sqlite3_stmt *pStmt = 0;23 const void *pBlob = 0;24 int nBlob = 0;25 26 *pSize = 0;27 28 rc = register_stat_init(db);29 if( rc!=SQLITE_OK ) return rc;30 31 rc = sqlite3_prepare_v2(db, "SELECT stat_init_test(?1,?2,?3,?4)", -1, &pStmt, 0);32 if( rc!=SQLITE_OK ) return rc;33 34 sqlite3_bind_int(pStmt, 1, N);35 sqlite3_bind_int(pStmt, 2, K);36 sqlite3_bind_int64(pStmt, 3, C);37 sqlite3_bind_int(pStmt, 4, L);38 39 rc = sqlite3_step(pStmt);40 if( rc==SQLITE_ROW ){41 nBlob = sqlite3_column_bytes(pStmt, 0);42 pBlob = sqlite3_column_blob(pStmt, 0);43 /* Finalize before returning. The destructor for the result will be invoked44 by SQLite once the row value is no longer needed internally. */45 rc = sqlite3_finalize(pStmt);46 if( rc!=SQLITE_OK ) return rc;47 48 if( nBlob<=0 || pBlob==NULL ){49 /* Should never happen: statInit always returns a non-empty blob */50 return SQLITE_ERROR;51 }52 *pSize = nBlob;53 return SQLITE_OK;54 }else{55 int rc2 = sqlite3_finalize(pStmt);56 if( rc==SQLITE_DONE && rc2==SQLITE_OK ){57 return SQLITE_ERROR;58 }59 return rc!=SQLITE_ROW ? rc : rc2;60 }61}62 63void setUp(void) {64 /* No global setup needed */65}66 67void tearDown(void) {68 /* No global teardown needed */69}70 71/* Test that stat_init returns a non-null, positive-length blob */72void test_statInit_basic_returns_blob(void){73 sqlite3 *db = 0;74 int rc = sqlite3_open(":memory:", &db);75 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);76 77 int sz = 0;78 rc = get_stat_init_blob_size(db, /*N*/2, /*K*/1, /*C*/1000, /*L*/0, &sz);79 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);80 TEST_ASSERT_MESSAGE(sz > 0, "stat_init_test returned zero-length blob");81 82 sqlite3_close(db);83}84 85/* Test that size is non-decreasing as N increases (for valid K<=N) */86void test_statInit_size_monotonic_with_N(void){87 sqlite3 *db = 0;88 int rc = sqlite3_open(":memory:", &db);89 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);90 91 int sz1=0, sz2=0, sz3=0, sz5=0;92 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, 1, 1, 100, 0, &sz1));93 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, 2, 1, 100, 0, &sz2));94 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, 3, 2, 100, 0, &sz3));95 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, 5, 3, 100, 0, &sz5));96 97 TEST_ASSERT_MESSAGE(sz2 >= sz1, "Size did not increase or stay the same from N=1 to N=2");98 TEST_ASSERT_MESSAGE(sz3 >= sz2, "Size did not increase or stay the same from N=2 to N=3");99 TEST_ASSERT_MESSAGE(sz5 >= sz3, "Size did not increase or stay the same from N=3 to N=5");100 101 sqlite3_close(db);102}103 104/* Test that size is independent of K (for fixed N) */105void test_statInit_size_independent_of_K(void){106 sqlite3 *db = 0;107 int rc = sqlite3_open(":memory:", &db);108 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);109 110 int N = 4;111 int szK1=0, szK2=0, szK4=0;112 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, N, 1, 1000, 0, &szK1));113 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, N, 2, 1000, 0, &szK2));114 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, N, 4, 1000, 0, &szK4));115 116 TEST_ASSERT_EQUAL_INT(szK1, szK2);117 TEST_ASSERT_EQUAL_INT(szK2, szK4);118 119 sqlite3_close(db);120}121 122/* Test that size is independent of the estimated row count C */123void test_statInit_size_independent_of_C(void){124 sqlite3 *db = 0;125 int rc = sqlite3_open(":memory:", &db);126 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);127 128 int szSmall=0, szLarge=0;129 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, 3, 2, 10, 0, &szSmall));130 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, 3, 2, 1000000, 0, &szLarge));131 132 TEST_ASSERT_EQUAL_INT(szSmall, szLarge);133 134 sqlite3_close(db);135}136 137/* Test that when L!=0, size is less-than-or-equal to size when L==0 */138void test_statInit_size_with_limit_le_without_limit(void){139 sqlite3 *db = 0;140 int rc = sqlite3_open(":memory:", &db);141 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);142 143 int szNoLimit=0, szWithLimit=0;144 145 /* Choose an N that is large enough to expose differences if STAT4 is enabled */146 int N = 6;147 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, N, 3, 10000, 0, &szNoLimit));148 TEST_ASSERT_EQUAL_INT(SQLITE_OK, get_stat_init_blob_size(db, N, 3, 10000, 50, &szWithLimit));149 150 TEST_ASSERT_MESSAGE(szWithLimit <= szNoLimit,151 "Size with non-zero limit should be <= size with zero limit");152 153 sqlite3_close(db);154}155 156int main(void) {157 UNITY_BEGIN();158 RUN_TEST(test_statInit_basic_returns_blob);159 RUN_TEST(test_statInit_size_monotonic_with_N);160 RUN_TEST(test_statInit_size_independent_of_K);161 RUN_TEST(test_statInit_size_independent_of_C);162 RUN_TEST(test_statInit_size_with_limit_le_without_limit);163 return UNITY_END();164}