SQLitePreparedStatement
From Xojo Documentation
Used to create a PreparedSQLStatement for a SQLiteDatabase.
Methods | ||||
|
Notes
The use of the prepared statement classes is rare because Database.SelectSQL and Database.ExecuteSQL utilize them automatically. See PreparedSQLStatement for information on cases where using prepared statement classes is appropriate. |
If you add a SQLiteDatabase directly to your project, then you need to upcast the result of the call to Database.Prepare to the SQLiteDatabase class. If you do not cast you will get a NilObjectException when you try to use it (refer to the example below).
These are the constants to use with the BindType method:
Constants |
---|
SQLITE_BLOB |
SQLITE_BOOLEAN |
SQLITE_DOUBLE |
SQLITE_INT64 |
SQLITE_INTEGER |
SQLITE_NULL |
SQLITE_TEXT |
SQLite can use 5 markers.
Markers |
---|
? |
?NNN |
:VVV |
@VVV |
$VVV |
In the markers above, NNN represents an integer literal, and VVV represents an alphanumeric identifier. For more information about these markers see SQLite binding.
Parameter binding does not do text substitution! Parameter binding substitutes each maker with your values at the database level for better security and performance.
When specifying parameters, do not wrap the value in single quotes like you might do with text substitution. The value you are substituting should contain the entire value. For example, if using '%' in a LIKE clause, the '%' is part of the value you supply, not part of the prepared SQL statement. |
For example, this is an invalid prepared statement because of the single quotes:
This is valid:
Multiple SQL Commands
If you prepare an SQL string that contains more than one SQL command then only the first command is executed .
For example a command such as this:
UPDATE foo SET bar = 1; UPDATE foo SET baz = 2;
will only execute "UPDATE foo SET bar = 1".
This is a specific security feature of SQLite.
Sample Code
The following sample creates an in-memory SQLiteDatabase, adds a table and populates it. It then uses a Prepared Statement to query the table and get a RecordSet.
Try
db.Connect
db.ExecuteSQL("CREATE TABLE Persons(Name, Age)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 20)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 21)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 22)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 20)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 21)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 22)")
db.ExecuteSQL("COMMIT")
Var ps As SQLitePreparedStatement = _
db.Prepare("SELECT * FROM Persons WHERE Name = ? AND Age >= ?")
ps.BindType(0, SQLitePreparedStatement.SQLITE_TEXT)
ps.BindType(1, SQLitePreparedStatement.SQLITE_INTEGER)
ps.Bind(0, "john")
ps.Bind(1, 20)
Var rs As RowSet = ps.SelectSQL
For Each row As DatabaseRow In rs
MessageBox("Name: " + row.Column("Name").StringValue + _
" Age: " + row.Column("Age").StringValue)
rs.MoveNext
Next
Catch error As DatabaseException
MessageBox("Database Error: " + error.Message
End Try
This sample passes the values to bind using the SQLSelect method rather than calling the Bind method:
Try
db.Connect
db.ExecuteSQL("CREATE TABLE Persons(Name, Age)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 20)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 21)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 22)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 20)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 21)")
db.ExecuteSQL("INSERT INTO Persons (Name, Age) VALUES ('john', 22)")
db.ExecuteSQL("COMMIT")
Var ps As SQLitePreparedStatement = _
db.Prepare("SELECT * FROM Persons WHERE Name = ? AND Age >= ?")
ps.BindType(0, SQLitePreparedStatement.SQLITE_TEXT)
ps.BindType(1, SQLitePreparedStatement.SQLITE_INTEGER)
Var rs As RowSet = ps.SelectSQL("john", 20) // Values are passed here
For Each Row As DatabaseRow In rs
MessageBox("Name: " + row.Column("Name").StringValue + _
" Age: " + row.Column("Age").StringValue)
rs.MoveNext
Next
Catch error As DatabaseException
MessageBox("Database Error: " + error.Message
End Try
This sample uses and reuses a Prepared Statement for the Insert:
Try
db.Connect
db.ExecuteSQL("CREATE TABLE Persons(Name, Age)")
Var ps As SQLitePreparedStatement = _
db.Prepare("INSERT INTO Persons (Name, Age) VALUES (?, ?)")
ps.BindType(0, SQLitePreparedStatement.SQLITE_TEXT)
ps.BindType(1, SQLitePreparedStatement.SQLITE_INTEGER)
ps.ExecuteSQL("john", 20)
ps.ExecuteSQL("john", 21)
ps.ExecuteSQL("john", 22)
ps.ExecuteSQL("john", 20)
ps.ExecuteSQL("john", 21)
ps.ExecuteSQL("john", 22)
db.ExecuteSQL("COMMIT")
ps = db.Prepare("SELECT * FROM Persons WHERE Name = ? AND Age >= ?")
ps.BindType(0, SQLitePreparedStatement.SQLITE_TEXT)
ps.BindType(1, SQLitePreparedStatement.SQLITE_INTEGER)
Var rs As RowSet = ps.SelectSQL("john", 20)
For Each row As DatabaseRow In rs
MessageBox("Name: " + row.Column("Name").StringValue + _
" Age: " + row.Column("Age").StringValue)
rs.MoveNext
Next
Catch error As DatabaseException
MessageBox("Database Error: " + error.Message
End Try
This sample uses a SQLite Database that was added to the project, so it has to cast the result from db.Prepare. TextField1 is used to enter the search string:
ps = SQLitePreparedStatement(CustomerDB.Prepare("SELECT * FROM Customers WHERE FirstName LIKE ?"))
ps.BindType(0, SQLitePreparedStatement.SQLITE_TEXT)
ps.Bind(0, TextField1.Text)
Var rs As RowSet = ps.SelectSQL
See Also
Database, PreparedSQLStatement, SQLiteDatabase classes.