AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdio.h>5 6/* Global DB handle for tests */7static sqlite3 *gDb = NULL;8/* Whether percentile_* functions are available in this build */9static int gHasPercentile = -1;10 11static void detect_percentile_support(void){12 /* Determine if percentile_cont exists in this SQLite build */13 sqlite3_stmt *pStmt = 0;14 const char *zSql = "SELECT percentile_cont(0.5) OVER (ORDER BY 1)";15 int rc = sqlite3_prepare_v2(gDb, zSql, -1, &pStmt, 0);16 if( rc==SQLITE_OK ){17 gHasPercentile = 1;18 sqlite3_finalize(pStmt);19 }else{20 const char *zMsg = sqlite3_errmsg(gDb);21 if( zMsg && strstr(zMsg, "no such function: percentile_cont") ){22 gHasPercentile = 0;23 }else{24 /* If prepare fails for other reasons, assume functions exist and runtime will error */25 gHasPercentile = 1;26 }27 }28}29 30static void assert_sql_error_contains(const char *zSql,31 const char *zMustContain,32 const char *zMustNotContain){33 char *zErr = NULL;34 int rc = sqlite3_exec(gDb, zSql, 0, 0, &zErr);35 /* Expect a runtime error */36 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_ERROR, rc, "Expected SQLITE_ERROR from SQL execution");37 TEST_ASSERT_NOT_NULL_MESSAGE(zErr, "Expected an error message string");38 if( zMustContain ){39 char msg[512];40 snprintf(msg, sizeof(msg), "Error message did not contain expected substring: %s\nSQL: %s\nMsg: %s",41 zMustContain, zSql, zErr);42 TEST_ASSERT_MESSAGE(strstr(zErr, zMustContain)!=NULL, msg);43 }44 if( zMustNotContain ){45 char msg[512];46 snprintf(msg, sizeof(msg), "Error message unexpectedly contained substring: %s\nSQL: %s\nMsg: %s",47 zMustNotContain, zSql, zErr);48 TEST_ASSERT_MESSAGE(strstr(zErr, zMustNotContain)==NULL, msg);49 }50 sqlite3_free(zErr);51}52 53void setUp(void) {54 int rc = sqlite3_open(":memory:", &gDb);55 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);56 57 /* Minimal data for ORDER BY cases */58 rc = sqlite3_exec(gDb,59 "CREATE TABLE t(x INTEGER);"60 "INSERT INTO t(x) VALUES(1),(2),(3),(4),(5);",61 0, 0, 062 );63 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);64 65 detect_percentile_support();66}67 68void tearDown(void) {69 if( gDb ){70 sqlite3_close(gDb);71 gDb = NULL;72 }73}74 75/* Tests */76 77void test_percentError_percentile_cont_requires_order_by(void){78 if( gHasPercentile==0 ){79 TEST_IGNORE_MESSAGE("percentile_cont not available in this build; cannot test percentError via percentile_*");80 }81 /* Missing ORDER BY in OVER() should cause an error referencing percentile_cont() */82 const char *zSql = "SELECT percentile_cont(0.5) OVER () FROM t";83 assert_sql_error_contains(zSql, "percentile_cont()", "%s()");84}85 86void test_percentError_percentile_disc_requires_order_by(void){87 if( gHasPercentile==0 ){88 TEST_IGNORE_MESSAGE("percentile_disc not available in this build; cannot test percentError via percentile_*");89 }90 const char *zSql = "SELECT percentile_disc(0.5) OVER () FROM t";91 assert_sql_error_contains(zSql, "percentile_disc()", "%s()");92}93 94void test_percentError_percentile_cont_percent_out_of_range(void){95 if( gHasPercentile==0 ){96 TEST_IGNORE_MESSAGE("percentile_cont not available in this build; cannot test percentError via percentile_*");97 }98 /* Percentile must be in [0,1]; using -0.1 should trigger an error */99 const char *zSql = "SELECT percentile_cont(-0.1) OVER (ORDER BY x) FROM t";100 assert_sql_error_contains(zSql, "percentile_cont()", "%s()");101}102 103void test_percentError_percentile_disc_multiple_order_by_terms_not_allowed(void){104 if( gHasPercentile==0 ){105 TEST_IGNORE_MESSAGE("percentile_disc not available in this build; cannot test percentError via percentile_*");106 }107 /* If implementation enforces single ORDER BY term, this should error */108 const char *zSql = "SELECT percentile_disc(0.5) OVER (ORDER BY x, x) FROM t";109 assert_sql_error_contains(zSql, "percentile_disc()", "%s()");110}111 112void test_percentError_percentile_cont_used_without_over_clause(void){113 if( gHasPercentile==0 ){114 TEST_IGNORE_MESSAGE("percentile_cont not available in this build; cannot test percentError via percentile_*");115 }116 /* Using percentile_cont as a plain aggregate or scalar should error in SQLite's implementation */117 const char *zSql = "SELECT percentile_cont(0.5) FROM t";118 assert_sql_error_contains(zSql, "percentile_cont()", "%s()");119}120 121int main(void) {122 UNITY_BEGIN();123 RUN_TEST(test_percentError_percentile_cont_requires_order_by);124 RUN_TEST(test_percentError_percentile_disc_requires_order_by);125 RUN_TEST(test_percentError_percentile_cont_percent_out_of_range);126 RUN_TEST(test_percentError_percentile_disc_multiple_order_by_terms_not_allowed);127 RUN_TEST(test_percentError_percentile_cont_used_without_over_clause);128 return UNITY_END();129}