增加晶全app静态页面

This commit is contained in:
微微一笑
2025-07-05 14:49:26 +08:00
parent 194035cf79
commit aede64dacd
2323 changed files with 524101 additions and 0 deletions

View File

@ -0,0 +1,600 @@
/*
* Copyright (c) 2012-present Christopher J. Brody (aka Chris Brody)
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
*/
package io.sqlc;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.sqlite.SQLiteConstraintException;
// no longer needed - for pre-Honeycomb NO LONGER SUPPORTED:
// import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;
import java.io.File;
import java.lang.IllegalArgumentException;
import java.lang.Number;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.cordova.CallbackContext;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Android Database helper class
*/
class SQLiteAndroidDatabase
{
private static final Pattern FIRST_WORD = Pattern.compile("^[\\s;]*([^\\s;]+)",
Pattern.CASE_INSENSITIVE);
private static final Pattern WHERE_CLAUSE = Pattern.compile("\\s+WHERE\\s+(.+)$",
Pattern.CASE_INSENSITIVE);
private static final Pattern UPDATE_TABLE_NAME = Pattern.compile("^\\s*UPDATE\\s+(\\S+)",
Pattern.CASE_INSENSITIVE);
private static final Pattern DELETE_TABLE_NAME = Pattern.compile("^\\s*DELETE\\s+FROM\\s+(\\S+)",
Pattern.CASE_INSENSITIVE);
private static final boolean isPostHoneycomb = android.os.Build.VERSION.SDK_INT >= 11;
File dbFile;
SQLiteDatabase mydb;
boolean isTransactionActive = false;
/**
* NOTE: Using default constructor, no explicit constructor.
*/
/**
* Open a database.
*
* @param dbfile The database File specification
*/
void open(File dbfile) throws Exception {
if (!isPostHoneycomb) {
Log.v("SQLiteAndroidDatabase.open",
"INTERNAL PLUGIN ERROR: deprecated android.os.Build.VERSION not supported: " +
android.os.Build.VERSION.SDK_INT);
throw new RuntimeException(
"INTERNAL PLUGIN ERROR: deprecated android.os.Build.VERSION not supported: " +
android.os.Build.VERSION.SDK_INT);
}
dbFile = dbfile; // for possible bug workaround
mydb = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
}
/**
* Close a database (in the current thread).
*/
void closeDatabaseNow() {
if (mydb != null) {
if (isTransactionActive) {
try {
mydb.endTransaction();
} catch (Exception ex) {
Log.v("closeDatabaseNow", "INTERNAL PLUGIN ERROR IGNORED: Not able to end active transaction before closing database: " + ex.getMessage());
ex.printStackTrace();
}
isTransactionActive = false;
}
mydb.close();
mydb = null;
}
}
void bugWorkaround() throws Exception {
this.closeDatabaseNow();
this.open(dbFile);
}
/**
* Executes a batch request and sends the results via cbc.
*
* @param queryarr Array of query strings
* @param jsonparamsArr Array of JSON query parameters
* @param cbc Callback context from Cordova API
*/
void executeSqlBatch(String[] queryarr, JSONArray[] jsonparamsArr, CallbackContext cbc) {
if (mydb == null) {
// not allowed - can only happen if someone has closed (and possibly deleted) a database and then re-used the database
// (internal plugin error)
cbc.error("INTERNAL PLUGIN ERROR: database not open");
return;
}
int len = queryarr.length;
JSONArray batchResults = new JSONArray();
for (int i = 0; i < len; i++) {
executeSqlBatchStatement(queryarr[i], jsonparamsArr[i], batchResults);
}
cbc.success(batchResults);
}
private void executeSqlBatchStatement(String query, JSONArray json_params, JSONArray batchResults) {
if (mydb == null) {
// Should not happen here
return;
} else {
int rowsAffectedCompat = 0;
boolean needRowsAffectedCompat = false;
JSONObject queryResult = null;
String errorMessage = "unknown";
int code = 0; // SQLException.UNKNOWN_ERR
try {
boolean needRawQuery = true;
//Log.v("executeSqlBatch", "get query type");
QueryType queryType = getQueryType(query);
//Log.v("executeSqlBatch", "query type: " + queryType);
if (queryType == QueryType.update || queryType == queryType.delete) {
// if (isPostHoneycomb) {
SQLiteStatement myStatement = mydb.compileStatement(query);
if (json_params != null) {
bindArgsToStatement(myStatement, json_params);
}
int rowsAffected = -1; // (assuming invalid)
// Use try & catch just in case android.os.Build.VERSION.SDK_INT >= 11 is lying:
// (Catch SQLiteException here to avoid extra retry)
try {
rowsAffected = myStatement.executeUpdateDelete();
// Indicate valid results:
needRawQuery = false;
} catch (SQLiteConstraintException ex) {
// Indicate problem & stop this query:
ex.printStackTrace();
errorMessage = "constraint failure: " + ex.getMessage();
code = 6; // SQLException.CONSTRAINT_ERR
Log.v("executeSqlBatch", "SQLiteStatement.executeUpdateDelete(): Error=" + errorMessage);
needRawQuery = false;
} catch (SQLiteException ex) {
// Indicate problem & stop this query:
ex.printStackTrace();
errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLiteStatement.executeUpdateDelete(): Error=" + errorMessage);
needRawQuery = false;
} catch (Exception ex) {
// Assuming SDK_INT was lying & method not found:
// do nothing here & try again with raw query.
ex.printStackTrace();
// Log.v("executeSqlBatch", "SQLiteStatement.executeUpdateDelete(): runtime error (fallback to old API): " + errorMessage);
Log.v("SQLiteAndroidDatabase.executeSqlBatchStatement",
"INTERNAL PLUGIN ERROR: could not do myStatement.executeUpdateDelete(): " + ex.getMessage());
throw(ex);
}
// "finally" cleanup myStatement
myStatement.close();
if (rowsAffected != -1) {
queryResult = new JSONObject();
queryResult.put("rowsAffected", rowsAffected);
}
// }
if (needRawQuery) { // for pre-honeycomb behavior
rowsAffectedCompat = countRowsAffectedCompat(queryType, query, json_params, mydb);
needRowsAffectedCompat = true;
}
}
// INSERT:
if (queryType == QueryType.insert && json_params != null) {
needRawQuery = false;
SQLiteStatement myStatement = mydb.compileStatement(query);
bindArgsToStatement(myStatement, json_params);
long insertId = -1; // (invalid)
try {
insertId = myStatement.executeInsert();
// statement has finished with no constraint violation:
queryResult = new JSONObject();
if (insertId != -1) {
queryResult.put("insertId", insertId);
queryResult.put("rowsAffected", 1);
} else {
queryResult.put("rowsAffected", 0);
}
} catch (SQLiteConstraintException ex) {
// report constraint violation error result with the error message
ex.printStackTrace();
errorMessage = "constraint failure: " + ex.getMessage();
code = 6; // SQLException.CONSTRAINT_ERR
Log.v("executeSqlBatch", "SQLiteDatabase.executeInsert(): Error=" + errorMessage);
} catch (SQLiteException ex) {
// report some other error result with the error message
ex.printStackTrace();
errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLiteDatabase.executeInsert(): Error=" + errorMessage);
}
// "finally" cleanup myStatement
myStatement.close();
}
if (queryType == QueryType.begin) {
needRawQuery = false;
try {
mydb.beginTransaction();
isTransactionActive = true;
queryResult = new JSONObject();
queryResult.put("rowsAffected", 0);
} catch (SQLiteException ex) {
ex.printStackTrace();
errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLiteDatabase.beginTransaction(): Error=" + errorMessage);
}
}
if (queryType == QueryType.commit) {
needRawQuery = false;
try {
mydb.setTransactionSuccessful();
mydb.endTransaction();
isTransactionActive = false;
queryResult = new JSONObject();
queryResult.put("rowsAffected", 0);
} catch (SQLiteException ex) {
ex.printStackTrace();
errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLiteDatabase.setTransactionSuccessful/endTransaction(): Error=" + errorMessage);
}
}
if (queryType == QueryType.rollback) {
needRawQuery = false;
try {
mydb.endTransaction();
isTransactionActive = false;
queryResult = new JSONObject();
queryResult.put("rowsAffected", 0);
} catch (SQLiteException ex) {
ex.printStackTrace();
errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLiteDatabase.endTransaction(): Error=" + errorMessage);
}
}
// raw query for other statements:
if (needRawQuery) {
try {
queryResult = this.executeSqlStatementQuery(mydb, query, json_params);
} catch (SQLiteConstraintException ex) {
// report constraint violation error result with the error message
ex.printStackTrace();
errorMessage = "constraint failure: " + ex.getMessage();
code = 6; // SQLException.CONSTRAINT_ERR
Log.v("executeSqlBatch", "Raw query error=" + errorMessage);
} catch (SQLiteException ex) {
// report some other error result with the error message
ex.printStackTrace();
errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "Raw query error=" + errorMessage);
}
if (needRowsAffectedCompat) {
queryResult.put("rowsAffected", rowsAffectedCompat);
}
}
} catch (Exception ex) {
ex.printStackTrace();
errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLiteAndroidDatabase.executeSql[Batch](): Error=" + errorMessage);
}
try {
if (queryResult != null) {
JSONObject r = new JSONObject();
r.put("type", "success");
r.put("result", queryResult);
batchResults.put(r);
} else {
JSONObject r = new JSONObject();
r.put("type", "error");
JSONObject er = new JSONObject();
er.put("message", errorMessage);
er.put("code", code);
r.put("result", er);
batchResults.put(r);
}
} catch (JSONException ex) {
ex.printStackTrace();
Log.v("executeSqlBatch", "SQLiteAndroidDatabase.executeSql[Batch](): Error=" + ex.getMessage());
// TODO what to do?
}
}
}
private final int countRowsAffectedCompat(QueryType queryType, String query, JSONArray json_params,
SQLiteDatabase mydb) throws JSONException {
// quick and dirty way to calculate the rowsAffected in pre-Honeycomb. just do a SELECT
// beforehand using the same WHERE clause. might not be perfect, but it's better than nothing
Matcher whereMatcher = WHERE_CLAUSE.matcher(query);
String where = "";
int pos = 0;
while (whereMatcher.find(pos)) {
where = " WHERE " + whereMatcher.group(1);
pos = whereMatcher.start(1);
}
// WHERE clause may be omitted, and also be sure to find the last one,
// e.g. for cases where there's a subquery
// bindings may be in the update clause, so only take the last n
int numQuestionMarks = 0;
for (int j = 0; j < where.length(); j++) {
if (where.charAt(j) == '?') {
numQuestionMarks++;
}
}
JSONArray subParams = null;
if (json_params != null) {
// only take the last n of every array of sqlArgs
JSONArray origArray = json_params;
subParams = new JSONArray();
int startPos = origArray.length() - numQuestionMarks;
for (int j = startPos; j < origArray.length(); j++) {
subParams.put(j - startPos, origArray.get(j));
}
}
if (queryType == QueryType.update) {
Matcher tableMatcher = UPDATE_TABLE_NAME.matcher(query);
if (tableMatcher.find()) {
String table = tableMatcher.group(1);
try {
SQLiteStatement statement = mydb.compileStatement(
"SELECT count(*) FROM " + table + where);
if (subParams != null) {
bindArgsToStatement(statement, subParams);
}
return (int)statement.simpleQueryForLong();
} catch (Exception e) {
// assume we couldn't count for whatever reason, keep going
Log.e(SQLiteAndroidDatabase.class.getSimpleName(), "uncaught", e);
}
}
} else { // delete
Matcher tableMatcher = DELETE_TABLE_NAME.matcher(query);
if (tableMatcher.find()) {
String table = tableMatcher.group(1);
try {
SQLiteStatement statement = mydb.compileStatement(
"SELECT count(*) FROM " + table + where);
bindArgsToStatement(statement, subParams);
return (int)statement.simpleQueryForLong();
} catch (Exception e) {
// assume we couldn't count for whatever reason, keep going
Log.e(SQLiteAndroidDatabase.class.getSimpleName(), "uncaught", e);
}
}
}
return 0;
}
private void bindArgsToStatement(SQLiteStatement myStatement, JSONArray sqlArgs) throws JSONException {
for (int i = 0; i < sqlArgs.length(); i++) {
if (sqlArgs.get(i) instanceof Float || sqlArgs.get(i) instanceof Double) {
myStatement.bindDouble(i + 1, sqlArgs.getDouble(i));
} else if (sqlArgs.get(i) instanceof Number) {
myStatement.bindLong(i + 1, sqlArgs.getLong(i));
} else if (sqlArgs.isNull(i)) {
myStatement.bindNull(i + 1);
} else {
myStatement.bindString(i + 1, sqlArgs.getString(i));
}
}
}
/**
* Get rows results from query cursor.
*
* @param cur Cursor into query results
* @return results in string form
*/
private JSONObject executeSqlStatementQuery(SQLiteDatabase mydb, String query,
JSONArray paramsAsJson) throws Exception {
JSONObject rowsResult = new JSONObject();
Cursor cur = null;
try {
String[] params = null;
params = new String[paramsAsJson.length()];
for (int j = 0; j < paramsAsJson.length(); j++) {
if (paramsAsJson.isNull(j))
params[j] = "";
else
params[j] = paramsAsJson.getString(j);
}
cur = mydb.rawQuery(query, params);
} catch (Exception ex) {
ex.printStackTrace();
String errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLiteAndroidDatabase.executeSql[Batch](): Error=" + errorMessage);
throw ex;
}
// If query result has rows
if (cur != null && cur.moveToFirst()) {
JSONArray rowsArrayResult = new JSONArray();
String key = "";
int colCount = cur.getColumnCount();
// Build up JSON result object for each row
do {
JSONObject row = new JSONObject();
try {
for (int i = 0; i < colCount; ++i) {
key = cur.getColumnName(i);
if (isPostHoneycomb) {
// Use try & catch just in case android.os.Build.VERSION.SDK_INT >= 11 is lying:
try {
bindPostHoneycomb(row, key, cur, i);
} catch (Exception ex) {
// bindPreHoneycomb(row, key, cur, i);
Log.v("SQLiteAndroidDatabase.executeSqlStatementQuery",
"INTERNAL PLUGIN ERROR: could not bindPostHoneycomb: " + ex.getMessage());
throw(ex);
}
} else {
// NOT EXPECTED:
// bindPreHoneycomb(row, key, cur, i);
Log.v("SQLiteAndroidDatabase.executeSqlStatementQuery",
"INTERNAL PLUGIN ERROR: deprecated android.os.Build.VERSION not supported: " + android.os.Build.VERSION.SDK_INT);
throw new RuntimeException(
"INTERNAL PLUGIN ERROR: deprecated android.os.Build.VERSION not supported: " +
android.os.Build.VERSION.SDK_INT);
}
}
rowsArrayResult.put(row);
} catch (JSONException e) {
e.printStackTrace();
}
} while (cur.moveToNext());
try {
rowsResult.put("rows", rowsArrayResult);
} catch (JSONException e) {
e.printStackTrace();
}
}
if (cur != null) {
cur.close();
}
return rowsResult;
}
private void bindPostHoneycomb(JSONObject row, String key, Cursor cur, int i) throws JSONException {
int curType = cur.getType(i);
switch (curType) {
case Cursor.FIELD_TYPE_NULL:
row.put(key, JSONObject.NULL);
break;
case Cursor.FIELD_TYPE_INTEGER:
row.put(key, cur.getLong(i));
break;
case Cursor.FIELD_TYPE_FLOAT:
row.put(key, cur.getDouble(i));
break;
case Cursor.FIELD_TYPE_STRING:
default: /* (BLOB) */
row.put(key, cur.getString(i));
break;
}
}
/* ** NO LONGER SUPPORTED:
private void bindPreHoneycomb(JSONObject row, String key, Cursor cursor, int i) throws JSONException {
// Since cursor.getType() is not available pre-honeycomb, this is
// a workaround so we don't have to bind everything as a string
// Details here: http://stackoverflow.com/q/11658239
SQLiteCursor sqLiteCursor = (SQLiteCursor) cursor;
CursorWindow cursorWindow = sqLiteCursor.getWindow();
int pos = cursor.getPosition();
if (cursorWindow.isNull(pos, i)) {
row.put(key, JSONObject.NULL);
} else if (cursorWindow.isLong(pos, i)) {
row.put(key, cursor.getLong(i));
} else if (cursorWindow.isFloat(pos, i)) {
row.put(key, cursor.getDouble(i));
} else {
// STRING or BLOB:
row.put(key, cursor.getString(i));
}
}
// */
static QueryType getQueryType(String query) {
Matcher matcher = FIRST_WORD.matcher(query);
// FIND & return query type, or throw:
if (matcher.find()) {
try {
String first = matcher.group(1);
// explictly reject if blank
// (needed for SQLCipher version)
if (first.length() == 0) throw new RuntimeException("query not found");
return QueryType.valueOf(first.toLowerCase(Locale.ENGLISH));
} catch (IllegalArgumentException ignore) {
// unknown verb (NOT blank)
return QueryType.other;
}
} else {
// explictly reject if blank
// (needed for SQLCipher version)
throw new RuntimeException("query not found");
}
}
static enum QueryType {
update,
insert,
delete,
select,
begin,
commit,
rollback,
other
}
} /* vim: set expandtab : */

