7. Februar 2013

Workspace Manager Teil II: Langlaufende Transaktionen in der Datenbank

Workspace Manager Part II: Long-Running transactions in the Database
Heute setze ich das Blog-Posting zum Thema "Oracle Workspace Manager" mit Teil 2 fort. Nachdem im ersten Teil die grundliegenden Fähigkeiten vorgestellt worden, wird dieses Blog-Posting sich mit weiterführenden Fähigkeiten, wie Savepoints, Workspace-Refresh oder Konfliktmanagement beschäftigen. Legen wir am besten gleich los. Wieder dient uns die wohlbekannte Tabelle EMP als Ausgangspunkt. Diese wird zunächst version-enabled (sofern noch nicht geschehen), dann legen wir einen neuen Workspace an und machen darin ein paar Änderungen ...
begin
  dbms_wm.enableVersioning('EMP,DEPT');
end;
/

begin
  dbms_wm.createWorkspace('PLANUNG_1');
end;
/

begin
  dbms_wm.gotoWorkspace('PLANUNG_1');
end;
/

SQL> update emp set sal = sal * 2 where deptno = 20;

SQL> delete from emp where job = 'SALESMAN';

SQL> commit;

SQL> select * from emp order by deptno;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7934 MILLER     CLERK      7782 23.01.1982 00:00:00  1300           10
 7839 KING       PRESIDENT       17.11.1981 00:00:00  5000           10
 7782 CLARK      MANAGER    7839 09.06.1981 00:00:00  2450           10
 7902 FORD       ANALYST    7566 03.12.1981 00:00:00  6000           20
 7369 SMITH      CLERK      7902 17.12.1980 00:00:00  1600           20
 7566 JONES      MANAGER    7839 02.04.1981 00:00:00  5950           20
 7876 ADAMS      CLERK      7788 12.01.1983 00:00:00  2200           20
 7788 SCOTT      ANALYST    7566 09.12.1982 00:00:00  6000           20
 7900 JAMES      CLERK      7698 03.12.1981 00:00:00   950           30
 7698 BLAKE      MANAGER    7839 01.05.1981 00:00:00  2850           30

10 Zeilen ausgewählt.
Soweit waren wir beim letzten Mal auch schon. Nun könnten sich im übergeordneten Workspace LIVE ja auch noch Änderungen ergeben ... das ganze gilt natürlich dann auch analog für den Workspace PLANUNG_1 und einen diesem untergeordneten Workspace: Änderungen müssen nicht zwingend nur im Child-Workspace geschehen; auch im Parent können Änderungen gemacht werden ...

Änderungen vom Parent- zum Child-Workspace: Refresh

begin
  dbms_wm.gotoWorkspace('LIVE');
end;
/

SQL> update emp set job='SEN_CLERK' where deptno = 30 and job = 'CLERK';

SQL> select * from emp where deptno = 30;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7499 ALLEN      SALESMAN   7698 20.02.1981 00:00:00  1600   300     30
 7521 WARD       SALESMAN   7698 22.02.1981 00:00:00  1250   500     30
 7654 MARTIN     SALESMAN   7698 28.09.1981 00:00:00  1250  1400     30
 7698 BLAKE      MANAGER    7839 01.05.1981 00:00:00  2850           30
 7844 TURNER     SALESMAN   7698 08.09.1981 00:00:00  1500     0     30
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00   950           30

6 Zeilen ausgewählt.
Im Workspace PLANUNG_1 ist diese Änderung nicht sichtbar ... denn sie wurde ja gemacht, nachdem der Workspace angelegt wurde.
begin
  dbms_wm.gotoWorkspace('PLANUNG_1');
end;
/

SQL> select * from emp where deptno =30;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7698 BLAKE      MANAGER    7839 01.05.1981 00:00:00  2850           30
 7900 JAMES      CLERK      7698 03.12.1981 00:00:00   950           30
Mit einer Refresh-Operation (DBMS_WM.REFRESHWORKSPACE) werden Änderungen in einem Parent-Workspace zum Child Workspace übertragen - die Planung bzw. Simulation wird also mit den Änderungen in der Realität "aufgefrischt".
begin
  dbms_wm.refreshworkspace(
    workspace    => 'PLANUNG_1',
    auto_commit  => true,
    copy_data    => true
  );
