Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_analyze_analysisLoader.c236 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Wrapper for calling the static function under test. */7extern int test_analysisLoader(void *pData, int argc, char **argv, char **NotUsed);8 9/* Use an opaque struct that matches the first fields of analysisInfo */10typedef struct {11  sqlite3 *db;12  const char *zDatabase;13} MyAnalysisInfo;14 15static sqlite3 *gDb = NULL;16 17static void execSql(sqlite3 *db, const char *zSql){18  char *zErr = NULL;19  int rc = sqlite3_exec(db, zSql, 0, 0, &zErr);20  if( rc!=SQLITE_OK ){21    /* Help debugging test failures */22    const char *msg = zErr ? zErr : "(no error message)";23    TEST_FAIL_MESSAGE(msg);24  }25  sqlite3_free(zErr);26}27 28void setUp(void) {29  int rc = sqlite3_open(":memory:", &gDb);30  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);31  TEST_ASSERT_NOT_NULL(gDb);32}33 34void tearDown(void) {35  if( gDb ){36    sqlite3_close(gDb);37    gDb = NULL;38  }39}40 41static char *dupz(const char *z){42  /* Allocate mutable copy for argv[2] */43  size_t n = strlen(z);44  char *out = (char*)sqlite3_malloc64(n+1);45  TEST_ASSERT_NOT_NULL(out);46  memcpy(out, z, n+1);47  return out;48}49 50/* Basic index stat row updates index and table */51void test_analysisLoader_index_basic(void){52  execSql(gDb, "CREATE TABLE t1(a, b);");53  execSql(gDb, "CREATE INDEX i1 ON t1(a, b);");54 55  Table *pTab = sqlite3FindTable(gDb, "t1", "main");56  Index *pIdx = sqlite3FindIndex(gDb, "i1", "main");57  TEST_ASSERT_NOT_NULL(pTab);58  TEST_ASSERT_NOT_NULL(pIdx);59 60  MyAnalysisInfo info = { gDb, "main" };61  char *azArg[3];62  azArg[0] = (char*)"t1";63  azArg[1] = (char*)"i1";64  azArg[2] = dupz("1000 10 1");65 66  int rc = test_analysisLoader(&info, 3, azArg, NULL);67  TEST_ASSERT_EQUAL_INT(0, rc);68 69  TEST_ASSERT_EQUAL_INT(1, pIdx->hasStat1);70  TEST_ASSERT_EQUAL_INT(0, pIdx->bUnordered);71  TEST_ASSERT_TRUE((pTab->tabFlags & TF_HasStat1)!=0);72  TEST_ASSERT_EQUAL_INT(pIdx->aiRowLogEst[0], pTab->nRowLogEst);73 74  sqlite3_free(azArg[2]);75}76 77/* "unordered" suffix sets bUnordered */78void test_analysisLoader_index_unordered(void){79  execSql(gDb, "CREATE TABLE t1(a, b);");80  execSql(gDb, "CREATE INDEX i1 ON t1(a, b);");81 82  Table *pTab = sqlite3FindTable(gDb, "t1", "main");83  Index *pIdx = sqlite3FindIndex(gDb, "i1", "main");84  TEST_ASSERT_NOT_NULL(pTab);85  TEST_ASSERT_NOT_NULL(pIdx);86 87  MyAnalysisInfo info = { gDb, "main" };88  char *azArg[3];89  azArg[0] = (char*)"t1";90  azArg[1] = (char*)"i1";91  azArg[2] = dupz("100 5 1 unordered");92 93  int rc = test_analysisLoader(&info, 3, azArg, NULL);94  TEST_ASSERT_EQUAL_INT(0, rc);95 96  TEST_ASSERT_EQUAL_INT(1, pIdx->hasStat1);97  TEST_ASSERT_EQUAL_INT(1, pIdx->bUnordered);98  TEST_ASSERT_TRUE((pTab->tabFlags & TF_HasStat1)!=0);99  TEST_ASSERT_EQUAL_INT(pIdx->aiRowLogEst[0], pTab->nRowLogEst);100 101  sqlite3_free(azArg[2]);102}103 104/* Table-only entry (argv[1]==NULL) sets TF_HasStat1 on table */105void test_analysisLoader_table_only_entry(void){106  execSql(gDb, "CREATE TABLE t2(x);");107 108  Table *pTab = sqlite3FindTable(gDb, "t2", "main");109  TEST_ASSERT_NOT_NULL(pTab);110  LogEst before = pTab->nRowLogEst;111 112  MyAnalysisInfo info = { gDb, "main" };113  char *azArg[3];114  azArg[0] = (char*)"t2";115  azArg[1] = NULL;116  azArg[2] = dupz("12345");117 118  int rc = test_analysisLoader(&info, 3, azArg, NULL);119  TEST_ASSERT_EQUAL_INT(0, rc);120 121  TEST_ASSERT_TRUE((pTab->tabFlags & TF_HasStat1)!=0);122  /* nRowLogEst may or may not equal before depending on decodeIntArray; ensure it is a valid LogEst */123  TEST_ASSERT_TRUE(pTab->nRowLogEst <= 60); /* sanity: LogEst upper bound */124  sqlite3_free(azArg[2]);125}126 127/* Non-existent table should be ignored (return 0, no crash) */128void test_analysisLoader_nonexistent_table(void){129  MyAnalysisInfo info = { gDb, "main" };130  char *azArg[3];131  azArg[0] = (char*)"nosuchtable";132  azArg[1] = (char*)"nosuchindex";133  azArg[2] = dupz("1");134 135  int rc = test_analysisLoader(&info, 3, azArg, NULL);136  TEST_ASSERT_EQUAL_INT(0, rc);137 138  sqlite3_free(azArg[2]);139}140 141/* NULL argv and NULL fields handling */142void test_analysisLoader_null_argv_variants(void){143  MyAnalysisInfo info = { gDb, "main" };144 145  /* argv==NULL */146  int rc = test_analysisLoader(&info, 3, NULL, NULL);147  TEST_ASSERT_EQUAL_INT(0, rc);148 149  /* argv[0]==NULL, argv[2]==NULL */150  char *azArgA[3] = { NULL, NULL, NULL };151  rc = test_analysisLoader(&info, 3, azArgA, NULL);152  TEST_ASSERT_EQUAL_INT(0, rc);153 154  /* argv[2]==NULL */155  execSql(gDb, "CREATE TABLE t1x(a);");156  execSql(gDb, "CREATE INDEX i1x ON t1x(a);");157  char *azArgB[3];158  azArgB[0] = (char*)"t1x";159  azArgB[1] = (char*)"i1x";160  azArgB[2] = NULL;161  rc = test_analysisLoader(&info, 3, azArgB, NULL);162  TEST_ASSERT_EQUAL_INT(0, rc);163}164 165/* argv[1]==argv[0] => use PRIMARY KEY index path */166void test_analysisLoader_pk_index_path(void){167  execSql(gDb, "CREATE TABLE t3(a INTEGER PRIMARY KEY, b);");168 169  Table *pTab = sqlite3FindTable(gDb, "t3", "main");170  TEST_ASSERT_NOT_NULL(pTab);171  Index *pPk = sqlite3PrimaryKeyIndex(pTab);172  TEST_ASSERT_NOT_NULL(pPk);173 174  MyAnalysisInfo info = { gDb, "main" };175  char *azArg[3];176  azArg[0] = (char*)"t3";177  azArg[1] = (char*)"t3"; /* triggers sqlite3PrimaryKeyIndex path */178  azArg[2] = dupz("100 1");179 180  int rc = test_analysisLoader(&info, 3, azArg, NULL);181  TEST_ASSERT_EQUAL_INT(0, rc);182 183  TEST_ASSERT_EQUAL_INT(1, pPk->hasStat1);184  TEST_ASSERT_TRUE((pTab->tabFlags & TF_HasStat1)!=0);185  TEST_ASSERT_EQUAL_INT(pPk->aiRowLogEst[0], pTab->nRowLogEst);186 187  sqlite3_free(azArg[2]);188}189 190/* Partial index stats must not overwrite table nRowLogEst */191void test_analysisLoader_partial_index_does_not_override_table_rowcount(void){192  execSql(gDb, "CREATE TABLE t4(a, b);");193  execSql(gDb, "CREATE INDEX ip ON t4(a) WHERE b IS NOT NULL;");194 195  Table *pTab = sqlite3FindTable(gDb, "t4", "main");196  Index *pPartial = sqlite3FindIndex(gDb, "ip", "main");197  TEST_ASSERT_NOT_NULL(pTab);198  TEST_ASSERT_NOT_NULL(pPartial);199  TEST_ASSERT_NOT_NULL(pPartial->pPartIdxWhere); /* ensure it is partial */200 201  MyAnalysisInfo info = { gDb, "main" };202 203  /* First, set table-only stat to establish a baseline */204  char *azTbl[3];205  azTbl[0] = (char*)"t4";206  azTbl[1] = NULL;207  azTbl[2] = dupz("100");208  int rc = test_analysisLoader(&info, 3, azTbl, NULL);209  TEST_ASSERT_EQUAL_INT(0, rc);210  LogEst base = pTab->nRowLogEst;211  sqlite3_free(azTbl[2]);212 213  /* Now, provide stats for the partial index; should not change table nRowLogEst */214  char *azIdx[3];215  azIdx[0] = (char*)"t4";216  azIdx[1] = (char*)"ip";217  azIdx[2] = dupz("1000 10");218  rc = test_analysisLoader(&info, 3, azIdx, NULL);219  TEST_ASSERT_EQUAL_INT(0, rc);220  TEST_ASSERT_EQUAL_INT(1, pPartial->hasStat1);221  TEST_ASSERT_EQUAL_INT(base, pTab->nRowLogEst); /* unchanged */222 223  sqlite3_free(azIdx[2]);224}225 226int main(void){227  UNITY_BEGIN();228  RUN_TEST(test_analysisLoader_index_basic);229  RUN_TEST(test_analysisLoader_index_unordered);230  RUN_TEST(test_analysisLoader_table_only_entry);231  RUN_TEST(test_analysisLoader_nonexistent_table);232  RUN_TEST(test_analysisLoader_null_argv_variants);233  RUN_TEST(test_analysisLoader_pk_index_path);234  RUN_TEST(test_analysisLoader_partial_index_does_not_override_table_rowcount);235  return UNITY_END();236}