View File

@ -0,0 +1,280 @@
/*
* Copyright (c) 2012-present Christopher J. Brody (aka Chris Brody)
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
*/
package io.sqlc;
import android.util.Log;
import java.io.File;
import java.lang.Number;
import java.sql.SQLException;
import org.apache.cordova.CallbackContext;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import io.liteglue.SQLCode;
import io.liteglue.SQLColumnType;
import io.liteglue.SQLiteConnector;
import io.liteglue.SQLiteConnection;
import io.liteglue.SQLiteOpenFlags;
import io.liteglue.SQLiteStatement;
/**
* Android SQLite-Connector Database helper class
*/
class SQLiteConnectorDatabase extends SQLiteAndroidDatabase
{
static SQLiteConnector connector = new SQLiteConnector();
SQLiteConnection mydb;
/**
* NOTE: Using default constructor, no explicit constructor.
*/
/**
* Open a database.
*
* @param dbFile The database File specification
*/
@Override
void open(File dbFile) throws Exception {
mydb = connector.newSQLiteConnection(dbFile.getAbsolutePath(),
SQLiteOpenFlags.READWRITE | SQLiteOpenFlags.CREATE);
}
/**
* Close a database (in the current thread).
*/
@Override
void closeDatabaseNow() {
try {
if (mydb != null)
mydb.dispose();
} catch (Exception e) {
Log.e(SQLitePlugin.class.getSimpleName(), "couldn't close database, ignoring", e);
}
}
/**
* Ignore Android bug workaround for NDK version
*/
@Override
void bugWorkaround() { }
/**
* Executes a batch request and sends the results via cbc.
*
* @param dbname The name of the database.
* @param queryarr Array of query strings
* @param jsonparams Array of JSON query parameters
* @param cbc Callback context from Cordova API
*/
@Override
void executeSqlBatch( String[] queryarr, JSONArray[] jsonparams, CallbackContext cbc) {
if (mydb == null) {
// not allowed - can only happen if someone has closed (and possibly deleted) a database and then re-used the database
cbc.error("database has been closed");
return;
}
int len = queryarr.length;
JSONArray batchResults = new JSONArray();
for (int i = 0; i < len; i++) {
int rowsAffectedCompat = 0;
boolean needRowsAffectedCompat = false;
JSONObject queryResult = null;
String errorMessage = "unknown";
int sqliteErrorCode = -1;
int code = 0; // SQLException.UNKNOWN_ERR
try {
String query = queryarr[i];
long lastTotal = mydb.getTotalChanges();
queryResult = this.executeSQLiteStatement(query, jsonparams[i], cbc);
long newTotal = mydb.getTotalChanges();
long rowsAffected = newTotal - lastTotal;
queryResult.put("rowsAffected", rowsAffected);
if (rowsAffected > 0) {
long insertId = mydb.getLastInsertRowid();
if (insertId > 0) {
queryResult.put("insertId", insertId);
}
}
} catch (SQLException ex) {
ex.printStackTrace();
sqliteErrorCode = ex.getErrorCode();
errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLitePlugin.executeSql[Batch](): SQL Error code = " + sqliteErrorCode + " message = " + errorMessage);
switch(sqliteErrorCode) {
case SQLCode.ERROR:
code = 5; // SQLException.SYNTAX_ERR
break;
case 13: // SQLITE_FULL
code = 4; // SQLException.QUOTA_ERR
break;
case SQLCode.CONSTRAINT:
code = 6; // SQLException.CONSTRAINT_ERR
break;
default:
/* do nothing */
}
} catch (JSONException ex) {
// NOT expected:
ex.printStackTrace();
errorMessage = ex.getMessage();
code = 0; // SQLException.UNKNOWN_ERR
Log.e("executeSqlBatch", "SQLitePlugin.executeSql[Batch](): UNEXPECTED JSON Error=" + errorMessage);
}
try {
if (queryResult != null) {
JSONObject r = new JSONObject();
r.put("type", "success");
r.put("result", queryResult);
batchResults.put(r);
} else {
JSONObject r = new JSONObject();
r.put("type", "error");
JSONObject er = new JSONObject();
er.put("message", errorMessage);
er.put("code", code);
r.put("result", er);
batchResults.put(r);
}
} catch (JSONException ex) {
ex.printStackTrace();
Log.e("executeSqlBatch", "SQLitePlugin.executeSql[Batch](): Error=" + ex.getMessage());
// TODO what to do?
}
}
cbc.success(batchResults);
}
/**
* Get rows results from query cursor.
*
* @param cur Cursor into query results
* @return results in string form
*/
private JSONObject executeSQLiteStatement(String query, JSONArray paramsAsJson,
CallbackContext cbc) throws JSONException, SQLException {
JSONObject rowsResult = new JSONObject();
boolean hasRows = false;
SQLiteStatement myStatement = mydb.prepareStatement(query);
try {
String[] params = null;
params = new String[paramsAsJson.length()];
for (int i = 0; i < paramsAsJson.length(); ++i) {
if (paramsAsJson.isNull(i)) {
myStatement.bindNull(i + 1);
} else {
Object p = paramsAsJson.get(i);
if (p instanceof Float || p instanceof Double)
myStatement.bindDouble(i + 1, paramsAsJson.getDouble(i));
else if (p instanceof Number)
myStatement.bindLong(i + 1, paramsAsJson.getLong(i));
else
myStatement.bindTextNativeString(i + 1, paramsAsJson.getString(i));
}
}
hasRows = myStatement.step();
} catch (SQLException ex) {
ex.printStackTrace();
String errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLitePlugin.executeSql[Batch](): Error=" + errorMessage);
// cleanup statement and throw the exception:
myStatement.dispose();
throw ex;
} catch (JSONException ex) {
ex.printStackTrace();
String errorMessage = ex.getMessage();
Log.v("executeSqlBatch", "SQLitePlugin.executeSql[Batch](): Error=" + errorMessage);
// cleanup statement and throw the exception:
myStatement.dispose();
throw ex;
}
// If query result has rows
if (hasRows) {
JSONArray rowsArrayResult = new JSONArray();
String key = "";
int colCount = myStatement.getColumnCount();
// Build up JSON result object for each row
do {
JSONObject row = new JSONObject();
try {
for (int i = 0; i < colCount; ++i) {
key = myStatement.getColumnName(i);
switch (myStatement.getColumnType(i)) {
case SQLColumnType.NULL:
row.put(key, JSONObject.NULL);
break;
case SQLColumnType.REAL:
row.put(key, myStatement.getColumnDouble(i));
break;
case SQLColumnType.INTEGER:
row.put(key, myStatement.getColumnLong(i));
break;
case SQLColumnType.BLOB:
case SQLColumnType.TEXT:
default: // (just in case)
row.put(key, myStatement.getColumnTextNativeString(i));
}
}
rowsArrayResult.put(row);
} catch (JSONException e) {
e.printStackTrace();
}
} while (myStatement.step());
try {
rowsResult.put("rows", rowsArrayResult);
} catch (JSONException e) {
e.printStackTrace();
}
}
myStatement.dispose();
return rowsResult;
}
} /* vim: set expandtab : */

