Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_build_sqlite3EndTable.c224 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5static sqlite3 *gDb = NULL;6 7static void initParse(Parse *pParse){8  memset(pParse, 0, sizeof(*pParse));9  pParse->db = gDb;10}11 12static Table* allocTable(const char *zName, int nCol){13  Table *p = (Table*)sqlite3DbMallocZero(gDb, sizeof(Table));14  TEST_ASSERT_NOT_NULL_MESSAGE(p, "sqlite3DbMallocZero(Table) failed");15  p->zName = sqlite3DbStrDup(gDb, zName);16  TEST_ASSERT_NOT_NULL_MESSAGE(p->zName, "sqlite3DbStrDup(zName) failed");17  p->nCol = nCol;18  p->nNVCol = nCol;19  p->aCol = (Column*)sqlite3DbMallocZero(gDb, sizeof(Column)*nCol);20  TEST_ASSERT_NOT_NULL_MESSAGE(p->aCol, "sqlite3DbMallocZero(aCol) failed");21  p->iPKey = -1; /* No INTEGER PRIMARY KEY */22  /* Ordinary table (default flags 0). Leave p->pSchema NULL for early-return tests. */23  return p;24}25 26static void freeTable(Table *p){27  if( p ){28    /* Use the SQLite helper that frees all parts of Table safely. */29    sqlite3DeleteTable(gDb, p);30  }31}32 33void setUp(void) {34  int rc = sqlite3_open(":memory:", &gDb);35  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");36}37 38void tearDown(void) {39  if( gDb ){40    sqlite3_close(gDb);41    gDb = NULL;42  }43}44 45/* Helper to make a minimal non-NULL Token to avoid top-level early return */46static void makeDummyEndToken(Token *pTok){47  static const char zDummy[] = ")";48  pTok->z = zDummy;49  pTok->n = 1;50}51 52/* Test: early return when pEnd==NULL and pSelect==NULL */53void test_sqlite3EndTable_early_return_when_no_end_or_select(void){54  Parse pParse; initParse(&pParse);55  Table *p = allocTable("t", 1);56  pParse.pNewTable = p;57 58  /* Before call */59  unsigned preFlags = p->tabFlags;60  int preErr = pParse.nErr;61 62  sqlite3EndTable(&pParse, NULL, NULL, 0, NULL);63 64  TEST_ASSERT_EQUAL_UINT(preFlags, p->tabFlags);65  TEST_ASSERT_EQUAL_INT(preErr, pParse.nErr);66 67  freeTable(p);68}69 70/* Test: STRICT mode with missing datatype (COLTYPE_CUSTOM without COLFLAG_HASTYPE) -> error */71void test_sqlite3EndTable_strict_missing_datatype_error(void){72  Parse pParse; initParse(&pParse);73  Table *p = allocTable("t", 1);74  pParse.pNewTable = p;75 76  /* Column with custom type but no explicit type string -> missing datatype */77  p->aCol[0].zCnName = sqlite3DbStrDup(gDb, "c1");78  TEST_ASSERT_NOT_NULL(p->aCol[0].zCnName);79  p->aCol[0].eCType = COLTYPE_CUSTOM;80  p->aCol[0].colFlags = 0; /* no COLFLAG_HASTYPE */81  p->aCol[0].notNull = OE_None;82 83  Token tEnd; makeDummyEndToken(&tEnd);84 85  int preErr = pParse.nErr;86  sqlite3EndTable(&pParse, NULL, &tEnd, TF_Strict, NULL);87 88  TEST_ASSERT_TRUE_MESSAGE(pParse.nErr > preErr, "STRICT missing datatype should set an error");89  TEST_ASSERT_TRUE(p->tabFlags & TF_Strict);90 91  freeTable(p);92}93 94/* Test: STRICT mode with unknown datatype (COLTYPE_CUSTOM with COLFLAG_HASTYPE) -> error */95void test_sqlite3EndTable_strict_unknown_datatype_error(void){96  Parse pParse; initParse(&pParse);97  Table *p = allocTable("t", 1);98  pParse.pNewTable = p;99 100  p->aCol[0].zCnName = sqlite3DbStrDup(gDb, "c1");101  TEST_ASSERT_NOT_NULL(p->aCol[0].zCnName);102  p->aCol[0].eCType = COLTYPE_CUSTOM;103  p->aCol[0].colFlags = COLFLAG_HASTYPE; /* has a (custom) type name */104  p->aCol[0].notNull = OE_None;105 106  Token tEnd; makeDummyEndToken(&tEnd);107 108  int preErr = pParse.nErr;109  sqlite3EndTable(&pParse, NULL, &tEnd, TF_Strict, NULL);110 111  TEST_ASSERT_TRUE_MESSAGE(pParse.nErr > preErr, "STRICT unknown datatype should set an error");112  TEST_ASSERT_TRUE(p->tabFlags & TF_Strict);113 114  freeTable(p);115}116 117/* Test: STRICT promotes PK cols to NOT NULL and sets affinity for COLTYPE_ANY.118   Force early return later using WITHOUT ROWID + AUTOINCREMENT conflict to avoid deep VDBE paths. */119void test_sqlite3EndTable_strict_promotes_pk_to_not_null_and_sets_affinity(void){120  Parse pParse; initParse(&pParse);121  Table *p = allocTable("t", 2);122  pParse.pNewTable = p;123 124  /* Two PK columns, initially not-null=OE_None */125  p->aCol[0].zCnName = sqlite3DbStrDup(gDb, "c1");126  p->aCol[1].zCnName = sqlite3DbStrDup(gDb, "c2");127  TEST_ASSERT_NOT_NULL(p->aCol[0].zCnName);128  TEST_ASSERT_NOT_NULL(p->aCol[1].zCnName);129  p->aCol[0].colFlags = COLFLAG_PRIMKEY;130  p->aCol[1].colFlags = COLFLAG_PRIMKEY;131  p->aCol[0].notNull = OE_None;132  p->aCol[1].notNull = OE_None;133 134  /* Set types so STRICT does not throw datatype error */135  p->aCol[0].eCType = COLTYPE_ANY; /* will set affinity to BLOB */136  p->aCol[1].eCType = COLTYPE_ANY; /* will set affinity to BLOB */137 138  /* Make AUTOINCREMENT to conflict with WITHOUT ROWID and force return after STRICT */139  p->tabFlags |= TF_Autoincrement;140 141  Token tEnd; makeDummyEndToken(&tEnd);142 143  int preErr = pParse.nErr;144  sqlite3EndTable(&pParse, NULL, &tEnd, (TF_Strict | TF_WithoutRowid), NULL);145 146  /* STRICT effects should have occurred before the WITHOUT ROWID error */147  TEST_ASSERT_TRUE(p->tabFlags & TF_Strict);148  TEST_ASSERT_TRUE(p->tabFlags & TF_HasNotNull);149  TEST_ASSERT_EQUAL_INT(OE_Abort, p->aCol[0].notNull);150  TEST_ASSERT_EQUAL_INT(OE_Abort, p->aCol[1].notNull);151  TEST_ASSERT_EQUAL_INT(SQLITE_AFF_BLOB, p->aCol[0].affinity);152  TEST_ASSERT_EQUAL_INT(SQLITE_AFF_BLOB, p->aCol[1].affinity);153 154  /* Confirm an error was reported due to AUTOINCREMENT not allowed on WITHOUT ROWID */155  TEST_ASSERT_TRUE_MESSAGE(pParse.nErr > preErr, "Expected error from AUTOINCREMENT on WITHOUT ROWID table");156 157  freeTable(p);158}159 160/* Test: db->init.busy branch sets tnum and TF_Readonly when newTnum==1.161   Use STRICT missing datatype to force early return after init.busy handling. */162void test_sqlite3EndTable_init_busy_sets_tnum_and_readonly(void){163  Parse pParse; initParse(&pParse);164  Table *p = allocTable("t", 1);165  pParse.pNewTable = p;166 167  /* Prepare a STRICT error to return after init.busy handling */168  p->aCol[0].zCnName = sqlite3DbStrDup(gDb, "c1");169  TEST_ASSERT_NOT_NULL(p->aCol[0].zCnName);170  p->aCol[0].eCType = COLTYPE_CUSTOM;      /* custom type */171  p->aCol[0].colFlags = 0;                 /* no HASTYPE -> missing datatype */172  p->aCol[0].notNull = OE_None;173 174  /* Force init.busy path */175  gDb->init.busy = 1;176  gDb->init.newTnum = 1; /* will cause TF_Readonly */177 178  Token tEnd; makeDummyEndToken(&tEnd);179 180  int preErr = pParse.nErr;181  sqlite3EndTable(&pParse, NULL, &tEnd, TF_Strict, NULL);182 183  TEST_ASSERT_EQUAL_INT(1, p->tnum);184  TEST_ASSERT_TRUE(p->tabFlags & TF_Readonly);185  TEST_ASSERT_TRUE_MESSAGE(pParse.nErr > preErr, "STRICT missing datatype should set an error");186 187  /* Reset init state for safety */188  gDb->init.busy = 0;189  gDb->init.newTnum = 0;190 191  freeTable(p);192}193 194/* Test: WITHOUT ROWID requires PRIMARY KEY -> error when missing */195void test_sqlite3EndTable_without_rowid_missing_pk_error(void){196  Parse pParse; initParse(&pParse);197  Table *p = allocTable("t", 1);198  pParse.pNewTable = p;199 200  /* No TF_HasPrimaryKey bit and no PK index -> should error */201  p->aCol[0].zCnName = sqlite3DbStrDup(gDb, "c1");202  TEST_ASSERT_NOT_NULL(p->aCol[0].zCnName);203  p->aCol[0].eCType = COLTYPE_ANY; /* benign */204 205  Token tEnd; makeDummyEndToken(&tEnd);206 207  int preErr = pParse.nErr;208  sqlite3EndTable(&pParse, NULL, &tEnd, TF_WithoutRowid, NULL);209 210  TEST_ASSERT_TRUE_MESSAGE(pParse.nErr > preErr, "WITHOUT ROWID without PRIMARY KEY should set an error");211 212  freeTable(p);213}214 215int main(void) {216  UNITY_BEGIN();217  RUN_TEST(test_sqlite3EndTable_early_return_when_no_end_or_select);218  RUN_TEST(test_sqlite3EndTable_strict_missing_datatype_error);219  RUN_TEST(test_sqlite3EndTable_strict_unknown_datatype_error);220  RUN_TEST(test_sqlite3EndTable_strict_promotes_pk_to_not_null_and_sets_affinity);221  RUN_TEST(test_sqlite3EndTable_init_busy_sets_tnum_and_readonly);222  RUN_TEST(test_sqlite3EndTable_without_rowid_missing_pk_error);223  return UNITY_END();224}