1720 lines
31 KiB
C++
Executable File
1720 lines
31 KiB
C++
Executable File
/*
|
|
* This file is a part of Winix
|
|
* and is not publicly distributed
|
|
*
|
|
* Copyright (c) 2008-2012, 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 UserPass & up)
|
|
{
|
|
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, env, aenv, status, locale_id, time_zone_id) values (")
|
|
<< user.name;
|
|
|
|
// for safety we put up.pass only if there is not an encrypted version
|
|
// someone could have forgotten to clear up.pass
|
|
if( up.pass_encrypted.empty() )
|
|
query << up.pass;
|
|
else
|
|
query << "";
|
|
|
|
query.EPutBin(up.pass_encrypted);
|
|
|
|
query << user.super_user
|
|
<< user.email
|
|
<< user.notify
|
|
<< up.pass_type
|
|
<< up.pass_hash_salted
|
|
<< user.env
|
|
<< user.aenv
|
|
<< user.status
|
|
<< user.locale_id
|
|
<< user.time_zone_id
|
|
<< 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::ChangeUserPass(long user_id, const UserPass & up)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(password, pass_encrypted,"
|
|
"pass_type, pass_hash_salted) = (");
|
|
|
|
// for safety
|
|
if( up.pass_encrypted.empty() )
|
|
query << up.pass;
|
|
else
|
|
query << "";
|
|
|
|
query.EPutBin(up.pass_encrypted);
|
|
|
|
query << up.pass_type
|
|
<< up.pass_hash_salted
|
|
<< R(") where id=")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserEnv(long user_id, const PT::Space & space)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(env) = (")
|
|
<< space
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserAdminEnv(long user_id, const PT::Space & space)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(aenv) = (")
|
|
<< space
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserStatus(long user_id, int status)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(status) = (")
|
|
<< status
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
|
|
Error Db::ChangeUserEmail(long user_id, const std::wstring & email)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(email) = (")
|
|
<< email
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserLocale(long user_id, size_t locale_id)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(locale_id) = (")
|
|
<< locale_id
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::ChangeUserTimeZone(long user_id, size_t time_zone_id)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.user set(time_zone_id) = (")
|
|
<< time_zone_id
|
|
<< R(") where id = ")
|
|
<< user_id
|
|
<< R(";");
|
|
|
|
return DoCommand(query);
|
|
}
|
|
|
|
|
|
Error Db::RemoveUser(long user_id)
|
|
{
|
|
query.Clear();
|
|
query << R("delete from core.user where id = ")
|
|
<< user_id
|
|
<< 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, meta, 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
|
|
<< item.meta;
|
|
|
|
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, meta");
|
|
|
|
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
|
|
<< item.meta;
|
|
|
|
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 PT::Space & meta, long id)
|
|
{
|
|
query.Clear();
|
|
query << R("update core.item set (meta) = (")
|
|
<< meta
|
|
<< R(") where id=")
|
|
<< id
|
|
<< R(";");
|
|
|
|
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,"
|
|
" env, aenv, status, locale_id, time_zone_id"
|
|
" 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");
|
|
int cenv = AssertColumn(r, "env");
|
|
int caenv = AssertColumn(r, "aenv");
|
|
int cstatus = AssertColumn(r, "status");
|
|
int clocale_id = AssertColumn(r, "locale_id");
|
|
int ctzone_id = AssertColumn(r, "time_zone_id");
|
|
|
|
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);
|
|
u.status = AssertValueInt(r, i, cstatus);
|
|
u.locale_id = (size_t)AssertValueInt(r, i, clocale_id);
|
|
u.time_zone_id = (size_t)AssertValueInt(r, i, ctzone_id);
|
|
AssertValueSpace(r, i, cenv, u.env);
|
|
AssertValueSpace(r, i, caenv, u.aenv);
|
|
|
|
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);
|
|
}
|
|
|
|
|