View File

@ -0,0 +1,431 @@
/*
* Copyright (c) 2012-present Christopher J. Brody (aka Chris Brody)
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010, IBM Corporation
*/
package io.sqlc;
import android.util.Log;
import java.io.File;
import java.lang.IllegalArgumentException;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class SQLitePlugin extends CordovaPlugin {
/**
* Concurrent database runner map.
*
* NOTE: no public static accessor to db (runner) map since it is not
* expected to work properly with db threading.
*
* FUTURE TBD put DBRunner into a public class that can provide external accessor.
*
* ADDITIONAL NOTE: Storing as Map<String, DBRunner> to avoid portabiity issue
* between Java 6/7/8 as discussed in:
* https://gist.github.com/AlainODea/1375759b8720a3f9f094
*
* THANKS to @NeoLSN (Jason Yang/楊朝傑) for giving the pointer in:
* https://github.com/litehelpers/Cordova-sqlite-storage/issues/727
*/
private Map<String, DBRunner> dbrmap = new ConcurrentHashMap<String, DBRunner>();
/**
* NOTE: Using default constructor, no explicit constructor.
*/
/**
* Executes the request and returns PluginResult.
*
* @param actionAsString The action to execute.
* @param args JSONArry of arguments for the plugin.
* @param cbc Callback context from Cordova API
* @return Whether the action was valid.
*/
@Override
public boolean execute(String actionAsString, JSONArray args, CallbackContext cbc) {
Action action;
try {
action = Action.valueOf(actionAsString);
} catch (IllegalArgumentException e) {
// shouldn't ever happen
Log.e(SQLitePlugin.class.getSimpleName(), "unexpected error", e);
return false;
}
try {
return executeAndPossiblyThrow(action, args, cbc);
} catch (JSONException e) {
// TODO: signal JSON problem to JS
Log.e(SQLitePlugin.class.getSimpleName(), "unexpected error", e);
return false;
}
}
private boolean executeAndPossiblyThrow(Action action, JSONArray args, CallbackContext cbc)
throws JSONException {
boolean status = true;
JSONObject o;
String echo_value;
String dbname;
switch (action) {
case echoStringValue:
o = args.getJSONObject(0);
echo_value = o.getString("value");
cbc.success(echo_value);
break;
case open:
o = args.getJSONObject(0);
dbname = o.getString("name");
// open database and start reading its queue
this.startDatabase(dbname, o, cbc);
break;
case close:
o = args.getJSONObject(0);
dbname = o.getString("path");
// put request in the q to close the db
this.closeDatabase(dbname, cbc);
break;
case delete:
o = args.getJSONObject(0);
dbname = o.getString("path");
deleteDatabase(dbname, cbc);
break;
case executeSqlBatch:
case backgroundExecuteSqlBatch:
JSONObject allargs = args.getJSONObject(0);
JSONObject dbargs = allargs.getJSONObject("dbargs");
dbname = dbargs.getString("dbname");
JSONArray txargs = allargs.getJSONArray("executes");
if (txargs.isNull(0)) {
cbc.error("INTERNAL PLUGIN ERROR: missing executes list");
} else {
int len = txargs.length();
String[] queries = new String[len];
JSONArray[] jsonparams = new JSONArray[len];
for (int i = 0; i < len; i++) {
JSONObject a = txargs.getJSONObject(i);
queries[i] = a.getString("sql");
jsonparams[i] = a.getJSONArray("params");
}
// put db query in the queue to be executed in the db thread:
DBQuery q = new DBQuery(queries, jsonparams, cbc);
DBRunner r = dbrmap.get(dbname);
if (r != null) {
try {
r.q.put(q);
} catch(Exception e) {
Log.e(SQLitePlugin.class.getSimpleName(), "couldn't add to queue", e);
cbc.error("INTERNAL PLUGIN ERROR: couldn't add to queue");
}
} else {
cbc.error("INTERNAL PLUGIN ERROR: database not open");
}
}
break;
}
return status;
}
/**
* Clean up and close all open databases.
*/
@Override
public void onDestroy() {
while (!dbrmap.isEmpty()) {
String dbname = dbrmap.keySet().iterator().next();
this.closeDatabaseNow(dbname);
DBRunner r = dbrmap.get(dbname);
try {
// stop the db runner thread:
r.q.put(new DBQuery());
} catch(Exception e) {
Log.e(SQLitePlugin.class.getSimpleName(), "INTERNAL PLUGIN CLEANUP ERROR: could not stop db thread due to exception", e);
}
dbrmap.remove(dbname);
}
}
// --------------------------------------------------------------------------
// LOCAL METHODS
// --------------------------------------------------------------------------
private void startDatabase(String dbname, JSONObject options, CallbackContext cbc) {
DBRunner r = dbrmap.get(dbname);
if (r != null) {
// NO LONGER EXPECTED due to BUG 666 workaround solution:
cbc.error("INTERNAL ERROR: database already open for db name: " + dbname);
} else {
r = new DBRunner(dbname, options, cbc);
dbrmap.put(dbname, r);
this.cordova.getThreadPool().execute(r);
}
}
/**
* Open a database.
*
* @param dbName The name of the database file
*/
private SQLiteAndroidDatabase openDatabase(String dbname, CallbackContext cbc, boolean old_impl) throws Exception {
try {
// ASSUMPTION: no db (connection/handle) is already stored in the map
// [should be true according to the code in DBRunner.run()]
File dbfile = this.cordova.getActivity().getDatabasePath(dbname);
if (!dbfile.exists()) {
dbfile.getParentFile().mkdirs();
}
Log.v("info", "Open sqlite db: " + dbfile.getAbsolutePath());
SQLiteAndroidDatabase mydb = old_impl ? new SQLiteAndroidDatabase() : new SQLiteConnectorDatabase();
mydb.open(dbfile);
if (cbc != null) // XXX Android locking/closing BUG workaround
cbc.success();
return mydb;
} catch (Exception e) {
if (cbc != null) // XXX Android locking/closing BUG workaround
cbc.error("can't open database " + e);
throw e;
}
}
/**
* Close a database (in another thread).
*
* @param dbName The name of the database file
*/
private void closeDatabase(String dbname, CallbackContext cbc) {
DBRunner r = dbrmap.get(dbname);
if (r != null) {
try {
r.q.put(new DBQuery(false, cbc));
} catch(Exception e) {
if (cbc != null) {
cbc.error("couldn't close database" + e);
}
Log.e(SQLitePlugin.class.getSimpleName(), "couldn't close database", e);
}
} else {
if (cbc != null) {
cbc.success();
}
}
}
/**
* Close a database (in the current thread).
*
* @param dbname The name of the database file
*/
private void closeDatabaseNow(String dbname) {
DBRunner r = dbrmap.get(dbname);
if (r != null) {
SQLiteAndroidDatabase mydb = r.mydb;
if (mydb != null)
mydb.closeDatabaseNow();
}
}
private void deleteDatabase(String dbname, CallbackContext cbc) {
DBRunner r = dbrmap.get(dbname);
if (r != null) {
try {
r.q.put(new DBQuery(true, cbc));
} catch(Exception e) {
if (cbc != null) {
cbc.error("couldn't close database" + e);
}
Log.e(SQLitePlugin.class.getSimpleName(), "couldn't close database", e);
}
} else {
boolean deleteResult = this.deleteDatabaseNow(dbname);
if (deleteResult) {
cbc.success();
} else {
cbc.error("couldn't delete database");
}
}
}
/**
* Delete a database.
*
* @param dbName The name of the database file
*
* @return true if successful or false if an exception was encountered
*/
private boolean deleteDatabaseNow(String dbname) {
File dbfile = this.cordova.getActivity().getDatabasePath(dbname);
try {
return cordova.getActivity().deleteDatabase(dbfile.getAbsolutePath());
} catch (Exception e) {
Log.e(SQLitePlugin.class.getSimpleName(), "couldn't delete database", e);
return false;
}
}
private class DBRunner implements Runnable {
final String dbname;
private boolean oldImpl;
private boolean bugWorkaround;
final BlockingQueue<DBQuery> q;
final CallbackContext openCbc;
SQLiteAndroidDatabase mydb;
DBRunner(final String dbname, JSONObject options, CallbackContext cbc) {
this.dbname = dbname;
this.oldImpl = options.has("androidOldDatabaseImplementation");
Log.v(SQLitePlugin.class.getSimpleName(), "Android db implementation: built-in android.database.sqlite package");
this.bugWorkaround = this.oldImpl && options.has("androidBugWorkaround");
if (this.bugWorkaround)
Log.v(SQLitePlugin.class.getSimpleName(), "Android db closing/locking workaround applied");
this.q = new LinkedBlockingQueue<DBQuery>();
this.openCbc = cbc;
}
public void run() {
try {
this.mydb = openDatabase(dbname, this.openCbc, this.oldImpl);
} catch (Exception e) {
Log.e(SQLitePlugin.class.getSimpleName(), "unexpected error, stopping db thread", e);
dbrmap.remove(dbname);
return;
}
DBQuery dbq = null;
try {
dbq = q.take();
while (!dbq.stop) {
mydb.executeSqlBatch(dbq.queries, dbq.jsonparams, dbq.cbc);
if (this.bugWorkaround && dbq.queries.length == 1 && dbq.queries[0] == "COMMIT")
mydb.bugWorkaround();
dbq = q.take();
}
} catch (Exception e) {
Log.e(SQLitePlugin.class.getSimpleName(), "unexpected error", e);
}
if (dbq != null && dbq.close) {
try {
closeDatabaseNow(dbname);
dbrmap.remove(dbname); // (should) remove ourself
if (!dbq.delete) {
dbq.cbc.success();
} else {
try {
boolean deleteResult = deleteDatabaseNow(dbname);
if (deleteResult) {
dbq.cbc.success();
} else {
dbq.cbc.error("couldn't delete database");
}
} catch (Exception e) {
Log.e(SQLitePlugin.class.getSimpleName(), "couldn't delete database", e);
dbq.cbc.error("couldn't delete database: " + e);
}
}
} catch (Exception e) {
Log.e(SQLitePlugin.class.getSimpleName(), "couldn't close database", e);
if (dbq.cbc != null) {
dbq.cbc.error("couldn't close database: " + e);
}
}
}
}
}
private final class DBQuery {
// XXX TODO replace with DBRunner action enum:
final boolean stop;
final boolean close;
final boolean delete;
final String[] queries;
final JSONArray[] jsonparams;
final CallbackContext cbc;
DBQuery(String[] myqueries, JSONArray[] params, CallbackContext c) {
this.stop = false;
this.close = false;
this.delete = false;
this.queries = myqueries;
this.jsonparams = params;
this.cbc = c;
}
DBQuery(boolean delete, CallbackContext cbc) {
this.stop = true;
this.close = true;
this.delete = delete;
this.queries = null;
this.jsonparams = null;
this.cbc = cbc;
}
// signal the DBRunner thread to stop:
DBQuery() {
this.stop = true;
this.close = false;
this.delete = false;
this.queries = null;
this.jsonparams = null;
this.cbc = null;
}
}
private static enum Action {
echoStringValue,
open,
close,
delete,
executeSqlBatch,
backgroundExecuteSqlBatch,
}
}
/* vim: set expandtab : */

