///<summary>Executes the GetLockedObjects command, returning an FdoILockedObjectReader.</summary> /// <returns>Returns FdoILockedObjectReade.r</returns> FdoILockedObjectReader* ArcSDEGetLockedObjectsCommand::Execute () { FdoPtr<ArcSDEConnection> connection; CHAR user_name[SE_MAX_OWNER_LEN]; FdoStringP user_str; CHAR* user; LONG result; SE_REGINFO *registrations; LONG count; CHAR table_name[SE_QUALIFIED_TABLE_NAME]; LONG number; LONG *ids; FdoPtr<ArcSDELockedObjectReader> ret; // verify the connection connection = static_cast<ArcSDEConnection*>(GetConnection ()); if (connection == NULL) throw FdoException::Create (NlsMsgGet (ARCSDE_CONNECTION_NOT_ESTABLISHED, "Connection not established.")); // establish an empty locked object reader ret = new ArcSDELockedObjectReader (connection); // get the user name if (NULL == GetLockOwner () || (0 == wcscmp (L"", GetLockOwner ()))) { result = SE_connection_get_user_name (connection->GetConnection (), user_name); handle_sde_err<FdoCommandException> (connection->GetConnection (), result, __FILE__, __LINE__, ARCSDE_USER_UNKNOWN, "Cannot determine current user."); user = user_name; } else { user_str = mLockOwner.Upper(); #ifdef SDE_UNICODE user = (CHAR*)sde_cstwc(user_str); #else sde_wide_to_multibyte (user, (FdoString*)user_str); #endif } // process the list of registered arcsde tables, checking for locks by user (or not) // Read all registered arcsde tables, adding user locks on the rows to the FdoILockedObjectReader connection->GetArcSDERegistrationList(®istrations, &count); for (int i = 0; i < count; i++) { if (SE_reginfo_allow_rowlocks (registrations[i])) { result = SE_reginfo_get_table_name (registrations[i], table_name); handle_sde_err<FdoCommandException> (connection->GetConnection(), result, __FILE__, __LINE__, ARCSDE_REGISTRATION_INFO_ITEM, "Table registration info item '%1$ls' could not be retrieved.", L"table_name"); result = SE_table_get_rowlocks_by_user (connection->GetConnection(), table_name, user, &number, &ids); handle_sde_err<FdoCommandException>(connection->GetConnection(), result, __FILE__, __LINE__, ARCSDE_GET_ROW_LOCK_LIST_FAILED, "Failed to get the row lock list."); for (int j = 0; j < number; j++) ret->AddIdentity (table_name, ids[j]); SE_table_free_rowlocks_list (number, ids, NULL); } } return (FDO_SAFE_ADDREF (ret.p)); }
/// <summary>Executes the release lock command, returning an FdoILockConflictReader.</summary> /// <returns>Returns an FdoILockConflictReader</returns> FdoILockConflictReader* ArcSDEReleaseLockCommand::Execute () { const CHAR* columns[1]; FdoPtr<ArcSDEConnection> connection; CHAR table[SE_QUALIFIED_TABLE_NAME]; CHAR column[SE_MAX_COLUMN_LEN]; wchar_t* wcolumn; CHAR *where; SHORT count; SE_FILTER* filters; FdoString* property; LONG result; SE_STREAM stream; CHAR user_name[SE_MAX_OWNER_LEN]; wchar_t* me; CHAR logfile[SE_MAX_PATH_LEN]; SE_SQL_CONSTRUCT sql_construct; CHAR* tables[1]; FdoPtr<FdoISQLDataReader> reader; SE_LOG log; LONG number = 0; Lock* locks = NULL; wchar_t* locktable = NULL; FdoPtr<ArcSDELockConflictReader> ret; // verify the connection connection = static_cast<ArcSDEConnection*>(GetConnection ()); if (connection == NULL) throw FdoException::Create (NlsMsgGet (ARCSDE_CONNECTION_NOT_ESTABLISHED, "Connection not established.")); // verify the feature class name is specified if (mClassName == NULL) throw FdoException::Create (NlsMsgGet (ARCSDE_FEATURE_CLASS_UNSPECIFIED, "Feature class name not specified.")); // get the class definition which reflects the requested feature class name FdoPtr<FdoClassDefinition> definition = connection->GetRequestedClassDefinition (mClassName); // get the filter if any FdoPtr<FdoFilter> filter = GetFilter (); // get SQL query's "from" table list mConnection->ClassToTable (table, definition); // ensure lockable table if (!ArcSDELockUtility::IsLockable (connection->GetConnection (), table, column)) { wchar_t* wtable; sde_multibyte_to_wide (wtable, table); throw FdoException::Create (NlsMsgGet1 (ARCSDE_LOCKING_NOT_ENABLED, "Table '%1$ls' is not lock enabled.", wtable)); } // get the property name that is the row_id sde_multibyte_to_wide (wcolumn, column); property = connection->ColumnToProperty (definition, wcolumn); // get SQL query's "where" clause & spatial filters where = NULL; count = 0; filters = NULL; GetFilterInfo (connection, filter, definition, where, count, filters); // establish an empty conflict reader ret = new ArcSDELockConflictReader (connection, definition->GetQualifiedName (), table, property); // initialize the stream query result = SE_stream_create (connection->GetConnection (), &stream); handle_sde_err<FdoCommandException> (connection->GetConnection (), result, __FILE__, __LINE__, ARCSDE_STREAM_ALLOC, "Cannot initialize SE_STREAM structure."); // if necessary, version enable the stream ArcSDELongTransactionUtility::VersionStream (connection, stream, table, false); // release lock, don't return rows result = SE_connection_get_user_name (connection->GetConnection (), user_name); handle_sde_err<FdoCommandException> (connection->GetConnection (), result, __FILE__, __LINE__, ARCSDE_USER_UNKNOWN, "Cannot determine current user."); sde_multibyte_to_wide (me, user_name); if (0 == wcscmp (GetLockOwner (), L"")) { result = SE_stream_set_rowlocking (stream, SE_ROWLOCKING_UNLOCK_ON_QUERY | SE_ROWLOCKING_LOCK_ONLY); handle_sde_err<FdoCommandException> (connection->GetConnection (), result, __FILE__, __LINE__, ARCSDE_STREAM_LOCK, "Cannot set row locking on the stream."); } else if (0 == wcscmp (GetLockOwner (), me)) { result = SE_stream_set_rowlocking (stream, SE_ROWLOCKING_UNLOCK_ON_QUERY | SE_ROWLOCKING_FILTER_MY_LOCKS | SE_ROWLOCKING_LOCK_ONLY); handle_sde_err<FdoCommandException> (connection->GetConnection (), result, __FILE__, __LINE__, ARCSDE_STREAM_LOCK, "Cannot set row locking on the stream."); } else { LONG *ids = NULL; CHAR **users = NULL; CHAR lt[SE_QUALIFIED_TABLE_NAME]; if (0) throw FdoCommandException::Create (NlsMsgGet (ARCSDE_RELEASE_UNOWNED_LOCKS, "Releasing other owners locks is not supported.")); result = SE_table_get_rowlocks (connection->GetConnection(), table, &number, &ids, &users); handle_sde_err<FdoCommandException>(connection->GetConnection(), result, __FILE__, __LINE__, ARCSDE_GET_ROW_LOCK_LIST_FAILED, "Failed to get the row lock list."); if (0 != number) { // put the id's and users in an array of lock structures locks = (Lock*)calloc (number, sizeof (Lock)); for (int i = 0; i < number; i++) { locks[i].id = ids[i]; sde_strcpy (sde_pus2wc(locks[i].user), sde_pcus2wc(users[i])); } qsort (locks, number, sizeof (LONG), compare); ArcSDELockUtility::LockTableName (lt, connection, table); sde_multibyte_to_wide (locktable, lt); SE_table_free_rowlocks_list (number, ids, users); } } // apply attribute and spatial query to stream columns[0] = column; ApplyFilterInfoToStream (connection, stream, table, where, 1, columns, count, filters); // set up a temporary log file mConnection->MakeLog (&log, table); // accumulate the query in the log file result = SE_stream_set_logfile (stream, log, FALSE); handle_sde_err<FdoCommandException> (stream, result, __FILE__, __LINE__, ARCSDE_LOG_SET_LOGFILE, "Could not set log file."); // lock the table's lock table to prevent alteration reader = ArcSDELockUtility::LockLockTable (mConnection, table); // actually execute the query result = SE_stream_execute (stream); handle_sde_err<FdoCommandException>(stream, result, __FILE__, __LINE__, ARCSDE_STREAM_EXECUTE, "Stream execute failed."); result = SE_stream_fetch (stream); // three possibilities: locks for the specified user exist (SE_SUCCESS) and the log file isn't filled, // everything was unlocked (SE_FINISHED) // or there was a conflict (SE_LOCK_CONFLICT) switch (result) { case SE_SUCCESS: if (0 != number) { CHAR* user; LONG id; wchar_t drop[1024]; FdoPtr<FdoISQLCommand> sql; Lock key; Lock* item; // Get lock owner name: const wchar_t *wLockOwner = GetLockOwner(); wchar_t *wLockOwnerUpr = (wchar_t*)alloca( (1+wcslen(wLockOwner)) * sizeof(wchar_t)); wcscpy(wLockOwnerUpr, wLockOwner); FdoCommonOSUtil::wcsupr(wLockOwnerUpr); // ToDo: Oracle-specific sde_wide_to_multibyte (user, wLockOwnerUpr); // process each row returned (ignoring the log file) sql = (FdoISQLCommand*)connection->CreateCommand (FdoCommandType_SQLCommand); do { if (SE_SUCCESS != (result = SE_stream_get_integer (stream, 1, &id))) { sde_multibyte_to_wide (wcolumn, column); handle_sde_err<FdoCommandException> (stream, result, __FILE__, __LINE__, ARCSDE_STREAM_GET, "Stream get ('%1$ls') failed for column '%2$ls'.", L"SE_stream_get_integer", wcolumn); } else { key.id = id; // look it up to see if it's a conflict (i.e. not found) if (NULL != (item = (Lock*)bsearch (&key, locks, number, sizeof (LONG), compare))) { if (0 == sde_strcmp (sde_pcus2wc(user), sde_pcus2wc(item->user))) { // ToDo: optimize this singleton delete somewhat //ROW_ID NOT NULL NUMBER(38) //USER_NAME NOT NULL VARCHAR2(32) FdoCommonOSUtil::swprintf (drop, ELEMENTS (drop), L"delete from %ls where user_name=upper('%ls') and row_id = %ld", locktable, GetLockOwner (), id); sql->SetSQLStatement (drop); sql->ExecuteNonQuery (); } else ret->AddIdentity (id); } else { // no lock, hence no conflict } } } while (SE_SUCCESS == (result = SE_stream_fetch (stream))); if (SE_FINISHED != result) handle_sde_err<FdoCommandException> (stream, result, __FILE__, __LINE__, ARCSDE_STREAM_FETCH, "Stream fetch failed."); } break; case SE_FINISHED: break; case SE_LOCK_CONFLICT: // reuse the same stream result = SE_stream_close (stream, TRUE); // if necessary, version enable the stream ArcSDELongTransactionUtility::VersionStream (connection, stream, table, false); // select locks still remaining result = SE_stream_set_rowlocking (stream, SE_ROWLOCKING_FILTER_OTHER_LOCKS); handle_sde_err<FdoCommandException> (connection->GetConnection (), result, __FILE__, __LINE__, ARCSDE_STREAM_LOCK, "Cannot set row locking on the stream."); // get the list of row ids from the log file tables[0] = table; sql_construct.tables = tables; sql_construct.num_tables = ELEMENTS (tables); sql_construct.where = NULL; ArcSDELockUtility::GetLogFile (logfile, connection->GetConnection (), log); result = SE_stream_query_logfile (stream, logfile, 1, columns, &sql_construct); handle_sde_err<FdoCommandException>(stream, result, __FILE__, __LINE__, ARCSDE_LOG_FILE_QUERY, "Unable to query log file."); // execute the query that fetches conflicts result = SE_stream_execute (stream); handle_sde_err<FdoCommandException>(stream, result, __FILE__, __LINE__, ARCSDE_STREAM_EXECUTE, "Stream execute failed."); // gather the conflicts ArcSDELockUtility::GatherConflicts (stream, column, 1, ret); // if there were conflicts (and there will be), do a partial unlock if (0 != ret->mIds->GetCount ()) { // reuse the same stream result = SE_stream_close (stream, TRUE); // if necessary, version enable the stream ArcSDELongTransactionUtility::VersionStream (connection, stream, table, false); // select locks still remaining result = SE_stream_set_rowlocking (stream, SE_ROWLOCKING_FILTER_MY_LOCKS | SE_ROWLOCKING_UNLOCK_ON_QUERY | SE_ROWLOCKING_LOCK_ONLY); handle_sde_err<FdoCommandException> (connection->GetConnection (), result, __FILE__, __LINE__, ARCSDE_STREAM_LOCK, "Cannot set row locking on the stream."); // get the list of row ids from the log file result = SE_stream_query_logfile (stream, logfile, 1, columns, &sql_construct); handle_sde_err<FdoCommandException>(stream, result, __FILE__, __LINE__, ARCSDE_LOG_FILE_QUERY, "Unable to query log file."); // execute the query that unlocks rows result = SE_stream_execute (stream); handle_sde_err<FdoCommandException>(stream, result, __FILE__, __LINE__, ARCSDE_STREAM_EXECUTE, "Stream execute failed."); } else throw FdoException::Create (NlsMsgGet(ARCSDE_UNEXPECTED_ERROR, "Unexpected error encountered in ArcSDE Provider.")); break; default: handle_sde_err<FdoCommandException> (stream, result, __FILE__, __LINE__, ARCSDE_STREAM_FETCH, "Stream fetch failed."); } // release the transaction lock if (reader != NULL) reader->Close (); // clean up if (NULL != locks) free(locks); result = SE_stream_free (stream); handle_sde_err<FdoCommandException>(connection->GetConnection (), result, __FILE__, __LINE__, ARCSDE_STREAM_FREE, "Stream free failed."); delete[] where; if (NULL != filters) { for (int i = 0; i < count; i++) if (NULL != filters[i].filter.shape) SE_shape_free (filters[i].filter.shape); delete[] filters; } return (FDO_SAFE_ADDREF (ret.p)); }