end;
/

begin
  dbms_wm.gotoWorkspace('PLANUNG_1');
end;
/

SQL> select * from emp where deptno =30;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7698 BLAKE      MANAGER    7839 01.05.1981 00:00:00  2850           30
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00   950           30
Die Änderung im LIVE-Workspace ist also bei der PLANUNG_1 angekommen. Beim Workspace-Refresh ist nun vor allem der dritte Parameter copy_data wichtig.
  • false ändert nur die Versionsinformation der im Parent-Workspace geänderten Tabellenzeile; dadurch wird sie im Child-Workspace und auch in allen hierarchisch nachfolgenden Workspaces sofort sichtbar. Die Änderung wird quasi "in der Zeit vor das Anlegen der Child-Workspaces zurückgeschickt". Wenn der Workspace PLANUNG_1 also noch einen Child-Workspace PLANUNG_1_A hat, dann ist der Refresh auch für diesen sofort sichtbar.
  • true kopiert die im Parent geänderten Tabellenzeilen - dadurch wird der Refresh im Child-Workspace sichtbar (wie gewünscht), in den hierarchisch darunter liegenden Workspaces ist die Änderung aber nicht - hierfür müssen dann nochmals eigene Refresh-Operationen durchgeführt werden.

Was tun bei Konflikten?

Nun wollen wir die Refresh-Operation nochmal ausprobieren. Diesmal machen wir aber eine Änderung an einer Tabellenzeile, die im Child-Workspace ebenfalls verändert wurde ...
begin
  dbms_wm.gotoWorkspace('LIVE');
end;
/

SQL> update emp set sal = sal * 3 where deptno = 20;

SQL> select * from emp where deptno = 20;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7369 SMITH      CLERK      7902 17.12.1980 00:00:00  2400           20
 7566 JONES      MANAGER    7839 02.04.1981 00:00:00  8925           20
 7788 SCOTT      ANALYST    7566 09.12.1982 00:00:00  9000           20
 7876 ADAMS      CLERK      7788 12.01.1983 00:00:00  3300           20
 7902 FORD       ANALYST    7566 03.12.1981 00:00:00  9000           20
Im Workspace PLANUNG_1 sieht die DEPTNO 20 so aus ...
begin
  dbms_wm.gotoWorkspace('PLANUNG_1');
end;
/

SQL> select * from emp where deptno = 20;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7369 SMITH      CLERK      7902 17.12.1980 00:00:00  1600           20
 7566 JONES      MANAGER    7839 02.04.1981 00:00:00  5950           20
 7788 SCOTT      ANALYST    7566 09.12.1982 00:00:00  6000           20
 7876 ADAMS      CLERK      7788 12.01.1983 00:00:00  2200           20
 7902 FORD       ANALYST    7566 03.12.1981 00:00:00  6000           20
Man sieht sofort, dass hier ein Konflikt vorliegt. Und das merkt man - sowohl beim Versuch eines Refresh von LIVE nach PLANUNG_1 ...
begin
  dbms_wm.refreshworkspace(
    workspace    => 'PLANUNG_1',
    auto_commit  => true,
    copy_data    => true
  );
end;
/

begin
*
FEHLER in Zeile 1:
ORA-20055: conflicts detected for workspace: 'PLANUNG_1' in table: 'WM.EMP'
ORA-06512: in "WMSYS.LT", Zeile 5293
ORA-06512: in Zeile 2
... als auch bei der umgekehrten Merge-Operation ...
begin
  dbms_wm.mergeworkspace(
    workspace    => 'PLANUNG_1'
  );
end;
/

