AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Global database handle for Vdbe creation */6static sqlite3 *gDb = NULL;7 8static Vdbe* newVdbe(void){9 Parse pParse;10 memset(&pParse, 0, sizeof(pParse));11 pParse.db = gDb;12 Vdbe *v = sqlite3VdbeCreate(&pParse);13 TEST_ASSERT_NOT_NULL_MESSAGE(v, "sqlite3VdbeCreate returned NULL");14 return v;15}16 17void setUp(void) {18 int rc = sqlite3_open(":memory:", &gDb);19 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");20}21 22void tearDown(void) {23 if( gDb ){24 sqlite3_close(gDb);25 gDb = NULL;26 }27}28 29/* STRICT table, iReg==0: transform previous MakeRecord into TypeCheck and append new MakeRecord */30void test_sqlite3TableAffinity_strict_iReg0_inserts_TypeCheck_before_MakeRecord(void){31 Vdbe *v = newVdbe();32 33 /* Create a STRICT table descriptor */34 Table tab;35 memset(&tab, 0, sizeof(tab));36 tab.tabFlags = TF_Strict;37 tab.nNVCol = 3; /* not used in iReg==0 path, but set anyway */38 39 /* Seed with an OP_MakeRecord so iReg==0 path can transform it */40 int p1 = 10, p2 = 20, p3 = 30;41 int addrMake = sqlite3VdbeAddOp3(v, OP_MakeRecord, p1, p2, p3);42 TEST_ASSERT_TRUE(addrMake >= 0);43 44 /* Under STRICT, iReg==0 should turn the existing MakeRecord into TypeCheck and append new MakeRecord */45 sqlite3TableAffinity(v, &tab, 0);46 47 /* The opcode at addrMake should now be OP_TypeCheck with same p1/p2, p3 cleared to 0.48 Its P4 should be P4_TABLE pointing to &tab. */49 VdbeOp *opType = sqlite3VdbeGetOp(v, addrMake);50 TEST_ASSERT_NOT_NULL(opType);51 TEST_ASSERT_EQUAL_INT(OP_TypeCheck, opType->opcode);52 TEST_ASSERT_EQUAL_INT(p1, opType->p1);53 TEST_ASSERT_EQUAL_INT(p2, opType->p2);54 TEST_ASSERT_EQUAL_INT(0, opType->p3);55 TEST_ASSERT_EQUAL_UINT8(P4_TABLE, opType->p4type);56 TEST_ASSERT_EQUAL_PTR(&tab, opType->p4.p);57 58 /* The last opcode should be a new OP_MakeRecord with original p1/p2/p3 */59 VdbeOp *opLast = sqlite3VdbeGetLastOp(v);60 TEST_ASSERT_NOT_NULL(opLast);61 TEST_ASSERT_EQUAL_INT(OP_MakeRecord, opLast->opcode);62 TEST_ASSERT_EQUAL_INT(p1, opLast->p1);63 TEST_ASSERT_EQUAL_INT(p2, opLast->p2);64 TEST_ASSERT_EQUAL_INT(p3, opLast->p3);65 66 sqlite3VdbeDelete(v);67}68 69/* STRICT table, iReg>0: add isolated OP_TypeCheck with p1=iReg, p2=nNVCol and P4_TABLE set */70void test_sqlite3TableAffinity_strict_with_registers_adds_TypeCheck_with_p4_table(void){71 Vdbe *v = newVdbe();72 73 Table tab;74 memset(&tab, 0, sizeof(tab));75 tab.tabFlags = TF_Strict;76 tab.nNVCol = 4;77 78 int iReg = 7;79 sqlite3TableAffinity(v, &tab, iReg);80 81 VdbeOp *op = sqlite3VdbeGetLastOp(v);82 TEST_ASSERT_NOT_NULL(op);83 TEST_ASSERT_EQUAL_INT(OP_TypeCheck, op->opcode);84 TEST_ASSERT_EQUAL_INT(iReg, op->p1);85 TEST_ASSERT_EQUAL_INT(tab.nNVCol, op->p2);86 TEST_ASSERT_EQUAL_UINT8(P4_TABLE, op->p4type);87 TEST_ASSERT_EQUAL_PTR(&tab, op->p4.p);88 89 sqlite3VdbeDelete(v);90}91 92/* Legacy (non-STRICT), iReg>0: add OP_Affinity with correct p1/p2 and P4 string */93void test_sqlite3TableAffinity_legacy_iReg_sets_Affinity_on_registers(void){94 Vdbe *v = newVdbe();95 96 Table tab;97 memset(&tab, 0, sizeof(tab));98 tab.tabFlags = 0; /* legacy */99 const char *aff = "DEC"; /* 3 columns: REAL/INTEGER/TEXT in SQLite's mapping comment */100 tab.zColAff = (char*)aff;101 102 int iReg = 2;103 sqlite3TableAffinity(v, &tab, iReg);104 105 VdbeOp *op = sqlite3VdbeGetLastOp(v);106 TEST_ASSERT_NOT_NULL(op);107 TEST_ASSERT_EQUAL_INT(OP_Affinity, op->opcode);108 TEST_ASSERT_EQUAL_INT(iReg, op->p1);109 TEST_ASSERT_EQUAL_INT((int)strlen(aff), op->p2);110 /* The affinity string may be stored with exact length; compare prefix */111 TEST_ASSERT_NOT_NULL(op->p4.z);112 TEST_ASSERT_EQUAL_INT(0, strncmp(op->p4.z, aff, (int)strlen(aff)));113 114 sqlite3VdbeDelete(v);115}116 117/* Legacy (non-STRICT), iReg==0: set P4 of existing MakeRecord to affinity string */118void test_sqlite3TableAffinity_legacy_iReg0_sets_affinity_on_MakeRecord_p4(void){119 Vdbe *v = newVdbe();120 121 Table tab;122 memset(&tab, 0, sizeof(tab));123 tab.tabFlags = 0; /* legacy */124 const char *aff = "BCD"; /* TEXT/NUMERIC/INTEGER affinity codes mapping from comments */125 tab.zColAff = (char*)aff;126 127 /* Seed a MakeRecord */128 int addr = sqlite3VdbeAddOp3(v, OP_MakeRecord, 1, 2, 3);129 TEST_ASSERT_TRUE(addr >= 0);130 131 sqlite3TableAffinity(v, &tab, 0);132 133 VdbeOp *op = sqlite3VdbeGetOp(v, addr);134 TEST_ASSERT_NOT_NULL(op);135 TEST_ASSERT_EQUAL_INT(OP_MakeRecord, op->opcode);136 TEST_ASSERT_NOT_NULL(op->p4.z);137 TEST_ASSERT_EQUAL_INT(0, strncmp(op->p4.z, aff, (int)strlen(aff)));138 139 sqlite3VdbeDelete(v);140}141 142/* Legacy (non-STRICT), empty affinity string => no-op (do not alter previous op or P4) */143void test_sqlite3TableAffinity_legacy_empty_affinity_noop(void){144 Vdbe *v = newVdbe();145 146 Table tab;147 memset(&tab, 0, sizeof(tab));148 tab.tabFlags = 0; /* legacy */149 const char *aff = ""; /* empty -> no-op */150 tab.zColAff = (char*)aff;151 152 /* Seed a MakeRecord without P4 */153 int addr = sqlite3VdbeAddOp3(v, OP_MakeRecord, 5, 6, 7);154 TEST_ASSERT_TRUE(addr >= 0);155 156 /* Capture initial p4type (should be 0 / none) */157 VdbeOp *before = sqlite3VdbeGetOp(v, addr);158 TEST_ASSERT_NOT_NULL(before);159 unsigned char p4type_before = before->p4type;160 void *p4ptr_before = before->p4.p;161 162 sqlite3TableAffinity(v, &tab, 0);163 164 VdbeOp *after = sqlite3VdbeGetOp(v, addr);165 TEST_ASSERT_NOT_NULL(after);166 TEST_ASSERT_EQUAL_INT(OP_MakeRecord, after->opcode);167 TEST_ASSERT_EQUAL_UINT8(p4type_before, after->p4type);168 TEST_ASSERT_EQUAL_PTR(p4ptr_before, after->p4.p);169 170 sqlite3VdbeDelete(v);171}172 173int main(void) {174 UNITY_BEGIN();175 RUN_TEST(test_sqlite3TableAffinity_strict_iReg0_inserts_TypeCheck_before_MakeRecord);176 RUN_TEST(test_sqlite3TableAffinity_strict_with_registers_adds_TypeCheck_with_p4_table);177 RUN_TEST(test_sqlite3TableAffinity_legacy_iReg_sets_Affinity_on_registers);178 RUN_TEST(test_sqlite3TableAffinity_legacy_iReg0_sets_affinity_on_MakeRecord_p4);179 RUN_TEST(test_sqlite3TableAffinity_legacy_empty_affinity_noop);180 return UNITY_END();181}