winix/db/db.cpp

1621 lines
29 KiB
C++
Executable File

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2011, Tomasz Sowa
* All rights reserved.
*
*/
#include "db.h"
#include "core/log.h"
#include "core/misc.h"
bool Db::GetUserPass(const std::wstring & login, long & user_id, UserPass & up)
{
PGresult * r = 0;
bool user_ok = false;
user_id = -1;
try
{
query.Clear();
query << R("select id, password, pass_encrypted, pass_type, pass_hash_salted from core.user where login=")
<< login
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
int rows = Rows(r);
if( rows == 0 )
throw Error(WINIX_ERR_DB_INCORRECT_LOGIN);
if( rows > 1 )
{
log << log1 << "Db: there is more than one user: " << login << logend;
throw Error(WINIX_ERR_DB_MORE_THAN_ONE_LOGIN);
}
int cuser_id = AssertColumn(r, "id");
int cpass_type = AssertColumn(r, "pass_type");
int csalted = AssertColumn(r, "pass_hash_salted");
int cpassword = AssertColumn(r, "password");
int cpass_encrypted = AssertColumn(r, "pass_encrypted");
user_ok = true;
user_id = AssertValueLong(r, 0, cuser_id);
up.pass_type = AssertValueInt(r, 0, cpass_type);
up.pass_hash_salted = AssertValueBool(r, 0, csalted);
AssertValueWide(r, 0, cpassword, up.pass);
AssertValueBin(r, 0, cpass_encrypted, up.pass_encrypted);
}
catch(const Error &)
{
}
ClearResult(r);
return user_ok;
}
Error Db::AddUser(User & user, const std::wstring & password, const std::string & password_encrypted,
int pass_type, bool pass_hash_salted)
{
PGresult * r = 0;
Error status = WINIX_ERR_OK;
try
{
query.Clear();
query << R("insert into core.user (login, password, pass_encrypted, super_user, email,"
"notify, pass_type, pass_hash_salted) values (")
<< user.name;
// for safety
if( password_encrypted.empty() )
query << password;
else
query << "";
query.EPutBin(password_encrypted);
query << user.super_user
<< user.email
<< user.notify
<< pass_type
<< pass_hash_salted
<< R(");");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
user.id = AssertCurrval("core.user_id_seq");
}
catch(const Error & e)
{
status = e;
}
ClearResult(r);
return status;
}
Error Db::ChangePass(const std::wstring & login,
const std::wstring & password, const std::string & password_encrypted,
int pass_type, bool pass_hash_salted)
{
query.Clear();
query << R("update core.user set(password, pass_encrypted,"
"pass_type, pass_hash_salted) = (");
// for safety
if( password_encrypted.empty() )
query << password;
else
query << "";
query.EPutBin(password_encrypted);
query << pass_type
<< pass_hash_salted
<< R(") where login=")
<< login
<< R(";");
return DoCommand(query);
}
//!! wywalic z nazwy 'Subject' nic nie jest robione z tytulem
// ta metoda uzywana tez jest w EditParentUrlById()
bool Db::AddItemCreateUrlSubject(Item & item)
{
bool is_that_url;
PGresult * r = 0;
int index = 1;
const int max_index = 99;
wchar_t appendix[20];
size_t appendix_len = sizeof(appendix) / sizeof(wchar_t);
appendix[0] = 0;
// only root dir may not have url
if( item.parent_id != -1 && item.url.empty() )
item.url = L"empty";
try
{
do
{
query_create_url.Clear();
temp_url = item.url;
temp_url += appendix;
query_create_url
<< R("select id from core.item where url=")
<< temp_url
<< R(" and parent_id=")
<< item.parent_id
<< R(";");
r = AssertQuery(query_create_url);
AssertResult(r, PGRES_TUPLES_OK);
if( Rows(r) != 0 )
{
swprintf(appendix, appendix_len, L"_(%d)", ++index);
is_that_url = true;
}
else
{
item.url = temp_url;
is_that_url = false;
}
ClearResult(r);
r = 0;
}
while( is_that_url && index <= max_index );
}
catch(const Error &)
{
is_that_url = true; // for returning false
}
ClearResult(r);
return !is_that_url;
}
Error Db::AddItemIntoItem(Item & item)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
bool url_without_id = false;
try
{
query.Clear();
query << R("insert into core.item (user_id, modification_user_id, group_id, privileges, "
"date_creation, date_modification, type, parent_id, content_id, "
"link_to, link_redirect, subject, guest_name, template, sort_index, url) values (")
<< item.user_id
<< item.modification_user_id
<< item.group_id
<< item.privileges
<< item.date_creation
<< item.date_modification
<< static_cast<int>(item.type)
<< item.parent_id
<< item.content_id
<< item.link_to
<< item.link_redirect
<< item.subject
<< item.guest_name
<< item.html_template
<< item.sort_index;
url_without_id = AddItemCreateUrlSubject(item);
if( url_without_id )
query << item.url;
else
query << R(", currval('core.item_id_seq')"); // !! zrobic test czy to obecnie dziala dobrze
query << R(");");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
item.id = AssertCurrval("core.item_id_seq");
if( !url_without_id )
Toa(item.id, item.url);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::AddItemIntoContent(Item & item)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
int first_ref = 1;
try
{
query.Clear();
query << R("insert into core.content (content, content_type, file_path, file_fs, "
"file_type, has_thumb, hash, hash_type, file_size, ref, modify_index) values (")
<< item.content
<< static_cast<int>(item.content_type)
<< item.file_path
<< item.file_fs
<< item.file_type
<< static_cast<int>(item.has_thumb)
<< item.hash
<< item.hash_type
<< item.file_size
<< first_ref
<< item.modify_index
<< R(");");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
item.content_id = AssertCurrval("core.content_id_seq");
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::AddItem(Item & item)
{
BeginTrans();
Error result = WINIX_ERR_OK;
if( item.type == Item::file )
result = AddItemIntoContent(item);
else
item.content_id = -1;
if( result == WINIX_ERR_OK )
result = AddItemIntoItem(item);
return EndTrans(result);
}
Error Db::IncrementContentRef(long content_id)
{
query.Clear();
query << R("update core.content set (ref) = (ref + 1) where id = ")
<< content_id
<< R(";");
return DoCommand(query);
}
Error Db::DecrementContentRef(long content_id)
{
query.Clear();
query << R("update core.content set (ref) = (ref - 1) where id = ")
<< content_id
<< R(";");
return DoCommand(query);
}
// item.id must be set (it's used by GetContentId)
Error Db::AddHardLink(Item & item)
{
if( item.type != Item::file || item.content_id == -1 )
return WINIX_ERR_FILE_EXPECTED;
BeginTrans();
Error result = IncrementContentRef(item.content_id);
if( result == WINIX_ERR_OK )
result = AddItemIntoItem(item);
return EndTrans(result);
}
Error Db::EditItemInItem(Item & item, bool with_url)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
bool url_without_id = false;
try
{
query.Clear();
query << R("update core.item set (user_id, modification_user_id, group_id, privileges, "
"date_creation, date_modification, type, link_to, link_redirect, parent_id, subject, "
"guest_name, template, sort_index");
if( with_url )
query << R(", url");
query << R(") = (")
<< item.user_id
<< item.modification_user_id
<< item.group_id
<< item.privileges
<< item.date_creation
<< item.date_modification
<< static_cast<int>(item.type)
<< item.link_to
<< item.link_redirect
<< item.parent_id
<< item.subject
<< item.guest_name
<< item.html_template
<< item.sort_index;
if( with_url )
{
url_without_id = AddItemCreateUrlSubject(item);
if( url_without_id )
query << item.url;
else
query << item.id;
}
query << R(") where id=") << item.id << R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
if( with_url && !url_without_id )
Toa(item.id, item.url);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::EditItemInContent(Item & item)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
// we don't change 'ref' here
query.Clear();
query << R("update core.content set (content, content_type, file_path, file_fs, "
"file_type, has_thumb, hash, hash_type, file_size, modify_index) = (")
<< item.content
<< static_cast<int>(item.content_type)
<< item.file_path
<< item.file_fs
<< item.file_type
<< static_cast<int>(item.has_thumb)
<< item.hash
<< item.hash_type
<< item.file_size
<< item.modify_index
<< R(") where id=")
<< item.content_id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
long Db::GetContentId(long item_id)
{
PGresult * r = 0;
long result = -1;
try
{
query.Clear();
query << R("select content_id from core.item where item.id=")
<< item_id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
if( Rows(r) == 1 && Cols(r) == 1 )
result = AssertValueLong(r, 0, 0);
}
catch(const Error)
{
}
ClearResult(r);
return result;
}
// item.id must be set
// !! moze nazwa poprostu EditItem (nie trzeba tego ById) ? (sprawdzic czy nie koliduje z inna nazwa)
Error Db::EditItemById(Item & item, bool with_url)
{
BeginTrans();
Error result = WINIX_ERR_OK;
if( item.type == Item::file )
{
item.content_id = GetContentId(item.id);
result = EditItemInContent(item);
}
if( result == WINIX_ERR_OK )
result = EditItemInItem(item, with_url);
return EndTrans(result);
}
Error Db::EditItemGetIdsByUrl(Item & item)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
query.Clear();
query << R("select id, content_id from core.item where parent_id=")
<< item.parent_id
<< R(" and item.url=")
<< item.url
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
if( Rows(r) != 1 )
throw Error(WINIX_ERR_NO_ITEM);
int cid = AssertColumn(r, "id");
int cc_id = AssertColumn(r, "content_id");
item.id = AssertValueLong(r, 0, cid);
item.content_id = AssertValueLong(r, 0, cc_id);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
// item.url and item.parent_id must be set
Error Db::EditItemByUrl(Item & item, bool with_url)
{
BeginTrans();
Error result = EditItemGetIdsByUrl(item);
if( result == WINIX_ERR_OK )
{
if( item.type == Item::file )
result = EditItemInContent(item);
if( result == WINIX_ERR_OK )
result = EditItemInItem(item, with_url);
}
return EndTrans(result);
}
Error Db::EditLinkItem(long id, const std::wstring & link_to, int link_redirect)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
query.Clear();
query << R("update core.item set (link_to, link_redirect) = (")
<< link_to
<< link_redirect
<< R(") where id=")
<< id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
if( AffectedRows(r) == 0 )
{
result = WINIX_ERR_NO_ITEM;
log << log1 << "Db: EditLinkItem: no such an item, id: " << id << logend;
}
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::EditTemplateItemById(long id, const std::wstring & new_html_template)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
query.Clear();
query << R("update core.item set (template) = (")
<< new_html_template
<< R(") where id=")
<< id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
if( AffectedRows(r) == 0 )
{
result = WINIX_ERR_NO_ITEM;
log << log1 << "Db: EditTemplateItemById: no such an item, id: " << id << logend;
}
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::EditSortIndexItemById(long id, int sort_index)
{
query.Clear();
query << R("update core.item set (sort_index) = (")
<< sort_index
<< R(") where id=")
<< id
<< R(";");
return DoCommand(query);
}
void Db::GetItemsQuerySelect(const DbItemQuery & iq, DbTextStream & query, bool skip_other_sel)
{
query << R("select item.id, content_id");
if( !skip_other_sel )
{
if( iq.sel_parent_id ) query << R(", parent_id");
if( iq.sel_user_id ) query << R(", user_id, modification_user_id");
if( iq.sel_group_id ) query << R(", group_id");
if( iq.sel_guest_name) query << R(", guest_name");
if( iq.sel_privileges ) query << R(", privileges");
if( iq.sel_date ) query << R(", date_creation, date_modification");
if( iq.sel_subject ) query << R(", subject");
if( iq.sel_content ) query << R(", content, content_type, ref, modify_index");
if( iq.sel_url ) query << R(", url");
if( iq.sel_type ) query << R(", type");
if( iq.sel_link ) query << R(", link_to, link_redirect");
if( iq.sel_file ) query << R(", file_path, file_fs, file_type, has_thumb, hash, hash_type, file_size");
if( iq.sel_html_template ) query << R(", template");
if( iq.sel_sort_index ) query << R(", sort_index");
if( iq.sel_meta ) query << R(", meta");
}
query << R(" from core.item");
}
void Db::GetItemsQueryJoin(const DbItemQuery & iq, DbTextStream & query)
{
if( iq.sel_content || iq.sel_file || iq.where_file_type )
query << R(" left join core.content on item.content_id = content.id");
}
void Db::GetItemsQueryWhere(const DbItemQuery & iq, DbTextStream & query)
{
if( iq.where_id || iq.where_parent_id || iq.where_type || iq.where_file_type )
{
query << R(" where ");
const char * add_and = " and ";
const char * if_and = "";
if( iq.where_id ) { query << R(if_and) << R("item.id=") << iq.id ; if_and = add_and; }
if( iq.id_tab && !iq.id_tab->empty() )
{
CreateIdList(*iq.id_tab, iq_id_list);
query << R(if_and) << R("item.id in ") << R(iq_id_list);
if_and = add_and;
}
if( iq.where_parent_id ){ query << R(if_and) << R("parent_id=") << iq.parent_id ; if_and = add_and; }
if( iq.where_type )
{
query << R(if_and) << R("type");
if( iq.type_equal )
query << R("=");
else
query << R("!=");
query << int(iq.type);
if_and = add_and;
}
if( iq.where_file_type )
{
query << R(if_and) << R("file_type");
if( iq.file_type_equal )
query << R("=");
else
query << R("!=");
query << iq.file_type;
if_and = add_and;
}
}
}
void Db::GetItemsQueryOrder(const DbItemQuery & iq, DbTextStream & query)
{
if( iq.sel_sort_index || iq.sel_date )
{
query << R(" order by");
if( iq.sel_sort_index )
query << R(" sort_index");
if( iq.sel_date )
{
if( iq.sel_sort_index )
query << R(",");
query << R(" item.date_creation");
}
if( iq.sort_asc )
query << R(" asc");
else
query << R(" desc");
}
}
void Db::GetItemsQueryLimit(const DbItemQuery & iq, DbTextStream & query)
{
if( iq.limit != 0 )
query << R(" limit ") << iq.limit;
if( iq.offset != 0 )
query << R(" offset ") << iq.offset;
}
PGresult * Db::GetItemsQuery(const DbItemQuery & iq, DbTextStream & query, bool skip_other_sel)
{
query.Clear();
GetItemsQuerySelect(iq, query, skip_other_sel);
GetItemsQueryJoin(iq, query);
GetItemsQueryWhere(iq, query);
GetItemsQueryOrder(iq, query);
GetItemsQueryLimit(iq, query);
query << R(";");
return AssertQuery(query);
}
PGresult * Db::GetItemsQuery(const DbItemQuery & iq, bool skip_other_sel)
{
return GetItemsQuery(iq, query, skip_other_sel);
}
void Db::GetItems(std::vector<Item> & item_tab, const DbItemQuery & item_query)
{
item_tab.clear();
PGresult * r = 0;
try
{
r = GetItemsQuery(item_query);
AssertResult(r, PGRES_TUPLES_OK);
get_item_temp.Clear();
int rows = Rows(r);
if( rows > 0 && size_t(rows) > item_tab.capacity() )
item_tab.reserve(rows);
item_cols.SetColumns(r);
for(int i=0 ; i<rows ; ++i)
{
item_tab.push_back(get_item_temp);
item_cols.SetItem(r, i, item_tab.back());
}
}
catch(const Error &)
{
}
ClearResult(r);
}
void Db::GetItems(std::vector<long> & item_tab, const DbItemQuery & item_query)
{
item_tab.clear();
PGresult * r = 0;
try
{
r = GetItemsQuery(item_query, true);
AssertResult(r, PGRES_TUPLES_OK);
int rows = Rows(r);
for(int i = 0 ; i<rows ; ++i)
{
long id = AssertValueLong(r, i, 0);
item_tab.push_back(id);
}
}
catch(const Error &)
{
}
ClearResult(r);
}
Error Db::GetItem(Item & item, const DbItemQuery & item_query)
{
item.Clear();
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
r = GetItemsQuery(item_query);
AssertResult(r, PGRES_TUPLES_OK);
int rows = Rows(r);
if( rows == 1 )
{
item_cols.SetColumns(r);
item_cols.SetItem(r, 0, item);
}
else
if( rows == 0 )
{
result = WINIX_ERR_NO_ITEM;
}
else
{
result = WINIX_ERR_NO_ITEM;
log << log1 << "Db: more than one item matches the query (" << rows << ")";
}
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
// how many items there are in a 'parent_id' directory
long Db::Size(long parent_id, Item::Type type)
{
PGresult * r = 0;
long res = 0;
try
{
query.Clear();
query << R("select count(id) from core.item where ");
if( type != Item::none )
query << R("type=") << (int)type << R(" and ");
query << R("parent_id=") << parent_id << R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
res = AssertValueLong(r, 0, 0);
}
catch(const Error &)
{
}
ClearResult(r);
return res;
}
// !! nowy interfejs
Error Db::GetItem(long parent_id, const std::wstring & url, Item & item)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
query.Clear();
query << R("select * from core.item left join core.content on item.content_id = content.id"
" where item.parent_id=")
<< parent_id
<< R(" and item.url=")
<< url
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
if( Rows(r) == 0 )
throw Error(WINIX_ERR_NO_ITEM);
item_cols.SetColumns(r);
item_cols.SetItem(r, 0, item);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::GetItemById(long item_id, Item & item)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
query.Clear();
query << R("select * from core.item left join core.content on item.content_id = content.id"
" where item.id=") << item_id << R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
if( Rows(r) == 0 )
throw Error(WINIX_ERR_NO_ITEM);
item_cols.SetColumns(r);
item_cols.SetItem(r, 0, item);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
long Db::GetItemId(long parent_id, const std::wstring & url, Item::Type type)
{
PGresult * r = 0;
long result = -1;
try
{
query.Clear();
query << R("select id from core.item where type=")
<< static_cast<int>(type)
<< R(" and item.parent_id=")
<< parent_id
<< R(" and item.url=")
<< url
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
if( Rows(r) == 1 )
result = AssertValueLong(r, 0, 0);
}
catch(const Error & e)
{
}
ClearResult(r);
return result;
}
long Db::GetFileId(long parent_id, const std::wstring & url)
{
return GetItemId(parent_id, url, Item::file);
}
long Db::GetDirId(long parent_id, const std::wstring & url)
{
return GetItemId(parent_id, url, Item::dir);
}
bool Db::GetPriv(Item & item, long id)
{
bool result = false;
PGresult * r = 0;
try
{
query.Clear();
query << R("select user_id, modification_user_id, group_id, privileges, guest_name from core.item"
" where item.id=")
<< id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
if( Rows(r) != 1 )
throw Error();
item_cols.SetColumns(r);
item_cols.SetItem(r, 0, item);
result = true;
}
catch(const Error &)
{
}
ClearResult(r);
return result;
}
// !! to jest nowy interfejs, z jawnym podaniem id
Error Db::EditPrivById(Item & item, long id)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
query.Clear();
query << R("update core.item set (user_id, modification_user_id, group_id, privileges, guest_name) = (")
<< item.user_id
<< item.modification_user_id
<< item.group_id
<< item.privileges
<< item.guest_name
<< R(") where id=")
<< id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::EditParentUrlById(Item & item, long id)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
bool url_without_id = false;
try
{
query.Clear();
query << R("update core.item set (parent_id, url) = (") << item.parent_id;
url_without_id = AddItemCreateUrlSubject(item);
if( url_without_id )
query << item.url;
else
query << item.id;
query << R(") where id=") << id << R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::EditFileById(const Item & item, long id)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
BeginTrans();
try
{
long content_id = GetContentId(id);
if( content_id == -1 )
throw Error(WINIX_ERR_NO_ITEM);
query.Clear();
query << R("update core.content set (file_path, file_fs, file_type, has_thumb, hash, hash_type, file_size) = (")
<< item.file_path
<< item.file_fs
<< item.file_type
<< static_cast<int>(item.has_thumb)
<< item.hash
<< item.hash_type
<< item.file_size
<< R(") where id=") << content_id << R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return EndTrans(result);
}
Error Db::EditHasThumbById(bool has_thumb, long id)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
BeginTrans();
try
{
long content_id = GetContentId(id);
if( content_id == -1 )
throw Error(WINIX_ERR_NO_ITEM);
query.Clear();
query << R("update core.content set (has_thumb) = (")
<< static_cast<int>(has_thumb)
<< R(") where id=") << content_id << R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return EndTrans(result);
}
Error Db::EditMetaById(const Space & meta, long id)
{
meta_stream.Clear();
meta.Serialize(meta_stream);
query.Clear();
query << R("update core.item set (meta) = (")
<< meta_stream.Str()
<< R(") where id=")
<< id
<< R(";");
meta_stream.Clear();
return DoCommand(query);
}
Error Db::EditSubjectById(Item & item, long id)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
query.Clear();
query << R("update core.item set (subject) = (")
<< item.subject
<< R(") where id=")
<< id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::DelDirById(long id)
{
Error result = WINIX_ERR_OK;
PGresult * r = 0;
BeginTrans();
try
{
// decrementing ref in core.content
query.Clear();
query << R("update core.content set (ref) = (ref - 1) where content.id in "
"(select content_id from core.item where type=1 and parent_id=")
<< id
<< R(");");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
ClearResult(r);
// deleting in core.content where ref is zero
query.Clear();
query << R("delete from core.content where ref=0;");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
log << log2 << "Db: deleted " << AffectedRows(r) << " rows from core.content" << logend;
ClearResult(r);
// deleting from core.item
query.Clear();
query << R("delete from core.item where id=")
<< id
<< R(" or parent_id=")
<< id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
log << log2 << "Db: deleted dir: " << id << " (deleted: " << AffectedRows(r) << " rows from core.item)" << logend;
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return EndTrans(result);
}
Error Db::DelItemDelItem(long item_id, int type)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
query.Clear();
query << R("delete from core.item where id=")
<< item_id
<< R(" and type=")
<< type
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
log << log2 << "Db: deleted " << AffectedRows(r) << " from core.item" << logend;
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::DelItemDelContent(long content_id)
{
PGresult * r = 0;
Error result = WINIX_ERR_OK;
try
{
result = DecrementContentRef(content_id);
if( result == WINIX_ERR_OK )
{
query.Clear();
query << R("delete from core.content where ref=0 and id=")
<< content_id
<< R(";");
r = AssertQuery(query);
AssertResult(r, PGRES_COMMAND_OK);
log << log2 << "Db: deleted " << AffectedRows(r) << " rows from core.content" << logend;
}
}
catch(const Error & e)
{
result = e;
}
ClearResult(r);
return result;
}
Error Db::DelItem(const Item & item)
{
Error result = WINIX_ERR_NO_ITEM;
if( item.type == Item::file )
{
BeginTrans();
result = DelItemDelContent(item.content_id);
if( result == WINIX_ERR_OK )
result = DelItemDelItem(item.id, 1);
result = EndTrans(result);
}
else
if( item.type == Item::symlink )
{
result = DelItemDelItem(item.id, 2);
}
else
if( item.type == Item::dir )
{
result = DelDirById(item.id);
}
return result;
}
Error Db::DelFileById(long file_id)
{
Error result = WINIX_ERR_NO_ITEM;
BeginTrans();
long content_id = GetContentId(file_id);
if( content_id != -1 )
{
result = DelItemDelContent(content_id);
if( result == WINIX_ERR_OK )
result = DelItemDelItem(file_id, 1);
}
result = EndTrans(result);
return result;
}
Error Db::DelSymlinkById(long symlink_id)
{
return DelItemDelItem(symlink_id, 2);
}
void Db::GetDirs(DirContainer & dir_tab)
{
PGresult * r = 0;
try
{
query.Clear();
query << R("select * from core.item where type=0;");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
dir_temp.Clear();
int rows = Rows(r);
item_cols.SetColumns(r);
for(int i=0 ; i<rows ; ++i)
{
item_cols.SetItem(r, i, dir_temp);
dir_tab.PushBack(dir_temp);
}
}
catch(const Error &)
{
}
ClearResult(r);
}
void Db::GetUsers(UGContainer<User> & user_tab)
{
PGresult * r = 0;
try
{
query.Clear();
query << R("select id, login, super_user, group_id, email, notify"
" from core.user left outer join core.group_mem on"
" core.user.id = core.group_mem.user_id order by id asc;");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
int rows = Rows(r);
int cid = AssertColumn(r, "id");
int cname = AssertColumn(r, "login");
int csuper_user = AssertColumn(r, "super_user");
int cgroup_id = AssertColumn(r, "group_id");
int cemail = AssertColumn(r, "email");
int cnotify = AssertColumn(r, "notify");
User u;
long last_id = -1;
UGContainer<User>::Iterator iter = user_tab.End();
for(int i = 0 ; i<rows ; ++i)
{
u.id = AssertValueLong(r, i, cid);
if( u.id != last_id )
{
u.name = AssertValueWide(r, i, cname);
u.super_user = AssertValueBool(r, i, csuper_user);
u.email = AssertValueWide(r, i, cemail);
u.notify = AssertValueInt(r, i, cnotify);
log << log2 << "Db: user: id: " << u.id << ", name: " << u.name << ", super_user: " << u.super_user << logend;
iter = user_tab.PushBack( u );
if( iter == user_tab.End() )
log << log1 << "Db: can't add a user: " << u.name << logend;
last_id = u.id;
}
long group_id = AssertValueLong(r, i, cgroup_id);
if( !IsNull(r, i, cgroup_id) && group_id!=-1 && iter!=user_tab.End() )
{
(*iter)->groups.push_back(group_id);
log << log3 << "Db: user:" << (*iter)->name << " is a member of group_id: " << group_id << logend;
}
}
}
catch(const Error &)
{
}
ClearResult(r);
}
void Db::GetGroups(UGContainer<Group> & group_tab)
{
PGresult * r = 0;
try
{
query.Clear();
query << R("select id, core.group.group, user_id from core.group left outer join"
" core.group_mem on core.group.id = core.group_mem.group_id order by id asc;");
r = AssertQuery(query);
AssertResult(r, PGRES_TUPLES_OK);
int rows = Rows(r);
int cid = AssertColumn(r, "id");
int cname = AssertColumn(r, "group");
int cuser_id = AssertColumn(r, "user_id");
Group g;
long last_id = -1;
UGContainer<Group>::Iterator iter;
for(int i = 0 ; i<rows ; ++i)
{
g.id = AssertValueLong(r, i, cid);
if( g.id != last_id )
{
g.name = AssertValueWide(r, i, cname);
log << log3 << "Db: get group, id: " << g.id << ", group: " << g.name << logend;
iter = group_tab.PushBack( g );
last_id = g.id;
}
long user_id = AssertValueLong(r, i, cuser_id);
if( !IsNull(r, i, cuser_id) && user_id!=-1 && !group_tab.Empty() )
{
(*iter)->members.push_back(user_id);
log << log3 << "Db: get group member: user_id: " << user_id << logend;
}
}
}
catch(const Error &)
{
}
ClearResult(r);
}