begin
*
FEHLER in Zeile 1:
ORA-20055: conflicts detected for workspace: 'PLANUNG_1' in table: 'WM.EMP'
ORA-06512: in "WMSYS.LT", Zeile 6043
ORA-06512: in Zeile 2
... gibt es einen Fehlermeldung. Diese Konflikte müssen gelöst werden, bevor ein Refresh oder Merge erfolgreich durchgeführt werden kann. Dazu dienen die Prozeduren BEGINRESOLVE, RESOLVECONFLICTS und COMMITRESOLVE im Paket DBMS_WM.
  • Zunächst wird mit DBMW_WM.BEGINRESOLVE eine Konfliktlösungs-Session begonnen.
    begin
      dbms_wm.beginResolve(
        workspace    => 'PLANUNG_1'
      );
    end;
    /
    
  • Danach wird mit DBMS_WM.RESOLVECONFLICTS festgelegt, welche Version (aus dem Parent- oder aus dem Child-Workspace) beim einem Merge oder Refresh genommen werden soll. Mit einer WHERE-Klausel wird festgelegt, für welche Tabellenzeilen die Regel gelten soll. So können auch mehrere Regeln hinterlegt werden. Im folgenden soll für die MANAGER die Änderung aus dem Parent-Workspace (LIVE) und für alle anderen die Änderung aus dem Child-Workspace gelten. Da in der WHERE-Klausel nur Primärschlüsselspalten angesprochen werden dürfen, müssen wir hierfür mit etwas PL/SQL arbeiten ...
    begin
      for e in (select empno, job from emp) loop
        if e.job = 'MANAGER' then 
          dbms_wm.resolveConflicts (
            workspace    => 'PLANUNG_1',
            table_name   => 'EMP',
            where_clause => 'EMPNO = '||e.empno,
            keep         => 'PARENT'
          );
        else 
          dbms_wm.resolveConflicts (
            workspace    => 'PLANUNG_1',
            table_name   => 'EMP',
            where_clause => 'EMPNO = '||e.empno,
            keep         => 'CHILD'
          );
        end if;
      end loop;
    end;
    /
    
  • Schließlich wird die Konfliktlösungs-Session mit DBMW_WM.COMMITRESOLVE abgeschlossen. Achten Sie darauf, vorher ein "normales" COMMIT abzusetzen.
    commit
    /
    
    begin
      dbms_wm.commitResolve(
        workspace    => 'PLANUNG_1'
      );
    end;
    /
    
Anschließend wird die Merge- oder Refresh-Operation fehlerfrei durchlaufen.
begin
  dbms_wm.mergeworkspace(
    workspace    => 'PLANUNG_1'
  );
end;
/

PL/SQL-Prozedur erfolgreich abgeschlossen.
Nach der Merge-Operation befindet sich die folgende Version der Tabelle EMP im Workspace LIVE.
SQL> select * from emp where deptno = 20;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7369 SMITH      CLERK      7902 17.12.1980 00:00:00  1600           20
 7566 JONES      MANAGER    7839 02.04.1981 00:00:00  8925           20
 7788 SCOTT      ANALYST    7566 09.12.1982 00:00:00  6000           20
 7876 ADAMS      CLERK      7788 12.01.1983 00:00:00  2200           20
 7902 FORD       ANALYST    7566 03.12.1981 00:00:00  6000           20
Im "echten Leben" kennt man die Konflikte natürlich nicht im Voraus. Doch der Workspace Manager bietet auch Möglichkeiten an, Workspaces auf Konflikte hin zu untersuchen. Wir starten nochmals in der Konfliktsituation.
begin
  dbms_wm.mergeworkspace(
    workspace    => 'PLANUNG_1'
  );
end;
/

begin
*
FEHLER in Zeile 1:
ORA-20055: conflicts detected for workspace: 'PLANUNG_1' in table: 'WM.EMP'
ORA-06512: in "WMSYS.LT", Zeile 6043
ORA-06512: in Zeile 2
Die Konfliktuntersuchung startet mit einem Aufruf von DBMS_WM.SETCONFLICTWORKSPACE. Danach dann die View EMP_CONF untersucht werden ...
begin
  dbms_wm.setConflictWorkspace('PLANUNG_1');
end;
/

SQL> select wm_workspace, empno, ename, job, deptno, sal, wm_deleted from emp_conf order by empno, wm_workspace;

