firefox extension SQLite saving and getting - sqlite

Ok now for the juicy stuff. All attempts failed to save my string so far.
Here is the code for saving it in sqllite in firefox extension:
var file = Components.classes["#mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
file.append("my_db_file_name.sqlite");
var storageService = Components.classes["#mozilla.org/storage/service;1"]
.getService(Components.interfaces.mozIStorageService);
var mDBConn = storageService.openDatabase(file);
mDBConn.execute("CREATE TABLE IF NOT EXISTS log_det (id INTEGER PRIMARY KEY AUTOINCREMENT, acc STRING)");
mDBConn.execute("INSERT INTO log_det (acc) VALUES(" + window['gluistr']+ ")");
mDBConn.drop();
And the code for retrieving the value:
var file = Components.classes["#mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
file.append("my_db_file_name.sqlite");
var storageService = Components.classes["#mozilla.org/storage/service;1"]
.getService(Components.interfaces.mozIStorageService);
var mDBConn = storageService.openDatabase(file);
var res = mDBConn.execute("SELECT * FROM log_det");
mDBConn.drop();
Is not working. Anybody knows why? Is "execute" ok or do I need "createStatement" or "executeSimpleSQL". I am confused.

Use executeSimpleSQL.
openDatabase returns a mozIStorageConnection instance, which does not have any method named execute. You can use executeSimpleSQL any time you want to execute a SQL statement without bound parameters (which is what you're doing).
You were probably thinking of mozIStorageStatement's execute method. executeSimpleSQL is not sufficient when bound parameters are necessary. Instead, you need to create a statement, bind any parameters, and then execute it:
var statement = mDBConn.createStatement(
"SELECT * FROM log_det WHERE column_name = :parameter");
statement.bindStringParameter(0, "value");
statement.execute();
statement.reset();
Also note that mozIStorageConnection does not have any method named drop. Maybe you meant to write mDBConn.close()?
All of this is covered here:
https://developer.mozilla.org/en/storage

Related

Add "blocking" to Swift for-loop

I am using Swift in a project, and using SQLite.swift for database handling. I am trying to retrieve the most recent entry from my database like below:
func returnLatestEmailAddressFromEmailsTable() -> String{
let dbPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String
let db = Database("\(dbPath)/db.sqlite3")
let emails = db["emails"]
let email = Expression<String>("email")
let time = Expression<Int>("time")
var returnEmail:String = ""
for res in emails.limit(1).order(time.desc) {
returnEmail = res[email]
println("from inside: \(returnEmail)")
}
return returnEmail
}
I am trying to test the returned string from the above function like this:
println("from outside: \(returnLatestEmailAddressFromEmailsTable())")
Note how I print the value from both inside and outside of the function. Inside, it works every single time. I am struggling with the "from outside:" part.
Sometimes the function returns the correct email, but sometimes it returns "" (presumably, the value was not set in the for loop).
How can I add "blocking" functionality so calling returnLatestEmailAddressFromEmailsTable() will always first evaluate the for loop, and only after this return the value?

Firefox addon development: SQLite Database Connection

So I am developing this add-on using the MDN's Add-on Builder and need to connect with the SQLite Database. The connection gets created fine and insertion is fine as long as I am inserting values without binding parameters(that is, through executeSimpleSQL()). As soon as I use the createStatement() method to INSERT values, it does not work. Here's what I have done so far.
let file = FileUtils.getFile("Desk", ["my_db_file_name.sqlite"]);
let mDBConn = Services.storage.openDatabase(file);
mDBConn.executeSimpleSQL("CREATE TEMP TABLE IF NOT EXISTS element (rating VARCHAR(50))");
let stmt = mDBConn.createStatement("INSERT INTO element (rating) VALUES(:value)");
stmt.params.value = 13;
//mDBConn.executeSimpleSQL("INSERT INTO element (rating) VALUES(13)");
var statement = mDBConn.createStatement("SELECT * FROM element WHERE rating = :rat");
statement.params.rat = 13;
try {
while (statement.step()) {
let value = statement.row.rating;
console.log(value);
}
}
finally {
statement.reset();
}
Note that the SELECT statement with the bound parameters works fine, it's just the INSERT statement that's problematic.
Any ideas?
You forgot to call execute().

Get oracle output parameter using OracleCommand

I have a oracle stored procedure which will return a value. I need to get the OUTPUT value in my C# program. I need to know how we can get the OUTPUT parameter using the OracleCommands AddWithValue method.
The way i have written now is:
OracleCommand Ocmd = new OracleCommand(_StoredProcedure, OraCon);
Ocmd.CommandType = CommandType.StoredProcedure;
Ocmd.Parameters.AddWithValue("Filed1", "Value1");
Ocmd.Parameters.AddWithValue("OUTPUTParam","").Direction = ParameterDirection.Output;
OraCon.Open();
int RecivedDetID = Ocmd.ExecuteNonQuery();
OraCon.Close();
return Ocmd.Parameters[_OutParam].Value.ToString();
I know the OUTPUTPARAm how i have called is wrong. How can i achieve it using the
AddWithValue method of the OracleCommand. I dont want to use the OracleCommands Add method where we need to specify the Type also.
Make sure you set the SIZE property on the parameter before executing. With output parameters in Oracle, the specified size acts as a buffer. If the buffer isn't set, it is 0 so you don't get the value from the database.
var param = Ocmd.Parameters.AddWithValue("OUTPUTParam","").Direction = ParameterDirection.Output;
param.Size = 255;
The rest is good!

How can I make my AS3/Air code better?

Hello everyone this is my little Frankenstein code, don't make fun of it, it works!
So you would pass in the table name and a data as an Associative array which are objects.
I'm pretty sure this is not good code as I was and still am learning ActionScript. So what can I change or how would you guys make it better?
public function save(table:String,data:Object):void
{
var conn:SQLConnection = new SQLConnection();
var folder:File = File.applicationStorageDirectory;
var dbFile:File = folder.resolvePath("task.db");
conn.open(dbFile);
var stat:SQLStatement=new SQLStatement();
stat.sqlConnection=conn;
//make fields and values
var fields:String="";
var values:String="";
for(var sRole:String in data)
{
fields=fields+sRole+",:";
stat.parameters[":"+sRole]=data[sRole];
}
//trim off white space
var s:String=new String(fields);
var cleanString:String=s.slice( 0, -2 );
//over here we add : infront of the values I forget why
var find:RegExp=/:/g;
var mymyField:String=new String(cleanString.replace(find,""));
cleanString=":"+cleanString;
var SQLFields:String=mymyField;
var SQLValues:String=cleanString;
stat.text="INSERT INTO "+table+" ("+SQLFields+")VALUES("+SQLValues+")";
stat.execute();
}
The part where you build your query is quite a horror, to be honest. Half the code removes junk you added just a few lines before. This makes it hard to read and understand. Which is a sign of poor code quality. The following is far shorter and simpler:
//make fields and values
var fields:Array = [];
for(var field:String in data) {
fields.push(field);
stat.parameters[":"+field]=data[fieldName];
}
var sqlFields:String = fields.join(",");
var sqlValues:String = ":"+fields.join(",:");
stat.text="INSERT INTO "+table+" ("+sqlFields+")VALUES("+sqlValues+")";
stat.execute();
Someone once told me that a stupid idea that works isn't stupid. As programmer's our first goal is (often) to solve business issues; and as long as our code does that then we are successful. You don't need to apologize for code that works.
In terms of what I would do to change your snippet; I might just encapsulate it a bit more. Can the folder, dbFile, and db file name (task.db) be added either as properties to your class or arguments to the method?
Can you separate out the creation of the SQL Statement from the connection handling from your data parsing?
Some remarks,
As said before you can factorise out all the db connection so you can reuse the function without rewriting it if you need to change the db name.
Don't use new String() you can avoid it
it's not usefull to clean white space between your field :a, :b is the same as :a,:b
Some convention don't begin your local var name with an uppercase, and it's not usefull to reassign them to another var
If i don't get wrong after your //make fields and values can be rewritten for example as :
//make fields and values
var fields:String = "";
var values:String = "";
var fieldSeparator:String = "";
for(var sRole:String in data)
{
fields += fieldSeparator + sRole;
var paramName:String = ":" + sRole;
values += fieldSeparator + paramName;
stat.parameters[paramName] = data[sRole];
fieldSeparator = ",";
}
stat.text = "INSERT INTO " + table +" (" + fields + ") VALUES (" + values + ")";
stat.execute();

NS_ERROR_FILE_IS_LOCKED when several requests using SQLite on Mozilla plateform

I'm trying to use Storage mechanism in Mozilla platform (in thundebird 3.0).
The following code is used after each test to erase the table present in the database:
function tearDown()
{
let database = new Database();
let req1 = "SELECT name FROM sqlite_master WHERE type='table'";
let statement = database.connection.createStatement(req1);
let tables = [];
while(statement.executeStep()) {
tables.push(statement.row.name);
}
statement.reset();
for(table in tables) {
let req2 = "DROP TABLE " + tables[table];
database.connection.executeSimpleSQL(req2);
}
}
But I've an error during executeSimpleSQL of req2 (NS_ERROR_FILE_IS_LOCKED), It seems that SQLite doesn't release the lock from the first statement. I've tried reset(), finalize(), but nothing works. How can I properly release the lock of the first statement?
Answering myself: I forgot to release a previous statement in previous code of my application.
Final story: when you use
statement.executeStep()
Check:
be sure that the last call of this statement return false
or never forgot to release it:
statement.reset();
var statement = dbConn.createStatement("SELECT COUNT(name) AS nameOcurrences FROM Table1 WHERE name = '" + aName + "';");
var occurrences;
while(statement.executeStep()) {
occurrences = statement.row.nameOcurrences;
}

Resources