#ifndef SQL_API_PRIVATE_H #define SQL_API_PRIVATE_H #include "sql-api.h" #include "module-context.h" enum sql_db_state { /* not connected to database */ SQL_DB_STATE_DISCONNECTED, /* waiting for connection attempt to succeed or fail */ SQL_DB_STATE_CONNECTING, /* connected, allowing more queries */ SQL_DB_STATE_IDLE, /* connected, no more queries allowed */ SQL_DB_STATE_BUSY }; /* Minimum delay between reconnecting to same server */ #define SQL_CONNECT_MIN_DELAY 1 /* Maximum time to avoiding reconnecting to same server */ #define SQL_CONNECT_MAX_DELAY (60*30) /* If no servers are connected but a query is requested, try reconnecting to next server which has been disconnected longer than this (with a single server setup this is really the "max delay" and the SQL_CONNECT_MAX_DELAY is never used). */ #define SQL_CONNECT_RESET_DELAY 15 /* Abort connect() if it can't connect within this time. */ #define SQL_CONNECT_TIMEOUT_SECS 5 /* Abort queries after this many seconds */ #define SQL_QUERY_TIMEOUT_SECS 60 /* Default max. number of connections to create per host */ #define SQL_DEFAULT_CONNECTION_LIMIT 5 #define SQL_DB_IS_READY(db) \ ((db)->state == SQL_DB_STATE_IDLE) #define SQL_ERRSTR_NOT_CONNECTED "Not connected to database" /* What is considered slow query */ #define SQL_SLOW_QUERY_MSEC 1000 #define SQL_QUERY_FINISHED "sql_query_finished" #define SQL_CONNECTION_FINISHED "sql_connection_finished" #define SQL_TRANSACTION_FINISHED "sql_transaction_finished" #define SQL_QUERY_FINISHED_FMT "Finished query '%s' in %u msecs" struct sql_db_module_register { unsigned int id; }; union sql_db_module_context { struct sql_db_module_register *reg; }; extern struct sql_db_module_register sql_db_module_register; extern struct event_category event_category_sql; struct sql_transaction_query { struct sql_transaction_query *next; struct sql_transaction_context *trans; const char *query; unsigned int *affected_rows; }; struct sql_db_vfuncs { struct sql_db *(*init)(const char *connect_string); int (*init_full)(const struct sql_settings *set, struct sql_db **db_r, const char **error); void (*deinit)(struct sql_db *db); void (*unref)(struct sql_db *db); void (*wait) (struct sql_db *db); enum sql_db_flags (*get_flags)(struct sql_db *db); int (*connect)(struct sql_db *db); void (*disconnect)(struct sql_db *db); const char *(*escape_string)(struct sql_db *db, const char *string); void (*exec)(struct sql_db *db, const char *query); void (*query)(struct sql_db *db, const char *query, sql_query_callback_t *callback, void *context); struct sql_result *(*query_s)(struct sql_db *db, const char *query); struct sql_transaction_context *(*transaction_begin)(struct sql_db *db); void (*transaction_commit)(struct sql_transaction_context *ctx, sql_commit_callback_t *callback, void *context); int (*transaction_commit_s)(struct sql_transaction_context *ctx, const char **error_r); void (*transaction_rollback)(struct sql_transaction_context *ctx); void (*update)(struct sql_transaction_context *ctx, const char *query, unsigned int *affected_rows); const char *(*escape_blob)(struct sql_db *db, const unsigned char *data, size_t size); struct sql_prepared_statement * (*prepared_statement_init)(struct sql_db *db, const char *query_template); void (*prepared_statement_deinit)(struct sql_prepared_statement *prep_stmt); struct sql_statement * (*statement_init)(struct sql_db *db, const char *query_template); struct sql_statement * (*statement_init_prepared)(struct sql_prepared_statement *prep_stmt); void (*statement_abort)(struct sql_statement *stmt); void (*statement_set_timestamp)(struct sql_statement *stmt, const struct timespec *ts); void (*statement_bind_str)(struct sql_statement *stmt, unsigned int column_idx, const char *value); void (*statement_bind_binary)(struct sql_statement *stmt, unsigned int column_idx, const void *value, size_t value_size); void (*statement_bind_int64)(struct sql_statement *stmt, unsigned int column_idx, int64_t value); void (*statement_query)(struct sql_statement *stmt, sql_query_callback_t *callback, void *context); struct sql_result *(*statement_query_s)(struct sql_statement *stmt); void (*update_stmt)(struct sql_transaction_context *ctx, struct sql_statement *stmt, unsigned int *affected_rows); }; struct sql_db { const char *name; enum sql_db_flags flags; int refcount; struct sql_db_vfuncs v; ARRAY(union sql_db_module_context *) module_contexts; void (*state_change_callback)(struct sql_db *db, enum sql_db_state prev_state, void *context); void *state_change_context; struct event *event; HASH_TABLE(char *, struct sql_prepared_statement *) prepared_stmt_hash; enum sql_db_state state; /* last time we started connecting to this server (which may or may not have succeeded) */ time_t last_connect_try; unsigned int connect_delay; unsigned int connect_failure_count; struct timeout *to_reconnect; uint64_t succeeded_queries; uint64_t failed_queries; /* includes both succeeded and failed */ uint64_t slow_queries; bool no_reconnect:1; }; struct sql_result_vfuncs { void (*free)(struct sql_result *result); int (*next_row)(struct sql_result *result); unsigned int (*get_fields_count)(struct sql_result *result); const char *(*get_field_name)(struct sql_result *result, unsigned int idx); int (*find_field)(struct sql_result *result, const char *field_name); const char *(*get_field_value)(struct sql_result *result, unsigned int idx); const unsigned char * (*get_field_value_binary)(struct sql_result *result, unsigned int idx, size_t *size_r); const char *(*find_field_value)(struct sql_result *result, const char *field_name); const char *const *(*get_values)(struct sql_result *result); const char *(*get_error)(struct sql_result *result); void (*more)(struct sql_result **result, bool async, sql_query_callback_t *callback, void *context); }; struct sql_prepared_statement { struct sql_db *db; int refcount; char *query_template; }; struct sql_statement { struct sql_db *db; pool_t pool; const char *query_template; ARRAY_TYPE(const_string) args; /* Tell the driver to not log this query with expanded values. */ bool no_log_expanded_values; }; struct sql_field_map { enum sql_field_type type; size_t offset; }; struct sql_result { struct sql_result_vfuncs v; int refcount; struct sql_db *db; const struct sql_field_def *fields; unsigned int map_size; struct sql_field_map *map; void *fetch_dest; struct event *event; size_t fetch_dest_size; enum sql_result_error_type error_type; bool failed:1; bool failed_try_retry:1; bool callback:1; }; struct sql_transaction_context { struct sql_db *db; struct event *event; /* commit() must use this query list if head is non-NULL. */ struct sql_transaction_query *head, *tail; }; ARRAY_DEFINE_TYPE(sql_drivers, const struct sql_db *); extern ARRAY_TYPE(sql_drivers) sql_drivers; extern struct sql_result sql_not_connected_result; void sql_init_common(struct sql_db *db); struct sql_db * driver_sqlpool_init(const char *connect_string, const struct sql_db *driver); int driver_sqlpool_init_full(const struct sql_settings *set, const struct sql_db *driver, struct sql_db **db_r, const char **error_r); void sql_db_set_state(struct sql_db *db, enum sql_db_state state); void sql_transaction_add_query(struct sql_transaction_context *ctx, pool_t pool, const char *query, unsigned int *affected_rows); const char *sql_statement_get_log_query(struct sql_statement *stmt); const char *sql_statement_get_query(struct sql_statement *stmt); void sql_connection_log_finished(struct sql_db *db); struct event_passthrough * sql_query_finished_event(struct sql_db *db, struct event *event, const char *query, bool success, int *duration_r); struct event_passthrough *sql_transaction_finished_event(struct sql_transaction_context *ctx); #endif