Sqflite Database exception type in flutter - sqlite

I am using package Sqflite for database management in flutter, I want to discriminate database exception, i.e. I want to know what went wrong during INSERT query, whether it was missing table or a mismatch in column name or trying to insert duplicate value in a column with UNIQUE constraint.
In following code I am able to catch exceptions but I am unable to discriminate them.
DatabaseHelper helper = DatabaseHelper.instance;
try {
id = await helper.insertMeter(dataMap);
print('inserted row: $id');
} catch (ex) {
// Here I want to know what caused exception.
print('Failed to insert: ' + ex.toString());
}
Please help.

Unfortunately, the native report we get is not always consistent between iOS and Android. There are some helpers you can use if you catch explicitely a DatabaseException such as isUniqueConstraintError, isNoSuchTableError. It is based on parsing the exception text thrown for a few example tested. Some could be added assuming we can parse a relevant error but it cannot be more than what we can extract from the string you currently print.

Related

Catching DatabaseException in Flutter

I wanted to know how I can handle and succesfully catch my Database Exception. I had a primary key ID and another key called name in my Sqlite database. Im using the flutter plugin sqflite. I wanted to handle the case when there is already a entry in my database with the given ID i want to display ID already exists, for that I want to know how I can handle the exceptions.
I tried to surround the code in a try catch block but Im not able to make FLutter realize about the DatabaseException class, it gives me error saying "DatabaseException" isn't a type and can't be used in on catch clause. I want to add a new Subject into my database after a button is pressed and if user enters the same ID value as already existing one I want to handle the error.
onSubmitted: (test) async {
Subject newSubject = Subject(name: name, id: test);
try {
await DBProvider.db.newSubject(newSubject);
} on DatabaseException {}
},
You should import sqflite in the dart file where you're using the exception, add
this:
import 'package:sqflite/sqflite.dart';

Is it possible to validate a GQL query in cloud datastore before submitting it? Any examples preferably using the Java lib

From the google code examples:
public QueryResults<?> newQuery(String kind) {
// [START newQuery]
String gqlQuery = "select * from " + kind;
Query<?> query = Query.newGqlQueryBuilder(gqlQuery).build();
QueryResults<?> results = datastore.run(query);
// Use results
// [END newQuery]
return results;
}
Is it possible to validate the gqlQuery before officially running the query?
It looks like you can't. Your best option would be to test your queries with the LocalDatastoreHelper class, like it's done in here. Check how it's set up and the assertValidKey and the GQL methods there.
Again, this is not actual validation of the query, but it seems like the best shot. Also, upon failures, the exception thrown would be DatastoreException, so, you can try and catch said exception in your code.

Trouble inserting data into sqlite database with JDBC

