sources/cqlrt_cf/cqlrt_cf.h (205 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include <assert.h> #include <stddef.h> #include <stdint.h> #include <math.h> #include <sqlite3.h> #include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CFBase.h> #include <CoreFoundation/CFString.h> #ifndef __clang__ #ifndef _Nonnull /* Hide Clang-only nullability specifiers if not Clang */ #define _Nonnull #define _Nullable #endif #endif #define cql_contract assert #define cql_invariant assert #define cql_tripwire assert // Default database loggign does nothing #define cql_log_database_error(db, cat, msg) // Default tracing does nothing #ifndef CQL_TRACING_ENABLED #define cql_error_trace() #else // whatever tracing you want, for example this might help in test code. #define cql_error_trace() \ fprintf(stderr, "Error at %s:%d in %s: %d %s\n", __FILE__, __LINE__, _PROC_, _rc_, sqlite3_errmsg(_db_)) #endif // value types typedef Boolean cql_bool; #define cql_true TRUE #define cql_false FALSE // metatypes for the straight C implementation #define CQL_C_TYPE_STRING 0 #define CQL_C_TYPE_BLOB 1 #define CQL_C_TYPE_RESULTS 2 #define CQL_C_TYPE_BOXED_STMT 3 #define CQL_C_TYPE_OBJECT 4 typedef unsigned long cql_hash_code; typedef int32_t cql_int32; typedef uint32_t cql_uint32; typedef uint16_t cql_uint16; typedef sqlite3_int64 cql_int64; typedef double cql_double; typedef int cql_code; // CF base helpers typedef CFTypeRef cql_type_ref; void cql_retain(CFTypeRef _Nullable ref); void cql_release(CFTypeRef _Nullable ref); cql_hash_code cql_ref_hash(CFTypeRef _Nonnull ref); cql_bool cql_ref_equal(CFTypeRef _Nonnull r1, CFTypeRef _Nonnull r2); // CF Blob typedef CFDataRef cql_blob_ref ; void cql_blob_retain(cql_blob_ref _Nullable obj); void cql_blob_release(cql_blob_ref _Nullable obj); void *_Nonnull cql_get_blob_bytes(cql_blob_ref _Nonnull blob); cql_int64 cql_get_blob_size(cql_blob_ref _Nonnull blob); cql_blob_ref _Nonnull cql_blob_ref_new(const void *_Nonnull bytes, cql_int64 size); cql_bool cql_blob_equal(cql_blob_ref _Nonnull b1, cql_blob_ref _Nonnull b2); // CF object typedef CFTypeRef cql_object_ref ; void cql_object_retain(cql_object_ref _Nullable obj); void cql_object_release(cql_object_ref _Nullable obj); #define CF_C_STRING_STACK_MAX_LENGTH 512 #define CF_STRING_CREATE_C_STRING_STACK(cStringVar) \ char __##cStringVar##Stack[CF_C_STRING_STACK_MAX_LENGTH]; \ char *_Nonnull cStringVar = __##cStringVar##Stack; // The strange calling convention is designed to catch errors. // the stack storage is passed in via cStringVar // if it's usable, great, if not, cStringVar is mutated to point to the heap. // The heap allocation, if any, is returned. If you fail to use the CF_STRING_FREE_C_STRING // then the compiler will warn you that __cStringVarHeap is unused. // The funky argument choice creates a safer macro and better code-gen. // CF_STRING_CREATE_C_STRING will produce a NULL cStringVar if passed a NULL cfString. #define CF_STRING_CREATE_C_STRING(cStringVar, cfString) \ CF_STRING_CREATE_C_STRING_STACK(cStringVar) \ char *_Nullable __##cStringVar##Heap = cql_copy_string_to_stack_or_heap(cfString, &cStringVar); // CF_STRING_FREE_C_STRING will do nothing if passed a NULL cStringVar. #define CF_STRING_FREE_C_STRING(cStringVar, cfString) \ if (__##cStringVar##Heap) free(__##cStringVar##Heap); char *_Nullable cql_copy_string_to_stack_or_heap(CFStringRef _Nullable cfString, char *_Nullable *_Nonnull result); // CF String typedef CFStringRef cql_string_ref; void cql_string_retain(cql_string_ref _Nullable str); void cql_string_release(cql_string_ref _Nullable str); cql_string_ref _Nonnull cql_string_ref_new(const char *_Nonnull cstr); cql_hash_code cql_string_hash(cql_string_ref _Nonnull str); cql_int32 cql_string_equal(cql_string_ref _Nonnull s1, cql_string_ref _Nonnull s2); cql_int32 cql_string_compare(cql_string_ref _Nonnull s1, cql_string_ref _Nonnull s2); cql_int32 cql_string_like(cql_string_ref _Nonnull s1, cql_string_ref _Nonnull s2); // useful for declaring strings in C, not useful to other languages #define cql_alloc_cstr(cstr, str) CF_STRING_CREATE_C_STRING(cstr, str) #define cql_free_cstr(cstr, str) CF_STRING_FREE_C_STRING(cstr, str) #define CF_CONST_STRING(name, value) CFStringRef _Nonnull name = CFSTR(value); #define cql_string_literal CF_CONST_STRING #define cql_string_proc_name CF_CONST_STRING // This is the abstract holder for these items with only the C interface to get the contents typedef CFTypeRef CQLHolderRef; typedef CQLHolderRef cql_result_set_ref; typedef CQLHolderRef cql_boxed_stmt_ref; // builtin statement box typedef struct cql_boxed_stmt { sqlite3_stmt *_Nullable stmt; } cql_boxed_stmt; typedef struct cql_result_set_meta { // release the internal memory for the rowset void (*_Nonnull teardown)(cql_result_set_ref _Nonnull result_set); // copy a slice of a result set starting at from of length count void (*_Nullable copy)( cql_result_set_ref _Nonnull result_set, cql_result_set_ref _Nullable *_Nonnull to_result_set, cql_int32 from, cql_int32 count); // hash a row in a row set using the metadata cql_hash_code (*_Nullable rowHash)( cql_result_set_ref _Nonnull result_set, cql_int32 row); // compare two rows for equality cql_bool (*_Nullable rowsEqual)( cql_result_set_ref _Nonnull rs1, cql_int32 row1, cql_result_set_ref _Nonnull rs2, cql_int32 row2); // compare two rows for the same identity column value(s) cql_bool (*_Nullable rowsSame)( cql_result_set_ref _Nonnull rs1, cql_int32 row1, cql_result_set_ref _Nonnull rs2, cql_int32 row2); // check whether the column value is encoded cql_bool(*_Nullable getIsEncoded)( cql_result_set_ref _Nonnull result_set, cql_int32 col); // count of references and offset to the first uint16_t refsCount; uint16_t refsOffset; // offsets to all the columns uint16_t *_Nullable columnOffsets; // size of the row size_t rowsize; // number of columns cql_int32 columnCount; // count and column indexes of all the columns in the identity uint16_t *_Nullable identityColumns; // all datatypes of the columns uint8_t *_Nullable dataTypes; // index of the encode context column int16_t encodeContextIndex; } cql_result_set_meta; typedef struct cql_result_set { cql_result_set_meta meta; cql_int32 count; void *_Nonnull data; } cql_result_set; #define cql_result_set_type_decl(result_set_type, result_set_ref) \ typedef cql_result_set_ref result_set_ref; cql_result_set_ref _Nonnull cql_result_set_create( void *_Nonnull data, cql_int32 count, cql_result_set_meta meta); cql_result_set *_Nonnull cql_get_result_set_from_ref(cql_result_set_ref _Nonnull ref); #define cql_result_set_retain(result_set) cql_retain((cql_type_ref)result_set); #define cql_result_set_release(result_set) cql_release((cql_type_ref)result_set); #define cql_result_set_note_ownership_transferred(result_set) #define cql_result_set_get_meta(result_set_ref) (&cql_get_result_set_from_ref(result_set_ref)->meta) #define cql_result_set_get_data(result_set_ref) (cql_get_result_set_from_ref(result_set_ref)->data) #define cql_result_set_get_count(result_set_ref) (cql_get_result_set_from_ref(result_set_ref)->count) #ifdef CQL_RUN_TEST #define sqlite3_step mockable_sqlite3_step SQLITE_API cql_code mockable_sqlite3_step(sqlite3_stmt *_Nonnull); #endif // No-op implementation of profiling // * Note: we emit the crc as an expression just to be sure that there are no compiler // errors caused by names being incorrect. This improves the quality of the CQL // code gen tests significantly. If these were empty macros (as they once were) // you could emit any junk in the call and it would still compile. #define cql_profile_start(crc, index) (void)crc; (void)index; #define cql_profile_stop(crc, index) (void)crc; (void)index; // the basic version doesn't use column getters #define CQL_NO_GETTERS 1 // implementation of encoding values. All sensitive values read from sqlite db will // be encoded at the source. CQL never decode encoded sensitive string unless the // user call explicitly decode function from code. cql_object_ref _Nullable cql_copy_encoder(sqlite3 *_Nonnull db); cql_bool cql_encode_bool( cql_object_ref _Nullable encoder, cql_bool value, cql_int32 context_type, void *_Nullable context); cql_int32 cql_encode_int32( cql_object_ref _Nullable encoder, cql_int32 value, cql_int32 context_type, void *_Nullable context); cql_int64 cql_encode_int64( cql_object_ref _Nullable encoder, cql_int64 value, cql_int32 context_type, void *_Nullable context); cql_double cql_encode_double( cql_object_ref _Nullable encoder, cql_double value, cql_int32 context_type, void *_Nullable context); cql_string_ref _Nonnull cql_encode_string_ref_new( cql_object_ref _Nullable encoder, cql_string_ref _Nonnull value, cql_int32 context_type, void *_Nullable context); cql_blob_ref _Nonnull cql_encode_blob_ref_new( cql_object_ref _Nullable encoder, cql_blob_ref _Nonnull value, cql_int32 context_type, void *_Nullable context); cql_bool cql_decode_bool( cql_object_ref _Nullable encoder, cql_bool value, cql_int32 context_type, void *_Nullable context); cql_int32 cql_decode_int32( cql_object_ref _Nullable encoder, cql_int32 value, cql_int32 context_type, void *_Nullable context); cql_int64 cql_decode_int64( cql_object_ref _Nullable encoder, cql_int64 value, cql_int32 context_type, void *_Nullable context); cql_double cql_decode_double( cql_object_ref _Nullable encoder, cql_double value, cql_int32 context_type, void *_Nullable context); cql_string_ref _Nonnull cql_decode_string_ref_new( cql_object_ref _Nullable encoder, cql_string_ref _Nonnull value, cql_int32 context_type, void *_Nullable context); cql_blob_ref _Nonnull cql_decode_blob_ref_new( cql_object_ref _Nullable encoder, cql_blob_ref _Nonnull value, cql_int32 context_type, void *_Nullable context); cql_object_ref _Nonnull cql_box_stmt(sqlite3_stmt *_Nullable stmt); sqlite3_stmt *_Nullable cql_unbox_stmt(cql_object_ref _Nonnull ref); // NOTE: This must be included *after* all of the above symbols/macros. #include "cqlrt_common.h"