AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5#include <stdio.h>6 7/* Simple scalar function that returns constant 42 */8static void xConst42(sqlite3_context *ctx, int argc, sqlite3_value **argv){9 SQLITE_UNUSED_PARAMETER(argc);10 SQLITE_UNUSED_PARAMETER(argv);11 sqlite3_result_int(ctx, 42);12}13 14/* Scalar function that returns the argc it was called with */15static void xCountArgs(sqlite3_context *ctx, int argc, sqlite3_value **argv){16 SQLITE_UNUSED_PARAMETER(argv);17 sqlite3_result_int(ctx, argc);18}19 20void setUp(void) {21 /* no-op */22}23 24void tearDown(void) {25 /* no-op */26}27 28/* Helper: prepare, step once expecting a row, fetch first column int */29static int eval_single_int(sqlite3 *db, const char *sql, int *pOut){30 sqlite3_stmt *pStmt = 0;31 int rc = sqlite3_prepare_v2(db, sql, -1, &pStmt, 0);32 if( rc!=SQLITE_OK ) goto done;33 rc = sqlite3_step(pStmt);34 if( rc==SQLITE_ROW ){35 *pOut = sqlite3_column_int(pStmt, 0);36 rc = SQLITE_OK;37 }else{38 /* Return step rc if not a row */39 }40done:41 sqlite3_finalize(pStmt);42 return rc;43}44 45/* Test: If a function already exists, sqlite3_overload_function is a no-op */46void test_sqlite3_overload_function_noop_when_function_exists(void){47 sqlite3 *db = 0;48 int rc = sqlite3_open(":memory:", &db);49 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);50 TEST_ASSERT_NOT_NULL(db);51 52 /* Create a scalar function 'preexist' with 1 argument that returns 42 */53 rc = sqlite3_create_function(db, "preexist", 1, SQLITE_UTF8, 0, xConst42, 0, 0);54 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);55 56 /* Call sqlite3_overload_function — should be a no-op returning OK */57 rc = sqlite3_overload_function(db, "preexist", 1);58 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);59 60 /* Verify the function still behaves as the user-defined function */61 sqlite3_stmt *pStmt = 0;62 rc = sqlite3_prepare_v2(db, "SELECT preexist(7)", -1, &pStmt, 0);63 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);64 rc = sqlite3_step(pStmt);65 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);66 TEST_ASSERT_EQUAL_INT(42, sqlite3_column_int(pStmt, 0));67 sqlite3_finalize(pStmt);68 69 sqlite3_close(db);70}71 72/* Test: Creating an overloaded function when none exists (fixed arity) */73void test_sqlite3_overload_function_creates_invalid_function_fixed_arity(void){74 sqlite3 *db = 0;75 int rc = sqlite3_open(":memory:", &db);76 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);77 TEST_ASSERT_NOT_NULL(db);78 79 /* No function 'ovfA' exists yet. Overload should create an invalid function. */80 rc = sqlite3_overload_function(db, "ovfA", 2);81 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);82 83 /* Prepare should succeed because name resolution finds the function */84 sqlite3_stmt *pStmt = 0;85 rc = sqlite3_prepare_v2(db, "SELECT ovfA(1, 2)", -1, &pStmt, 0);86 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);87 88 /* Execution should error because sqlite3InvalidFunction is used */89 rc = sqlite3_step(pStmt);90 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);91 sqlite3_finalize(pStmt);92 93 /* Now define a real function with same name/arity and confirm it overrides */94 rc = sqlite3_create_function(db, "ovfA", 2, SQLITE_UTF8, 0, xCountArgs, 0, 0);95 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);96 97 int out = 0;98 rc = eval_single_int(db, "SELECT ovfA(10, 20)", &out);99 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);100 TEST_ASSERT_EQUAL_INT(2, out);101 102 sqlite3_close(db);103}104 105/* Test: Any-arity (-1) overloaded function is created and can be overridden */106void test_sqlite3_overload_function_creates_invalid_function_any_arity_and_can_be_overridden(void){107 sqlite3 *db = 0;108 int rc = sqlite3_open(":memory:", &db);109 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);110 TEST_ASSERT_NOT_NULL(db);111 112 /* Create any-arity overloaded function */113 rc = sqlite3_overload_function(db, "ovfAny", -1);114 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);115 116 /* Prepare should succeed for 0 args, but execution should error */117 sqlite3_stmt *pStmt = 0;118 rc = sqlite3_prepare_v2(db, "SELECT ovfAny()", -1, &pStmt, 0);119 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);120 rc = sqlite3_step(pStmt);121 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);122 sqlite3_finalize(pStmt);123 124 /* Prepare with multiple args should also resolve, but execution should error */125 rc = sqlite3_prepare_v2(db, "SELECT ovfAny(1,2,3)", -1, &pStmt, 0);126 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);127 rc = sqlite3_step(pStmt);128 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);129 sqlite3_finalize(pStmt);130 131 /* Override ovfAny with a real any-arity function that returns the arg count */132 rc = sqlite3_create_function(db, "ovfAny", -1, SQLITE_UTF8, 0, xCountArgs, 0, 0);133 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);134 135 int out = -1;136 rc = eval_single_int(db, "SELECT ovfAny(5,6,7,8)", &out);137 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);138 TEST_ASSERT_EQUAL_INT(4, out);139 140 sqlite3_close(db);141}142 143/* Test: Idempotent behavior when called again after prior overload creation */144void test_sqlite3_overload_function_idempotent_on_existing_invalid_function(void){145 sqlite3 *db = 0;146 int rc = sqlite3_open(":memory:", &db);147 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);148 TEST_ASSERT_NOT_NULL(db);149 150 /* First call creates the invalid function */151 rc = sqlite3_overload_function(db, "ovfB", 1);152 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);153 154 /* Second call should be a no-op and still return OK */155 rc = sqlite3_overload_function(db, "ovfB", 1);156 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);157 158 /* Behavior should remain the same: prepare OK, execution error */159 sqlite3_stmt *pStmt = 0;160 rc = sqlite3_prepare_v2(db, "SELECT ovfB(123)", -1, &pStmt, 0);161 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);162 rc = sqlite3_step(pStmt);163 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);164 sqlite3_finalize(pStmt);165 166 sqlite3_close(db);167}168 169int main(void) {170 UNITY_BEGIN();171 RUN_TEST(test_sqlite3_overload_function_noop_when_function_exists);172 RUN_TEST(test_sqlite3_overload_function_creates_invalid_function_fixed_arity);173 RUN_TEST(test_sqlite3_overload_function_creates_invalid_function_any_arity_and_can_be_overridden);174 RUN_TEST(test_sqlite3_overload_function_idempotent_on_existing_invalid_function);175 return UNITY_END();176}