summaryrefslogtreecommitdiffstats
path: root/src/lib-sql/sql-api.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-sql/sql-api.h249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/lib-sql/sql-api.h b/src/lib-sql/sql-api.h
new file mode 100644
index 0000000..7936b98
--- /dev/null
+++ b/src/lib-sql/sql-api.h
@@ -0,0 +1,249 @@
+#ifndef SQL_API_H
+#define SQL_API_H
+
+struct timespec;
+
+/* This SQL API is designed to work asynchronously. The underlying drivers
+ however may not. */
+
+enum sql_db_flags {
+ /* Set if queries are not executed asynchronously */
+ SQL_DB_FLAG_BLOCKING = 0x01,
+ /* Set if database wants to use connection pooling */
+ SQL_DB_FLAG_POOLED = 0x02,
+ /* Prepared statements are supported by the database. If they aren't,
+ the functions can still be used, but they're just internally
+ convered into regular statements. */
+ SQL_DB_FLAG_PREP_STATEMENTS = 0x04,
+ /* Database supports INSERT .. ON DUPLICATE KEY syntax. */
+ SQL_DB_FLAG_ON_DUPLICATE_KEY = 0x08,
+ /* Database supports INSERT .. ON CONFLICT DO UPDATE syntax. */
+ SQL_DB_FLAG_ON_CONFLICT_DO = 0x10,
+};
+
+enum sql_field_type {
+ SQL_TYPE_STR,
+ SQL_TYPE_UINT,
+ SQL_TYPE_ULLONG,
+ SQL_TYPE_BOOL
+};
+
+struct sql_field_def {
+ enum sql_field_type type;
+ const char *name;
+ size_t offset;
+};
+
+enum sql_result_error_type {
+ SQL_RESULT_ERROR_TYPE_UNKNOWN = 0,
+ /* It's unknown whether write succeeded or not. This could be due to
+ a timeout or a disconnection from server. */
+ SQL_RESULT_ERROR_TYPE_WRITE_UNCERTAIN
+};
+
+enum sql_result_next {
+ /* Row was returned */
+ SQL_RESULT_NEXT_OK = 1,
+ /* There are no more rows */
+ SQL_RESULT_NEXT_LAST = 0,
+ /* Error occurred - see sql_result_get_error*() */
+ SQL_RESULT_NEXT_ERROR = -1,
+ /* There are more results - call sql_result_more() */
+ SQL_RESULT_NEXT_MORE = -99
+};
+
+#define SQL_DEF_STRUCT(name, struct_name, type, c_type) \
+ { (type) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+ ((struct struct_name *)0)->name, c_type), \
+ #name, offsetof(struct struct_name, name) }
+
+#define SQL_DEF_STRUCT_STR(name, struct_name) \
+ SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_STR, const char *)
+#define SQL_DEF_STRUCT_UINT(name, struct_name) \
+ SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_UINT, unsigned int)
+#define SQL_DEF_STRUCT_ULLONG(name, struct_name) \
+ SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_ULLONG, unsigned long long)
+#define SQL_DEF_STRUCT_BOOL(name, struct_name) \
+ SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_BOOL, bool)
+
+struct sql_db;
+struct sql_result;
+
+struct sql_commit_result {
+ const char *error;
+ enum sql_result_error_type error_type;
+};
+
+struct sql_settings {
+ const char *driver;
+ const char *connect_string;
+ struct event *event_parent;
+};
+
+typedef void sql_query_callback_t(struct sql_result *result, void *context);
+typedef void sql_commit_callback_t(const struct sql_commit_result *result, void *context);
+
+void sql_drivers_init(void);
+void sql_drivers_deinit(void);
+
+/* register all built-in SQL drivers */
+void sql_drivers_register_all(void);
+
+void sql_driver_register(const struct sql_db *driver);
+void sql_driver_unregister(const struct sql_db *driver);
+
+/* Initialize database connections. db_driver is the database driver name,
+ eg. "mysql" or "pgsql". connect_string is driver-specific. */
+struct sql_db *sql_init(const char *db_driver, const char *connect_string);
+int sql_init_full(const struct sql_settings *set, struct sql_db **db_r,
+ const char **error_r);
+
+void sql_ref(struct sql_db *db);
+void sql_unref(struct sql_db **db);
+
+/* Returns SQL database state flags. */
+enum sql_db_flags sql_get_flags(struct sql_db *db);
+
+/* Explicitly connect to the database. It's not required to call this function
+ though. Returns -1 if we're not connected, 0 if we started connecting or
+ 1 if we are fully connected now. */
+int sql_connect(struct sql_db *db);
+/* Explicitly disconnect from database and abort pending auth requests. */
+void sql_disconnect(struct sql_db *db);
+
+/* Escape the given string if needed and return it. */
+const char *sql_escape_string(struct sql_db *db, const char *string);
+/* Escape the given data as a string. */
+const char *sql_escape_blob(struct sql_db *db,
+ const unsigned char *data, size_t size);
+
+/* Execute SQL query without waiting for results. */
+void sql_exec(struct sql_db *db, const char *query);
+/* Execute SQL query and return result in callback. If fields list is given,
+ the returned fields are validated to be of correct type, and you can use
+ sql_result_next_row_get() */
+void sql_query(struct sql_db *db, const char *query,
+ sql_query_callback_t *callback, void *context);
+#define sql_query(db, query, callback, context) \
+ sql_query(db, query - \
+ CALLBACK_TYPECHECK(callback, void (*)( \
+ struct sql_result *, typeof(context))), \
+ (sql_query_callback_t *)callback, context)
+/* Execute blocking SQL query and return result. */
+struct sql_result *sql_query_s(struct sql_db *db, const char *query);
+
+struct sql_prepared_statement *
+sql_prepared_statement_init(struct sql_db *db, const char *query_template);
+void sql_prepared_statement_unref(struct sql_prepared_statement **prep_stmt);
+
+struct sql_statement *
+sql_statement_init(struct sql_db *db, const char *query_template);
+struct sql_statement *
+sql_statement_init_prepared(struct sql_prepared_statement *prep_stmt);
+void sql_statement_abort(struct sql_statement **stmt);
+void sql_statement_set_timestamp(struct sql_statement *stmt,
+ const struct timespec *ts);
+void sql_statement_bind_str(struct sql_statement *stmt,
+ unsigned int column_idx, const char *value);
+void sql_statement_bind_binary(struct sql_statement *stmt,
+ unsigned int column_idx, const void *value,
+ size_t value_size);
+void sql_statement_bind_int64(struct sql_statement *stmt,
+ unsigned int column_idx, int64_t value);
+void sql_statement_query(struct sql_statement **stmt,
+ sql_query_callback_t *callback, void *context);
+#define sql_statement_query(stmt, callback, context) \
+ sql_statement_query(stmt, \
+ (sql_query_callback_t *)callback, TRUE ? context : \
+ CALLBACK_TYPECHECK(callback, void (*)( \
+ struct sql_result *, typeof(context))))
+struct sql_result *sql_statement_query_s(struct sql_statement **stmt);
+
+void sql_result_setup_fetch(struct sql_result *result,
+ const struct sql_field_def *fields,
+ void *dest, size_t dest_size);
+
+/* Go to next row. See enum sql_result_next. */
+int sql_result_next_row(struct sql_result *result);
+
+/* If sql_result_next_row() returned SQL_RESULT_NEXT_MORE, this can be called
+ to continue returning more results. The result is freed with this call, so
+ it must not be accesed anymore until the callback is finished. */
+void sql_result_more(struct sql_result **result,
+ sql_query_callback_t *callback, void *context);
+#define sql_result_more(result, callback, context) \
+ sql_result_more(result - \
+ CALLBACK_TYPECHECK(callback, void (*)( \
+ struct sql_result *, typeof(context))), \
+ (sql_query_callback_t *)callback, context)
+/* Synchronous version of sql_result_more(). The result will be replaced with
+ the new result. */
+void sql_result_more_s(struct sql_result **result);
+
+void sql_result_ref(struct sql_result *result);
+/* Needs to be called only with sql_query_s() or when result has been
+ explicitly referenced. */
+void sql_result_unref(struct sql_result *result);
+
+/* Return number of fields in result. */
+unsigned int sql_result_get_fields_count(struct sql_result *result);
+/* Return name of the given field index. */
+const char *sql_result_get_field_name(struct sql_result *result,
+ unsigned int idx);
+/* Return field index for given name, or -1 if not found. */
+int sql_result_find_field(struct sql_result *result, const char *field_name);
+
+/* Returns value of given field as string. Note that it can be NULL. */
+const char *sql_result_get_field_value(struct sql_result *result,
+ unsigned int idx);
+/* Returns a binary value. Note that a NULL is returned as NULL with size=0,
+ while empty string returns non-NULL with size=0. */
+const unsigned char *
+sql_result_get_field_value_binary(struct sql_result *result,
+ unsigned int idx, size_t *size_r);
+/* Find the field and return its value. NULL return value can mean that either
+ the field didn't exist or that its value is NULL. */
+const char *sql_result_find_field_value(struct sql_result *result,
+ const char *field_name);
+/* Return all values of current row. Note that this array is not
+ NULL-terminated - you must use sql_result_get_fields_count() to find out
+ the array's length. It's also possible that some of the values inside the
+ array are NULL. */
+const char *const *sql_result_get_values(struct sql_result *result);
+
+/* Return last error message in result. */
+const char *sql_result_get_error(struct sql_result *result);
+enum sql_result_error_type sql_result_get_error_type(struct sql_result *result);
+
+/* Begin a new transaction. Currently you're limited to only one open
+ transaction at a time. */
+struct sql_transaction_context *sql_transaction_begin(struct sql_db *db);
+/* Commit transaction. */
+void sql_transaction_commit(struct sql_transaction_context **ctx,
+ sql_commit_callback_t *callback, void *context);
+#define sql_transaction_commit(ctx, callback, context) \
+ sql_transaction_commit(ctx - \
+ CALLBACK_TYPECHECK(callback, void (*)( \
+ const struct sql_commit_result *, typeof(context))), \
+ (sql_commit_callback_t *)callback, context)
+/* Synchronous commit. Returns 0 if ok, -1 if error. */
+int sql_transaction_commit_s(struct sql_transaction_context **ctx,
+ const char **error_r);
+void sql_transaction_rollback(struct sql_transaction_context **ctx);
+
+/* Execute query in given transaction. */
+void sql_update(struct sql_transaction_context *ctx, const char *query);
+void sql_update_stmt(struct sql_transaction_context *ctx,
+ struct sql_statement **stmt);
+/* Save the number of rows updated by this query. The value is set before
+ commit callback is called. */
+void sql_update_get_rows(struct sql_transaction_context *ctx, const char *query,
+ unsigned int *affected_rows);
+void sql_update_stmt_get_rows(struct sql_transaction_context *ctx,
+ struct sql_statement **stmt,
+ unsigned int *affected_rows);
+
+/* Wait for SQL query results. */
+void sql_wait(struct sql_db *db);
+
+#endif