View File

@ -0,0 +1,143 @@
var dbmap = {};
var closed_dbmap = {};
function echoStringValue(success, error, options) {
success(options[0].value);
}
var SQL = null;
window.initSqlJs().then(sql => { SQL = sql })
function openDatabase(success, error, options) {
var name = options[0].name;
if (!!dbmap[name]) return setTimeout(function() {
error('INTERNAL OPEN ERROR: db already open for ' + name);
}, 0);
// Support close-and-reopen tests
if (!!closed_dbmap[name]) {
var db = dbmap[name] = closed_dbmap[name];
delete closed_dbmap[name];
try {
db.exec('ROLLBACK');
} catch(e) { }
return setTimeout(success, 0);
}
try {
dbmap[name] = new SQL.Database();
} catch(e) {
// INTERNAL OPEN ERROR
return error(e);
}
setTimeout(success, 0);
}
function backgroundExecuteSqlBatch(success, error, options) {
var dbname = options[0].dbargs.dbname;
if (!dbmap[dbname]) return error('INTERNAL ERROR: database not open');
var db = dbmap[dbname];
var e = options[0].executes;
var resultList = [];
for (var i = 0; i < e.length; ++i) {
var sql = e[i].sql;
var params = e[i].params;
var rr = []
var prevTotalChanges = (db.exec('SELECT total_changes()'))[0].values[0][0];
try {
db.each(sql, params, function(r) {
rr.push(r);
}, function() {
var insertId = (db.exec('SELECT last_insert_rowid()'))[0].values[0][0];
var totalChanges = (db.exec('SELECT total_changes()'))[0].values[0][0];
var rowsAffected = totalChanges - prevTotalChanges;
resultList.push({
type: 'success',
result: (rowsAffected !== 0) ? {
rows: rr,
insertId: insertId,
rowsAffected: rowsAffected
} : {
rows: rr,
rowsAffected: 0
}
});
});
} catch(e) {
// FUTURE TODO: report correct error code according to Web SQL
resultList.push({
type: 'error',
result: {
code: 0,
message: e.toString()
}
});
}
}
setTimeout(function() {
success(resultList);
}, 0);
}
function closeDatabase(success, error, options) {
var dbname = options[0].path;
var db = dbmap[dbname];
if (!db) return setTimeout(function() {
error('INTERNAL CLOSE ERROR: database not open');
}, 0);
// Keep in memory to support close-and-reopen tests
closed_dbmap[dbname] = dbmap[dbname];
delete dbmap[dbname];
setTimeout(success, 0);
}
function deleteDatabase(success, error, options) {
var dbname = options[0].path;
if (!!closed_dbmap[dbname]) {
// XXX TBD causes test timeouts:
// closed_dbmap[name].close();
delete closed_dbmap[dbname];
return setTimeout(success, 0);
}
var db = dbmap[dbname];
if (!db) return setTimeout(function() {
error('INTERNAL DELETE ERROR');
}, 0);
db.close();
delete dbmap[dbname];
setTimeout(success, 0);
}
module.exports = {
echoStringValue: echoStringValue,
open: openDatabase,
backgroundExecuteSqlBatch: backgroundExecuteSqlBatch,
close: closeDatabase,
delete: deleteDatabase
}
require('cordova/exec/proxy').add('SQLitePlugin', module.exports);

View File

@ -0,0 +1,167 @@
//
// CustomPSPDFThreadSafeMutableDictionary.m
//
// renamed from PSPDFThreadSafeMutableDictionary.m
//
// Copyright (c) 2019-present Christopher J. Brody (aka Chris Brody)
//
// Copyright (c) 2013 Peter Steinberger, PSPDFKit GmbH. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
// Dictionary-Subclasss whose primitive operations are thread safe.
@interface CustomPSPDFThreadSafeMutableDictionary : NSMutableDictionary
@end
// ----------------------------------------------------------------
//
// CustomPSPDFThreadSafeMutableDictionary.m
//
// renamed from PSPDFThreadSafeMutableDictionary.m
//
// PSPDFKit
//
// Copyright (c) 2013 PSPDFKit GmbH. All rights reserved.
//
// #import "PSPDFThreadSafeMutableDictionary.h"
#import <libkern/OSAtomic.h>
#define LOCKED(...) OSSpinLockLock(&_lock); \
__VA_ARGS__; \
OSSpinLockUnlock(&_lock);
@implementation CustomPSPDFThreadSafeMutableDictionary {
OSSpinLock _lock;
NSMutableDictionary *_dictionary; // Class Cluster!
}
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - NSObject
- (id)init {
return [self initWithCapacity:0];
}
- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys {
if ((self = [self initWithCapacity:objects.count])) {
[objects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
_dictionary[keys[idx]] = obj;
}];
}
return self;
}
- (id)initWithCapacity:(NSUInteger)capacity {
if ((self = [super init])) {
_dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity];
_lock = OS_SPINLOCK_INIT;
}
return self;
}
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - NSMutableDictionary
- (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey {
LOCKED(_dictionary[aKey] = anObject)
}
- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary {
LOCKED([_dictionary addEntriesFromDictionary:otherDictionary]);
}
- (void)setDictionary:(NSDictionary *)otherDictionary {
LOCKED([_dictionary setDictionary:otherDictionary]);
}
- (void)removeObjectForKey:(id)aKey {
LOCKED([_dictionary removeObjectForKey:aKey])
}
- (void)removeAllObjects {
LOCKED([_dictionary removeAllObjects]);
}
- (NSUInteger)count {
LOCKED(NSUInteger count = _dictionary.count)
return count;
}
- (NSArray *)allKeys {
LOCKED(NSArray *allKeys = _dictionary.allKeys)
return allKeys;
}
- (NSArray *)allValues {
LOCKED(NSArray *allValues = _dictionary.allValues)
return allValues;
}
- (id)objectForKey:(id)aKey {
LOCKED(id obj = _dictionary[aKey])
return obj;
}
- (NSEnumerator *)keyEnumerator {
LOCKED(NSEnumerator *keyEnumerator = [_dictionary keyEnumerator])
return keyEnumerator;
}
- (id)copyWithZone:(NSZone *)zone {
return [self mutableCopyWithZone:zone];
}
- (id)mutableCopyWithZone:(NSZone *)zone {
LOCKED(id copiedDictionary = [[self.class allocWithZone:zone] initWithDictionary:_dictionary])
return copiedDictionary;
}
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id __unsafe_unretained [])stackbuf
count:(NSUInteger)len {
LOCKED(NSUInteger count = [[_dictionary copy] countByEnumeratingWithState:state objects:stackbuf count:len]);
return count;
}
- (void)performLockedWithDictionary:(void (^)(NSDictionary *dictionary))block {
if (block) LOCKED(block(_dictionary));
}
- (BOOL)isEqual:(id)object {
if (object == self) return YES;
if ([object isKindOfClass:CustomPSPDFThreadSafeMutableDictionary.class]) {
CustomPSPDFThreadSafeMutableDictionary *other = object;
__block BOOL isEqual = NO;
[other performLockedWithDictionary:^(NSDictionary *dictionary) {
[self performLockedWithDictionary:^(NSDictionary *otherDictionary) {
isEqual = [dictionary isEqual:otherDictionary];
}];
}];
return isEqual;
}
return NO;
}
@end

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2012-present Christopher J. Brody (aka Chris Brody)
* Copyright (C) 2011 Davide Bertola
*
* This library is available under the terms of the MIT License (2008).
* See http://opensource.org/licenses/alphabetical for full text.
*/
#import <Cordova/CDVPlugin.h>
// Used to remove dependency on sqlite3.h in this header:
struct sqlite3;
enum WebSQLError {
UNKNOWN_ERR = 0,
DATABASE_ERR = 1,
VERSION_ERR = 2,
TOO_LARGE_ERR = 3,
QUOTA_ERR = 4,
SYNTAX_ERR_ = 5,
CONSTRAINT_ERR = 6,
TIMEOUT_ERR = 7
};
typedef int WebSQLError;
@interface SQLitePlugin : CDVPlugin {
NSMutableDictionary *openDBs;
}
@property (nonatomic, copy) NSMutableDictionary *openDBs;
@property (nonatomic, copy) NSMutableDictionary *appDBPaths;
// Self-test
-(void) echoStringValue: (CDVInvokedUrlCommand*)command;
// Open / Close / Delete
-(void) open: (CDVInvokedUrlCommand*)command;
-(void) close: (CDVInvokedUrlCommand*)command;
-(void) delete: (CDVInvokedUrlCommand*)command;
-(void) openNow: (CDVInvokedUrlCommand*)command;
-(void) closeNow: (CDVInvokedUrlCommand*)command;
-(void) deleteNow: (CDVInvokedUrlCommand*)command;
// Batch processing interface
-(void) backgroundExecuteSqlBatch: (CDVInvokedUrlCommand*)command;
-(void) executeSqlBatchNow: (CDVInvokedUrlCommand*)command;
@end /* vim: set expandtab : */