WM_WORKSPACE      EMPNO ENAME      JOB           DEPTNO        SAL WM_
------------ ---------- ---------- --------- ---------- ---------- ---
BASE               7369 SMITH      CLERK             20        800 NO
LIVE               7369 SMITH      CLERK             20       2400 NO
PLANUNG_1          7369 SMITH      CLERK             20       1600 NO
BASE               7566 JONES      MANAGER           20       2975 NO
LIVE               7566 JONES      MANAGER           20       8925 NO
PLANUNG_1          7566 JONES      MANAGER           20       5950 NO
BASE               7788 SCOTT      ANALYST           20       3000 NO
LIVE               7788 SCOTT      ANALYST           20       9000 NO
PLANUNG_1          7788 SCOTT      ANALYST           20       6000 NO
BASE               7876 ADAMS      CLERK             20       1100 NO
LIVE               7876 ADAMS      CLERK             20       3300 NO
PLANUNG_1          7876 ADAMS      CLERK             20       2200 NO
BASE               7902 FORD       ANALYST           20       3000 NO
LIVE               7902 FORD       ANALYST           20       9000 NO
PLANUNG_1          7902 FORD       ANALYST           20       6000 NO

15 Zeilen ausgewählt.
Die View EMP_CONF enthält nun für jede Tabellenzeile, für die ein Konflikt besteht, drei Informationen: Mit BASE wird die gemeinsame Basis beider "Konfliktparteien" - in unserem Fall der Originalwert aus der Tabelle EMP angegeben. Zusätzlich sind die Versionsstände aus beiden Workspaces vorhanden. Auf Basis dieser View ließe sich nun auch eine Oberfläche für den Endanwender erstellen - dieser könnte dann jeweils anklicken, welche Version die Richtige sein soll.

Savepoints in einem Workspace

Savepoints im Workspace Manager sind prinzipiell das gleiche wie Savepoints im Rahmen einer "normalen" Datenbanktransaktion. Sie werden mit DBMS_WM.CREATESAVEPOINT erstellt und können beim Rollback eines Workspace verwendet werden. Anstelle der Prozedur RollbackWorkspace verwendet man dann DBMS_WM.ROLLBACKTOSP. Es werden dann nicht alle Änderungen des Workspace zurückgerollt, sondern nur die bis zum angegebenen Savepoint.
SQL> select * from emp where empno = 7900;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00   950           30

SQL> update emp set sal = 2000 where empno=7900;

SQL> commit;

SQL> select * from emp where empno = 7900;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00  2000           30


begin
  dbms_wm.createSavepoint(
    workspace      => 'PLANUNG_1',
    savepoint_name => 'SP_A',
    description    => '...',
    auto_commit    => true
  );
end;
/

SQL> update emp set sal = 5000 where empno=7900;

SQL> commit;

SQL> select * from emp where empno=7900;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00  5000           30

begin
  dbms_wm.rollbackToSp(
    workspace      => 'PLANUNG_1',
    savepoint_name => 'SP_A'
  );
end;
/

SQL> select * from emp where empno = 7900;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00  2000           30
Damit soll es für heute nun auch genug sein. Die verbleibenden Features werde ich dann in einem dritten Blog-Posting abdecken.
  • Gibt es ein Privilegienmodell für den Workspace Manager?
  • Gibt es eine Historisierung?
  • ...
Bis dahin verweise ich auf folgendes Material zum Weiterlesen ...
Today I'll continue the blog posting about "Oracle Workspace Manager". The first posting covered the very basic functionality like version-enabling one or more tables, creating a workspace and merging changes. This posting contains the Refresh operation, Conflict Management and Savepoints in a Workspace. Again, we'll use the well-known table EMP to illustrate the examples - first we'll version-enable (if not done already), then we'll create a new workspace and make some changes ....
begin
  dbms_wm.enableVersioning('EMP,DEPT');
end;
/

begin
  dbms_wm.createWorkspace('PLAN_1');
end;
/

begin
  dbms_wm.gotoWorkspace('PLAN_1');
end;
/

SQL> update emp set sal = sal * 2 where deptno = 20;

SQL> delete from emp where job = 'SALESMAN';

SQL> commit;

