PhoneGap - How to query SQLite in a for loop? - android

I have a problem with a SQLite query on PhoneGap application.
I would open a folder and make a select with where clause for every entries in the folder.
I open a for loop, after a select query, but the script uses same variables for all the entries (it remembers only the last record's variables).
The loop reads correctly the number of entries, but it works only with one record's variables, and it works for as many times as there are files in the folder only with these variables.
function readerSuccess(entries) {
var db = window.openDatabase("Test", "1.0", "Demo test", 200000);
db.transaction(function(tx) {
var i;
for (i=0; i<entries.length; i+=1) {
var imgName=entries[i].name;
var upfi=entries[i];
console.log(imgName);
tx.executeSql("SELECT * FROM FOTO WHERE img=?", [imgName], function(tx, result) {
console.log(imgName+" after SQL");
var dataset = result.rows;
console.log("Returned rows = " + dataset.length);
if (dataset.length==0) {
console.log('No rows!');
console.log('File sync: '+imgName);
} else {
console.log('File already sync: '+imgName);
};
}, successCB, errorCB)}}, successCB, errorCB);
};
I have tested with global variables or local variables without a success.
I do not know where to turn!! :(

Related

Sqlite table and database migrations on a Published app?

I have developed an android app in react-native and expo. I have also published the app on google play.
Now, I have made some modifications on my SQLite DB tables locally.
Suppose, before the schema of a table was like this:
CREATE TABLE expenditures (id integer primary key, max_amount REAL not null);
And now I would like to change it to this:
CREATE TABLE expenditures (id integer primary key, max_amount TEXT not null);
Is there any way to run a method after a new update/upgrade on a production app (google play store)? That way I can alter the tables only once after the upgrade, and other newly installed users won't be affected by this function. I found two methods on native android:
onCreate: Called for the first time when creation of tables are needed.
onUpgrade: This method is called when database version is upgraded.
But since I have developed my app with react-native and expo, I can't use the above methods. Although I have found onUpgrade in the expo code, I am not sure how to use this feature in expo.
Or is there any better way to handle database migrations on a published app in react-native and expo?
I don't think you can really use the versioning stuff you linked to, as that will drop your db and recreate it from scratch, so you would lose your data.
A simple solution to this is to manually keep track of migrations you've already executed in a table. Then you can create this table if it doesn't exist yet (which can be done in a very dumb way by first trying to query it, and if that fails, create it). If you have a list of all known migrations in order, you can just drop items that already have an entry in the table and run the remaining ones.
From an old Cordova application I wrote this code (yeah it's really old, it's still using Require JS to define the module):
/**
* Provide access to an SQL database, using the SQLite plugin for
* Cordova devices so we aren't limited in how much data we can store,
* and falling back to browser native support on desktop.
*
* Unfortunately webSQL is deprecated and slowly being phased out.
*/
define(['require', 'module', 'deviceReady!'], function(require, module, isCordova) {
'use strict';
var dbRootObject = isCordova ? window.sqlitePlugin : window,
config = module.config();
if (typeof dbRootObject.openDatabase == 'undefined') {
window.alert('Your browser has no SQL support! Please try a Webkit-based browser');
return null;
} else {
var db = dbRootObject.openDatabase(config.dbName, '', 'Direct Result database', null),
transaction = function(callback) {
// We go through this trouble to automatically provide
// error reporting and auto-rollback.
var makeFacade = function(t) {
return {
sql: function(sql, args, okCallback, errorCallback) {
var okFn, errFn;
if (okCallback) {
okFn = function(t, r) { return okCallback(makeFacade(t), r); };
} else {
okFn = null;
}
if (errorCallback) {
errFn = function(t, e) { console.log('SQL error: '+sql, e); return errorCallback(makeFacade(t), e); };
} else {
errFn = function(t, e) {
// It's important we throw an exn,
// else the txn won't be aborted!
window.alert(e.message + ' sql: '+sql);
throw(e.message + ' sql: '+sql);
};
}
return t.executeSql(sql, args, okFn, errFn);
}
};
};
return db.transaction(function(t) {
return callback(makeFacade(t));
}, function(e) { console.log('error'); console.log(e); });
},
// We're going to have to create or own migrations, because
// both the Cordova SQLite plugin and the Firefox WebSQL
// extension don't implement versioning in their WebSQL API.
migrate = function(version, upFn, done, txn) { // "Down" migrations are currently not supported
var doIt = function(t) {
t.sql('SELECT NOT EXISTS (SELECT version FROM sqldb_migrations WHERE version = ?) AS missing',
[version], function(t, r) {
if (r.rows.item(0).missing == '1') {
upFn(t, function() {
t.sql('INSERT INTO sqldb_migrations (version)'+
'VALUES (?)', [version], done);
});
} else {
done(t);
}
});
};
if (txn) doIt(txn);
else transaction(doIt);
},
maybeRunMigrations = function(callback) {
var migrations = [],
addMigration = function(name, migration) {
migrations.push([name, migration]);
},
runMigrations = function(t) {
if (migrations.length === 0) {
callback(t);
} else {
var m = migrations.shift(),
name = m[0],
migration = m[1];
migrate(name, migration, runMigrations, t);
}
};
// ADD MIGRATIONS HERE. The idea is you can just add migrations
// in a queue and they'll be run in sequence.
// Here are two example migrations
addMigration('1', function (t, done) {
t.sql('CREATE TABLE people ('+
' id integer PRIMARY KEY NOT NULL, '+
' initials text NOT NULL, '+
' first_name text NOT NULL, '+
' family_name text NOT NULL, '+
' email text NOT NULL, ', [], done);
});
addMigration('2', function(t, done) {
t.sql('ALTER TABLE people ADD COLUMN phone_number text', [], done);
});
transaction(function(t) {
t.sql('CREATE TABLE IF NOT EXISTS sqldb_migrations ('+
' version int UNIQUE, '+
' timestamp_applied text NOT NULL DEFAULT CURRENT_TIMESTAMP '+
')', [], function (t, r) { runMigrations(t, migrations); });
});
};
// Expose "migrate" just in case
return {transaction: transaction, migrate: migrate, maybeRunMigrations: maybeRunMigrations};
}
});
You'll also need to take a lot of care, as I found out the hard way you cannot actually alter or even drop columns with SQLite (or at least not with the Cordova plugin at the time I wrote this code)! So also be very careful with constraints or you'll end up painting yourself into a corner.
I have not tried it, but it might be possible if you rename the old table, create the new one again with the changed columns and then copy over the data.
you can put the sql alteration files in assets folder android/app/src/main/assets/ like
<version>.sql -> 1.sql or 2.sql
and these file can contain the migration query like
alter table NOTE add NAME TEXT;
and trigger these query according to version of app in onUpgrade() method

Visual Studio 2015 apache cordova

I have an app that uses WebSQL transactions to create a table, insert data, and retrieve information from a database.
The app works fine on the Ripple Nexus (Galaxy) but not on the device (Galaxy Note 5) nor the emulator. The UI is there: text boxes, labels, buttons, etc. However, according to my notice, the operations on the database are not performed.
What can I do?
There are not enough details here to tell what is going on and no code samples. Note that ripple is using http and your app on the device is probably using a non http:// calling location. Another possible issue is that on your machine there is web connectivity to a local http endpoint and on the device the end point would not be available unless it is public on the internet / available to the device.
Here is sample of my code, open database and populate data tables:
document.addEventListener('deviceready', onDeviceReady.bind(this), false);
var db = openDatabase('DUTIESDB', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql("DROP TABLE DUTIES", []);
tx.executeSql("DROP TABLE SDUTIES", []);
tx.executeSql('CREATE TABLE IF NOT EXISTS DUTIES (id, name, date, time, course, room)');
tx.executeSql('CREATE TABLE IF NOT EXISTS SDUTIES (id, name, date, time, course, room, invg)');
});
PupulateSupTable();
function PopulateSupTable() {
var xmlhttp = new XMLHttpRequest();
var url = "/scripts/SupDuties.txt";
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var myArr = JSON.parse(xmlhttp.responseText);
db.transaction(
function (tx) {
var k, sql = 'INSERT INTO SDUTIES (id, name, date, time, course, room, invg) VALUES (?,?,?,?,?,?,?)';
for (k = 0; k < myArr.length; k++) {
tx.executeSql(sql, [myArr[k].ID, myArr[k].Name, myArr[k].Date, myArr[k].Time, myArr[k].Course, myArr[k].Room, myArr[k].Invigilator]);
}
}
);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
}

How to know that Web SQL already exist?

I am making very simple application in cordova for ios/android. I have made it all but I am getting problem in database. I am trying to make sure that when app run it look for internet and if internet is available than it login using api, but it also create two databases one for user login(I know it is not good practice, but my requirement will search something to encrypt database) and save only current user in database. While other db will be used to store offline working of user. But when I am not clear how to know if my db is already made. Following are codes, kindly check, as I have search everywhere and seem like there is no solution except to check tables but when I do check tables my program stops to work.
When application start it asks userid, password than after validation following commands run.
document.addEventListener("deviceready", onDeviceReady(user, serviceURL, pass), false)
Following is function I am using on deviceready, if internet available it log in user and create db, if internet is not available it access db, but here is problem how I know if db exist so let login user otherwise alert him that internet is required for first time.
function onDeviceReady(user, serviceURL, pass) {
if(navigator.network.connection.type == Connection.NONE)
{
var db = window.openDatabase(
'test',
'1.0.0',
'Test Database',
64 * 1024
);
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM USERS', [], function (tx, results) {
var len = results.rows.length, i;
msg = "<p>Found rows: " + len + "</p>";
}
alert(msg);
for (i = 0; i < len; i++){
alert(results.rows.item(i).user );
}
}, null);
});
}
else
{
alert("Internet is available!!");
$.getJSON(serviceURL + 'APIjson.php?user='+user+'&pass='+pass+'&action=login', function(data)
{
if(data.error==-1)
{
alert("Invalid user id or password.");
return false;
}
else {
//navigator.notification.activityStop(); // for android only
// ActivityIndicator.hide(); // for IOS
window.localStorage["user_id"] = data.id;
var db = window.openDatabase(
'test',
'1.0.0',
'Test Database',
64 * 1024
);
db.transaction(function populateDB(tx) {
tx.executeSql('DROP TABLE IF EXISTS USERS');
tx.executeSql('CREATE TABLE IF NOT EXISTS USERS (id unique, user, pass)');
var sql = 'INSERT INTO USERS (id, user, pass) VALUES (?, ?, ?)';
tx.executeSql(sql,[data.id, user, pass]);
},function errorCB(tx, err) {
alert("Error processing SQL: "+err);
},function successCB() {
alert("success!");
});
window.location.href = "contact.html";
return true;
}
})
}
}
I also tried to add when database retrieve on len that howmany rows came and it should alert, but it failed and my app stop to work
if (!len > 0) {
alert("Sorry you need to connect internet for first time use");
return false;
You should move the javascript redirect into the success callback:
db.transaction(function populateDB(tx) {
tx.executeSql('DROP TABLE IF EXISTS USERS');
tx.executeSql('CREATE TABLE IF NOT EXISTS USERS (id unique, user, pass)');
var sql = 'INSERT INTO USERS (id, user, pass) VALUES (?, ?, ?)';
tx.executeSql(sql,[data.id, user, pass]);
},function errorCB(tx, err) {
alert("Error processing SQL: "+err);
},function successCB(){
alert("success!");
window.location.href = "contact.html";
});
The problem is that you are navigating away from your current page before the transaction has the chance to complete. The whole point of a call back is that it is called at a later time when the async task completes. However when you navigate away from the page, the webview will simply drop all tasks on the current page and move on.
Secondly, instead of a drop create you should use:
db.executeSql('CREATE TABLE IF NOT EXISTS tableName (someID text primary key, data text)');
To see if the data was added:
I suggest you use the chrome console to interact with the db. https://developers.google.com/chrome-developer-tools/docs/remote-debugging
You will need to write a couple db.executeSql(selectStatement) eg:
db.transaction(function(tx) {
tx.executeSql("select * from table1 where theID ='"+theID+"';", [], function(tx, rs) {
for (var i=0; i < rs.rows.length; i++) {
console.log(rs.rows.item(i));
console.log('data found in db');
}
if(rs.rows.length < 1){
console.log('data not in db');
}
},function(tx,e){console.log(e.message);});
});
To see the database, use the chrome debugger:
Connect your phone in debug mode/start emulator
In chrome go to this url: chrome://inspect/
Find your app and click inspect. A new window will open up.
Click on resources tab on top.
In the left pane click WebSQL (see screenshot)

SQLitePlugin with cordova and ANDROID

I need to use 2 sqlite database for my app
the 2 databases have the some structure because one of it is StoricDB
in some procedure i need to use both db.
i do this code:
var onDeviceReady = function ()
{
testwith2db();
};
document.addEventListener("deviceready", onDeviceReady, true);
function testwith2db (){
var dbCurrent_path = "/sdcard/Android/data/myDatabase/DbCurrent"
var dbStoric_poath = "/sdcard/Android/data/myDatabase/DbStoric"
// this work fine
var db_current = window.sqlitePlugin.openDatabase(dbCurrent_path , "1.0", "DbCurrent", 10000000);
db_current.transaction(doquerycurrent, on_tran_error, on_tran_success);
//this work fine
var db_storic = window.sqlitePlugin.openDatabase(dbStoric_poath , "1.0", "DbStoric", 10000000);
db_storic.transaction(doquerystoric, on_tran_error, on_tran_success);
/*
following lines are my problem
because if i do:... another query on currentdb, the query is alwais executed on last db opened
for me is impossible to use currentdb again
*/
var db_current = window.sqlitePlugin.openDatabase(dbCurrent_path , "1.0", "DbCurrent", 10000000);
db_current.transaction(doquerycurrent, on_tran_error, on_tran_success);
}
function doquerycurrent(txc){
// strange behaviour
// this query is executed on storic db if a have opened it
txc.executeSql("SELECT * FROM table1", [],[]);
}
function doquerystoric(txs){
txs.executeSql("SELECT * FROM table1", [],[]);
}
i have tried with attach db form my query but is unsupported from android ????
tx.executeSql("ATTACH DATABASE '/mnt/sdcard/Android/data/myDatabase/DbStoric' as S",[], on_query_success) // this line return error
please help me
thanks

first time running sqlite after app install issue with phonegap/coredava

I am developing an APP using phonegap/coredava while trying to create an access database for the first time after app is installed I am unable to access database but on second run everything working fine how can I fix this my javascript code is below
var dbsize=4*1024;
document.addEventListener("deviceready", onDeviceReady, false);
var dbShell = window.openDatabase("mydb", "1.0", "my db", dbsize);
function onDeviceReady(){
dbShell.transaction(defaultPopulatedb,errorDF,successDF);
}
function defaultPopulatedb(tx){ //creating tables for the first time
tx.executeSql('CREATE TABLE IF NOT EXISTS Userlocation (id INTEGER PRIMARY KEY AUTOINCREMENT, Location TEXT NOT NULL, Locationvalue TEXT NOT NULL)',[],checkfirst,errorTB);
}
function checkfirst(tx)
{
tx.executeSql('SELECT * FROM Userlocation',[],chevals,errorDFS); }
}
function chevals(tx,result)
{
var len =result.rows.length;
if(!len){
tx.executeSql('INSERT INTO Userlocation(Location,Locationvalue) VALUES ("default","default")',[],added,erdf);
}
}
function errorDFS()
{
alert("error");
}
function added()
{
alert("added");
}
function erdf()
{
alert("error adding default");
}
function errorTB()
{
alert("error table");
}
I met this problem once too. You can just simply try{...} catch (ex){...} and ignores the first exception.
Actually, there is a great data access framework for phonegap.

Categories

Resources