View File

@ -0,0 +1,567 @@
/*
* Copyright (c) 2012-present Christopher J. Brody (aka Chris Brody)
* Copyright (C) 2011 Davide Bertola
*
* This library is available under the terms of the MIT License (2008).
* See http://opensource.org/licenses/alphabetical for full text.
*/
#import "SQLitePlugin.h"
#import "sqlite3.h"
// Defines Macro to only log lines when in DEBUG mode
#ifdef DEBUG
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
# define DLog(...)
#endif
#if !__has_feature(objc_arc)
# error "Missing objc_arc feature"
#endif
// CustomPSPDFThreadSafeMutableDictionary interface copied from
// CustomPSPDFThreadSafeMutableDictionary.m:
//
// Dictionary-Subclasss whose primitive operations are thread safe.
@interface CustomPSPDFThreadSafeMutableDictionary : NSMutableDictionary
@end
@implementation SQLitePlugin
@synthesize openDBs;
@synthesize appDBPaths;
-(void)pluginInitialize
{
DLog(@"Initializing SQLitePlugin");
{
openDBs = [CustomPSPDFThreadSafeMutableDictionary dictionaryWithCapacity:0];
appDBPaths = [NSMutableDictionary dictionaryWithCapacity:0];
NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0];
DLog(@"Detected docs path: %@", docs);
[appDBPaths setObject: docs forKey:@"docs"];
NSString *libs = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex: 0];
DLog(@"Detected Library path: %@", libs);
[appDBPaths setObject: libs forKey:@"libs"];
NSString *nosync = [libs stringByAppendingPathComponent:@"LocalDatabase"];
NSError *err;
// GENERAL NOTE: no `nosync` directory path entry to be added
// to appDBPaths map in case of any isses creating the
// required directory or setting the resource value for
// NSURLIsExcludedFromBackupKey
//
// This is to avoid potential for issue raised here:
// https://github.com/xpbrew/cordova-sqlite-storage/issues/907
if ([[NSFileManager defaultManager] fileExistsAtPath: nosync])
{
DLog(@"no cloud sync directory already exists at path: %@", nosync);
}
else
{
if ([[NSFileManager defaultManager] createDirectoryAtPath: nosync withIntermediateDirectories:NO attributes: nil error:&err])
{
DLog(@"no cloud sync directory created with path: %@", nosync);
}
else
{
// STOP HERE & LOG WITH INTERNAL PLUGIN ERROR:
NSLog(@"INTERNAL PLUGIN ERROR: could not create no cloud sync directory at path: %@", nosync);
return;
}
}
{
{
// Set the resource value for NSURLIsExcludedFromBackupKey
NSURL *nosyncURL = [ NSURL fileURLWithPath: nosync];
if (![nosyncURL setResourceValue: [NSNumber numberWithBool: YES] forKey: NSURLIsExcludedFromBackupKey error: &err])
{
// STOP HERE & LOG WITH INTERNAL PLUGIN ERROR:
NSLog(@"INTERNAL PLUGIN ERROR: error setting nobackup flag in LocalDatabase directory: %@", err);
return;
}
// now ready to add `nosync` entry to appDBPaths:
DLog(@"no cloud sync at path: %@", nosync);
[appDBPaths setObject: nosync forKey:@"nosync"];
}
}
}
}
-(id) getDBPath:(NSString *)dbFile at:(NSString *)atkey {
if (dbFile == NULL) {
return NULL;
}
NSString *dbdir = [appDBPaths objectForKey:atkey];
if (dbdir == NULL) {
// INTERNAL PLUGIN ERROR:
return NULL;
}
NSString *dbPath = [dbdir stringByAppendingPathComponent: dbFile];
return dbPath;
}
-(void)echoStringValue: (CDVInvokedUrlCommand*)command
{
CDVPluginResult * pluginResult = nil;
NSMutableDictionary * options = [command.arguments objectAtIndex:0];
NSString * string_value = [options objectForKey:@"value"];
DLog(@"echo string value: %@", string_value);
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:string_value];
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
}
-(void)open: (CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
[self openNow: command];
}];
}
-(void)openNow: (CDVInvokedUrlCommand*)command
{
CDVPluginResult* pluginResult = nil;
NSMutableDictionary *options = [command.arguments objectAtIndex:0];
NSString *dbfilename = [options objectForKey:@"name"];
NSString *dblocation = [options objectForKey:@"dblocation"];
if (dblocation == NULL) dblocation = @"docs";
// DLog(@"using db location: %@", dblocation);
NSString *dbname = [self getDBPath:dbfilename at:dblocation];
if (!sqlite3_threadsafe()) {
// INTERNAL PLUGIN ERROR:
NSLog(@"INTERNAL PLUGIN ERROR: sqlite3_threadsafe() returns false value");
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: @"INTERNAL PLUGIN ERROR: sqlite3_threadsafe() returns false value"];
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
return;
} else if (dbname == NULL) {
// INTERNAL PLUGIN ERROR - NOT EXPECTED:
NSLog(@"INTERNAL PLUGIN ERROR (NOT EXPECTED): open with database name missing");
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: @"INTERNAL PLUGIN ERROR: open with database name missing"];
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
return;
} else {
NSValue *dbPointer = [openDBs objectForKey:dbfilename];
if (dbPointer != NULL) {
// NO LONGER EXPECTED due to BUG 666 workaround solution:
// DLog(@"Reusing existing database connection for db name %@", dbfilename);
NSLog(@"INTERNAL PLUGIN ERROR: database already open for db name: %@ (db file name: %@)", dbname, dbfilename);
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: @"INTERNAL PLUGIN ERROR: database already open"];
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
return;
}
@synchronized(self) {
const char *name = [dbname UTF8String];
sqlite3 *db;
DLog(@"open full db path: %@", dbname);
if (sqlite3_open(name, &db) != SQLITE_OK) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Unable to open DB"];
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
return;
} else {
sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, NULL);
// for SQLCipher version:
// NSString *dbkey = [options objectForKey:@"key"];
// const char *key = NULL;
// if (dbkey != NULL) key = [dbkey UTF8String];
// if (key != NULL) sqlite3_key(db, key, strlen(key));
// Attempt to read the SQLite master table [to support SQLCipher version]:
if(sqlite3_exec(db, (const char*)"SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) {
dbPointer = [NSValue valueWithPointer:db];
[openDBs setObject: dbPointer forKey: dbfilename];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Database opened"];
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Unable to open DB with key"];
// XXX TODO: close the db handle & [perhaps] remove from openDBs!!
}
}
}
}
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
// DLog(@"open cb finished ok");
}
-(void) close: (CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
[self closeNow: command];
}];
}
-(void)closeNow: (CDVInvokedUrlCommand*)command
{
CDVPluginResult* pluginResult = nil;
NSMutableDictionary *options = [command.arguments objectAtIndex:0];
NSString *dbFileName = [options objectForKey:@"path"];
if (dbFileName == NULL) {
// Should not happen:
DLog(@"No db name specified for close");
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"INTERNAL PLUGIN ERROR: You must specify database path"];
} else {
NSValue *val = [openDBs objectForKey:dbFileName];
sqlite3 *db = [val pointerValue];
if (db == NULL) {
// Should not happen:
DLog(@"close: db name was not open: %@", dbFileName);
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"INTERNAL PLUGIN ERROR: Specified db was not open"];
}
else {
DLog(@"close db name: %@", dbFileName);
sqlite3_close (db);
[openDBs removeObjectForKey:dbFileName];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"DB closed"];
}
}
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
}
-(void) delete: (CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
[self deleteNow: command];
}];
}
-(void)deleteNow: (CDVInvokedUrlCommand*)command
{
CDVPluginResult* pluginResult = nil;
NSMutableDictionary *options = [command.arguments objectAtIndex:0];
NSString *dbFileName = [options objectForKey:@"path"];
NSString *dblocation = [options objectForKey:@"dblocation"];
if (dblocation == NULL) dblocation = @"docs";
if (dbFileName==NULL) {
// Should not happen:
DLog(@"No db name specified for delete");
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"INTERNAL PLUGIN ERROR: You must specify database path"];
} else {
NSString *dbPath = [self getDBPath:dbFileName at:dblocation];
if (dbPath == NULL) {
// INTERNAL PLUGIN ERROR - NOT EXPECTED:
NSLog(@"INTERNAL PLUGIN ERROR (NOT EXPECTED): delete with no valid database path found");
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: @"INTERNAL PLUGIN ERROR: delete with no valid database path found"];
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
return;
}
if ([[NSFileManager defaultManager]fileExistsAtPath:dbPath]) {
DLog(@"delete full db path: %@", dbPath);
[[NSFileManager defaultManager]removeItemAtPath:dbPath error:nil];
[openDBs removeObjectForKey:dbFileName];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"DB deleted"];
} else {
DLog(@"delete: db was not found: %@", dbPath);
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"The database does not exist on that path"];
}
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
-(void) backgroundExecuteSqlBatch: (CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
[self executeSqlBatchNow: command];
}];
}
-(void) executeSqlBatchNow: (CDVInvokedUrlCommand*)command
{
NSMutableDictionary *options = [command.arguments objectAtIndex:0];
NSMutableArray *results = [NSMutableArray arrayWithCapacity:0];
NSMutableDictionary *dbargs = [options objectForKey:@"dbargs"];
NSMutableArray *executes = [options objectForKey:@"executes"];
CDVPluginResult* pluginResult;
{
for (NSMutableDictionary *dict in executes) {
CDVPluginResult *result = [self executeSqlWithDict:dict andArgs:dbargs];
if ([result.status intValue] == CDVCommandStatus_ERROR) {
/* add error with result.message: */
NSMutableDictionary *r = [NSMutableDictionary dictionaryWithCapacity:0];
[r setObject:@"error" forKey:@"type"];
[r setObject:result.message forKey:@"error"];
[r setObject:result.message forKey:@"result"];
[results addObject: r];
} else {
/* add result with result.message: */
NSMutableDictionary *r = [NSMutableDictionary dictionaryWithCapacity:0];
[r setObject:@"success" forKey:@"type"];
[r setObject:result.message forKey:@"result"];
[results addObject: r];
}
}
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:results];
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
-(void) executeSql: (CDVInvokedUrlCommand*)command
{
NSMutableDictionary *options = [command.arguments objectAtIndex:0];
NSMutableDictionary *dbargs = [options objectForKey:@"dbargs"];
NSMutableDictionary *ex = [options objectForKey:@"ex"];
CDVPluginResult * pluginResult = [self executeSqlWithDict: ex andArgs: dbargs];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
-(CDVPluginResult*) executeSqlWithDict: (NSMutableDictionary*)options andArgs: (NSMutableDictionary*)dbargs
{
NSString *dbFileName = [dbargs objectForKey:@"dbname"];
if (dbFileName == NULL) {
return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"INTERNAL PLUGIN ERROR: You must specify database path"];
}
NSMutableArray *params = [options objectForKey:@"params"]; // optional
NSValue *dbPointer = [openDBs objectForKey:dbFileName];
if (dbPointer == NULL) {
return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"INTERNAL PLUGIN ERROR: No such database, you must open it first"];
}
sqlite3 *db = [dbPointer pointerValue];
NSString *sql = [options objectForKey:@"sql"];
if (sql == NULL) {
return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"INTERNAL PLUGIN ERROR: You must specify a sql query to execute"];
}
const char *sql_stmt = [sql UTF8String];
NSDictionary *error = nil;
sqlite3_stmt *statement;
int result, i, column_type, count;
int previousRowsAffected, nowRowsAffected, diffRowsAffected;
long long previousInsertId, nowInsertId;
BOOL keepGoing = YES;
BOOL hasInsertId;
NSMutableDictionary *resultSet = [NSMutableDictionary dictionaryWithCapacity:0];
NSMutableArray *resultRows = [NSMutableArray arrayWithCapacity:0];
NSMutableDictionary *entry;
NSObject *columnValue;
NSString *columnName;
NSObject *insertId;
NSObject *rowsAffected;
hasInsertId = NO;
previousRowsAffected = sqlite3_total_changes(db);
previousInsertId = sqlite3_last_insert_rowid(db);
if (sqlite3_prepare_v2(db, sql_stmt, -1, &statement, NULL) != SQLITE_OK) {
error = [SQLitePlugin captureSQLiteErrorFromDb:db];
keepGoing = NO;
} else if (params != NULL) {
for (int b = 0; b < params.count; b++) {
result = [self bindStatement:statement withArg:[params objectAtIndex:b] atIndex:(b+1)];
if (result != SQLITE_OK) {
error = [SQLitePlugin captureSQLiteErrorFromDb:db];
keepGoing = NO;
break;
}
}
}
while (keepGoing) {
result = sqlite3_step (statement);
switch (result) {
case SQLITE_ROW:
i = 0;
entry = [NSMutableDictionary dictionaryWithCapacity:0];
count = sqlite3_column_count(statement);
while (i < count) {
columnValue = nil;
columnName = [NSString stringWithFormat:@"%s", sqlite3_column_name(statement, i)];
column_type = sqlite3_column_type(statement, i);
switch (column_type) {
case SQLITE_INTEGER:
columnValue = [NSNumber numberWithLongLong: sqlite3_column_int64(statement, i)];
break;
case SQLITE_FLOAT:
columnValue = [NSNumber numberWithDouble: sqlite3_column_double(statement, i)];
break;
case SQLITE_BLOB:
case SQLITE_TEXT:
columnValue = [[NSString alloc] initWithBytes:(char *)sqlite3_column_text(statement, i)
length:sqlite3_column_bytes(statement, i)
encoding:NSUTF8StringEncoding];
break;
case SQLITE_NULL:
// just in case (should not happen):
default:
columnValue = [NSNull null];
break;
}
if (columnValue) {
[entry setObject:columnValue forKey:columnName];
}
i++;
}
[resultRows addObject:entry];
break;
case SQLITE_DONE:
nowRowsAffected = sqlite3_total_changes(db);
diffRowsAffected = nowRowsAffected - previousRowsAffected;
rowsAffected = [NSNumber numberWithInt:diffRowsAffected];
nowInsertId = sqlite3_last_insert_rowid(db);
if (diffRowsAffected > 0 && nowInsertId != 0) {
hasInsertId = YES;
insertId = [NSNumber numberWithLongLong:sqlite3_last_insert_rowid(db)];
}
keepGoing = NO;
break;
default:
error = [SQLitePlugin captureSQLiteErrorFromDb:db];
keepGoing = NO;
}
}
sqlite3_finalize (statement);
if (error) {
return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:error];
}
[resultSet setObject:resultRows forKey:@"rows"];
[resultSet setObject:rowsAffected forKey:@"rowsAffected"];
if (hasInsertId) {
[resultSet setObject:insertId forKey:@"insertId"];
}
return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:resultSet];
}
-(int)bindStatement:(sqlite3_stmt *)statement withArg:(NSObject *)arg atIndex:(int)argIndex
{
int bindResult = SQLITE_ERROR;
if ([arg isEqual:[NSNull null]]) {
// bind null:
bindResult = sqlite3_bind_null(statement, argIndex);
} else if ([arg isKindOfClass:[NSNumber class]]) {
// bind NSNumber (int64 or double):
NSNumber *numberArg = (NSNumber *)arg;
const char *numberType = [numberArg objCType];
// Bind each number as INTEGER (long long int) or REAL (double):
if (strcmp(numberType, @encode(int)) == 0 ||
strcmp(numberType, @encode(long long int)) == 0) {
bindResult = sqlite3_bind_int64(statement, argIndex, [numberArg longLongValue]);
} else {
bindResult = sqlite3_bind_double(statement, argIndex, [numberArg doubleValue]);
}
} else {
// bind NSString (text):
NSString *stringArg;
if ([arg isKindOfClass:[NSString class]]) {
stringArg = (NSString *)arg;
} else {
stringArg = [arg description]; // convert to text
}
// always bind text string as UTF-8 (sqlite does internal conversion if necessary):
NSData *data = [stringArg dataUsingEncoding:NSUTF8StringEncoding];
bindResult = sqlite3_bind_text(statement, argIndex, data.bytes, (int)data.length, SQLITE_TRANSIENT);
}
return bindResult;
}
-(void)dealloc
{
int i;
NSArray *keys = [openDBs allKeys];
NSValue *pointer;
NSString *key;
sqlite3 *db;
/* close db the user forgot */
for (i=0; i<[keys count]; i++) {
key = [keys objectAtIndex:i];
pointer = [openDBs objectForKey:key];
db = [pointer pointerValue];
sqlite3_close (db);
}
}
+(NSDictionary *)captureSQLiteErrorFromDb:(struct sqlite3 *)db
{
int code = sqlite3_errcode(db);
int webSQLCode = [SQLitePlugin mapSQLiteErrorCode:code];
#if INCLUDE_SQLITE_ERROR_INFO
int extendedCode = sqlite3_extended_errcode(db);
#endif
const char *message = sqlite3_errmsg(db);
NSMutableDictionary *error = [NSMutableDictionary dictionaryWithCapacity:4];
[error setObject:[NSNumber numberWithInt:webSQLCode] forKey:@"code"];
[error setObject:[NSString stringWithUTF8String:message] forKey:@"message"];
#if INCLUDE_SQLITE_ERROR_INFO
[error setObject:[NSNumber numberWithInt:code] forKey:@"sqliteCode"];
[error setObject:[NSNumber numberWithInt:extendedCode] forKey:@"sqliteExtendedCode"];
[error setObject:[NSString stringWithUTF8String:message] forKey:@"sqliteMessage"];
#endif
return error;
}
+(int)mapSQLiteErrorCode:(int)code
{
// map the sqlite error code to
// the websql error code
switch(code) {
case SQLITE_ERROR:
return SYNTAX_ERR_;
case SQLITE_FULL:
return QUOTA_ERR;
case SQLITE_CONSTRAINT:
return CONSTRAINT_ERR;
default:
return UNKNOWN_ERR;
}
}
@end /* vim: set expandtab : */

