| 2 |
* |
* |
| 3 |
* $Revision$ |
* $Revision$ |
| 4 |
* $Log$ |
* $Log$ |
| 5 |
|
* Revision 1.37 2005/01/14 10:36:59 aga |
| 6 |
|
* ・index関係の処理を追加. |
| 7 |
|
* ・insertAccountでprivate indexを作成するよう修正. |
| 8 |
|
* ・insertGroupでgroup index を作成するよう修正. |
| 9 |
|
* |
| 10 |
* Revision 1.36 2005/01/13 04:19:22 aga |
* Revision 1.36 2005/01/13 04:19:22 aga |
| 11 |
* ・VPをXNPに変換. |
* ・VPをXNPに変換. |
| 12 |
* |
* |
| 176 |
#include "session.h" |
#include "session.h" |
| 177 |
#include "criteria.h" |
#include "criteria.h" |
| 178 |
#include "commonal.h" |
#include "commonal.h" |
| 179 |
|
#include "item.h" |
| 180 |
|
#include "index.h" |
| 181 |
|
|
| 182 |
static string dbprefix; //!< XOOPSデータベーステーブルのPREFIX |
static string dbprefix; //!< XOOPSデータベーステーブルのPREFIX |
| 183 |
|
|
| 185 |
static SQLHANDLE hdbc = NULL; |
static SQLHANDLE hdbc = NULL; |
| 186 |
static SQLHANDLE hstmt = NULL; |
static SQLHANDLE hstmt = NULL; |
| 187 |
|
|
| 188 |
|
static result_t insertIndexInternal( sessionid_t sid, index_t *index, indexid_t *xid ); |
| 189 |
|
|
| 190 |
static string odbcDiagString( SQLSMALLINT HandleType, SQLHANDLE hstmt, SQLRETURN sqlcode ); |
static string odbcDiagString( SQLSMALLINT HandleType, SQLHANDLE hstmt, SQLRETURN sqlcode ); |
| 191 |
static result_t deleteMemberNoLimit( sessionid_t sid, groupid_t gid, userid_t uid ); |
static result_t deleteMemberNoLimit( sessionid_t sid, groupid_t gid, userid_t uid ); |
| 192 |
|
|
| 213 |
return ret; |
return ret; |
| 214 |
} |
} |
| 215 |
|
|
| 216 |
|
/** SQLを実行する。結果は捨てる。 |
| 217 |
|
* @param sql sql |
| 218 |
|
* @return result_t |
| 219 |
|
*/ |
| 220 |
|
static result_t querySimple( const char *functionName, string &sql ){ |
| 221 |
|
result_t ret = RES_ERROR; |
| 222 |
|
SQLRETURN sqlcode; |
| 223 |
|
SQLHANDLE hstmt = NULL; |
| 224 |
|
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
| 225 |
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), strlen( sql.c_str() ) ) ) == SQL_SUCCESS ){ |
| 226 |
|
ret = RES_OK; |
| 227 |
|
}else{ |
| 228 |
|
string s( "SQLExecDirect in querySimple " ); |
| 229 |
|
s += functionName; |
| 230 |
|
s += odbcDiagString( SQL_HANDLE_STMT, hstmt, sqlcode ); |
| 231 |
|
s += "sql="; |
| 232 |
|
s += sql; |
| 233 |
|
setLastErrorString( s.c_str( ) ); |
| 234 |
|
ret = RES_DB_QUERY_ERROR; |
| 235 |
|
} |
| 236 |
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
| 237 |
|
} |
| 238 |
|
else { |
| 239 |
|
setLastErrorString( "SQLAllocHandle(SQL_HANDLE_STMT,...) in querySimple " ); |
| 240 |
|
ret = RES_ERROR; |
| 241 |
|
} |
| 242 |
|
return ret; |
| 243 |
|
} |
| 244 |
|
|
| 245 |
|
/** SQLを実行し、1行目の最初の整数値(NULLなら0とみなす)のみ受け取る。 |
| 246 |
|
* @param sql sql |
| 247 |
|
* @param u 整数値を受け取る変数。 |
| 248 |
|
* @return result_t |
| 249 |
|
*/ |
| 250 |
|
static result_t queryGetUnsignedInt( const char *functionName, string &sql, unsigned int *u ){ |
| 251 |
|
result_t ret = RES_ERROR; |
| 252 |
|
SQLRETURN sqlcode; |
| 253 |
|
SQLHANDLE hstmt = NULL; |
| 254 |
|
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
| 255 |
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), strlen( sql.c_str() ) ) ) == SQL_SUCCESS ){ |
| 256 |
|
SQLUINTEGER sInt = 0; |
| 257 |
|
SQLINTEGER len; |
| 258 |
|
SQLBindCol( hstmt, 1, SQL_C_ULONG, &sInt, 0, &len ); |
| 259 |
|
if( ( sqlcode = SQLFetch( hstmt ) ) == SQL_SUCCESS ){ |
| 260 |
|
if ( len == SQL_NULL_DATA ) |
| 261 |
|
sInt = 0; |
| 262 |
|
*u = sInt; |
| 263 |
|
ret = RES_OK; |
| 264 |
|
}else{ |
| 265 |
|
string s( "SQLFetch in queryGetUnsignedInt " ); |
| 266 |
|
s += functionName; |
| 267 |
|
setLastErrorString( s.c_str( ) ); |
| 268 |
|
ret = RES_ERROR; |
| 269 |
|
} |
| 270 |
|
}else{ |
| 271 |
|
string s( "SQLExecDirect in queryGetUnsignedInt " ); |
| 272 |
|
s += functionName; |
| 273 |
|
s += odbcDiagString( SQL_HANDLE_STMT, hstmt, sqlcode ); |
| 274 |
|
s += "sql="; |
| 275 |
|
s += sql; |
| 276 |
|
setLastErrorString( s.c_str( ) ); |
| 277 |
|
ret = RES_DB_QUERY_ERROR; |
| 278 |
|
} |
| 279 |
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
| 280 |
|
} |
| 281 |
|
else { |
| 282 |
|
setLastErrorString( "SQLAllocHandle(SQL_HANDLE_STMT,...) in queryGetUnsignedInt " ); |
| 283 |
|
ret = RES_ERROR; |
| 284 |
|
} |
| 285 |
|
return ret; |
| 286 |
|
} |
| 287 |
|
|
| 288 |
|
/** sidからuidを得る。 |
| 289 |
|
* @param sid session id |
| 290 |
|
* @param uid uidを受け取る変数 |
| 291 |
|
* @return |
| 292 |
|
*/ |
| 293 |
|
static result_t sessionID2UID( sessionid_t sid, userid_t *uid ){ |
| 294 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 295 |
|
|
| 296 |
|
SQLRETURN sqlcode; |
| 297 |
|
SQLHANDLE hstmt = NULL; |
| 298 |
|
|
| 299 |
|
string sql = "SELECT uid FROM " + dbprefix + "_xnpaccount_session WHERE sid=" + unsignedIntToString(sid); |
| 300 |
|
return queryGetUnsignedInt( "sessionID2UID", sql, (unsigned int*)uid ); |
| 301 |
|
} |
| 302 |
|
|
| 303 |
/** |
/** |
| 304 |
* |
* |
| 305 |
* 文字列コピー. |
* 文字列コピー. |
| 922 |
string sql; |
string sql; |
| 923 |
account_t* dst = new account_t[ uidsLen ]; |
account_t* dst = new account_t[ uidsLen ]; |
| 924 |
|
|
| 925 |
sql += "SELECT u1.uid, u1.name, u1.uname, u1.email, u1.url, u1.user_avatar, u1.user_regdate, u1.user_icq, u1.user_from, u1.user_sig, u1.user_viewemail, u1.actkey, u1.user_aim, u1.user_yim, u1.user_msnm, u1.pass, u1.posts, u1.attachsig, u1.rank, u1.level, u1.theme, u1.timezone_offset, u1.last_login, u1.umode, u1.uorder, u1.notify_method, u1.notify_mode, u1.user_occ, u1.bio, u1.user_intrest, u1.user_mailok, u2.activate, u2.address, u2.division, u2.tel, u2.company_name, u2.country, u2.zipcode, u2.fax, u2.base_url, u2.notice_mail, u2.notice_mail_since "; |
sql += "SELECT u1.uid, u1.name, u1.uname, u1.email, u1.url, u1.user_avatar, u1.user_regdate, u1.user_icq, u1.user_from, u1.user_sig, u1.user_viewemail, u1.actkey, u1.user_aim, u1.user_yim, u1.user_msnm, u1.pass, u1.posts, u1.attachsig, u1.rank, u1.level, u1.theme, u1.timezone_offset, u1.last_login, u1.umode, u1.uorder, u1.notify_method, u1.notify_mode, u1.user_occ, u1.bio, u1.user_intrest, u1.user_mailok, u2.activate, u2.address, u2.division, u2.tel, u2.company_name, u2.country, u2.zipcode, u2.fax, u2.base_url, u2.notice_mail, u2.notice_mail_since, u2.private_index_id "; |
| 926 |
sql += "FROM " + dbprefix + "_users AS u1, " + dbprefix + "_xnpaccount_users AS u2 "; |
sql += "FROM " + dbprefix + "_users AS u1, " + dbprefix + "_xnpaccount_users AS u2 "; |
| 927 |
sql += "WHERE u1.uid = u2.uid "; |
sql += "WHERE u1.uid = u2.uid "; |
| 928 |
if( uidsLen > 0 ){ |
if( uidsLen > 0 ){ |
| 992 |
dst[ i ].setBaseURL( getResultCol( hstmt, 40 ).c_str() ); |
dst[ i ].setBaseURL( getResultCol( hstmt, 40 ).c_str() ); |
| 993 |
dst[ i ].setNoticeMail( atoi( getResultCol( hstmt, 41 ).c_str() )); |
dst[ i ].setNoticeMail( atoi( getResultCol( hstmt, 41 ).c_str() )); |
| 994 |
dst[ i ].setNoticeMailSince( atoi( getResultCol( hstmt, 42 ).c_str() )); |
dst[ i ].setNoticeMailSince( atoi( getResultCol( hstmt, 42 ).c_str() )); |
| 995 |
|
dst[ i ].setPrivateIndexID( atoi( getResultCol( hstmt, 43 ).c_str() )); |
| 996 |
#ifdef USE_SYSLOG |
#ifdef USE_SYSLOG |
| 997 |
syslog( LOG_DEBUG, "set to account_t %d", i ); |
syslog( LOG_DEBUG, "set to account_t %d", i ); |
| 998 |
#endif |
#endif |
| 1060 |
1. insert user profile into xoops_users |
1. insert user profile into xoops_users |
| 1061 |
2. insert platform user profile into xnpaccount_users |
2. insert platform user profile into xnpaccount_users |
| 1062 |
3. add user to default platform group |
3. add user to default platform group |
| 1063 |
|
4. create private index |
| 1064 |
|
5. update account set private_index_id=... |
| 1065 |
*/ |
*/ |
| 1066 |
|
|
| 1067 |
//1.xoopsのユーザテーブルに書き込む |
//1.xoopsのユーザテーブルに書き込む |
| 1288 |
ret = RES_ERROR; |
ret = RES_ERROR; |
| 1289 |
} |
} |
| 1290 |
} |
} |
| 1291 |
|
|
| 1292 |
|
if ( ret == RES_OK ){ |
| 1293 |
|
//4.private indexを作成 |
| 1294 |
|
|
| 1295 |
|
// private index用のsort_number生成 |
| 1296 |
|
string sql = "select min(sort_number) from " + |
| 1297 |
|
dbprefix + "_xnpaccount_index where parent_index_id=" + unsignedIntToString(item::IID_ROOT) + |
| 1298 |
|
" and open_level=" + unsignedIntToString(index::OL_PRIVATE); |
| 1299 |
|
unsigned int sortNumber; |
| 1300 |
|
ret = queryGetUnsignedInt( "insertAccount", sql, &sortNumber ); |
| 1301 |
|
sortNumber--; |
| 1302 |
|
if ( ret == RES_OK ){ |
| 1303 |
|
// private index作成 |
| 1304 |
|
index_t index; |
| 1305 |
|
index.setItemTypeID(item::ITID_INDEX); |
| 1306 |
|
index.setContributorUID(*uid); |
| 1307 |
|
index.setParentIndexID(item::IID_ROOT); |
| 1308 |
|
index.setOwnerUID(*uid); |
| 1309 |
|
index.setOpenLevel(index::OL_PRIVATE); |
| 1310 |
|
index.setSortNumber(sortNumber); |
| 1311 |
|
index.setTitle(account->getUname()); |
| 1312 |
|
indexid_t privateXID; |
| 1313 |
|
ret = insertIndexInternal( sid, &index, &privateXID ); |
| 1314 |
|
if ( ret == RES_OK ){ |
| 1315 |
|
// xnpaccuont_usersのprivate_index_idの書き換え |
| 1316 |
|
sql = "UPDATE " + dbprefix + "_xnpaccount_users SET private_index_id=" |
| 1317 |
|
+ unsignedIntToString(privateXID) + " WHERE uid=" + unsignedIntToString(*uid); |
| 1318 |
|
ret = querySimple( "insertAccount", sql ); |
| 1319 |
|
} |
| 1320 |
|
} |
| 1321 |
|
} |
| 1322 |
|
|
| 1323 |
return ret; |
return ret; |
| 1324 |
} |
} |
| 1325 |
|
|
| 2312 |
setLastErrorString( "SQLAllocHandle(SQL_HANDLE_STMT,...) in insertGroup" ); |
setLastErrorString( "SQLAllocHandle(SQL_HANDLE_STMT,...) in insertGroup" ); |
| 2313 |
ret = RES_ERROR; |
ret = RES_ERROR; |
| 2314 |
} |
} |
| 2315 |
|
|
| 2316 |
|
// |
| 2317 |
|
if ( ret == RES_OK ){ |
| 2318 |
|
//group indexを作成 |
| 2319 |
|
|
| 2320 |
|
//group index用のsort_num生成 |
| 2321 |
|
string sql = "SELECT MAX(sort_number) FROM " + |
| 2322 |
|
dbprefix + "_xnpaccount_index WHERE parent_index_id=" + unsignedIntToString(item::IID_ROOT) + |
| 2323 |
|
" AND (open_level=" + unsignedIntToString(index::OL_GROUP_ONLY) + |
| 2324 |
|
" OR open_level=" + unsignedIntToString(index::OL_PUBLIC) + ")"; |
| 2325 |
|
unsigned int sortNumber; |
| 2326 |
|
ret = queryGetUnsignedInt( "insertGroup", sql, &sortNumber ); |
| 2327 |
|
sortNumber++; |
| 2328 |
|
if ( ret == RES_OK ){ |
| 2329 |
|
// group index作成 |
| 2330 |
|
index_t index; |
| 2331 |
|
userid_t uid; |
| 2332 |
|
ret = sessionID2UID( sid, &uid ); |
| 2333 |
|
if ( ret == RES_OK ){ |
| 2334 |
|
index.setItemTypeID(item::ITID_INDEX); |
| 2335 |
|
index.setContributorUID(uid); |
| 2336 |
|
index.setParentIndexID(item::IID_ROOT); |
| 2337 |
|
index.setOwnerGID(*gid); |
| 2338 |
|
index.setOpenLevel(index::OL_GROUP_ONLY); |
| 2339 |
|
index.setSortNumber(sortNumber); |
| 2340 |
|
index.setTitle(group->getGname()); |
| 2341 |
|
indexid_t groupXID; |
| 2342 |
|
ret = insertIndexInternal( sid, &index, &groupXID ); |
| 2343 |
|
if ( ret == RES_OK ){ |
| 2344 |
|
// xnpaccuont_groupsのgroup_index_idの書き換え |
| 2345 |
|
sql = "UPDATE " + dbprefix + "_xnpaccount_groups SET group_index_id=" |
| 2346 |
|
+ unsignedIntToString(groupXID) + " WHERE gid=" + unsignedIntToString(*gid); |
| 2347 |
|
ret = querySimple( "insertGroup", sql ); |
| 2348 |
|
} |
| 2349 |
|
} |
| 2350 |
|
} |
| 2351 |
|
} |
| 2352 |
|
|
| 2353 |
return ret; |
return ret; |
| 2354 |
} |
} |
| 2355 |
|
|
| 2470 |
string sql; |
string sql; |
| 2471 |
group_t* dst = new group_t[ gidsLen ]; |
group_t* dst = new group_t[ gidsLen ]; |
| 2472 |
|
|
| 2473 |
sql += "SELECT gid, gname, gdesc "; |
sql += "SELECT gid, gname, gdesc, group_index_id "; |
| 2474 |
sql += "FROM " + dbprefix + "_xnpaccount_groups "; |
sql += "FROM " + dbprefix + "_xnpaccount_groups "; |
| 2475 |
if( gidsLen > 0 ){ |
if( gidsLen > 0 ){ |
| 2476 |
sql += "WHERE gid=" + string( unsignedIntToString( gids[ 0 ] ) ); |
sql += "WHERE gid=" + string( unsignedIntToString( gids[ 0 ] ) ); |
| 2490 |
dst[ i ].setGID( gid ); |
dst[ i ].setGID( gid ); |
| 2491 |
dst[ i ].setGname( getResultCol( hstmt, 2 ).c_str() ); |
dst[ i ].setGname( getResultCol( hstmt, 2 ).c_str() ); |
| 2492 |
dst[ i ].setDesc( getResultCol( hstmt, 3 ).c_str() ); |
dst[ i ].setDesc( getResultCol( hstmt, 3 ).c_str() ); |
| 2493 |
|
dst[ i ].setGroupIndexID( atoi(getResultCol( hstmt, 4 ).c_str()) ); |
| 2494 |
( *groupsLen )++; |
( *groupsLen )++; |
| 2495 |
} |
} |
| 2496 |
*groups = dst; |
*groups = dst; |
| 2641 |
*/ |
*/ |
| 2642 |
static result_t addSession( userid_t uid, sessionid_t* session ) |
static result_t addSession( userid_t uid, sessionid_t* session ) |
| 2643 |
{ |
{ |
| 2644 |
result_t ret = RES_DB_QUERY_ERROR; |
char *functionName = "addSession"; |
|
SQLRETURN sqlcode; |
|
| 2645 |
string sql = "INSERT INTO " + dbprefix + "_xnpaccount_session (uid) values (" + |
string sql = "INSERT INTO " + dbprefix + "_xnpaccount_session (uid) values (" + |
| 2646 |
unsignedIntToString(uid) + ")"; |
unsignedIntToString(uid) + ")"; |
| 2647 |
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
result_t ret = querySimple( functionName, sql ); |
| 2648 |
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), sql.length() ) ) == SQL_SUCCESS ){ |
if ( ret == RES_OK ){ |
| 2649 |
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
sql = "SELECT LAST_INSERT_ID()"; |
| 2650 |
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
ret = queryGetUnsignedInt( functionName, sql, (unsigned int*)session ); |
|
sql = "SELECT LAST_INSERT_ID()"; |
|
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), sql.length() ) ) == SQL_SUCCESS ){ |
|
|
sessionid_t sid; |
|
|
SQLINTEGER len; |
|
|
SQLBindCol( hstmt, 1, SQL_C_ULONG, &sid, 0, &len ); |
|
|
if( ( sqlcode = SQLFetch( hstmt ) ) == SQL_SUCCESS ){ |
|
|
*session = sid; |
|
|
ret = RES_OK; |
|
|
} |
|
|
} |
|
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
|
|
} |
|
|
}else{ |
|
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
|
|
} |
|
| 2651 |
} |
} |
| 2652 |
return ret; |
return ret; |
| 2653 |
} |
} |
| 2931 |
return ret; |
return ret; |
| 2932 |
} |
} |
| 2933 |
|
|
| 2934 |
|
|
| 2935 |
|
|
| 2936 |
|
// todo |
| 2937 |
|
// basic informationに書き込み |
| 2938 |
|
result_t insertItemInternal( sessionid_t sid, item_t *item, itemid_t *iid ){ |
| 2939 |
|
string sql = "INSERT INTO " + dbprefix + "_xnpaccount_item_basic " |
| 2940 |
|
" ( item_type_id, uid, title, last_update_date, creation_date ) values ( " |
| 2941 |
|
+ unsignedIntToString(item->getItemTypeID()) + "," + unsignedIntToString(item->getContributorUID()) + "," |
| 2942 |
|
+ " '" + addSlashes(item->getTitle()) + "'," + unsignedIntToString(item->getLastUpdateDate()) |
| 2943 |
|
+ "," + unsignedIntToString(item->getCreationDate()) + ")"; |
| 2944 |
|
result_t result = querySimple( "insertItemInternal", sql ); |
| 2945 |
|
if( result == RES_OK ){ |
| 2946 |
|
sql = "SELECT LAST_INSERT_ID()"; |
| 2947 |
|
result = queryGetUnsignedInt( "insertItemInternal", sql, (unsigned int*)iid ); |
| 2948 |
|
} |
| 2949 |
|
return result; |
| 2950 |
|
} |
| 2951 |
|
|
| 2952 |
|
|
| 2953 |
|
/** |
| 2954 |
|
* |
| 2955 |
|
* 条件に一致するインデックスの一覧を得る。 |
| 2956 |
|
* |
| 2957 |
|
* @param cond SQLの条件式。省略時は0。 条件式内でtx(index), ti(item), tlink(group_user_link) が利用可能。 |
| 2958 |
|
* @param uid このuidが読み込み権限を持つようなインデックスのみ取得する。 |
| 2959 |
|
ただしuid==0なら、読み込み権限を無視する。 |
| 2960 |
|
* @param indexes インデックスの一覧を返す変数 |
| 2961 |
|
* @param indexesLen indexesの配列長 |
| 2962 |
|
* @return RES_OK 成功 |
| 2963 |
|
* |
| 2964 |
|
*/ |
| 2965 |
|
static result_t getIndexesInternal( sessionid_t sid, const char *cond, userid_t uid, const index_t **indexes, int *indexesLen, string &criteriaString ){ |
| 2966 |
|
result_t result; |
| 2967 |
|
SQLRETURN sqlcode; |
| 2968 |
|
SQLHANDLE hstmt = NULL; |
| 2969 |
|
|
| 2970 |
|
string groupUserLinkTable = dbprefix + "_xnpaccount_groups_users_link"; |
| 2971 |
|
string indexTable = dbprefix + "_xnpaccount_index"; |
| 2972 |
|
string itemTable = dbprefix + "_xnpaccount_item_basic"; |
| 2973 |
|
string uidString = unsignedIntToString( uid ); |
| 2974 |
|
if ( cond == 0 ) |
| 2975 |
|
cond = " 1 "; |
| 2976 |
|
|
| 2977 |
|
string accessRightCond = "1"; |
| 2978 |
|
if ( uid != 0 && !isModerator( sid, uid ) ) |
| 2979 |
|
accessRightCond = |
| 2980 |
|
" ( tx.open_level=1 " |
| 2981 |
|
" OR tx.open_level=2 AND tlink.uid is not NULL " |
| 2982 |
|
" OR tx.open_level=3 AND tx.uid = " + uidString + ")"; // アクセス権を表すSQL |
| 2983 |
|
string sql = "SELECT tx.index_id " |
| 2984 |
|
" FROM " + indexTable + " AS tx " + |
| 2985 |
|
" LEFT JOIN " + itemTable + " AS ti on tx.index_id = ti.item_id " |
| 2986 |
|
" LEFT JOIN " + groupUserLinkTable + " AS tlink on tlink.gid = tx.gid and tlink.uid = " + uidString + |
| 2987 |
|
" WHERE " + accessRightCond + " AND " + cond; |
| 2988 |
|
SQLINTEGER len = 0; |
| 2989 |
|
result = countResultRows( sql.c_str(), &len ); |
| 2990 |
|
if ( result != RES_OK ) |
| 2991 |
|
return result; |
| 2992 |
|
if ( len == 0 ){ |
| 2993 |
|
*indexes = 0; |
| 2994 |
|
*indexesLen = 0; |
| 2995 |
|
return result; |
| 2996 |
|
} |
| 2997 |
|
|
| 2998 |
|
sql = "SELECT tx.index_id, tx.parent_index_id, tx.uid, tx.gid, tx.open_level, tx.sort_number " |
| 2999 |
|
" , ti.item_type_id, ti.item_subtype, ti.uid, ti.title, ti.keywords, ti.description, ti.last_update_date, ti.creation_date " |
| 3000 |
|
" FROM " + indexTable + " AS tx " + |
| 3001 |
|
" LEFT JOIN " + itemTable + " AS ti on tx.index_id = ti.item_id " |
| 3002 |
|
" LEFT JOIN " + groupUserLinkTable + " AS tlink on tlink.gid = tx.gid and tlink.uid = " + uidString + |
| 3003 |
|
" WHERE " + accessRightCond + " AND " + cond + criteriaString; |
| 3004 |
|
SQLCHAR subtype[XNP_ITEM_SUBTYPE_LEN+1], title[XNP_ITEM_TITLE_LEN+1], |
| 3005 |
|
keywords[XNP_ITEM_KEYWORDS_LEN+1], description[XNP_ITEM_DESCRIPTION_LEN+1]; |
| 3006 |
|
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
| 3007 |
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), sql.length() ) ) == SQL_SUCCESS ){ |
| 3008 |
|
SQLUINTEGER xid = 0, parentXID = 0, ownerUID = 0, ownerGID = 0, openLevel = 0, |
| 3009 |
|
sortNumber = 0, itemTypeID = 0, contributorUID = 0, lastUpdateDate = 0, creationDate = 0; |
| 3010 |
|
SQLINTEGER lens[14]; |
| 3011 |
|
SQLBindCol( hstmt, 1, SQL_C_ULONG, &xid, 0, lens+0 ); |
| 3012 |
|
SQLBindCol( hstmt, 2, SQL_C_ULONG, &parentXID, 0, lens+1 ); |
| 3013 |
|
SQLBindCol( hstmt, 3, SQL_C_ULONG, &ownerUID, 0, lens+2 ); |
| 3014 |
|
SQLBindCol( hstmt, 4, SQL_C_ULONG, &ownerGID, 0, lens+3 ); |
| 3015 |
|
SQLBindCol( hstmt, 5, SQL_C_ULONG, &openLevel, 0, lens+4 ); |
| 3016 |
|
SQLBindCol( hstmt, 6, SQL_C_ULONG, &sortNumber, 0, lens+5 ); |
| 3017 |
|
|
| 3018 |
|
SQLBindCol( hstmt, 7, SQL_C_ULONG, &itemTypeID, 0, lens+6 ); |
| 3019 |
|
SQLBindCol( hstmt, 8, SQL_C_CHAR , &subtype, XNP_ITEM_SUBTYPE_LEN+1, lens+7 ); |
| 3020 |
|
SQLBindCol( hstmt, 9, SQL_C_ULONG, &contributorUID, 0, lens+8 ); |
| 3021 |
|
SQLBindCol( hstmt,10, SQL_C_CHAR , &title, XNP_ITEM_TITLE_LEN+1, lens+9 ); |
| 3022 |
|
SQLBindCol( hstmt,11, SQL_C_CHAR , &keywords, XNP_ITEM_KEYWORDS_LEN+1, lens+10 ); |
| 3023 |
|
SQLBindCol( hstmt,12, SQL_C_CHAR , &description, XNP_ITEM_DESCRIPTION_LEN+1, lens+11 ); |
| 3024 |
|
SQLBindCol( hstmt,13, SQL_C_ULONG, &lastUpdateDate, 0, lens+12 ); |
| 3025 |
|
SQLBindCol( hstmt,14, SQL_C_ULONG, &creationDate, 0, lens+13 ); |
| 3026 |
|
|
| 3027 |
|
index_t *index = new index_t[len]; |
| 3028 |
|
int i = 0; |
| 3029 |
|
while ( i < len && ( sqlcode = SQLFetch( hstmt ) ) == SQL_SUCCESS ){ |
| 3030 |
|
if ( lens[ 7] == SQL_NULL_DATA ) subtype[0] = '\0'; |
| 3031 |
|
if ( lens[ 9] == SQL_NULL_DATA ) title[0] = '\0'; |
| 3032 |
|
if ( lens[10] == SQL_NULL_DATA ) keywords[0] = '\0'; |
| 3033 |
|
if ( lens[11] == SQL_NULL_DATA ) description[0] = '\0'; |
| 3034 |
|
index[i].setIndexID( xid ); |
| 3035 |
|
index[i].setParentIndexID( parentXID ); |
| 3036 |
|
index[i].setOwnerUID( ownerUID ); |
| 3037 |
|
index[i].setOwnerGID( ownerGID ); |
| 3038 |
|
index[i].setOpenLevel( openLevel ); |
| 3039 |
|
index[i].setSortNumber( sortNumber ); |
| 3040 |
|
index[i].setItemTypeID( itemTypeID ); |
| 3041 |
|
index[i].setSubtype( (char *)subtype ); |
| 3042 |
|
index[i].setContributorUID( contributorUID ); |
| 3043 |
|
index[i].setTitle( (char *)title ); |
| 3044 |
|
index[i].setKeywords( (char *)keywords ); |
| 3045 |
|
index[i].setDescription( (char *)description ); |
| 3046 |
|
index[i].setLastUpdateDate( lastUpdateDate ); |
| 3047 |
|
index[i].setCreationDate( creationDate ); |
| 3048 |
|
i++; |
| 3049 |
|
} |
| 3050 |
|
*indexes = index; |
| 3051 |
|
*indexesLen = i; |
| 3052 |
|
result = RES_OK; |
| 3053 |
|
}else{ |
| 3054 |
|
string message( "SQLExecDirect in getIndexesInternal. sql=" ); |
| 3055 |
|
message = message + sql; |
| 3056 |
|
setLastErrorString( message.c_str() ); |
| 3057 |
|
result = RES_ERROR; |
| 3058 |
|
} |
| 3059 |
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
| 3060 |
|
} |
| 3061 |
|
else { |
| 3062 |
|
setLastErrorString( "SQLAllocHandle(SQL_HANDLE_STMT,...) in getIndexesInternal" ); |
| 3063 |
|
result = RES_ERROR; |
| 3064 |
|
} |
| 3065 |
|
return result; |
| 3066 |
|
} |
| 3067 |
|
|
| 3068 |
|
/** |
| 3069 |
|
* |
| 3070 |
|
* uidの人が(ownerUID,ownerGID,openLevel)のインデックスに書き込む権限があるかどうか調べる。 |
| 3071 |
|
* |
| 3072 |
|
* @param uid セッションID |
| 3073 |
|
* @param ownerUID index所有者 |
| 3074 |
|
* @param ownerGID index所有グループ |
| 3075 |
|
* @param openLevel |
| 3076 |
|
* @return RES_OK 成功 |
| 3077 |
|
* |
| 3078 |
|
*/ |
| 3079 |
|
static bool isWritableInternal( sessionid_t sid, userid_t uid, userid_t ownerUID, groupid_t ownerGID, openlevel_t openLevel ){ |
| 3080 |
|
// todo: 遅いようならisGroupAdmin,isModeratorを使わずになんとかする |
| 3081 |
|
if ( openLevel == index::OL_PUBLIC ){ |
| 3082 |
|
} |
| 3083 |
|
else if ( openLevel == index::OL_GROUP_ONLY ){ |
| 3084 |
|
if ( isGroupAdmin( sid, ownerGID, uid ) ) |
| 3085 |
|
return true; |
| 3086 |
|
} |
| 3087 |
|
else if ( openLevel == index::OL_PRIVATE ){ |
| 3088 |
|
if ( uid == ownerUID ) |
| 3089 |
|
return true; |
| 3090 |
|
} |
| 3091 |
|
if ( isModerator(sid, uid) ) |
| 3092 |
|
return true; |
| 3093 |
|
char buf[100]; |
| 3094 |
|
sprintf( buf, "isWritableInternal: sid=%d uid=%d ownerUID=%d ownerGID=%d openLevel=%d", sid, uid, ownerUID, ownerGID, openLevel ); |
| 3095 |
|
setLastErrorString( buf ); |
| 3096 |
|
|
| 3097 |
|
return false; |
| 3098 |
|
} |
| 3099 |
|
|
| 3100 |
|
static bool isWritableInternal( sessionid_t sid, userid_t uid, const index_t *index ){ |
| 3101 |
|
return isWritableInternal( sid, uid, index->getOwnerUID(), index->getOwnerGID(), index->getOpenLevel() ); |
| 3102 |
|
} |
| 3103 |
|
|
| 3104 |
|
/** |
| 3105 |
|
* |
| 3106 |
|
* |
| 3107 |
|
* @param sid セッションID |
| 3108 |
|
* @param gid グループのUID |
| 3109 |
|
* @param uid ユーザのUID |
| 3110 |
|
* @return true 管理権限あり |
| 3111 |
|
* @return false 管理権限なし,または不明 |
| 3112 |
|
* |
| 3113 |
|
*/ |
| 3114 |
|
bool isGroupMemberInternal( sessionid_t sid, groupid_t gid, userid_t uid ) |
| 3115 |
|
{ |
| 3116 |
|
if( hdbc == NULL ) return false; |
| 3117 |
|
if( !isValidSessionID( sid ) ) return false; |
| 3118 |
|
if( !uidExists( uid ) ) return false; |
| 3119 |
|
if( !gidExists( gid ) ) return false; |
| 3120 |
|
|
| 3121 |
|
bool ret = false; |
| 3122 |
|
string sql; |
| 3123 |
|
SQLRETURN sqlcode; |
| 3124 |
|
SQLINTEGER count = 0; |
| 3125 |
|
|
| 3126 |
|
sql = "SELECT * FROM " + dbprefix + "_xnpaccount_groups_users_link "; |
| 3127 |
|
sql += "WHERE gid=" + string( unsignedIntToString( gid ) ); |
| 3128 |
|
sql += " AND uid=" + string( unsignedIntToString( uid ) ); |
| 3129 |
|
if( countResultRows( sql.c_str(), &count ) == RES_OK ){ |
| 3130 |
|
if( count > 0 ){ |
| 3131 |
|
ret = true; |
| 3132 |
|
}else{ |
| 3133 |
|
ret = false; |
| 3134 |
|
} |
| 3135 |
|
}else{ |
| 3136 |
|
ret = false; |
| 3137 |
|
} |
| 3138 |
|
return ret; |
| 3139 |
|
} |
| 3140 |
|
|
| 3141 |
|
|
| 3142 |
|
/** |
| 3143 |
|
* |
| 3144 |
|
* uidの人が(ownerUID,ownerGID,openLevel)のインデックスを読み込む権限があるかどうか調べる。 |
| 3145 |
|
* |
| 3146 |
|
* @param uid セッションID |
| 3147 |
|
* @param ownerUID index所有者 |
| 3148 |
|
* @param ownerGID index所有グループ |
| 3149 |
|
* @param openLevel |
| 3150 |
|
* @return RES_OK 成功 |
| 3151 |
|
* |
| 3152 |
|
*/ |
| 3153 |
|
static bool isReadableInternal( sessionid_t sid, userid_t uid, userid_t ownerUID, groupid_t ownerGID, openlevel_t openLevel ){ |
| 3154 |
|
// todo: 遅いようならisGroupMemberInternalを使わずになんとかする |
| 3155 |
|
if ( openLevel == index::OL_PUBLIC ){ |
| 3156 |
|
return true; |
| 3157 |
|
} |
| 3158 |
|
else if ( openLevel == index::OL_GROUP_ONLY ){ |
| 3159 |
|
if ( isGroupMemberInternal( sid, ownerGID, uid ) ) |
| 3160 |
|
return true; |
| 3161 |
|
} |
| 3162 |
|
else if ( openLevel == index::OL_PRIVATE ){ |
| 3163 |
|
if ( uid == ownerUID ) |
| 3164 |
|
return true; |
| 3165 |
|
} |
| 3166 |
|
if ( isModerator(sid, uid) ) |
| 3167 |
|
return true; |
| 3168 |
|
return false; |
| 3169 |
|
} |
| 3170 |
|
|
| 3171 |
|
static bool isReadableInternal( sessionid_t sid, userid_t uid, const index_t *index ){ |
| 3172 |
|
return isReadableInternal( sid, uid, index->getOwnerUID(), index->getOwnerGID(), index->getOpenLevel() ); |
| 3173 |
|
} |
| 3174 |
|
|
| 3175 |
|
|
| 3176 |
|
/** |
| 3177 |
|
* |
| 3178 |
|
* インデックスキーワードへの読み込み権を調べる |
| 3179 |
|
* |
| 3180 |
|
* @param sid セッションID |
| 3181 |
|
* @param xid 取得したいインデックスキーワードのXID |
| 3182 |
|
* @return |
| 3183 |
|
* |
| 3184 |
|
*/ |
| 3185 |
|
bool isIndexReadable( sessionid_t sid, indexid_t xid ) |
| 3186 |
|
{ |
| 3187 |
|
result_t result; |
| 3188 |
|
userid_t uid; |
| 3189 |
|
if( hdbc == NULL ) return false; |
| 3190 |
|
|
| 3191 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3192 |
|
if( result == RES_OK ){ |
| 3193 |
|
string criteria; |
| 3194 |
|
string cond( "tx.index_id = " + unsignedIntToString( xid ) ); |
| 3195 |
|
const index_t *indexes; |
| 3196 |
|
int indexesLen; |
| 3197 |
|
// todo: 遅いようなら他の方法にする |
| 3198 |
|
result = getIndexesInternal( sid, cond.c_str() , uid, &indexes, &indexesLen, criteria ); |
| 3199 |
|
if ( result == RES_OK ){ |
| 3200 |
|
freeIndex( indexes ); |
| 3201 |
|
if ( indexesLen != 0 ){ |
| 3202 |
|
return true; |
| 3203 |
|
} |
| 3204 |
|
else ; // 不正なxid |
| 3205 |
|
} |
| 3206 |
|
} |
| 3207 |
|
return false; |
| 3208 |
|
} |
| 3209 |
|
|
| 3210 |
|
/** |
| 3211 |
|
* |
| 3212 |
|
* インデックスキーワードへの書き込み権を調べる |
| 3213 |
|
* |
| 3214 |
|
* @param sid セッションID |
| 3215 |
|
* @param xid 取得したいインデックスキーワードのXID |
| 3216 |
|
* @return |
| 3217 |
|
* |
| 3218 |
|
*/ |
| 3219 |
|
bool isIndexWritable( sessionid_t sid, indexid_t xid ) |
| 3220 |
|
{ |
| 3221 |
|
result_t result; |
| 3222 |
|
userid_t uid; |
| 3223 |
|
if( hdbc == NULL ) return false; |
| 3224 |
|
|
| 3225 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3226 |
|
if( result == RES_OK ){ |
| 3227 |
|
string criteria; |
| 3228 |
|
string cond( "tx.index_id = " + unsignedIntToString( xid ) ); |
| 3229 |
|
const index_t *indexes; |
| 3230 |
|
int indexesLen; |
| 3231 |
|
// todo: 遅いようなら他の方法にする |
| 3232 |
|
result = getIndexesInternal( sid, cond.c_str() , uid, &indexes, &indexesLen, criteria ); |
| 3233 |
|
if ( result == RES_OK ){ |
| 3234 |
|
bool writable = false; |
| 3235 |
|
if ( indexesLen != 0 ){ |
| 3236 |
|
writable = isWritableInternal( sid, uid, indexes ); |
| 3237 |
|
} |
| 3238 |
|
freeIndex( indexes ); |
| 3239 |
|
return writable; |
| 3240 |
|
} |
| 3241 |
|
} |
| 3242 |
|
return false; |
| 3243 |
|
} |
| 3244 |
|
|
| 3245 |
|
|
| 3246 |
|
|
| 3247 |
|
|
| 3248 |
|
/** parentXIDの直下のインデックスのsort_numberの最大値+1 を求める。parentXIDの値が有効かどうかは判断しない。 |
| 3249 |
|
* ROOT直下はsort_numberの埋め方が異なるので、この関数では処理できない。 |
| 3250 |
|
* @param parentXID 親index_id |
| 3251 |
|
* @param sortNumber max(sort_number)+1 |
| 3252 |
|
* @return RES_OK 成功 |
| 3253 |
|
*/ |
| 3254 |
|
result_t getNewSortNumber( indexid_t parentXID, unsigned int *sortNumber ){ |
| 3255 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3256 |
|
|
| 3257 |
|
string sql = "SELECT max(sort_number) FROM " + dbprefix + "_xnpaccount_index WHERE parent_index_id=" + unsignedIntToString(parentXID); |
| 3258 |
|
unsigned int u; |
| 3259 |
|
result_t result = queryGetUnsignedInt( "getNewSortNumber", sql, &u ); |
| 3260 |
|
if ( result == RES_OK ){ |
| 3261 |
|
if ( u == 0 ) // NULLだった。つまりparentXIDはleaf node である。 |
| 3262 |
|
*sortNumber = 1; // sort_number=0は予約済みなので1から始まる |
| 3263 |
|
else |
| 3264 |
|
*sortNumber = u+1; |
| 3265 |
|
} |
| 3266 |
|
return result; |
| 3267 |
|
} |
| 3268 |
|
|
| 3269 |
|
/** |
| 3270 |
|
* |
| 3271 |
|
* インデックスキーワードを取得する |
| 3272 |
|
* |
| 3273 |
|
* @param sid セッションID |
| 3274 |
|
* @param xid 取得したいインデックスキーワードのXID |
| 3275 |
|
* @param index 取得したインデックスキーワード |
| 3276 |
|
* @return RES_OK 成功 |
| 3277 |
|
* |
| 3278 |
|
*/ |
| 3279 |
|
result_t getIndex( sessionid_t sid, indexid_t xid, const index_t **index ) |
| 3280 |
|
{ |
| 3281 |
|
result_t result; |
| 3282 |
|
userid_t uid; |
| 3283 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3284 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3285 |
|
if( result == RES_OK ){ |
| 3286 |
|
string criteriaString; |
| 3287 |
|
string cond( " index_id = "); |
| 3288 |
|
cond += unsignedIntToString(xid); |
| 3289 |
|
int indexesLen; |
| 3290 |
|
result = getIndexesInternal( sid, cond.c_str(), uid, index, &indexesLen, criteriaString ); |
| 3291 |
|
if ( result == RES_OK && indexesLen == 0 ){ |
| 3292 |
|
string s = "in getIndex: no match " + cond; |
| 3293 |
|
setLastErrorString( s.c_str() ); |
| 3294 |
|
result = RES_ERROR; |
| 3295 |
|
} |
| 3296 |
|
} |
| 3297 |
|
return result; |
| 3298 |
|
} |
| 3299 |
|
|
| 3300 |
|
/** |
| 3301 |
|
* |
| 3302 |
|
* 全てのインデックスキーワードを得る |
| 3303 |
|
* |
| 3304 |
|
* @param sid セッションID |
| 3305 |
|
* @param cri 結果の範囲指定,ソート条件指定 |
| 3306 |
|
* @param indexes indexの配列を受け取るポインタ |
| 3307 |
|
* @param indexesLen indexes配列の要素数 |
| 3308 |
|
* @return RES_OK 成功 |
| 3309 |
|
* |
| 3310 |
|
*/ |
| 3311 |
|
result_t getAllIndexes( sessionid_t sid, criteria_t *cri, const index_t **indexes, int *indexesLen ) |
| 3312 |
|
{ |
| 3313 |
|
result_t result; |
| 3314 |
|
userid_t uid; |
| 3315 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3316 |
|
|
| 3317 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3318 |
|
if( result == RES_OK ){ |
| 3319 |
|
string criteriaString = criteria2str( cri ); |
| 3320 |
|
result = getIndexesInternal( sid, 0, uid, indexes, indexesLen, criteriaString ); |
| 3321 |
|
} |
| 3322 |
|
return result; |
| 3323 |
|
} |
| 3324 |
|
|
| 3325 |
|
/** |
| 3326 |
|
* |
| 3327 |
|
* 特定のインデックスキーワードの全ての子インデックスキーワードを得る |
| 3328 |
|
* |
| 3329 |
|
* @param sid セッションID |
| 3330 |
|
* @param parentXID このインデックスの子を得る |
| 3331 |
|
* @param cri 結果の範囲指定,ソート条件指定 |
| 3332 |
|
* @param indexes indexの配列を受け取るポインタ |
| 3333 |
|
* @param indexesLen indexes配列の要素数 |
| 3334 |
|
* @return RES_OK 成功 |
| 3335 |
|
* |
| 3336 |
|
*/ |
| 3337 |
|
result_t getIndexes( sessionid_t sid, indexid_t parentXID, criteria_t *cri, const index_t **indexes, int *indexesLen ) |
| 3338 |
|
{ |
| 3339 |
|
result_t result; |
| 3340 |
|
userid_t uid; |
| 3341 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3342 |
|
|
| 3343 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3344 |
|
if( result == RES_OK ){ |
| 3345 |
|
string criteriaString = criteria2str( cri ); |
| 3346 |
|
string cond( " parent_index_id = "); |
| 3347 |
|
cond += unsignedIntToString(parentXID); |
| 3348 |
|
|
| 3349 |
|
result = getIndexesInternal( sid, cond.c_str(), uid, indexes, indexesLen, criteriaString ); |
| 3350 |
|
} |
| 3351 |
|
return result; |
| 3352 |
|
} |
| 3353 |
|
|
| 3354 |
|
/** インデックスを作成する。引数のチェックは行わない。 |
| 3355 |
|
*/ |
| 3356 |
|
static result_t insertIndexInternal( sessionid_t sid, index_t *index, indexid_t *xid ){ |
| 3357 |
|
itemid_t iid; |
| 3358 |
|
|
| 3359 |
|
result_t result = insertItemInternal( sid, index, &iid ); |
| 3360 |
|
if ( result == RES_OK ){ |
| 3361 |
|
string sql = "INSERT INTO " + dbprefix + "_xnpaccount_index ( parent_index_id, uid, gid, open_level, sort_number ) values ( " |
| 3362 |
|
+ unsignedIntToString(index->getParentIndexID()) + "," + unsignedIntToString(index->getOwnerUID()) + "," |
| 3363 |
|
+ unsignedIntToString(index->getOwnerGID()) + "," + unsignedIntToString(index->getOpenLevel()) + "," |
| 3364 |
|
+ unsignedIntToString(index->getSortNumber()) + ") "; |
| 3365 |
|
result = querySimple( "insertIndexInternal", sql ); |
| 3366 |
|
if( result == RES_OK ){ |
| 3367 |
|
*xid = iid; |
| 3368 |
|
} |
| 3369 |
|
else { |
| 3370 |
|
sql = "DELETE FROM " + dbprefix + "_xnpaccount_item where item_id=" + unsignedIntToString( iid ); |
| 3371 |
|
querySimple( "insertIndexInternal", sql ); |
| 3372 |
|
string message( "in insertIndexInternal: bad uid/gid/openlevel. sql=" ); |
| 3373 |
|
message = message + sql; |
| 3374 |
|
setLastErrorString( message.c_str() ); |
| 3375 |
|
result = RES_ERROR; // エラー: insertに失敗した |
| 3376 |
|
} |
| 3377 |
|
}else{ |
| 3378 |
|
; |
| 3379 |
|
} |
| 3380 |
|
return result; |
| 3381 |
|
} |
| 3382 |
|
|
| 3383 |
|
/** |
| 3384 |
|
* |
| 3385 |
|
* インデックスキーワードを登録する |
| 3386 |
|
* |
| 3387 |
|
* @param sid セッションID |
| 3388 |
|
* @param index 登録するインデックスキーワード |
| 3389 |
|
* @param xid 登録したインデックスのItemID |
| 3390 |
|
* @return RES_OK 成功 |
| 3391 |
|
* |
| 3392 |
|
*/ |
| 3393 |
|
result_t insertIndex( sessionid_t sid, index_t *index, indexid_t *xid ) |
| 3394 |
|
{ |
| 3395 |
|
result_t result = RES_ERROR; |
| 3396 |
|
userid_t uid; |
| 3397 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3398 |
|
|
| 3399 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3400 |
|
if( result != RES_OK ) return result; |
| 3401 |
|
|
| 3402 |
|
if( index->getParentIndexID() == item::IID_ROOT || |
| 3403 |
|
index->getParentIndexID() == item::IID_BINDERS ){ |
| 3404 |
|
setLastErrorString( "in insertIndex: parentXID must not Root/Binders " ); |
| 3405 |
|
return RES_ERROR; // エラー: Root/Binders直下には作成できない。 |
| 3406 |
|
} |
| 3407 |
|
|
| 3408 |
|
// parentXID のアクセス権を調べる |
| 3409 |
|
SQLRETURN sqlcode; |
| 3410 |
|
SQLHANDLE hstmt = NULL; |
| 3411 |
|
string sql; |
| 3412 |
|
|
| 3413 |
|
SQLINTEGER cbTitle = SQL_NTS, parentXIDInd = 0; |
| 3414 |
|
SQLINTEGER parentXID = index->getParentIndexID(); |
| 3415 |
|
string indexTable = dbprefix + "_xnpaccount_index"; |
| 3416 |
|
string itemTable = dbprefix + "_xnpaccount_item_basic"; |
| 3417 |
|
sql = "SELECT tx_parent.uid, tx_parent.gid, tx_parent.open_level, tx_child.index_id, ti_child.item_id " |
| 3418 |
|
" FROM " + indexTable + " AS tx_parent " |
| 3419 |
|
" LEFT JOIN " + indexTable + " AS tx_child ON tx_child.parent_index_id = tx_parent.index_id " |
| 3420 |
|
" LEFT JOIN " + itemTable + " AS ti_child ON tx_child.index_id = ti_child.item_id AND ti_child.title = ? AND ti_child.item_type_id = " + unsignedIntToString( item::ITID_INDEX ) + |
| 3421 |
|
" WHERE tx_parent.index_id = ? "; |
| 3422 |
|
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
| 3423 |
|
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, XNP_ITEM_TITLE_LEN, 0, (SQLCHAR *)index->getTitle(), strlen(index->getTitle()), &cbTitle ); |
| 3424 |
|
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 10, 0, &parentXID, 0, &parentXIDInd ); |
| 3425 |
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), sql.length() ) ) == SQL_SUCCESS ){ |
| 3426 |
|
SQLUINTEGER parentUID = 0, parentGID = 0, parentOpenLevel = 0, childXID = 0, childItemID = 0; |
| 3427 |
|
SQLINTEGER len1, len2, len3, len4, len5; |
| 3428 |
|
SQLBindCol( hstmt, 1, SQL_C_ULONG, &parentUID, 0, &len1 ); |
| 3429 |
|
SQLBindCol( hstmt, 2, SQL_C_ULONG, &parentGID, 0, &len2 ); |
| 3430 |
|
SQLBindCol( hstmt, 3, SQL_C_ULONG, &parentOpenLevel, 0, &len3 ); |
| 3431 |
|
SQLBindCol( hstmt, 4, SQL_C_ULONG, &childXID, 0, &len4 ); |
| 3432 |
|
SQLBindCol( hstmt, 5, SQL_C_ULONG, &childItemID, 0, &len5 ); |
| 3433 |
|
if( ( sqlcode = SQLFetch( hstmt ) ) == SQL_SUCCESS ){ |
| 3434 |
|
if ( len5 != SQL_NULL_DATA ){ |
| 3435 |
|
setLastErrorString( "in insertIndex: title conflict" ); |
| 3436 |
|
result = RES_ERROR; // エラー: 同名の子indexが既に存在する。 |
| 3437 |
|
} |
| 3438 |
|
else if ( !isWritableInternal( sid, uid, parentUID, parentGID, parentOpenLevel ) ){ |
| 3439 |
|
setLastErrorString( "in insertIndex: cannot write to parentindex" ); |
| 3440 |
|
result = RES_ERROR; // エラー: 親インデックスへの書き込み権限が無い。 |
| 3441 |
|
} |
| 3442 |
|
/* else if ( !(parentOpenLevel == index::OL_PUBLIC && index->getOpenLevel() == index::OL_PUBLIC) |
| 3443 |
|
&& !(parentOpenLevel == index::OL_GROUP_ONLY && index->getOpenLevel() == index::OL_GROUP_ONLY && parentGID == index->getOwnerGID()) |
| 3444 |
|
&& !(parentOpenLevel == index::OL_PRIVATE && index->getOpenLevel() == index::OL_PRIVATE && parentUID == index->getOwnerUID())) { |
| 3445 |
|
setLastErrorString( "in insertIndex: bad uid/gid/openlevel" ); |
| 3446 |
|
result = RES_ERROR; // エラー: 親インデックスとアクセス権限が矛盾する。 |
| 3447 |
|
} |
| 3448 |
|
*/ |
| 3449 |
|
else { |
| 3450 |
|
unsigned int sortNumber; |
| 3451 |
|
result = getNewSortNumber( index->getParentIndexID(), &sortNumber ); |
| 3452 |
|
if ( result == RES_OK ){ |
| 3453 |
|
index->setOpenLevel( parentOpenLevel ); |
| 3454 |
|
index->setOwnerGID( parentGID ); |
| 3455 |
|
index->setOwnerUID( parentUID ); |
| 3456 |
|
index->setSortNumber( sortNumber ); |
| 3457 |
|
// インデックスを作成する。 |
| 3458 |
|
result = insertIndexInternal( sid, index, xid ); |
| 3459 |
|
} |
| 3460 |
|
else { |
| 3461 |
|
; // error: getNewSortNumber failed. |
| 3462 |
|
} |
| 3463 |
|
} |
| 3464 |
|
}else { |
| 3465 |
|
string s( "SQLFetch in insertIndex sql=" ); |
| 3466 |
|
s += sql; |
| 3467 |
|
s += " sqlcode=" + intToString(sqlcode); |
| 3468 |
|
s += odbcDiagString( SQL_HANDLE_STMT, hstmt, sqlcode ); |
| 3469 |
|
setLastErrorString( s.c_str() ); |
| 3470 |
|
result = RES_ERROR; |
| 3471 |
|
} |
| 3472 |
|
}else{ |
| 3473 |
|
string s( "in insertIndex: SQLExecDirect failed. sql=" ); |
| 3474 |
|
s += sql; |
| 3475 |
|
s += " sqlcode=" + intToString(sqlcode); |
| 3476 |
|
s += odbcDiagString( SQL_HANDLE_STMT, hstmt, sqlcode ); |
| 3477 |
|
setLastErrorString( s.c_str() ); |
| 3478 |
|
result = RES_ERROR; |
| 3479 |
|
} |
| 3480 |
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
| 3481 |
|
} |
| 3482 |
|
else { |
| 3483 |
|
setLastErrorString( "SQLAllocHandle in insertIndex" ); |
| 3484 |
|
result = RES_ERROR; |
| 3485 |
|
} |
| 3486 |
|
return result; |
| 3487 |
|
} |
| 3488 |
|
|
| 3489 |
|
/** 内部で使用。xidの子孫(xidを含む)のインデックスのIDを全て取得する。delete[] *descndexIDが必要。 |
| 3490 |
|
* @param xid 対象 |
| 3491 |
|
* @param descXID 子孫を受け取る配列 |
| 3492 |
|
* @param descXIDLen descXIDの配列長 |
| 3493 |
|
*/ |
| 3494 |
|
result_t getDescendantIndexID( int xid, indexid_t **descXID, int *descXIDLen ){ |
| 3495 |
|
// todo |
| 3496 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3497 |
|
|
| 3498 |
|
string cond = "select count(*) from " + dbprefix + "_xnpaccount_index"; |
| 3499 |
|
unsigned int allIndexCount; |
| 3500 |
|
result_t result = queryGetUnsignedInt( "getDescendantIndexID", cond, &allIndexCount ); |
| 3501 |
|
if ( result != RES_OK ) |
| 3502 |
|
return result; |
| 3503 |
|
|
| 3504 |
|
indexid_t *p0 = new indexid_t[allIndexCount+1]; |
| 3505 |
|
indexid_t *p = p0; |
| 3506 |
|
indexid_t *pFill = p0; |
| 3507 |
|
indexid_t *pEnd = p0 + allIndexCount+1; |
| 3508 |
|
*pFill++ = xid; |
| 3509 |
|
/* *p 〜 *(pFill-1) : 未探索ノード。これが空になると探索終了。 |
| 3510 |
|
*pFill 〜 *(pEnd-1) : 空き領域。これが空になると、それ以上探索できないので異常終了 |
| 3511 |
|
*/ |
| 3512 |
|
SQLRETURN sqlcode; |
| 3513 |
|
SQLHANDLE hstmt = NULL; |
| 3514 |
|
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
| 3515 |
|
result = RES_ERROR; |
| 3516 |
|
while ( true ) { |
| 3517 |
|
if ( p == pFill ){ |
| 3518 |
|
// もう未探索ノードが無い。 |
| 3519 |
|
result = RES_OK; |
| 3520 |
|
break; |
| 3521 |
|
} |
| 3522 |
|
else if ( pFill == pEnd ){ |
| 3523 |
|
// これ以上探索できない。 |
| 3524 |
|
result = RES_ERROR; |
| 3525 |
|
setLastErrorString( "getDescendantIndexID: index buffer overflow." ); |
| 3526 |
|
break; |
| 3527 |
|
} |
| 3528 |
|
|
| 3529 |
|
xid = *p++; // 未探索ノードを1つ取り出す |
| 3530 |
|
|
| 3531 |
|
// 子を列挙して未探索ノードとして追加。 |
| 3532 |
|
string sql = "SELECT index_id FROM " + dbprefix + "_xnpaccount_index WHERE parent_index_id=" + unsignedIntToString(xid); |
| 3533 |
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), sql.length() ) ) == SQL_SUCCESS ){ |
| 3534 |
|
SQLUINTEGER sXID = 0; |
| 3535 |
|
SQLINTEGER len; |
| 3536 |
|
SQLBindCol( hstmt, 1, SQL_C_ULONG, &sXID, 0, &len ); |
| 3537 |
|
while ( ( sqlcode = SQLFetch( hstmt ) ) == SQL_SUCCESS ){ |
| 3538 |
|
*pFill++ = sXID; |
| 3539 |
|
if ( pFill == pEnd ) |
| 3540 |
|
break; |
| 3541 |
|
} |
| 3542 |
|
}else{ |
| 3543 |
|
setLastErrorString( "SQLExecDirect in getDescendantIndexID" ); |
| 3544 |
|
result = RES_ERROR; |
| 3545 |
|
break; |
| 3546 |
|
} |
| 3547 |
|
} |
| 3548 |
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
| 3549 |
|
}else{ |
| 3550 |
|
setLastErrorString( "SQLAllocHandle in getDescendantIndexID" ); |
| 3551 |
|
result = RES_ERROR; |
| 3552 |
|
} |
| 3553 |
|
|
| 3554 |
|
if ( result == RES_OK ){ |
| 3555 |
|
*descXID = p0; |
| 3556 |
|
*descXIDLen = pFill - p0; |
| 3557 |
|
} |
| 3558 |
|
else { |
| 3559 |
|
delete[] p0; |
| 3560 |
|
} |
| 3561 |
|
return result; |
| 3562 |
|
} |
| 3563 |
|
|
| 3564 |
|
|
| 3565 |
|
#if 0 |
| 3566 |
|
typedef struct { |
| 3567 |
|
indexid_t xid; |
| 3568 |
|
indexid_t parentXID; |
| 3569 |
|
int tag; |
| 3570 |
|
} indexLink_t; |
| 3571 |
|
/** 全ての(index_id,parent_index_id)を列挙する。 |
| 3572 |
|
* @param links 配列。RES_OKを返した場合のみ有効。delete[]が必要。 |
| 3573 |
|
* @param linksLen linksの配列長 |
| 3574 |
|
*/ |
| 3575 |
|
static result_t getAllIndexLink( indexLink_t **links, int *linksLen ){ |
| 3576 |
|
result_t result = RES_OK; |
| 3577 |
|
string sql("SELECT COUNT(*) from " + dbprefix + "_xnpaccount_index"); |
| 3578 |
|
int totalIndexCount; |
| 3579 |
|
result = getCountInternal( "getAllIndexLink", sql, &totalIndexCount ); |
| 3580 |
|
|
| 3581 |
|
if ( result != RES_OK ){ |
| 3582 |
|
return result; |
| 3583 |
|
} |
| 3584 |
|
|
| 3585 |
|
SQLRETURN sqlcode; |
| 3586 |
|
SQLHANDLE hstmt = NULL; |
| 3587 |
|
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
| 3588 |
|
string sql("SELECT index_id, parent_index_id FROM " + dbprefix + "_xnpaccount_index ORDER BY index_id"); |
| 3589 |
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), sql.length() ) ) == SQL_SUCCESS ){ |
| 3590 |
|
SQLUINTEGER xid = 0, parentXID = 0; |
| 3591 |
|
SQLINTEGER len1, len2; |
| 3592 |
|
SQLBindCol( hstmt, 1, SQL_C_ULONG, &xid, 0, &len1 ); |
| 3593 |
|
SQLBindCol( hstmt, 2, SQL_C_ULONG, &parentXID, 0, &len2 ); |
| 3594 |
|
|
| 3595 |
|
indexLink_t *p = new indexLink_t[totalIndexCount]; |
| 3596 |
|
int i = 0; |
| 3597 |
|
while ( ( sqlcode = SQLFetch( hstmt ) ) == SQL_SUCCESS ){ |
| 3598 |
|
if ( i == totalIndexCount ){ |
| 3599 |
|
result = RES_ERROR; |
| 3600 |
|
break; |
| 3601 |
|
} |
| 3602 |
|
p[i].xid = xid; |
| 3603 |
|
p[i].parentXID = parentXID; |
| 3604 |
|
p[i].tag = 0; |
| 3605 |
|
i++; |
| 3606 |
|
} |
| 3607 |
|
if ( result == RES_OK ){ |
| 3608 |
|
*links = p; |
| 3609 |
|
*linksLen = i; |
| 3610 |
|
|
| 3611 |
|
for ( |
| 3612 |
|
|
| 3613 |
|
} |
| 3614 |
|
} |
| 3615 |
|
else { |
| 3616 |
|
setLastErrorString( "SQLExecDirect in getAllIndexLink" ); |
| 3617 |
|
result = RES_ERROR; |
| 3618 |
|
} |
| 3619 |
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
| 3620 |
|
}else{ |
| 3621 |
|
setLastErrorString( "SQLAllocHandle(SQL_HANDLE_STMT,...) in getAllIndexLink" ); |
| 3622 |
|
result = RES_ERROR; |
| 3623 |
|
} |
| 3624 |
|
return result; |
| 3625 |
|
} |
| 3626 |
|
#endif |
| 3627 |
|
|
| 3628 |
|
|
| 3629 |
|
result_t updateIndexInternal( sessionid_t sid, userid_t uid, index_t *newIndex, const index_t *oldIndex, const index_t *newParentIndex, const index_t *oldParentIndex ){ |
| 3630 |
|
bool move = ( newIndex->getParentIndexID() != oldIndex->getParentIndexID() ); |
| 3631 |
|
|
| 3632 |
|
result_t result = RES_ERROR; |
| 3633 |
|
if ( ( oldIndex->getItemID() == item::IID_ROOT || oldIndex->getParentIndexID() == item::IID_ROOT || oldIndex->getIndexID() == item::IID_BINDERS ) |
| 3634 |
|
&& ( newIndex->getOwnerUID() != oldIndex->getOwnerUID() |
| 3635 |
|
|| newIndex->getOwnerGID() != oldIndex->getOwnerGID() |
| 3636 |
|
|| newIndex->getOpenLevel() != oldIndex->getOpenLevel() ) ){ |
| 3637 |
|
setLastErrorString( "in updateIndex: cannot change owner/openlevel of system-created-index" ); |
| 3638 |
|
return RES_ERROR; // Root/Binder/Public/Group/Privateの公開属性を書き換えることはできない。 |
| 3639 |
|
} |
| 3640 |
|
|
| 3641 |
|
// parent_index_idを書き換える場合は更に面倒なエラーチェックを行う |
| 3642 |
|
if ( move ){ |
| 3643 |
|
if ( oldIndex->getItemID() == item::IID_ROOT || oldIndex->getParentIndexID() == item::IID_ROOT ){ |
| 3644 |
|
setLastErrorString( "in updateIndex: cannot change parent_index_id of system-created-index" ); |
| 3645 |
|
return RES_ERROR; //自分がRootあるいは親がRootの場合は、親XIDを変更できない。 |
| 3646 |
|
} |
| 3647 |
|
else if ( newIndex->getParentIndexID() == item::IID_BINDERS ){ |
| 3648 |
|
setLastErrorString( "in updateIndex: parent_index_id must not be BINDERS" ); |
| 3649 |
|
return RES_ERROR; // 親をBinderにすることはできない。 |
| 3650 |
|
} |
| 3651 |
|
else if ( newIndex->getParentIndexID() == item::IID_ROOT ){ |
| 3652 |
|
setLastErrorString( "in updateIndex: cannot change parent_index_id to ROOT" ); |
| 3653 |
|
return RES_ERROR; // 親がRootでないなら、親をRootにすることはできない。 |
| 3654 |
|
} |
| 3655 |
|
} |
| 3656 |
|
|
| 3657 |
|
// 親ディレクトリに書き込めるかどうかチェック |
| 3658 |
|
if ( !isWritableInternal( sid, uid, newParentIndex ) ){ |
| 3659 |
|
setLastErrorString( "in updateIndex: no access right. cannot move." ); |
| 3660 |
|
return RES_ERROR; // 移動先への書き込み権限が必要。 |
| 3661 |
|
} |
| 3662 |
|
|
| 3663 |
|
// sort_numberを変更する場合は重複が無いかどうかチェック。ただし移動する場合は自動でsort_numberが振られるのでチェックしない |
| 3664 |
|
if ( !move && newIndex->getSortNumber() != oldIndex->getSortNumber() ){ |
| 3665 |
|
const index_t *conflictIndexes; |
| 3666 |
|
int conflictIndexesLen; |
| 3667 |
|
string criteriaString; |
| 3668 |
|
string cond("tx.sort_number=" + unsignedIntToString(newIndex->getSortNumber())); |
| 3669 |
|
result = getIndexesInternal( sid, cond.c_str() , 0, &conflictIndexes, &conflictIndexesLen, criteriaString ); |
| 3670 |
|
if ( result == RES_OK ){ |
| 3671 |
|
freeIndex( conflictIndexes ); |
| 3672 |
|
if ( conflictIndexesLen != 0 ){ |
| 3673 |
|
setLastErrorString( "in updateIndex: sort_number conflicts" ); |
| 3674 |
|
return RES_ERROR; // sortNumberの重複あり |
| 3675 |
|
} |
| 3676 |
|
else { |
| 3677 |
|
;// sortNumberの重複無し。 |
| 3678 |
|
} |
| 3679 |
|
} |
| 3680 |
|
else { |
| 3681 |
|
return result; // cannot getIndexesInternal() |
| 3682 |
|
} |
| 3683 |
|
} |
| 3684 |
|
|
| 3685 |
|
|
| 3686 |
|
if ( move ){ |
| 3687 |
|
indexid_t *descXID = 0; |
| 3688 |
|
int descXIDLen; |
| 3689 |
|
|
| 3690 |
|
// 子孫のxidを列挙。循環のチェックを行う。 |
| 3691 |
|
result = getDescendantIndexID( oldIndex->getIndexID(), &descXID, &descXIDLen ); |
| 3692 |
|
if ( result != RES_OK ){ |
| 3693 |
|
setLastErrorString( "in updateIndexInternal: getDescendantIndexID failed" ); |
| 3694 |
|
return RES_ERROR; |
| 3695 |
|
} |
| 3696 |
|
int i; |
| 3697 |
|
for ( i = 0; i < descXIDLen; i++ ){ |
| 3698 |
|
if ( descXID[i] == newIndex->getParentIndexID() ){ |
| 3699 |
|
break; |
| 3700 |
|
} |
| 3701 |
|
} |
| 3702 |
|
freeIndexID( descXID ); |
| 3703 |
|
if ( i != descXIDLen ){ |
| 3704 |
|
// 子孫のIndexを親にしようとした |
| 3705 |
|
setLastErrorString( "in updateIndexInternal: circular parent" ); |
| 3706 |
|
return RES_ERROR; |
| 3707 |
|
} |
| 3708 |
|
|
| 3709 |
|
// sort_numberを生成する。 |
| 3710 |
|
unsigned int sortNumber; |
| 3711 |
|
result = getNewSortNumber(newParentIndex->getIndexID(), &sortNumber); |
| 3712 |
|
if ( result != RES_OK ){ |
| 3713 |
|
return result; |
| 3714 |
|
} |
| 3715 |
|
newIndex->setSortNumber( sortNumber ); |
| 3716 |
|
} |
| 3717 |
|
|
| 3718 |
|
SQLRETURN sqlcode; |
| 3719 |
|
SQLHANDLE hstmt = NULL; |
| 3720 |
|
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
| 3721 |
|
string ownerUIDString = "0"; |
| 3722 |
|
string ownerGIDString = "0"; |
| 3723 |
|
if ( newIndex->getOwnerUID() != 0 ) ownerUIDString = unsignedIntToString(newIndex->getOwnerUID()); |
| 3724 |
|
if ( newIndex->getOwnerGID() != 0 ) ownerGIDString = unsignedIntToString(newIndex->getOwnerGID()); |
| 3725 |
|
string sql("UPDATE " + dbprefix + "_xnpaccount_index set" |
| 3726 |
|
" parent_index_id = " + unsignedIntToString(newIndex->getParentIndexID()) + |
| 3727 |
|
", uid = " + ownerUIDString + |
| 3728 |
|
", gid = " + ownerGIDString + |
| 3729 |
|
", open_level = " + unsignedIntToString(newIndex->getOpenLevel()) + |
| 3730 |
|
", sort_number = " + unsignedIntToString(newIndex->getSortNumber()) + |
| 3731 |
|
" where index_id = " + unsignedIntToString(newIndex->getIndexID()) ); |
| 3732 |
|
|
| 3733 |
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), sql.length() ) ) == SQL_SUCCESS ){ |
| 3734 |
|
string sql("UPDATE " + dbprefix + "_xnpaccount_item_basic set" |
| 3735 |
|
" item_type_id = " + unsignedIntToString(newIndex->getItemTypeID()) + |
| 3736 |
|
", uid = " + unsignedIntToString(newIndex->getContributorUID()) + |
| 3737 |
|
", last_update_date = " + unsignedIntToString(newIndex->getLastUpdateDate()) + |
| 3738 |
|
", creation_date = " + unsignedIntToString(newIndex->getCreationDate()) + |
| 3739 |
|
", item_subtype = ?, title = ?, keywords = ?, description = ? " |
| 3740 |
|
" where item_id = " + unsignedIntToString(newIndex->getIndexID()) ); |
| 3741 |
|
sqlcode = SQLPrepare(hstmt, (SQLCHAR*)sql.c_str(), SQL_NTS); |
| 3742 |
|
if( sqlcode == SQL_SUCCESS || sqlcode == SQL_SUCCESS_WITH_INFO ){ |
| 3743 |
|
SQLINTEGER cb1 = SQL_NTS, cb2 = SQL_NTS, cb3 = SQL_NTS, cb4 = SQL_NTS; |
| 3744 |
|
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, XNP_ITEM_SUBTYPE_LEN, 0, (SQLCHAR *)newIndex->getSubtype(), 0, &cb1 ); |
| 3745 |
|
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, XNP_ITEM_TITLE_LEN, 0, (SQLCHAR *)newIndex->getTitle(), 0, &cb2 ); |
| 3746 |
|
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, XNP_ITEM_KEYWORDS_LEN, 0, (SQLCHAR *)newIndex->getKeywords(), 0, &cb3 ); |
| 3747 |
|
SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, XNP_ITEM_DESCRIPTION_LEN, 0, (SQLCHAR *)newIndex->getDescription(), 0, &cb4 ); |
| 3748 |
|
if( ( sqlcode = SQLExecute( hstmt ) ) == SQL_SUCCESS ){ |
| 3749 |
|
result = RES_OK; |
| 3750 |
|
} |
| 3751 |
|
else { |
| 3752 |
|
string s( "SQLExecDirect in updateIndex "); |
| 3753 |
|
s += odbcDiagString( SQL_HANDLE_STMT, hstmt, sqlcode ); |
| 3754 |
|
s += string( ", sql=" ) + string( sql ); |
| 3755 |
|
setLastErrorString( s.c_str( ) ); |
| 3756 |
|
result = RES_ERROR; |
| 3757 |
|
} |
| 3758 |
|
} |
| 3759 |
|
else { |
| 3760 |
|
setLastErrorString( "SQLPrepare in updateIndex " ); |
| 3761 |
|
result = RES_ERROR; |
| 3762 |
|
} |
| 3763 |
|
} |
| 3764 |
|
else { |
| 3765 |
|
string s( "SQLExecDirect in updateIndex "); |
| 3766 |
|
s += odbcDiagString( SQL_HANDLE_STMT, hstmt, sqlcode ); |
| 3767 |
|
s += string( ", sql=" ) + string( sql ); |
| 3768 |
|
setLastErrorString( s.c_str( ) ); |
| 3769 |
|
result = RES_ERROR; |
| 3770 |
|
} |
| 3771 |
|
|
| 3772 |
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt ); |
| 3773 |
|
} |
| 3774 |
|
else { |
| 3775 |
|
string s( "SQLAllocHandle in updateIndex "); |
| 3776 |
|
s += odbcDiagString( SQL_HANDLE_STMT, hstmt, sqlcode ); |
| 3777 |
|
setLastErrorString( s.c_str( ) ); |
| 3778 |
|
result = RES_ERROR; |
| 3779 |
|
} |
| 3780 |
|
|
| 3781 |
|
if ( result == RES_OK ){ |
| 3782 |
|
if ( newParentIndex->getOwnerUID() != oldParentIndex->getOwnerUID() |
| 3783 |
|
|| newParentIndex->getOwnerGID() != oldParentIndex->getOwnerGID() |
| 3784 |
|
|| newParentIndex->getOpenLevel() != oldParentIndex->getOpenLevel() ){ |
| 3785 |
|
// 親の公開領域が変わる場合は、このインデックスとその子孫の公開領域も変わる。 |
| 3786 |
|
indexid_t *descXID = 0; |
| 3787 |
|
int descXIDLen; |
| 3788 |
|
result = getDescendantIndexID( oldIndex->getIndexID(), &descXID, &descXIDLen ); |
| 3789 |
|
if ( result != RES_OK ){ |
| 3790 |
|
setLastErrorString( "in updateIndexInternal: getDescendantIndexID failed" ); |
| 3791 |
|
return RES_ERROR; |
| 3792 |
|
} |
| 3793 |
|
int i; |
| 3794 |
|
for ( i = 0; i < descXIDLen; i++ ){ |
| 3795 |
|
string sql = "UPDATE " + dbprefix + "_xnpaccount_index set " |
| 3796 |
|
" uid=" + unsignedIntToString(newParentIndex->getOwnerUID()) + |
| 3797 |
|
", gid=" + unsignedIntToString(newParentIndex->getOwnerGID()) + |
| 3798 |
|
", open_level=" + unsignedIntToString(newParentIndex->getOpenLevel()) + |
| 3799 |
|
" WHERE index_id=" + unsignedIntToString(descXID[i]); |
| 3800 |
|
querySimple( "updateIndex", sql ); |
| 3801 |
|
} |
| 3802 |
|
freeIndexID( descXID ); |
| 3803 |
|
|
| 3804 |
|
// todo: インデックスが移動した場合は、アイテムの所有者に何らかの通知を行う。 |
| 3805 |
|
} |
| 3806 |
|
} |
| 3807 |
|
|
| 3808 |
|
return result; |
| 3809 |
|
|
| 3810 |
|
} |
| 3811 |
|
|
| 3812 |
|
/** |
| 3813 |
|
* |
| 3814 |
|
* インデックスキーワードを変更する |
| 3815 |
|
* |
| 3816 |
|
* @param sid セッションID |
| 3817 |
|
* @param index 変更するインデックスキーワード |
| 3818 |
|
* @return RES_OK 成功 |
| 3819 |
|
* |
| 3820 |
|
*/ |
| 3821 |
|
/* |
| 3822 |
|
親XIDを書き換えるときは、以下の点に注意。 |
| 3823 |
|
親インデックスへの書き込み権限が必要。 |
| 3824 |
|
|
| 3825 |
|
自分またはその子孫のXIDを親XIDとして設定することはできない |
| 3826 |
|
親の公開領域が変わる場合は、このインデックスとその子孫の公開領域も変わる。 |
| 3827 |
|
*/ |
| 3828 |
|
result_t updateIndex( sessionid_t sid, index_t *newIndex ) |
| 3829 |
|
{ |
| 3830 |
|
result_t result; |
| 3831 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3832 |
|
|
| 3833 |
|
userid_t uid; |
| 3834 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3835 |
|
if( result != RES_OK ) return result; |
| 3836 |
|
|
| 3837 |
|
const index_t *oldIndex; |
| 3838 |
|
result = getIndex( sid, newIndex->getIndexID(), &oldIndex ); |
| 3839 |
|
if ( result == RES_OK ){ |
| 3840 |
|
const index_t *newParentIndex; |
| 3841 |
|
result = getIndex( sid, newIndex->getParentIndexID(), &newParentIndex ); |
| 3842 |
|
if ( result == RES_OK ){ |
| 3843 |
|
const index_t *oldParentIndex; |
| 3844 |
|
result = getIndex( sid, oldIndex->getParentIndexID(), &oldParentIndex ); |
| 3845 |
|
if ( result == RES_OK ){ |
| 3846 |
|
// oldIndex, newParentIndex, oldParentIndexの開放忘れを防ぐ為の2重構造 |
| 3847 |
|
result = updateIndexInternal( sid, uid, newIndex, oldIndex, newParentIndex, oldParentIndex ); |
| 3848 |
|
freeIndex( oldParentIndex ); |
| 3849 |
|
} |
| 3850 |
|
else { |
| 3851 |
|
; |
| 3852 |
|
} |
| 3853 |
|
freeIndex( newParentIndex ); |
| 3854 |
|
} |
| 3855 |
|
else { |
| 3856 |
|
; |
| 3857 |
|
} |
| 3858 |
|
freeIndex( oldIndex ); |
| 3859 |
|
} |
| 3860 |
|
else { |
| 3861 |
|
; |
| 3862 |
|
} |
| 3863 |
|
|
| 3864 |
|
return result; |
| 3865 |
|
} |
| 3866 |
|
|
| 3867 |
|
/** |
| 3868 |
|
* |
| 3869 |
|
* インデックスキーワードを削除する |
| 3870 |
|
* |
| 3871 |
|
* @param sid セッションID |
| 3872 |
|
* @param xid 削除するインデックスキーワード |
| 3873 |
|
* @return RES_OK 成功 |
| 3874 |
|
* |
| 3875 |
|
*/ |
| 3876 |
|
result_t deleteIndex( sessionid_t sid, indexid_t xid ) |
| 3877 |
|
{ |
| 3878 |
|
char *functionName = "deleteIndex"; |
| 3879 |
|
result_t result; |
| 3880 |
|
userid_t uid; |
| 3881 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3882 |
|
|
| 3883 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3884 |
|
if( result != RES_OK ) return result; |
| 3885 |
|
|
| 3886 |
|
const index_t *index; |
| 3887 |
|
result = getIndex( sid, xid, &index ); |
| 3888 |
|
if ( result != RES_OK ) |
| 3889 |
|
return result; |
| 3890 |
|
|
| 3891 |
|
if ( index->getIndexID() == item::IID_ROOT || index->getParentIndexID() == item::IID_ROOT ){ |
| 3892 |
|
result = RES_ERROR; |
| 3893 |
|
setLastErrorString( "in deleteIndex: cannot delete system-created-index." ); |
| 3894 |
|
} |
| 3895 |
|
else { |
| 3896 |
|
if ( !isWritableInternal( sid, uid, index ) ){ |
| 3897 |
|
result = RES_NO_WRITE_ACCESS_RIGHT; |
| 3898 |
|
setLastErrorString( "in deleteIndex: no write access right." ); |
| 3899 |
|
} |
| 3900 |
|
else { |
| 3901 |
|
// 削除対象を列挙 |
| 3902 |
|
indexid_t *descXID = 0; |
| 3903 |
|
int descXIDLen; |
| 3904 |
|
result = getDescendantIndexID( xid, &descXID, &descXIDLen ); |
| 3905 |
|
if ( result != RES_OK ){ |
| 3906 |
|
setLastErrorString( "in deleteIndex: getDescendantIndexID failed" ); |
| 3907 |
|
return RES_ERROR; |
| 3908 |
|
} |
| 3909 |
|
|
| 3910 |
|
SQLRETURN sqlcode; |
| 3911 |
|
SQLHANDLE hstmt = NULL; |
| 3912 |
|
if( ( sqlcode = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ) == SQL_SUCCESS ) { |
| 3913 |
|
result = RES_OK; |
| 3914 |
|
string strParentXID = unsignedIntToString( index->getParentIndexID() ); |
| 3915 |
|
for ( int i = descXIDLen-1; i >= 0; i-- ){ // 逆方向にして、途中で失敗した場合の惨事を防ぐ。descXIDは幅優先探索順に並んでいるので。 |
| 3916 |
|
string strXID = unsignedIntToString(descXID[i]); |
| 3917 |
|
string linkTable = dbprefix + "_index_item_link"; |
| 3918 |
|
|
| 3919 |
|
// descXID[i] のアイテムの中で、被参照数が1のものを列挙 → 迷子にならないように移動 |
| 3920 |
|
// HAVINGを使うべき? "select item_id, count(*) as v1, sum(index_id=$index_id) as v2 from $link_table having v1=1 and v2=1" |
| 3921 |
|
// しかしsum内に<predicate>を書いてもいいのだろうか? 代わりにnullifとcoalesceならsqliteは通るが・・・ |
| 3922 |
|
// → 互換性の高い方法がよくわからないので、とりあえず自己joinにする。 |
| 3923 |
|
string sql( "SELECT t1.index_item_link_id " |
| 3924 |
|
" FROM " + linkTable + " AS t1 " |
| 3925 |
|
" LEFT JOIN " + linkTable + " AS t2 ON t1.item_id = t2.item_id and t2.index_id <> t1.index_id " |
| 3926 |
|
" WHERE t1.index_id=" + strXID + " and t2.item_id is NULL" ); |
| 3927 |
|
if( ( sqlcode = SQLExecDirect( hstmt, (SQLCHAR*)sql.c_str(), sql.length() ) ) == SQL_SUCCESS ){ |
| 3928 |
|
SQLUINTEGER sLinkID = 0; |
| 3929 |
|
SQLINTEGER len; |
| 3930 |
|
SQLBindCol( hstmt, 1, SQL_C_ULONG, &sLinkID, 0, &len ); |
| 3931 |
|
while ( ( sqlcode = SQLFetch( hstmt ) ) == SQL_SUCCESS ){ |
| 3932 |
|
string sql2( "UPDATE " + linkTable + " set index_id= " + strParentXID + " where index_item_link_id = " + unsignedIntToString(sLinkID) ); |
| 3933 |
|
result = querySimple( "deleteIndex", sql2 ); |
| 3934 |
|
if( result != RES_OK ) |
| 3935 |
|
break; |
| 3936 |
|
} |
| 3937 |
|
if ( result != RES_OK ) |
| 3938 |
|
break; |
| 3939 |
|
}else{ |
| 3940 |
|
setLastErrorString( "SQLExecDirect in getDescendantIndexID" ); |
| 3941 |
|
result = RES_ERROR; |
| 3942 |
|
break; |
| 3943 |
|
} |
| 3944 |
|
|
| 3945 |
|
// descXID[i] のアイテムを全て削除 |
| 3946 |
|
sql = "DELETE from " + linkTable + " where index_id=" + strXID; |
| 3947 |
|
result = querySimple( functionName, sql ); |
| 3948 |
|
if ( result == RES_OK ){ |
| 3949 |
|
// descXID[i] を削除 |
| 3950 |
|
sql = "DELETE from " + dbprefix + "_item_basic where item_id =" + strXID; |
| 3951 |
|
result = querySimple( functionName, sql ); |
| 3952 |
|
if ( result == RES_OK ){ |
| 3953 |
|
sql = "DELETE from " + dbprefix + "_index where index_id=" + strXID; |
| 3954 |
|
result = querySimple( functionName, sql ); |
| 3955 |
|
} |
| 3956 |
|
} |
| 3957 |
|
} |
| 3958 |
|
}else{ |
| 3959 |
|
setLastErrorString( "SQLAllocHandle in deleteIndex" ); |
| 3960 |
|
result = RES_ERROR; |
| 3961 |
|
} |
| 3962 |
|
|
| 3963 |
|
freeIndexID( descXID ); |
| 3964 |
|
} |
| 3965 |
|
} |
| 3966 |
|
return result; |
| 3967 |
|
} |
| 3968 |
|
|
| 3969 |
|
|
| 3970 |
|
|
| 3971 |
|
|
| 3972 |
|
|
| 3973 |
|
/** |
| 3974 |
|
* |
| 3975 |
|
* インデックスキーワードの順番を入れ替える |
| 3976 |
|
* |
| 3977 |
|
* @param sid セッションID |
| 3978 |
|
* @param xid1 入れ替えたいインデックスキーワードのXID |
| 3979 |
|
* @param xid2 入れ替えたいインデックスキーワードのXID |
| 3980 |
|
* @return RES_OK 成功 |
| 3981 |
|
* |
| 3982 |
|
*/ |
| 3983 |
|
result_t swapIndexSortNumber( sessionid_t sid, itemid_t xid1, itemid_t xid2 ) |
| 3984 |
|
{ |
| 3985 |
|
char *functionName = "swapIndexSortNumber"; |
| 3986 |
|
result_t result; |
| 3987 |
|
userid_t uid; |
| 3988 |
|
if( hdbc == NULL ) return RES_DB_NOT_INITIALIZED; |
| 3989 |
|
|
| 3990 |
|
result = sessionID2UID( sid, &uid ); // sid から uid を得る |
| 3991 |
|
if( result == RES_OK ){ |
| 3992 |
|
/* |
| 3993 |
|
xid1, xid2 の親が異なるなら、エラー。 |
| 3994 |
|
xid1, xid2 の両方に書き込み権限があることを確認。 |
| 3995 |
|
操作順序は、 |
| 3996 |
|
tmp1 = x1.sort_number; |
| 3997 |
|
tmp2 = x2.sort_number; |
| 3998 |
|
x1.sort_number = 0; // (parent_index_id,sort_number)はuniqueなので、一旦1に変更する。 |
| 3999 |
|
x2.sort_number = tmp1; |
| 4000 |
|
x1.sort_number = tmp2; |
| 4001 |
|
*/ |
| 4002 |
|
const index_t *index1, *index2; |
| 4003 |
|
result = getIndex( sid, xid1, &index1 ); |
| 4004 |
|
if ( result == RES_OK ){ |
| 4005 |
|
result = getIndex( sid, xid2, &index2 ); |
| 4006 |
|
if ( result == RES_OK ){ |
| 4007 |
|
if ( index1->getParentIndexID() == index2->getParentIndexID() ){ |
| 4008 |
|
if ( isWritableInternal( sid, uid, index1 ) && isWritableInternal( sid, uid, index2 ) ){ |
| 4009 |
|
string xid1String = unsignedIntToString(xid1); |
| 4010 |
|
string xid2String = unsignedIntToString(xid2); |
| 4011 |
|
string indexTable = dbprefix + "_xnpaccount_index"; |
| 4012 |
|
string sql1 = "UPDATE " + indexTable + " set sort_number=0 WHERE index_id=" + xid1String; |
| 4013 |
|
string sql2 = "UPDATE " + indexTable + " set sort_number=" + unsignedIntToString(index1->getSortNumber()) + " WHERE index_id=" + xid2String; |
| 4014 |
|
string sql3 = "UPDATE " + indexTable + " set sort_number=" + unsignedIntToString(index2->getSortNumber()) + " WHERE index_id=" + xid1String; |
| 4015 |
|
|
| 4016 |
|
if( (result=querySimple(functionName,sql1)) == RES_OK ){ |
| 4017 |
|
if( (result=querySimple(functionName,sql2)) == RES_OK ){ |
| 4018 |
|
if( (result=querySimple(functionName,sql3)) == RES_OK ){ |
| 4019 |
|
; |
| 4020 |
|
} |
| 4021 |
|
} |
| 4022 |
|
} |
| 4023 |
|
} |
| 4024 |
|
else { |
| 4025 |
|
setLastErrorString( "swapIndexSortNumber: not writable" ); |
| 4026 |
|
result = RES_ERROR; |
| 4027 |
|
} |
| 4028 |
|
} |
| 4029 |
|
else { |
| 4030 |
|
setLastErrorString( "swapIndexSortNumber: not brother" ); |
| 4031 |
|
result = RES_ERROR; |
| 4032 |
|
} |
| 4033 |
|
freeIndex( index2 ); |
| 4034 |
|
} |
| 4035 |
|
else { |
| 4036 |
|
} |
| 4037 |
|
freeIndex( index1 ); |
| 4038 |
|
} |
| 4039 |
|
else { |
| 4040 |
|
} |
| 4041 |
|
} |
| 4042 |
|
return result; |
| 4043 |
|
} |
| 4044 |
|
|
| 4045 |
|
|
| 4046 |
|
|
| 4047 |
|
void freeIndex( const index_t* ptr ){ delete[] ptr; } |
| 4048 |
|
void freeIndexID( const indexid_t* ptr ){ delete[] ptr; } |
| 4049 |
|
|
| 4050 |
|
|
| 4051 |
void freeAccount( const account_t* ptr ){ delete[] ( account_t* )ptr; } |
void freeAccount( const account_t* ptr ){ delete[] ( account_t* )ptr; } |
| 4052 |
void freeGroup( const group_t* ptr ){ delete[] ( group_t* )ptr; } |
void freeGroup( const group_t* ptr ){ delete[] ( group_t* )ptr; } |
| 4053 |
void freeSession( const session_t* ptr ){ delete[] ( session_t* )ptr; } |
void freeSession( const session_t* ptr ){ delete[] ( session_t* )ptr; } |