I have a very unusual problem.
I'm trying to create a simple database (6 tables, 4 of which only have 2 columns).
I'm using an in-house database library which I've used in a previous project, and it does work.
However with my current project there are occasional bugs. Basically the database isn't created correctly. It is added to the sdcard but when I access it I get a DatabaseException.
When I access the device from the desktop manager and try to open the database (with SQLite Database Browser v2.0b1) I get "File is not a SQLite 3 database".
UPDATE
I found that this happens when I delete the database manually off the sdcard.
Since there's no way to stop a user doing that, is there anything I can do to handle it?
CODE
public static boolean initialize()
{
boolean memory_card_available = ApplicationInterface.isSDCardIn();
String application_name = ApplicationInterface.getApplicationName();
if (memory_card_available == true)
{
file_path = "file:///SDCard/" + application_name + ".db";
}
else
{
file_path = "file:///store/" + application_name + ".db";
}
try
{
uri = URI.create(file_path);
FileClass.hideFile(file_path);
} catch (MalformedURIException mue)
{
}
return create(uri);
}
private static boolean create(URI db_file)
{
boolean response = false;
try
{
db = DatabaseFactory.create(db_file);
db.close();
response = true;
} catch (Exception e)
{
}
return response;
}
My only suggestion is keep a default database in your assets - if there is a problem with the one on the SD Card, attempt to recreate it by copying the default one.
Not a very good answer I expect.
Since it looks like your problem is that the user is deleting your database, just make sure to catch exceptions when you open it (or access it ... wherever you're getting the exception):
try {
URI uri = URI.create("file:///SDCard/Databases/database1.db");
sqliteDB = DatabaseFactory.open(myURI);
Statement st = sqliteDB.createStatement( "CREATE TABLE 'Employee' ( " +
"'Name' TEXT, " +
"'Age' INTEGER )" );
st.prepare();
st.execute();
} catch ( DatabaseException e ) {
System.out.println( e.getMessage() );
// TODO: decide if you want to create a new database here, or
// alert the user if the SDCard is not available
}
Note that even though it's probably unusual for a user to delete a private file that your app creates, it's perfectly normal for the SDCard to be unavailable because the device is connected to a PC via USB. So, you really should always be testing for this condition (file open error).
See this answer regarding checking for SDCard availability.
Also, read this about SQLite db storage locations, and make sure to review this answer by Michael Donohue about eMMC storage.
Update: SQLite Corruption
See this link describing the many ways SQLite databases can be corrupted. It definitely sounded to me like maybe the .db file was deleted, but not the journal / wal file. If that was it, you could try deleting database1* programmatically before you create database1.db. But, your comments seem to suggest that it was something else. Perhaps you could look into the file locking failure modes, too.
If you are desperate, you might try changing your code to use a different name (e.g. database2, database3) each time you create a new db, to make sure you're not getting artifacts from the previous db.
Related
I am doing a project in wicket
How to solve the problem.
I came across such a message:
WicketMessage: Can't instantiate page using constructor public itucs.blg361.g03.HomePage()
Root cause:
java.lang.UnsupportedOperationException: [SQLITE_BUSY] The database file is locked (database is locked)
at itucs.blg361.g03.CategoryEvents.CategoryEventCollection.getCategoryEvents(CategoryEventCollection.java:41)
public List<CategoryEvent> getCategoryEvents() {
List<CategoryEvent> categoryEvents = new
LinkedList<CategoryEvent>();
try {
String query = "SELECT id, name, group_id"
+ " FROM event_category";
Statement statement = this.db.createStatement();
ResultSet result = statement.executeQuery(query);
while (result.next()) {
int id = result.getInt("id");
String name = result.getString("name");
int group_id = result.getInt("group_id");
categoryEvents.add(new CategoryEvent(id, name, group_id));
}
} catch (SQLException ex) {
throw new UnsupportedOperationException(ex.getMessage());
}
return categoryEvents;
}
at itucs.blg361.g03.HomePage.(HomePage.java:71)
categories = categoryCollection.getCategoryEvents();
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
Sqlite allows only one writer to the whole database at a time and, unless you selected "WAL" journal mode, no reader while writing. Moreover unless you explicitly ask it to wait, it simply returns the SQLITE_BUSY status for any attempt to access the database while conflicting operation is running.
You can tell sqlite to wait for the database to become available for a specified amount of time. The C-level API is sqlite3_busy_timeout; I never used sqlite from Java though, so I don't know where to find it there.
(...) tell sqlite to wait for the database to become available for specified amount of time.
In order to do it from Java, run the following statement just like a simple SQL statement:
pragma busy_timeout=30000; -- Busy timeout set to 30000 milliseconds
I am making an app that runs in the background, and starts on device boot.
I have read the docs, and have the SQLiteDemo files from RIM, and I am using them to try create a database on my SD Card in the simulator.
Unfortunately, I am getting this error:
DatabasePathException:Invalid path name. Path does not contains a proper root list. See FileSystemRegistry class for details.
Here's my code:
public static Database storeDB;
public static final String DATABASE_NAME = "testDB";
private String DATABASE_LOCATION = "file:///SDCard/Databases/MyDBFolder/";
public static URI dbURI;
dbURI = URI.create(DATABASE_LOCATION+DATABASE_NAME);
storeDB = DatabaseFactory.openOrCreate(dbURI);
I took out a try/catch for URI.create and DatabaseFactory.openOrCreate for the purposes of this post.
So, can anyone tell me why I can't create a database on my simulator?
If I load it up and go into media, I can create a folder manually. The SD card is pointing to a folder on my hard drive, and if I create a folder in there, it is shown on the simulator too, so I can create folders, just not programatically.
Also, I have tried this from the developer docs:
// Determine if an SDCard is present
boolean sdCardPresent = false;
String root = null;
Enumeration enum = FileSystemRegistry.listRoots();
while (enum.hasMoreElements())
{
root = (String)enum.nextElement();
System.err.println("root="+root);
if(root.equalsIgnoreCase("sdcard/"))
{
sdCardPresent = true;
}
}
But it only picks up store/ and never sdcard/.
Can anyone help?
Thanks.
FYI,
I think I resolved this.
The problem was I was trying to write to storage during boot-up, but the storage wasn't ready. Once the device/simulator was loaded, and a few of my listeners were triggered, the DB was created.
See here:
http://www.blackberry.com/knowledgecenterpublic/livelink.exe/fetch/2000/348583/800332/832062/How_To_-_Write_safe_initialization_code.html?nodeid=1487426&vernum=0
I am using SQLite for Windows Phone 7 (http://sqlitewindowsphone.codeplex.com/) and I have done every steps from this tutorial (http://dotnetslackers.com/articles/silverlight/Windows-Phone-7-Native-Database-Programming-via-Sqlite-Client-for-Windows-Phone.aspx)
Then I try to make some simple application with basic features like select and delete. App is working properly till I want to make one of this operations. After I click select or delete, compiler shows me errors that he is unable to open database file...
I have no idea why?
I used the same Sqlite client, and had the same problem. This problem occurs because the sqlite try to create file in IsolatedFileStorage "DatabaseName.sqlite-journal" and it does not have enough permissions for that. I solved the problem, so that created "DatabaseName.sqlite-journal" before copying database to IsolatedFileStorage. Here's my method that did it:
private void CopyFromContentToStorage(String assemblyName, String dbName)
{
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
string uri = dbName + "-journal";
store.CreateFile(uri);
using (Stream input = Application.GetResourceStream(new Uri("/" + assemblyName + ";component/" + dbName,UriKind.Relative)).Stream)
{
IsolatedStorageFileStream dest = new IsolatedStorageFileStream(dbName, FileMode.OpenOrCreate, FileAccess.Write, store);
input.Position = 0;
CopyStream(input, dest);
dest.Flush();
dest.Close();
dest.Dispose();
}
}
it helped me, and worked well.
hope this will help you
Are you sure the file exists?
You can check like that:
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
exists = store.FileExists(DbfileName);
}
... and not by reading it from the config file! Nor inferring it from anyplace other than be reading exactly what the Membership Provider is itself using. Call me paranoid.
The first data access in my application is an access to the membership provider. The vast majority of connectivity issues have been where the application is deployed to staging or production with a connection string from development, so I'd like to change this:
MembershipUser me = Membership.GetUser();
to this:
MembershipUser me;
try
{
me = Membership.GetUser();
}
catch ( SqlException E )
{
Response.Write( "SQL Error " + E.Message + ".<br />" );
Response.Write( "Connection String: " + Membership.Provider.WHAT? + "<br />" );
}
Seems so obvious, but every reference I find instructs me to use the ConfigurationManager, which is what I specifically don't want to do. Although I concede that such may be my only option, and a satisfactory one at that.
I'm perfectly willing to accept the possibility that my question is on par with this:
int i;
try
{
i = 42;
}
catch ( Exception e )
{
Response.Write( "Error assigning literal to integer." );
}
If this is the case, please comment accordingly.
I don't believe there is a direct property that you can use that will give you the connection information. One thing you could do though is subclass your chosen membership provider and implement your own properties to give you the info.
It's generally considered a bad idea to surface connection strings in the UI (i.e. poor security) which is why you won't find readily available properties to pass on the value from classes that have read it from the config file.
You may want to consider addressing the root cause of the problem which is related to deployment. This problem is easily solved by using different configuration files for development, staging and production. Visual Studio has built-in support for automatically managing the deployment of the appropriate config file. Full details here:
http://blogs.msdn.com/b/webdevtools/archive/2009/05/04/web-deployment-web-config-transformation.aspx
Hi Here is a way to get connection string from or by the specified Provider Name (ex MySQL provider).
using MySql.Data.MySqlClient;
using MySql.Data;
using MySql.Web.Security;
using System.Collections.Specialized;
using System.Reflection;
void SomeFunction()
{
Type t = Membership.Provider.GetType();
FieldInfo fi = null;
while (fi == null && t != null)
{
fi = t.GetField("connectionString", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
t = t.BaseType;
}
MySql.Web.Security.MySQLMembershipProvider a =(MySql.Web.Security.MySQLMembershipProvider)Membership.Provider;
string Connection_String_Value= fi.GetValue(a).ToString();
}
By replace 'connectionString' with other Non-Public field name You
can Access its Value too.
By replacing Provider(default) with
Membership.Providers["Name_Of_Your_Provider"] you can get its
connection string too.
I have a lot of XSL files in my ASP.NET web app. A lot. I generate a bunch of AJAX HTML responses using this kind of generic transform method:
public void Transform(XmlDocument xml, string xslPath)
{
...
XslTransform myXslTrans = new XslTransform();
myXslTrans.Load(xslPath);
myXslTrans.Transform(xml,null, HttpContext.Current.Response.Output);
}
I'd like to move the XSL definitions into SQL Server, using a column of type xml.
I would store an entire XSL file in a single row in SQL, and each XSL is self-contained (no imports). I would read out the XSL definition from SQL into my XslTransform object.
Something like this:
public void Transform(XmlDocument xml, string xslKey)
{
...
SqlCommand cmd = new SqlCommand("GetXslDefinition");
cmd.AddParameter("#xslKey", SqlDbType.VarChar).Value = xslKey;
// where the result set has a single column of XSL: "<xslt:stylesheet>..."
...
SqlDataReader dr = cmd.ExecuteReader();
if(dr.Read()) {
SqlXml xsl = dr.GetSqlXml(0);
XslTransform myXslTrans = new XslTransform();
myXslTrans.Load(xsl.CreateReader());
myXslTrans.Transform(xml,null, HttpContext.Current.Response.Output);
}
}
It seems like a straightforward way to:
add metadata to each XSL, like lastUsed, useCount, etc.
bulk update/search capabilities
prevent lots of disk access
avoid referencing relative paths and organizing files
allow XSL changes without redeploying (I could even write an admin page that selects/updates the XSL in the database)
Has anyone tried this before? Are there any caveats?
EDIT
Caveats that responders have listed:
disk access isn't guaranteed to diminish
this will break xsl:includes
The two big issues I can see are:
We use a lot of includes to ensure that we only do things once, storing the XSLT in the database would stop us from doing that.
It makes updating XSLs more interesting - we've been quite happy to dump new .xsl files into deployed sites without doing a full update of the site. For that matter we've got bits of code that look for client specific xsl in a folder and those bits of code can reach back up to common code (templates) in the root - so I'm not sure about the redeploy thing at all, but this will depend very much on the particular use case, yours is certainly different to ours.
In terms of disk access, hmm... the db still has to go access the disk to pull the data and if you're talking about caching then the db isn't a requirement for enabling caching.
Have to agree about the update/search options - you can do stuff with Powershell but that needs to be run on the server and that's not always a good idea.
Technically I can see no reason why not (excepting the wish to do includes as above) but practically it seems to be fairly balanced with good arguments either way.
I store XSLTs in a database in my application dbscript. (However I keep them in an NVARCHAR column, since it also runs on SQL Server 2000)
Since users are able to edit their XSLTs, I needed to write a custom validator which loads the text of TextBox in a .Net XslCompiledTransform object like this:
args.IsValid = true;
if (args.Value.Trim() == "")
return;
try
{
System.IO.TextReader rd = new System.IO.StringReader(args.Value);
System.Xml.XmlReader xrd = System.Xml.XmlReader.Create(rd);
System.Xml.Xsl.XslCompiledTransform xslt = new System.Xml.Xsl.XslCompiledTransform();
System.Xml.Xsl.XsltSettings xslts = new System.Xml.Xsl.XsltSettings(false, false);
xslt.Load(xrd, xslts, new System.Xml.XmlUrlResolver());
xrd.Close();
}
catch (Exception ex)
{
this.ErrorMessage = (string.IsNullOrEmpty(sErrorMessage) ? "" : (sErrorMessage + "<br/>") +
ex.Message);
if (ex.InnerException != null)
{
ex = ex.InnerException;
this.ErrorMessage += "<br />" + ex.Message;
}
args.IsValid = false;
}
As for your points:
file I/O will be replaced by database-generated disk I/O, so no gains there
deployment changes to providing an INSERT/UPDATE script containing the new data