summaryrefslogtreecommitdiffstats
path: root/www/session/rebaser.html
blob: f9751f4979c133d1ea25399fafeb8cf9b9f7b47c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link href="../sqlite.css" rel="stylesheet">
<title>Rebasing changesets</title>
<!-- path=../ -->
</head>
<body>
<div class=nosearch>
<a href="../index.html">
<img class="logo" src="../images/sqlite370_banner.gif" alt="SQLite" border="0">
</a>
<div><!-- IE hack to prevent disappearing logo --></div>
<div class="tagline desktoponly">
Small. Fast. Reliable.<br>Choose any three.
</div>
<div class="menu mainmenu">
<ul>
<li><a href="../index.html">Home</a>
<li class='mobileonly'><a href="javascript:void(0)" onclick='toggle_div("submenu")'>Menu</a>
<li class='wideonly'><a href='../about.html'>About</a>
<li class='desktoponly'><a href="../docs.html">Documentation</a>
<li class='desktoponly'><a href="../download.html">Download</a>
<li class='wideonly'><a href='../copyright.html'>License</a>
<li class='desktoponly'><a href="../support.html">Support</a>
<li class='desktoponly'><a href="../prosupport.html">Purchase</a>
<li class='search' id='search_menubutton'>
<a href="javascript:void(0)" onclick='toggle_search()'>Search</a>
</ul>
</div>
<div class="menu submenu" id="submenu">
<ul>
<li><a href='../about.html'>About</a>
<li><a href='../docs.html'>Documentation</a>
<li><a href='../download.html'>Download</a>
<li><a href='../support.html'>Support</a>
<li><a href='../prosupport.html'>Purchase</a>
</ul>
</div>
<div class="searchmenu" id="searchmenu">
<form method="GET" action="../search">
<select name="s" id="searchtype">
<option value="d">Search Documentation</option>
<option value="c">Search Changelog</option>
</select>
<input type="text" name="q" id="searchbox" value="">
<input type="submit" value="Go">
</form>
</div>
</div>
<script>
function toggle_div(nm) {
var w = document.getElementById(nm);
if( w.style.display=="block" ){
w.style.display = "none";
}else{
w.style.display = "block";
}
}
function toggle_search() {
var w = document.getElementById("searchmenu");
if( w.style.display=="block" ){
w.style.display = "none";
} else {
w.style.display = "block";
setTimeout(function(){
document.getElementById("searchbox").focus()
}, 30);
}
}
function div_off(nm){document.getElementById(nm).style.display="none";}
window.onbeforeunload = function(e){div_off("submenu");}
/* Disable the Search feature if we are not operating from CGI, since */
/* Search is accomplished using CGI and will not work without it. */
if( !location.origin || !location.origin.match || !location.origin.match(/http/) ){
document.getElementById("search_menubutton").style.display = "none";
}
/* Used by the Hide/Show button beside syntax diagrams, to toggle the */
function hideorshow(btn,obj){
var x = document.getElementById(obj);
var b = document.getElementById(btn);
if( x.style.display!='none' ){
x.style.display = 'none';
b.innerHTML='show';
}else{
x.style.display = '';
b.innerHTML='hide';
}
return false;
}
var antiRobot = 0;
function antiRobotGo(){
if( antiRobot!=3 ) return;
antiRobot = 7;
var j = document.getElementById("mtimelink");
if(j && j.hasAttribute("data-href")) j.href=j.getAttribute("data-href");
}
function antiRobotDefense(){
document.body.onmousedown=function(){
antiRobot |= 2;
antiRobotGo();
document.body.onmousedown=null;
}
document.body.onmousemove=function(){
antiRobot |= 2;
antiRobotGo();
document.body.onmousemove=null;
}
setTimeout(function(){
antiRobot |= 1;
antiRobotGo();
}, 100)
antiRobotGo();
}
antiRobotDefense();
</script>
<a href="../session/intro.html"><h2>Session Module C Interface</h2></a><h2>Rebasing changesets</h2><blockquote><pre>typedef struct sqlite3_rebaser sqlite3_rebaser;
</pre></blockquote><p><b>Important:</b> This interface is <a href="../c3ref/experimental.html">experimental</a> and is subject to change without notice.</p><p>
Suppose there is a site hosting a database in state S0. And that
modifications are made that move that database to state S1 and a
changeset recorded (the "local" changeset). Then, a changeset based
on S0 is received from another site (the "remote" changeset) and 
applied to the database. The database is then in state 
(S1+"remote"), where the exact state depends on any conflict
resolution decisions (OMIT or REPLACE) made while applying "remote".
Rebasing a changeset is to update it to take those conflict 
resolution decisions into account, so that the same conflicts
do not have to be resolved elsewhere in the network. </p>

