// Executes the select command and returns a reference to an IFeatureReader.
// During execution an attempt is made to place a lock on each feature. If
// there are conflicts the conflicts are reported and made available to the
// user via a lock conflict reader. The user retrieves the lock conflict
// reader when executing the function "GetLockConflicts()".
// NOTE: The current implementation is a work-around due some timing issues as
//       explained: When using DBI to apply a lock on an object the lock is
//       actually applied only when the object is fetched via the procedure
//       dbi_fetch. In this command the fetching of the object is delayed until
//       the user actually queries the feature reader. That means that locks
//       are applied at that time. As a result the feature reader should have a
//       method to retrieve the lock conflicts because this object documents
//       them. This is not the case. Therefore, until a better solution is found
//       the work-around is to have two passes for the execution of the command:
//       the first one actually locks the objects and provides lock conflict
//       information whereas the second pass prepares the feature reader for the
//       user to retrieve the requested data.
FdoIFeatureReader* FdoRdbmsSelectCommand::ExecuteWithLock()
{

    FdoFilter       *tempFilter     = NULL;
    FdoIdentifier   *tempClassName  = NULL;
    FdoIAcquireLock *acquireLockCmd = NULL;

    // If a lock conflict reader already exists dispose it.

    FDO_SAFE_RELEASE(mLockConflictReader);

    // Create the command to lock the objects, set the command parameters
    // and execute it.

    acquireLockCmd = (FdoIAcquireLock *) mConn->CreateCommand(
                                                    FdoCommandType_AcquireLock);

    tempClassName = GetFeatureClassName();
    acquireLockCmd->SetFeatureClassName(tempClassName);
    tempClassName->Release();
    tempFilter = GetFilter();
    acquireLockCmd->SetFilter(tempFilter);
    acquireLockCmd->SetLockStrategy(mLockStrategy);
    acquireLockCmd->SetLockType(mLockType);

    mLockConflictReader = (FdoRdbmsLockConflictReader *)acquireLockCmd->Execute();

    acquireLockCmd->Release();
    acquireLockCmd = NULL;

    // Get the data as requested by the user.

    return (Execute());
}
/// <summary>Executes the select command and returns a reference to an FdoIDataReader.</summary>
/// <returns>Returns the feature reader.</returns> 
FdoIDataReader* FdoCommonSelectAggregatesCommand::Execute ()
{
    FdoString* class_name;

    class_name = FdoPtr<FdoIdentifier> (GetFeatureClassName ())->GetName ();
    FdoPtr<FdoIConnection> conn = (FdoIConnection*)GetConnection ();


    //we will need a vanilla select command to get the features
    //the user would like to work with (given class and FdoFilter)
    FdoPtr <FdoISelect> selectCmd = (FdoISelect*)conn->CreateCommand(FdoCommandType_Select);
    selectCmd->SetFeatureClassName(class_name);
    selectCmd->SetFilter(mFilter);

    // Get other relevant info:
    FdoPtr<FdoIdentifierCollection> selectedIds = GetPropertyNames();
    FdoPtr<FdoClassDefinition> originalClassDef = FdoCommonSchemaUtil::GetLogicalClassDefinition(conn, class_name, NULL);

    // Create and return the data reader:
    FdoPtr<FdoIDataReader> dataReader = new FdoCommonDataReader(conn, selectCmd, originalClassDef, selectedIds, m_bDistinct, m_OrderingIds, m_eOrderingOption);
    return FDO_SAFE_ADDREF(dataReader.p);
}
FdoRdbmsLockConflictReader *FdoRdbmsAcquireLock::ExecuteLockRequest ()

// +---------------------------------------------------------------------------
// | The function executes the requested lock operation.
// +---------------------------------------------------------------------------

