AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Globals for each test */7static sqlite3 *gDb = NULL;8static Parse gParse;9 10/* Helpers */11static void enterDbMutex(sqlite3 *db){ sqlite3_mutex_enter(sqlite3_db_mutex(db)); }12static void leaveDbMutex(sqlite3 *db){ sqlite3_mutex_leave(sqlite3_db_mutex(db)); }13 14static void resetParse(void){15 memset(&gParse, 0, sizeof(gParse));16 gParse.db = gDb;17 gDb->pParse = &gParse;18}19 20static Table* makeTestTable(21 sqlite3 *db,22 const char *zTab,23 const char *const *azCol,24 const u8 *aNotNull,25 int nCol26){27 Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));28 TEST_ASSERT_NOT_NULL(pTab);29 pTab->zName = sqlite3DbStrDup(db, zTab);30 pTab->pSchema = db->aDb[0].pSchema;31 pTab->nCol = nCol;32 pTab->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nCol);33 TEST_ASSERT_NOT_NULL(pTab->aCol);34 pTab->iPKey = -1;35 for(int i=0;i<nCol;i++){36 /* Column name and minimal properties */37 pTab->aCol[i].zCnName = sqlite3DbStrDup(db, azCol[i]);38 pTab->aCol[i].notNull = aNotNull ? aNotNull[i] : 0;39 pTab->aCol[i].szEst = 1; /* keep estimateIndexWidth happy */40 pTab->aCol[i].colFlags = 0;41 }42 return pTab;43}44 45static ExprList* makeExprListOfColumn(Parse *pParse, const char *zCol, const char *zCollate, int desc){46 Token tCol; sqlite3TokenInit(&tCol, zCol);47 Expr *pCol = sqlite3ExprAlloc(pParse->db, TK_ID, &tCol, 0);48 TEST_ASSERT_NOT_NULL(pCol);49 Expr *pExpr = pCol;50 if( zCollate ){51 Token tColl; sqlite3TokenInit(&tColl, zCollate);52 Expr *pColl = sqlite3ExprAlloc(pParse->db, TK_COLLATE, &tColl, 0);53 TEST_ASSERT_NOT_NULL(pColl);54 pColl->pLeft = pCol;55 pExpr = pColl;56 }57 ExprList *pList = sqlite3ExprListAppend(pParse, 0, pExpr);58 TEST_ASSERT_NOT_NULL(pList);59 /* Manually set sort flag: 1 means DESC in requestedSortOrder */60 if( desc ){61 pList->a[0].fg.sortFlags = 1;62 }63 return pList;64}65 66static ExprList* makeExprListWithNulls(Parse *pParse, const char *zCol, int nullsFirst){67 ExprList *pList = makeExprListOfColumn(pParse, zCol, NULL, 0);68 /* Flag explicit NULLS; sortFlags used to determine FIRST or LAST in error */69 pList->a[0].fg.bNulls = 1;70 pList->a[0].fg.sortFlags = nullsFirst ? 0 : 1;71 return pList;72}73 74static ExprList* makeExprListOfExpression(Parse *pParse, const char *zCol){75 Token tCol; sqlite3TokenInit(&tCol, zCol);76 Token tOne; sqlite3TokenInit(&tOne, "1");77 Expr *pL = sqlite3ExprAlloc(pParse->db, TK_ID, &tCol, 0);78 Expr *pR = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &tOne, 0);79 TEST_ASSERT_NOT_NULL(pL);80 TEST_ASSERT_NOT_NULL(pR);81 Expr *pPlus = sqlite3ExprAlloc(pParse->db, TK_PLUS, 0, 0);82 TEST_ASSERT_NOT_NULL(pPlus);83 pPlus->pLeft = pL;84 pPlus->pRight = pR;85 ExprList *pList = sqlite3ExprListAppend(pParse, 0, pPlus);86 TEST_ASSERT_NOT_NULL(pList);87 return pList;88}89 90static int countIndexes(Index *p){ int n=0; while(p){ n++; p=p->pNext; } return n; }91 92void setUp(void){93 int rc = sqlite3_open(":memory:", &gDb);94 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);95 resetParse();96}97 98void tearDown(void){99 if( gParse.zErrMsg ){100 sqlite3DbFree(gDb, gParse.zErrMsg);101 gParse.zErrMsg = 0;102 }103 if( gParse.pNewTable ){104 enterDbMutex(gDb);105 sqlite3DeleteTable(gDb, gParse.pNewTable);106 leaveDbMutex(gDb);107 gParse.pNewTable = 0;108 }109 if( gDb ){110 sqlite3_close(gDb);111 gDb = NULL;112 }113 memset(&gParse, 0, sizeof(gParse));114}115 116/* Tests */117 118void test_sqlite3CreateIndex_early_exit_on_parse_error(void){119 gParse.nErr = 1; /* force early exit */120 /* Satisfy assertion db->pParse==pParse */121 TEST_ASSERT_EQUAL_PTR(&gParse, gDb->pParse);122 123 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, NULL,124 OE_None, NULL, NULL, 0, 0, SQLITE_IDXTYPE_APPDEF);125 126 TEST_ASSERT_EQUAL_INT(1, gParse.nErr);127 /* No index or table mutations expected */128 TEST_ASSERT_NULL(gParse.pNewTable);129}130 131void test_sqlite3CreateIndex_in_declare_vtab_skips_non_pk(void){132 gParse.declareVtab = 1; /* IN_DECLARE_VTAB */133 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, NULL,134 OE_None, NULL, NULL, 0, 0, SQLITE_IDXTYPE_APPDEF);135 /* No error and no side-effects */136 TEST_ASSERT_EQUAL_INT(0, gParse.nErr);137 TEST_ASSERT_NULL(gParse.pNewTable);138}139 140void test_sqlite3CreateIndex_explicit_nulls_first_error(void){141 ExprList *pList = makeExprListWithNulls(&gParse, "a", 1 /* FIRST */);142 /* Call; expect error due to explicit NULLS FIRST */143 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, pList,144 OE_None, NULL, NULL, 0, 0, SQLITE_IDXTYPE_APPDEF);145 TEST_ASSERT_NOT_EQUAL(0, gParse.nErr);146 TEST_ASSERT_NOT_NULL(gParse.zErrMsg);147 TEST_ASSERT_NOT_NULL(strstr(gParse.zErrMsg, "NULLS FIRST"));148}149 150void test_sqlite3CreateIndex_autoindex_on_last_column_and_desc(void){151 const char *cols[] = {"a","b"};152 u8 nn[] = {0,1};153 Table *pTab = makeTestTable(gDb, "t1", cols, nn, 2);154 gParse.pNewTable = pTab;155 /* Ensure DESC sort is honored (file_format>=4) */156 enterDbMutex(gDb);157 gDb->aDb[0].pSchema->file_format = 4;158 /* Call with pList==NULL to make index on last column 'b' */159 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, NULL,160 OE_Abort, NULL, NULL, 1 /* sort DESC for last-col pk/unique */, 0,161 SQLITE_IDXTYPE_UNIQUE);162 leaveDbMutex(gDb);163 164 TEST_ASSERT_NOT_NULL(pTab->pIndex);165 Index *pIdx = pTab->pIndex;166 TEST_ASSERT_EQUAL_INT(SQLITE_IDXTYPE_UNIQUE, pIdx->idxType);167 TEST_ASSERT_EQUAL_PTR(pTab, pIdx->pTable);168 TEST_ASSERT_EQUAL_INT(1, pIdx->nKeyCol);169 TEST_ASSERT_EQUAL_INT(1, pIdx->aiColumn[0]); /* column 'b' index 1 */170 TEST_ASSERT_EQUAL_UINT8(1, pIdx->aSortOrder[0]); /* DESC honored */171 TEST_ASSERT_TRUE(pIdx->uniqNotNull); /* 'b' was NOT NULL */172 /* Ensure rowid appended */173 TEST_ASSERT_EQUAL_INT(XN_ROWID, pIdx->aiColumn[pIdx->nKeyCol]);174}175 176void test_sqlite3CreateIndex_collate_nocase_on_column(void){177 const char *cols[] = {"a"};178 u8 nn[] = {1};179 Table *pTab = makeTestTable(gDb, "t2", cols, nn, 1);180 gParse.pNewTable = pTab;181 ExprList *pList = makeExprListOfColumn(&gParse, "a", "nocase", 0);182 183 enterDbMutex(gDb);184 gDb->aDb[0].pSchema->file_format = 4;185 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, pList,186 OE_Abort, NULL, NULL, 0, 0, SQLITE_IDXTYPE_UNIQUE);187 leaveDbMutex(gDb);188 189 TEST_ASSERT_EQUAL_INT(0, gParse.nErr);190 TEST_ASSERT_NOT_NULL(pTab->pIndex);191 Index *pIdx = pTab->pIndex;192 TEST_ASSERT_EQUAL_INT(1, pIdx->nKeyCol);193 TEST_ASSERT_EQUAL_INT(0, pIdx->aiColumn[0]);194 TEST_ASSERT_NOT_NULL(pIdx->azColl[0]);195 TEST_ASSERT_EQUAL_INT(0, sqlite3StrICmp(pIdx->azColl[0], "nocase"));196}197 198void test_sqlite3CreateIndex_unique_nullable_column_uniqNotNull_cleared(void){199 const char *cols[] = {"x"};200 u8 nn[] = {0}; /* nullable */201 Table *pTab = makeTestTable(gDb, "t3", cols, nn, 1);202 gParse.pNewTable = pTab;203 ExprList *pList = makeExprListOfColumn(&gParse, "x", NULL, 0);204 205 enterDbMutex(gDb);206 gDb->aDb[0].pSchema->file_format = 4;207 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, pList,208 OE_Abort, NULL, NULL, 0, 0, SQLITE_IDXTYPE_UNIQUE);209 leaveDbMutex(gDb);210 211 TEST_ASSERT_NOT_NULL(pTab->pIndex);212 TEST_ASSERT_FALSE(pTab->pIndex->uniqNotNull); /* cleared due to nullable column */213}214 215void test_sqlite3CreateIndex_sort_order_ignored_in_old_file_format(void){216 const char *cols[] = {"a"};217 u8 nn[] = {1};218 Table *pTab = makeTestTable(gDb, "t4", cols, nn, 1);219 gParse.pNewTable = pTab;220 ExprList *pList = makeExprListOfColumn(&gParse, "a", NULL, 1 /* DESC requested */);221 222 enterDbMutex(gDb);223 gDb->aDb[0].pSchema->file_format = 3; /* old format: ignore DESC */224 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, pList,225 OE_None, NULL, NULL, 0, 0, SQLITE_IDXTYPE_APPDEF);226 leaveDbMutex(gDb);227 228 TEST_ASSERT_NOT_NULL(pTab->pIndex);229 TEST_ASSERT_EQUAL_UINT8(0, pTab->pIndex->aSortOrder[0]); /* DESC ignored */230}231 232void test_sqlite3CreateIndex_duplicate_constraint_suppresses_second_index(void){233 const char *cols[] = {"a","b"};234 u8 nn[] = {1,1};235 Table *pTab = makeTestTable(gDb, "t5", cols, nn, 2);236 gParse.pNewTable = pTab;237 238 enterDbMutex(gDb);239 gDb->aDb[0].pSchema->file_format = 4;240 ExprList *pList1 = makeExprListOfColumn(&gParse, "a", NULL, 0);241 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, pList1,242 OE_Abort, NULL, NULL, 0, 0, SQLITE_IDXTYPE_UNIQUE);243 int n1 = countIndexes(pTab->pIndex);244 TEST_ASSERT_EQUAL_INT(1, n1);245 246 ExprList *pList2 = makeExprListOfColumn(&gParse, "a", NULL, 0);247 sqlite3CreateIndex(&gParse, NULL, NULL, NULL, pList2,248 OE_Abort, NULL, NULL, 0, 0, SQLITE_IDXTYPE_UNIQUE);249 int n2 = countIndexes(pTab->pIndex);250 leaveDbMutex(gDb);251 252 TEST_ASSERT_EQUAL_INT(1, n2); /* still one index after duplicate constraint */253}254 255int main(void){256 UNITY_BEGIN();257 RUN_TEST(test_sqlite3CreateIndex_early_exit_on_parse_error);258 RUN_TEST(test_sqlite3CreateIndex_in_declare_vtab_skips_non_pk);259 RUN_TEST(test_sqlite3CreateIndex_explicit_nulls_first_error);260 RUN_TEST(test_sqlite3CreateIndex_autoindex_on_last_column_and_desc);261 RUN_TEST(test_sqlite3CreateIndex_collate_nocase_on_column);262 RUN_TEST(test_sqlite3CreateIndex_unique_nullable_column_uniqNotNull_cleared);263 RUN_TEST(test_sqlite3CreateIndex_sort_order_ignored_in_old_file_format);264 RUN_TEST(test_sqlite3CreateIndex_duplicate_constraint_suppresses_second_index);265 return UNITY_END();266}