<p>For example, if both the local and remote changesets contain an
INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)":</p>

<p>  local:  INSERT INTO t1 VALUES(1, 'v1');
  remote: INSERT INTO t1 VALUES(1, 'v2');</p>

<p>and the conflict resolution is REPLACE, then the INSERT change is
removed from the local changeset (it was overridden). Or, if the
conflict resolution was "OMIT", then the local changeset is modified
to instead contain:</p>

<p>          UPDATE t1 SET b = 'v2' WHERE a=1;</p>

<p>Changes within the local changeset are rebased as follows:</p>

<p><dl>
<dt>Local INSERT<dd>
  This may only conflict with a remote INSERT. If the conflict 
  resolution was OMIT, then add an UPDATE change to the rebased
  changeset. Or, if the conflict resolution was REPLACE, add
  nothing to the rebased changeset.</p>

<p><dt>Local DELETE<dd>
  This may conflict with a remote UPDATE or DELETE. In both cases the
  only possible resolution is OMIT. If the remote operation was a
  DELETE, then add no change to the rebased changeset. If the remote
  operation was an UPDATE, then the old.* fields of change are updated
  to reflect the new.* values in the UPDATE.</p>

<p><dt>Local UPDATE<dd>
  This may conflict with a remote UPDATE or DELETE. If it conflicts
  with a DELETE, and the conflict resolution was OMIT, then the update
  is changed into an INSERT. Any undefined values in the new.* record
  from the update change are filled in using the old.* values from
  the conflicting DELETE. Or, if the conflict resolution was REPLACE,
  the UPDATE change is simply omitted from the rebased changeset.</p>

<p>  If conflict is with a remote UPDATE and the resolution is OMIT, then
  the old.* values are rebased using the new.* values in the remote
  change. Or, if the resolution is REPLACE, then the change is copied
  into the rebased changeset with updates to columns also updated by
  the conflicting remote UPDATE removed. If this means no columns would 
  be updated, the change is omitted.
</dl></p>

<p>A local change may be rebased against multiple remote changes 
simultaneously. If a single key is modified by multiple remote 
changesets, they are combined as follows before the local changeset
is rebased:</p>

<p><ul>
   <li> If there has been one or more REPLACE resolutions on a
        key, it is rebased according to a REPLACE.</p>

<p>   <li> If there have been no REPLACE resolutions on a key, then
        the local changeset is rebased according to the most recent
        of the OMIT resolutions.
</ul></p>

<p>Note that conflict resolutions from multiple remote changesets are 
combined on a per-field basis, not per-row. This means that in the 
case of multiple remote UPDATE operations, some fields of a single 
local change may be rebased for REPLACE while others are rebased for 
OMIT.</p>

<p>In order to rebase a local changeset, the remote changeset must first
be applied to the local database using sqlite3changeset_apply_v2() and
the buffer of rebase information captured. Then:</p>

<p><ol>
  <li> An sqlite3_rebaser object is created by calling 
       sqlite3rebaser_create().
  <li> The new object is configured with the rebase buffer obtained from
       sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure().
       If the local changeset is to be rebased against multiple remote
       changesets, then sqlite3rebaser_configure() should be called
       multiple times, in the same order that the multiple
       sqlite3changeset_apply_v2() calls were made.
  <li> Each local changeset is rebased by calling sqlite3rebaser_rebase().
  <li> The sqlite3_rebaser object is deleted by calling
       sqlite3rebaser_delete().
</ol>
</p><p>See also lists of
  <a href="../session/objlist.html">Objects</a>,
  <a href="../session/constlist.html">Constants</a>, and
  <a href="../session/funclist.html">Functions</a>.</p>