{
	FdoRdbmsLockConflictReader *conflictReader = NULL;
	// get class name, filter
	// get table name sql filter
	// start transaction
	// get lock conflicts
	// acquire lock


    // Declare and initialize all necessary local variables.

    bool               filter_modified         = FALSE,
                       transaction_started     = FALSE,
                       class_name_modified     = FALSE;

    FdoFilter          *fdo_filter             = NULL;

    FdoIdentifier      *class_name             = NULL,
                       *temp_class_name        = NULL,
                       *modified_class_name    = NULL;

    FdoITransaction    *fdo_i_transaction      = NULL;
	char			   *tableName;
	char			   *sqlFilter;
	int					execution_status;

    try {

      // Get the current class name. The class name can come in any of the
      // following structures:
      //
      //   just a class name (like "testClass")
      //   <class_name>.<property>[.<property>]
      //   <schema>:<class_name> (like "LockTests:testClass")
      //
      // At the end of the process a usable class name is available.

      class_name = GetFeatureClassName();
      req_class_name = LockUtility::GetClassName(class_name,
                                                      &class_name_modified);
      // The request is executed only, if the connection and the class support
      // locking. If this is not the case issue an error.

      if (!LockUtility::IsLockSupported(fdo_rdbms_connection,
                                        req_class_name))
          throw FdoCommandException::Create(
                        LockUtility::GetExceptionMessage(
                                      LockUtility::LOCK_SUPPORT_ERROR,
                                      req_class_name->GetName(),
                                      L"FdoIAcquireLock"));

	  

      if ((class_name_modified) && (this->GetFilterRef() != NULL)) {

          temp_class_name =
              FdoRdbmsFilterUtil::ConvertFilterToMainClass(class_name,
                                                         this->GetFilterRef());
          temp_class_name->Release();
          filter_modified = TRUE;

      }  //  if (class_name_modified) ...

      execution_status =
                LockUtility::ProcessLockRequest(fdo_rdbms_connection,
                                                FdoPtr<FdoRdbmsFilterProcessor>(FdoPtr<FdoRdbmsConnection>((FdoRdbmsConnection*)GetConnection())->GetFilterProcessor()),
                                                class_name,
                                                req_class_name,
												class_name_modified,
                                                GetFilter(),
												&tableName,
												&sqlFilter);
	  if (!execution_status)
		throw FdoCommandException::Create(
                        LockUtility::GetExceptionMessage(
                                      LockUtility::LOCK_REQUEST_PROCESSING_ERROR));

	  // Start a transaction to cover the following modifications. They may
      // have to be rolled back depending on the execution status of the pro-
      // cedure applying the lock. Don't start a transaction if there is one
      // already active.
	  FdoLockType lockType = GetLockType();

	  if (!fdo_rdbms_connection->GetIsTransactionStarted()) {

		  if (lockType == FdoLockType_Transaction)
			  throw FdoCommandException::Create(
                        LockUtility::GetExceptionMessage(
                                      LockUtility::LOCK_ACTIVE_TRANSACTION_ERROR));

          if ((fdo_i_transaction =
                        fdo_rdbms_connection->BeginTransaction()) == NULL) {

               if ((class_name_modified         ) &&
                   (filter_modified             ) &&
                   (this->GetFilterRef() != NULL)    )
                    FdoRdbmsFilterUtil::ConvertFilterToObjectClass(
                                                        class_name,
                                                        this->GetFilterRef());
               if ((class_name_modified) && (req_class_name != NULL))
                    req_class_name->Release();
               req_class_name = NULL;
               class_name->Release();
               class_name = NULL;
               if (fdo_filter != NULL) {

                   fdo_filter->Release();
                   fdo_filter = NULL;

               }  //  if (fdo_filter != NULL) ...

               return conflictReader;

          }  //  if ((fdo_i_transaction = ...

          transaction_started = TRUE;

      }  //  if (!fdo_rdbms_connection->GetIsTransactionStarted()) ...

	  execution_status = 
		      FdoPtr<FdoRdbmsLockManager>(fdo_rdbms_connection->GetLockManager())->AcquireLock(LockUtility::ConvertString(tableName), 
			                                                      LockUtility::ConvertString(sqlFilter), 
																  (FdoString *)NULL, FdoLockType_Transaction);

	  FdoRdbmsLockConflictQueryHandler *lockConflictQuery = 
				FdoPtr<FdoRdbmsLockManager>(fdo_rdbms_connection->GetLockManager())->LockConflictQuery(LockUtility::ConvertString(tableName),
																		  LockUtility::ConvertString(sqlFilter));

	  if (lockType != FdoLockType_Transaction)
	  {
		execution_status = 
			FdoPtr<FdoRdbmsLockManager>(fdo_rdbms_connection->GetLockManager())->AcquireLock(LockUtility::ConvertString(tableName), 
									   LockUtility::ConvertString(sqlFilter), 
									   lockConflictQuery->GetConflictDbObject(), lockType);

		// If a transaction was started, it has to be handled: it is rolled back
		// if the execution of the lock request fails, committed otherwise.
		if (!execution_status)
		{
			if (transaction_started)
			{
				fdo_i_transaction->Rollback();
				fdo_i_transaction->Release();
			}
		}
		else
		{	
			if (transaction_started)
			{	
				fdo_i_transaction->Commit();
				fdo_i_transaction->Release();
			}
		}
	  }

	  // Finally, create a lock conflict reader.
	  if (execution_status)
		conflictReader = new FdoRdbmsLockConflictReader(fdo_rdbms_connection, 
		                                                lockConflictQuery, req_class_name);
		
      // If the filter was modified, set it back.

      if ((class_name_modified         ) &&
          (filter_modified             ) &&
          (this->GetFilterRef() != NULL)    )
           FdoRdbmsFilterUtil::ConvertFilterToObjectClass(class_name,
                                                      this->GetFilterRef());

      // Do some cleaning up and return the execution status back to the calling
      // routine.

      if ((class_name_modified) && (modified_class_name != NULL))
           modified_class_name->Release();
      modified_class_name = NULL;
      class_name->Release();
      class_name = NULL;
      if (fdo_filter != NULL) {fdo_filter->Release(); fdo_filter = NULL;}

      return conflictReader;

    }  //  try ...

    catch ( ... ) {

      if (fdo_i_transaction != NULL) {

          fdo_i_transaction->Rollback();
          fdo_i_transaction->Release();

      }  //  if (fdo_i_transaction != NULL)

      if ((class_name_modified         ) &&
          (filter_modified             ) &&
          (this->GetFilterRef() != NULL)    )
           FdoRdbmsFilterUtil::ConvertFilterToObjectClass(class_name,
                                                      this->GetFilterRef());

      if ((class_name_modified) && (modified_class_name != NULL))
           modified_class_name->Release();
      modified_class_name = NULL;

      if (class_name != NULL) { class_name->Release(); class_name = NULL; }
      if (fdo_filter != NULL) { fdo_filter->Release(); fdo_filter = NULL; }

      throw;

    } //  catch ( ... ) ...
}  //  ExecuteLockRequest ()