Skip to content

Commit

Permalink
Handle open/close of result set w/ <mysql-stmt> properly.
Browse files Browse the repository at this point in the history
git-svn-id: svn+ssh://svn.kahua.org/var/local/repos/kahua/Gauche-dbd-mysql/trunk@3566 4e392e78-dc3f-dc11-8fd5-00188bfc9ac4
  • Loading branch information
bizenn committed Aug 10, 2011
1 parent 4308227 commit 1e4a201
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 103 deletions.
6 changes: 6 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
2011-08-10 Tatsuya BIZENN <bizenn@kahua.org>

* Add: mysql-stmt-res-closed?

* Fix: handling <mysql-stmt> result set open/close properly.

2011-07-29 Tatsuya BIZENN <bizenn@kahua.org>

* Fix: a typo.
Expand Down
45 changes: 19 additions & 26 deletions dbd/mysql.scm
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@
(let1 handle (mysql-real-connect host user passwd db port socket flags)
(make <mysql-connection> :driver-name d :open #t :handle handle))))

(define-method dbi-open? ((c <mysql-connection>))
(not (mysql-handle-closed? (slot-ref c '%handle))))

(define-class <mysql-query> (<dbi-query>)
())

Expand All @@ -88,33 +91,23 @@
(%current-rowid :init-value 0)))

(define-method dbi-prepare ((c <mysql-connection>) (sql <string>) . args)
(let* ((conn (slot-ref c '%handle))
(prepared (if (and (get-keyword :pass-through args #f)
(not (string-scan sql #\?)))
(lambda args
(unless (null? args)
(error <dbi-parameter-error> "parameters are given to the pass through sql:" sql))
sql)
(guard (e ((mysql-error? e)
(dbi-prepare-sql c sql)))
(mysql-stmt-prepare conn sql)))))
(make <mysql-query> :connection c :prepared prepared :open #t)))
(make <mysql-query> :connection c :prepared (mysql-stmt-prepare (slot-ref c '%handle) sql)))

(define-method dbi-open? ((q <mysql-query>))
(not (mysql-stmt-closed? (slot-ref q 'prepared))))

(define-method dbi-execute-using-connection ((c <mysql-connection>)
(q <dbi-query>) params)
(let* ((conn (slot-ref c '%handle))
(prepared (slot-ref q 'prepared)))
(if (procedure? prepared)
(begin
(mysql-real-query conn (apply prepared params))
(and-let* ((rs (mysql-store-result conn)))
(make <mysql-result-set>
:open #t :handle conn :statement rs :row-count (mysql-affected-rows conn))))
(begin
(apply mysql-stmt-execute prepared params)
(and (< 0 (mysql-stmt-field-count prepared))
(make <mysql-result-set>
:open #t :handle conn :statement prepared :row-count (mysql-stmt-affected-rows prepared)))))))
(unless (dbi-open? q)
(error <dbi-error> "query already closed: " q))
(unless (dbi-open? c)
(error <dbi-error> "connection already closed: " c))
(apply mysql-stmt-execute prepared params)
(and (< 0 (mysql-stmt-field-count prepared))
(make <mysql-result-set>
:open #t :handle conn :statement prepared :row-count (mysql-stmt-affected-rows prepared)))))

(define-method dbi-escape-sql ((c <mysql-connection>) str)
(mysql-real-escape-string (slot-ref c '%handle) str))
Expand Down Expand Up @@ -182,17 +175,17 @@
(and (not (let1 stmt (slot-ref result-set '%statement)
(if (mysql-res? stmt)
(mysql-res-closed? stmt)
(mysql-stmt-closed? stmt))))
(mysql-stmt-res-closed? stmt))))
(not (mysql-handle-closed? (slot-ref result-set '%handle)))))

(define-method dbi-close ((result-set <mysql-result-set>))
(let1 stmt (slot-ref result-set '%statement)
(if (mysql-res? stmt)
(mysql-free-result stmt)
(mysql-stmt-close stmt))))
(mysql-stmt-free-result stmt))))

(define-method dbi-open? ((c <mysql-connection>))
(not (mysql-handle-closed? (slot-ref c '%handle))))
(define-method dbi-close ((query <mysql-query>))
(mysql-stmt-close (slot-ref query 'prepared)))

(define-method dbi-close ((c <mysql-connection>))
(mysql-close (slot-ref c '%handle)))
Expand Down
104 changes: 61 additions & 43 deletions dbd_mysql.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ void mysql_cleanup(ScmObj obj)
if (!MysqlClosedP(obj)) {
MYSQL *s = MYSQL_HANDLE_UNBOX(obj);
mysql_close(s);
MysqlMarkClosed(obj);
MysqlMarkClosed(obj);
}
}

Expand All @@ -58,7 +58,7 @@ void mysql_res_cleanup(ScmObj obj)
if (!MysqlClosedP(obj)) {
MYSQL_RES *r = MYSQL_RES_UNBOX(obj);
mysql_free_result(r);
MysqlMarkClosed(obj);
MysqlMarkClosed(obj);
}
}

Expand All @@ -74,19 +74,36 @@ void mysql_rows_cleanup(ScmObj obj)
*/
/* Symbol 'closed? */
static ScmObj sym_closed;
static ScmObj sym_result_closed;

int MysqlClosedP(ScmObj obj)
{
SCM_ASSERT(SCM_FOREIGN_POINTER_P(obj));
return !SCM_FALSEP(Scm_ForeignPointerAttrGet(SCM_FOREIGN_POINTER(obj),
sym_closed, SCM_FALSE));
return !SCM_FALSEP(Scm_ForeignPointerAttrGet(SCM_FOREIGN_POINTER(obj), sym_closed, SCM_FALSE));
}

void MysqlMarkClosed(ScmObj obj)
{
SCM_ASSERT(SCM_FOREIGN_POINTER_P(obj));
Scm_ForeignPointerAttrSet(SCM_FOREIGN_POINTER(obj),
sym_closed, SCM_TRUE);
Scm_ForeignPointerAttrSet(SCM_FOREIGN_POINTER(obj), sym_closed, SCM_TRUE);
}

int MysqlResultClosedP(ScmObj obj)
{
SCM_ASSERT(SCM_FOREIGN_POINTER_P(obj));
return !SCM_FALSEP(Scm_ForeignPointerAttrGet(SCM_FOREIGN_POINTER(obj), sym_result_closed, SCM_TRUE));
}

void MysqlResultMarkClosed(ScmObj obj)
{
SCM_ASSERT(SCM_FOREIGN_POINTER_P(obj));
Scm_ForeignPointerAttrSet(SCM_FOREIGN_POINTER(obj), sym_result_closed, SCM_TRUE);
}

void MysqlResultUnmarkClosed(ScmObj obj)
{
SCM_ASSERT(SCM_FOREIGN_POINTER_P(obj));
Scm_ForeignPointerAttrSet(SCM_FOREIGN_POINTER(obj), sym_result_closed, SCM_FALSE);
}

#if defined(GAUCHE_CHAR_ENCODING_EUC_JP)
Expand Down Expand Up @@ -469,54 +486,54 @@ void MysqlStmtxExecute(MYSQL_STMTX *stmtx, ScmObj args)
stmtx->param_count = param_count = mysql_stmt_param_count(stmt);
memset(params, 0, sizeof(MYSQL_BIND)*param_count);
for (ptr = args, i = 0, param = params;
!SCM_NULLP(ptr);
ptr = Scm_Cdr(ptr), i++, param++) {
obj = Scm_Car(ptr);
if (i >= param_count)
Scm_RaiseCondition(MYSQL_ERROR, "error-code", SCM_MAKE_INT(0), "sql-code", SCM_MAKE_STR_IMMUTABLE(""),
SCM_RAISE_CONDITION_MESSAGE, "mysql-stmt-execute require %d parameters, but got %d parameters",
param_count, Scm_Length(args));
mysql_init_param(param, obj);
!SCM_NULLP(ptr);
ptr = Scm_Cdr(ptr), i++, param++) {
obj = Scm_Car(ptr);
if (i >= param_count)
Scm_RaiseCondition(MYSQL_ERROR, "error-code", SCM_MAKE_INT(0), "sql-code", SCM_MAKE_STR_IMMUTABLE(""),
SCM_RAISE_CONDITION_MESSAGE, "mysql-stmt-execute require %d parameters, but got %d parameters",
param_count, Scm_Length(args));
mysql_init_param(param, obj);
}
if (i != param_count)
Scm_RaiseCondition(MYSQL_ERROR, "error-code", SCM_MAKE_INT(0), "sql-code", SCM_MAKE_STR_IMMUTABLE(""),
SCM_RAISE_CONDITION_MESSAGE, "mysql-stmt-execute require %d parameters, but got %d parameters",
param_count, i);
Scm_RaiseCondition(MYSQL_ERROR, "error-code", SCM_MAKE_INT(0), "sql-code", SCM_MAKE_STR_IMMUTABLE(""),
SCM_RAISE_CONDITION_MESSAGE, "mysql-stmt-execute require %d parameters, but got %d parameters",
param_count, i);
if (mysql_stmt_bind_param(stmt, params) != 0)
raise_mysql_stmt_error(stmt, "mysql_stmt_bind_param");
raise_mysql_stmt_error(stmt, "mysql_stmt_bind_param");
stmtx->field_count = field_count = mysql_stmt_field_count(stmt);
if (field_count > 0) {
int i;
MYSQL_FIELD *field = mysql_fetch_fields(stmtx->metares);
for (i = 0; i < field_count; i++, field++) {
if (field->type == MYSQL_TYPE_BLOB) {
fix_metadata = 1;
mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &fix_metadata);
break;
}
}
int i;
MYSQL_FIELD *field = mysql_fetch_fields(stmtx->metares);
for (i = 0; i < field_count; i++, field++) {
if (field->type == MYSQL_TYPE_BLOB) {
fix_metadata = 1;
mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &fix_metadata);
break;
}
}
}
if (mysql_stmt_execute(stmt) != 0)
raise_mysql_stmt_error(stmt, "mysql_stmt_execute");
raise_mysql_stmt_error(stmt, "mysql_stmt_execute");
if (mysql_stmt_store_result(stmt) != 0)
raise_mysql_stmt_error(stmt, "mysql_stmt_store_result");
raise_mysql_stmt_error(stmt, "mysql_stmt_store_result");
if (fix_metadata) {
MYSQL_RES *metares;
if ((metares = mysql_stmt_result_metadata(stmt)) == NULL)
if (mysql_stmt_errno(stmt) != 0)
raise_mysql_stmt_error(stmt, "mysql_stmt_result_metadata");
mysql_free_result(stmtx->metares);
stmtx->metares = metares;
MYSQL_RES *metares;
if ((metares = mysql_stmt_result_metadata(stmt)) == NULL)
if (mysql_stmt_errno(stmt) != 0)
raise_mysql_stmt_error(stmt, "mysql_stmt_result_metadata");
mysql_free_result(stmtx->metares);
stmtx->metares = metares;
}
if (field_count > 0) {
int i;
if ((fields = (MYSQL_BIND*)calloc(field_count, sizeof(MYSQL_BIND))) == NULL)
Scm_SysError("Cannot allocate MYSQL_BIND buffers");
stmtx->fields = fields;
for (i = 0, field = fields; i < field_count; i++, field++)
mysql_init_field(field, mysql_fetch_field_direct(stmtx->metares, i));
if (mysql_stmt_bind_result(stmt, fields) != 0)
raise_mysql_stmt_error(stmt, "mysql_stmt_bind_result");
int i;
if ((fields = (MYSQL_BIND*)calloc(field_count, sizeof(MYSQL_BIND))) == NULL)
Scm_SysError("Cannot allocate MYSQL_BIND buffers");
stmtx->fields = fields;
for (i = 0, field = fields; i < field_count; i++, field++)
mysql_init_field(field, mysql_fetch_field_direct(stmtx->metares, i));
if (mysql_stmt_bind_result(stmt, fields) != 0)
raise_mysql_stmt_error(stmt, "mysql_stmt_bind_result");
}
}

Expand Down Expand Up @@ -650,6 +667,7 @@ void Scm_Init_dbd_mysql(void)

/* Get handle of the symbol 'closed? */
sym_closed = SCM_INTERN("closed?");
sym_result_closed = SCM_INTERN("result-closed?");

/* Register stub-generated procedures */
Scm_Init_dbd_mysqllib(mod);
Expand Down
3 changes: 3 additions & 0 deletions dbd_mysql.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ typedef ScmForeignPointer ScmMysqlRows;

extern int MysqlClosedP(ScmObj obj);
extern void MysqlMarkClosed(ScmObj obj);
int MysqlResultClosedP(ScmObj obj);
void MysqlResultMarkClosed(ScmObj obj);
void MysqlResultUnmarkClosed(ScmObj obj);

extern MYSQL *MysqlRealConnect(const char *host,
const char *user,
Expand Down
11 changes: 8 additions & 3 deletions dbd_mysqllib.stub
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@

;; mysql_stmt_execute
(define-cproc mysql-stmt-execute (stmtx::<mysql-stmt> &rest args)
(body <void> "MysqlStmtxExecute(stmtx, args);"))
(body <void> "MysqlStmtxExecute(stmtx, args); MysqlResultUnmarkClosed(stmtx_scm);"))

;; mysql_stmt_fetch
(define-cproc mysql-stmt-fetch (stmtx::<mysql-stmt>)
Expand All @@ -659,7 +659,8 @@
(define-cproc mysql-stmt-free-result (stmtx::<mysql-stmt>)
(body <void>
"if (mysql_stmt_free_result(stmtx->stmt))"
" raise_mysql_stmt_error(stmtx->stmt, \"mysql_stmt_free_result\");"))
" raise_mysql_stmt_error(stmtx->stmt, \"mysql_stmt_free_result\");"
"MysqlResultMarkClosed(stmtx_scm);"))

;; mysql_stmt_init(integrate into mysql-stmt-prepare)

Expand All @@ -685,7 +686,8 @@
(define-cproc mysql-stmt-reset (stmtx::<mysql-stmt>)
(body <void>
"if (mysql_stmt_reset(stmtx->stmt) != 0)"
" raise_mysql_stmt_error(stmtx->stmt, \"mysql_stmt_reset\");"))
" raise_mysql_stmt_error(stmtx->stmt, \"mysql_stmt_reset\");"
"MysqlResultMarkClosed(stmtx_scm);"))

;; mysql_stmt_result_metadata
;; mysql_stmt_row_seek
Expand All @@ -700,6 +702,9 @@
(define-cproc mysql-stmt-closed? (stmtx::<mysql-stmt>)
(expr <boolean> "MysqlClosedP(stmtx_scm)"))

(define-cproc mysql-stmt-res-closed? (stmtx::<mysql-stmt>)
(expr <boolean> "MysqlResultClosedP(stmtx_scm)"))

(define-cproc mysql-stmt-fetch-field-names (stmtx::<mysql-stmt>)
(call "MysqlStmtxFetchFieldNames"))))

Expand Down
Loading

0 comments on commit 1e4a201

Please sign in to comment.