AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6 7/* Helpers to build minimal Table and Index objects for testing */8 9static void init_parse_and_vdbe(sqlite3 **ppDb, Parse *pParse){10 sqlite3 *db = 0;11 int rc = sqlite3_open(":memory:", &db);12 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);13 memset(pParse, 0, sizeof(*pParse));14 pParse->db = db;15 /* Create a Vdbe and attach to Parse to satisfy sqlite3HaltConstraint assert */16 Vdbe *v = sqlite3VdbeCreate(db);17 TEST_ASSERT_NOT_NULL(v);18 pParse->pVdbe = v;19 *ppDb = db;20}21 22static void free_vdbe_and_close(Parse *pParse){23 if( pParse && pParse->pVdbe ){24 sqlite3VdbeDelete(pParse->pVdbe);25 pParse->pVdbe = 0;26 }27 if( pParse && pParse->db ){28 sqlite3_close(pParse->db);29 pParse->db = 0;30 }31}32 33static void make_table(sqlite3 *db, Table *pTab,34 const char *zTabName,35 int nCol, const char **azColNames){36 memset(pTab, 0, sizeof(*pTab));37 pTab->zName = sqlite3_mprintf("%s", zTabName);38 TEST_ASSERT_NOT_NULL(pTab->zName);39 pTab->nCol = (i16)nCol;40 pTab->aCol = (Column*)sqlite3_malloc64(sizeof(Column)*nCol);41 TEST_ASSERT_NOT_NULL(pTab->aCol);42 memset(pTab->aCol, 0, sizeof(Column)*nCol);43 for(int i=0; i<nCol; i++){44 pTab->aCol[i].zCnName = sqlite3_mprintf("%s", azColNames[i]);45 TEST_ASSERT_NOT_NULL(pTab->aCol[i].zCnName);46 }47 (void)db; /* db not used here, but kept for symmetry if needed */48}49 50static void free_table(Table *pTab){51 if( pTab->aCol ){52 for(int i=0; i<pTab->nCol; i++){53 if( pTab->aCol[i].zCnName ){54 sqlite3_free(pTab->aCol[i].zCnName);55 pTab->aCol[i].zCnName = 0;56 }57 }58 sqlite3_free(pTab->aCol);59 pTab->aCol = 0;60 }61 if( pTab->zName ){62 sqlite3_free(pTab->zName);63 pTab->zName = 0;64 }65}66 67static void make_index(Index *pIdx, Table *pTab,68 const char *zName,69 int nKeyCol, const i16 *aiCols,70 int idxType, int hasColExpr){71 memset(pIdx, 0, sizeof(*pIdx));72 pIdx->pTable = pTab;73 pIdx->zName = sqlite3_mprintf("%s", zName);74 TEST_ASSERT_NOT_NULL(pIdx->zName);75 pIdx->nKeyCol = (i16)nKeyCol;76 /* For tests, we can point aiColumn to a provided array with static/storage duration.77 We cast away const because struct expects non-const; we do not modify it. */78 pIdx->aiColumn = (i16*)aiCols;79 pIdx->idxType = (u8)idxType;80 pIdx->aColExpr = hasColExpr ? (ExprList*)pTab /* any non-NULL sentinel */ : 0;81}82 83static void free_index(Index *pIdx){84 if( pIdx->zName ){85 sqlite3_free(pIdx->zName);86 pIdx->zName = 0;87 }88 /* aiColumn points to caller-owned memory; not freed here */89}90 91/* Unity hooks */92void setUp(void) {93 /* No global setup */94}95void tearDown(void) {96 /* No global teardown */97}98 99/* Tests */100 101void test_sqlite3UniqueConstraint_nonpk_multi_column_message_and_op_fields(void){102 sqlite3 *db = 0;103 Parse parse;104 init_parse_and_vdbe(&db, &parse);105 106 /* Build table t(a,b) */107 const char *cols[] = {"a","b"};108 Table t;109 make_table(db, &t, "t", 2, cols);110 111 /* Non-PK index on (a,b) */112 static i16 aiCols[2] = {0,1};113 Index idx;114 make_index(&idx, &t, "idx_t_ab", 2, aiCols, SQLITE_IDXTYPE_APPDEF, 0);115 116 int onError = OE_Abort;117 int addr = sqlite3VdbeCurrentAddr(parse.pVdbe);118 sqlite3UniqueConstraint(&parse, onError, &idx);119 120 VdbeOp *op = sqlite3VdbeGetOp(parse.pVdbe, addr);121 TEST_ASSERT_NOT_NULL(op);122 TEST_ASSERT_EQUAL_INT(OP_Halt, op->opcode);123 TEST_ASSERT_EQUAL_INT(SQLITE_CONSTRAINT_UNIQUE, op->p1);124 TEST_ASSERT_EQUAL_INT(onError, op->p2);125 TEST_ASSERT_EQUAL_INT(P5_ConstraintUnique, op->p5);126 TEST_ASSERT_NOT_NULL(op->p4.z);127 TEST_ASSERT_EQUAL_STRING("t.a, t.b", op->p4.z);128 129 free_index(&idx);130 free_table(&t);131 free_vdbe_and_close(&parse);132}133 134void test_sqlite3UniqueConstraint_index_with_expr_uses_index_name(void){135 sqlite3 *db = 0;136 Parse parse;137 init_parse_and_vdbe(&db, &parse);138 139 /* Build table t(a) */140 const char *cols[] = {"a"};141 Table t;142 make_table(db, &t, "t", 1, cols);143 144 /* Index with expressions: force aColExpr non-NULL */145 static i16 aiCols[1] = {0};146 Index idx;147 make_index(&idx, &t, "u1", 1, aiCols, SQLITE_IDXTYPE_APPDEF, 1 /* hasColExpr */);148 149 int onError = OE_Fail;150 int addr = sqlite3VdbeCurrentAddr(parse.pVdbe);151 sqlite3UniqueConstraint(&parse, onError, &idx);152 153 VdbeOp *op = sqlite3VdbeGetOp(parse.pVdbe, addr);154 TEST_ASSERT_NOT_NULL(op);155 TEST_ASSERT_EQUAL_INT(OP_Halt, op->opcode);156 TEST_ASSERT_EQUAL_INT(SQLITE_CONSTRAINT_UNIQUE, op->p1);157 TEST_ASSERT_EQUAL_INT(onError, op->p2);158 TEST_ASSERT_EQUAL_INT(P5_ConstraintUnique, op->p5);159 TEST_ASSERT_NOT_NULL(op->p4.z);160 TEST_ASSERT_EQUAL_STRING("index 'u1'", op->p4.z);161 162 free_index(&idx);163 free_table(&t);164 free_vdbe_and_close(&parse);165}166 167void test_sqlite3UniqueConstraint_primary_key_uses_pk_extended_code(void){168 sqlite3 *db = 0;169 Parse parse;170 init_parse_and_vdbe(&db, &parse);171 172 /* Build table t(id) */173 const char *cols[] = {"id"};174 Table t;175 make_table(db, &t, "t", 1, cols);176 177 /* Primary key index on (id) */178 static i16 aiCols[1] = {0};179 Index idx;180 make_index(&idx, &t, "pk_t", 1, aiCols, SQLITE_IDXTYPE_PRIMARYKEY, 0 /* no expr */);181 182 int onError = OE_Ignore;183 int addr = sqlite3VdbeCurrentAddr(parse.pVdbe);184 sqlite3UniqueConstraint(&parse, onError, &idx);185 186 VdbeOp *op = sqlite3VdbeGetOp(parse.pVdbe, addr);187 TEST_ASSERT_NOT_NULL(op);188 TEST_ASSERT_EQUAL_INT(OP_Halt, op->opcode);189 TEST_ASSERT_EQUAL_INT(SQLITE_CONSTRAINT_PRIMARYKEY, op->p1);190 TEST_ASSERT_EQUAL_INT(onError, op->p2);191 TEST_ASSERT_EQUAL_INT(P5_ConstraintUnique, op->p5);192 TEST_ASSERT_NOT_NULL(op->p4.z);193 TEST_ASSERT_EQUAL_STRING("t.id", op->p4.z);194 195 free_index(&idx);196 free_table(&t);197 free_vdbe_and_close(&parse);198}199 200void test_sqlite3UniqueConstraint_onError_value_is_propagated(void){201 sqlite3 *db = 0;202 Parse parse;203 init_parse_and_vdbe(&db, &parse);204 205 /* Build table t(x) */206 const char *cols[] = {"x"};207 Table t;208 make_table(db, &t, "t", 1, cols);209 210 /* Simple unique index on (x) */211 static i16 aiCols[1] = {0};212 Index idx;213 make_index(&idx, &t, "u_x", 1, aiCols, SQLITE_IDXTYPE_APPDEF, 0);214 215 /* Try several onError values */216 int onErrors[] = {OE_None, OE_Rollback, OE_Abort, OE_Fail, OE_Ignore, OE_Replace};217 const int nErr = (int)(sizeof(onErrors)/sizeof(onErrors[0]));218 219 for(int i=0; i<nErr; i++){220 int addr = sqlite3VdbeCurrentAddr(parse.pVdbe);221 sqlite3UniqueConstraint(&parse, onErrors[i], &idx);222 VdbeOp *op = sqlite3VdbeGetOp(parse.pVdbe, addr);223 TEST_ASSERT_NOT_NULL(op);224 TEST_ASSERT_EQUAL_INT(OP_Halt, op->opcode);225 TEST_ASSERT_EQUAL_INT(SQLITE_CONSTRAINT_UNIQUE, op->p1);226 TEST_ASSERT_EQUAL_INT(onErrors[i], op->p2);227 TEST_ASSERT_EQUAL_INT(P5_ConstraintUnique, op->p5);228 TEST_ASSERT_NOT_NULL(op->p4.z);229 /* For non-expr index, message uses "t.x" */230 TEST_ASSERT_EQUAL_STRING("t.x", op->p4.z);231 }232 233 free_index(&idx);234 free_table(&t);235 free_vdbe_and_close(&parse);236}237 238int main(void) {239 UNITY_BEGIN();240 RUN_TEST(test_sqlite3UniqueConstraint_nonpk_multi_column_message_and_op_fields);241 RUN_TEST(test_sqlite3UniqueConstraint_index_with_expr_uses_index_name);242 RUN_TEST(test_sqlite3UniqueConstraint_primary_key_uses_pk_extended_code);243 RUN_TEST(test_sqlite3UniqueConstraint_onError_value_is_propagated);244 return UNITY_END();245}