AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Helper to get the last constraint name from pTab->pCheck */7static const char* get_last_check_name(Table *pTab){8 if( pTab==0 || pTab->pCheck==0 || pTab->pCheck->nExpr<=0 ) return NULL;9 return pTab->pCheck->a[pTab->pCheck->nExpr-1].zName;10}11 12/* Helper to get the i'th constraint name from pTab->pCheck */13static const char* get_check_name_at(Table *pTab, int i){14 if( pTab==0 || pTab->pCheck==0 ) return NULL;15 if( i<0 || i>=pTab->pCheck->nExpr ) return NULL;16 return pTab->pCheck->a[i].zName;17}18 19void setUp(void) {20 /* No global setup; each test sets up its own db/parse/table */21}22 23void tearDown(void) {24 /* No global teardown */25}26 27/* Basic test: appends a constraint and derives the name from zStart/zEnd */28void test_sqlite3AddCheckConstraint_append_and_trimmed_name(void){29 sqlite3 *db = 0;30 int rc = sqlite3_open(":memory:", &db);31 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);32 db->init.iDb = 0;33 34 Parse parse;35 memset(&parse, 0, sizeof(parse));36 parse.db = db;37 parse.isCreate = 1;38 39 Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));40 TEST_ASSERT_NOT_NULL(pTab);41 parse.pNewTable = pTab;42 43 Token t1 = { (char*)"1", 1 };44 Expr *pExpr = sqlite3Expr(db, TK_INTEGER, &t1);45 TEST_ASSERT_NOT_NULL(pExpr);46 47 const char *src = "( a + 1 )";48 const char *zStart = src; /* points to '(' */49 const char *zEnd = src + strlen(src) - 1; /* points to ')' */50 51 sqlite3AddCheckConstraint(&parse, pExpr, zStart, zEnd);52 53 TEST_ASSERT_NOT_NULL(pTab->pCheck);54 TEST_ASSERT_EQUAL_INT(1, pTab->pCheck->nExpr);55 56 const char *zName = get_last_check_name(pTab);57 TEST_ASSERT_NOT_NULL(zName);58 TEST_ASSERT_EQUAL_STRING("a + 1", zName);59 60 /* Cleanup */61 sqlite3ExprListDelete(db, pTab->pCheck);62 sqlite3DbFree(db, pTab);63 sqlite3_close(db);64}65 66/* If a constraint name token is provided, it overrides the derived name */67void test_sqlite3AddCheckConstraint_constraintName_overrides(void){68 sqlite3 *db = 0;69 int rc = sqlite3_open(":memory:", &db);70 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);71 db->init.iDb = 0;72 73 Parse parse;74 memset(&parse, 0, sizeof(parse));75 parse.db = db;76 parse.isCreate = 1;77 78 Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));79 TEST_ASSERT_NOT_NULL(pTab);80 parse.pNewTable = pTab;81 82 Token tExpr = { (char*)"1", 1 };83 Expr *pExpr = sqlite3Expr(db, TK_INTEGER, &tExpr);84 TEST_ASSERT_NOT_NULL(pExpr);85 86 const char *src = "(x > 0)";87 const char *zStart = src; /* '(' */88 const char *zEnd = src + strlen(src) - 1; /* ')' */89 90 /* Provide a constraint name token */91 const char *nm = "my_constraint";92 Token tName = { (char*)nm, (int)strlen(nm) };93 parse.u1.cr.constraintName = tName;94 95 sqlite3AddCheckConstraint(&parse, pExpr, zStart, zEnd);96 97 TEST_ASSERT_NOT_NULL(pTab->pCheck);98 TEST_ASSERT_EQUAL_INT(1, pTab->pCheck->nExpr);99 100 const char *zName = get_last_check_name(pTab);101 TEST_ASSERT_NOT_NULL(zName);102 TEST_ASSERT_EQUAL_STRING(nm, zName);103 104 /* Cleanup */105 sqlite3ExprListDelete(db, pTab->pCheck);106 sqlite3DbFree(db, pTab);107 sqlite3_close(db);108}109 110/* Multiple constraints accumulate and each has correct derived name */111void test_sqlite3AddCheckConstraint_multiple_constraints_accumulate(void){112 sqlite3 *db = 0;113 int rc = sqlite3_open(":memory:", &db);114 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);115 db->init.iDb = 0;116 117 Parse parse;118 memset(&parse, 0, sizeof(parse));119 parse.db = db;120 parse.isCreate = 1;121 122 Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));123 TEST_ASSERT_NOT_NULL(pTab);124 parse.pNewTable = pTab;125 126 /* First constraint */127 Token t1 = { (char*)"1", 1 };128 Expr *pExpr1 = sqlite3Expr(db, TK_INTEGER, &t1);129 TEST_ASSERT_NOT_NULL(pExpr1);130 131 const char *src1 = "(x>0)";132 sqlite3AddCheckConstraint(&parse, pExpr1, src1, src1 + strlen(src1) - 1);133 134 TEST_ASSERT_NOT_NULL(pTab->pCheck);135 TEST_ASSERT_EQUAL_INT(1, pTab->pCheck->nExpr);136 TEST_ASSERT_EQUAL_STRING("x>0", get_check_name_at(pTab, 0));137 138 /* Ensure no explicit constraintName is used for next call */139 parse.u1.cr.constraintName.n = 0;140 141 /* Second constraint with interior spaces and outer whitespace */142 Token t2 = { (char*)"2", 1 };143 Expr *pExpr2 = sqlite3Expr(db, TK_INTEGER, &t2);144 TEST_ASSERT_NOT_NULL(pExpr2);145 146 const char *src2 = " ( y is not null ) ";147 /* The function expects zStart at '(' and zEnd at the closing ')'. */148 const char *lp = strchr(src2, '(');149 const char *rp = strrchr(src2, ')');150 TEST_ASSERT_NOT_NULL(lp);151 TEST_ASSERT_NOT_NULL(rp);152 153 sqlite3AddCheckConstraint(&parse, pExpr2, lp, rp);154 155 TEST_ASSERT_NOT_NULL(pTab->pCheck);156 TEST_ASSERT_EQUAL_INT(2, pTab->pCheck->nExpr);157 TEST_ASSERT_EQUAL_STRING("x>0", get_check_name_at(pTab, 0));158 TEST_ASSERT_EQUAL_STRING("y is not null", get_check_name_at(pTab, 1));159 160 /* Cleanup */161 sqlite3ExprListDelete(db, pTab->pCheck);162 sqlite3DbFree(db, pTab);163 sqlite3_close(db);164}165 166/* Else-path: when pNewTable is NULL, the expression is deleted and nothing is appended */167void test_sqlite3AddCheckConstraint_null_table_expression_deleted_no_append(void){168 sqlite3 *db = 0;169 int rc = sqlite3_open(":memory:", &db);170 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);171 db->init.iDb = 0;172 173 Parse parse;174 memset(&parse, 0, sizeof(parse));175 parse.db = db;176 parse.isCreate = 1;177 178 /* No table under construction */179 parse.pNewTable = NULL;180 181 Token t1 = { (char*)"1", 1 };182 Expr *pExpr = sqlite3Expr(db, TK_INTEGER, &t1);183 TEST_ASSERT_NOT_NULL(pExpr);184 185 const char *src = "( x )";186 const char *zStart = src;187 const char *zEnd = src + strlen(src) - 1;188 189 /* Should hit the else-branch and delete pExpr internally without appending */190 sqlite3AddCheckConstraint(&parse, pExpr, zStart, zEnd);191 192 /* Nothing to assert on pTab since it is NULL; primary check is "no crash". */193 /* Close DB */194 sqlite3_close(db);195}196 197int main(void) {198 UNITY_BEGIN();199 RUN_TEST(test_sqlite3AddCheckConstraint_append_and_trimmed_name);200 RUN_TEST(test_sqlite3AddCheckConstraint_constraintName_overrides);201 RUN_TEST(test_sqlite3AddCheckConstraint_multiple_constraints_accumulate);202 RUN_TEST(test_sqlite3AddCheckConstraint_null_table_expression_deleted_no_append);203 return UNITY_END();204}