AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Wrapper for the static function under test (provided by module for testing) */7extern int test_loadStat4(sqlite3 *db, const char *zDb);8 9/* Global connection for tests; opened per-test and closed in tearDown */10static sqlite3 *g_db = NULL;11 12/* Helpers */13static void exec_sql(sqlite3 *db, const char *zSql){14 char *zErr = 0;15 int rc = sqlite3_exec(db, zSql, 0, 0, &zErr);16 if( rc!=SQLITE_OK ){17 const char *msg = zErr ? zErr : "exec_sql failed";18 TEST_FAIL_MESSAGE(msg);19 }20 if( zErr ) sqlite3_free(zErr);21}22 23void setUp(void) {24 g_db = NULL;25}26 27void tearDown(void) {28 if( g_db ){29 /* Close DB; this will clean up any allocated schema objects as well */30 sqlite3_close(g_db);31 g_db = NULL;32 }33}34 35/* Test: No sqlite_stat4 table present -> no changes, SQLITE_OK */36void test_loadStat4_no_stat4_table(void){37 int rc;38 Index *pIdx;39 40 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &g_db));41 /* Disable lookaside as required by loadStat4 assertions */42 g_db->lookaside.bDisable = 1;43 44 exec_sql(g_db, "CREATE TABLE t(a, b, c);");45 exec_sql(g_db, "CREATE INDEX i_ab ON t(a, b);");46 47 rc = test_loadStat4(g_db, "main");48 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);49 50 pIdx = sqlite3FindIndex(g_db, "i_ab", "main");51 TEST_ASSERT_NOT_NULL(pIdx);52 TEST_ASSERT_EQUAL_INT(0, pIdx->nSample);53 TEST_ASSERT_EQUAL_INT(0, pIdx->mxSample);54 TEST_ASSERT_NULL(pIdx->aSample);55}56 57/* Test: Single sample for a rowid table index; verify arrays and blob padding */58void test_loadStat4_single_sample_rowid_index(void){59 int rc;60 Index *pIdx;61 62 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &g_db));63 g_db->lookaside.bDisable = 1;64 65 /* Schema: rowid table with a 2-column index (implies nColumn==nKeyCol+1) */66 exec_sql(g_db, "CREATE TABLE t(a, b, c);");67 exec_sql(g_db, "CREATE INDEX i_ab ON t(a, b);");68 69 /* Create sqlite_stat4 and insert one row for index i_ab.70 For a rowid table, nSampleCol = pIdx->nColumn = nKeyCol + 1 = 3. */71 exec_sql(g_db, "CREATE TABLE sqlite_stat4(idx TEXT, neq TEXT, nlt TEXT, ndlt TEXT, sample BLOB);");72 exec_sql(g_db,73 "INSERT INTO sqlite_stat4(idx,neq,nlt,ndlt,sample) "74 "VALUES('i_ab','100 10 1','40 20 10','39 19 9',X'11223344');"75 );76 77 rc = test_loadStat4(g_db, "main");78 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);79 80 pIdx = sqlite3FindIndex(g_db, "i_ab", "main");81 TEST_ASSERT_NOT_NULL(pIdx);82 83 /* nSampleCol should equal nColumn (3) for rowid table non-PK index */84 TEST_ASSERT_EQUAL_INT(pIdx->nColumn, pIdx->nSampleCol);85 TEST_ASSERT_EQUAL_INT(3, pIdx->nSampleCol);86 87 TEST_ASSERT_EQUAL_INT(1, pIdx->mxSample); /* count(*) per idx */88 TEST_ASSERT_EQUAL_INT(1, pIdx->nSample);89 TEST_ASSERT_NOT_NULL(pIdx->aSample);90 TEST_ASSERT_NOT_NULL(pIdx->aAvgEq);91 92 /* Verify decoded integer arrays */93 TEST_ASSERT_EQUAL_INT64(100, pIdx->aSample[0].anEq[0]);94 TEST_ASSERT_EQUAL_INT64(10, pIdx->aSample[0].anEq[1]);95 TEST_ASSERT_EQUAL_INT64(1, pIdx->aSample[0].anEq[2]);96 97 TEST_ASSERT_EQUAL_INT64(40, pIdx->aSample[0].anLt[0]);98 TEST_ASSERT_EQUAL_INT64(20, pIdx->aSample[0].anLt[1]);99 TEST_ASSERT_EQUAL_INT64(10, pIdx->aSample[0].anLt[2]);100 101 TEST_ASSERT_EQUAL_INT64(39, pIdx->aSample[0].anDLt[0]);102 TEST_ASSERT_EQUAL_INT64(19, pIdx->aSample[0].anDLt[1]);103 TEST_ASSERT_EQUAL_INT64(9, pIdx->aSample[0].anDLt[2]);104 105 /* Verify sample blob copy and 8 trailing zero bytes */106 {107 const unsigned char *p = (const unsigned char*)pIdx->aSample[0].p;108 int n = pIdx->aSample[0].n;109 TEST_ASSERT_NOT_NULL(p);110 TEST_ASSERT_EQUAL_INT(4, n);111 TEST_ASSERT_EQUAL_UINT8(0x11, p[0]);112 TEST_ASSERT_EQUAL_UINT8(0x22, p[1]);113 TEST_ASSERT_EQUAL_UINT8(0x33, p[2]);114 TEST_ASSERT_EQUAL_UINT8(0x44, p[3]);115 /* Check 8 zero bytes padding */116 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+0]);117 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+1]);118 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+2]);119 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+3]);120 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+4]);121 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+5]);122 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+6]);123 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+7]);124 }125}126 127/* Test: Multiple samples for same index; verify mxSample and nSample */128void test_loadStat4_multiple_samples(void){129 int rc;130 Index *pIdx;131 132 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &g_db));133 g_db->lookaside.bDisable = 1;134 135 exec_sql(g_db, "CREATE TABLE t(a, b, c);");136 exec_sql(g_db, "CREATE INDEX i_ab ON t(a, b);");137 138 exec_sql(g_db, "CREATE TABLE sqlite_stat4(idx TEXT, neq TEXT, nlt TEXT, ndlt TEXT, sample BLOB);");139 /* Provide two rows; each with 3 integers for rowid table index */140 exec_sql(g_db,141 "INSERT INTO sqlite_stat4 VALUES('i_ab','100 10 1','40 20 10','39 19 9',X'01');"142 );143 exec_sql(g_db,144 "INSERT INTO sqlite_stat4 VALUES('i_ab','200 20 2','80 40 20','79 39 19',X'0203');"145 );146 147 rc = test_loadStat4(g_db, "main");148 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);149 150 pIdx = sqlite3FindIndex(g_db, "i_ab", "main");151 TEST_ASSERT_NOT_NULL(pIdx);152 153 TEST_ASSERT_EQUAL_INT(2, pIdx->mxSample);154 TEST_ASSERT_EQUAL_INT(2, pIdx->nSample);155 TEST_ASSERT_NOT_NULL(pIdx->aSample);156 TEST_ASSERT_NOT_NULL(pIdx->aSample[0].p);157 TEST_ASSERT_NOT_NULL(pIdx->aSample[1].p);158}159 160/* Test: WITHOUT ROWID table primary key: nSampleCol should be nKeyCol */161void test_loadStat4_without_rowid_pk(void){162 int rc;163 Table *pTab;164 Index *pPk;165 166 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &g_db));167 g_db->lookaside.bDisable = 1;168 169 /* WITHOUT ROWID table with composite primary key (2 cols) */170 exec_sql(g_db, "CREATE TABLE w(a INTEGER, b INTEGER, c TEXT, PRIMARY KEY(a,b)) WITHOUT ROWID;");171 172 /* Insert stat4 row that refers to the PRIMARY KEY by using idx=table-name.173 For WITHOUT ROWID PK index, nSampleCol should be nKeyCol (2). */174 exec_sql(g_db, "CREATE TABLE sqlite_stat4(idx TEXT, neq TEXT, nlt TEXT, ndlt TEXT, sample BLOB);");175 exec_sql(g_db,176 "INSERT INTO sqlite_stat4(idx,neq,nlt,ndlt,sample) "177 "VALUES('w','300 30','90 9','80 8',X'A55A');"178 );179 180 rc = test_loadStat4(g_db, "main");181 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);182 183 pTab = sqlite3FindTable(g_db, "w", "main");184 TEST_ASSERT_NOT_NULL(pTab);185 pPk = sqlite3PrimaryKeyIndex(pTab);186 TEST_ASSERT_NOT_NULL(pPk);187 188 /* Verify nSampleCol equals nKeyCol (2) and arrays populated accordingly */189 TEST_ASSERT_EQUAL_INT(pPk->nKeyCol, pPk->nSampleCol);190 TEST_ASSERT_EQUAL_INT(2, pPk->nSampleCol);191 TEST_ASSERT_EQUAL_INT(1, pPk->mxSample);192 TEST_ASSERT_EQUAL_INT(1, pPk->nSample);193 TEST_ASSERT_NOT_NULL(pPk->aSample);194 195 TEST_ASSERT_EQUAL_INT64(300, pPk->aSample[0].anEq[0]);196 TEST_ASSERT_EQUAL_INT64(30, pPk->aSample[0].anEq[1]);197 198 TEST_ASSERT_EQUAL_INT64(90, pPk->aSample[0].anLt[0]);199 TEST_ASSERT_EQUAL_INT64(9, pPk->aSample[0].anLt[1]);200 201 TEST_ASSERT_EQUAL_INT64(80, pPk->aSample[0].anDLt[0]);202 TEST_ASSERT_EQUAL_INT64(8, pPk->aSample[0].anDLt[1]);203 204 /* Verify blob padding */205 {206 const unsigned char *p = (const unsigned char*)pPk->aSample[0].p;207 int n = pPk->aSample[0].n;208 TEST_ASSERT_NOT_NULL(p);209 TEST_ASSERT_EQUAL_INT(2, n);210 TEST_ASSERT_EQUAL_UINT8(0xA5, p[0]);211 TEST_ASSERT_EQUAL_UINT8(0x5A, p[1]);212 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+0]);213 TEST_ASSERT_EQUAL_UINT8(0x00, p[n+7]);214 }215}216 217int main(void){218 UNITY_BEGIN();219 RUN_TEST(test_loadStat4_no_stat4_table);220 RUN_TEST(test_loadStat4_single_sample_rowid_index);221 RUN_TEST(test_loadStat4_multiple_samples);222 RUN_TEST(test_loadStat4_without_rowid_pk);223 return UNITY_END();224}