/** * Ends a transaction and rollsback the changes (SQL ROLLBACK) * \param _h database handle * \return 1 if there was something to rollback, 0 if not, negative on failure */ int db_postgres_abort_transaction(db1_con_t* _h) { db1_res_t *res = NULL; str query_str = str_init("ROLLBACK"); if (!_h) { LM_ERR("invalid parameter value\n"); return -1; } if (CON_TRANSACTION(_h) == 0) { LM_DBG("nothing to rollback\n"); return 0; } /* Whether the rollback succeeds or not we need to _end_ the transaction now or all future starts will fail */ CON_TRANSACTION(_h) = 0; if (db_postgres_raw_query(_h, &query_str, &res) < 0) { LM_ERR("executing raw_query\n"); return -1; } if (res) db_postgres_free_result(_h, res); return 1; }
/** * Starts a single transaction that will consist of one or more queries (SQL BEGIN) * \param _h database handle * \return 0 on success, negative on failure */ int db_postgres_start_transaction(db1_con_t* _h) { db1_res_t *res = NULL; str query_str = str_init("BEGIN"); if (!_h) { LM_ERR("invalid parameter value\n"); return -1; } if (CON_TRANSACTION(_h) == 1) { LM_ERR("transaction already started\n"); return -1; } if (db_postgres_raw_query(_h, &query_str, &res) < 0) { LM_ERR("executing raw_query\n"); return -1; } if (res) db_postgres_free_result(_h, res); CON_TRANSACTION(_h) = 1; return 0; }
/** * Ends a transaction and commits the changes (SQL COMMIT) * \param _h database handle * \return 0 on success, negative on failure */ int db_postgres_end_transaction(db1_con_t* _h) { db1_res_t *res = NULL; str query_str = str_init("COMMIT"); if (!_h) { LM_ERR("invalid parameter value\n"); return -1; } if (CON_TRANSACTION(_h) == 0) { LM_ERR("transaction not in progress\n"); return -1; } if (db_postgres_raw_query(_h, &query_str, &res) < 0) { LM_ERR("executing raw_query\n"); return -1; } if (res) db_postgres_free_result(_h, res); /* Only _end_ the transaction after the raw_query. That way, if the raw_query fails, and the calling module does an abort_transaction() to clean-up, a ROLLBACK will be sent to the DB. */ CON_TRANSACTION(_h) = 0; return 0; }
/** * Starts a single transaction that will consist of one or more queries (SQL BEGIN) * \param _h database handle * \return 0 on success, negative on failure */ int db_postgres_start_transaction(db1_con_t* _h, db_locking_t _l) { db1_res_t *res = NULL; str begin_str = str_init("BEGIN"); str lock_start_str = str_init("LOCK TABLE "); str lock_write_end_str = str_init(" IN EXCLUSIVE MODE"); str lock_full_end_str = str_init(" IN ACCESS EXCLUSIVE MODE"); str *lock_end_str = &lock_write_end_str; str lock_str = {0, 0}; if (!_h) { LM_ERR("invalid parameter value\n"); return -1; } if (CON_TRANSACTION(_h) == 1) { LM_ERR("transaction already started\n"); return -1; } if (db_postgres_raw_query(_h, &begin_str, &res) < 0) { LM_ERR("executing raw_query\n"); return -1; } if (res) db_postgres_free_result(_h, res); CON_TRANSACTION(_h) = 1; switch(_l) { case DB_LOCKING_NONE: break; case DB_LOCKING_FULL: lock_end_str = &lock_full_end_str; /* Fall-thru */ case DB_LOCKING_WRITE: if ((lock_str.s = pkg_malloc((lock_start_str.len + CON_TABLE(_h)->len + lock_end_str->len) * sizeof(char))) == NULL) { LM_ERR("allocating pkg memory\n"); goto error; } memcpy(lock_str.s, lock_start_str.s, lock_start_str.len); lock_str.len += lock_start_str.len; memcpy(lock_str.s + lock_str.len, CON_TABLE(_h)->s, CON_TABLE(_h)->len); lock_str.len += CON_TABLE(_h)->len; memcpy(lock_str.s + lock_str.len, lock_end_str->s, lock_end_str->len); lock_str.len += lock_end_str->len; if (db_postgres_raw_query(_h, &lock_str, &res) < 0) { LM_ERR("executing raw_query\n"); goto error; } if (res) db_postgres_free_result(_h, res); if (lock_str.s) pkg_free(lock_str.s); break; default: LM_WARN("unrecognised lock type\n"); goto error; } return 0; error: if (lock_str.s) pkg_free(lock_str.s); db_postgres_abort_transaction(_h); return -1; }