View File

@ -0,0 +1 @@
#include "Constants.h"

View File

@ -0,0 +1,50 @@
#pragma once
#include "sqlite3.h"
namespace SQLite3
{
public ref class Datatype sealed
{
public:
static property int Integer { int get() { return SQLITE_INTEGER; } }
static property int Float { int get() { return SQLITE_FLOAT; } }
static property int Text { int get() { return SQLITE_TEXT; } }
static property int Blob { int get() { return SQLITE_BLOB; } }
static property int Null { int get() { return SQLITE_NULL; } }
};
public ref class ResultCode sealed
{
public:
static property int Ok { int get() { return SQLITE_OK; } }
static property int Error { int get() { return SQLITE_ERROR; } }
static property int Internal { int get() { return SQLITE_INTERNAL; } }
static property int Perm { int get() { return SQLITE_PERM; } }
static property int Abort { int get() { return SQLITE_ABORT; } }
static property int Busy { int get() { return SQLITE_BUSY; } }
static property int Locked { int get() { return SQLITE_LOCKED; } }
static property int NoMem { int get() { return SQLITE_NOMEM; } }
static property int ReadOnly { int get() { return SQLITE_READONLY; } }
static property int Interrupt { int get() { return SQLITE_INTERRUPT; } }
static property int IoErr { int get() { return SQLITE_IOERR; } }
static property int Corrupt { int get() { return SQLITE_CORRUPT; } }
static property int NotFound { int get() { return SQLITE_NOTFOUND; } }
static property int Full { int get() { return SQLITE_FULL; } }
static property int CantOpen { int get() { return SQLITE_CANTOPEN; } }
static property int Protocol { int get() { return SQLITE_PROTOCOL; } }
static property int Empty { int get() { return SQLITE_EMPTY; } }
static property int Schema { int get() { return SQLITE_SCHEMA; } }
static property int TooBig { int get() { return SQLITE_TOOBIG; } }
static property int Constraint { int get() { return SQLITE_CONSTRAINT; } }
static property int Mismatch { int get() { return SQLITE_MISMATCH; } }
static property int Misuse { int get() { return SQLITE_MISUSE; } }
static property int NoLfs { int get() { return SQLITE_NOLFS; } }
static property int Auth { int get() { return SQLITE_AUTH; } }
static property int Format { int get() { return SQLITE_FORMAT; } }
static property int Range { int get() { return SQLITE_RANGE; } }
static property int NotADb { int get() { return SQLITE_NOTADB; } }
static property int Row { int get() { return SQLITE_ROW; } }
static property int Done { int get() { return SQLITE_DONE; } }
};
}

View File

