static int dbd_mysql_transaction(apr_pool_t *pool, apr_dbd_t *handle, apr_dbd_transaction_t **trans) { /* Don't try recursive transactions here */ if (handle->trans) { dbd_mysql_end_transaction(handle->trans) ; } if (!*trans) { *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); } (*trans)->errnum = mysql_autocommit(handle->conn, 0); (*trans)->handle = handle; handle->trans = *trans; return (*trans)->errnum; }
static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans) { int ret = -1; if (trans) { #if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) /* rollback on error or explicit rollback request */ if (trans->errnum || TXN_DO_ROLLBACK(trans)) { #else if (trans->errnum) { #endif trans->errnum = 0; ret = mysql_rollback(trans->handle->conn); } else { ret = mysql_commit(trans->handle->conn); } } ret |= mysql_autocommit(trans->handle->conn, 1); trans->handle->trans = NULL; return ret; } /* Whether or not transactions work depends on whether the * underlying DB supports them within MySQL. Unfortunately * it fails silently with the default InnoDB. */ static int dbd_mysql_transaction(apr_pool_t *pool, apr_dbd_t *handle, apr_dbd_transaction_t **trans) { /* Don't try recursive transactions here */ if (handle->trans) { dbd_mysql_end_transaction(handle->trans) ; } if (!*trans) { *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); } (*trans)->errnum = mysql_autocommit(handle->conn, 0); (*trans)->handle = handle; handle->trans = *trans; return (*trans)->errnum; } #if APU_MAJOR_VERSION >= 2 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) static int dbd_mysql_transaction_mode_get(apr_dbd_transaction_t *trans) { if (!trans) return APR_DBD_TRANSACTION_COMMIT; return trans->mode; } static int dbd_mysql_transaction_mode_set(apr_dbd_transaction_t *trans, int mode) { if (!trans) return APR_DBD_TRANSACTION_COMMIT; return trans->mode = (mode & TXN_MODE_BITS); } #endif static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params) { static const char *const delims = " \r\n\t;|,"; const char *ptr; int i; const char *key; size_t klen; const char *value; size_t vlen; #if MYSQL_VERSION_ID >= 50013 my_bool do_reconnect = 1; #endif MYSQL *real_conn; unsigned long flags = 0; struct { const char *field; const char *value; } fields[] = { {"host", NULL}, {"user", NULL}, {"pass", NULL}, {"dbname", NULL}, {"port", NULL}, {"sock", NULL}, {"flags", NULL}, {"fldsz", NULL}, {NULL, NULL} }; unsigned int port = 0; apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t)); sql->fldsz = FIELDSIZE; sql->conn = mysql_init(sql->conn); if ( sql->conn == NULL ) { return NULL; } for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) { for (key = ptr-1; isspace(*key); --key); klen = 0; while (isalpha(*key)) { /* don't parse backwards off the start of the string */ if (key == params) { --key; ++klen; break; } --key; ++klen; } ++key; for (value = ptr+1; isspace(*value); ++value); vlen = strcspn(value, delims); for (i = 0; fields[i].field != NULL; i++) { if (!strncasecmp(fields[i].field, key, klen)) { fields[i].value = apr_pstrndup(pool, value, vlen); break; } } ptr = value+vlen; } if (fields[4].value != NULL) { port = atoi(fields[4].value); } if (fields[6].value != NULL && !strcmp(fields[6].value, "CLIENT_FOUND_ROWS")) { flags |= CLIENT_FOUND_ROWS; /* only option we know */ } if (fields[7].value != NULL) { sql->fldsz = atol(fields[7].value); } #if MYSQL_VERSION_ID >= 50013 /* the MySQL manual says this should be BEFORE mysql_real_connect */ mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect); #endif real_conn = mysql_real_connect(sql->conn, fields[0].value, fields[1].value, fields[2].value, fields[3].value, port, fields[5].value, flags); if(real_conn == NULL) { mysql_close(sql->conn); return NULL; } #if MYSQL_VERSION_ID >= 50013 /* Some say this should be AFTER mysql_real_connect */ mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect); #endif return sql; } static apr_status_t dbd_mysql_close(apr_dbd_t *handle) { mysql_close(handle->conn); return APR_SUCCESS; }