touch $(UPDATE_FLAG)\r
\r
native: $(UPDATE_FLAG)\r
+ mvn test\r
\r
NATIVE_DLL=$(WORK_DIR)/$(LIB_FOLDER)/$(LIBNAME)\r
\r
package: $(UPDATE_FLAG)\r
mkdir -p $(RESOURCE_DIR)/native/$(LIB_FOLDER)\r
cp $(NATIVE_DLL) $(RESOURCE_DIR)/native/$(LIB_FOLDER)\r
+ rm -rf target/dependency-maven-plugin-markers\r
mvn package\r
\r
clean-native:\r
<modelVersion>4.0.0</modelVersion>\r
<groupId>org.xerial</groupId>\r
<artifactId>sqlite-jdbc</artifactId>\r
- <version>3.6.13</version>\r
+ <version>3.6.13-SNAPSHOT</version>\r
<name>SQLite JDBC</name>\r
<description>SQLite JDBC library</description>\r
\r
<executions>\r
<execution>\r
<id>unpack-dependency</id>\r
- <phase>generate-sources</phase>\r
+ <phase>package</phase>\r
<goals>\r
<goal>unpack</goal>\r
</goals>\r
<type>jar</type>\r
</artifactItem>\r
</artifactItems>\r
+ <overWrite>true</overWrite>\r
<outputDirectory>target/classes</outputDirectory>\r
</configuration>\r
</execution>\r
package org.sqlite;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
db.enable_load_extension(enableLoadExtension);
}
+ private static final String RESOURCE_NAME_PREFIX = ":resource:";
+
public Conn(String url, String filename) throws SQLException
{
// check the path to the file exists
if (!":memory:".equals(filename))
{
- File file = new File(filename).getAbsoluteFile();
- File parent = file.getParentFile();
- if (parent != null && !parent.exists())
+ if (filename.startsWith(RESOURCE_NAME_PREFIX))
{
- for (File up = parent; up != null && !up.exists();)
+ String resourceName = filename.substring(RESOURCE_NAME_PREFIX.length());
+
+ ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
+ URL resourceAddr = contextCL.getResource(resourceName);
+ if (resourceAddr == null)
+ throw new SQLException(String.format("resource not found: %s", resourceName));
+
+ try
{
- parent = up;
- up = up.getParentFile();
+ filename = extractResource(resourceAddr).getAbsolutePath();
+ }
+ catch (IOException e)
+ {
+ throw new SQLException(String.format("failed to load %s: %s", resourceName, e));
}
- throw new SQLException("path to '" + filename + "': '" + parent + "' does not exist");
- }
-
- // check write access if file does not exist
- try
- {
- // The extra check to exists() is necessary as createNewFile()
- // does not follow the JavaDoc when used on read-only shares.
- if (!file.exists() && file.createNewFile())
- file.delete();
}
- catch (Exception e)
+ else
{
- throw new SQLException("opening db: '" + filename + "': " + e.getMessage());
+ File file = new File(filename).getAbsoluteFile();
+ File parent = file.getParentFile();
+ if (parent != null && !parent.exists())
+ {
+ for (File up = parent; up != null && !up.exists();)
+ {
+ parent = up;
+ up = up.getParentFile();
+ }
+ throw new SQLException("path to '" + filename + "': '" + parent + "' does not exist");
+ }
+
+ // check write access if file does not exist
+ try
+ {
+ // The extra check to exists() is necessary as createNewFile()
+ // does not follow the JavaDoc when used on read-only shares.
+ if (!file.exists() && file.createNewFile())
+ file.delete();
+ }
+ catch (Exception e)
+ {
+ throw new SQLException("opening db: '" + filename + "': " + e.getMessage());
+ }
+ filename = file.getAbsolutePath();
}
- filename = file.getAbsolutePath();
}
- // TODO: library variable to explicitly control load type
- // attempt to use the Native library first
+ // tries to load native library first
try
{
- Class nativedb = Class.forName("org.sqlite.NativeDB");
- if (((Boolean) nativedb.getDeclaredMethod("load", null).invoke(null, null)).booleanValue())
+ Class< ? > nativedb = Class.forName("org.sqlite.NativeDB");
+ if (((Boolean) nativedb.getDeclaredMethod("load", (Class< ? >[]) null).invoke((Object) null,
+ (Object[]) null)).booleanValue())
db = (DB) nativedb.newInstance();
+
}
catch (Exception e)
{} // fall through to nested library
setTimeout(3000);
}
+ /**
+ * @param resourceAddr
+ * @return extracted file name
+ * @throws IOException
+ */
+ private File extractResource(URL resourceAddr) throws IOException
+ {
+ if (resourceAddr.getProtocol().equals("file"))
+ {
+ try
+ {
+ return new File(resourceAddr.toURI());
+ }
+ catch (URISyntaxException e)
+ {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ String tempFolder = new File(System.getProperty("java.io.tmpdir")).getAbsolutePath();
+ String dbFileName = String.format("sqlite-jdbc-tmp-%d.db", resourceAddr.hashCode());
+ File dbFile = new File(tempFolder, dbFileName);
+
+ if (dbFile.exists())
+ {
+ long resourceLastModified = resourceAddr.openConnection().getLastModified();
+ long tmpFileLastModified = dbFile.lastModified();
+ if (resourceLastModified < tmpFileLastModified)
+ {
+ return dbFile;
+ }
+ else
+ {
+ // remove the old DB file
+ boolean deletionSucceeded = dbFile.delete();
+ if (!deletionSucceeded)
+ {
+ throw new IOException("failed to remove existing DB file: " + dbFile.getAbsolutePath());
+ }
+ }
+
+ // String md5sum1 = SQLiteJDBCLoader.md5sum(resourceAddr.openStream());
+ // String md5sum2 = SQLiteJDBCLoader.md5sum(new FileInputStream(dbFile));
+ //
+ // if (md5sum1.equals(md5sum2))
+ // return dbFile; // no need to extract the DB file
+ // else
+ // {
+ // }
+ }
+
+ byte[] buffer = new byte[8192]; // 8K buffer
+ FileOutputStream writer = new FileOutputStream(dbFile);
+ InputStream reader = resourceAddr.openStream();
+ try
+ {
+ int bytesRead = 0;
+ while ((bytesRead = reader.read(buffer)) != -1)
+ {
+ writer.write(buffer, 0, bytesRead);
+ }
+ return dbFile;
+ }
+ finally
+ {
+ writer.close();
+ reader.close();
+ }
+
+ }
+
int getTimeout()
{
return timeout;
sharedCache.description = "Enable SQLite Shared-Cache mode, native driver only.";
sharedCache.required = false;
- return new DriverPropertyInfo[] { sharedCache };
+ DriverPropertyInfo loadExt = new DriverPropertyInfo("enable_load_extension", "false");
+ loadExt.choices = new String[] { "true", "false" };
+ loadExt.description = "Enable SQLite load_extension() functionality";
+ loadExt.required = false;
+
+ return new DriverPropertyInfo[] { sharedCache, loadExt };
}
public Connection connect(String url, Properties info) throws SQLException
--- /dev/null
+/*--------------------------------------------------------------------------
+ * Copyright 2009 Taro L. Saito
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *--------------------------------------------------------------------------*/
+//--------------------------------------
+// sqlite-jdbc Project
+//
+// ResourceFinder.java
+// Since: Apr 28, 2009
+//
+// $URL$
+// $Author$
+//--------------------------------------
+package org.sqlite;
+
+import java.net.URL;
+
+/**
+ * Resource address finder for files inside the jar file
+ *
+ * @author leo
+ *
+ */
+public class ResourceFinder
+{
+ /**
+ * Gets the {@link URL} of the file resource
+ *
+ * @param referenceClass
+ * the base class for finding resources files. This method will
+ * search the package containing the given referenceClass.
+ * @param resourceFileName
+ * the resource file name relative to the package of the
+ * referenceClass
+ * @return the URL of the file resource
+ */
+ public static URL find(Class< ? > referenceClass, String resourceFileName)
+ {
+ return find(referenceClass.getClassLoader(), referenceClass.getPackage(), resourceFileName);
+ }
+
+ /**
+ * Finds the {@link URL} of the resource
+ *
+ * @param basePackage
+ * the base package to find the resource
+ * @param resourceFileName
+ * the resource file name relative to the package folder
+ * @return the URL of the specified resource
+ */
+ public static URL find(ClassLoader classLoader, Package basePackage, String resourceFileName)
+ {
+ return find(classLoader, basePackage.getName(), resourceFileName);
+ }
+
+ /**
+ * Finds the {@link URL} of the resource
+ *
+ * @param packageName
+ * the base package name to find the resource
+ * @param resourceFileName
+ * the resource file name relative to the package folder
+ * @return the URL of the specified resource
+ */
+ public static URL find(ClassLoader classLoader, String packageName, String resourceFileName)
+ {
+ String packagePath = packagePath(packageName);
+ String resourcePath = packagePath + resourceFileName;
+ if (!resourcePath.startsWith("/"))
+ resourcePath = "/" + resourcePath;
+
+ return classLoader.getResource(resourcePath);
+ }
+
+ private static String packagePath(Class< ? > referenceClass)
+ {
+ return packagePath(referenceClass.getPackage());
+ }
+
+ private static String packagePath(Package basePackage)
+ {
+ return packagePath(basePackage.getName());
+ }
+
+ private static String packagePath(String packageName)
+ {
+ String packageAsPath = packageName.replaceAll("\\.", "/");
+ return packageAsPath.endsWith("/") ? packageAsPath : packageAsPath + "/";
+ }
+
+}
* @throws IOException\r
* @throws NoSuchAlgorithmException\r
*/\r
- private static String md5sum(InputStream input) throws IOException, NoSuchAlgorithmException\r
+ static String md5sum(InputStream input) throws IOException\r
{\r
BufferedInputStream in = new BufferedInputStream(input);\r
\r
md5out.write(digest.digest());\r
return md5out.toString();\r
}\r
+ catch (NoSuchAlgorithmException e)\r
+ {\r
+ throw new IllegalStateException("MD5 algorithm is not available: " + e);\r
+ }\r
finally\r
{\r
in.close();\r
System.err.println(e.getMessage());\r
return false;\r
}\r
- catch (NoSuchAlgorithmException e)\r
- {\r
- System.err.println(e.getMessage());\r
- return false;\r
- }\r
\r
}\r
\r
import java.sql.PreparedStatement;\r
import java.sql.ResultSet;\r
import java.sql.SQLException;\r
+import java.sql.Statement;\r
\r
import org.junit.BeforeClass;\r
import org.junit.Test;\r
Connection conn = DriverManager.getConnection("jdbc:sqlite:/");\r
conn.close();\r
}\r
+\r
+ @Test\r
+ public void openResource() throws SQLException\r
+ {\r
+ Connection conn = DriverManager.getConnection("jdbc:sqlite::resource:org/sqlite/sample.db");\r
+ Statement stat = conn.createStatement();\r
+ ResultSet rs = stat.executeQuery("select * from coordinate");\r
+ assertTrue(rs.next());\r
+ rs.close();\r
+ stat.close();\r
+ conn.close();\r
+\r
+ }\r
}\r