@ -0,0 +1,57 @@
#include "Winerror.h"
#include "Database.h"
#include "Statement.h"
namespace SQLite3
{
Database::Database(Platform::String^ dbPath)
: sqlite(nullptr)
{
int ret = sqlite3_open16(dbPath->Data(), &sqlite);
if (ret != SQLITE_OK)
{
sqlite3_close(sqlite);
HRESULT hresult = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, ret);
throw ref new Platform::COMException(hresult);
}
sqlite3_db_config(sqlite, SQLITE_DBCONFIG_DEFENSIVE, 1, NULL);
}
Database::~Database()
{
if (sqlite != nullptr) sqlite3_close(sqlite);
}
Statement^ Database::Prepare(Platform::String^ sql)
{
return ref new Statement(this, sql);
}
int Database::closedb()
{
int rc = sqlite3_close(sqlite);
if (rc == SQLITE_OK) sqlite = nullptr;
return rc;
}
int Database::close_v2()
{
int rc = sqlite3_close_v2(sqlite);
if (rc == SQLITE_OK) sqlite = nullptr;
return rc;
}
int Database::LastInsertRowid()
{
return sqlite3_last_insert_rowid(sqlite);
}
int Database::TotalChanges()
{
return sqlite3_total_changes(sqlite);
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "sqlite3.h"
namespace SQLite3
{
ref class Statement;
public ref class Database sealed
{
public:
Database(Platform::String^ dbPath);
virtual ~Database();
int closedb();
int close_v2();
Statement^ Prepare(Platform::String^ sql);
int LastInsertRowid();
int TotalChanges();
private:
friend Statement;
sqlite3* sqlite;
};
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<ItemsProjectGuid>{db84ae51-4b93-44f5-be22-1eae1833ecec}</ItemsProjectGuid>
<ItemsRootNamespace>SQLite3</ItemsRootNamespace>
<ItemsProjectName>SQLite3.Shared</ItemsProjectName>
<CodeSharingProject>248F659F-DAC5-46E8-AC09-60EC9FC95053</CodeSharingProject>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(MSBuildThisFileDirectory)..\..\..\..\node_modules\cordova-sqlite-storage-dependencies</AdditionalIncludeDirectories>
<AdditionalOptions>/DSQLITE_THREADSAFE=1 /DSQLITE_DEFAULT_SYNCHRONOUS=3 /DSQLITE_DEFAULT_MEMSTATUS=0 /DSQLITE_OMIT_DECLTYPE /DSQLITE_OMIT_DEPRECATED /DSQLITE_OMIT_PROGRESS_CALLBACK /DSQLITE_OMIT_SHARED_CACHE /DSQLITE_TEMP_STORE=2 /DSQLITE_OMIT_LOAD_EXTENSION /DSQLITE_ENABLE_FTS3 /DSQLITE_ENABLE_FTS3_PARENTHESIS /DSQLITE_ENABLE_FTS4 /DSQLITE_ENABLE_RTREE /DSQLITE_DEFAULT_PAGE_SIZE=4096 /DSQLITE_OS_WINRT %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)..\..\..\..\node_modules\cordova-sqlite-storage-dependencies\sqlite3.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)Constants.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)Database.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)Statement.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)Constants.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)Database.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)Statement.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)..\..\..\..\node_modules\cordova-sqlite-storage-dependencies\sqlite3.c">
<CompileAsWinRT>false</CompileAsWinRT>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,268 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
- -->
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
- -->
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{76e68196-b7dc-4393-a070-d32fc33bc489}</ProjectGuid>
<Keyword>WindowsRuntimeComponent</Keyword>
<ProjectName>SQLite3.UWP</ProjectName>
<RootNamespace>SQLite3</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
- -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
- -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="SQLite3.Shared.vcxitems" Label="Shared" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared" >
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
- -->
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
- -->
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
- -->
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
- -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
<FunctionLevelLinking>true</FunctionLevelLinking>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
- -->
<!-- MOBILE (ARM) NOT SUPPORTED (...)
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
<FunctionLevelLinking>true</FunctionLevelLinking>
<SDLCheck>false</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
- -->
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,75 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 14 for Windows
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLite3", "SQLite3", "{F0B5DA26-91CD-44D3-97C8-19B43134837E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SQLite3.Shared", "SQLite3.Shared.vcxitems", "{DB84AE51-4B93-44F5-BE22-1EAE1833ECEC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SQLite3.Windows", "SQLite3.Windows\SQLite3.Windows.vcxproj", "{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SQLite3.WindowsPhone", "SQLite3.WindowsPhone\SQLite3.WindowsPhone.vcxproj", "{6435C2E4-4FD2-405A-9EE2-5312AE852782}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SQLite3.UWP", "SQLite3.UWP\SQLite3.UWP.vcxproj", "{76E68196-B7DC-4393-A070-D32FC33BC489}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
SQLite3.Shared.vcxitems*{db84ae51-4b93-44f5-be22-1eae1833ecec}*SharedItemsImports = 9
SQLite3.Shared.vcxitems*{d1848fee-6a8e-4ef1-8bfb-8652e5a9cd4a}*SharedItemsImports = 4
SQLite3.Shared.vcxitems*{6435c2e4-4fd2-405a-9ee2-5312ae852782}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|ARM = Release|ARM
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Debug|ARM.ActiveCfg = Debug|ARM
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Debug|ARM.Build.0 = Debug|ARM
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Debug|Win32.ActiveCfg = Debug|Win32
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Debug|Win32.Build.0 = Debug|Win32
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Debug|x64.ActiveCfg = Debug|x64
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Debug|x64.Build.0 = Debug|x64
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Release|ARM.ActiveCfg = Release|ARM
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Release|ARM.Build.0 = Release|ARM
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Release|Win32.ActiveCfg = Release|Win32
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Release|Win32.Build.0 = Release|Win32
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Release|x64.ActiveCfg = Release|x64
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A}.Release|x64.Build.0 = Release|x64
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Debug|ARM.ActiveCfg = Debug|ARM
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Debug|ARM.Build.0 = Debug|ARM
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Debug|Win32.ActiveCfg = Debug|Win32
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Debug|Win32.Build.0 = Debug|Win32
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Debug|x64.ActiveCfg = Debug|Win32
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Release|ARM.ActiveCfg = Release|ARM
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Release|ARM.Build.0 = Release|ARM
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Release|Win32.ActiveCfg = Release|Win32
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Release|Win32.Build.0 = Release|Win32
{6435C2E4-4FD2-405A-9EE2-5312AE852782}.Release|x64.ActiveCfg = Release|Win32
{76E68196-B7DC-4393-A070-D32FC33BC489}.Debug|ARM.ActiveCfg = Debug|ARM
{76E68196-B7DC-4393-A070-D32FC33BC489}.Debug|ARM.Build.0 = Debug|ARM
{76E68196-B7DC-4393-A070-D32FC33BC489}.Debug|Win32.ActiveCfg = Debug|Win32
{76E68196-B7DC-4393-A070-D32FC33BC489}.Debug|Win32.Build.0 = Debug|Win32
{76E68196-B7DC-4393-A070-D32FC33BC489}.Debug|x64.ActiveCfg = Debug|x64
{76E68196-B7DC-4393-A070-D32FC33BC489}.Debug|x64.Build.0 = Debug|x64
{76E68196-B7DC-4393-A070-D32FC33BC489}.Release|ARM.ActiveCfg = Release|ARM
{76E68196-B7DC-4393-A070-D32FC33BC489}.Release|ARM.Build.0 = Release|ARM
{76E68196-B7DC-4393-A070-D32FC33BC489}.Release|Win32.ActiveCfg = Release|Win32
{76E68196-B7DC-4393-A070-D32FC33BC489}.Release|Win32.Build.0 = Release|Win32
{76E68196-B7DC-4393-A070-D32FC33BC489}.Release|x64.ActiveCfg = Release|x64
{76E68196-B7DC-4393-A070-D32FC33BC489}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{DB84AE51-4B93-44F5-BE22-1EAE1833ECEC} = {F0B5DA26-91CD-44D3-97C8-19B43134837E}
{D1848FEE-6A8E-4EF1-8BFB-8652E5A9CD4A} = {F0B5DA26-91CD-44D3-97C8-19B43134837E}
{6435C2E4-4FD2-405A-9EE2-5312AE852782} = {F0B5DA26-91CD-44D3-97C8-19B43134837E}
{76E68196-B7DC-4393-A070-D32FC33BC489} = {F0B5DA26-91CD-44D3-97C8-19B43134837E}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,90 @@
#include "Winerror.h"
#include "Statement.h"
#include "Database.h"
namespace SQLite3
{
Statement::Statement(Database^ database, Platform::String^ sql)
{
int ret = sqlite3_prepare16(database->sqlite, sql->Data(), -1, &statement, 0);
if (ret != SQLITE_OK)
{
sqlite3_finalize(statement);
HRESULT hresult = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, ret);
throw ref new Platform::COMException(hresult);
}
}
Statement::~Statement()
{
sqlite3_finalize(statement);
}
int Statement::Step()
{
return sqlite3_step(statement);
}
int Statement::ColumnCount()
{
return sqlite3_column_count(statement);
}
int Statement::ColumnType(int index)
{
return sqlite3_column_type(statement, index);
}
Platform::String^ Statement::ColumnName(int index)
{
return ref new Platform::String(static_cast<const wchar_t*>(sqlite3_column_name16(statement, index)));
}
Platform::String^ Statement::ColumnText(int index)
{
return ref new Platform::String(static_cast<const wchar_t*>(sqlite3_column_text16(statement, index)));
}
int Statement::ColumnInt(int index)
{
return sqlite3_column_int(statement, index);
}
long long Statement::ColumnInt64(int index)
{
return sqlite3_column_int64(statement, index);
}
double Statement::ColumnDouble(int index)
{
return sqlite3_column_double(statement, index);
}
int Statement::BindText(int index, Platform::String^ val)
{
return sqlite3_bind_text16(statement, index, val->Data(), -1, SQLITE_TRANSIENT);
}
int Statement::BindInt(int index, int val)
{
return sqlite3_bind_int(statement, index, val);
}
int Statement::BindInt64(int index, long long val)
{
return sqlite3_bind_int64(statement, index, val);
}
int Statement::BindDouble(int index, double val)
{
return sqlite3_bind_double(statement, index, val);
}
int Statement::BindNull(int index)
{
return sqlite3_bind_null(statement, index);
}
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "sqlite3.h"
namespace SQLite3
{
ref class Database;
public ref class Statement sealed
{
public:
Statement(Database^ database, Platform::String^ sql);
virtual ~Statement();
int Step();
int ColumnCount();
int ColumnType(int index);
Platform::String^ ColumnName(int index);
Platform::String^ ColumnText(int index);
int ColumnInt(int index);
long long ColumnInt64(int index);
double ColumnDouble(int index);
int BindText(int index, Platform::String^ val);
int BindInt(int index, int val);
int BindInt64(int index, long long val);
int BindDouble(int index, double val);
int BindNull(int index);
private:
sqlite3_stmt* statement;
};
}

View File

@ -0,0 +1 @@
#include "pch.h"

View File

@ -0,0 +1,4 @@
#pragma once
#include <collection.h>
#include <ppltasks.h>

View File

@ -0,0 +1,294 @@
(function () {
"use strict";
var Statement, Database, ItemDataSource, GroupDataSource;
// Alternative typeof implementation yielding more meaningful results,
// see http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
function type(obj) {
var typeString;
typeString = Object.prototype.toString.call(obj);
return typeString.substring(8, typeString.length - 1).toLowerCase();
}
function throwSQLiteError(message, comException) {
var error = new Error(message);
error.resultCode = comException.number & 0xffff;
throw error;
}
Statement = WinJS.Class.define(function (db, sql, args) {
try {
this.statement = db.connection.prepare(sql);
} catch (comException) {
throwSQLiteError('Error preparing an SQLite statement.', comException);
}
if (args) {
this.bind(args);
}
}, {
bind: function (args) {
var index, resultCode;
args.forEach(function (arg, i) {
index = i + 1;
switch (type(arg)) {
case 'number':
if (arg % 1 === 0) {
resultCode = this.statement.bindInt64(index, arg);
} else {
resultCode = this.statement.bindDouble(index, arg);
}
break;
case 'string':
resultCode = this.statement.bindText(index, arg);
break;
case 'null':
resultCode = this.statement.bindNull(index);
break;
default:
throw new Error("Unsupported argument type: " + type(arg));
}
if (resultCode !== SQLite3.ResultCode.ok) {
throw new Error("Error " + resultCode + " when binding argument to SQL query.");
}
}, this);
},
run: function () {
this.statement.step();
},
one: function () {
this.statement.step();
return this._getRow();
},
all: function () {
var result = [];
this.each(function (row) {
result.push(row);
});
return result;
},
each: function (callback) {
var resultCode = this.statement.step();
while (resultCode === SQLite3.ResultCode.row) {
callback(this._getRow());
resultCode = this.statement.step();
}
if (resultCode !== SQLite3.ResultCode.done && resultCode !== SQLite3.ResultCode.ok) {
throw new Error("SQLite3 step error result code: " + resultCode);
}
},
map: function (callback) {
var result = [];
this.each(function (row) {
result.push(callback(row));
});
return result;
},
close: function () {
this.statement.close();
},
_getRow: function () {
var i, len, name, row = {};
for (i = 0, len = this.statement.columnCount() ; i < len; i += 1) {
name = this.statement.columnName(i);
row[name] = this._getColumn(i);
}
return row;
},
_getColumn: function (index) {
switch (this.statement.columnType(index)) {
case SQLite3.Datatype.integer:
return this.statement.columnInt64(index);
case SQLite3.Datatype.float:
return this.statement.columnDouble(index);
case SQLite3.Datatype.text:
return this.statement.columnText(index);
case SQLite3.Datatype["null"]:
return null;
default:
throw new Error('Unsupported column type in column ' + index);
}
}
});
Database = WinJS.Class.define(function (dbPath) {
try {
this.connection = SQLite3.Database(dbPath);
} catch (comException) {
throwSQLiteError('Error creating an SQLite database connection.', comException);
}
}, {
run: function (sql, args) {
var statement = this.prepare(sql, args);
statement.run();
statement.close();
},
one: function (sql, args) {
var row, statement = this.prepare(sql, args);
row = statement.one();
statement.close();
return row;
},
all: function (sql, args) {
var rows, statement = this.prepare(sql, args);
rows = statement.all();
statement.close();
return rows;
},
each: function (sql, args, callback) {
if (!callback && type(args) === 'function') {
callback = args;
args = null;
}
var statement = this.prepare(sql, args);
statement.each(callback);
statement.close();
},
map: function (sql, args, callback) {
if (!callback && type(args) === 'function') {
callback = args;
args = null;
}
var rows, statement = this.prepare(sql, args);
rows = statement.map(callback);
statement.close();
return rows;
},
prepare: function (sql, args) {
return new Statement(this, sql, args);
},
itemDataSource: function (sql, args, keyColumnName, groupKeyColumnName) {
if (type(args) === 'string') {
groupKeyColumnName = keyColumnName;
keyColumnName = args;
args = undefined;
}
return new ItemDataSource(this, sql, args, keyColumnName, groupKeyColumnName);
},
groupDataSource: function (sql, args, keyColumnName, sizeColumnName) {
if (type(args) === 'string') {
sizeColumnName = keyColumnName;
keyColumnName = args;
args = undefined;
}
return new GroupDataSource(this, sql, args, keyColumnName, sizeColumnName);
},
close: function () {
return this.connection.closedb();
},
close_v2: function () {
return this.connection.close_v2();
},
lastInsertRowid: function () {
return this.connection.lastInsertRowid();
},
totalChanges: function () {
return this.connection.totalChanges();
}
});
ItemDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource,
function (db, sql, args, keyColumnName, groupKeyColumnName) {
var dataAdapter = {
getCount: function () {
var row = db.one('SELECT COUNT(*) AS cnt FROM (' + sql + ')', args);
return WinJS.Promise.wrap(row.cnt);
},
itemsFromIndex: function (requestIndex, countBefore, countAfter) {
var items,
limit = countBefore + 1 + countAfter,
offset = requestIndex - countBefore;
items = db.map(
'SELECT * FROM (' + sql + ') LIMIT ' + limit + ' OFFSET ' + offset,
function (row) {
var item = {
key: row[keyColumnName].toString(),
data: row
};
if (groupKeyColumnName) {
item.groupKey = row[groupKeyColumnName].toString();
}
return item;
});
return WinJS.Promise.wrap({
items: items,
offset: countBefore,
atEnd: items.length < limit
});
}
};
this._baseDataSourceConstructor(dataAdapter);
}
);
GroupDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource,
function (db, sql, args, keyColumnName, sizeColumnName) {
var groups,
dataAdapter,
keyIndexMap = {},
groupIndex = 0,
firstItemIndex = 0;
groups = db.map(sql, args, function (row) {
var item = {
key: row[keyColumnName].toString(),
groupSize: row[sizeColumnName],
firstItemIndexHint: firstItemIndex,
data: row
};
keyIndexMap[item.key] = groupIndex;
groupIndex += 1;
firstItemIndex += item.groupSize;
return item;
});
dataAdapter = {
getCount: function () {
return WinJS.Promise.wrap(groups.length);
},
itemsFromIndex: function (requestIndex, countBefore, countAfter) {
return WinJS.Promise.wrap({
items: groups.slice(),
offset: requestIndex,
absoluteIndex: requestIndex,
atStart: true,
atEnd: true
});
},
itemsFromKey: function (key, countBefore, countAfter) {
return this.itemsFromIndex(keyIndexMap[key], countBefore, countAfter);
}
};
this._baseDataSourceConstructor(dataAdapter);
}
);
WinJS.Namespace.define('SQLite3JS', {
Database: Database
});
}());

