Index: packages/dbd-sqlite/SQLite.st =================================================================== RCS file: /srv/git/smalltalk.git/master/packages/dbd-sqlite/SQLite.st,v retrieving revision 1.2 diff -p -u packages/dbd-sqlite/SQLite.st --- packages/dbd-sqlite/SQLite.st revision 1.2 +++ packages/dbd-sqlite/SQLite.st working copy @@ -107,6 +107,21 @@ ] + bindingAt: index put: value [ + + + ] + + clearBindings [ + + + ] + + reset [ + + + ] + colCount [ ^colCount Index: packages/dbd-sqlite/SQLiteTests.st =================================================================== RCS file: /srv/git/smalltalk.git/master/packages/dbd-sqlite/SQLiteTests.st,v retrieving revision 1.3 diff -p -u packages/dbd-sqlite/SQLiteTests.st --- packages/dbd-sqlite/SQLiteTests.st revision 1.3 +++ packages/dbd-sqlite/SQLiteTests.st working copy @@ -146,6 +146,40 @@ ] ] + +SQLiteBaseTest subclass: SQLitePreparedStatementTestCase [ + | stmt stmt2 | + + setUp [ + super setUp. + stmt := self connection prepare: 'SELECT * FROM test WHERE int_field = ?'. + stmt2 := self connection prepare: 'SELECT * FROM test WHERE int_field = ? AND string_field = ? AND double_field = ?'. + ] + + testExecute [ + | rs row | + "execute with one parameter" + rs := stmt executeWith: 1. + row := rs rows at: 1. + self should: [(row atIndex: 1) = 1]. + + "re-execute so that we are sure that the statement is reset" + rs := stmt executeWith: 2. + row := rs rows at: 1. + self should: [(row atIndex: 1) = 2]. + ] + + testExecuteWithAll [ + | rs row | + rs := stmt2 executeWithAll: #(1 'one' 1.0). + row := rs rows at: 1. + self should: [(row atIndex: 1) = 1]. + + rs := stmt2 executeWithAll: #(1 'two' 3.0). + self should: [rs rows size = 0]. + ] +] + TestSuite subclass: SQLiteTestSuite [ SQLiteTestSuite class >> suite [ ^super new initialize @@ -162,5 +196,8 @@ self addTest: (SQLiteRowTestCase selector: #testAtIndex). self addTest: (SQLiteDMLResultSetTestCase selector: #testRowsAffected). + + self addTest: (SQLitePreparedStatementTestCase selector: #testExecute). + self addTest: (SQLitePreparedStatementTestCase selector: #testExecuteWithAll). ] ] Index: packages/dbd-sqlite/Statement.st =================================================================== RCS file: /srv/git/smalltalk.git/master/packages/dbd-sqlite/Statement.st,v retrieving revision 1.2 diff -p -u packages/dbd-sqlite/Statement.st --- packages/dbd-sqlite/Statement.st revision 1.2 +++ packages/dbd-sqlite/Statement.st working copy @@ -70,13 +70,26 @@ ] execute [ - + ^SQLiteResultSet on: self ] executeWithAll: aParams [ - self notYetImplemented + | resCode resultSet | + aParams keysAndValuesDo: [:i :param | + resCode := self handle bindingAt: i put: param. + self handle checkError: resCode = 0]. + + resultSet := SQLiteResultSet on: self. + self resetAndClear. + ^resultSet + ] + + resetAndClear [ + + self handle reset. + self handle clearBindings. ] getCommand [ Index: packages/dbd-sqlite/sqlite3.c =================================================================== RCS file: /srv/git/smalltalk.git/master/packages/dbd-sqlite/sqlite3.c,v retrieving revision 1.3 diff -p -u packages/dbd-sqlite/sqlite3.c --- packages/dbd-sqlite/sqlite3.c revision 1.3 +++ packages/dbd-sqlite/sqlite3.c working copy @@ -205,6 +205,58 @@ return rc; } +int +gst_sqlite3_bind (OOP self, int index, OOP value) +{ + sqlite3_stmt *stmt; + SQLite3StmtHandle h; + + h = (SQLite3StmtHandle) OOP_TO_OBJ (self); + if (h->stmt == vmProxy->nilOOP) + return SQLITE_MISUSE; + + stmt = (sqlite3_stmt *) vmProxy->OOPToCObject (h->stmt); + + if (vmProxy->objectIsKindOf (value, vmProxy->smallIntegerClass)) + return sqlite3_bind_int (stmt, index, vmProxy->OOPToInt (value)); + + if (vmProxy->objectIsKindOf (value, vmProxy->stringClass)) + return sqlite3_bind_text (stmt, index, vmProxy->OOPToString (value), -1, SQLITE_TRANSIENT); + + if (vmProxy->objectIsKindOf (value, vmProxy->floatDClass)) + return sqlite3_bind_double (stmt, index, vmProxy->OOPToFloat (value)); + + return -1; +} + +int +gst_sqlite3_clear_bindings (OOP self) +{ + sqlite3_stmt *stmt; + SQLite3StmtHandle h; + + h = (SQLite3StmtHandle) OOP_TO_OBJ (self); + if (h->stmt == vmProxy->nilOOP) + return SQLITE_MISUSE; + + stmt = (sqlite3_stmt *) vmProxy->OOPToCObject (h->stmt); + return sqlite3_clear_bindings (stmt); +} + +int +gst_sqlite3_reset (OOP self) +{ + sqlite3_stmt *stmt; + SQLite3StmtHandle h; + + h = (SQLite3StmtHandle) OOP_TO_OBJ (self); + if (h->stmt == vmProxy->nilOOP) + return SQLITE_MISUSE; + + stmt = (sqlite3_stmt *) vmProxy->OOPToCObject (h->stmt); + return sqlite3_reset (stmt); +} + const char * gst_sqlite3_error_message (OOP self) { @@ -252,6 +304,9 @@ vmProxy->defineCFunc ("gst_sqlite3_close", gst_sqlite3_close); vmProxy->defineCFunc ("gst_sqlite3_prepare", gst_sqlite3_prepare); vmProxy->defineCFunc ("gst_sqlite3_exec", gst_sqlite3_exec); + vmProxy->defineCFunc ("gst_sqlite3_bind", gst_sqlite3_bind); + vmProxy->defineCFunc ("gst_sqlite3_clear_bindings", gst_sqlite3_clear_bindings); + vmProxy->defineCFunc ("gst_sqlite3_reset", gst_sqlite3_reset); vmProxy->defineCFunc ("gst_sqlite3_changes", gst_sqlite3_changes); vmProxy->defineCFunc ("gst_sqlite3_error_message", gst_sqlite3_error_message); vmProxy->defineCFunc ("gst_sqlite3_finalize", gst_sqlite3_finalize);