sources/cqlrt_common.h (237 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 <sqlite3.h> #include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <stddef.h> #include <string.h> #include <limits.h> #include <setjmp.h> #ifdef __cplusplus #define CQL_EXTERN_C_BEGIN extern "C" { #define CQL_EXTERN_C_END } #else #define CQL_EXTERN_C_BEGIN #define CQL_EXTERN_C_END #endif // __cplusplus #if LONG_MAX > 0x7fffffff #define _64(x) x##L #else #define _64(x) x##LL #endif #ifndef __has_attribute // Optional of course. #define __has_attribute(x) 0 // Compatibility with non-clang compilers. #endif #if __has_attribute(optnone) #define CQL_OPT_NONE __attribute__((optnone)) #elif __has_attribute(optimize) #define CQL_OPT_NONE __attribute__((optimize("O0"))) #else #define CQL_OPT_NONE #endif #define CQL_EXPORT extern __attribute__((visibility("default"))) #define CQL_WARN_UNUSED __attribute__((warn_unused_result)) CQL_EXTERN_C_BEGIN // Define CQL_COMPAT_VERSION_NUMBER in order to override and test compatibility APIs with any real version of sqlite. static inline int cql_sqlite3_libversion_number(void) { #ifdef CQL_COMPAT_VERSION_NUMBER return CQL_COMPAT_VERSION_NUMBER; #else // CQL_COMPAT_VERSION_NUMBER return sqlite3_libversion_number(); #endif // CQL_COMPAT_VERSION_NUMBER } typedef struct cql_nullable_int32 { cql_bool is_null; cql_int32 value; } cql_nullable_int32; typedef struct cql_nullable_int64 { cql_bool is_null; cql_int64 value; } cql_nullable_int64; typedef struct cql_nullable_double { cql_bool is_null; cql_double value; } cql_nullable_double; typedef struct cql_nullable_bool { cql_bool is_null; cql_bool value; } cql_nullable_bool; // These macros are only used when generate_type_getters is enabled. #define CQL_DATA_TYPE_INT32 1 #define CQL_DATA_TYPE_INT64 2 #define CQL_DATA_TYPE_DOUBLE 3 #define CQL_DATA_TYPE_BOOL 4 #define CQL_DATA_TYPE_STRING 5 #define CQL_DATA_TYPE_BLOB 6 #define CQL_DATA_TYPE_OBJECT 7 #define CQL_DATA_TYPE_CORE 0x3f // bit mask for core types #define CQL_DATA_TYPE_ENCODED 0x40 // set if and only if encode #define CQL_DATA_TYPE_NOT_NULL 0x80 // set if and only if null is not possible #define CQL_CORE_DATA_TYPE_OF(type) ((type) & CQL_DATA_TYPE_CORE) CQL_EXPORT int cql_outstanding_refs; CQL_EXPORT void cql_copyoutrow(sqlite3 *_Nullable db, cql_result_set_ref _Nonnull rs, cql_int32 row, cql_int32 count, ...); CQL_EXPORT void cql_multifetch(cql_code rc, sqlite3_stmt *_Nullable stmt, cql_int32 count, ...); CQL_EXPORT void cql_multibind(cql_code *_Nonnull rc, sqlite3 *_Nonnull db, sqlite3_stmt *_Nullable *_Nonnull pstmt, cql_int32 count, ...); CQL_EXPORT void cql_multibind_var(cql_code *_Nonnull rc, sqlite3 *_Nonnull db, sqlite3_stmt *_Nullable *_Nonnull pstmt, cql_int32 count, const char *_Nullable vpreds, ...); CQL_EXPORT cql_code cql_best_error(cql_code rc); CQL_EXPORT void cql_set_encoding(uint8_t *_Nonnull data_types, cql_int32 count, cql_int32 col, cql_bool encode); typedef struct cql_fetch_info { cql_code rc; sqlite3 *_Nullable db; sqlite3_stmt *_Nullable stmt; uint8_t *_Nonnull data_types; uint16_t *_Nonnull col_offsets; uint16_t refs_count; uint16_t refs_offset; uint16_t *_Nullable identity_columns; int16_t encode_context_index; int32_t rowsize; const char *_Nullable autodrop_tables; int64_t crc; int32_t *_Nullable perf_index; cql_object_ref _Nullable encoder; } cql_fetch_info; CQL_EXPORT void cql_multifetch_meta(char *_Nonnull data, cql_fetch_info *_Nonnull info); CQL_EXPORT cql_code cql_fetch_all_results(cql_fetch_info *_Nonnull info, cql_result_set_ref _Nullable *_Nonnull result_set); CQL_EXPORT cql_code cql_one_row_result(cql_fetch_info *_Nonnull info, char *_Nullable data, int32_t count, cql_result_set_ref _Nullable *_Nonnull result_set); CQL_EXPORT void cql_set_blob_ref(cql_blob_ref _Nullable *_Nonnull target, cql_blob_ref _Nullable source); CQL_EXPORT void cql_set_string_ref(cql_string_ref _Nullable *_Nonnull target, cql_string_ref _Nullable source); CQL_EXPORT void cql_set_object_ref(cql_object_ref _Nullable *_Nonnull target, cql_object_ref _Nullable source); CQL_EXPORT cql_code cql_prepare(sqlite3 *_Nonnull db, sqlite3_stmt *_Nullable *_Nonnull pstmt, const char *_Nonnull sql); CQL_EXPORT cql_code cql_prepare_var(sqlite3 *_Nonnull db, sqlite3_stmt *_Nullable *_Nonnull pstmt, cql_int32 count, const char *_Nullable preds, ...); CQL_EXPORT cql_code cql_no_rows_stmt(sqlite3 *_Nonnull db, sqlite3_stmt *_Nullable *_Nonnull pstmt); CQL_EXPORT cql_result_set_ref _Nonnull cql_no_rows_result_set(void); CQL_EXPORT cql_code cql_exec(sqlite3 *_Nonnull db, const char *_Nonnull sql); CQL_EXPORT cql_code cql_exec_var(sqlite3 *_Nonnull db, cql_int32 count, const char *_Nullable preds, ...); CQL_EXPORT CQL_WARN_UNUSED cql_code cql_exec_internal(sqlite3 *_Nonnull db, cql_string_ref _Nonnull str_ref); CQL_EXPORT cql_code cql_prepare_frags(sqlite3 *_Nonnull db, sqlite3_stmt *_Nullable *_Nonnull pstmt, const char *_Nonnull base, const char *_Nonnull frags); CQL_EXPORT cql_code cql_exec_frags(sqlite3 *_Nonnull db, const char *_Nonnull base, const char *_Nonnull frags); CQL_EXPORT void cql_finalize_on_error(cql_code rc, sqlite3_stmt *_Nullable *_Nonnull pstmt); CQL_EXPORT void cql_finalize_stmt(sqlite3_stmt *_Nullable *_Nonnull pstmt); CQL_EXPORT void cql_column_nullable_bool(sqlite3_stmt *_Nonnull stmt, cql_int32 index, cql_nullable_bool *_Nonnull data); CQL_EXPORT void cql_column_nullable_int32(sqlite3_stmt *_Nonnull stmt, cql_int32 index, cql_nullable_int32 *_Nonnull data); CQL_EXPORT void cql_column_nullable_int64(sqlite3_stmt *_Nonnull stmt, cql_int32 index, cql_nullable_int64 *_Nonnull data); CQL_EXPORT void cql_column_nullable_double(sqlite3_stmt *_Nonnull stmt, cql_int32 index, cql_nullable_double *_Nonnull data); CQL_EXPORT void cql_column_nullable_string_ref(sqlite3_stmt *_Nonnull stmt, cql_int32 index, cql_string_ref _Nullable *_Nonnull data); CQL_EXPORT void cql_column_nullable_blob_ref(sqlite3_stmt *_Nonnull stmt, cql_int32 index, cql_blob_ref _Nullable *_Nonnull data); CQL_EXPORT void cql_column_string_ref(sqlite3_stmt *_Nonnull stmt, cql_int32 index, cql_string_ref _Nonnull *_Nonnull data); CQL_EXPORT void cql_column_blob_ref(sqlite3_stmt *_Nonnull stmt, cql_int32 index, cql_blob_ref _Nonnull *_Nonnull data); #define cql_teardown_row(r) cql_release_offsets(&(r), (r)._refs_count_, (r)._refs_offset_) #define cql_retain_row(r) cql_retain_offsets(&(r), (r)._refs_count_, (r)._refs_offset_) #define cql_offsetof(_struct, _field) ((cql_uint16)offsetof(_struct, _field)) #define cql_combine_nullables(output, l_is_null, r_is_null, value_) \ { cql_bool __saved_is_null = (l_is_null) || (r_is_null); \ (output).value = __saved_is_null ? 0 : (value_); \ (output).is_null = __saved_is_null; } #define cql_set_null(output) \ (output).is_null = cql_true; (output).value = 0; #define cql_set_notnull(output, val) \ (output).value = val; (output).is_null = cql_false; #define cql_set_nullable(output, isnull_, value_) \ { cql_bool __saved_is_null = isnull_; \ (output).value = __saved_is_null ? 0 : (value_); \ (output).is_null = __saved_is_null; } #define cql_is_nullable_true(is_null, value) (!(is_null) && (value)) #define cql_is_nullable_false(is_null, value) (!(is_null) && !(value)) // Enforces (via `cql_tripwire`) that an argument passed in from C to a stored // procedure is not NULL. `position` indicates for which argument we're doing // the checking, counting from 1, *not* 0. void cql_contract_argument_notnull(void *_Nullable argument, cql_uint32 position); // Like `cql_contract_argument_notnull`, but also checks that `*argument` is not // NULL. This should only be used for INOUT arguments of a NOT NULL reference // type; `cql_contract_argument_notnull` should be used in all other cases. void cql_contract_argument_notnull_when_dereferenced(void *_Nullable argument, cql_uint32 position); #ifdef CQL_RUN_TEST // If compiled with `CQL_RUN_TEST`, `cql_contract_argument_notnull` and // `cql_contract_argument_notnull_when_dereferenced` will longjmp here instead // of calling `cql_tripwire` when this is not NULL. The jump will be performed // with a value of `position`, thus allowing tests to know for which argument a // tripwire would have normally been encountered. extern jmp_buf *_Nullable cql_contract_argument_notnull_tripwire_jmp_buf; #endif #define BYTEBUF_GROWTH_SIZE 1024 #define BYTEBUF_EXP_GROWTH_CAP 1024 * 1024 #define BYTEBUF_GROWTH_SIZE_AFTER_CAP 200 * 1024 typedef struct cql_bytebuf { char *_Nullable ptr; // pointer to stored data, if any int used; // bytes used in current buffer int max; // max bytes in current buffer } cql_bytebuf; CQL_EXPORT int bytebuf_open_count; CQL_EXPORT void cql_bytebuf_open(cql_bytebuf *_Nonnull b); CQL_EXPORT void cql_bytebuf_close(cql_bytebuf *_Nonnull b); CQL_EXPORT void *_Nonnull cql_bytebuf_alloc(cql_bytebuf *_Nonnull b, int needed); CQL_EXPORT void cql_bytebuf_append(cql_bytebuf *_Nonnull buffer, const void *_Nonnull data, int32_t bytes); // sqlite3 compat functions for implementations that do not exist in lib versions that are supported. If the runtime // version of sqlite3 supports these functions, it will use those, otherwise it will use the compat version. CQL_EXPORT int cql_compat_sqlite3_strlike(const char *_Nonnull zGlob, const char *_Nonnull zStr, unsigned int cEsc); // teardown all the internal data for the given result_set CQL_EXPORT void cql_result_set_teardown(cql_result_set_ref _Nonnull result_set); // retain/release references in a row using the given offset array CQL_EXPORT void cql_retain_offsets(void *_Nonnull pv, cql_uint16 refs_count, cql_uint16 refs_offset); CQL_EXPORT void cql_release_offsets(void *_Nonnull pv, cql_uint16 refs_count, cql_uint16 refs_offset); // hash a row in a row set using the metadata CQL_EXPORT cql_hash_code cql_row_hash(cql_result_set_ref _Nonnull result_set, cql_int32 row); // compare two rows for equality CQL_EXPORT cql_bool cql_rows_equal(cql_result_set_ref _Nonnull rs1, cql_int32 row1, cql_result_set_ref _Nonnull rs2, cql_int32 row2); // compare two rows for same identity column values CQL_EXPORT cql_bool cql_rows_same(cql_result_set_ref _Nonnull rs1, cql_int32 row1, cql_result_set_ref _Nonnull rs2, cql_int32 row2); // copy a set of rows from a result_set CQL_EXPORT void cql_rowset_copy(cql_result_set_ref _Nonnull result_set, cql_result_set_ref _Nonnull *_Nonnull to_result_set, int32_t from, cql_int32 count); // getters CQL_EXPORT cql_int32 cql_result_set_get_int32_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col); CQL_EXPORT cql_int64 cql_result_set_get_int64_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col); CQL_EXPORT cql_bool cql_result_set_get_bool_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col); CQL_EXPORT cql_double cql_result_set_get_double_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col); CQL_EXPORT cql_string_ref _Nullable cql_result_set_get_string_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col); CQL_EXPORT cql_object_ref _Nullable cql_result_set_get_object_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col); CQL_EXPORT cql_blob_ref _Nullable cql_result_set_get_blob_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col); // setters CQL_EXPORT void cql_result_set_set_int32_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_nullable_int32 new_value); CQL_EXPORT void cql_result_set_set_int32_col_not_null(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_int32 new_value); CQL_EXPORT void cql_result_set_set_int64_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_nullable_int64 new_value); CQL_EXPORT void cql_result_set_set_int64_col_not_null(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_int64 new_value); CQL_EXPORT void cql_result_set_set_bool_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_nullable_bool new_value); CQL_EXPORT void cql_result_set_set_bool_col_not_null(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_bool new_value); CQL_EXPORT void cql_result_set_set_double_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_nullable_double new_value); CQL_EXPORT void cql_result_set_set_double_col_not_null(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_double new_value); CQL_EXPORT void cql_result_set_set_string_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_string_ref _Nullable new_value); CQL_EXPORT void cql_result_set_set_object_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_object_ref _Nullable new_value); CQL_EXPORT void cql_result_set_set_blob_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col, cql_blob_ref _Nullable new_value); // blob serialization and deserialization CQL_EXPORT cql_code cql_deserialize_from_blob( cql_blob_ref _Nullable b, void *_Nonnull cursor, cql_bool *_Nonnull has_row, uint16_t *_Nonnull col_offsets, uint8_t *_Nonnull data_types); CQL_EXPORT cql_code cql_serialize_to_blob( cql_blob_ref _Nullable *_Nonnull b, void *_Nonnull cursor, cql_bool has_row, uint16_t *_Nonnull col_offsets, uint8_t *_Nonnull data_types); CQL_EXPORT cql_bool cql_result_set_get_is_null_col(cql_result_set_ref _Nonnull result_set, cql_int32 row, cql_int32 col); CQL_EXPORT cql_bool cql_result_set_get_is_encoded_col(cql_result_set_ref _Nonnull result_set, cql_int32 col); // result set metadata management CQL_EXPORT void cql_initialize_meta(cql_result_set_meta *_Nonnull meta, cql_fetch_info *_Nonnull info); #ifndef cql_sqlite3_exec #define cql_sqlite3_exec(db, sql) sqlite3_exec((db), (sql), NULL, NULL, NULL) #endif // cql_sqlite3_exec #ifndef cql_sqlite3_prepare_v2 #define cql_sqlite3_prepare_v2(db, sql, len, stmt, tail) sqlite3_prepare_v2((db), (sql), (len), (stmt), (tail)) #endif // cql_sqlite3_prepare_v2 #ifndef cql_sqlite3_finalize #define cql_sqlite3_finalize(stmt) sqlite3_finalize((stmt)) #endif // cql_sqlite3_finalize CQL_EXPORT void cql_results_from_data( cql_code rc, cql_bytebuf *_Nonnull buffer, cql_fetch_info *_Nonnull info, cql_result_set_ref _Nullable *_Nonnull result_set); // data entry for a closed hash table typedef struct cql_hashtab_entry { cql_string_ref _Nullable key; cql_int64 val; } cql_hashtab_entry; // hash table with payloads and capacity info typedef struct cql_hashtab { cql_int32 count; cql_int32 capacity; cql_hashtab_entry *_Nullable payload; } cql_hashtab; // elementary hash table functions CQL_EXPORT cql_hashtab *_Nonnull cql_hashtab_new(void); CQL_EXPORT void cql_hashtab_delete(cql_hashtab *_Nonnull ht); CQL_EXPORT cql_bool cql_hashtab_add(cql_hashtab *_Nonnull ht, cql_string_ref _Nonnull key, cql_int64 val); CQL_EXPORT cql_hashtab_entry *_Nullable cql_hashtab_find(cql_hashtab *_Nonnull ht, cql_string_ref _Nonnull key); // CQL friendly versions of the above, easy to call from CQL CQL_EXPORT cql_int64 cql_facets_new(void); CQL_EXPORT void cql_facets_delete(cql_int64 facets); CQL_EXPORT cql_bool cql_facet_add(cql_int64 facets, cql_string_ref _Nonnull name, cql_int64 crc); CQL_EXPORT cql_int64 cql_facet_find(cql_int64 facets, cql_string_ref _Nonnull key); CQL_EXTERN_C_END