View File

@ -0,0 +1,174 @@
var dbmap = {};
var nextTick = window.setImmediate || function(fun) {
window.setTimeout(fun, 0);
};
/* **
function handle(p, win, fail) {
if (p)
p.done(
function (res) {
if (res[1])
fail(res[1]);
else
win(res[0]?JSON.parse(res[0]):[]);
},
function (err) {
fail(err);
}
);
}
// */
module.exports = {
echoStringValue: function(win, fail, args) {
var options = args[0];
win(options.value);
},
open: function(win, fail, args) {
var options = args[0];
var res;
function openImmediate(dbname) {
if (!!dbmap[dbname]) {
// NO LONGER EXPECTED due to BUG 666 workaround solution:
fail("INTERNAL ERROR: database already open for dbname: " + dbname);
}
// from @EionRobb / phonegap-win8-sqlite:
var opendbname = Windows.Storage.ApplicationData.current.localFolder.path + "\\" + dbname;
console.log("open db name: " + dbname + " at full path: " + opendbname);
var db = new SQLite3JS.Database(opendbname);
dbmap[dbname] = db;
nextTick(function() {
win();
});
//res = SQLitePluginRT.SQLitePlugin.openAsync(options.name);
}
try {
//res = SQLitePluginRT.SQLitePlugin.openAsync(options.name);
var dbname = options.name;
openImmediate(dbname);
} catch(ex) {
//fail(ex);
nextTick(function() {
fail(ex);
});
}
//handle(res, win, fail);
},
close: function(win, fail, args) {
var options = args[0];
var res;
try {
var dbname = options.path;
nextTick(function() {
var rc = 0;
var db = dbmap[dbname];
if (!db) {
fail("CLOSE ERROR: cannot find db object for dbname: " + dbname);
} else if ((rc = db.close()) !== 0) {
fail("CLOSE ERROR CODE: " + rc);
} else {
delete dbmap[dbname];
win();
}
});
} catch (ex) {
fail(ex);
}
},
backgroundExecuteSqlBatch: function(win, fail, args) {
var options = args[0];
var dbname = options.dbargs.dbname;
var executes = options.executes;
var db = dbmap[dbname];
var results = [];
var i, count=executes.length;
//console.log("executes: " + JSON.stringify(executes));
//console.log("execute sql count: " + count);
for (i=0; i<count; ++i) {
var e = executes[i];
//console.log("execute sql: " + e.sql + " params: " + JSON.stringify(e.params));
try {
var oldTotalChanges = db.totalChanges();
var rows = db.all(e.sql, e.params);
//console.log("got rows: " + JSON.stringify(rows));
var rowsAffected = db.totalChanges() - oldTotalChanges;
var result = { rows: rows, rowsAffected: rowsAffected };
if (rowsAffected > 0) {
var lastInsertRowid = db.lastInsertRowid();
if (lastInsertRowid !== 0) result.insertId = lastInsertRowid;
}
results.push({
type: "success",
result: result
});
} catch(ex) {
console.log("sql exception error: " + ex.message);
results.push({
type: "error",
result: { message: ex.message, code: 0 }
});
}
}
//console.log("return results: " + JSON.stringify(results));
nextTick(function() {
//console.log("return results: " + JSON.stringify(results));
win(results);
});
},
"delete": function(win, fail, args) {
var options = args[0];
var res;
try {
//res = SQLitePluginRT.SQLitePlugin.deleteAsync(JSON.stringify(options));
var dbname = options.path;
WinJS.Application.local.exists(dbname).then(function(isExisting) {
if (!isExisting) {
// XXX FUTURE TBD consistent for all platforms:
fail("file does not exist");
return;
}
if (!!dbmap[dbname]) {
dbmap[dbname].close_v2();
delete dbmap[dbname];
}
//console.log('test db name: ' + dbname);
Windows.Storage.ApplicationData.current.localFolder.getFileAsync(dbname)
.then(function (dbfile) {
//console.log('get db file to delete ok');
return dbfile.deleteAsync(Windows.Storage.StorageDeleteOption.permanentDelete);
}, function (e) {
console.log('get file failure: ' + JSON.stringify(e));
// XXX FUTURE TBD consistent for all platforms:
fail(e);
}).then(function () {
//console.log('delete ok');
win();
}, function (e) {
console.log('delete failure: ' + JSON.stringify(e));
// XXX FUTURE TBD consistent for all platforms:
fail(e);
});
});
} catch(ex) {
fail(ex);
}
//handle(res, win, fail);
}
};
require("cordova/exec/proxy").add("SQLitePlugin", module.exports);