SQL> select * from emp order by deptno;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7934 MILLER     CLERK      7782 23.01.1982 00:00:00  1300           10
 7839 KING       PRESIDENT       17.11.1981 00:00:00  5000           10
 7782 CLARK      MANAGER    7839 09.06.1981 00:00:00  2450           10
 7902 FORD       ANALYST    7566 03.12.1981 00:00:00  6000           20
 7369 SMITH      CLERK      7902 17.12.1980 00:00:00  1600           20
 7566 JONES      MANAGER    7839 02.04.1981 00:00:00  5950           20
 7876 ADAMS      CLERK      7788 12.01.1983 00:00:00  2200           20
 7788 SCOTT      ANALYST    7566 09.12.1982 00:00:00  6000           20
 7900 JAMES      CLERK      7698 03.12.1981 00:00:00   950           30
 7698 BLAKE      MANAGER    7839 01.05.1981 00:00:00  2850           30

10 rows selected.
Now we have the same state as in the last blog posting. But what, if there are changes in the parent workspace of PLAN_1? Other sessions might change the table in the LIVE workspace. And it would be the same situation, if we changed the table in PLAN_1 and PLAN_1 had child workspaces.

Propagating changes from Parent to Child Workspaces: Refresh

begin
  dbms_wm.gotoWorkspace('LIVE');
end;
/

SQL> update emp set job='SEN_CLERK' where deptno = 30 and job = 'CLERK';

SQL> select * from emp where deptno = 30;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7499 ALLEN      SALESMAN   7698 20.02.1981 00:00:00  1600   300     30
 7521 WARD       SALESMAN   7698 22.02.1981 00:00:00  1250   500     30
 7654 MARTIN     SALESMAN   7698 28.09.1981 00:00:00  1250  1400     30
 7698 BLAKE      MANAGER    7839 01.05.1981 00:00:00  2850           30
 7844 TURNER     SALESMAN   7698 08.09.1981 00:00:00  1500     0     30
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00   950           30

6 rows selected.
The changes in the LIVE workspace are not visible in the child workspace PLAN_1. And this is obvious, since the change has been done after the child workspace was created.
begin
  dbms_wm.gotoWorkspace('PLAN');
end;
/

SQL> select * from emp where deptno = 30;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7698 BLAKE      MANAGER    7839 01.05.1981 00:00:00  2850           30
 7900 JAMES      CLERK      7698 03.12.1981 00:00:00   950           30
The Refresh Operation (DBMS_WM.REFRESHWORKSPACE) propagates changes from the parent to a child workspace. Expressed otherwise, the simulation or planning scenario is being refreshed with the change of reality.
begin
  dbms_wm.refreshworkspace(
    workspace    => 'PLAN_1',
    auto_commit  => true,
    copy_data    => true
  );
end;
/

begin
  dbms_wm.gotoWorkspace('PLAN_1');
end;
/

SQL> select * from emp where deptno = 30;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7698 BLAKE      MANAGER    7839 01.05.1981 00:00:00  2850           30
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00   950           30
Now the change, which was done within the LIVE workspace, arrived in PLAN_1. The third parameter copy_data is very important.
  • false just updates the version information of the changed rows. The change is, so-to-say, being "pushed into the past - before the child workspaces were created". The effect of this is that the change is not only visible in the direct child workspace, but also in all subsequent child workspaces. So if PLAN_1 also had child workspaces the refresh operation would affect them as well.
  • true copies the changed rows to the child workspace. So the refresh operation only affects the given child workspaces. Subsequent child workspaces are not affected.

Conflict Management

Now we'll do the refresh operation again - but this time we'll (in the parent workspace) change some rows for which we know that they already have been changed in the child workspace. So in the LIVE workspace we have this situation:
begin
  dbms_wm.gotoWorkspace('LIVE');
end;
/

SQL> update emp set sal = sal * 3 where deptno = 20;

SQL> select * from emp where deptno = 20;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7369 SMITH      CLERK      7902 17.12.1980 00:00:00  2400           20
 7566 JONES      MANAGER    7839 02.04.1981 00:00:00  8925           20
 7788 SCOTT      ANALYST    7566 09.12.1982 00:00:00  9000           20
 7876 ADAMS      CLERK      7788 12.01.1983 00:00:00  3300           20
 7902 FORD       ANALYST    7566 03.12.1981 00:00:00  9000           20
