Can you please tell me how to import external SQLite or MySQL DB to android SQLite or how can i use the external db in the android application?
Take care that the external SQLite database you wish to import uses INTEGER datatypes for the primary key, not INT or any of the other variants of INT. Some flavors of SQLite from the various SQLite Consortium members treat INTEGER and INT primary keys the same whereas (flagship) SQLite treats them differently.
See section 2.0 here: http://www.sqlite.org/datatypes.html
and see section on RowId and Primary Key here: http://www.sqlite.org/lang_createtable.html#rowid
A PRIMARY KEY column only becomes an
integer primary key if the declared
type name is exactly "INTEGER". Other
integer type names like "INT" or
"BIGINT" or "SHORT INTEGER" or
"UNSIGNED INTEGER" causes the primary
key column to behave as an ordinary
table column with integer affinity and
a unique index, not as an alias for
the rowid. [emphasis added]
EDIT: If your external SQLite database has its integer primary keys defined as INT or any of the other variants of INT, rather than as "INTEGER", you can get erroneous results when attaching to the database file from a consortium member's implementation. Let's say the FK value in a child table is 110; a join that treats the integer value as an alias for the rowid will look to the parent table to grab the 110th physical row, which may or may not be the row whose PK value = 110 if, in the parent table, the PK was defined as INT or BIGINT any of the other variants! In SQLite only an INTEGER [verbatim] PK is treated as alias for rowid, but some implementations did not follow that rule and treat all INT types as aliases for the rowid. Thus, when attaching from one of those implementations to an external SQLite datafile that was created using flagship SQLite, it is imperative to have used "INTEGER" (verbatim) primary keys and not any of the other INT types.
Have a look here to find some converters tools that can convert an MySQL dumb to a SQLite database. You could then import the database in your application as usual.
It is impossible to use the MySQL db directly.
I know it can be a cheap way but I used a push message service (MQTT) to take a copy of my mysql dump file and push the message to the phone, where I run it through a parser to insert rows into my local db. The mqtt message service has a precompiled .jar library that you can use quite easily in an android app.
There are a variety of means in which to implement the mqtt on your web server (SAM->php, or what I did write a c++ listening service to forward messages [Using an open source mqtt library called mosquitto]). The code to parse in the data is only a few lines since the message I receive in my android service is just a byte array.
As an example, I convert the byte array into a string, tokenize the string, and then insert it into the database:
public void parseMysqlDump(byte[] thisPayload) {
ContentResolver cr = this.getContentResolver();
String mysqlDump = "";
for(int i = 0; i < thisPayload.length; i++) {
mysqlDump += (char) thisPayload[i];
}
String[] mysqlDumpNewLineTokens = mysqlDump.split("\\n");
//The first line is the table headers stuff so start with i=1 to get to the first
//data line
for(int i = 1; i < mysqlDumpNewLineTokens.length; i++) {
String[] mysqlDumpSpaceTokens = mysqlDumpNewLineTokens[i].split("\\s");
String dataTitle = mysqlDumpSpaceTokens[0];
ContentValues cv = new ContentValues();
cv.put(Vehicle_DataMetaData.DATA_VALUE, mysqlDumpSpaceTokens[1]);
cr.insert(Vehicle_DataMetaData.CONTENT_URI, cv);
}
TL;DR: Take a mysql dump, send it as a string to the phone, parse the string into the db.
If you are interested in the mqtt stuff or wanted any clarification, just comment and I will get back to you
Related
I am using SQLite in an Android app which stores, amongst other things, a table that records the mood of the user. The table schema is shown below
CREATE TABLE moods
(
dow INTEGER,
tsn INTEGER,
lato INTEGER,
agitation TEXT DEFAULT '{}',
preoccupancy TEXT DEFAULT '{}',
tensity TEXT DEFAULT '{}',
taps TEXT DEFAULT '{}'
);
Unlike, say, Postgres, SQLite does not have a dedicated jsonb storage type. To quote
Backwards compatibility constraints mean that SQLite is only able to store values that are NULL, integers, floating-point numbers, text, and BLOBs. It is not possible to add a sixth "JSON" type.
SQLite JSON1 extension documentation
On the SQLite commandline processor I can populate this table using a simple INSERT statement such as this one
INSERT INTO moods (dow,tsn,lato,agitation,preoccupancy,tensity,taps)
VALUES(1,0,20,'{"A2":1}','{"P4":2}','{"T4":3}','{"M10":4}');
since it accepts both single and double quotes for strings.
In order to accomplish the same thing in my Hybrid Android app I do the following
String ag = JOString("A" + DBManage.agitation,1);
String po = JOString("P" + (DBManage.preoccupancy + 15),1);
String te = JOString("T" + DBManage.tensity,1);
which returns strings such as {"P4":2} etc. My next step is as follows
ContentValues cv = new ContentValues();
cv.put("dow",0);
cv.put("tsn",1);
cv.put("lato",2);
cv.put("agitation",ag);
cv.put("preoccupancy",po);
cv.put("tensity",te);
long rowid = db.insert("moods",null,cv);
which works. However, upon examining the stored values I find that what has gone in is in fact
{"dow":0,"tsn":5,"lato":191,"tensity":"{\"T0\":1}","agitation":"
{\"A1\":1}","preoccupancy":"{\"P15\":1}","taps":"{}"}]
Unless I am misunderstanding something here the underlying ContentValues.put or the SQLiteDatabase.insert implementation has taken it upon itself to escape the quoted strings. Perhaps this is to be expected given that the benefit of going down the SQLiteDatabase.insert route with ContentValues is protection from SQL injection attacks. However, in the present instance it is being a hindrance not a help.
Short of executing raw SQL via execSQL is there another way to get the JSON into the SQLite database table here?
I should add that simply replacing the double quotes with single quotes
String ag = JOString("A" + DBManage.agitation,1);
ag = ag.replaceAll("\"","'");
will not work since a subsequent attempt to extract JSON from the table
SELECT ifnull((select json_extract(preoccupancy,'$.P4') from moods where dow = '1' AND tsn = '0'),0);
would result in the error malformed JSON being emitted by the SQLite JSON1 extension.
Here is the table where i want to insert the value:
" create table if not exists "+CipherCongfigTable +
" ( DATABSE_NAME **TEXT** PRIMARY KEY NOT NULL,DATABSE_KEY **TEXT** NOT NULL);";
when i want to insert
String **configDBPassword**= "**x\'2DD29CA89\'**"
through statement
"insert into "+CipherCongfigTable+ " values("+DataBaseName+","+**configDBPassword**+")"
I am getting exception:
unrecognized token: "\":
I need the password in the same format i.e. having escape charecter. Is there any way to do it????
Thanks
Don't manually build INSERT (or any other if you can avoid it) queries on Android (or any other database wrapper as long as there is a predefined API to get what you want). It opens up your application to quoting problems like the one from your question and --at the worst-- to SQL injection attacks from outside of your application.
For example, setting configDBPassword = "\"; DROP TABLE <tablename>; --" I could possibly wreak havoc on your database as long as configDBPassword can be entered by the user.
Also, SQLite uses double quotes ("), backticks (`, borrowed from MySQL), or square brackets ([], borrowed from MS SQL) to quote identifiers (e.g. column or table names with spaces in them), string literals are canonically quoted with single (') quotes. SQLite is a quite liberal in allowing to mix both quoting types, but it is significantly more readable to use the proper quoting style whereever appropriate. From the documentation:
Programmers are cautioned not to use the two exceptions described in the previous bullets. We emphasize that they exist only so that old and ill-formed SQL statements will run correctly. Future versions of SQLite might raise errors instead of accepting the malformed statements covered by the exceptions above.
As a matter of fact, you should avoid doing the quoting by yourself whenever possible. For inserting values, please instead use SQLiteDatabase.insert() which is the proper way of inserting values into an SQLiteDatabase on Android. It also does proper quoting of the arguments, too:
db.beginTransaction();
try {
final ContentValues values = new ContentValues();
values.put("DATABSE_NAME", DataBaseName);
values.put("DATABSE_KEY", configDBPassword);
db.insert(CipherCongfigTable, null, values);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
Always properly quote your SQL parameters.
Try this .
"INSERT INTO "+CipherCongfigTable+ " values('DataBaseName','configDBPassword')”
You are not adding Single quotes(') in your insert query
Edit :
If you need to insert string with Single qotes means use like this before insert.
configDBPassword = configDBPassword.replace ("'", "''");
Also change your **
" create table if not exists "+CipherCongfigTable +
" ( DATABSE_NAME TEXT PRIMARY KEY NOT NULL,DATABSE_KEY TEXT NOT NULL);";
I have a sqlite database where all rows have a UUID as the primary key, the db column is defined as a BLOB.
The keys are inserted as byte[] instead of Strings to avoid wasting storage and index spaces. I can insert, update and delete rows using SQLiteDatabase.compileStatement and using bindBlob on the SQLiteStatement but I can't find anyway to bind a blob to the parameters of a SELECT query.
Both SQLiteDatabase.query and .rawQuery expects my WHERE arguments to be Strings which will never match my byte array blobs. I can find my row if I construct my WHERE manually using a BLOB literal like this:
final Cursor query = db.query(getTableName(),
getColumns(),
"id = X'" + bytesToHex(getByteArrayFromUUID(id)) + "'" ,
null,
null,
null,
null);
But then I am vulnerable to SQL injections...
In every other language I have used SQLite in this is not a problem, is there really no way to get a standard prepared SELECT statement with android SQLite?
Most of the APIs in Android sqlite expect the parameter to be strings.
You can use compileStatement() to prepare your query and then use bindBlob() to bind a blob argument to it. Getting useful results out from the query is not easy though, SQLiteStatement has methods for only a few 1x1 result sets.
On the other hand, using a blob as a key doesn't seem like a good idea.
I was curious if androids SQLiteDatabase insert method automatically handles type conversion.
Here is my example:
I have a csv file with a column name of age. Its type will be an INTEGER.
Lets say I have already created the database and table.
Now I am parsing the csv file with CSVReader, which parses each line and inserts each value into an index of a String[].
In order to insert each line of data into the database, I have to use a ContentValue object, which allows me to store values in it.
//Parse each line and store in line...
ContentValue values = new ContentValue();
values.put(KEY_AGE, line[1]); // Assume line[1] is the age
database.insert(table, null, values);
If I store the age value as a string (as seen above), and then insert it into the table, does Android handle the conversion to INTEGER before inserting it into the database?
I am asking this because I am trying to insert a bunch of tables into a database, and it looks much cleaner when I can just iterate through an array then explicitly state each put call, i.e:
Also if anyone has any design suggestions feel free to tell me.
CLEAN
int i = 0;
for(String s : TransitContract.Routes.COLUMN_ARRAY) {
values.put(s, line[i]);
i++;
}
UGLY
values.put(TransitContract.Routes.KEY_ROUTE_ID, line[0]);
values.put(TransitContract.Routes.KEY_AGENCY_ID, line[1]);
values.put(TransitContract.Routes.KEY_SHORT_NAME, line[2]);
values.put(TransitContract.Routes.KEY_LONG_NAME, line[3]);
values.put(TransitContract.Routes.KEY_DESCRIPTION, line[4]);
values.put(TransitContract.Routes.KEY_ROUTE_TYPE, Integer.parseInt(line[5]));
values.put(TransitContract.Routes.KEY_URL, line[6]);
values.put(TransitContract.Routes.KEY_COLOR, line[7]);
values.put(TransitContract.Routes.KEY_TEXT_COLOR, line[8]);
return mDatabase.insert(TransitContract.Routes.TABLE_NAME, null, values);
When you declare a column as INTEGER, SQLite will automatically convert strings to numbers, if possible.
See the documentation for Type Affinity.
If your ContentProvider doesn't restrict it (i.e. pass it directly to the SQLiteDatabase.insert() method), it should work. SQLite is not that picky about the types used in queries/inserts and the actual column type.
However, it would be best practice to parse and check the values before inserting. Otherwise you might actually insert a string which can't be parsed as integer and therefore retrieving the value might fail.
References:
Boolean datatype accepting string value and integer value
SQLite table with integer column stores string
I am using a SQLite database to store data that can be used to reconstruct some objects that I am using in the application I am developing. I am storing CheckIns, Recipients, and ContactMethods.
These objects are related as follows:
CheckIn <--many -- to -- many--> Recipient
Recipient <--one -- to -- many--> ContactMethod
In Java, these objects' fields are defined as follows:
public class CheckIn {
private int id;
private boolean isEnabled;
private Date startTime;
private Repetition repetition;
private Set<Recipient> recipients;
}
public class Recipient {
private String name;
private Set<ContactMethod> contactMethods;
}
public class ContactMethod {
private String type;
private String address;
}
The database schema I have come up with for these objects is defined as follows:
CREATE TABLE checkIn(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
isEnabled INTEGER,
startTime INTEGER,
repetitionNum INTEGER,
repetitionUnits TEXT
);
CREATE TABLE recipient(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT
);
CREATE TABLE contactMethod(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
type TEXT,
address TEXT,
recipientID INTEGER,
FOREIGN KEY(recipientID) REFERENCES recipient(_id) ON DELETE CASCADE
);
CREATE TABLE checkIn_recipient(
checkInID INTEGER,
recipientID INTEGER,
FOREIGN KEY(checkInID) REFERENCES checkIn(_id),
FOREIGN KEY(recipientID) REFERENCES recipient(_id)
);
I have two questions.
1. How do I efficiently INSERT a CheckIn to the database, along with its related objects?
To be more specific, if I have a CheckIn object in Java, not yet committed to the database, how can I structure an INSERT statement that will insert the CheckIn to the CheckIn table, but also store the new CheckIn's relation to one or more Recipients? It seems like to store the relation to the Recipients, I would need to already know the checkIn._id, which hasn't been set yet, since the CheckIn hasn't been entered into the database yet.
2. In Android, what is the best way to rebuild a CheckIn object, for example, from a database query?
I think I know the SQL query that I will need to get the right data:
SELECT checkIn.*, recipient.name, contactMethod.type, contactMethod.address
FROM checkIn
JOIN checkIn_recipient
ON (checkIn._id = checkIn_recipient.checkInID)
JOIN recipient
ON (checkIn_recipient.recipientID = recipient._id)
JOIN contactMethod
ON (recipient._id = contactMethod.recipientID)
This query will get me rows of data containing all of the information I need to build an object for every CheckIn and Recipient in the database, and I know how to get a Cursor object that will iterate through these rows. However, since the data required for a single CheckIn appears on multiple rows, I am confused about the best way to construct individual CheckIn objects. If I am trying to write a method like public Set<CheckIn> getAllCheckIns() that will return a set of all CheckIns that are stored in the database, do I need to run the query above, then loop through each row with the same checkIn._id, and within that loop, every row with the same recipient._id, and so forth? Is there any better way to do this?
I am sorry for the long question. I have only been working with SQL beyond single table databases since this morning, and I didn't want to leave out any important information. Let me know if I missed something.
Answer to Question 1: There are 2 possible ways.
a. You find the ID of the inserted row and use that to insert into the 2nd table. You can find the ID of inserted row if you are using the Android Insert method as documented here:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert%28java.lang.String,%20java.lang.String,%20android.content.ContentValues%29
Here you must ensure that all DB tables are committed or none.
b. You can create triggers. Triggers are database operations that are automatically performed when a specified database event occurs.
Learn how to create triggers: http://www.sqlite.org/lang_createtrigger.html
So for e.g. you can create a AFTER INSERT trigger that will be fired when a row in inserted in check in table. Then in that trigger you can insert a row into another table.
When the trigger is fired, you have access to the newly inserted row.
Answer to question 2:
I usually do the following :
Select from table 1 - Check In table
Iterate over the cursor and prepare the Check In object.
Within the loop, select from table 2 - Recipient table
Iterate over the recipient table and prepare the Check in object.
This would involve too many DB selects.
Alternatively, you could select all data once and then iterate to prepare the objects.
The point I am trying to make is that you have to iterate :D