AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdio.h>5 6static sqlite3 *gDb = NULL;7 8static void init_parse(sqlite3 *db, Parse *p){9 memset(p, 0, sizeof(*p));10 p->db = db;11 db->pParse = p; /* sqlite3Insert asserts this */12}13 14static void cleanup_parse(Parse *p){15 if( p && p->pVdbe ){16 sqlite3VdbeDelete(p->pVdbe);17 p->pVdbe = NULL;18 }19 if( p && p->db ){20 p->db->pParse = NULL;21 }22}23 24static SrcList* srcListFromName(sqlite3 *db, const char *zName){25 Token t;26 t.z = zName;27 t.n = (int)strlen(zName);28 return sqlite3SrcListAppend(db, NULL, &t, NULL);29}30 31static IdList* idListFromNames(sqlite3 *db, const char *const *az, int n){32 IdList *p = NULL;33 for(int i=0;i<n;i++){34 Token t;35 t.z = az[i];36 t.n = (int)strlen(az[i]);37 p = sqlite3IdListAppend(db, p, &t);38 }39 return p;40}41 42static int vdbeHasOpcode(Vdbe *v, int opcode){43 if( v==NULL ) return 0;44 int n = sqlite3VdbeCurrentAddr(v);45 for(int i=0; i<n; i++){46 VdbeOp *pOp = sqlite3VdbeGetOp(v, i);47 if( pOp && pOp->opcode==opcode ) return 1;48 }49 return 0;50}51 52void setUp(void) {53 int rc = sqlite3_open(":memory:", &gDb);54 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);55}56 57void tearDown(void) {58 if( gDb ){59 sqlite3_close(gDb);60 gDb = NULL;61 }62}63 64/* Test 1: Successful DEFAULT VALUES insert into a simple rowid table. */65void test_sqlite3Insert_default_values_generates_insert_ops(void){66 int rc;67 char *zErr = 0;68 rc = sqlite3_exec(gDb, "CREATE TABLE t1(a INTEGER, b TEXT);", 0, 0, &zErr);69 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, zErr?zErr:"exec failed");70 if(zErr) sqlite3_free(zErr);71 72 Parse p; init_parse(gDb, &p);73 SrcList *pTabList = srcListFromName(gDb, "t1");74 /* DEFAULT VALUES: pSelect=NULL, pColumn=NULL, onError=OE_Default */75 sqlite3Insert(&p, pTabList, NULL, NULL, OE_Default, NULL);76 77 /* No parse errors expected */78 TEST_ASSERT_EQUAL_INT(0, p.nErr);79 TEST_ASSERT_NOT_NULL(p.pVdbe);80 81 /* Verify essential VDBE opcodes for an insert path */82 TEST_ASSERT_TRUE_MESSAGE(vdbeHasOpcode(p.pVdbe, OP_OpenWrite), "Expected OP_OpenWrite");83 TEST_ASSERT_TRUE_MESSAGE(vdbeHasOpcode(p.pVdbe, OP_MakeRecord), "Expected OP_MakeRecord");84 TEST_ASSERT_TRUE_MESSAGE(vdbeHasOpcode(p.pVdbe, OP_Insert), "Expected OP_Insert");85 86 cleanup_parse(&p);87}88 89/* Test 2: Error when IDLIST contains a non-existent column name. */90void test_sqlite3Insert_nonexistent_column_sets_error(void){91 int rc; char *zErr = 0;92 rc = sqlite3_exec(gDb, "CREATE TABLE t1(a, b);", 0, 0, &zErr);93 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, zErr?zErr:"exec failed");94 if(zErr) sqlite3_free(zErr);95 96 Parse p; init_parse(gDb, &p);97 SrcList *pTabList = srcListFromName(gDb, "t1");98 const char *cols[] = {"doesnotexist"};99 IdList *pColumn = idListFromNames(gDb, cols, 1);100 101 sqlite3Insert(&p, pTabList, NULL, pColumn, OE_Default, NULL);102 103 TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "Expected parse error when column does not exist");104 TEST_ASSERT_EQUAL_INT(1, p.checkSchema); /* sqlite3Insert sets this on this error */105 106 cleanup_parse(&p);107}108 109/* Test 3: Mismatch between provided column list and number of values. */110void test_sqlite3Insert_column_value_count_mismatch_sets_error(void){111 int rc; char *zErr = 0;112 rc = sqlite3_exec(gDb, "CREATE TABLE t1(a, b);", 0, 0, &zErr);113 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, zErr?zErr:"exec failed");114 if(zErr) sqlite3_free(zErr);115 116 Parse p; init_parse(gDb, &p);117 SrcList *pTabList = srcListFromName(gDb, "t1");118 /* Provide IDLIST with one valid column but no values (DEFAULT VALUES scenario).119 This should trigger the mismatch check: nColumn(=0) != pColumn->nId(=1). */120 const char *cols[] = {"a"};121 IdList *pColumn = idListFromNames(gDb, cols, 1);122 123 sqlite3Insert(&p, pTabList, NULL, pColumn, OE_Default, NULL);124 125 TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "Expected error due to column/value count mismatch");126 127 cleanup_parse(&p);128}129 130/* Test 4: Attempt to insert into a view should set an error (read-only). */131void test_sqlite3Insert_into_view_sets_error(void){132 int rc; char *zErr = 0;133 rc = sqlite3_exec(gDb,134 "CREATE TABLE t1(a, b);"135 "CREATE VIEW v1 AS SELECT a, b FROM t1;",136 0, 0, &zErr137 );138 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, zErr?zErr:"exec failed");139 if(zErr) sqlite3_free(zErr);140 141 Parse p; init_parse(gDb, &p);142 SrcList *pTabList = srcListFromName(gDb, "v1");143 144 sqlite3Insert(&p, pTabList, NULL, NULL, OE_Default, NULL);145 146 TEST_ASSERT_TRUE_MESSAGE(p.nErr>0, "Expected error inserting into a view");147 148 cleanup_parse(&p);149}150 151int main(void){152 UNITY_BEGIN();153 RUN_TEST(test_sqlite3Insert_default_values_generates_insert_ops);154 RUN_TEST(test_sqlite3Insert_nonexistent_column_sets_error);155 RUN_TEST(test_sqlite3Insert_column_value_count_mismatch_sets_error);156 RUN_TEST(test_sqlite3Insert_into_view_sets_error);157 return UNITY_END();158}