Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_build_sqlite3AddGenerated.c328 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Global DB handle used for allocations in tests */7static sqlite3 *gDb = NULL;8 9/* Unity setUp/tearDown */10void setUp(void) {11  int rc = sqlite3_open(":memory:", &gDb);12  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "Failed to open in-memory DB");13}14 15void tearDown(void) {16  if (gDb) {17    sqlite3_close(gDb);18    gDb = NULL;19  }20}21 22/* Helpers */23static Token makeToken(const char *z){24  Token t;25  t.z = z;26  t.n = (int)strlen(z);27  return t;28}29 30static Expr* makeIdExpr(sqlite3 *db, const char *zName){31  Token t = makeToken(zName);32  return sqlite3ExprAlloc(db, TK_ID, &t, 0);33}34 35static Expr* makeIntExpr(sqlite3 *db, const char *zVal){36  Token t = makeToken(zVal);37  return sqlite3ExprAlloc(db, TK_INTEGER, &t, 0);38}39 40static Table* makeTestTable(sqlite3 *db, const char *zColName, int affinity, u32 colFlagsInit, int iDfltInit){41  Table *pTab = (Table*)sqlite3DbMallocZero(db, sizeof(Table));42  TEST_ASSERT_NOT_NULL_MESSAGE(pTab, "Failed to allocate Table");43  pTab->nCol = 1;44  pTab->nNVCol = 1; /* initially, 1 non-virtual column */45  pTab->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column));46  TEST_ASSERT_NOT_NULL_MESSAGE(pTab->aCol, "Failed to allocate Column array");47  Column *pCol = &pTab->aCol[0];48  pCol->zCnName = sqlite3DbStrDup(db, zColName);49  TEST_ASSERT_NOT_NULL_MESSAGE(pCol->zCnName, "Failed to allocate column name");50  pCol->affinity = (char)affinity;51  pCol->colFlags = colFlagsInit;52  pCol->iDflt = iDfltInit;53  /* pTab->tabFlags defaults to 0 for ordinary table */54  return pTab;55}56 57static void freeTestTable(sqlite3 *db, Table *pTab){58  if (!pTab) return;59  if (pTab->u.tab.pDfltList){60    sqlite3ExprListDelete(db, pTab->u.tab.pDfltList);61  }62  if (pTab->aCol){63    if (pTab->aCol[0].zCnName){64      sqlite3DbFree(db, pTab->aCol[0].zCnName);65    }66    sqlite3DbFree(db, pTab->aCol);67  }68  sqlite3DbFree(db, pTab);69}70 71static int strContains(const char *hay, const char *needle){72  if (!hay || !needle) return 0;73  return strstr(hay, needle)!=0;74}75 76/* Tests */77 78/* Virtual generated column via explicit "ViRtUaL" token; ID expr is wrapped with TK_UPLUS and affinity applied */79void test_sqlite3AddGenerated_virtual_id_expr_affinity_and_flags(void){80#ifndef SQLITE_OMIT_GENERATED_COLUMNS81  Parse p; memset(&p, 0, sizeof(p)); p.db = gDb;82  Table *tab = makeTestTable(gDb, "c1", (int)'T', 0, 0);83  p.pNewTable = tab;84 85  Token tType = makeToken("ViRtUaL"); /* case-insensitive */86  Expr *e = makeIdExpr(gDb, "x");87  sqlite3AddGenerated(&p, e, &tType);88 89  TEST_ASSERT_EQUAL_INT(0, p.nErr);90  TEST_ASSERT_NULL(p.zErrMsg);91 92  Column *c = &tab->aCol[0];93 94  TEST_ASSERT_NOT_NULL(tab->u.tab.pDfltList);95  TEST_ASSERT_EQUAL_INT(1, tab->u.tab.pDfltList->nExpr);96  TEST_ASSERT_EQUAL_INT(1, c->iDflt);97 98  Expr *stored = tab->u.tab.pDfltList->a[0].pExpr;99  TEST_ASSERT_NOT_NULL(stored);100  TEST_ASSERT_EQUAL_INT(TK_UPLUS, stored->op);101  TEST_ASSERT_NOT_NULL(stored->pLeft);102  TEST_ASSERT_EQUAL_INT(TK_ID, stored->pLeft->op);103  TEST_ASSERT_EQUAL_INT((int)c->affinity, (int)stored->affExpr);104 105  TEST_ASSERT_TRUE( (c->colFlags & COLFLAG_VIRTUAL)!=0 );106  TEST_ASSERT_TRUE( (tab->tabFlags & COLFLAG_VIRTUAL)!=0 );107  TEST_ASSERT_EQUAL_INT(0, tab->nNVCol); /* decremented from 1 -> 0 */108 109  freeTestTable(gDb, tab);110  if (p.zErrMsg) sqlite3DbFree(gDb, p.zErrMsg);111#else112  TEST_IGNORE_MESSAGE("Built with SQLITE_OMIT_GENERATED_COLUMNS");113#endif114}115 116/* Stored generated column; nNVCol unchanged; ID expr wrapped; flags set to stored */117void test_sqlite3AddGenerated_stored_basic(void){118#ifndef SQLITE_OMIT_GENERATED_COLUMNS119  Parse p; memset(&p, 0, sizeof(p)); p.db = gDb;120  Table *tab = makeTestTable(gDb, "c1", (int)'S', 0, 0);121  p.pNewTable = tab;122 123  Token tType = makeToken("StoReD"); /* case-insensitive */124  Expr *e = makeIdExpr(gDb, "x");125  sqlite3AddGenerated(&p, e, &tType);126 127  TEST_ASSERT_EQUAL_INT(0, p.nErr);128  TEST_ASSERT_NULL(p.zErrMsg);129 130  Column *c = &tab->aCol[0];131 132  TEST_ASSERT_NOT_NULL(tab->u.tab.pDfltList);133  TEST_ASSERT_EQUAL_INT(1, tab->u.tab.pDfltList->nExpr);134  TEST_ASSERT_EQUAL_INT(1, c->iDflt);135 136  Expr *stored = tab->u.tab.pDfltList->a[0].pExpr;137  TEST_ASSERT_NOT_NULL(stored);138  TEST_ASSERT_EQUAL_INT(TK_UPLUS, stored->op);139  TEST_ASSERT_EQUAL_INT((int)c->affinity, (int)stored->affExpr);140 141  TEST_ASSERT_TRUE( (c->colFlags & COLFLAG_STORED)!=0 );142  TEST_ASSERT_TRUE( (tab->tabFlags & COLFLAG_STORED)!=0 );143  TEST_ASSERT_EQUAL_INT(1, tab->nNVCol); /* unchanged */144 145  freeTestTable(gDb, tab);146  if (p.zErrMsg) sqlite3DbFree(gDb, p.zErrMsg);147#else148  TEST_IGNORE_MESSAGE("Built with SQLITE_OMIT_GENERATED_COLUMNS");149#endif150}151 152/* Default type (pType=NULL) means virtual; nNVCol decremented */153void test_sqlite3AddGenerated_default_type_is_virtual(void){154#ifndef SQLITE_OMIT_GENERATED_COLUMNS155  Parse p; memset(&p, 0, sizeof(p)); p.db = gDb;156  Table *tab = makeTestTable(gDb, "c1", (int)'A', 0, 0);157  p.pNewTable = tab;158 159  Expr *e = makeIdExpr(gDb, "y");160  sqlite3AddGenerated(&p, e, NULL);161 162  Column *c = &tab->aCol[0];163  TEST_ASSERT_EQUAL_INT(0, p.nErr);164  TEST_ASSERT_TRUE( (c->colFlags & COLFLAG_VIRTUAL)!=0 );165  TEST_ASSERT_TRUE( (tab->tabFlags & COLFLAG_VIRTUAL)!=0 );166  TEST_ASSERT_EQUAL_INT(0, tab->nNVCol);167 168  TEST_ASSERT_NOT_NULL(tab->u.tab.pDfltList);169  TEST_ASSERT_EQUAL_INT(1, c->iDflt);170 171  freeTestTable(gDb, tab);172  if (p.zErrMsg) sqlite3DbFree(gDb, p.zErrMsg);173#else174  TEST_IGNORE_MESSAGE("Built with SQLITE_OMIT_GENERATED_COLUMNS");175#endif176}177 178/* Invalid pType token leads to "error in generated column" and no changes */179void test_sqlite3AddGenerated_invalid_type_token_errors(void){180#ifndef SQLITE_OMIT_GENERATED_COLUMNS181  Parse p; memset(&p, 0, sizeof(p)); p.db = gDb;182  Table *tab = makeTestTable(gDb, "c1", (int)'X', 0, 0);183  p.pNewTable = tab;184 185  Token bad = makeToken("unknown_type");186  Expr *e = makeIntExpr(gDb, "123");187  sqlite3AddGenerated(&p, e, &bad);188 189  TEST_ASSERT_TRUE(p.nErr > 0);190  TEST_ASSERT_NOT_NULL(p.zErrMsg);191  TEST_ASSERT_TRUE(strContains(p.zErrMsg, "error in generated column"));192 193  Column *c = &tab->aCol[0];194  TEST_ASSERT_EQUAL_INT(0, c->iDflt);195  TEST_ASSERT_NULL(tab->u.tab.pDfltList);196  TEST_ASSERT_EQUAL_INT(1, tab->nNVCol);197  TEST_ASSERT_TRUE( (c->colFlags & (COLFLAG_VIRTUAL|COLFLAG_STORED)) == 0 );198  TEST_ASSERT_TRUE( (tab->tabFlags & (COLFLAG_VIRTUAL|COLFLAG_STORED)) == 0 );199 200  freeTestTable(gDb, tab);201  if (p.zErrMsg) sqlite3DbFree(gDb, p.zErrMsg);202#else203  TEST_IGNORE_MESSAGE("Built with SQLITE_OMIT_GENERATED_COLUMNS");204#endif205}206 207/* Generated column marked as PRIMARY KEY -> specific error but expr still attached */208void test_sqlite3AddGenerated_primary_key_generated_errors_but_attaches_expr(void){209#ifndef SQLITE_OMIT_GENERATED_COLUMNS210  Parse p; memset(&p, 0, sizeof(p)); p.db = gDb;211  /* Start with PRIMKEY flag set */212  Table *tab = makeTestTable(gDb, "c1", (int)'P', COLFLAG_PRIMKEY, 0);213  p.pNewTable = tab;214 215  Token tType = makeToken("stored");216  Expr *e = makeIntExpr(gDb, "1");217  sqlite3AddGenerated(&p, e, &tType);218 219  TEST_ASSERT_TRUE(p.nErr > 0);220  TEST_ASSERT_NOT_NULL(p.zErrMsg);221  TEST_ASSERT_TRUE(strContains(p.zErrMsg, "cannot be part of the PRIMARY KEY"));222 223  Column *c = &tab->aCol[0];224  TEST_ASSERT_NOT_NULL(tab->u.tab.pDfltList);225  TEST_ASSERT_EQUAL_INT(1, tab->u.tab.pDfltList->nExpr);226  TEST_ASSERT_EQUAL_INT(1, c->iDflt);227 228  TEST_ASSERT_TRUE( (c->colFlags & COLFLAG_STORED)!=0 );229  TEST_ASSERT_TRUE( (tab->tabFlags & COLFLAG_STORED)!=0 );230  TEST_ASSERT_EQUAL_INT(1, tab->nNVCol); /* stored: unchanged */231 232  freeTestTable(gDb, tab);233  if (p.zErrMsg) sqlite3DbFree(gDb, p.zErrMsg);234#else235  TEST_IGNORE_MESSAGE("Built with SQLITE_OMIT_GENERATED_COLUMNS");236#endif237}238 239/* IN_DECLARE_VTAB -> specific error, no expr attached, no flag changes */240void test_sqlite3AddGenerated_in_declare_vtab_errors_and_no_changes(void){241#ifndef SQLITE_OMIT_GENERATED_COLUMNS242  Parse p; memset(&p, 0, sizeof(p)); p.db = gDb; p.declareVtab = 1;243  Table *tab = makeTestTable(gDb, "c1", (int)'V', 0, 0);244  p.pNewTable = tab;245 246  Token tType = makeToken("virtual");247  Expr *e = makeIdExpr(gDb, "colref");248  sqlite3AddGenerated(&p, e, &tType);249 250  TEST_ASSERT_TRUE(p.nErr > 0);251  TEST_ASSERT_NOT_NULL(p.zErrMsg);252  TEST_ASSERT_TRUE(strContains(p.zErrMsg, "virtual tables cannot use computed columns"));253 254  Column *c = &tab->aCol[0];255  TEST_ASSERT_NULL(tab->u.tab.pDfltList);256  TEST_ASSERT_EQUAL_INT(0, c->iDflt);257  TEST_ASSERT_TRUE( (c->colFlags & (COLFLAG_VIRTUAL|COLFLAG_STORED)) == 0 );258  TEST_ASSERT_TRUE( (tab->tabFlags & (COLFLAG_VIRTUAL|COLFLAG_STORED)) == 0 );259  TEST_ASSERT_EQUAL_INT(1, tab->nNVCol);260 261  freeTestTable(gDb, tab);262  if (p.zErrMsg) sqlite3DbFree(gDb, p.zErrMsg);263#else264  TEST_IGNORE_MESSAGE("Built with SQLITE_OMIT_GENERATED_COLUMNS");265#endif266}267 268/* pNewTable == NULL -> no error, expr deleted, nothing else to assert */269void test_sqlite3AddGenerated_null_newtable_noop(void){270#ifndef SQLITE_OMIT_GENERATED_COLUMNS271  Parse p; memset(&p, 0, sizeof(p)); p.db = gDb;272  p.pNewTable = NULL;273 274  Token tType = makeToken("virtual");275  Expr *e = makeIntExpr(gDb, "7");276  sqlite3AddGenerated(&p, e, &tType);277 278  TEST_ASSERT_EQUAL_INT(0, p.nErr);279  TEST_ASSERT_NULL(p.zErrMsg);280  /* e is freed by sqlite3AddGenerated; nothing else to clean */281 282  if (p.zErrMsg) sqlite3DbFree(gDb, p.zErrMsg);283#else284  TEST_IGNORE_MESSAGE("Built with SQLITE_OMIT_GENERATED_COLUMNS");285#endif286}287 288/* If column already has a default (iDflt>0), signal error and do not attach expr */289void test_sqlite3AddGenerated_existing_default_conflict_errors(void){290#ifndef SQLITE_OMIT_GENERATED_COLUMNS291  Parse p; memset(&p, 0, sizeof(p)); p.db = gDb;292  /* Pretend column already has a default index; no list attached yet */293  Table *tab = makeTestTable(gDb, "c1", (int)'Q', 0, 2);294  p.pNewTable = tab;295 296  Token tType = makeToken("stored");297  Expr *e = makeIntExpr(gDb, "99");298  sqlite3AddGenerated(&p, e, &tType);299 300  TEST_ASSERT_TRUE(p.nErr > 0);301  TEST_ASSERT_NOT_NULL(p.zErrMsg);302  TEST_ASSERT_TRUE(strContains(p.zErrMsg, "error in generated column"));303 304  Column *c = &tab->aCol[0];305  TEST_ASSERT_NULL(tab->u.tab.pDfltList);306  TEST_ASSERT_EQUAL_INT(2, c->iDflt); /* unchanged */307  TEST_ASSERT_EQUAL_INT(1, tab->nNVCol); /* unchanged */308  TEST_ASSERT_TRUE( (c->colFlags & (COLFLAG_VIRTUAL|COLFLAG_STORED)) == 0 );309 310  freeTestTable(gDb, tab);311  if (p.zErrMsg) sqlite3DbFree(gDb, p.zErrMsg);312#else313  TEST_IGNORE_MESSAGE("Built with SQLITE_OMIT_GENERATED_COLUMNS");314#endif315}316 317int main(void) {318  UNITY_BEGIN();319  RUN_TEST(test_sqlite3AddGenerated_virtual_id_expr_affinity_and_flags);320  RUN_TEST(test_sqlite3AddGenerated_stored_basic);321  RUN_TEST(test_sqlite3AddGenerated_default_type_is_virtual);322  RUN_TEST(test_sqlite3AddGenerated_invalid_type_token_errors);323  RUN_TEST(test_sqlite3AddGenerated_primary_key_generated_errors_but_attaches_expr);324  RUN_TEST(test_sqlite3AddGenerated_in_declare_vtab_errors_and_no_changes);325  RUN_TEST(test_sqlite3AddGenerated_null_newtable_noop);326  RUN_TEST(test_sqlite3AddGenerated_existing_default_conflict_errors);327  return UNITY_END();328}