999 lines
33 KiB
C++
999 lines
33 KiB
C++
//
|
|
// storagenodedbaccess.cpp
|
|
//
|
|
// Created by Frank Vernon on 3/20/14.
|
|
// Copyright (c) 2014 IOnU. All rights reserved.
|
|
// Copyright (c) 2016, Sequence Logic, Inc. All rights reserved.
|
|
//
|
|
|
|
#include "storagenodedbaccess.h"
|
|
#include "storagenodedbaccess_java.h"
|
|
#include "../cppcoreobjects/cloudguardurn.h"
|
|
#include "../cppcoreobjects/permissions.h"
|
|
#include "eyetime.h"
|
|
#include "eyelog.h"
|
|
#include "eyeutils.h"
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
using namespace sequencelogic;
|
|
|
|
|
|
/**
|
|
SQLite3 routine to extract a value from JSON.
|
|
This is presently limted to elements at the root level of the JSON object.
|
|
Non-scalar values are returned as BLOBs in JSON format. You could presumably call this again
|
|
with that result until you get to the scalar value you want.
|
|
|
|
The routine expects two arguments: key, and json. Both as text.
|
|
*/
|
|
#ifndef WIN32
|
|
static void value_from_json(sqlite3_context * context, int argc, sqlite3_value ** argv) __attribute__ ((unused));
|
|
#endif
|
|
static void value_from_json(sqlite3_context * context, int argc, sqlite3_value ** argv)
|
|
{
|
|
//check we have what we need
|
|
if (argc != 2 ||
|
|
sqlite3_value_type(argv[0]) == SQLITE_NULL ||
|
|
sqlite3_value_type(argv[1]) == SQLITE_NULL)
|
|
{
|
|
sqlite3_result_null(context);
|
|
}
|
|
|
|
sequencelogic::JSONObject parser(reinterpret_cast<const char *>(sqlite3_value_text(argv[1])));
|
|
sequencelogic::JSONObject value = parser.getJSONObject(reinterpret_cast<const char *>(sqlite3_value_text(argv[0])));
|
|
|
|
switch (value.gettype()) {
|
|
case T_JSON::J_NUMBER:
|
|
sqlite3_result_double(context, value.getdouble());
|
|
break;
|
|
|
|
case T_JSON::J_STRING: {
|
|
const std::string result = value.getstring();
|
|
char * returnValue = (char *)sqlite3_malloc((int)result.length());
|
|
memcpy(returnValue, result.c_str(), result.length());
|
|
sqlite3_result_text(context, result.c_str(), (int)result.length(), sqlite3_free);
|
|
}
|
|
break;
|
|
|
|
case T_JSON::J_BOOLEAN:
|
|
sqlite3_result_int(context, value.getboolean() ? 1 : 0);
|
|
break;
|
|
|
|
case T_JSON::J_OBJECT:
|
|
case T_JSON::J_ARRAY: {
|
|
const std::string result = value.toString();
|
|
char * returnValue = (char *)sqlite3_malloc((int)result.length());
|
|
memcpy(returnValue, result.c_str(), result.length());
|
|
sqlite3_result_blob(context, result.c_str(), (int)result.length(), sqlite3_free);
|
|
}
|
|
break;
|
|
|
|
case T_JSON::J_NULL:
|
|
default:
|
|
sqlite3_result_null(context);
|
|
break;
|
|
}
|
|
}
|
|
|
|
namespace sequencelogic {
|
|
|
|
//#pragma mark - StorageNodeDBAccess
|
|
|
|
StorageNodeDBAccess::StorageNodeDBAccess()
|
|
:EyeDB(), _tableInitialized(false)
|
|
{
|
|
}
|
|
|
|
//NOTE: This method will also be responsible for migrating database changes as necessary.
|
|
bool
|
|
StorageNodeDBAccess::initDB(const std::string & dbFilePath)
|
|
{
|
|
std::lock_guard<std::mutex> lock(_protectInit);
|
|
_tableInitialized = false;
|
|
|
|
if (!EyeDB::open(dbFilePath.c_str())) {
|
|
return false;
|
|
}
|
|
|
|
static std::string const tableQuery =
|
|
"create table if not exists 'storageguard' ( \
|
|
'urn' TEXT, \
|
|
'mount' TEXT, \
|
|
'signature' TEXT, \
|
|
'path' TEXT, \
|
|
'parent' TEXT, \
|
|
'mime_type' TEXT, \
|
|
'nodeJSON' BLOB, \
|
|
'metadata_utime' INTEGER, \
|
|
'metadata_status' INTEGER, \
|
|
'permission_status' INTEGER, \
|
|
UNIQUE (urn) on conflict replace)";
|
|
|
|
//determine existing table matches table hash
|
|
std::string digest(DigestMessage("sha1", (const unsigned char *)tableQuery.c_str(), tableQuery.length()));
|
|
if (getTableHash() != digest) {
|
|
IONUWARN("StorageNodeDBAccess::initDB Drop \'storageguard\' table based on digest change.\n");
|
|
executeQuery("drop table if exists 'storageguard'");
|
|
if (executeQuery(tableQuery)) {
|
|
setTableHash(digest);
|
|
}
|
|
}
|
|
|
|
_tableInitialized = getTableHash() == digest;
|
|
|
|
return _tableInitialized;
|
|
}
|
|
|
|
StorageNodeVector
|
|
StorageNodeDBAccess::getNodes(const StorageNode & node)
|
|
{
|
|
StorageNodeVector result;
|
|
// try a partial match
|
|
static std::string const query =
|
|
"select * from storageguard where \
|
|
mount like ? \
|
|
and signature like ? \
|
|
and path like ? \
|
|
";
|
|
//get query parameter or convert to wildcard if nil
|
|
std::string mount = makeSQLWildcardIfNecessary(node.getMount());
|
|
std::string signature = makeSQLWildcardIfNecessary(node.getSignature());
|
|
std::string path = makeSQLWildcardIfNecessary(node.getPath());
|
|
if (path != "%")
|
|
{
|
|
path = replaceFilesystemWildcard(path);
|
|
}
|
|
|
|
uint16_t bindPos = 0;
|
|
statement statement(*this, query);
|
|
if (statement.isPrepared() &&
|
|
statement.bind(++bindPos, mount) &&
|
|
statement.bind(++bindPos, signature) &&
|
|
statement.bind(++bindPos, path))
|
|
{
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
for (STRING_STRING_MAP & node : nodes) {
|
|
result.push_back(StorageNodePtr(new StorageNode(node["nodeJSON"])));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
StorageNodeVector
|
|
StorageNodeDBAccess::getNodesInDirectory(const StorageNode & node)
|
|
{
|
|
//Get nodes for parent
|
|
static std::string const query =
|
|
"select * from storageguard where \
|
|
mount is ? \
|
|
and signature is ? \
|
|
and parent is ? \
|
|
";
|
|
|
|
StorageNodeVector result;
|
|
std::string mount = makeSQLWildcardIfNecessary(node.getMount());
|
|
std::string signature = makeSQLWildcardIfNecessary(node.getSignature());
|
|
std::string parent = node.getURN();
|
|
|
|
uint16_t bindPos = 0;
|
|
statement statement(*this, query);
|
|
if (statement.isPrepared() &&
|
|
statement.bind(++bindPos, mount) &&
|
|
statement.bind(++bindPos, signature) &&
|
|
statement.bind(++bindPos, parent))
|
|
{
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
for (STRING_STRING_MAP & node : nodes) {
|
|
result.push_back(StorageNodePtr(new StorageNode(node["nodeJSON"])));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
StorageNodeVector
|
|
StorageNodeDBAccess::getNodesByPath(const StorageNode & node)
|
|
{
|
|
StorageNodeVector result;
|
|
|
|
std::string path = node.getPath();
|
|
if (!path.empty()) {
|
|
static std::string const query = "select * from storageguard where path like ?";
|
|
|
|
path = makeSQLWildcardIfNecessary(node.getPath());
|
|
if (path != "%")
|
|
{
|
|
path = replaceFilesystemWildcard(path);
|
|
}
|
|
|
|
statement statement(*this, query);
|
|
if (statement.isPrepared() &&
|
|
statement.bind(1, path))
|
|
{
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
//this should only be a single result but we'll do this just in case
|
|
// the upstream consumer might want to interrogate the result to figure out
|
|
// what is going on.
|
|
for (STRING_STRING_MAP & node : nodes) {
|
|
result.push_back(StorageNodePtr(new StorageNode(node["nodeJSON"])));
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
StorageNodeVector
|
|
StorageNodeDBAccess::getNodesByPathForMountAndSignature(const StorageNode & node)
|
|
{
|
|
StorageNodeVector result;
|
|
|
|
static std::string const query = "select * from storageguard where mount like ? and signature like ? and path like ?";
|
|
|
|
std::string mount = makeSQLWildcardIfNecessary(node.getMount());
|
|
std::string signature = makeSQLWildcardIfNecessary(node.getSignature());
|
|
std::string path = makeSQLWildcardIfNecessary(node.getPath());
|
|
if (path != "%")
|
|
{
|
|
path = replaceFilesystemWildcard(path);
|
|
}
|
|
|
|
uint16_t bindPos = 0;
|
|
statement statement(*this, query);
|
|
if (statement.isPrepared() &&
|
|
statement.bind(++bindPos, mount) &&
|
|
statement.bind(++bindPos, signature) &&
|
|
statement.bind(++bindPos, path))
|
|
{
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
//this should only be a single result but we'll do this just in case
|
|
// the upstream consumer might want to interrogate the result to figure out
|
|
// what is going on.
|
|
for (STRING_STRING_MAP & node : nodes) {
|
|
result.push_back(StorageNodePtr(new StorageNode(node["nodeJSON"])));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
StorageNodeVector
|
|
StorageNodeDBAccess::getNodesByStatus(const StorageNode & node)
|
|
{
|
|
StorageNodeVector result;
|
|
|
|
// Finding deleted nodes is a common use case; deleted files can not be discovered
|
|
// using the local file system
|
|
static std::string const query =
|
|
"select * from storageguard where \
|
|
mount like ? \
|
|
and metadata_status like ? \
|
|
and signature like ? \
|
|
and path like ? \
|
|
";
|
|
|
|
//get query parameter or convert to wildcard if nil
|
|
std::string mount = makeSQLWildcardIfNecessary(node.getMount());
|
|
int metadata_status = (int) node.getStatus();
|
|
std::string signature = makeSQLWildcardIfNecessary(node.getSignature());
|
|
std::string path = makeSQLWildcardIfNecessary(node.getPath());
|
|
if (path != "%")
|
|
{
|
|
path = replaceFilesystemWildcard(path);
|
|
}
|
|
|
|
uint16_t bindPos = 0;
|
|
statement statement(*this, query);
|
|
if (statement.isPrepared() &&
|
|
statement.bind(++bindPos, mount) &&
|
|
statement.bind(++bindPos, metadata_status) &&
|
|
statement.bind(++bindPos, signature) &&
|
|
statement.bind(++bindPos, path))
|
|
{
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
for (STRING_STRING_MAP & node : nodes) {
|
|
result.push_back(StorageNodePtr(new StorageNode(node["nodeJSON"])));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
StorageNodeVector
|
|
StorageNodeDBAccess::getNodesByUniformResourceName(const StorageNode & node)
|
|
{
|
|
StorageNodeVector result;
|
|
|
|
std::string urn = node.getURN();
|
|
if (!urn.empty()) {
|
|
static std::string const query = "select * from storageguard where urn is ?";
|
|
|
|
statement statement(*this, query);
|
|
if (statement.isPrepared() &&
|
|
statement.bind(1, urn))
|
|
{
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
//this should only be a single result but we'll do this just in case
|
|
// the upstream consumer might want to interrogate the result to figure out
|
|
// what is going on.
|
|
for (STRING_STRING_MAP & node : nodes) {
|
|
result.push_back(StorageNodePtr(new StorageNode(node["nodeJSON"])));
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
StorageNodeDBAccess::replaceNode(const StorageNode & node) {
|
|
|
|
//prepare statement
|
|
static std::string const query = "replace into storageguard (urn, mount, signature, path, parent, mime_type, nodeJSON, metadata_utime, metadata_status, permission_status) values (?,?,?,?,?,?,?,?,?,?)";
|
|
|
|
statement statement(*this, query);
|
|
|
|
std::string urn = node.getURN();
|
|
std::string mount = node.getMount();
|
|
std::string signature = node.getSignature();
|
|
std::string path = node.getPath();
|
|
std::string parent = node.getParent();
|
|
std::string mimeType = node.getMimeType();
|
|
int status = node.getStatus();
|
|
int permStatus = node.getInt(SGDB_PERM_STATUS);
|
|
sqlite3_int64 utime = node.getutime().GetTimeMs();
|
|
std::string nodeJSON = node.toString();
|
|
|
|
if (urn.length() == 0) {
|
|
std::cout << "Bad document URN in database insert." << std::endl;
|
|
}
|
|
|
|
uint16_t bindPos = 0;
|
|
if (statement.isPrepared() &&
|
|
statement.bind(++bindPos, urn) &&
|
|
statement.bind(++bindPos, mount) &&
|
|
statement.bind(++bindPos, signature) &&
|
|
statement.bind(++bindPos, path) &&
|
|
statement.bind(++bindPos, parent) &&
|
|
statement.bind(++bindPos, mimeType) &&
|
|
statement.bind(++bindPos, (const void*)nodeJSON.data(), (int)nodeJSON.length()) &&
|
|
statement.bind(++bindPos, utime) &&
|
|
statement.bind(++bindPos, status) &&
|
|
statement.bind(++bindPos, permStatus))
|
|
{
|
|
int result = statement.step();
|
|
if (result != SQLITE_DONE) {
|
|
IONUDEBUG("StorageNodeDBAccess::putNode() - sqlite3_step failed %d", result);
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
StorageNodeDBAccess::putNode(const StorageNode & node)
|
|
{
|
|
transaction transaction(*this);
|
|
|
|
//add children as necessary
|
|
StorageNodeVector children = node.getChildren();
|
|
if (children.size() > 0) {
|
|
for (StorageNodePtr & child : children) {
|
|
if (!putNode(*child)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//insert node
|
|
else if (!replaceNode(node)) {
|
|
return false;
|
|
}
|
|
|
|
transaction.commit();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
StorageNodeDBAccess::deleteNodes(const StorageNode & node)
|
|
{
|
|
transaction transaction(*this);
|
|
|
|
//do children first
|
|
StorageNodeVector children = node.getChildren();
|
|
for (StorageNodePtr & child : children) {
|
|
if (!deleteNodes(*child)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//delete the node, prefer urn if specified
|
|
std::string urn = node.getURN();
|
|
if (!urn.empty() && CloudGuardURN(urn).getType() == CloudGuardURN::PMO_DEVICE_DOCUMENT) {
|
|
static std::string const query = "delete from storageguard where urn is ?";
|
|
statement statement(*this, query);
|
|
if (statement.isPrepared() && statement.bind(1, urn))
|
|
{
|
|
int result = statement.step();
|
|
if (result != SQLITE_DONE) {
|
|
IONUDEBUG("StorageNodeDBAccess::deleteNodes() - sqlite3_step failed %d", result);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
static std::string const query =
|
|
"delete from storageguard where \
|
|
mount like ? \
|
|
and signature like ? \
|
|
and path like ? \
|
|
";
|
|
//get query parameter or convert to wildcard if nil
|
|
std::string mount = makeSQLWildcardIfNecessary(node.getMount());
|
|
std::string signature = makeSQLWildcardIfNecessary(node.getSignature());
|
|
std::string path = makeSQLWildcardIfNecessary(node.getPath());
|
|
if (path != "%")
|
|
{
|
|
path = replaceFilesystemWildcard(path);
|
|
}
|
|
|
|
uint16_t bindPos = 0;
|
|
statement statement(*this, query);
|
|
if (statement.isPrepared() &&
|
|
statement.bind(++bindPos, mount) &&
|
|
statement.bind(++bindPos, signature) &&
|
|
statement.bind(++bindPos, path))
|
|
{
|
|
int result = statement.step();
|
|
if (result != SQLITE_DONE) {
|
|
IONUDEBUG("StorageNodeDBAccess::deleteNodes() - sqlite3_step failed %d", result);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
transaction.commit();
|
|
|
|
return true;
|
|
}
|
|
|
|
StorageNodePtr
|
|
StorageNodeDBAccess::listChildren(const StorageNode & parent,
|
|
const StorageNode & startingNode,
|
|
int32_t limit,
|
|
const std::string & sort,
|
|
bool sortAscending)
|
|
{
|
|
std::string parentURN = parent.getURN();
|
|
std::string startingNodeURN = startingNode.getURN();
|
|
if (parentURN.empty() ||
|
|
startingNodeURN.empty())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
std::string query = "select * from storageguard where parent is ?";
|
|
|
|
sequencelogic::StorageNodeStatus status = parent.getStatus();
|
|
bool haveStatus = false;
|
|
if (status != sequencelogic::StorageNodeStatus::unknown) {
|
|
query += " and metadata_status is ?";
|
|
haveStatus = true;
|
|
}
|
|
|
|
int permStatus = parent.getInt(SGDB_PERM_STATUS);
|
|
bool havePermStatus = false;
|
|
if (permStatus != 0) {
|
|
query += " and permission_status is ?";
|
|
havePermStatus = true;
|
|
}
|
|
|
|
//special case utime sort
|
|
//this may need to be extended to other columns
|
|
bool haveOffset = false;
|
|
bool haveLimit = false;
|
|
if (sort == "metadata_utime") {
|
|
query += " and metadata_utime";
|
|
query += sortAscending ? " >" : " <";
|
|
query += " (select metadata_utime from storageguard where urn is ?) order by metadata_utime";
|
|
query += sortAscending ? " ASC" : " DESC";
|
|
|
|
haveOffset = true;
|
|
|
|
//Do limit in the query in the simple case
|
|
if (limit > 0) {
|
|
haveLimit = true;
|
|
query += " LIMIT ";
|
|
std::stringstream limitStr;
|
|
limitStr << limit;
|
|
query += limitStr.str();
|
|
}
|
|
}
|
|
|
|
//prepare and execute statement
|
|
int bindPos = 0;
|
|
statement statement(*this, query);
|
|
if (statement.bind(++bindPos, parentURN))
|
|
{
|
|
//bind status if necessary
|
|
if (haveStatus) {
|
|
statement.bind(++bindPos, status);
|
|
}
|
|
|
|
if (havePermStatus) {
|
|
statement.bind(++bindPos, havePermStatus);
|
|
}
|
|
|
|
//bind offset if necessary
|
|
if (haveOffset) {
|
|
statement.bind(++bindPos, startingNodeURN);
|
|
}
|
|
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
|
|
//sort
|
|
if (sort.length() > 0 && sort != "metadata_utime") {
|
|
MapVectorSortFunctor sorter(sort, sortAscending);
|
|
std::sort(nodes.begin(), nodes.end(), sorter);
|
|
}
|
|
|
|
//offset
|
|
if (!haveOffset) {
|
|
//ugly... have to walk array to find our starting point
|
|
MapVectorFindFunctor finder("urn", startingNodeURN);
|
|
MAP_VECTOR::iterator node_offset = std::find_if(nodes.begin(), nodes.end(), finder);
|
|
if (node_offset != nodes.end()) {
|
|
nodes.erase(nodes.begin(), node_offset);
|
|
}
|
|
}
|
|
|
|
//limit
|
|
if (!haveLimit && nodes.size() > (MAP_VECTOR::size_type)abs(limit)) {
|
|
if (limit > 0) {
|
|
nodes.erase(nodes.begin()+abs(limit), nodes.end());
|
|
}
|
|
else if (limit < 0)
|
|
{
|
|
nodes.erase(nodes.begin(), nodes.end()-abs(limit));
|
|
}
|
|
}
|
|
|
|
//create result...
|
|
StorageNodePtr result = StorageNodePtr(new StorageNode(parent));
|
|
|
|
StorageNodeVector children;
|
|
for (STRING_STRING_MAP & node : nodes) {
|
|
children.push_back(StorageNodePtr(new StorageNode(node["nodeJSON"])));
|
|
}
|
|
|
|
result->setChildren(children);
|
|
|
|
return result;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
StorageNodePtr
|
|
StorageNodeDBAccess::listChildren(const StorageNode & parent,
|
|
int32_t offset,
|
|
int32_t limit,
|
|
const std::string & sort,
|
|
bool sortAscending)
|
|
{
|
|
std::string parentURN = parent.getURN();
|
|
if (parentURN.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::string query = "select * from storageguard where parent is ?";
|
|
|
|
sequencelogic::StorageNodeStatus status = parent.getStatus();
|
|
bool haveStatus = false;
|
|
if (status != sequencelogic::StorageNodeStatus::unknown) {
|
|
query += " and metadata_status is ?";
|
|
haveStatus = true;
|
|
}
|
|
|
|
int permStatus = parent.getInt(SGDB_PERM_STATUS);
|
|
bool havePermStatus = false;
|
|
if (permStatus != 0) {
|
|
query += " and permission_status is ?";
|
|
havePermStatus = true;
|
|
}
|
|
|
|
//special case utime sort
|
|
//this may need to be extended to other columns
|
|
bool haveOffset = false;
|
|
bool haveLimit = false;
|
|
if (sort == "metadata_utime") {
|
|
query += " order by metadata_utime";
|
|
query += sortAscending ? " ASC" : " DESC";
|
|
|
|
//Do the offset and limit in the query in the simple case
|
|
// ...the other cases make my head hurt
|
|
if (limit > 0) {
|
|
haveLimit = true;
|
|
query += " LIMIT ";
|
|
std::stringstream limitStr;
|
|
limitStr << limit;
|
|
query += limitStr.str();
|
|
}
|
|
|
|
if (offset > 0) {
|
|
haveOffset = true;
|
|
query += " OFFSET ";
|
|
std::stringstream offsetStr;
|
|
offsetStr << offset;
|
|
query += offsetStr.str();
|
|
}
|
|
}
|
|
|
|
//prepare and execute statement
|
|
int bindPos = 0;
|
|
statement statement(*this, query);
|
|
if (statement.bind(++bindPos, parentURN))
|
|
{
|
|
//bind status if necessary
|
|
if (haveStatus) {
|
|
statement.bind(++bindPos, status);
|
|
}
|
|
|
|
if (havePermStatus) {
|
|
statement.bind(++bindPos, permStatus);
|
|
}
|
|
|
|
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
|
|
//sort
|
|
if (sort.length() > 0 && sort != "metadata_utime") {
|
|
MapVectorSortFunctor sorter(sort, sortAscending);
|
|
std::sort(nodes.begin(), nodes.end(), sorter);
|
|
}
|
|
|
|
//offset
|
|
if (!haveOffset) {
|
|
if (nodes.size() >= static_cast<size_t>(abs(offset))) {
|
|
if (offset > 0) {
|
|
nodes.erase(nodes.begin(), nodes.begin()+abs(offset));
|
|
}
|
|
else if (offset < 0) {
|
|
nodes.erase(nodes.begin(), nodes.end()-abs(offset));
|
|
}
|
|
} else if (abs(offset) > 0) {
|
|
nodes.erase(nodes.begin(), nodes.end());
|
|
}
|
|
}
|
|
|
|
//limit
|
|
if (!haveLimit && nodes.size() > (MAP_VECTOR::size_type)abs(limit)) {
|
|
if (limit > 0) {
|
|
nodes.erase(nodes.begin()+abs(limit), nodes.end());
|
|
}
|
|
else if (limit < 0)
|
|
{
|
|
nodes.erase(nodes.begin(), nodes.end()-abs(limit));
|
|
}
|
|
}
|
|
|
|
//create result...
|
|
StorageNodePtr result = StorageNodePtr(new StorageNode(parent));
|
|
|
|
StorageNodeVector children;
|
|
for (STRING_STRING_MAP & node : nodes) {
|
|
children.push_back(StorageNodePtr(new StorageNode(node["nodeJSON"])));
|
|
}
|
|
|
|
result->setChildren(children);
|
|
|
|
return result;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
int32_t
|
|
StorageNodeDBAccess::countChildren(const StorageNode & parent)
|
|
{
|
|
std::string parentURN = parent.getURN();
|
|
if (parentURN.empty()) {
|
|
return 0;
|
|
}
|
|
|
|
std::string query = "select count(*) as rows from storageguard where parent is ? ";
|
|
|
|
sequencelogic::StorageNodeStatus status = parent.getStatus();
|
|
bool haveStatus = false;
|
|
if (status != sequencelogic::StorageNodeStatus::unknown) {
|
|
query += " and metadata_status is ?";
|
|
haveStatus = true;
|
|
}
|
|
|
|
int permStatus = parent.getInt(SGDB_PERM_STATUS);
|
|
bool havePermStatus = false;
|
|
if (permStatus != 0) {
|
|
query += " and permission_status is ?";
|
|
havePermStatus = true;
|
|
}
|
|
|
|
statement statement(*this, query);
|
|
int bindPos = 0;
|
|
if (statement.bind(++bindPos, parentURN))
|
|
{
|
|
//bind status if necessary
|
|
if (haveStatus) {
|
|
statement.bind(++bindPos, status);
|
|
}
|
|
|
|
if (havePermStatus) {
|
|
statement.bind(++bindPos, permStatus);
|
|
}
|
|
|
|
MAP_VECTOR nodes = fetchResults(statement);
|
|
std::string resultString = nodes[0]["rows"];
|
|
return (int32_t)std::atol(resultString.c_str());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t
|
|
StorageNodeDBAccess::rowCount()
|
|
{
|
|
int32_t result = -1;
|
|
|
|
static std::string const query = "select count(*) as rows from storageguard";
|
|
statement queryStatement(*this, query);
|
|
if (queryStatement.isPrepared()) {
|
|
MAP_VECTOR nodes = fetchResults(queryStatement);
|
|
std::string resultString = nodes[0]["rows"];
|
|
result = (int32_t)std::atol(resultString.c_str());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//#pragma mark - Utilities
|
|
|
|
std::string
|
|
StorageNodeDBAccess::getTableHash()
|
|
{
|
|
std::string tableHash;
|
|
|
|
static std::string const query = "select hash from version";
|
|
statement queryStatement(*this, query);
|
|
if (queryStatement.isPrepared()) {
|
|
MAP_VECTOR result = fetchResults(queryStatement);
|
|
if (result.size() > 0) {
|
|
tableHash = result[0]["hash"];
|
|
}
|
|
}
|
|
|
|
return tableHash;
|
|
}
|
|
|
|
bool
|
|
StorageNodeDBAccess::setTableHash(const std::string & tableHash)
|
|
{
|
|
static std::string const versionTable = "create table if not exists 'version' (hash)";
|
|
if (executeQuery(versionTable)) {
|
|
static std::string const clearTableQuery = "delete from version";
|
|
executeQuery(clearTableQuery);
|
|
|
|
static std::string const updateTableQuery = "insert into version values (?)";
|
|
statement updateStatement(*this, updateTableQuery);
|
|
updateStatement.bind(1, tableHash);
|
|
int result = updateStatement.step();
|
|
return result == SQLITE_DONE;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//might promote this to the EyeDB class, could be generally useful
|
|
std::string
|
|
StorageNodeDBAccess::makeSQLWildcardIfNecessary(const std::string & string)
|
|
{
|
|
if (string.length() == 0) {
|
|
return "%";
|
|
}
|
|
|
|
return string;
|
|
}
|
|
|
|
std::string
|
|
StorageNodeDBAccess::replaceFilesystemWildcard(const std::string & string)
|
|
{
|
|
std::string result(string);
|
|
|
|
// escape existing wildcard characters presuming they are
|
|
// expected parts of the filesystem query
|
|
ReplaceStringInSitu(result, "%", "\\%");
|
|
ReplaceStringInSitu(result, "?", "\\?");
|
|
|
|
#ifdef WIN32
|
|
// replace windows directory wildcard
|
|
// do this before * substitution below to avoid conflicts
|
|
ReplaceStringInSitu(result, "**", "%");
|
|
#endif
|
|
|
|
// replace all multi char matches
|
|
std::replace(result.begin(), result.end(), '*', '%');
|
|
|
|
// replace all single char matches
|
|
std::replace(result.begin(), result.end(), '?', '_');
|
|
|
|
// character set notation should be the same
|
|
|
|
return result;
|
|
}
|
|
|
|
//#pragma mark - StorageNodeDBAccessJava
|
|
|
|
StorageNodeDBAccessJava::StorageNodeDBAccessJava()
|
|
{
|
|
}
|
|
StorageNodeDBAccessJava::~StorageNodeDBAccessJava()
|
|
{
|
|
}
|
|
|
|
bool
|
|
StorageNodeDBAccessJava::initDB(const std::string & dbFilePath)
|
|
{
|
|
return dbAccess.initDB(dbFilePath);
|
|
}
|
|
|
|
StorageNodeDBAccessJava::STRING_VECTOR_PTR
|
|
StorageNodeDBAccessJava::getNodes(const std::string & nodeJSON)
|
|
{
|
|
StorageNode node(nodeJSON);
|
|
StorageNodeVector nodes = dbAccess.getNodes(node);
|
|
|
|
STRING_VECTOR_PTR result(new STRING_VECTOR);
|
|
for (const StorageNode resultNode : nodes) {
|
|
result->push_back(resultNode.toString());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string
|
|
StorageNodeDBAccessJava::listChildren(const std::string & parentJSON,
|
|
const std::string & startingNodeJSON,
|
|
int32_t limit,
|
|
const std::string & sort,
|
|
bool sortAscending)
|
|
{
|
|
StorageNode node(parentJSON);
|
|
StorageNode startingNode(startingNodeJSON);
|
|
StorageNodePtr result = dbAccess.listChildren(node, startingNode, limit, sort, sortAscending);
|
|
|
|
if (result != nullptr) {
|
|
return result->toString();
|
|
} else {
|
|
return "";
|
|
}
|
|
|
|
}
|
|
|
|
std::string
|
|
StorageNodeDBAccessJava::listChildren(const std::string & parentJSON,
|
|
int32_t offset,
|
|
int32_t limit,
|
|
const std::string & sort,
|
|
bool sortAscending)
|
|
{
|
|
StorageNode node(parentJSON);
|
|
StorageNodePtr result = dbAccess.listChildren(node, offset, limit, sort, sortAscending);
|
|
|
|
if (result != nullptr) {
|
|
return result->toString();
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
bool
|
|
StorageNodeDBAccessJava::putNode(const std::string & nodeJSON)
|
|
{
|
|
StorageNode node(nodeJSON);
|
|
return dbAccess.putNode(node);
|
|
}
|
|
|
|
int
|
|
StorageNodeDBAccessJava::rowCount()
|
|
{
|
|
return dbAccess.rowCount();
|
|
}
|
|
|
|
int
|
|
StorageNodeDBAccessJava::countChildren(const std::string & parent)
|
|
{
|
|
StorageNode node(parent);
|
|
return dbAccess.countChildren(node);
|
|
}
|
|
|
|
StorageNodeDBAccessJava::STRING_VECTOR_PTR
|
|
StorageNodeDBAccessJava::getNodesInDirectory(const std::string & nodeJSON)
|
|
{
|
|
StorageNode node(nodeJSON);
|
|
|
|
StorageNodeVector nodeVec = dbAccess.getNodesInDirectory(node);
|
|
STRING_VECTOR_PTR result(new STRING_VECTOR);
|
|
for (const StorageNode resultNode : nodeVec)
|
|
result->push_back(resultNode.toString());
|
|
|
|
return result;
|
|
}
|
|
|
|
StorageNodeDBAccessJava::STRING_VECTOR_PTR
|
|
StorageNodeDBAccessJava::getNodesByPath(const std::string & nodeJSON)
|
|
{
|
|
StorageNode node(nodeJSON);
|
|
|
|
StorageNodeVector nodeVec = dbAccess.getNodesByPath(node);
|
|
STRING_VECTOR_PTR result(new STRING_VECTOR);
|
|
for (const StorageNode resultNode : nodeVec)
|
|
result->push_back(resultNode.toString());
|
|
|
|
return result;
|
|
}
|
|
|
|
StorageNodeDBAccessJava::STRING_VECTOR_PTR
|
|
StorageNodeDBAccessJava::getNodesByPathForMountAndSignature(const std::string & nodeJSON)
|
|
{
|
|
StorageNode node(nodeJSON);
|
|
|
|
StorageNodeVector nodeVec = dbAccess.getNodesByPathForMountAndSignature(node);
|
|
STRING_VECTOR_PTR result(new STRING_VECTOR);
|
|
for (const StorageNode resultNode : nodeVec)
|
|
result->push_back(resultNode.toString());
|
|
|
|
return result;
|
|
}
|
|
|
|
StorageNodeDBAccessJava::STRING_VECTOR_PTR
|
|
StorageNodeDBAccessJava::getNodesByStatus(const std::string & nodeJSON)
|
|
{
|
|
StorageNode node(nodeJSON);
|
|
|
|
StorageNodeVector nodeVec = dbAccess.getNodesByStatus(node);
|
|
STRING_VECTOR_PTR result(new STRING_VECTOR);
|
|
for (const StorageNode resultNode : nodeVec)
|
|
result->push_back(resultNode.toString());
|
|
|
|
return result;
|
|
}
|
|
|
|
StorageNodeDBAccessJava::STRING_VECTOR_PTR
|
|
StorageNodeDBAccessJava::getNodesByUniformResourceName(const std::string & nodeJSON)
|
|
{
|
|
StorageNode node(nodeJSON);
|
|
|
|
StorageNodeVector nodeVec = dbAccess.getNodesByUniformResourceName(node);
|
|
STRING_VECTOR_PTR result(new STRING_VECTOR);
|
|
for (const StorageNode resultNode : nodeVec)
|
|
result->push_back(resultNode.toString());
|
|
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
StorageNodeDBAccessJava::deleteNodes(const std::string & nodeJSON)
|
|
{
|
|
StorageNode node(nodeJSON);
|
|
return dbAccess.deleteNodes(node);
|
|
}
|
|
}
|