The table rows in PLAN_1 (the change was done above) looks like this ...
begin
  dbms_wm.gotoWorkspace('PLAN_1');
end;
/

SQL> select * from emp where deptno = 20;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7369 SMITH      CLERK      7902 17.12.1980 00:00:00  1600           20
 7566 JONES      MANAGER    7839 02.04.1981 00:00:00  5950           20
 7788 SCOTT      ANALYST    7566 09.12.1982 00:00:00  6000           20
 7876 ADAMS      CLERK      7788 12.01.1983 00:00:00  2200           20
 7902 FORD       ANALYST    7566 03.12.1981 00:00:00  6000           20
The conflict is obvious - the same rows have been changed in LIVE as well as in PLAN_1. An attempt to refresh from LIVE to PLAN_1 ...
begin
  dbms_wm.refreshworkspace(
    workspace    => 'PLAN_1',
    auto_commit  => true,
    copy_data    => true
  );
end;
/

begin
*
ERROR in line 1:
ORA-20055: conflicts detected for workspace: 'PLAN_1' in table: 'WM.EMP'
ORA-06512: in "WMSYS.LT", line 5293
ORA-06512: in line 2
... will fail as well as the Merge operation from PLAN_1 to LIVE.
begin
  dbms_wm.mergeworkspace(
    workspace    => 'PLAN_1'
  );
end;
/

begin
*
ERROR in line 1:
ORA-20055: conflicts detected for workspace: 'PLAN_1' in table: 'WM.EMP'
ORA-06512: in "WMSYS.LT", line 6043
ORA-06512: in line 2
These conflicts must be resolved before the operation can succeed. For this, we have the procedures BEGINRESOLVE, RESOLVECONFLICTS and COMMITRESOLVE in DBMS_WM.
  • First, we'll start a conflict resolving session by calling DBMW_WM.BEGINRESOLVE.
    begin
      dbms_wm.beginResolve(
        workspace    => 'PLAN_1'
      );
    end;
    /
    
  • Then we'll use DBMS_WM.RESOLVECONFLICTS to decide, which version (Parent, Child or the common base) will succeed, when a conflict is being detected. DBMS_WNM.RESOLVECONFLICTS can be called multiple times. A SQL WHERE clause, given as the third parameter, determines the table row(s) for which this rule is to be applied. The following example will take the version from the parent workspace for all MANAGERs and the version from the child workspace for all other rows. But we cannot supply any WHERE clause we want: Workspace Manager forces us to use primary key columns in most cases. But with a bit of PL/SQL, this is an easy task ...
    begin
      for e in (select empno, job from emp) loop
        if e.job = 'MANAGER' then 
          dbms_wm.resolveConflicts (
            workspace    => 'PLAN_1',
            table_name   => 'EMP',
            where_clause => 'EMPNO = '||e.empno,
            keep         => 'PARENT'
          );
        else 
          dbms_wm.resolveConflicts (
            workspace    => 'PLAN_1',
            table_name   => 'EMP',
            where_clause => 'EMPNO = '||e.empno,
            keep         => 'CHILD'
          );
        end if;
      end loop;
    end;
    /
    
  • Finally we'll close the Conflict Resolving Session by calling DBMW_WM.COMMITRESOLVE. Make sure to issue an "normal" COMMIT beforehand.
    commit
    /
    
    begin
      dbms_wm.commitResolve(
        workspace    => 'PLAN_1'
      );
    end;
    /
    
Now the Merge and Refresh Operations will both succeed.
begin
  dbms_wm.mergeworkspace(
    workspace    => 'PLAN_1'
  );
end;
/

PL/SQL procedure successfully completed.
After a Merge Operation, LIVE contains the following version of EMP.
SQL> select * from emp where deptno = 20;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7369 SMITH      CLERK      7902 17.12.1980 00:00:00  1600           20
 7566 JONES      MANAGER    7839 02.04.1981 00:00:00  8925           20
 7788 SCOTT      ANALYST    7566 09.12.1982 00:00:00  6000           20
 7876 ADAMS      CLERK      7788 12.01.1983 00:00:00  2200           20
 7902 FORD       ANALYST    7566 03.12.1981 00:00:00  6000           20