This is what my code currently looks like:
import java.sql.*
import java.sql.SQLException
class SqliteDB {
val conn = DriverManager.getConnection("jdbc:sqlite:cs2820-database.db")
fun createUser123(userID: String, password: String, adminStatus: String) {
val statement = conn.prepareStatement("INSERT INTO Users(id,pass,admin) VALUES(?,?,?)")
statement.setString(1, userID)
statement.setString(2,password)
statement.setString(3,adminStatus)
println("123")
statement.executeUpdate()
conn.commit()
println("User Created")
}
// create a user
fun createUser(userID: String, password: String, adminStatus: String) {
println("inside createUser")
val sql = "INSERT INTO Users(id,pass,admin) VALUES(?,?,?)"
Class.forName("org.sqlite.JDBC")
try {
conn.use { conn ->
conn.prepareStatement(sql).use { pstmt ->
pstmt.setString(1, userID)
pstmt.setString(2, password)
pstmt.setString(3, adminStatus)
pstmt.executeUpdate()
//conn.commit()
pstmt.close()
}
}
} catch (e: SQLException) {
println(e.message)
}
}
fun main(args: Array<String>) {
val db = SqliteDB()
db.createUser("Jim", "password", "false")
}
I have tested two different createUser methods and most everything I have tried will return the error [SQLITE_BUSY] The database file is locked (database is locked). I have several other methods within the same SqliteDB class that query data ("SELECT") that all work correctly, but every time I try to perform any kind of update of information I am given the same error. I am at a loss for what to do at this point having searched many different forums and posts about syntax and such.
The full stacktrace is as follows:
Exception in thread "main" org.sqlite.SQLiteException: [SQLITE_BUSY] The database file is locked (database is locked)
at org.sqlite.core.DB.newSQLException(DB.java:909)
at org.sqlite.core.DB.newSQLException(DB.java:921)
at org.sqlite.core.DB.execute(DB.java:822)
at org.sqlite.core.DB.executeUpdate(DB.java:863)
at org.sqlite.jdbc3.JDBC3PreparedStatement.executeUpdate(JDBC3PreparedStatement.java:99)
at SqliteDB.createUser(SqliteDB.kt:50)
at SqliteDBKt.main(SqliteDB.kt:122)
I don't believe the issue is with an open connection as the error seems to occur as soon as I try to execute the update to the User table. The insert seems to hit some sort of loop of some kind at the execution stage.
EDIT: Something else I noticed, is that when attempting to create a new user with a primary key (userID) that already exists, I am given a uniqueness error, suggesting the update is going thru and realizing the userID is already in the table; however, there is still the issue with the INSERT creating a new row in the table. I'm just not sure how to go about debugging that specific issue.
So this has been quite an issue for me for the past week or so and it looks like I have been able to figure out the issue.
I am aware that you have to make sure to close any connections to the database before opening a new one to avoid locks and any other similar issues. What I did not realize is that I have been using a program in IntelliJ called "DB Browser". This plugin creates a UI that much more easily allows you to access and change any aspect of the database you want without using actual SQL commands. What I didn't realize is this plugin takes up the only writeable connection the SQLite and JDBC allow to the database.
So, after deleting the connection to the database through the DB Browser plugin, all of my functions are working properly.

AddToSet operation requires a target array field

Trying to make use of Azure DocumentDB/CosmsoDB using the MongoDB driver. I have learned that there are many limitations as the full set of features is not currently implemented. I want to use aggregate functions, specifically $group, and .distinct but I don't think that is available yet. As a work around, I am trying to maintain a separate "tracking" document to enable "distinct". trying to update a document using $addToSet, but getting the following:
MongoError: Message: {"Errors":["Encountered exception while executing function. Exception = Error: AddToSet operation requires a target array field.\r\nStack trace: Error: AddToSet operation requires a target array field.\n at arrayAddToSet (__.sys.commonUpdate.js:2907:25)\n at handleUpdate (__.sys.commonUpdate.js:2649:29)\n at processOneResult (__.sys.commonUpdate.js:2484:25)\n at queryCallback (__.sys.commonUpdate.js:2461:21)\n at Anonymous function (__.sys.commonUpdate.js:619:29)"]}
The update command i am using:
var usersDocument = collection.updateOne(
{ "type": "users" },
{ $addToSet: {users: "someone#gmail.com"} },
function(err, count, status) {
console.log("updateOne err: " + err)
console.log("updateOne count: " + count)
console.log("updateOne status: " + status)
}
)
This seems to me to be a pretty straight-forward command, pulled from the mongo documentation and fields adjusted as needed. Maybe I am missing something really basic?
My ultimate goal was to make sure that my code was portable as to be able to move it into a Mongo cluster, if I so desired (not be locked into Azure-specific). To get started and not have to manage a multi-server cluster, Azure CosmosDB looked like a great jumpstart, but the limitations are maddening.
UPDATE:
Now that I have fixed my document and I actually have a field with an array, $addToSet is just replacing the value, rather than adding to the array. I'll create a new question for that.
Yup, something basic. The error message was actually correct. After inspecting the existing document:
I found:
{ "users": "[]" }
And changed it to:
{ "users": [] }
Now it is working.

If one of the multiple adds in a saveChangesAsync fails do the others get added?

I have this function in my application. If the insert of Phrase fails then can someone tell me if the Audit entry still gets added? If that's the case then is there a way that I can package these into a single transaction that could be rolled back.
Also if it fails can I catch this and then still have the procedure exit with an exception?
[Route("Post")]
[ValidateModel]
public async Task<IHttpActionResult> Post([FromBody]Phrase phrase)
{
phrase.StatusId = (int)EStatus.Saved;
UpdateHepburn(phrase);
db.Phrases.Add(phrase);
var audit = new Audit()
{
Entity = (int)EEntity.Phrase,
Action = (int)EAudit.Insert,
Note = phrase.English,
UserId = userId,
Date = DateTime.UtcNow,
Id = phrase.PhraseId
};
db.Audits.Add(audit);
await db.SaveChangesAsync();
return Ok(phrase);
}
I have this function in my application. If the insert of Phrase fails
then can someone tell me if the Audit entry still gets added?
You have written your code in a correct way by calling await db.SaveChangesAsync(); only one time after doing all your modifications on the DbContext.
The answer to your question is: No, the Audit will not be added if Phrase fails.
Because you are calling await db.SaveChangesAsync(); after doing all your things with your entities, Entity Framework wil generate all the required SQL Queries and put them in a single SQL transaction which makes the whole queries as an atomic operation to your database. If one of the generated query e.g. Auditgenerated query failed then the transaction will be rolled back. So every modification that have been done to your database will be removed and so Entity Framework will let your database in a coherent state.

Resources