AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdint.h>6 7/* Helper: Build a UTF-16 native-endian string from a UTF-8 (ASCII) C-string.8** Returns malloc'd buffer that must be freed by caller. */9static void *make_utf16_native(const char *z){10 size_t n = strlen(z);11 /* Allocate 2 bytes per character + 2 bytes for terminator */12 unsigned char *buf = (unsigned char*)sqlite3_malloc64((n + 1) * 2);13 TEST_ASSERT_NOT_NULL_MESSAGE(buf, "Failed to allocate UTF16 buffer");14 /* Determine endianness */15 union { uint16_t s; unsigned char b[2]; } u;16 u.s = 0x0102;17 int is_be = (u.b[0] == 0x01);18 19 for(size_t i=0; i<n; i++){20 unsigned char c = (unsigned char)z[i];21 if( is_be ){22 buf[2*i+0] = 0x00;23 buf[2*i+1] = c;24 }else{25 buf[2*i+0] = c;26 buf[2*i+1] = 0x00;27 }28 }29 /* Terminator */30 buf[2*n+0] = 0x00;31 buf[2*n+1] = 0x00;32 return (void*)buf;33}34 35/* Scalar function: add 1 to integer argument, or return NULL if arg is NULL */36static void xAdd1(sqlite3_context *ctx, int argc, sqlite3_value **argv){37 if( argc<1 || sqlite3_value_type(argv[0])==SQLITE_NULL ){38 sqlite3_result_null(ctx);39 return;40 }41 sqlite3_int64 v = sqlite3_value_int64(argv[0]);42 sqlite3_result_int64(ctx, v + 1);43}44 45/* Aggregate sum: sums integer values (NULLs treated as 0) */46static void xSumStep(sqlite3_context *ctx, int argc, sqlite3_value **argv){47 sqlite3_int64 *pSum = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));48 if( pSum==0 ) return; /* OOM handled by SQLite */49 if( argc>0 && sqlite3_value_type(argv[0])!=SQLITE_NULL ){50 *pSum += sqlite3_value_int64(argv[0]);51 }52}53static void xSumFinal(sqlite3_context *ctx){54 sqlite3_int64 *pSum = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);55 if( pSum ){56 sqlite3_result_int64(ctx, *pSum);57 }else{58 sqlite3_result_int64(ctx, 0);59 }60}61 62void setUp(void) {63 /* no-op */64}65void tearDown(void) {66 /* no-op */67}68 69/* Helper: prepare single-step query returning single integer result.70 Asserts success and returns the int64 result. */71static sqlite3_int64 run_single_int64(sqlite3 *db, const char *sql){72 sqlite3_stmt *pStmt = 0;73 int rc = sqlite3_prepare_v2(db, sql, -1, &pStmt, 0);74 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, sqlite3_errmsg(db));75 rc = sqlite3_step(pStmt);76 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ROW, rc, "Expected one row");77 sqlite3_int64 v = sqlite3_column_int64(pStmt, 0);78 rc = sqlite3_step(pStmt);79 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_DONE, rc, "Expected exactly one row");80 sqlite3_finalize(pStmt);81 return v;82}83 84void test_sqlite3_create_function16_scalar_ok(void){85 sqlite3 *db = 0;86 int rc = sqlite3_open(":memory:", &db);87 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);88 89 void *name16 = make_utf16_native("x_add1");90 rc = sqlite3_create_function16(91 db, name16, 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,92 NULL, xAdd1, NULL, NULL93 );94 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);95 96 sqlite3_int64 v = run_single_int64(db, "SELECT x_add1(41)");97 TEST_ASSERT_EQUAL_INT64(42, v);98 99 sqlite3_free(name16);100 sqlite3_close(db);101}102 103void test_sqlite3_create_function16_aggregate_ok(void){104 sqlite3 *db = 0;105 int rc = sqlite3_open(":memory:", &db);106 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);107 108 void *name16 = make_utf16_native("mysum");109 rc = sqlite3_create_function16(110 db, name16, 1, SQLITE_UTF8, NULL, NULL, xSumStep, xSumFinal111 );112 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);113 114 sqlite3_int64 v = run_single_int64(db,115 "SELECT mysum(x) FROM (VALUES(1),(2),(3)) AS t(x)"116 );117 TEST_ASSERT_EQUAL_INT64(6, v);118 119 sqlite3_free(name16);120 sqlite3_close(db);121}122 123void test_sqlite3_create_function16_misuse_flags(void){124 sqlite3 *db = 0;125 int rc = sqlite3_open(":memory:", &db);126 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);127 128 /* Both xSFunc and xFinal non-NULL is misuse */129 void *name16a = make_utf16_native("badfunc1");130 rc = sqlite3_create_function16(131 db, name16a, 1, SQLITE_UTF8, NULL, xAdd1, NULL, xSumFinal132 );133 TEST_ASSERT_EQUAL_INT(SQLITE_MISUSE, rc);134 sqlite3_free(name16a);135 136 /* xStep without xFinal is misuse */137 void *name16b = make_utf16_native("badfunc2");138 rc = sqlite3_create_function16(139 db, name16b, 1, SQLITE_UTF8, NULL, NULL, xSumStep, NULL140 );141 TEST_ASSERT_EQUAL_INT(SQLITE_MISUSE, rc);142 sqlite3_free(name16b);143 144 sqlite3_close(db);145}146 147void test_sqlite3_create_function16_nArg_invalid(void){148 sqlite3 *db = 0;149 int rc = sqlite3_open(":memory:", &db);150 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);151 152 /* nArg < -1 is invalid */153 void *name16 = make_utf16_native("negarg");154 rc = sqlite3_create_function16(155 db, name16, -2, SQLITE_UTF8, NULL, xAdd1, NULL, NULL156 );157 TEST_ASSERT_EQUAL_INT(SQLITE_MISUSE, rc);158 sqlite3_free(name16);159 160 sqlite3_close(db);161}162 163void test_sqlite3_create_function16_delete_function(void){164 sqlite3 *db = 0;165 int rc = sqlite3_open(":memory:", &db);166 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);167 168 void *name16 = make_utf16_native("toDelete");169 170 /* Create */171 rc = sqlite3_create_function16(172 db, name16, 1, SQLITE_UTF8, NULL, xAdd1, NULL, NULL173 );174 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);175 176 /* Verify works */177 sqlite3_int64 v = run_single_int64(db, "SELECT toDelete(5)");178 TEST_ASSERT_EQUAL_INT64(6, v);179 180 /* Delete by passing NULL xSFunc and NULL xFinal */181 rc = sqlite3_create_function16(182 db, name16, 1, SQLITE_UTF8, NULL, NULL, NULL, NULL183 );184 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);185 186 /* Now preparing a statement that uses the deleted function should fail */187 sqlite3_stmt *pStmt = 0;188 rc = sqlite3_prepare_v2(db, "SELECT toDelete(5)", -1, &pStmt, 0);189 TEST_ASSERT_NOT_EQUAL_MESSAGE(SQLITE_OK, rc, "Expected error preparing unknown function");190 if( pStmt ) sqlite3_finalize(pStmt);191 192 /* Error message should mention 'no such function' */193 const char *zErr = sqlite3_errmsg(db);194 TEST_ASSERT_NOT_NULL(zErr);195 TEST_ASSERT_NOT_NULL_MESSAGE(strstr(zErr, "no such function"), "Expected 'no such function' in error message");196 197 sqlite3_free(name16);198 sqlite3_close(db);199}200 201int main(void){202 UNITY_BEGIN();203 RUN_TEST(test_sqlite3_create_function16_scalar_ok);204 RUN_TEST(test_sqlite3_create_function16_aggregate_ok);205 RUN_TEST(test_sqlite3_create_function16_misuse_flags);206 RUN_TEST(test_sqlite3_create_function16_nArg_invalid);207 RUN_TEST(test_sqlite3_create_function16_delete_function);208 return UNITY_END();209}