In reality, of course, we don't know the conflicts in advance. The good news is that Workspace Manager provides Views which provide information about conflicts. We'll - again - start with the conflict situation.
begin
  dbms_wm.mergeworkspace(
    workspace    => 'PLAN_1'
  );
end;
/

begin
*
ERROR in line 1:
ORA-20055: conflicts detected for workspace: 'PLAN_1' in table: 'WM.EMP'
ORA-06512: in "WMSYS.LT", line 5293
ORA-06512: in line 2
First, we need to set the workspace, for which we want to see the conflicts: DBMS_WM.SETCONFLICTWORKSPACE. Having done this, we can examine the View EMP_CONF to see the conflicts, Workspace Manager has detected.
begin
  dbms_wm.setConflictWorkspace('PLAN_1');
end;
/

SQL> select wm_workspace, empno, ename, job, deptno, sal, wm_deleted from emp_conf order by empno, wm_workspace;

WM_WORKSPACE      EMPNO ENAME      JOB           DEPTNO        SAL WM_
------------ ---------- ---------- --------- ---------- ---------- ---
BASE               7369 SMITH      CLERK             20        800 NO
LIVE               7369 SMITH      CLERK             20       2400 NO
PLAN_1             7369 SMITH      CLERK             20       1600 NO
BASE               7566 JONES      MANAGER           20       2975 NO
LIVE               7566 JONES      MANAGER           20       8925 NO
PLAN_1             7566 JONES      MANAGER           20       5950 NO
BASE               7788 SCOTT      ANALYST           20       3000 NO
LIVE               7788 SCOTT      ANALYST           20       9000 NO
PLAN_1             7788 SCOTT      ANALYST           20       6000 NO
BASE               7876 ADAMS      CLERK             20       1100 NO
LIVE               7876 ADAMS      CLERK             20       3300 NO
PLAN_1             7876 ADAMS      CLERK             20       2200 NO
BASE               7902 FORD       ANALYST           20       3000 NO
LIVE               7902 FORD       ANALYST           20       9000 NO
PLAN_1             7902 FORD       ANALYST           20       6000 NO

15 rows selected.
EMP_CONF contains three rows for each conflict. BASE is the common base of both conflict workspaces - in our case this is the original value from the EMP table. The other two rows contain the version from both conflict workspaces - here LIVE and PLAN_1. Based on this information, we could easily generate a user interface (use APEX), in which the end user just clicks the version he wants to be the "right" one.

Savepoints in a Workspace

Savepoints in Workspace Manager are basically the same as Savepoints in "normal" database transactions. DBMS_WM.CREATESAVEPOINT creates a savepoint and DBMS_WM.ROLLBACKTOSP rolls back all changes, but only up to the given Savepoint. The following example illustrates the behaviour.
SQL> select * from emp where empno = 7900;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00   950           30

SQL> update emp set sal = 2000 where empno=7900;

SQL> commit;

SQL> select * from emp where empno = 7900;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00  2000           30


begin
  dbms_wm.createSavepoint(
    workspace      => 'PLAN_1',
    savepoint_name => 'SP_A',
    description    => '...',
    auto_commit    => true
  );
end;
/

SQL> update emp set sal = 5000 where empno=7900;

SQL> commit;

SQL> select * from emp where empno=7900;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00  5000           30

begin
  dbms_wm.rollbackToSp(
    workspace      => 'PLAN_1',
    savepoint_name => 'SP_A'
  );
end;
/

SQL> select * from emp where empno = 7900;

EMPNO ENAME      JOB         MGR HIREDATE              SAL  COMM DEPTNO
----- ---------- --------- ----- ------------------- ----- ----- ------
 7900 JAMES      SEN_CLERK  7698 03.12.1981 00:00:00  2000           30
For today, this should be enough information - so I think, I'll need a third posting to cover the remaining topics ...
  • Does Workspace Manager keep a history?
  • Is there are privilege model for Workspace Manager?
  • ...
Until then ... here's some material for further reading ...

Beliebte Postings