AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Helpers to construct minimal Table/Column and ExprList objects */7static Table* makeTable(sqlite3 *db, const char *zTabName,8 int nCol, const char *const *azCol,9 const int *aiIsInteger){10 Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));11 int i;12 TEST_ASSERT_NOT_NULL_MESSAGE(pTab, "malloc Table failed");13 pTab->zName = sqlite3DbStrDup(db, zTabName);14 TEST_ASSERT_NOT_NULL_MESSAGE(pTab->zName, "malloc zName failed");15 pTab->nCol = (i16)nCol;16 pTab->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nCol);17 TEST_ASSERT_NOT_NULL_MESSAGE(pTab->aCol, "malloc aCol failed");18 pTab->iPKey = -1;19 for(i=0; i<nCol; i++){20 Column *pCol = &pTab->aCol[i];21 /* Name */22 pCol->zCnName = sqlite3DbStrDup(db, azCol[i]);23 TEST_ASSERT_NOT_NULL_MESSAGE(pCol->zCnName, "malloc column name failed");24 /* Type classification: only check for INTEGER explicitly */25 pCol->eCType = (aiIsInteger && aiIsInteger[i]) ? COLTYPE_INTEGER : 0; /* non-integer as 0 */26 pCol->colFlags = 0;27 pCol->notNull = 0;28 }29 return pTab;30}31 32static void freeTable(sqlite3 *db, Table *pTab){33 if(!pTab) return;34 if(pTab->aCol){35 for(int i=0; i<pTab->nCol; i++){36 if(pTab->aCol[i].zCnName) sqlite3DbFree(db, (void*)pTab->aCol[i].zCnName);37 }38 sqlite3DbFree(db, pTab->aCol);39 }40 if(pTab->zName) sqlite3DbFree(db, pTab->zName);41 sqlite3DbFree(db, pTab);42}43 44static ExprList* makeExprListForColumn(Parse *pParse, const char *zCol){45 Token t;46 Expr *pExpr;47 ExprList *pList;48 t.z = zCol;49 t.n = (int)strlen(zCol);50 pExpr = sqlite3ExprAlloc(pParse->db, TK_ID, &t, 0);51 TEST_ASSERT_NOT_NULL_MESSAGE(pExpr, "sqlite3ExprAlloc failed");52 pList = sqlite3ExprListAppend(pParse, 0, pExpr);53 TEST_ASSERT_NOT_NULL_MESSAGE(pList, "sqlite3ExprListAppend failed");54 return pList;55}56 57void setUp(void) {58 /* no-op */59}60 61void tearDown(void) {62 /* no-op */63}64 65/* Test: last column is INTEGER, AUTOINCREMENT flag set, and conflict policy recorded */66void test_sqlite3AddPrimaryKey_lastcol_integer_autoinc(void){67 sqlite3 *db = 0; Parse p; memset(&p, 0, sizeof(p));68 const char *cols[] = {"c1", "id"};69 int isInt[] = {0, 1};70 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));71 p.db = db;72 Table *t = makeTable(db, "t1", 2, cols, isInt);73 p.pNewTable = t;74 75 sqlite3AddPrimaryKey(&p, 0, OE_Abort, 1, SQLITE_SO_ASC);76 77 TEST_ASSERT_EQUAL_INT(1, t->iPKey);78 TEST_ASSERT_EQUAL_UINT8(OE_Abort, t->keyConf);79 TEST_ASSERT_NOT_EQUAL(0, (t->tabFlags & TF_Autoincrement));80 TEST_ASSERT_NOT_EQUAL(0, (t->aCol[1].colFlags & COLFLAG_PRIMKEY));81 TEST_ASSERT_EQUAL_INT(0, p.nErr);82 83 if(p.zErrMsg){ sqlite3DbFree(db, p.zErrMsg); p.zErrMsg = 0; }84 freeTable(db, t);85 sqlite3_close(db);86}87 88/* Test: named single INTEGER column primary key sets iPKey and captures iPkSortOrder */89void test_sqlite3AddPrimaryKey_named_integer_column_and_sortflags(void){90 sqlite3 *db = 0; Parse p; memset(&p, 0, sizeof(p));91 const char *cols[] = {"a"};92 int isInt[] = {1};93 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));94 p.db = db;95 Table *t = makeTable(db, "t2", 1, cols, isInt);96 p.pNewTable = t;97 98 ExprList *pList = makeExprListForColumn(&p, "a");99 /* Simulate a DESC sort-flag on the column in the list */100 pList->a[0].fg.sortFlags = SQLITE_SO_DESC;101 102 sqlite3AddPrimaryKey(&p, pList, OE_Ignore, 0, SQLITE_SO_ASC);103 104 TEST_ASSERT_EQUAL_INT(0, t->iPKey);105 TEST_ASSERT_EQUAL_UINT8(OE_Ignore, t->keyConf);106 TEST_ASSERT_EQUAL_INT(SQLITE_SO_DESC, p.iPkSortOrder);107 TEST_ASSERT_NOT_EQUAL(0, (t->aCol[0].colFlags & COLFLAG_PRIMKEY));108 TEST_ASSERT_EQUAL_INT(0, p.nErr);109 110 if(p.zErrMsg){ sqlite3DbFree(db, p.zErrMsg); p.zErrMsg = 0; }111 freeTable(db, t);112 sqlite3_close(db);113}114 115/* Test: AUTOINCREMENT on non-integer primary key column yields an error */116void test_sqlite3AddPrimaryKey_autoinc_error_on_non_integer(void){117 sqlite3 *db = 0; Parse p; memset(&p, 0, sizeof(p));118 const char *cols[] = {"x", "y"};119 int isInt[] = {0, 0}; /* neither column is INTEGER */120 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));121 p.db = db;122 Table *t = makeTable(db, "t3", 2, cols, isInt);123 p.pNewTable = t;124 125 sqlite3AddPrimaryKey(&p, 0, OE_None, 1, SQLITE_SO_ASC);126 127 TEST_ASSERT_TRUE(p.nErr > 0);128 TEST_ASSERT_NOT_NULL(p.zErrMsg);129#ifndef SQLITE_OMIT_AUTOINCREMENT130 TEST_ASSERT_NOT_NULL(strstr(p.zErrMsg, "AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY"));131#endif132 TEST_ASSERT_EQUAL_INT(-1, t->iPKey); /* Should remain unchanged */133 134 if(p.zErrMsg){ sqlite3DbFree(db, p.zErrMsg); p.zErrMsg = 0; }135 freeTable(db, t);136 sqlite3_close(db);137}138 139/* Test: second primary key definition triggers appropriate error */140void test_sqlite3AddPrimaryKey_duplicate_pk_error(void){141 sqlite3 *db = 0; Parse p; memset(&p, 0, sizeof(p));142 const char *cols[] = {"a"};143 int isInt[] = {1};144 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));145 p.db = db;146 Table *t = makeTable(db, "tDup", 1, cols, isInt);147 t->tabFlags |= TF_HasPrimaryKey; /* Simulate already having a PK */148 p.pNewTable = t;149 150 sqlite3AddPrimaryKey(&p, 0, OE_None, 0, SQLITE_SO_ASC);151 152 TEST_ASSERT_TRUE(p.nErr > 0);153 TEST_ASSERT_NOT_NULL(p.zErrMsg);154 TEST_ASSERT_NOT_NULL(strstr(p.zErrMsg, "more than one primary key"));155 156 if(p.zErrMsg){ sqlite3DbFree(db, p.zErrMsg); p.zErrMsg = 0; }157 freeTable(db, t);158 sqlite3_close(db);159}160 161/* Test: explicit NULLS FIRST/LAST is rejected for INTEGER PRIMARY KEY */162void test_sqlite3AddPrimaryKey_explicit_nulls_error(void){163 sqlite3 *db = 0; Parse p; memset(&p, 0, sizeof(p));164 const char *cols[] = {"id"};165 int isInt[] = {1};166 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));167 p.db = db;168 Table *t = makeTable(db, "tNulls", 1, cols, isInt);169 p.pNewTable = t;170 171 ExprList *pList = makeExprListForColumn(&p, "id");172 /* Set explicit NULLS FIRST */173 pList->a[0].fg.bNulls = 1;174 pList->a[0].fg.sortFlags = 0; /* choose FIRST */175 176 sqlite3AddPrimaryKey(&p, pList, OE_Abort, 0, SQLITE_SO_ASC);177 178 TEST_ASSERT_TRUE(p.nErr > 0);179 TEST_ASSERT_NOT_NULL(p.zErrMsg);180 TEST_ASSERT_NOT_NULL(strstr(p.zErrMsg, "NULLS FIRST"));181 /* Even though error is set, the function may have set iPKey already */182 TEST_ASSERT_EQUAL_INT(0, t->iPKey);183 184 if(p.zErrMsg){ sqlite3DbFree(db, p.zErrMsg); p.zErrMsg = 0; }185 freeTable(db, t);186 sqlite3_close(db);187}188 189int main(void){190 UNITY_BEGIN();191 RUN_TEST(test_sqlite3AddPrimaryKey_lastcol_integer_autoinc);192 RUN_TEST(test_sqlite3AddPrimaryKey_named_integer_column_and_sortflags);193 RUN_TEST(test_sqlite3AddPrimaryKey_autoinc_error_on_non_integer);194 RUN_TEST(test_sqlite3AddPrimaryKey_duplicate_pk_error);195 RUN_TEST(test_sqlite3AddPrimaryKey_explicit_nulls_error);196 return UNITY_END();197}