summaryrefslogtreecommitdiff
path: root/doc/TODO.detail/merge
blob: 276e2528a3590b180a846ed7fb2853f5763ae342 (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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
From kleptog@svana.org Thu Nov 17 07:33:25 2005
Return-path: <kleptog@svana.org>
Received: from svana.org (mail@svana.org [203.20.62.76])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAHCXNu09324
	for <pgman@candle.pha.pa.us>; Thu, 17 Nov 2005 07:33:25 -0500 (EST)
Received: from kleptog by svana.org with local (Exim 3.35 #1 (Debian))
	id 1Eciwk-0007Gd-00; Thu, 17 Nov 2005 23:32:58 +1100
Date: Thu, 17 Nov 2005 13:32:57 +0100
From: Martijn van Oosterhout <kleptog@svana.org>
To: Csaba Nagy <nagy@ecircle-ag.com>
cc: Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Dann Corbit <DCorbit@connx.com>, Simon Riggs <simon@2ndquadrant.com>,
   Bruce Momjian <pgman@candle.pha.pa.us>,
   Rick Gigger <rick@alpinenetworking.com>, Tom Lane <tgl@sss.pgh.pa.us>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
Subject: Re: [HACKERS] MERGE vs REPLACE
Message-ID: <20051117123250.GC22933@svana.org>
Reply-To: Martijn van Oosterhout <kleptog@svana.org>
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="raC6veAxrt5nqIoY"
Content-Disposition: inline
In-Reply-To: <1132228373.10890.313.camel@coppola.muc.ecircle.de>
User-Agent: Mutt/1.3.28i
X-PGP-Key-ID: Length=1024; ID=0x0DC67BE6
X-PGP-Key-Fingerprint: 295F A899 A81A 156D B522  48A7 6394 F08A 0DC6 7BE6
X-PGP-Key-URL: <http://svana.org/kleptog/0DC67BE6.pgp.asc>
Status: OR


--raC6veAxrt5nqIoY
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Thu, Nov 17, 2005 at 12:52:53PM +0100, Csaba Nagy wrote:
> Yes, these algorithms are clear to me, but they don't work for batch
> updates in postgres without savepoints before each row insert/update,
> which is not good for performance (not to mention on older postgres
> versions without savepoint support it won't work at all). If there is a
> way of no race condition, no performance penalty, that would be
> something new and useful. I just guess the MERGE would provide that.

Well, then you guess wrong. This isn't what MERGE is for. MERGE is just
a neat way of specifying the UPDATE and INSERT cases in the same
statement. It doesn't remove the possibility duplicate inserts and thus
primary key violations.

If someone wants to make extensions to MERGE so that it can avoid the
race condition and avoid the duplicate key violations, that's fine. But
be aware that this is outside of the spec. It may be a useful addition,
but perhaps we should consider MERGE and REPLACE as completely seperate
targets.

MERGE has a whole join construction with subqueries that would be a
pain to make work in a way that is truly serialisable. REPLACE deals
with only one row and tries to solve the race for that case only. Much
easier to consider them seperately, no?

I guess what's really irritating is that this clearly exposes the case
listed in the docs as "Why SERIALIZABLE isn't in all cases". If we
could solve that for MERGE, we could probably solve it in the general
case too.

Have a nice day,
--=20
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.

--raC6veAxrt5nqIoY
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQFDfHhxIB7bNG8LQkwRAhIwAJwPmzE2GHrqzPujkkj2I5r6OlVo5QCeN4st
Ka50Vh0AnXuj4pBt27V6j7I=
=7rb7
-----END PGP SIGNATURE-----

--raC6veAxrt5nqIoY--

From pgsql-hackers-owner+M76186@postgresql.org Thu Nov 17 09:44:46 2005
Return-path: <pgsql-hackers-owner+M76186@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAHEihu07081
	for <pgman@candle.pha.pa.us>; Thu, 17 Nov 2005 09:44:44 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 84700C4B33D;
	Thu, 17 Nov 2005 14:44:42 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 84C6BD967F
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Thu, 17 Nov 2005 10:41:57 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 47040-01
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Thu, 17 Nov 2005 14:42:00 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from sss.pgh.pa.us (sss.pgh.pa.us [66.207.139.130])
	by svr1.postgresql.org (Postfix) with ESMTP id ECB3CD963C
	for <pgsql-hackers@postgresql.org>; Thu, 17 Nov 2005 10:41:53 -0400 (AST)
Received: from sss2.sss.pgh.pa.us (tgl@localhost [127.0.0.1])
	by sss.pgh.pa.us (8.13.1/8.13.1) with ESMTP id jAHEfAuK025850;
	Thu, 17 Nov 2005 09:41:11 -0500 (EST)
To: Csaba Nagy <nagy@ecircle-ag.com>
cc: Martijn van Oosterhout <kleptog@svana.org>,
   Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Dann Corbit <DCorbit@connx.com>, Simon Riggs <simon@2ndquadrant.com>,
   Bruce Momjian <pgman@candle.pha.pa.us>,
   Rick Gigger <rick@alpinenetworking.com>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
Subject: Re: [HACKERS] MERGE vs REPLACE 
In-Reply-To: <1132231474.10890.317.camel@coppola.muc.ecircle.de> 
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de>
Comments: In-reply-to Csaba Nagy <nagy@ecircle-ag.com>
	message dated "Thu, 17 Nov 2005 13:44:35 +0100"
Date: Thu, 17 Nov 2005 09:41:10 -0500
Message-ID: <25849.1132238470@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.008 required=5 tests=[AWL=0.008]
X-Spam-Score: 0.008
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: ORr

Csaba Nagy <nagy@ecircle-ag.com> writes:
> OK, in this case I don't care about either MERGE or REPLACE, but for an
> UPSERT which does the locking :-)

This is exactly the point --- pretty much nobody has come to us and
asked for a feature that does what Peter and Martijn say MERGE does.
(I haven't bothered to look at the 2003 spec, I'm assuming they read it
correctly.)  What we *have* been asked for, over and over, is an
insert-or-update feature that's not so tedious and inefficient as the
savepoint-insert-rollback-update kluge.  That's what we ought to be
concentrating on providing.

			regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

From pgsql-hackers-owner+M76189@postgresql.org Thu Nov 17 10:17:57 2005
Return-path: <pgsql-hackers-owner+M76189@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAHFHvu12126
	for <pgman@candle.pha.pa.us>; Thu, 17 Nov 2005 10:17:57 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 9B0AFC4B33D;
	Thu, 17 Nov 2005 15:17:55 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 02FEFDB988
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Thu, 17 Nov 2005 11:14:52 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 48136-10
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Thu, 17 Nov 2005 15:14:56 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from svr2.postgresql.org (svr2.postgresql.org [65.19.161.25])
	by svr1.postgresql.org (Postfix) with ESMTP id 34BD1DB97C
	for <pgsql-hackers@postgresql.org>; Thu, 17 Nov 2005 11:14:50 -0400 (AST)
Received: from ns.snowman.net (ns.snowman.net [66.92.160.21])
	by svr2.postgresql.org (Postfix) with ESMTP id A8A8FF0BEF
	for <pgsql-hackers@postgresql.org>; Thu, 17 Nov 2005 15:14:54 +0000 (GMT)
Received: by ns.snowman.net (Postfix, from userid 1000)
	id EDB5717AD6; Thu, 17 Nov 2005 10:15:30 -0500 (EST)
Date: Thu, 17 Nov 2005 10:15:30 -0500
From: Stephen Frost <sfrost@snowman.net>
To: Tom Lane <tgl@sss.pgh.pa.us>
cc: Csaba Nagy <nagy@ecircle-ag.com>,
   Martijn van Oosterhout <kleptog@svana.org>,
   Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Dann Corbit <DCorbit@connx.com>, Simon Riggs <simon@2ndquadrant.com>,
   Bruce Momjian <pgman@candle.pha.pa.us>,
   Rick Gigger <rick@alpinenetworking.com>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
Subject: Re: [HACKERS] MERGE vs REPLACE
Message-ID: <20051117151530.GU6026@ns.snowman.net>
Mail-Followup-To: Tom Lane <tgl@sss.pgh.pa.us>,
	Csaba Nagy <nagy@ecircle-ag.com>,
	Martijn van Oosterhout <kleptog@svana.org>,
	Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
	Dann Corbit <DCorbit@connx.com>, Simon Riggs <simon@2ndquadrant.com>,
	Bruce Momjian <pgman@candle.pha.pa.us>,
	Rick Gigger <rick@alpinenetworking.com>,
	Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
	"Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
	pgsql-hackers@postgresql.org,
	Jaime Casanova <systemguards@gmail.com>,
	Peter Eisentraut <peter_e@gmx.net>
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de> <25849.1132238470@sss.pgh.pa.us>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="aAYbr14jHAy2Yyau"
Content-Disposition: inline
In-Reply-To: <25849.1132238470@sss.pgh.pa.us>
X-Editor: Vim http://www.vim.org/
X-Info: http://www.snowman.net
X-Operating-System: Linux/2.4.24ns.3.0 (i686)
X-Uptime: 10:01:46 up 159 days,  7:15,  2 users,  load average: 0.31, 0.23, 0.13
User-Agent: Mutt/1.5.9i
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0 required=5 tests=[none]
X-Spam-Score: 0
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR


--aAYbr14jHAy2Yyau
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

* Tom Lane (tgl@sss.pgh.pa.us) wrote:
> This is exactly the point --- pretty much nobody has come to us and
> asked for a feature that does what Peter and Martijn say MERGE does.
> (I haven't bothered to look at the 2003 spec, I'm assuming they read it
> correctly.)  What we *have* been asked for, over and over, is an
> insert-or-update feature that's not so tedious and inefficient as the
> savepoint-insert-rollback-update kluge.  That's what we ought to be
> concentrating on providing.

I guess to be clear on what this distinction actually is, specifically:
MERGE under SQL2003 doesn't appear to be intended to be used
concurrently.  For data warehousing situations this can be just fine
such as in my case where I get a monthly update of some information and
need to merge that update in with the prior information.  In this case
there's only one MERGE running and I'd hope it'd be faster than doing
check for existance, insert/update on each row in plpgsql or something
(since there'd be multiple index lookups, etc, I think).  Concurrent
MERGEs running *can* fail, just like whole transactions which do the
check/insert/update can fail.

REPLACE/INSERT ON DUPLICATE UPDATE appears to essentially be a
transaction which is supposed to not fail but instead do locking to
ensure that it doesn't fail.  This requires predicate locking to be
efficient because you want to tell the concurrent transaction "if you
have the same key as me, just wait a second and you can do an update
'cause I'm going to create the key if it doesn't exist before I'm done".

I think REPLACE/INSERT ON DUPLICATE UPDATE is definitely harder to do
than MERGE because of the idea that it isn't supposed to fail generally.
I think SQL2003 MERGE would be reasonably easy to do and to get the
efficiency benefits out of it (assuming there are some to be had in the
end). =20

I don't think MERGE can really be made to be both though, in which case
it should really be the SQL2003 MERGE and we can make REPLACE/INSERT ON
DUPLICATE UPDATE something else.  Perhaps a special form of MERGE where
you know it's going to be doing that locking.  I really don't like the
idea of making the SQL2003 version of MERGE be the MERGE special case
(by requiring someone to take a table lock ahead of time or do something
else odd).

	Thanks,

		Stephen

--aAYbr14jHAy2Yyau
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFDfJ6SrzgMPqB3kigRAjXWAJ9R/50PoocURxvi74g7dwhIO4akgQCcDEDG
4hGZAVR/9Age8pFtEOp4kfo=
=F91e
-----END PGP SIGNATURE-----

--aAYbr14jHAy2Yyau--

From sfrost@snowman.net Thu Nov 17 10:14:59 2005
Return-path: <sfrost@snowman.net>
Received: from ns.snowman.net (ns.snowman.net [66.92.160.21])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAHFEwu11635
	for <pgman@candle.pha.pa.us>; Thu, 17 Nov 2005 10:14:58 -0500 (EST)
Received: by ns.snowman.net (Postfix, from userid 1000)
	id EDB5717AD6; Thu, 17 Nov 2005 10:15:30 -0500 (EST)
Date: Thu, 17 Nov 2005 10:15:30 -0500
From: Stephen Frost <sfrost@snowman.net>
To: Tom Lane <tgl@sss.pgh.pa.us>
cc: Csaba Nagy <nagy@ecircle-ag.com>,
   Martijn van Oosterhout <kleptog@svana.org>,
   Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Dann Corbit <DCorbit@connx.com>, Simon Riggs <simon@2ndquadrant.com>,
   Bruce Momjian <pgman@candle.pha.pa.us>,
   Rick Gigger <rick@alpinenetworking.com>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
Subject: Re: [HACKERS] MERGE vs REPLACE
Message-ID: <20051117151530.GU6026@ns.snowman.net>
Mail-Followup-To: Tom Lane <tgl@sss.pgh.pa.us>,
	Csaba Nagy <nagy@ecircle-ag.com>,
	Martijn van Oosterhout <kleptog@svana.org>,
	Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
	Dann Corbit <DCorbit@connx.com>,
	Simon Riggs <simon@2ndquadrant.com>,
	Bruce Momjian <pgman@candle.pha.pa.us>,
	Rick Gigger <rick@alpinenetworking.com>,
	Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
	"Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
	pgsql-hackers@postgresql.org,
	Jaime Casanova <systemguards@gmail.com>,
	Peter Eisentraut <peter_e@gmx.net>
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de> <25849.1132238470@sss.pgh.pa.us>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="aAYbr14jHAy2Yyau"
Content-Disposition: inline
In-Reply-To: <25849.1132238470@sss.pgh.pa.us>
X-Editor: Vim http://www.vim.org/
X-Info: http://www.snowman.net
X-Operating-System: Linux/2.4.24ns.3.0 (i686)
X-Uptime: 10:01:46 up 159 days,  7:15,  2 users,  load average: 0.31, 0.23, 0.13
User-Agent: Mutt/1.5.9i
Status: OR


--aAYbr14jHAy2Yyau
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

* Tom Lane (tgl@sss.pgh.pa.us) wrote:
> This is exactly the point --- pretty much nobody has come to us and
> asked for a feature that does what Peter and Martijn say MERGE does.
> (I haven't bothered to look at the 2003 spec, I'm assuming they read it
> correctly.)  What we *have* been asked for, over and over, is an
> insert-or-update feature that's not so tedious and inefficient as the
> savepoint-insert-rollback-update kluge.  That's what we ought to be
> concentrating on providing.

I guess to be clear on what this distinction actually is, specifically:
MERGE under SQL2003 doesn't appear to be intended to be used
concurrently.  For data warehousing situations this can be just fine
such as in my case where I get a monthly update of some information and
need to merge that update in with the prior information.  In this case
there's only one MERGE running and I'd hope it'd be faster than doing
check for existance, insert/update on each row in plpgsql or something
(since there'd be multiple index lookups, etc, I think).  Concurrent
MERGEs running *can* fail, just like whole transactions which do the
check/insert/update can fail.

REPLACE/INSERT ON DUPLICATE UPDATE appears to essentially be a
transaction which is supposed to not fail but instead do locking to
ensure that it doesn't fail.  This requires predicate locking to be
efficient because you want to tell the concurrent transaction "if you
have the same key as me, just wait a second and you can do an update
'cause I'm going to create the key if it doesn't exist before I'm done".

I think REPLACE/INSERT ON DUPLICATE UPDATE is definitely harder to do
than MERGE because of the idea that it isn't supposed to fail generally.
I think SQL2003 MERGE would be reasonably easy to do and to get the
efficiency benefits out of it (assuming there are some to be had in the
end). =20

I don't think MERGE can really be made to be both though, in which case
it should really be the SQL2003 MERGE and we can make REPLACE/INSERT ON
DUPLICATE UPDATE something else.  Perhaps a special form of MERGE where
you know it's going to be doing that locking.  I really don't like the
idea of making the SQL2003 version of MERGE be the MERGE special case
(by requiring someone to take a table lock ahead of time or do something
else odd).

	Thanks,

		Stephen

--aAYbr14jHAy2Yyau
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFDfJ6SrzgMPqB3kigRAjXWAJ9R/50PoocURxvi74g7dwhIO4akgQCcDEDG
4hGZAVR/9Age8pFtEOp4kfo=
=F91e
-----END PGP SIGNATURE-----

--aAYbr14jHAy2Yyau--

From pgsql-hackers-owner+M76234@postgresql.org Thu Nov 17 22:19:04 2005
Return-path: <pgsql-hackers-owner+M76234@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAI3J3O11471
	for <pgman@candle.pha.pa.us>; Thu, 17 Nov 2005 22:19:04 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id CBDDBC4B337;
	Fri, 18 Nov 2005 03:18:59 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id BB822DB600
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Thu, 17 Nov 2005 23:12:08 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 30987-04
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Fri, 18 Nov 2005 03:12:11 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from candle.pha.pa.us (candle.pha.pa.us [64.139.89.126])
	by svr1.postgresql.org (Postfix) with ESMTP id 7CB16DB466
	for <pgsql-hackers@postgresql.org>; Thu, 17 Nov 2005 23:12:05 -0400 (AST)
Received: (from pgman@localhost)
	by candle.pha.pa.us (8.11.6/8.11.6) id jAI3BXS10887;
	Thu, 17 Nov 2005 22:11:33 -0500 (EST)
From: Bruce Momjian <pgman@candle.pha.pa.us>
Message-ID: <200511180311.jAI3BXS10887@candle.pha.pa.us>
Subject: Re: [HACKERS] MERGE vs REPLACE
In-Reply-To: <25849.1132238470@sss.pgh.pa.us>
To: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 17 Nov 2005 22:11:33 -0500 (EST)
cc: Csaba Nagy <nagy@ecircle-ag.com>,
   Martijn van Oosterhout <kleptog@svana.org>,
   Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Dann Corbit <DCorbit@connx.com>, Simon Riggs <simon@2ndquadrant.com>,
   Rick Gigger <rick@alpinenetworking.com>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
X-Mailer: ELM [version 2.4ME+ PL121 (25)]
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.036 required=5 tests=[AWL=0.036]
X-Spam-Score: 0.036
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

Tom Lane wrote:
> Csaba Nagy <nagy@ecircle-ag.com> writes:
> > OK, in this case I don't care about either MERGE or REPLACE, but for an
> > UPSERT which does the locking :-)
> 
> This is exactly the point --- pretty much nobody has come to us and
> asked for a feature that does what Peter and Martijn say MERGE does.
> (I haven't bothered to look at the 2003 spec, I'm assuming they read it
> correctly.)  What we *have* been asked for, over and over, is an
> insert-or-update feature that's not so tedious and inefficient as the
> savepoint-insert-rollback-update kluge.  That's what we ought to be
> concentrating on providing.

I am confused over the various options.  I have heard these syntaxes:

	SQL2003 MERGE
	MySQL REPLACE
		http://dev.mysql.com/doc/refman/5.1/en/replace.html
	MySQL INSERT VIOLATION ...
	UPSERT

So it seems MERGE does not have the use-case we most need, though it can
be bent to do it.  (Given their MATCH syntax, it doesn't seem there is
any logic that it tries INSERT first).

Looking at the MySQL URL above, REPLACE has three possible syntaxes with
normal (DELETE), SET (UPDATE), and SELECT.  Is this the direction we
need to go?  I don't like INSERT ... VIOLATION because I would like a
new keyword for this.  Is UPSERT the same as REPLACE?  Should we use
UPSERT instead?
	
-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

From DCorbit@connx.com Thu Nov 17 22:43:54 2005
Return-path: <DCorbit@connx.com>
Received: from postal.corporate.connx.com (postal.corporate.connx.com [65.212.159.187])
	by candle.pha.pa.us (8.11.6/8.11.6) with SMTP id jAI3hqO14288
	for <pgman@candle.pha.pa.us>; Thu, 17 Nov 2005 22:43:52 -0500 (EST)
content-class: urn:content-classes:message
MIME-Version: 1.0
Content-Type: multipart/mixed;
	boundary="----_=_NextPart_001_01C5EBF2.45ACB7DC"
X-MimeOLE: Produced By Microsoft Exchange V6.5.7226.0
Subject: RE: [HACKERS] MERGE vs REPLACE
Date: Thu, 17 Nov 2005 19:43:43 -0800
Message-ID: <D425483C2C5C9F49B5B7A41F8944154757D2EB@postal.corporate.connx.com>
Thread-Topic: [HACKERS] MERGE vs REPLACE
Thread-Index: AcXr7dUIILx3WyhrREu/dEAzLwToBgABFVZw
From: "Dann Corbit" <DCorbit@connx.com>
To: "Bruce Momjian" <pgman@candle.pha.pa.us>, "Tom Lane" <tgl@sss.pgh.pa.us>
cc: "Csaba Nagy" <nagy@ecircle-ag.com>,
   "Martijn van Oosterhout" <kleptog@svana.org>,
   "Zeugswetter Andreas DCP SD" <ZeugswetterA@spardat.at>,
   "Simon Riggs" <simon@2ndquadrant.com>,
   "Rick Gigger" <rick@alpinenetworking.com>,
   "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, <josh@agliodbs.com>,
   <pgsql-hackers@postgresql.org>, "Jaime Casanova" <systemguards@gmail.com>,
   "Peter Eisentraut" <peter_e@gmx.net>
Status: OR

This is a multi-part message in MIME format.

------_=_NextPart_001_01C5EBF2.45ACB7DC
Content-Type: text/plain;
	charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

Attached web page is an extract from the SQL Standards working committee
document on MERGE

> -----Original Message-----
> From: Bruce Momjian [mailto:pgman@candle.pha.pa.us]
> Sent: Thursday, November 17, 2005 7:12 PM
> To: Tom Lane
> Cc: Csaba Nagy; Martijn van Oosterhout; Zeugswetter Andreas DCP SD;
Dann
> Corbit; Simon Riggs; Rick Gigger; Christopher Kings-Lynne; Jim C.
Nasby;
> josh@agliodbs.com; pgsql-hackers@postgresql.org; Jaime Casanova; Peter
> Eisentraut
> Subject: Re: [HACKERS] MERGE vs REPLACE
>=20
> Tom Lane wrote:
> > Csaba Nagy <nagy@ecircle-ag.com> writes:
> > > OK, in this case I don't care about either MERGE or REPLACE, but
for
> an
> > > UPSERT which does the locking :-)
> >
> > This is exactly the point --- pretty much nobody has come to us and
> > asked for a feature that does what Peter and Martijn say MERGE does.
> > (I haven't bothered to look at the 2003 spec, I'm assuming they read
it
> > correctly.)  What we *have* been asked for, over and over, is an
> > insert-or-update feature that's not so tedious and inefficient as
the
> > savepoint-insert-rollback-update kluge.  That's what we ought to be
> > concentrating on providing.
>=20
> I am confused over the various options.  I have heard these syntaxes:
>=20
> 	SQL2003 MERGE
> 	MySQL REPLACE
> 		http://dev.mysql.com/doc/refman/5.1/en/replace.html
> 	MySQL INSERT VIOLATION ...
> 	UPSERT
>=20
> So it seems MERGE does not have the use-case we most need, though it
can
> be bent to do it.  (Given their MATCH syntax, it doesn't seem there is
> any logic that it tries INSERT first).
>=20
> Looking at the MySQL URL above, REPLACE has three possible syntaxes
with
> normal (DELETE), SET (UPDATE), and SELECT.  Is this the direction we
> need to go?  I don't like INSERT ... VIOLATION because I would like a
> new keyword for this.  Is UPSERT the same as REPLACE?  Should we use
> UPSERT instead?
>=20
> --
>   Bruce Momjian                        |  http://candle.pha.pa.us
>   pgman@candle.pha.pa.us               |  (610) 359-1001
>   +  If your life is a hard drive,     |  13 Roberts Road
>   +  Christ can be your backup.        |  Newtown Square, Pennsylvania
> 19073

------_=_NextPart_001_01C5EBF2.45ACB7DC
Content-Type: text/html;
	name="merge.htm"
Content-Transfer-Encoding: base64
Content-Description: merge.htm
Content-Disposition: attachment;
	filename="merge.htm"

PGh0bWwgeG1sbnM6bz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6b2ZmaWNlIg0K
eG1sbnM6dz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCINCnhtbG5zOng9
InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOmV4Y2VsIg0KeG1sbnM9Imh0dHA6Ly93
d3cudzMub3JnL1RSL1JFQy1odG1sNDAiPg0KDQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9Q29u
dGVudC1UeXBlIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD13aW5kb3dzLTEyNTIiPg0KPG1l
dGEgbmFtZT1Qcm9nSWQgY29udGVudD1Xb3JkLkRvY3VtZW50Pg0KPG1ldGEgbmFtZT1HZW5lcmF0
b3IgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTEiPg0KPG1ldGEgbmFtZT1PcmlnaW5hdG9yIGNv
bnRlbnQ9Ik1pY3Jvc29mdCBXb3JkIDExIj4NCjxsaW5rIHJlbD1GaWxlLUxpc3QgaHJlZj0ibWVy
Z2VfZmlsZXMvZmlsZWxpc3QueG1sIj4NCjx0aXRsZT4xNDwvdGl0bGU+DQo8IS0tW2lmIGd0ZSBt
c28gOV0+PHhtbD4NCiA8bzpEb2N1bWVudFByb3BlcnRpZXM+DQogIDxvOkF1dGhvcj5EYW5uIENv
cmJpdDwvbzpBdXRob3I+DQogIDxvOkxhc3RBdXRob3I+RGFubiBDb3JiaXQ8L286TGFzdEF1dGhv
cj4NCiAgPG86UmV2aXNpb24+MTwvbzpSZXZpc2lvbj4NCiAgPG86VG90YWxUaW1lPjc8L286VG90
YWxUaW1lPg0KICA8bzpDcmVhdGVkPjIwMDUtMTEtMThUMDM6MzU6MDBaPC9vOkNyZWF0ZWQ+DQog
IDxvOkxhc3RTYXZlZD4yMDA1LTExLTE4VDAzOjQyOjAwWjwvbzpMYXN0U2F2ZWQ+DQogIDxvOlBh
Z2VzPjE8L286UGFnZXM+DQogIDxvOldvcmRzPjIzODk8L286V29yZHM+DQogIDxvOkNoYXJhY3Rl
cnM+MTM2MjE8L286Q2hhcmFjdGVycz4NCiAgPG86Q29tcGFueT5DT05OWCBTb2x1dGlvbnM8L286
Q29tcGFueT4NCiAgPG86TGluZXM+MTEzPC9vOkxpbmVzPg0KICA8bzpQYXJhZ3JhcGhzPjMxPC9v
OlBhcmFncmFwaHM+DQogIDxvOkNoYXJhY3RlcnNXaXRoU3BhY2VzPjE1OTc5PC9vOkNoYXJhY3Rl
cnNXaXRoU3BhY2VzPg0KICA8bzpWZXJzaW9uPjExLjY1Njg8L286VmVyc2lvbj4NCiA8L286RG9j
dW1lbnRQcm9wZXJ0aWVzPg0KPC94bWw+PCFbZW5kaWZdLS0+PCEtLVtpZiBndGUgbXNvIDldPjx4
bWw+DQogPHc6V29yZERvY3VtZW50Pg0KICA8dzpTcGVsbGluZ1N0YXRlPkNsZWFuPC93OlNwZWxs
aW5nU3RhdGU+DQogIDx3OkdyYW1tYXJTdGF0ZT5DbGVhbjwvdzpHcmFtbWFyU3RhdGU+DQogIDx3
OlB1bmN0dWF0aW9uS2VybmluZy8+DQogIDx3OlZhbGlkYXRlQWdhaW5zdFNjaGVtYXMvPg0KICA8
dzpTYXZlSWZYTUxJbnZhbGlkPmZhbHNlPC93OlNhdmVJZlhNTEludmFsaWQ+DQogIDx3Oklnbm9y
ZU1peGVkQ29udGVudD5mYWxzZTwvdzpJZ25vcmVNaXhlZENvbnRlbnQ+DQogIDx3OkFsd2F5c1No
b3dQbGFjZWhvbGRlclRleHQ+ZmFsc2U8L3c6QWx3YXlzU2hvd1BsYWNlaG9sZGVyVGV4dD4NCiAg
PHc6Q29tcGF0aWJpbGl0eT4NCiAgIDx3OkJyZWFrV3JhcHBlZFRhYmxlcy8+DQogICA8dzpTbmFw
VG9HcmlkSW5DZWxsLz4NCiAgIDx3OldyYXBUZXh0V2l0aFB1bmN0Lz4NCiAgIDx3OlVzZUFzaWFu
QnJlYWtSdWxlcy8+DQogICA8dzpEb250R3Jvd0F1dG9maXQvPg0KICA8L3c6Q29tcGF0aWJpbGl0
eT4NCiAgPHc6QnJvd3NlckxldmVsPk1pY3Jvc29mdEludGVybmV0RXhwbG9yZXI0PC93OkJyb3dz
ZXJMZXZlbD4NCiA8L3c6V29yZERvY3VtZW50Pg0KPC94bWw+PCFbZW5kaWZdLS0+PCEtLVtpZiBn
dGUgbXNvIDldPjx4bWw+DQogPHc6TGF0ZW50U3R5bGVzIERlZkxvY2tlZFN0YXRlPSJmYWxzZSIg
TGF0ZW50U3R5bGVDb3VudD0iMTU2Ij4NCiA8L3c6TGF0ZW50U3R5bGVzPg0KPC94bWw+PCFbZW5k
aWZdLS0+DQo8c3R5bGU+DQo8IS0tDQogLyogRm9udCBEZWZpbml0aW9ucyAqLw0KIEBmb250LWZh
Y2UNCgl7Zm9udC1mYW1pbHk6Q291cmllcjsNCglwYW5vc2UtMToyIDcgNCA5IDIgMiA1IDIgNCA0
Ow0KCW1zby1mb250LWNoYXJzZXQ6MDsNCgltc28tZ2VuZXJpYy1mb250LWZhbWlseTptb2Rlcm47
DQoJbXNvLWZvbnQtZm9ybWF0Om90aGVyOw0KCW1zby1mb250LXBpdGNoOmZpeGVkOw0KCW1zby1m
b250LXNpZ25hdHVyZTozIDAgMCAwIDEgMDt9DQogLyogU3R5bGUgRGVmaW5pdGlvbnMgKi8NCiBw
Lk1zb05vcm1hbCwgbGkuTXNvTm9ybWFsLCBkaXYuTXNvTm9ybWFsDQoJe21zby1zdHlsZS1wYXJl
bnQ6IiI7DQoJbWFyZ2luOjBpbjsNCgltYXJnaW4tYm90dG9tOi4wMDAxcHQ7DQoJbXNvLXBhZ2lu
YXRpb246d2lkb3ctb3JwaGFuOw0KCWZvbnQtc2l6ZToxMi4wcHQ7DQoJZm9udC1mYW1pbHk6IlRp
bWVzIE5ldyBSb21hbiI7DQoJbXNvLWZhcmVhc3QtZm9udC1mYW1pbHk6IlRpbWVzIE5ldyBSb21h
biI7fQ0Kc3Bhbi5TcGVsbEUNCgl7bXNvLXN0eWxlLW5hbWU6IiI7DQoJbXNvLXNwbC1lOnllczt9
DQpzcGFuLkdyYW1FDQoJe21zby1zdHlsZS1uYW1lOiIiOw0KCW1zby1ncmFtLWU6eWVzO30NCkBw
YWdlIFNlY3Rpb24xDQoJe3NpemU6OC41aW4gMTEuMGluOw0KCW1hcmdpbjouNzVpbiAuNzVpbiAu
NzVpbiAuNzVpbjsNCgltc28taGVhZGVyLW1hcmdpbjouNWluOw0KCW1zby1mb290ZXItbWFyZ2lu
Oi41aW47DQoJbXNvLXBhcGVyLXNvdXJjZTowO30NCmRpdi5TZWN0aW9uMQ0KCXtwYWdlOlNlY3Rp
b24xO30NCi0tPg0KPC9zdHlsZT4NCjwhLS1baWYgZ3RlIG1zbyAxMF0+DQo8c3R5bGU+DQogLyog
U3R5bGUgRGVmaW5pdGlvbnMgKi8NCiB0YWJsZS5Nc29Ob3JtYWxUYWJsZQ0KCXttc28tc3R5bGUt
bmFtZToiVGFibGUgTm9ybWFsIjsNCgltc28tdHN0eWxlLXJvd2JhbmQtc2l6ZTowOw0KCW1zby10
c3R5bGUtY29sYmFuZC1zaXplOjA7DQoJbXNvLXN0eWxlLW5vc2hvdzp5ZXM7DQoJbXNvLXN0eWxl
LXBhcmVudDoiIjsNCgltc28tcGFkZGluZy1hbHQ6MGluIDUuNHB0IDBpbiA1LjRwdDsNCgltc28t
cGFyYS1tYXJnaW46MGluOw0KCW1zby1wYXJhLW1hcmdpbi1ib3R0b206LjAwMDFwdDsNCgltc28t
cGFnaW5hdGlvbjp3aWRvdy1vcnBoYW47DQoJZm9udC1zaXplOjEwLjBwdDsNCglmb250LWZhbWls
eToiVGltZXMgTmV3IFJvbWFuIjsNCgltc28tYW5zaS1sYW5ndWFnZTojMDQwMDsNCgltc28tZmFy
ZWFzdC1sYW5ndWFnZTojMDQwMDsNCgltc28tYmlkaS1sYW5ndWFnZTojMDQwMDt9DQo8L3N0eWxl
Pg0KPCFbZW5kaWZdLS0+DQo8L2hlYWQ+DQoNCjxib2R5IGxhbmc9RU4tVVMgc3R5bGU9J3RhYi1p
bnRlcnZhbDouNWluJz4NCg0KPGRpdiBjbGFzcz1TZWN0aW9uMT4NCg0KPHAgY2xhc3M9TXNvTm9y
bWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25l
Jz48Yj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxNC4wcHQ7Y29sb3I6YmxhY2snPjE0LjkgJmx0
O21lcmdlIHN0YXRlbWVudCZndDs8bzpwPjwvbzpwPjwvc3Bhbj48L2I+PC9wPg0KDQo8cCBjbGFz
cz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3Nw
YWNlOm5vbmUnPjxiPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjE0LjBwdDtjb2xvcjpibGFjayc+
RnVuY3Rpb248bzpwPjwvbzpwPjwvc3Bhbj48L2I+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwg
c3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxz
cGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+Q29uZGl0aW9uYWxseSB1
cGRhdGUgcm93cyBvZiBhIHRhYmxlLCBvcg0KaW5zZXJ0IG5ldyByb3dzIGludG8gYSB0YWJsZSwg
b3IgYm90aC48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHls
ZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PGI+PHNw
YW4NCnN0eWxlPSdmb250LXNpemU6MTQuMHB0O2NvbG9yOmJsYWNrJz5Gb3JtYXQ8bzpwPjwvbzpw
Pjwvc3Bhbj48L2I+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQt
Z3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1z
aXplOjkuMHB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGktZm9udC1mYW1pbHk6Q291cmll
cjsNCmNvbG9yOmJsYWNrJz4mbHQ7PHNwYW4gY2xhc3M9R3JhbUU+bWVyZ2U8L3NwYW4+IHN0YXRl
bWVudCZndDsgOjo9PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwg
c3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxz
cGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGkt
Zm9udC1mYW1pbHk6Q291cmllcjsNCmNvbG9yOmJsYWNrJz5NRVJHRSBJTlRPICZsdDt0YXJnZXQg
dGFibGUmZ3Q7IDxzcGFuIGNsYXNzPUdyYW1FPlsgWzwvc3Bhbj4gQVMgXQ0KJmx0O21lcmdlIGNv
cnJlbGF0aW9uIG5hbWUmZ3Q7IF08bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1z
b05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6
bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6Q291cmllcjtt
c28tYmlkaS1mb250LWZhbWlseTpDb3VyaWVyOw0KY29sb3I6YmxhY2snPlVTSU5HICZsdDt0YWJs
ZSByZWZlcmVuY2UmZ3Q7PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3Jt
YWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUn
PjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJp
ZGktZm9udC1mYW1pbHk6Q291cmllcjsNCmNvbG9yOmJsYWNrJz5PTiAmbHQ7c2VhcmNoIGNvbmRp
dGlvbiZndDsgJmx0O21lcmdlIG9wZXJhdGlvbiBzcGVjaWZpY2F0aW9uJmd0OzxvOnA+PC9vOnA+
PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQt
YWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5
LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7DQpj
b2xvcjpibGFjayc+Jmx0OzxzcGFuIGNsYXNzPUdyYW1FPm1lcmdlPC9zcGFuPiBjb3JyZWxhdGlv
biBuYW1lJmd0OyA6Oj0NCiZsdDtjb3JyZWxhdGlvbiBuYW1lJmd0OzxvOnA+PC9vOnA+PC9zcGFu
PjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246
bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtm
b250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7DQpjb2xvcjpi
bGFjayc+Jmx0OzxzcGFuIGNsYXNzPUdyYW1FPm1lcmdlPC9zcGFuPiBvcGVyYXRpb24gc3BlY2lm
aWNhdGlvbiZndDsgOjo9DQombHQ7bWVyZ2Ugd2hlbiBjbGF1c2UmZ3Q7Li4uPG86cD48L286cD48
L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1h
bGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjku
MHB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGktZm9udC1mYW1pbHk6Q291cmllcjsNCmNv
bG9yOmJsYWNrJz4mbHQ7bWVyZ2Ugd2hlbiBjbGF1c2U8c3BhbiBjbGFzcz1HcmFtRT4mZ3Q7IDo8
L3NwYW4+Oj08bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHls
ZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4N
CnN0eWxlPSdmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6Q291cmllcjttc28tYmlkaS1mb250
LWZhbWlseTpDb3VyaWVyOw0KY29sb3I6YmxhY2snPiZsdDttZXJnZSB3aGVuIG1hdGNoZWQgY2xh
dXNlJmd0OzxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxl
PSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0K
c3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQt
ZmFtaWx5OkNvdXJpZXI7DQpjb2xvcjpibGFjayc+fCAmbHQ7bWVyZ2Ugd2hlbiBub3QgbWF0Y2hl
ZCBjbGF1c2UmZ3Q7PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwg
c3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxz
cGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGkt
Zm9udC1mYW1pbHk6Q291cmllcjsNCmNvbG9yOmJsYWNrJz4mbHQ7bWVyZ2Ugd2hlbiBtYXRjaGVk
IGNsYXVzZTxzcGFuIGNsYXNzPUdyYW1FPiZndDsgOjwvc3Bhbj46PTxvOnA+PC9vOnA+PC9zcGFu
PjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246
bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtm
b250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7DQpjb2xvcjpi
bGFjayc+V0hFTiBNQVRDSEVEIFRIRU4gJmx0O21lcmdlIHVwZGF0ZSBzcGVjaWZpY2F0aW9uJmd0
OzxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28t
bGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9
J2ZvbnQtc2l6ZTo5LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5
OkNvdXJpZXI7DQpjb2xvcjpibGFjayc+Jmx0OzxzcGFuIGNsYXNzPUdyYW1FPm1lcmdlPC9zcGFu
PiB3aGVuIG5vdCBtYXRjaGVkIGNsYXVzZSZndDsgOjo9PG86cD48L286cD48L3NwYW4+PC9wPg0K
DQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3Rl
eHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2ZvbnQtZmFt
aWx5OkNvdXJpZXI7bXNvLWJpZGktZm9udC1mYW1pbHk6Q291cmllcjsNCmNvbG9yOmJsYWNrJz5X
SEVOIE5PVCBNQVRDSEVEIFRIRU4gJmx0O21lcmdlIGluc2VydCBzcGVjaWZpY2F0aW9uJmd0Ozxv
OnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5
b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2Zv
bnQtc2l6ZTo5LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNv
dXJpZXI7DQpjb2xvcjpibGFjayc+Jmx0OzxzcGFuIGNsYXNzPUdyYW1FPm1lcmdlPC9zcGFuPiB1
cGRhdGUgc3BlY2lmaWNhdGlvbiZndDsgOjo9DQpVUERBVEUgU0VUICZsdDtzZXQgY2xhdXNlIGxp
c3QmZ3Q7PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9
J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpz
dHlsZT0nZm9udC1zaXplOjkuMHB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGktZm9udC1m
YW1pbHk6Q291cmllcjsNCmNvbG9yOmJsYWNrJz4mbHQ7PHNwYW4gY2xhc3M9R3JhbUU+bWVyZ2U8
L3NwYW4+IGluc2VydCBzcGVjaWZpY2F0aW9uJmd0OyA6Oj08bzpwPjwvbzpwPjwvc3Bhbj48L3A+
DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7
dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6OS4wcHQ7Zm9udC1m
YW1pbHk6Q291cmllcjttc28tYmlkaS1mb250LWZhbWlseTpDb3VyaWVyOw0KY29sb3I6YmxhY2sn
PklOU0VSVCA8c3BhbiBjbGFzcz1HcmFtRT5bICZsdDs8L3NwYW4+bGVmdCA8c3BhbiBjbGFzcz1T
cGVsbEU+cGFyZW48L3NwYW4+Jmd0Ow0KJmx0O2luc2VydCBjb2x1bW4gbGlzdCZndDsgJmx0O3Jp
Z2h0IDxzcGFuIGNsYXNzPVNwZWxsRT5wYXJlbjwvc3Bhbj4mZ3Q7IF08bzpwPjwvbzpwPjwvc3Bh
bj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWdu
Om5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCmNsYXNzPUdyYW1FPjxzcGFuIHN0eWxl
PSdmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6Q291cmllcjttc28tYmlkaS1mb250LWZhbWls
eToNCkNvdXJpZXI7Y29sb3I6YmxhY2snPlsgJmx0Ozwvc3Bhbj48L3NwYW4+PHNwYW4gc3R5bGU9
J2ZvbnQtc2l6ZTo5LjBwdDsNCmZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGktZm9udC1mYW1p
bHk6Q291cmllcjtjb2xvcjpibGFjayc+b3ZlcnJpZGUNCmNsYXVzZSZndDsgXTxvOnA+PC9vOnA+
PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQt
YWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5
LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7DQpj
b2xvcjpibGFjayc+VkFMVUVTICZsdDttZXJnZSBpbnNlcnQgdmFsdWUgbGlzdCZndDs8bzpwPjwv
bzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1n
cmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNp
emU6OS4wcHQ7Zm9udC1mYW1pbHk6Q291cmllcjttc28tYmlkaS1mb250LWZhbWlseTpDb3VyaWVy
Ow0KY29sb3I6YmxhY2snPiZsdDs8c3BhbiBjbGFzcz1HcmFtRT5tZXJnZTwvc3Bhbj4gaW5zZXJ0
IHZhbHVlIGxpc3QmZ3Q7IDo6PTxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNv
Tm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpu
b25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21z
by1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7DQpjb2xvcjpibGFjayc+Jmx0OzxzcGFuIGNsYXNz
PUdyYW1FPmxlZnQ8L3NwYW4+IDxzcGFuIGNsYXNzPVNwZWxsRT5wYXJlbjwvc3Bhbj4mZ3Q7PG86
cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlv
dXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9u
dC1zaXplOjkuMHB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGktZm9udC1mYW1pbHk6Q291
cmllcjsNCmNvbG9yOmJsYWNrJz4mbHQ7PHNwYW4gY2xhc3M9R3JhbUU+bWVyZ2U8L3NwYW4+IGlu
c2VydCB2YWx1ZSBlbGVtZW50Jmd0OyBbIHsNCiZsdDtjb21tYSZndDsgJmx0O21lcmdlIGluc2Vy
dCB2YWx1ZSBlbGVtZW50Jmd0OyB9Li4uIF08bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNs
YXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRv
c3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6Q291
cmllcjttc28tYmlkaS1mb250LWZhbWlseTpDb3VyaWVyOw0KY29sb3I6YmxhY2snPiZsdDs8c3Bh
biBjbGFzcz1HcmFtRT5yaWdodDwvc3Bhbj4gPHNwYW4gY2xhc3M9U3BlbGxFPnBhcmVuPC9zcGFu
PiZndDs8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0n
bXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0
eWxlPSdmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6Q291cmllcjttc28tYmlkaS1mb250LWZh
bWlseTpDb3VyaWVyOw0KY29sb3I6YmxhY2snPiZsdDs8c3BhbiBjbGFzcz1HcmFtRT5tZXJnZTwv
c3Bhbj4gaW5zZXJ0IHZhbHVlIGVsZW1lbnQmZ3Q7IDo6PTxvOnA+PC9vOnA+PC9zcGFuPjwvcD4N
Cg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0
ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtmb250LWZh
bWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7DQpjb2xvcjpibGFjayc+
Jmx0OzxzcGFuIGNsYXNzPUdyYW1FPnZhbHVlPC9zcGFuPiBleHByZXNzaW9uJmd0OzxvOnA+PC9v
OnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdy
aWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6
ZTo5LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7
DQpjb2xvcjpibGFjayc+fCAmbHQ7Y29udGV4dHVhbGx5IHR5cGVkIHZhbHVlIHNwZWNpZmljYXRp
b24mZ3Q7PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9
J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxiPjxzcGFu
DQpzdHlsZT0nZm9udC1zaXplOjE0LjBwdDtjb2xvcjpibGFjayc+U3ludGF4IFJ1bGVzPG86cD48
L286cD48L3NwYW4+PC9iPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5
b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2Zv
bnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjEpIE5laXRoZXIgJmx0O21lcmdlIHdoZW4gbWF0
Y2hlZA0KY2xhdXNlJmd0OyBub3IgJmx0O21lcmdlIHdoZW4gbm90IG1hdGNoZWQgY2xhdXNlJmd0
OyBzaGFsbCBiZSBzcGVjaWZpZWQgbW9yZQ0KdGhhbiBvbmNlLjxvOnA+PC9vOnA+PC9zcGFuPjwv
cD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9u
ZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29s
b3I6YmxhY2snPjIpIExldCA8aT5UTiA8L2k+YmUgdGhlICZsdDt0YWJsZSBuYW1lJmd0Ow0KY29u
dGFpbmVkIGluICZsdDt0YXJnZXQgdGFibGUmZ3Q7IGFuZCBsZXQgPGk+VCA8L2k+YmUgdGhlIHRh
YmxlIGlkZW50aWZpZWQgYnkgPGk+VE48L2k+Lg0KPGk+VCA8L2k+aXMgdGhlIDxpPnN1YmplY3Qg
dGFibGUgPC9pPm9mIHRoZSAmbHQ7bWVyZ2Ugc3RhdGVtZW50Jmd0Oy48bzpwPjwvbzpwPjwvc3Bh
bj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWdu
Om5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0
O2NvbG9yOmJsYWNrJz4zKSA8aT5UIDwvaT5zaGFsbCBiZSA8c3BhbiBjbGFzcz1TcGVsbEU+aW5z
ZXJ0YWJsZTwvc3Bhbj4taW50by48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1z
b05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6
bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz40KSA8aT5U
IDwvaT5zaGFsbCBub3QgYmUgYW4gb2xkIHRyYW5zaXRpb24NCnRhYmxlIG9yIGEgbmV3IHRyYW5z
aXRpb24gdGFibGUuPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwg
c3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxi
PjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjEwLjBwdDtjb2xvcjpibGFjayc+RGF0YSBtYW5pcHVs
YXRpb24gODA1PG86cD48L286cD48L3NwYW4+PC9iPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFs
IHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48
Yj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMC4wcHQ7Y29sb3I6YmxhY2snPldEIElTTy9JRUMg
OTA3NS0yOjIwMDcgKEUpPG86cD48L286cD48L3NwYW4+PC9iPjwvcD4NCg0KPHAgY2xhc3M9TXNv
Tm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpu
b25lJz48Yj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMC4wcHQ7Y29sb3I6YmxhY2snPjE0Ljkg
Jmx0O21lcmdlIHN0YXRlbWVudCZndDs8bzpwPjwvbzpwPjwvc3Bhbj48L2I+PC9wPg0KDQo8cCBj
bGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0
b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+
NSkgRm9yIGVhY2ggbGVhZiBnZW5lcmFsbHkgdW5kZXJseWluZw0KdGFibGUgb2YgPGk+VCA8L2k+
d2hvc2UgZGVzY3JpcHRvciBpbmNsdWRlcyBhIHVzZXItZGVmaW5lZCB0eXBlIG5hbWUgPGk+VURU
TjwvaT4sDQp0aGUgZGF0YSB0eXBlIGRlc2NyaXB0b3Igb2YgdGhlIHVzZXItZGVmaW5lZCB0eXBl
IDxpPlVEVCA8L2k+aWRlbnRpZmllZCBieSA8aT5VRFRODQo8L2k+c2hhbGwgaW5kaWNhdGUgdGhh
dCA8aT5VRFQgPC9pPmlzIDxzcGFuIGNsYXNzPVNwZWxsRT5pbnN0YW50aWFibGU8L3NwYW4+Ljxv
OnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5
b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2Zv
bnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjYpIElmIDxpPlQgPC9pPmlzIGEgdmlldywgdGhl
biAmbHQ7dGFyZ2V0DQp0YWJsZSZndDsgaXMgZWZmZWN0aXZlbHkgcmVwbGFjZWQgYnk6PG86cD48
L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQt
Z3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1z
aXplOjkuMHB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGktZm9udC1mYW1pbHk6Q291cmll
cjsNCmNvbG9yOmJsYWNrJz5PTkxZIDxzcGFuIGNsYXNzPUdyYW1FPiggPGk+VE48L2k+PC9zcGFu
PjxpPiA8L2k+KTxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0
eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bh
bg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjcpIENhc2U6PG86cD48L286
cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3Jp
ZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXpl
OjExLjBwdDtjb2xvcjpibGFjayc+YSkgSWYgJmx0O21lcmdlIGNvcnJlbGF0aW9uIG5hbWUmZ3Q7
IGlzDQpzcGVjaWZpZWQsIHRoZW4gbGV0IDxpPkNOIDwvaT5iZSB0aGUgJmx0O2NvcnJlbGF0aW9u
IG5hbWUmZ3Q7IGNvbnRhaW5lZCBpbg0KJmx0O21lcmdlIGNvcnJlbGF0aW9uIG5hbWUmZ3Q7Ljxv
OnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5
b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2Zv
bnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPmIpIE90aGVyd2lzZSwgbGV0IDxpPkNOIDwvaT5i
ZSB0aGUNCiZsdDt0YWJsZSBuYW1lJmd0OyBjb250YWluZWQgaW4gJmx0O3RhcmdldCB0YWJsZSZn
dDsuPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21z
by1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHls
ZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+OCkgVGhlIHNjb3BlIG9mIDxpPkNOIDwv
aT5pcyAmbHQ7c2VhcmNoDQpjb25kaXRpb24mZ3Q7IGFuZCAmbHQ7c2V0IGNsYXVzZSBsaXN0Jmd0
Oy48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNv
LWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxl
PSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz45KSBMZXQgPGk+VFIgPC9pPmJlIHRoZSAm
bHQ7dGFibGUNCnJlZmVyZW5jZSZndDsgaW1tZWRpYXRlbHkgY29udGFpbmVkIGluICZsdDttZXJn
ZSBzdGF0ZW1lbnQmZ3Q7LiA8aT5UUiA8L2k+c2hhbGwNCm5vdCBkaXJlY3RseSBjb250YWluIGEg
Jmx0O2pvaW5lZCB0YWJsZSZndDsuPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1N
c29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNl
Om5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+MTApIFRo
ZSAmbHQ7Y29ycmVsYXRpb24gbmFtZSZndDsgb3INCmV4cG9zZWQgJmx0O3RhYmxlIG5hbWUmZ3Q7
IHRoYXQgaXMgZXhwb3NlZCBieSA8aT5UUiA8L2k+c2hhbGwgbm90IGJlIGVxdWl2YWxlbnQNCnRv
IDxpPkNOPC9pPi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBz
dHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNw
YW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4xMSkgSWYgdGhlICZsdDtp
bnNlcnQgY29sdW1uIGxpc3QmZ3Q7IGlzDQpvbWl0dGVkLCB0aGVuIGFuICZsdDtpbnNlcnQgY29s
dW1uIGxpc3QmZ3Q7IHRoYXQgaWRlbnRpZmllcyBhbGwgY29sdW1ucyBvZiA8aT5UDQo8L2k+aW4g
dGhlIGFzY2VuZGluZyBzZXF1ZW5jZSBvZiB0aGVpciBvcmRpbmFsIHBvc2l0aW9uIHdpdGhpbiA8
aT5UIDwvaT5pcw0KaW1wbGljaXQuPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1N
c29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNl
Om5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+MTIpIENh
c2U6PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21z
by1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHls
ZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+YSkgSWYgPGk+VCA8L2k+aXMgYSA8c3Bh
biBjbGFzcz1TcGVsbEU+cmVmZXJlbmNlYWJsZTwvc3Bhbj4NCnRhYmxlIG9yIGEgdGFibGUgaGF2
aW5nIGFuIGlkZW50aXR5IGNvbHVtbiB3aG9zZSBkZXNjcmlwdG9yIGluY2x1ZGVzIGFuDQppbmRp
Y2F0aW9uIHRoYXQgdmFsdWVzIGFyZSBhbHdheXMgZ2VuZXJhdGVkLCB0aGVuOjxvOnA+PC9vOnA+
PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQt
YWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0KY2xhc3M9U3BlbGxFPjxzcGFu
IHN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5pPC9zcGFuPjwvc3Bhbj48c3Bh
bg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPikgTGV0IDxpPkMgPC9pPmJl
IHRoZSBzZWxmLXJlZmVyZW5jaW5nDQpjb2x1bW4gb3IgaWRlbnRpdHkgY29sdW1uIG9mIDxpPlQ8
L2k+LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdt
c28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5
bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPmlpKSBJZiA8aT5DIDwvaT5pcyBhbiBp
ZGVudGl0eSBjb2x1bW4sIGENCnN5c3RlbS1nZW5lcmF0ZWQgc2VsZi1yZWZlcmVuY2luZyBjb2x1
bW4gb3IgYSBkZXJpdmVkIHNlbGYtcmVmZXJlbmNpbmcgY29sdW1uDQphbmQgPGk+QyA8L2k+aXMg
Y29udGFpbmVkIGluICZsdDtpbnNlcnQgY29sdW1uIGxpc3QmZ3Q7LCB0aGVuICZsdDtvdmVycmlk
ZQ0KY2xhdXNlJmd0OyBzaGFsbCBiZSBzcGVjaWZpZWQ7IG90aGVyd2lzZSwgJmx0O292ZXJyaWRl
IGNsYXVzZSZndDsgc2hhbGwgbm90IGJlDQpzcGVjaWZpZWQuPG86cD48L286cD48L3NwYW4+PC9w
Pg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25l
O3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpjbGFzcz1HcmFtRT48c3BhbiBzdHlsZT0nZm9u
dC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+Yjwvc3Bhbj48L3NwYW4+PHNwYW4NCnN0eWxlPSdm
b250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4pIE90aGVyd2lzZSwgJmx0O292ZXJyaWRlIGNs
YXVzZSZndDsgc2hhbGwNCm5vdCBiZSBzcGVjaWZpZWQuPG86cD48L286cD48L3NwYW4+PC9wPg0K
DQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3Rl
eHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpi
bGFjayc+MTMpIFRoZSAmbHQ7c2VhcmNoIGNvbmRpdGlvbiZndDsgc2hhbGwgbm90DQpnZW5lcmFs
bHkgY29udGFpbiBhICZsdDtyb3V0aW5lIGludm9jYXRpb24mZ3Q7IHdob3NlIHN1YmplY3Qgcm91
dGluZSBpcyBhIDxzcGFuDQpjbGFzcz1TcGVsbEU+U1FMaW52b2tlZDwvc3Bhbj4gcm91dGluZSB0
aGF0IHBvc3NpYmx5IG1vZGlmaWVzIFNRTC1kYXRhLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0K
PHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0
LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6Ymxh
Y2snPjE0KSBFYWNoIGNvbHVtbiBpZGVudGlmaWVkIGJ5IGFuDQombHQ7b2JqZWN0IGNvbHVtbiZn
dDsgaW4gdGhlICZsdDtzZXQgY2xhdXNlIGxpc3QmZ3Q7IGlzIGFuIDxpPnVwZGF0ZSBvYmplY3QN
CmNvbHVtbjwvaT4uIEVhY2ggY29sdW1uIGlkZW50aWZpZWQgYnkgYSAmbHQ7Y29sdW1uIG5hbWUm
Z3Q7IGluIHRoZSBpbXBsaWNpdCBvcg0KZXhwbGljaXQgJmx0O2luc2VydCBjb2x1bW4gbGlzdCZn
dDsgaXMgYW4gPGk+aW5zZXJ0IG9iamVjdCBjb2x1bW48L2k+LiBFYWNoDQp1cGRhdGUgb2JqZWN0
IGNvbHVtbiBhbmQgZWFjaCBpbnNlcnQgb2JqZWN0IGNvbHVtbiBpcyBhbiA8aT5vYmplY3QgY29s
dW1uPC9pPi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHls
ZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4N
CnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4xNSkgRXZlcnkgb2JqZWN0IGNv
bHVtbiBzaGFsbCBpZGVudGlmeSBhbg0KdXBkYXRhYmxlIGNvbHVtbiBvZiA8aT5UPC9pPi48bzpw
PjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91
dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250
LXNpemU6OS4wcHQ7Y29sb3I6YmxhY2snPk5PVEUgMzc5IJcgPHNwYW4gY2xhc3M9R3JhbUU+VGhl
PC9zcGFuPg0Kbm90aW9uIG9mIHVwZGF0YWJsZSBjb2x1bW5zIG9mIGJhc2UgdGFibGVzIGlzIGRl
ZmluZWQgaW4gPC9zcGFuPjxzcGFuDQpjbGFzcz1TcGVsbEU+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6
ZTo5LjBwdDtjb2xvcjojMDAwMDcwJz5TdWJjbGF1c2U8L3NwYW4+PC9zcGFuPjxzcGFuDQpzdHls
ZT0nZm9udC1zaXplOjkuMHB0O2NvbG9yOiMwMDAwNzAnPiA0LjE0LCCTVGFibGVzlDwvc3Bhbj48
c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtjb2xvcjpibGFjayc+LiBUaGUgbm90aW9uIG9m
IHVwZGF0YWJsZSBjb2x1bW5zIG9mIHZpZXdlZA0KdGFibGVzIGlzIGRlZmluZWQgaW4gPC9zcGFu
PjxzcGFuIGNsYXNzPVNwZWxsRT48c3BhbiBzdHlsZT0nZm9udC1zaXplOjkuMHB0Ow0KY29sb3I6
IzAwMDA3MCc+U3ViY2xhdXNlPC9zcGFuPjwvc3Bhbj48c3BhbiBzdHlsZT0nZm9udC1zaXplOjku
MHB0O2NvbG9yOiMwMDAwNzAnPg0KMTEuMjIsIJMmbHQ7dmlldyBkZWZpbml0aW9uJmd0O5Q8L3Nw
YW4+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtjb2xvcjpibGFjayc+LjxvOnA+PC9vOnA+
PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQt
YWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6YmxhY2snPjE2KSBObyAmbHQ7Y29sdW1uIG5hbWUmZ3Q7IG9mIDxpPlQgPC9p
PnNoYWxsDQpiZSBpZGVudGlmaWVkIG1vcmUgdGhhbiBvbmNlIGluIDxzcGFuIGNsYXNzPVNwZWxs
RT5pbjwvc3Bhbj4gYW4gJmx0O2luc2VydA0KY29sdW1uIGxpc3QmZ3Q7LjxvOnA+PC9vOnA+PC9z
cGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxp
Z246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4w
cHQ7Y29sb3I6YmxhY2snPjE3KSBMZXQgPGk+TkkgPC9pPmJlIHRoZSBudW1iZXIgb2YNCiZsdDtt
ZXJnZSBpbnNlcnQgdmFsdWUgZWxlbWVudCZndDtzIGNvbnRhaW5lZCBpbiAmbHQ7bWVyZ2UgaW5z
ZXJ0IHZhbHVlDQpsaXN0Jmd0Oy4gTGV0IDxpPkVYUDwvaT48L3NwYW4+PHNwYW4gc3R5bGU9J2Zv
bnQtc2l6ZTo5LjBwdDtjb2xvcjpibGFjayc+MTwvc3Bhbj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6
ZToxMS4wcHQ7Y29sb3I6YmxhY2snPiwgPGk+RVhQPC9pPjwvc3Bhbj48c3BhbiBzdHlsZT0nZm9u
dC1zaXplOg0KOS4wcHQ7Y29sb3I6YmxhY2snPjI8L3NwYW4+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6
ZToxMS4wcHQ7Y29sb3I6YmxhY2snPiwgPHNwYW4NCmNsYXNzPUdyYW1FPi4uLiAsPC9zcGFuPiA8
aT5FWFA8L2k+PC9zcGFuPjxpPjxzcGFuIHN0eWxlPSdmb250LXNpemU6OS4wcHQ7DQpjb2xvcjpi
bGFjayc+TkkgPC9zcGFuPjwvaT48c3BhbiBzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpi
bGFjayc+YmUgdGhvc2UNCiZsdDttZXJnZSBpbnNlcnQgdmFsdWUgZWxlbWVudCZndDtzLjxvOnA+
PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0
LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQt
c2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjE4KSBUaGUgbnVtYmVyIG9mICZsdDtjb2x1bW4gbmFt
ZSZndDtzIGluDQp0aGUgJmx0O2luc2VydCBjb2x1bW4gbGlzdCZndDsgc2hhbGwgYmUgZXF1YWwg
dG8gPGk+Tkk8L2k+LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFs
IHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48
c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjE5KSBUaGUgZGVjbGFy
ZWQgdHlwZSBvZiBldmVyeQ0KJmx0O2NvbnRleHR1YWxseSB0eXBlZCB2YWx1ZSBzcGVjaWZpY2F0
aW9uJmd0OyA8aT5DVlMgPC9pPmluIGEgJmx0O21lcmdlIGluc2VydA0KdmFsdWUgbGlzdCZndDsg
aXMgdGhlIGRhdGEgdHlwZSA8aT5EVCA8L2k+aW5kaWNhdGVkIGluIHRoZSBjb2x1bW4gZGVzY3Jp
cHRvcg0KZm9yIHRoZSA8c3BhbiBjbGFzcz1TcGVsbEU+cG9zaXRpb25hbGx5PC9zcGFuPiBjb3Jy
ZXNwb25kaW5nIGNvbHVtbiBpbiB0aGUNCmV4cGxpY2l0IG9yIGltcGxpY2l0ICZsdDtpbnNlcnQg
Y29sdW1uIGxpc3QmZ3Q7LiBJZiA8aT5DVlMgPC9pPmlzIGFuICZsdDtlbXB0eQ0Kc3BlY2lmaWNh
dGlvbiZndDsgdGhhdCBzcGVjaWZpZXMgQVJSQVksIHRoZW4gPGk+RFQgPC9pPnNoYWxsIGJlIGFu
IGFycmF5IHR5cGUuDQpJZiA8aT5DVlMgPC9pPmlzIGFuICZsdDtlbXB0eSBzcGVjaWZpY2F0aW9u
Jmd0OyB0aGF0IHNwZWNpZmllcyBNVUxUSVNFVCwgdGhlbiA8aT5EVA0KPC9pPnNoYWxsIGJlIGEg
PHNwYW4gY2xhc3M9U3BlbGxFPm11bHRpc2V0PC9zcGFuPiB0eXBlLjxvOnA+PC9vOnA+PC9zcGFu
PjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246
bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7
Y29sb3I6YmxhY2snPjIwKSBFdmVyeSAmbHQ7bWVyZ2UgaW5zZXJ0IHZhbHVlDQplbGVtZW50Jmd0
OyB3aG9zZSA8c3BhbiBjbGFzcz1TcGVsbEU+cG9zaXRpb25hbGx5PC9zcGFuPiBjb3JyZXNwb25k
aW5nDQombHQ7Y29sdW1uIG5hbWUmZ3Q7IGluICZsdDtpbnNlcnQgY29sdW1uIGxpc3QmZ3Q7IHJl
ZmVyZW5jZXMgYSBjb2x1bW4gb2Ygd2hpY2gNCnNvbWUgdW5kZXJseWluZyBjb2x1bW4gaXMgYSBn
ZW5lcmF0ZWQgY29sdW1uIHNoYWxsIGJlIGEgJmx0O2RlZmF1bHQgc3BlY2lmaWNhdGlvbiZndDsu
PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1s
YXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0n
Zm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+MjEpIEZvciAxIChvbmUpIDwvc3Bhbj48c3Bh
bg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6U3ltYm9sO21zby1iaWRpLWZv
bnQtZmFtaWx5OlN5bWJvbDsNCmNvbG9yOmJsYWNrJz4mIzg4MDQ7IDwvc3Bhbj48c3BhbiBjbGFz
cz1TcGVsbEU+PGk+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7DQpjb2xvcjpibGFjayc+
aTwvc3Bhbj48L2k+PC9zcGFuPjxpPjxzcGFuIHN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9y
OmJsYWNrJz4NCk5JPC9zcGFuPjwvaT48c3BhbiBzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xv
cjpibGFjayc+LCB0aGUgU3ludGF4IFJ1bGVzIG9mIDwvc3Bhbj48c3Bhbg0KY2xhc3M9U3BlbGxF
PjxzcGFuIHN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOiMwMDAwNzAnPlN1YmNsYXVzZTwv
c3Bhbj48L3NwYW4+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOiMwMDAwNzAn
PiA5LjIsIJNTdG9yZSBhc3NpZ25tZW50lDwvc3Bhbj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6YmxhY2snPiwgYXBwbHkgdG8gdGhlIGNvbHVtbiBvZiB0YWJsZSA8aT5UIDwv
aT5pZGVudGlmaWVkDQpieSB0aGUgPHNwYW4gY2xhc3M9U3BlbGxFPjxpPmk8L2k+LXRoPC9zcGFu
PiAmbHQ7Y29sdW1uIG5hbWUmZ3Q7IGluIHRoZQ0KJmx0O2luc2VydCBjb2x1bW4gbGlzdCZndDsg
YW5kIDxzcGFuIGNsYXNzPVNwZWxsRT48aT5FWFA8L2k+PGk+PHNwYW4NCnN0eWxlPSdmb250LXNp
emU6OS4wcHQnPmk8L3NwYW4+PC9pPjwvc3Bhbj48L3NwYW4+PGk+PHNwYW4gc3R5bGU9J2ZvbnQt
c2l6ZToNCjkuMHB0O2NvbG9yOmJsYWNrJz4gPC9zcGFuPjwvaT48c3BhbiBzdHlsZT0nZm9udC1z
aXplOjExLjBwdDtjb2xvcjpibGFjayc+YXMgPGk+VEFSR0VUDQo8L2k+YW5kIDxpPlZBTFVFPC9p
PiwgcmVzcGVjdGl2ZWx5LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9y
bWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25l
Jz48Yj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxNC4wcHQ7Y29sb3I6YmxhY2snPkFjY2VzcyBS
dWxlczxvOnA+PC9vOnA+PC9zcGFuPjwvYj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHls
ZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4N
CnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4xKSBDYXNlOjxvOnA+PC9vOnA+
PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQt
YWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6YmxhY2snPmEpIElmICZsdDttZXJnZSBzdGF0ZW1lbnQmZ3Q7IGlzDQpjb250
YWluZWQsIHdpdGhvdXQgYW4gaW50ZXJ2ZW5pbmcgJmx0O1NRTCByb3V0aW5lIHNwZWMmZ3Q7IHRo
YXQgc3BlY2lmaWVzIFNRTCBTRUNVUklUWQ0KSU5WT0tFUiwgaW4gYW4gJmx0O1NRTCBzY2hlbWEg
c3RhdGVtZW50Jmd0OywgdGhlbiBsZXQgPGk+QSA8L2k+YmUgdGhlDQombHQ7YXV0aG9yaXphdGlv
biBpZGVudGlmaWVyJmd0OyB0aGF0IG93bnMgdGhhdCBzY2hlbWEuPG86cD48L286cD48L3NwYW4+
PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpu
b25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpjbGFzcz1TcGVsbEU+PHNwYW4gc3R5bGU9
J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPmk8L3NwYW4+PC9zcGFuPjxzcGFuDQpzdHls
ZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+KSBUaGUgYXBwbGljYWJsZSBwcml2aWxl
Z2VzIGZvciA8aT5BIDwvaT5zaGFsbA0KaW5jbHVkZSBVUERBVEUgZm9yIGVhY2ggdXBkYXRlIG9i
amVjdCBjb2x1bW4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwg
c3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxz
cGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+aWkpIFRoZSBhcHBsaWNh
YmxlIHByaXZpbGVnZXMgZm9yIDxpPkEgPC9pPnNoYWxsDQppbmNsdWRlIElOU0VSVCBmb3IgZWFj
aCBpbnNlcnQgb2JqZWN0IGNvbHVtbi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNz
PU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3Bh
Y2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5paWkp
IElmICZsdDt0YXJnZXQgdGFibGUmZ3Q7IGltbWVkaWF0ZWx5DQpjb250YWlucyBPTkxZLCB0aGVu
IHRoZSBhcHBsaWNhYmxlIHByaXZpbGVnZXMgZm9yIDxpPkEgPC9pPnNoYWxsIGluY2x1ZGUgU0VM
RUNUDQpXSVRIIEhJRVJBUkNIWSBPUFRJT04gb24gYXQgbGVhc3Qgb25lIDxzcGFuIGNsYXNzPVNw
ZWxsRT5zdXBlcnRhYmxlPC9zcGFuPiBvZiA8aT5UPC9pPi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+
DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7
dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9y
OmJsYWNrJz5iKSBPdGhlcndpc2UsPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1N
c29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNl
Om5vbmUnPjxzcGFuDQpjbGFzcz1TcGVsbEU+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7
Y29sb3I6YmxhY2snPmk8L3NwYW4+PC9zcGFuPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBw
dDtjb2xvcjpibGFjayc+KSBUaGUgY3VycmVudCBwcml2aWxlZ2VzIHNoYWxsIGluY2x1ZGUNClVQ
REFURSBmb3IgZWFjaCB1cGRhdGUgb2JqZWN0IGNvbHVtbi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+
DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7
dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9y
OmJsYWNrJz5paSkgVGhlIGN1cnJlbnQgcHJpdmlsZWdlcyBzaGFsbCBpbmNsdWRlDQpJTlNFUlQg
Zm9yIGVhY2ggaW5zZXJ0IG9iamVjdCBjb2x1bW4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8
cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQt
YXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFj
ayc+aWlpKSBJZiAmbHQ7dGFyZ2V0IHRhYmxlJmd0OyBpbW1lZGlhdGVseQ0KY29udGFpbnMgT05M
WSwgdGhlbiB0aGUgY3VycmVudCBwcml2aWxlZ2VzIHNoYWxsIGluY2x1ZGUgU0VMRUNUIFdJVEgg
SElFUkFSQ0hZDQpPUFRJT04gb24gYXQgbGVhc3Qgb25lIDxzcGFuIGNsYXNzPVNwZWxsRT5zdXBl
cnRhYmxlPC9zcGFuPiBvZiA8aT5UPC9pPi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNs
YXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRv
c3BhY2U6bm9uZSc+PGI+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTQuMHB0O2NvbG9yOmJsYWNr
Jz5HZW5lcmFsIFJ1bGVzPG86cD48L286cD48L3NwYW4+PC9iPjwvcD4NCg0KPHAgY2xhc3M9TXNv
Tm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpu
b25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjEpIElmIHRo
ZSBhY2Nlc3MgbW9kZSBvZiB0aGUgY3VycmVudA0KU1FMLXRyYW5zYWN0aW9uIG9yIHRoZSBhY2Nl
c3MgbW9kZSBvZiB0aGUgYnJhbmNoIG9mIHRoZSBjdXJyZW50IDxzcGFuDQpjbGFzcz1TcGVsbEU+
U1FMdHJhbnNhY3Rpb248L3NwYW4+IGF0IHRoZSBjdXJyZW50IFNRTC1jb25uZWN0aW9uIGlzIHJl
YWQtb25seSwNCmFuZCA8aT5UIDwvaT5pcyBub3QgYSB0ZW1wb3JhcnkgdGFibGUsIHRoZW4gYW4g
ZXhjZXB0aW9uIGNvbmRpdGlvbiBpcyByYWlzZWQ6IDxpPmludmFsaWQNCnRyYW5zYWN0aW9uIHN0
YXRlIJcgcmVhZC1vbmx5IFNRTC10cmFuc2FjdGlvbjwvaT4uPG86cD48L286cD48L3NwYW4+PC9w
Pg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25l
O3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xv
cjpibGFjayc+MikgSWYgdGhlcmUgaXMgYW55IHNlbnNpdGl2ZSBjdXJzb3IgPGk+Q1IgPC9pPnRo
YXQNCmlzIGN1cnJlbnRseSBvcGVuIGluIHRoZSBTUUwtdHJhbnNhY3Rpb24gaW4gd2hpY2ggdGhp
cyBTUUwtc3RhdGVtZW50IGlzIGJlaW5nDQpleGVjdXRlZCwgdGhlbjxvOnA+PC9vOnA+PC9zcGFu
PjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246
bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7
Y29sb3I6YmxhY2snPkNhc2U6PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29O
b3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5v
bmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+YSkgSWYgPGk+
Q1IgPC9pPmhhcyBub3QgYmVlbiBoZWxkIGludG8gYQ0Kc3Vic2VxdWVudCBTUUwtdHJhbnNhY3Rp
b24sIHRoZW4gZWl0aGVyIHRoZSBjaGFuZ2UgcmVzdWx0aW5nIGZyb20gdGhlIHN1Y2Nlc3NmdWwN
CmV4ZWN1dGlvbiBvZiB0aGlzIHN0YXRlbWVudCBzaGFsbCBiZSBtYWRlIHZpc2libGUgdG8gPGk+
Q1IgPC9pPm9yIGFuIGV4Y2VwdGlvbg0KY29uZGl0aW9uIGlzIHJhaXNlZDo8bzpwPjwvbzpwPjwv
c3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFs
aWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCmNsYXNzPUdyYW1FPjxpPjxzcGFu
IHN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5jdXJzb3I8L3NwYW4+PC9pPjwv
c3Bhbj48aT48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPiBzZW5z
aXRpdml0eSBleGNlcHRpb24glyByZXF1ZXN0IGZhaWxlZDwvc3Bhbj48L2k+PHNwYW4NCnN0eWxl
PSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4uPG86cD48L286cD48L3NwYW4+PC9wPg0K
DQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3Rl
eHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpi
bGFjayc+YikgT3RoZXJ3aXNlLCB3aGV0aGVyIHRoZSBjaGFuZ2UgcmVzdWx0aW5nDQpmcm9tIHRo
ZSBzdWNjZXNzZnVsIGV4ZWN1dGlvbiBvZiB0aGlzIFNRTC1zdGF0ZW1lbnQgaXMgbWFkZSB2aXNp
YmxlIHRvIDxpPkNSIDwvaT5pcw0KaW1wbGVtZW50YXRpb24tZGVmaW5lZC48bzpwPjwvbzpwPjwv
c3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFs
aWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEu
MHB0O2NvbG9yOmJsYWNrJz4zKSBJZiB0aGVyZSBpcyBhbnkgY3Vyc29yIDxpPkNSIDwvaT50aGF0
DQppcyBjdXJyZW50bHkgPHNwYW4gY2xhc3M9R3JhbUU+b3Blbjwvc3Bhbj4gYW5kIHdob3NlICZs
dDtkZWNsYXJlIGN1cnNvciZndDsNCmNvbnRhaW5lZCBJTlNFTlNJVElWRSwgdGhlbiBlaXRoZXIg
dGhlIGNoYW5nZSByZXN1bHRpbmcgZnJvbSB0aGUgc3VjY2Vzc2Z1bA0KZXhlY3V0aW9uIG9mIHRo
aXMgc3RhdGVtZW50IHNoYWxsIGJlIGludmlzaWJsZSB0byA8aT5DUjwvaT4sIG9yIGFuIGV4Y2Vw
dGlvbg0KY29uZGl0aW9uIGlzIHJhaXNlZDogPGk+Y3Vyc29yIHNlbnNpdGl2aXR5IGV4Y2VwdGlv
biCXIHJlcXVlc3QgZmFpbGVkPC9pPi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNz
PU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3Bh
Y2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz40KSBU
aGUgZXh0ZW50IHRvIHdoaWNoIGFuDQpTUUwtaW1wbGVtZW50YXRpb24gbWF5IGRpc2FsbG93IGlu
ZGVwZW5kZW50IGNoYW5nZXMgdGhhdCBhcmUgbm90IHNpZ25pZmljYW50IGlzDQppbXBsZW1lbnRh
dGlvbi1kZWZpbmVkLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFs
IHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48
c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjUpIExldCA8aT5RVCA8
L2k+YmUgdGhlIHRhYmxlIHNwZWNpZmllZCBieQ0KdGhlICZsdDt0YWJsZSByZWZlcmVuY2UmZ3Q7
LiA8aT5RVCA8L2k+aXMgZWZmZWN0aXZlbHkgZXZhbHVhdGVkIGJlZm9yZSB1cGRhdGUNCm9yIGlu
c2VydGlvbiBvZiBhbnkgcm93cyBpbiA8aT5UPC9pPi4gTGV0IDxpPlEgPC9pPmJlIHRoZSByZXN1
bHQgb2YgZXZhbHVhdGluZyA8aT5RVDwvaT4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBj
bGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0
b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+
NikgRm9yIGVhY2ggJmx0O21lcmdlIHdoZW4gY2xhdXNlJmd0Oyw8bzpwPjwvbzpwPjwvc3Bhbj48
L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5v
bmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2Nv
bG9yOmJsYWNrJz5DYXNlOjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9y
bWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25l
Jz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPmEpIElmICZsdDtt
ZXJnZSB3aGVuIG1hdGNoZWQgY2xhdXNlJmd0OyBpcw0Kc3BlY2lmaWVkLCB0aGVuOjxvOnA+PC9v
OnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdy
aWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0KY2xhc3M9U3BlbGxFPjxz
cGFuIHN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5pPC9zcGFuPjwvc3Bhbj48
c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPikgRm9yIGVhY2ggcm93
IDxpPlIxIDwvaT5vZiA8aT5UPC9pPjo8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNz
PU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3Bh
Y2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4xKSBU
aGUgJmx0O3NlYXJjaCBjb25kaXRpb24mZ3Q7IGlzIGFwcGxpZWQNCnRvIDxpPlIxIDwvaT53aXRo
IHRoZSBleHBvc2VkICZsdDt0YWJsZSBuYW1lJmd0OyBvZiB0aGUgJmx0O3RhcmdldCB0YWJsZSZn
dDsgYm91bmQNCnRvIDxpPlIxIDwvaT5hbmQgdG8gZWFjaCByb3cgb2YgPGk+USA8L2k+d2l0aCB0
aGUgZXhwb3NlZCAmbHQ7Y29ycmVsYXRpb24NCm5hbWUmZ3Q7cyBvciAmbHQ7dGFibGUgb3IgcXVl
cnkgbmFtZSZndDtzIG9mIHRoZSAmbHQ7dGFibGUgcmVmZXJlbmNlJmd0OyBib3VuZA0KdG8gdGhh
dCByb3cuIFRoZSAmbHQ7c2VhcmNoIGNvbmRpdGlvbiZndDsgaXMgZWZmZWN0aXZlbHkgZXZhbHVh
dGVkIGZvciA8aT5SMSA8L2k+YmVmb3JlDQp1cGRhdGluZyBhbnkgcm93IG9mIDxpPlQgPC9pPmFu
ZCBwcmlvciB0byB0aGUgaW52b2NhdGlvbiBvZiBhbnkgJmx0O3RyaWdnZXJlZCBhY3Rpb24mZ3Q7
DQpjYXVzZWQgYnkgdGhlIHVwZGF0ZSBvZiBhbnkgcm93IG9mIDxpPlQgPC9pPmFuZCBiZWZvcmUg
aW5zZXJ0aW5nIGFueSByb3dzIGludG8gPGk+VA0KPC9pPmFuZCBwcmlvciB0byB0aGUgaW52b2Nh
dGlvbiBvZiBhbnkgJmx0O3RyaWdnZXJlZCBhY3Rpb24mZ3Q7IGNhdXNlZCBieSB0aGUNCmluc2Vy
dCBvZiBhbnkgcm93IG9mIDxpPlQ8L2k+LiBFYWNoICZsdDs8c3BhbiBjbGFzcz1TcGVsbEU+c3Vi
cXVlcnk8L3NwYW4+Jmd0Ow0KaW4gdGhlICZsdDtzZWFyY2ggY29uZGl0aW9uJmd0OyBpcyBlZmZl
Y3RpdmVseSBleGVjdXRlZCBmb3IgPGk+UjEgPC9pPmFuZCBmb3INCmVhY2ggcm93IG9mIDxpPlEg
PC9pPmFuZCB0aGUgcmVzdWx0cyB1c2VkIGluIHRoZSBhcHBsaWNhdGlvbiBvZiB0aGUgJmx0O3Nl
YXJjaA0KY29uZGl0aW9uJmd0OyB0byA8aT5SMSA8L2k+YW5kIHRoZSBnaXZlbiByb3cgb2YgPGk+
UTwvaT4uIElmIGFueSBleGVjdXRlZCAmbHQ7PHNwYW4NCmNsYXNzPVNwZWxsRT5zdWJxdWVyeTwv
c3Bhbj4mZ3Q7IGNvbnRhaW5zIGFuIG91dGVyIHJlZmVyZW5jZSB0byBhIGNvbHVtbiBvZiA8aT5U
PC9pPiwNCnRoZW4gdGhlIHJlZmVyZW5jZSBpcyB0byB0aGUgdmFsdWUgb2YgdGhhdCBjb2x1bW4g
aW4gdGhlIGdpdmVuIHJvdyBvZiA8aT5UPC9pPi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxw
IGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1h
dXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNr
Jz5DYXNlOjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxl
PSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0K
c3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPkEpIElmICZsdDt0YXJnZXQgdGFi
bGUmZ3Q7IGNvbnRhaW5zIE9OTFksDQp0aGVuIDxpPlIxIDwvaT5pcyBhIHN1YmplY3Qgcm93IGlm
IDxpPlIxIDwvaT5oYXMgbm8gPHNwYW4gY2xhc3M9U3BlbGxFPnN1YnJvdzwvc3Bhbj4NCmluIGEg
cHJvcGVyIDxzcGFuIGNsYXNzPVNwZWxsRT5zdWJ0YWJsZTwvc3Bhbj4gb2YgPGk+VCA8L2k+YW5k
IHRoZSByZXN1bHQgb2YNCnRoZSAmbHQ7c2VhcmNoIGNvbmRpdGlvbiZndDsgaXMgPGk+VHJ1ZSA8
L2k+Zm9yIHNvbWUgcm93IDxpPlIyIDwvaT5vZiA8aT5RPC9pPi4NCjxpPlIyIDwvaT5pcyB0aGUg
bWF0Y2hpbmcgcm93LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFs
IHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48
c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPkIpIE90aGVyd2lzZSwg
PGk+UjEgPC9pPmlzIGEgc3ViamVjdCByb3cNCmlmIHRoZSByZXN1bHQgb2YgdGhlICZsdDtzZWFy
Y2ggY29uZGl0aW9uJmd0OyBpcyA8aT5UcnVlIDwvaT5mb3Igc29tZSByb3cgPGk+UjINCjwvaT5v
ZiA8aT5RPC9pPi4gPGk+UjIgPC9pPmlzIHRoZSBtYXRjaGluZyByb3cuPG86cD48L286cD48L3Nw
YW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGln
bjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0
O2NvbG9yOmJsYWNrJz5OT1RFIDM4MCCXIJNvdXRlciByZWZlcmVuY2WUIGlzIGRlZmluZWQgaW4g
PC9zcGFuPjxzcGFuDQpjbGFzcz1TcGVsbEU+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtj
b2xvcjojMDAwMDcwJz5TdWJjbGF1c2U8L3NwYW4+PC9zcGFuPjxzcGFuDQpzdHlsZT0nZm9udC1z
aXplOjkuMHB0O2NvbG9yOiMwMDAwNzAnPiA2LjcsIJMmbHQ7Y29sdW1uIHJlZmVyZW5jZSZndDuU
PC9zcGFuPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2NvbG9yOmJsYWNrJz4uPG86cD48
L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQt
Z3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1z
aXplOjExLjBwdDtjb2xvcjpibGFjayc+MikgSWYgPGk+UjEgPC9pPmlzIGEgc3ViamVjdCByb3cs
IHRoZW46PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9
J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpz
dHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+QSkgTGV0IDxpPk0gPC9pPmJlIHRo
ZSBudW1iZXIgb2YgbWF0Y2hpbmcNCnJvd3MgaW4gPGk+USA8L2k+Zm9yIDxpPlIxPC9pPi48bzpw
PjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91
dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250
LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5CKSBJZiA8aT5NIDwvaT5pcyBncmVhdGVyIHRoYW4g
MSAob25lKSwNCnRoZW4gYW4gZXhjZXB0aW9uIGNvbmRpdGlvbiBpcyByYWlzZWQ6IDxpPmNhcmRp
bmFsaXR5IHZpb2xhdGlvbjwvaT4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1N
c29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNl
Om5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+QykgVGhl
ICZsdDt1cGRhdGUgc291cmNlJmd0OyBvZiBlYWNoDQombHQ7c2V0IGNsYXVzZSZndDsgaXMgZWZm
ZWN0aXZlbHkgZXZhbHVhdGVkIGZvciA8aT5SMSA8L2k+YmVmb3JlIGFueSByb3cgb2YgPGk+VA0K
PC9pPmlzIHVwZGF0ZWQgYW5kIHByaW9yIHRvIHRoZSBpbnZvY2F0aW9uIG9mIGFueSAmbHQ7dHJp
Z2dlcmVkIGFjdGlvbiZndDsNCmNhdXNlZCBieSB0aGUgdXBkYXRlIG9mIGFueSByb3cgb2YgPGk+
VDwvaT4uIFRoZSByZXN1bHRpbmcgdmFsdWUgaXMgdGhlIHVwZGF0ZQ0KdmFsdWUuPG86cD48L286
cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3Jp
ZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXpl
OjExLjBwdDtjb2xvcjpibGFjayc+RCkgQSBjYW5kaWRhdGUgbmV3IHJvdyBpcyBjb25zdHJ1Y3Rl
ZCBieQ0KY29weWluZyB0aGUgc3ViamVjdCByb3cgYW5kIHVwZGF0aW5nIGl0IGFzIHNwZWNpZmll
ZCBieSBlYWNoICZsdDtzZXQgY2xhdXNlJmd0Ow0KYnkgYXBwbHlpbmcgdGhlIEdlbmVyYWwgUnVs
ZXMgb2YgPC9zcGFuPjxzcGFuIGNsYXNzPVNwZWxsRT48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6IzAwMDA3MCc+U3ViY2xhdXNlPC9zcGFuPjwvc3Bhbj48c3Bhbg0Kc3R5bGU9
J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6IzAwMDA3MCc+IDE0LjEyLCCTJmx0O3NldCBjbGF1c2Ug
bGlzdCZndDuUPC9zcGFuPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFj
ayc+LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdt
c28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5
bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPmlpKSBJZiA8aT5UIDwvaT5pcyBhIGJh
c2UgdGFibGUsIHRoZW4gZWFjaA0Kc3ViamVjdCByb3cgaXMgYWxzbyBhbiBvYmplY3Qgcm93OyBv
dGhlcndpc2UsIGFuIG9iamVjdCByb3cgaXMgYW55IHJvdyBvZiBhDQpsZWFmIGdlbmVyYWxseSB1
bmRlcmx5aW5nIHRhYmxlIG9mIDxpPlQgPC9pPmZyb20gd2hpY2ggYSBzdWJqZWN0IHJvdyBpcw0K
ZGVyaXZlZC48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHls
ZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4N
CnN0eWxlPSdmb250LXNpemU6OS4wcHQ7Y29sb3I6YmxhY2snPk5PVEUgMzgxIJcgPHNwYW4gY2xh
c3M9R3JhbUU+VGhlPC9zcGFuPg0KZGF0YSB2YWx1ZXMgYWxsb3dhYmxlIGluIHRoZSBvYmplY3Qg
cm93cyBtYXkgYmUgY29uc3RyYWluZWQgYnkgYSBXSVRIIENIRUNLDQpPUFRJT04gY29uc3RyYWlu
dC4gVGhlIGVmZmVjdCBvZiBhIFdJVEggQ0hFQ0sgT1BUSU9OIGNvbnN0cmFpbnQgaXMgZGVmaW5l
ZCBpbg0KdGhlIEdlbmVyYWwgUnVsZXMgb2YgPC9zcGFuPjxzcGFuIGNsYXNzPVNwZWxsRT48c3Bh
biBzdHlsZT0nZm9udC1zaXplOjkuMHB0Ow0KY29sb3I6IzAwMDA3MCc+U3ViY2xhdXNlPC9zcGFu
Pjwvc3Bhbj48c3BhbiBzdHlsZT0nZm9udC1zaXplOjkuMHB0O2NvbG9yOiMwMDAwNzAnPg0KMTQu
MjQsIJNFZmZlY3Qgb2YgcmVwbGFjaW5nIHNvbWUgcm93cyBpbiBhIHZpZXdlZCB0YWJsZZQ8L3Nw
YW4+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6OS4wcHQ7Y29sb3I6YmxhY2snPi48bzpwPjwvbzpw
Pjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlk
LWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6
MTEuMHB0O2NvbG9yOmJsYWNrJz5paWkpIElmIGFueSByb3cgaW4gdGhlIHNldCBvZiBvYmplY3Qg
cm93cw0KaGFzIGJlZW4gbWFya2VkIGZvciBkZWxldGlvbiBieSBhbnkgJmx0O2RlbGV0ZSBzdGF0
ZW1lbnQ6IHBvc2l0aW9uZWQmZ3Q7IHRoYXQNCmlkZW50aWZpZXMgc29tZSBjdXJzb3IgPGk+Q1Ig
PC9pPnRoYXQgaXMgc3RpbGwgb3BlbiBvciB1cGRhdGVkIGJ5IGFueQ0KJmx0O3VwZGF0ZSBzdGF0
ZW1lbnQ6IHBvc2l0aW9uZWQmZ3Q7IHRoYXQgaWRlbnRpZmllcyBzb21lIGN1cnNvciA8aT5DUiA8
L2k+dGhhdA0KaXMgc3RpbGwgb3BlbiwgdGhlbiBhIGNvbXBsZXRpb24gY29uZGl0aW9uIGlzIHJh
aXNlZDogPGk+d2FybmluZyCXIGN1cnNvcg0Kb3BlcmF0aW9uIGNvbmZsaWN0PC9pPi48bzpwPjwv
bzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1n
cmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCmNsYXNzPUdyYW1FPjxz
cGFuIHN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5pdikgTGV0PC9zcGFuPjwv
c3Bhbj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPiA8aT5DTCA8
L2k+YmUgdGhlIGNvbHVtbnMgb2YgPGk+VCA8L2k+aWRlbnRpZmllZA0KYnkgdGhlICZsdDtvYmpl
Y3QgY29sdW1uJmd0O3MgY29udGFpbmVkIGluIHRoZSAmbHQ7c2V0IGNsYXVzZSBsaXN0Jmd0Oy48
bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxh
eW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdm
b250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz52KSBFYWNoIHN1YmplY3Qgcm93IDxpPlNSIDwv
aT5pcw0KaWRlbnRpZmllZCBmb3IgcmVwbGFjZW1lbnQsIGJ5IGl0cyBjb3JyZXNwb25kaW5nIGNh
bmRpZGF0ZSBuZXcgcm93IDxpPkNOUjwvaT4sIGluDQo8aT5UPC9pPi4gVGhlIHNldCBvZiAoPGk+
U1I8L2k+LCA8aT5DTlI8L2k+KSA8c3BhbiBjbGFzcz1HcmFtRT5wYWlycyBpczwvc3Bhbj4NCnRo
ZSByZXBsYWNlbWVudCBzZXQgZm9yIDxpPlQ8L2k+LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0K
PHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0
LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtjb2xvcjpibGFj
ayc+Tk9URSAzODIglyBJZGVudGlmeWluZyBhIHJvdyBmb3INCnJlcGxhY2VtZW50LCBhc3NvY2lh
dGluZyBhIHJlcGxhY2VtZW50IHJvdyB3aXRoIGFuIGlkZW50aWZpZWQgcm93LCBhbmQNCmFzc29j
aWF0aW5nIGEgcmVwbGFjZW1lbnQgc2V0IHdpdGggYSB0YWJsZSBhcmUgaW1wbGVtZW50YXRpb24t
ZGVwZW5kZW50DQpvcGVyYXRpb25zLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9
TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFj
ZTpub25lJz48c3Bhbg0KY2xhc3M9R3JhbUU+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7
Y29sb3I6YmxhY2snPnZpKSBDYXNlPC9zcGFuPjwvc3Bhbj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6
ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjo8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNz
PU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3Bh
Y2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4xKSBJ
ZiA8aT5UIDwvaT5pcyBhIGJhc2UgdGFibGUsIHRoZW46PG86cD48L286cD48L3NwYW4+PC9wPg0K
DQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3Rl
eHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpi
bGFjayc+QSkgQ2FzZTo8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1h
bCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+
PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5JKSBJZiAmbHQ7dGFy
Z2V0IHRhYmxlJmd0OyBzcGVjaWZpZXMgT05MWSwNCnRoZW4gPGk+VCA8L2k+aXMgaWRlbnRpZmll
ZCBmb3IgcmVwbGFjZW1lbnQgcHJvY2Vzc2luZyB3aXRob3V0IDxzcGFuDQpjbGFzcz1TcGVsbEU+
c3VidGFibGVzPC9zcGFuPiB3aXRoIHJlc3BlY3QgdG8gb2JqZWN0IGNvbHVtbnMgPGk+Q0w8L2k+
LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28t
bGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9
J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPklJKSBPdGhlcndpc2UsIDxpPlQgPC9pPmlz
IGlkZW50aWZpZWQgZm9yDQpyZXBsYWNlbWVudCBwcm9jZXNzaW5nIHdpdGggPHNwYW4gY2xhc3M9
U3BlbGxFPnN1YnRhYmxlczwvc3Bhbj4gd2l0aCByZXNwZWN0IHRvDQpvYmplY3QgY29sdW1ucyA8
aT5DTDwvaT4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5
bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFu
DQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2NvbG9yOmJsYWNrJz5OT1RFIDM4MyCXIDxzcGFuIGNs
YXNzPUdyYW1FPklkZW50aWZ5aW5nPC9zcGFuPg0KYSBiYXNlIHRhYmxlIGZvciByZXBsYWNlbWVu
dCBwcm9jZXNzaW5nLCB3aXRoIG9yIHdpdGhvdXQgPHNwYW4gY2xhc3M9U3BlbGxFPnN1YnRhYmxl
czwvc3Bhbj4sDQppcyBhbiBpbXBsZW1lbnRhdGlvbi1kZXBlbmRlbnQgbWVjaGFuaXNtLiBJbiBn
ZW5lcmFsLCB0aG91Z2ggbm90IGhlcmUsIHRoZSBsaXN0DQpvZiBvYmplY3QgY29sdW1ucyBjYW4g
YmUgZW1wdHkuPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5
bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFu
DQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+QikgVGhlIEdlbmVyYWwgUnVs
ZXMgb2YgPC9zcGFuPjxzcGFuDQpjbGFzcz1TcGVsbEU+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6IzAwMDA3MCc+U3ViY2xhdXNlPC9zcGFuPjwvc3Bhbj48c3Bhbg0Kc3R5bGU9
J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6IzAwMDA3MCc+IDE0LjIyLCCTRWZmZWN0IG9mIHJlcGxh
Y2luZyByb3dzIGluDQpiYXNlIHRhYmxlc5Q8L3NwYW4+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6YmxhY2snPiwgYXJlIGFwcGxpZWQuPG86cD48L286cD48L3NwYW4+PC9wPg0K
DQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3Rl
eHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpi
bGFjayc+MikgSWYgPGk+VCA8L2k+aXMgYSB2aWV3ZWQgdGFibGUsIHRoZW4gdGhlDQpHZW5lcmFs
IFJ1bGVzIG9mIDwvc3Bhbj48c3BhbiBjbGFzcz1TcGVsbEU+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6
ZToxMS4wcHQ7DQpjb2xvcjojMDAwMDcwJz5TdWJjbGF1c2U8L3NwYW4+PC9zcGFuPjxzcGFuIHN0
eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOiMwMDAwNzAnPg0KMTQuMjQsIJNFZmZlY3Qgb2Yg
cmVwbGFjaW5nIHNvbWUgcm93cyBpbiBhIHZpZXdlZCB0YWJsZZQ8L3NwYW4+PHNwYW4NCnN0eWxl
PSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4sIGFyZSBhcHBsaWVkIHdpdGggJmx0O3Rh
cmdldCB0YWJsZSZndDsgYXMNCjxpPlZJRVcgTkFNRTwvaT4uPG86cD48L286cD48L3NwYW4+PC9w
Pg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25l
O3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xv
cjpibGFjayc+YikgSWYgJmx0O21lcmdlIHdoZW4gbm90IG1hdGNoZWQNCmNsYXVzZSZndDsgaXMg
c3BlY2lmaWVkLCB0aGVuOjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9y
bWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25l
Jz48c3Bhbg0KY2xhc3M9U3BlbGxFPjxzcGFuIHN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9y
OmJsYWNrJz5pPC9zcGFuPjwvc3Bhbj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29s
b3I6YmxhY2snPikgTGV0IDxpPlRSMSA8L2k+YmUgdGhlICZsdDt0YXJnZXQNCnRhYmxlJmd0OyBp
bW1lZGlhdGVseSBjb250YWluZWQgaW4gJmx0O21lcmdlIHN0YXRlbWVudCZndDssIGxldCA8aT5U
UjIgPC9pPmJlDQp0aGUgJmx0O3RhYmxlIHJlZmVyZW5jZSZndDsgaW1tZWRpYXRlbHkgY29udGFp
bmVkIGluICZsdDttZXJnZSBzdGF0ZW1lbnQmZ3Q7LA0KYW5kIGxldCA8aT5TQzEgPC9pPmJlIHRo
ZSAmbHQ7c2VhcmNoIGNvbmRpdGlvbiZndDsgaW1tZWRpYXRlbHkgY29udGFpbmVkIGluDQombHQ7
bWVyZ2Ugc3RhdGVtZW50Jmd0Oy4gSWYgJmx0O21lcmdlIGNvcnJlbGF0aW9uIG5hbWUmZ3Q7IGlz
IHNwZWNpZmllZCwgbGV0IDxpPk1DTg0KPC9pPmJlIJNBUyAmbHQ7bWVyZ2UgY29ycmVsYXRpb24g
bmFtZSZndDuUOyBvdGhlcndpc2UsIGxldCA8aT5NQ04gPC9pPmJlIGENCnplcm8tbGVuZ3RoIHN0
cmluZy4gTGV0IDxpPlMxIDwvaT5iZSB0aGUgcmVzdWx0IG9mPG86cD48L286cD48L3NwYW4+PC9w
Pg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25l
O3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2ZvbnQt
ZmFtaWx5OkNvdXJpZXI7bXNvLWJpZGktZm9udC1mYW1pbHk6Q291cmllcjsNCmNvbG9yOmJsYWNr
Jz5TRUxFQ1QgKjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0
eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bh
bg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZv
bnQtZmFtaWx5OkNvdXJpZXI7DQpjb2xvcjpibGFjayc+RlJPTSA8aT5UUjEgTUNOPC9pPiwgPGk+
VFIyPG86cD48L286cD48L2k+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxl
PSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0K
c3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQt
ZmFtaWx5OkNvdXJpZXI7DQpjb2xvcjpibGFjayc+V0hFUkUgPGk+U0MxPG86cD48L286cD48L2k+
PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQt
YWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6YmxhY2snPmlpKSBMZXQgPGk+UzIgPC9pPmJlIHRoZSBjb2xsZWN0aW9uIG9m
DQpyb3dzIG9mIDxpPlEgPC9pPmZvciB3aGljaCB0aGVyZSBleGlzdHMgaW4gPGk+UzEgPC9pPnNv
bWUgcm93IHRoYXQgaXMgdGhlDQpjb25jYXRlbmF0aW9uIG9mIHNvbWUgcm93IDxpPlIxIDwvaT5v
ZiA8aT5UIDwvaT5hbmQgc29tZSByb3cgPGk+UjIgPC9pPm9mIDxpPlE8L2k+LjxvOnA+PC9vOnA+
PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQt
YWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6YmxhY2snPmlpaSkgTGV0IDxpPlMzIDwvaT5iZSB0aGUgY29sbGVjdGlvbiBv
Zg0Kcm93cyBvZiA8aT5RIDwvaT50aGF0IGFyZSBub3QgaW4gPGk+UzI8L2k+LiBMZXQgPGk+U04z
IDwvaT5iZSB0aGUgZWZmZWN0aXZlDQpkaXN0aW5jdCBuYW1lIGZvciA8aT5TMzwvaT4uIExldCA8
aT5FTiA8L2k+YmUgdGhlIGV4cG9zZWQgJmx0O2NvcnJlbGF0aW9uDQpuYW1lJmd0OyBvciAmbHQ7
dGFibGUgb3IgcXVlcnkgbmFtZSZndDsgb2YgPGk+VFIyPC9pPi48bzpwPjwvbzpwPjwvc3Bhbj48
L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5v
bmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCmNsYXNzPUdyYW1FPjxzcGFuIHN0eWxlPSdm
b250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5pdikgTGV0PC9zcGFuPjwvc3Bhbj48c3Bhbg0K
c3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPiA8aT5TNCA8L2k+YmUgdGhlIHJl
c3VsdCBvZjo8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHls
ZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4N
CnN0eWxlPSdmb250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6Q291cmllcjttc28tYmlkaS1mb250
LWZhbWlseTpDb3VyaWVyOw0KY29sb3I6YmxhY2snPlNFTEVDVCA8aT5FWFA8L2k+PC9zcGFuPjxz
cGFuIHN0eWxlPSdmb250LXNpemU6Ny41cHQ7Zm9udC1mYW1pbHk6DQpDb3VyaWVyO21zby1iaWRp
LWZvbnQtZmFtaWx5OkNvdXJpZXI7Y29sb3I6YmxhY2snPjE8L3NwYW4+PHNwYW4NCnN0eWxlPSdm
b250LXNpemU6OS4wcHQ7Zm9udC1mYW1pbHk6Q291cmllcjttc28tYmlkaS1mb250LWZhbWlseTpD
b3VyaWVyOw0KY29sb3I6YmxhY2snPiwgPGk+RVhQPC9pPjwvc3Bhbj48c3BhbiBzdHlsZT0nZm9u
dC1zaXplOjcuNXB0O2ZvbnQtZmFtaWx5OkNvdXJpZXI7DQptc28tYmlkaS1mb250LWZhbWlseTpD
b3VyaWVyO2NvbG9yOmJsYWNrJz4yPC9zcGFuPjxzcGFuIHN0eWxlPSdmb250LXNpemU6OS4wcHQ7
DQpmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7Y29sb3I6
YmxhY2snPiwgPHNwYW4NCmNsYXNzPUdyYW1FPi4uLiAsPC9zcGFuPiA8aT5FWFA8L2k+PC9zcGFu
PjxpPjxzcGFuIHN0eWxlPSdmb250LXNpemU6Ny41cHQ7DQpmb250LWZhbWlseTpDb3VyaWVyO21z
by1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7Y29sb3I6YmxhY2snPk5JPG86cD48L286cD48L3Nw
YW4+PC9pPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQt
YWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5
LjBwdDtmb250LWZhbWlseTpDb3VyaWVyO21zby1iaWRpLWZvbnQtZmFtaWx5OkNvdXJpZXI7DQpj
b2xvcjpibGFjayc+RlJPTSA8aT5TTjMgPC9pPkFTIDxpPkVOPG86cD48L286cD48L2k+PC9zcGFu
PjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246
bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7
Y29sb3I6YmxhY2snPnYpIDxpPlM0IDwvaT5pcyBlZmZlY3RpdmVseSBldmFsdWF0ZWQNCmJlZm9y
ZSBpbnNlcnRpb24gb2YgYW55IHJvd3MgaW50byBvciB1cGRhdGUgb2YgYW55IHJvd3MgaW4gPGk+
VDwvaT4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9
J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpj
bGFzcz1HcmFtRT48c3BhbiBzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+dmkp
IEZvcjwvc3Bhbj48L3NwYW4+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJs
YWNrJz4gZWFjaCByb3cgPGk+UiA8L2k+b2YgPGk+UzQ8L2k+OjxvOnA+PC9vOnA+PC9zcGFuPjwv
cD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9u
ZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29s
b3I6YmxhY2snPjEpIEEgY2FuZGlkYXRlIHJvdyBvZiA8aT5UIDwvaT5pcw0KZWZmZWN0aXZlbHkg
Y3JlYXRlZCBpbiB3aGljaCB0aGUgdmFsdWUgb2YgZWFjaCBjb2x1bW4gaXMgaXRzIGRlZmF1bHQg
dmFsdWUsIGFzDQpzcGVjaWZpZWQgaW4gdGhlIEdlbmVyYWwgUnVsZXMgb2YgPC9zcGFuPjxzcGFu
IGNsYXNzPVNwZWxsRT48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6IzAwMDA3
MCc+U3ViY2xhdXNlPC9zcGFuPjwvc3Bhbj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7
Y29sb3I6IzAwMDA3MCc+IDExLjUsIJMmbHQ7ZGVmYXVsdCBjbGF1c2UmZ3Q7lDwvc3Bhbj48c3Bh
bg0Kc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPi4gVGhlIGNhbmRpZGF0ZSBy
b3cgY29uc2lzdHMgb2YgZXZlcnkNCmNvbHVtbiBvZiA8aT5UPC9pPi48bzpwPjwvbzpwPjwvc3Bh
bj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWdu
Om5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0
O2NvbG9yOmJsYWNrJz4yKSBJZiA8aT5UIDwvaT5oYXMgYSBjb2x1bW4gPGk+UkMgPC9pPm9mDQp3
aGljaCBzb21lIHVuZGVybHlpbmcgY29sdW1uIGlzIGEgc2VsZi1yZWZlcmVuY2luZyBjb2x1bW4s
IHRoZW4gPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9
J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpz
dHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+Q2FzZTo8bzpwPjwvbzpwPjwvc3Bh
bj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWdu
Om5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0
O2NvbG9yOmJsYWNrJz5BKSBJZiA8aT5SQyA8L2k+aXMgYSBzeXN0ZW0tZ2VuZXJhdGVkDQpzZWxm
LXJlZmVyZW5jaW5nIGNvbHVtbiwgdGhlbiB0aGUgdmFsdWUgb2YgPGk+UkMgPC9pPmlzIGVmZmVj
dGl2ZWx5IHJlcGxhY2VkIGJ5DQp0aGUgUkVGIHZhbHVlIG9mIHRoZSBjYW5kaWRhdGUgcm93Ljxv
OnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5
b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2Zv
bnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPkIpIElmIDxpPlJDIDwvaT5pcyBhIGRlcml2ZWQN
CnNlbGYtcmVmZXJlbmNpbmcgY29sdW1uLCB0aGVuIHRoZSB2YWx1ZSBvZiA8aT5SQyA8L2k+aXMg
ZWZmZWN0aXZlbHkgcmVwbGFjZWQgYnkNCmEgdmFsdWUgZGVyaXZlZCBmcm9tIHRoZSBjb2x1bW5z
IGluIHRoZSBjYW5kaWRhdGUgcm93IHRoYXQgY29ycmVzcG9uZCB0byB0aGUNCmxpc3Qgb2YgYXR0
cmlidXRlcyBvZiB0aGUgZGVyaXZlZCByZXByZXNlbnRhdGlvbiBvZiB0aGUgcmVmZXJlbmNlIHR5
cGUgb2YgPGk+UkMNCjwvaT5pbiBhbiBpbXBsZW1lbnRhdGlvbiBkZXBlbmRlbnQgbWFubmVyLjxv
OnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5
b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9J2Zv
bnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPjMpIEZvciBlYWNoIG9iamVjdCBjb2x1bW4gaW4g
dGhlIGNhbmRpZGF0ZQ0Kcm93LCBsZXQgPHNwYW4gY2xhc3M9U3BlbGxFPjxpPkM8L2k+PGk+PHNw
YW4gc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdCc+aTwvc3Bhbj48L2k+PC9zcGFuPjwvc3Bhbj48aT48
c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtjb2xvcjpibGFjayc+IDwvc3Bhbj48L2k+PHNw
YW4gc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7DQpjb2xvcjpibGFjayc+YmUgdGhlIG9iamVjdCBj
b2x1bW4gaWRlbnRpZmllZCBieSA8c3BhbiBjbGFzcz1HcmFtRT50aGUgPHNwYW4NCmNsYXNzPVNw
ZWxsRT48aT5pPC9pPjwvc3Bhbj48L3NwYW4+PHNwYW4gY2xhc3M9U3BlbGxFPi10aDwvc3Bhbj4g
Jmx0O2NvbHVtbg0KbmFtZSZndDsgaW4gdGhlICZsdDtpbnNlcnQgY29sdW1uIGxpc3QmZ3Q7IGFu
ZCBsZXQgPHNwYW4gY2xhc3M9U3BlbGxFPjxpPlNWPC9pPjxpPjxzcGFuDQpzdHlsZT0nZm9udC1z
aXplOjkuMHB0Jz5pPC9zcGFuPjwvaT48L3NwYW4+PC9zcGFuPjxpPjxzcGFuIHN0eWxlPSdmb250
LXNpemU6DQo5LjBwdDtjb2xvcjpibGFjayc+IDwvc3Bhbj48L2k+PHNwYW4gc3R5bGU9J2ZvbnQt
c2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPmJlDQp0aGUgPHNwYW4gY2xhc3M9U3BlbGxFPjxpPmk8
L2k+LXRoPC9zcGFuPiB2YWx1ZSBvZiA8aT5SPC9pPi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoN
CjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4
dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJs
YWNrJz40KSBGb3IgZXZlcnkgPHNwYW4gY2xhc3M9U3BlbGxFPjxpPkM8L2k+PGk+PHNwYW4NCnN0
eWxlPSdmb250LXNpemU6OS4wcHQnPmk8L3NwYW4+PC9pPjwvc3Bhbj48L3NwYW4+PGk+PHNwYW4g
c3R5bGU9J2ZvbnQtc2l6ZToNCjkuMHB0O2NvbG9yOmJsYWNrJz4gPC9zcGFuPjwvaT48c3BhbiBz
dHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+Zm9yDQp3aGljaCBvbmUgb2YgdGhl
IGZvbGxvd2luZyBjb25kaXRpb25zIGlzIHRydWU6PG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8
cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQt
YXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFj
ayc+QSkgPHNwYW4gY2xhc3M9U3BlbGxFPjxpPkM8L2k+PGk+PHNwYW4NCnN0eWxlPSdmb250LXNp
emU6OS4wcHQnPmk8L3NwYW4+PC9pPjwvc3Bhbj48L3NwYW4+PGk+PHNwYW4gc3R5bGU9J2ZvbnQt
c2l6ZToNCjkuMHB0O2NvbG9yOmJsYWNrJz4gPC9zcGFuPjwvaT48c3BhbiBzdHlsZT0nZm9udC1z
aXplOjExLjBwdDtjb2xvcjpibGFjayc+aXMNCm5vdCBtYXJrZWQgYXMgdW5hc3NpZ25lZCBhbmQg
bm8gdW5kZXJseWluZyBjb2x1bW4gb2YgPHNwYW4gY2xhc3M9U3BlbGxFPjxpPkM8L2k+PGk+PHNw
YW4NCnN0eWxlPSdmb250LXNpemU6OS4wcHQnPmk8L3NwYW4+PC9pPjwvc3Bhbj48L3NwYW4+PGk+
PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZToNCjkuMHB0O2NvbG9yOmJsYWNrJz4gPC9zcGFuPjwvaT48
c3BhbiBzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+aXMgYQ0Kc2VsZi1yZWZl
cmVuY2luZyBjb2x1bW4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3Jt
YWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUn
PjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+QikgU29tZSB1bmRl
cmx5aW5nIGNvbHVtbiBvZiA8c3Bhbg0KY2xhc3M9U3BlbGxFPjxpPkM8L2k+PGk+PHNwYW4gc3R5
bGU9J2ZvbnQtc2l6ZTo5LjBwdCc+aTwvc3Bhbj48L2k+PC9zcGFuPjwvc3Bhbj48aT48c3Bhbg0K
c3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtjb2xvcjpibGFjayc+IDwvc3Bhbj48L2k+PHNwYW4gc3R5
bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7DQpjb2xvcjpibGFjayc+aXMgYSB1c2VyLWdlbmVyYXRlZCBz
ZWxmLXJlZmVyZW5jaW5nIGNvbHVtbi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNz
PU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3Bh
Y2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5DKSBT
b21lIHVuZGVybHlpbmcgY29sdW1uIG9mIDxzcGFuDQpjbGFzcz1TcGVsbEU+PGk+QzwvaT48aT48
c3BhbiBzdHlsZT0nZm9udC1zaXplOjkuMHB0Jz5pPC9zcGFuPjwvaT48L3NwYW4+PC9zcGFuPjxp
PjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2NvbG9yOmJsYWNrJz4gPC9zcGFuPjwvaT48
c3BhbiBzdHlsZT0nZm9udC1zaXplOjExLjBwdDsNCmNvbG9yOmJsYWNrJz5pcyBhIHNlbGYtcmVm
ZXJlbmNpbmcgY29sdW1uIGFuZCBPVkVSUklESU5HIFNZU1RFTSBWQUxVRSBpcw0Kc3BlY2lmaWVk
LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28t
bGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0Kc3R5bGU9
J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPkQpIFNvbWUgdW5kZXJseWluZyBjb2x1bW4g
b2YgPHNwYW4NCmNsYXNzPVNwZWxsRT48aT5DPC9pPjxpPjxzcGFuIHN0eWxlPSdmb250LXNpemU6
OS4wcHQnPmk8L3NwYW4+PC9pPjwvc3Bhbj48L3NwYW4+PGk+PHNwYW4NCnN0eWxlPSdmb250LXNp
emU6OS4wcHQ7Y29sb3I6YmxhY2snPiA8L3NwYW4+PC9pPjxzcGFuIHN0eWxlPSdmb250LXNpemU6
MTEuMHB0Ow0KY29sb3I6YmxhY2snPmlzIGFuIGlkZW50aXR5IGNvbHVtbiBhbmQgT1ZFUlJJRElO
RyBTWVNURU0gVkFMVUUgaXMgc3BlY2lmaWVkLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAg
Y2xhc3M9TXNvTm9ybWFsIHN0eWxlPSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1
dG9zcGFjZTpub25lJz48c3Bhbg0KY2xhc3M9R3JhbUU+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZTox
MS4wcHQ7Y29sb3I6YmxhY2snPnRoZTwvc3Bhbj48L3NwYW4+PHNwYW4NCnN0eWxlPSdmb250LXNp
emU6MTEuMHB0O2NvbG9yOmJsYWNrJz4gR2VuZXJhbCBSdWxlcyBvZiA8L3NwYW4+PHNwYW4NCmNs
YXNzPVNwZWxsRT48c3BhbiBzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjojMDAwMDcwJz5T
dWJjbGF1c2U8L3NwYW4+PC9zcGFuPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xv
cjojMDAwMDcwJz4gOS4yLCCTU3RvcmUgYXNzaWdubWVudJQ8L3NwYW4+PHNwYW4NCnN0eWxlPSdm
b250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4sIGFyZSBhcHBsaWVkIHRvIDxzcGFuIGNsYXNz
PVNwZWxsRT48aT5DPC9pPjxpPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0Jz5pPC9zcGFu
PjwvaT48L3NwYW4+PC9zcGFuPjxpPjxzcGFuIHN0eWxlPSdmb250LXNpemU6DQo5LjBwdDtjb2xv
cjpibGFjayc+IDwvc3Bhbj48L2k+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6
YmxhY2snPmFuZCA8c3Bhbg0KY2xhc3M9U3BlbGxFPjxpPlNWPC9pPjxpPjxzcGFuIHN0eWxlPSdm
b250LXNpemU6OS4wcHQnPmk8L3NwYW4+PC9pPjwvc3Bhbj48L3NwYW4+PGk+PHNwYW4NCnN0eWxl
PSdmb250LXNpemU6OS4wcHQ7Y29sb3I6YmxhY2snPiA8L3NwYW4+PC9pPjxzcGFuIHN0eWxlPSdm
b250LXNpemU6MTEuMHB0Ow0KY29sb3I6YmxhY2snPmFzIDxpPlRBUkdFVCA8L2k+YW5kIDxpPlNP
VVJDRTwvaT4sIHJlc3BlY3RpdmVseS48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNz
PU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3Bh
Y2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6OS4wcHQ7Y29sb3I6YmxhY2snPk5PVEUg
Mzg0IJcgPHNwYW4gY2xhc3M9R3JhbUU+VGhlPC9zcGFuPg0KZGF0YSB2YWx1ZXMgYWxsb3dhYmxl
IGluIHRoZSBjYW5kaWRhdGUgcm93IG1heSBiZSBjb25zdHJhaW5lZCBieSBhIFdJVEggQ0hFQ0sN
Ck9QVElPTiBjb25zdHJhaW50LiBUaGUgZWZmZWN0IG9mIGEgV0lUSCBDSEVDSyBPUFRJT04gY29u
c3RyYWludCBpcyBkZWZpbmVkIGluDQp0aGUgR2VuZXJhbCBSdWxlcyBvZiA8L3NwYW4+PHNwYW4g
Y2xhc3M9U3BlbGxFPjxzcGFuIHN0eWxlPSdmb250LXNpemU6OS4wcHQ7DQpjb2xvcjojMDAwMDcw
Jz5TdWJjbGF1c2U8L3NwYW4+PC9zcGFuPjxzcGFuIHN0eWxlPSdmb250LXNpemU6OS4wcHQ7Y29s
b3I6IzAwMDA3MCc+DQoxNC4yMSwgk0VmZmVjdCBvZiBpbnNlcnRpbmcgYSB0YWJsZSBpbnRvIGEg
dmlld2VkIHRhYmxllDwvc3Bhbj48c3Bhbg0Kc3R5bGU9J2ZvbnQtc2l6ZTo5LjBwdDtjb2xvcjpi
bGFjayc+LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPHAgY2xhc3M9TXNvTm9ybWFsIHN0eWxl
PSdtc28tbGF5b3V0LWdyaWQtYWxpZ246bm9uZTt0ZXh0LWF1dG9zcGFjZTpub25lJz48c3Bhbg0K
c3R5bGU9J2ZvbnQtc2l6ZToxMS4wcHQ7Y29sb3I6YmxhY2snPnZpaSkgTGV0IDxpPlMgPC9pPmJl
IHRoZSB0YWJsZSBjb25zaXN0aW5nDQpvZiB0aGUgY2FuZGlkYXRlIHJvd3MuPG86cD48L286cD48
L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1h
bGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjEx
LjBwdDtjb2xvcjpibGFjayc+Q2FzZTo8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNz
PU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3Bh
Y2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4xKSBJ
ZiA8aT5UIDwvaT5pcyBhIGJhc2UgdGFibGUsIHRoZW46PG86cD48L286cD48L3NwYW4+PC9wPg0K
DQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3Rl
eHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpi
bGFjayc+QSkgPGk+VCA8L2k+aXMgPGk+aWRlbnRpZmllZCBmb3IgaW5zZXJ0aW9uDQpvZiBzb3Vy
Y2UgdGFibGUgUzwvaT4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3Jt
YWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUn
PjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjkuMHB0O2NvbG9yOmJsYWNrJz5OT1RFIDM4NSCXIDxz
cGFuIGNsYXNzPUdyYW1FPklkZW50aWZ5aW5nPC9zcGFuPg0KYSBiYXNlIHRhYmxlIGZvciBpbnNl
cnRpb24gb2YgYSBzb3VyY2UgdGFibGUgaXMgYW4gaW1wbGVtZW50YXRpb24tZGVwZW5kZW50IG9w
ZXJhdGlvbi48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHls
ZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4N
CnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz5CKSBUaGUgR2VuZXJhbCBSdWxl
cyBvZiA8L3NwYW4+PHNwYW4NCmNsYXNzPVNwZWxsRT48c3BhbiBzdHlsZT0nZm9udC1zaXplOjEx
LjBwdDtjb2xvcjojMDAwMDcwJz5TdWJjbGF1c2U8L3NwYW4+PC9zcGFuPjxzcGFuDQpzdHlsZT0n
Zm9udC1zaXplOjExLjBwdDtjb2xvcjojMDAwMDcwJz4gMTQuMTksIJNFZmZlY3Qgb2YgaW5zZXJ0
aW5nIHRhYmxlcyBpbnRvDQpiYXNlIHRhYmxlc5Q8L3NwYW4+PHNwYW4gc3R5bGU9J2ZvbnQtc2l6
ZToxMS4wcHQ7Y29sb3I6YmxhY2snPiwgYXJlIGFwcGxpZWQuPG86cD48L286cD48L3NwYW4+PC9w
Pg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25l
O3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xv
cjpibGFjayc+MikgSWYgPGk+VCA8L2k+aXMgYSB2aWV3ZWQgdGFibGUsIHRoZW4gdGhlDQpHZW5l
cmFsIFJ1bGVzIG9mIDwvc3Bhbj48c3BhbiBjbGFzcz1TcGVsbEU+PHNwYW4gc3R5bGU9J2ZvbnQt
c2l6ZToxMS4wcHQ7DQpjb2xvcjojMDAwMDcwJz5TdWJjbGF1c2U8L3NwYW4+PC9zcGFuPjxzcGFu
IHN0eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOiMwMDAwNzAnPg0KMTQuMjEsIJNFZmZlY3Qg
b2YgaW5zZXJ0aW5nIGEgdGFibGUgaW50byBhIHZpZXdlZCB0YWJsZZQ8L3NwYW4+PHNwYW4NCnN0
eWxlPSdmb250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz4sIGFyZSBhcHBsaWVkIHdpdGggPGk+
UyA8L2k+YXMgPGk+U09VUkNFIDwvaT5hbmQNCjxpPlQgPC9pPmFzIDxpPlRBUkdFVDwvaT4uPG86
cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlv
dXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9u
dC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+NykgSWYgPGk+USA8L2k+aXMgZW1wdHksIHRoZW4g
YSBjb21wbGV0aW9uDQpjb25kaXRpb24gaXMgcmFpc2VkOiA8aT5ubyBkYXRhPC9pPi48bzpwPjwv
bzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1n
cmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PGI+PHNwYW4NCnN0eWxlPSdmb250
LXNpemU6MTQuMHB0O2NvbG9yOmJsYWNrJz5Db25mb3JtYW5jZSBSdWxlczxvOnA+PC9vOnA+PC9z
cGFuPjwvYj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlk
LWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6
MTEuMHB0O2NvbG9yOmJsYWNrJz4xKSBXaXRob3V0IEZlYXR1cmUgRjc4MSwgk1NlbGYtcmVmZXJl
bmNpbmcNCm9wZXJhdGlvbnOULCBjb25mb3JtaW5nIFNRTCBsYW5ndWFnZSBzaGFsbCBub3QgY29u
dGFpbiBhICZsdDttZXJnZSBzdGF0ZW1lbnQmZ3Q7DQppbiB3aGljaCBhIGxlYWYgZ2VuZXJhbGx5
IHVuZGVybHlpbmcgdGFibGUgb2YgPGk+VCA8L2k+aXMgZ2VuZXJhbGx5IGNvbnRhaW5lZA0KaW4g
YSAmbHQ7cXVlcnkgZXhwcmVzc2lvbiZndDsgaW1tZWRpYXRlbHkgY29udGFpbmVkIGluIHRoZSAm
bHQ7dGFibGUgcmVmZXJlbmNlJmd0Ow0KZXhjZXB0IGFzIHRoZSAmbHQ7dGFibGUgb3IgcXVlcnkg
bmFtZSZndDsgb3IgJmx0O2NvcnJlbGF0aW9uIG5hbWUmZ3Q7IG9mIGENCmNvbHVtbiByZWZlcmVu
Y2UuPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBjbGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21z
by1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHls
ZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+MikgV2l0aG91dCBGZWF0dXJlIEY3ODEs
IJNTZWxmLXJlZmVyZW5jaW5nDQpvcGVyYXRpb25zlCwgY29uZm9ybWluZyBTUUwgbGFuZ3VhZ2Ug
c2hhbGwgbm90IGNvbnRhaW4gYSAmbHQ7bWVyZ2Ugc3RhdGVtZW50Jmd0Ow0KaW4gd2hpY2ggYSBs
ZWFmIGdlbmVyYWxseSB1bmRlcmx5aW5nIHRhYmxlIG9mIDxpPlQgPC9pPmlzIGFuIHVuZGVybHlp
bmcgdGFibGUNCm9mIGFueSAmbHQ7cXVlcnkgZXhwcmVzc2lvbiZndDsgZ2VuZXJhbGx5IGNvbnRh
aW5lZCBpbiB0aGUgJmx0O3NlYXJjaA0KY29uZGl0aW9uJmd0Oy48bzpwPjwvbzpwPjwvc3Bhbj48
L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxheW91dC1ncmlkLWFsaWduOm5v
bmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdmb250LXNpemU6MTEuMHB0O2Nv
bG9yOmJsYWNrJz4zKSBXaXRob3V0IEZlYXR1cmUgUzAyNCwgk0VuaGFuY2VkDQpzdHJ1Y3R1cmVk
IHR5cGVzlCwgY29uZm9ybWluZyBTUUwgbGFuZ3VhZ2Ugc2hhbGwgbm90IGNvbnRhaW4gYSAmbHQ7
bWVyZ2Ugc3RhdGVtZW50Jmd0Ow0KdGhhdCBkb2VzIG5vdCBzYXRpc2Z5IHRoZSBjb25kaXRpb246
IGZvciBlYWNoIGNvbHVtbiA8aT5DIDwvaT5pZGVudGlmaWVkIGluIHRoZQ0KZXhwbGljaXQgb3Ig
aW1wbGljaXQgJmx0O2luc2VydCBjb2x1bW4gbGlzdCZndDssIGlmIHRoZSBkZWNsYXJlZCB0eXBl
IG9mIDxpPkMgPC9pPmlzDQphIHN0cnVjdHVyZWQgdHlwZSA8aT5UWTwvaT4sIHRoZW4gdGhlIGRl
Y2xhcmVkIHR5cGUgb2YgdGhlIGNvcnJlc3BvbmRpbmcgY29sdW1uDQpvZiB0aGUgJmx0O3F1ZXJ5
IGV4cHJlc3Npb24mZ3Q7IG9yICZsdDtjb250ZXh0dWFsbHkgdHlwZWQgdGFibGUgdmFsdWUNCmNv
bnN0cnVjdG9yJmd0OyBpcyA8aT5UWTwvaT4uPG86cD48L286cD48L3NwYW4+PC9wPg0KDQo8cCBj
bGFzcz1Nc29Ob3JtYWwgc3R5bGU9J21zby1sYXlvdXQtZ3JpZC1hbGlnbjpub25lO3RleHQtYXV0
b3NwYWNlOm5vbmUnPjxzcGFuDQpzdHlsZT0nZm9udC1zaXplOjExLjBwdDtjb2xvcjpibGFjayc+
NCkgV2l0aG91dCBGZWF0dXJlIEYzMTIsIJNNRVJHRSBzdGF0ZW1lbnSULA0KY29uZm9ybWluZyBT
UUwgbGFuZ3VhZ2Ugc2hhbGwgbm90IGNvbnRhaW4gYSAmbHQ7bWVyZ2Ugc3RhdGVtZW50Jmd0Oy48
bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQoNCjxwIGNsYXNzPU1zb05vcm1hbCBzdHlsZT0nbXNvLWxh
eW91dC1ncmlkLWFsaWduOm5vbmU7dGV4dC1hdXRvc3BhY2U6bm9uZSc+PHNwYW4NCnN0eWxlPSdm
b250LXNpemU6MTEuMHB0O2NvbG9yOmJsYWNrJz41KSBXaXRob3V0IEZlYXR1cmUgVDExMSwgk1Vw
ZGF0YWJsZSBqb2lucywNCnVuaW9ucywgYW5kIGNvbHVtbnOULCBjb25mb3JtaW5nIFNRTCBsYW5n
dWFnZSBzaGFsbCBub3QgY29udGFpbiBhICZsdDttZXJnZQ0Kc3RhdGVtZW50Jmd0OyB0aGF0IGNv
bnRhaW5zIGFuICZsdDt0YXJnZXQgdGFibGUmZ3Q7IHRoYXQgaWRlbnRpZmllcyBhIHRhYmxlDQp0
aGF0IGlzIG5vdCBzaW1wbHkgdXBkYXRhYmxlLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCg0KPC9k
aXY+DQoNCjwvYm9keT4NCg0KPC9odG1sPg0K

------_=_NextPart_001_01C5EBF2.45ACB7DC--

From pgsql-hackers-owner+M76240@postgresql.org Fri Nov 18 00:37:18 2005
Return-path: <pgsql-hackers-owner+M76240@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAI5bHO24992
	for <pgman@candle.pha.pa.us>; Fri, 18 Nov 2005 00:37:17 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 568F2C4BB5D;
	Fri, 18 Nov 2005 05:37:13 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id B2ABDDB7D0
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Fri, 18 Nov 2005 00:57:11 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 41664-06
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Fri, 18 Nov 2005 04:57:10 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from zigo.dhs.org (ua-83-227-204-174.cust.bredbandsbolaget.se [83.227.204.174])
	by svr1.postgresql.org (Postfix) with ESMTP id E7930DB745
	for <pgsql-hackers@postgresql.org>; Fri, 18 Nov 2005 00:57:08 -0400 (AST)
Received: from zigo.zigo.dhs.org (zigo.zigo.dhs.org [192.168.0.1])
	by zigo.dhs.org (Postfix) with ESMTP
	id EC5488467; Fri, 18 Nov 2005 05:57:05 +0100 (CET)
Date: Fri, 18 Nov 2005 05:57:05 +0100 (CET)
From: Dennis Bjorklund <db@zigo.dhs.org>
To: Bruce Momjian <pgman@candle.pha.pa.us>
cc: Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Csaba Nagy <nagy@ecircle-ag.com>,
   Martijn van Oosterhout <kleptog@svana.org>, Dann Corbit <DCorbit@connx.com>,
   Simon Riggs <simon@2ndquadrant.com>,
   Rick Gigger <rick@alpinenetworking.com>, Tom Lane <tgl@sss.pgh.pa.us>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, <josh@agliodbs.com>,
   <pgsql-hackers@postgresql.org>, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
Subject: Re: [HACKERS] MERGE vs REPLACE
In-Reply-To: <200511180218.jAI2IPF04976@candle.pha.pa.us>
Message-ID: <Pine.LNX.4.44.0511180542100.17602-100000@zigo.dhs.org>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.479 required=5 tests=[DNS_FROM_RFC_ABUSE=0.479]
X-Spam-Score: 0.479
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: ORr

On Thu, 17 Nov 2005, Bruce Momjian wrote:

> Unless you have a table lock, INSERT has to be before UPDATE, think
> UPDATE, UPDATE (both fail), INSERT, INSERT.

No matter what operation you start with you need a loop that try 
insert/update until one of them succeed like in this example:

http://www.postgresql.org/docs/8.1/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE

Without a loop you might not get to execute neither the insert nor the 
update. Why? Think about this example:

BEGIN

INSERT      <- fail because there is a row already

            <- before we manage to do the update someone
               delete the row (which we can see in the
               default transaction isolation level)

UPDATE      <- fail because there is no row so we will loop
               and try the insert again

            <- before we manage to do the insert someone else does
               an insert

INSERT      <- fail because there is a row already

            <- before we manage to do the update someone
               delete the row 
....


You might need to loop any number of times before you manage to perform
one of the two operations. Which operation you should start with depends
on which of the two cases is the common one.

-- 
/Dennis Björklund


---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

From ZeugswetterA@spardat.at Fri Nov 18 05:32:16 2005
Return-path: <ZeugswetterA@spardat.at>
Received: from smxsat1.smxs.net (smxsat1.smxs.net [213.150.10.1])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAIAWFO17231
	for <pgman@candle.pha.pa.us>; Fri, 18 Nov 2005 05:32:15 -0500 (EST)
Received: from m01x1.s-mxs.net [10.3.55.201]
	by smxsat1.smxs.net
	over TLS secured channel
	with XWall v3.35d. ;
	Fri, 18 Nov 2005 11:32:04 +0100
Received: from m0102.s-mxs.net [10.3.55.2]
	by m01x1.s-mxs.net
	with XWall v3.35d. ;
	Fri, 18 Nov 2005 11:33:38 +0100
Received: from m0143.s-mxs.net ([10.252.53.143]) by m0102.s-mxs.net with Microsoft SMTPSVC(6.0.3790.1830);
  Fri, 18 Nov 2005 11:33:38 +0100
X-MimeOLE: Produced By Microsoft Exchange V6.5.7226.0
content-class: urn:content-classes:message
Subject: RE: [HACKERS] MERGE vs REPLACE
MIME-Version: 1.0
Content-Type: text/plain;
	charset="us-ascii"
Date: Fri, 18 Nov 2005 11:32:01 +0100
Message-ID: <E1539E0ED7043848906A8FF995BDA5799A53C4@m0143.s-mxs.net>
Thread-Topic: [HACKERS] MERGE vs REPLACE
Thread-Index: AcXr5pYcJO3ZR4d/RwebJDquaJx6SQARC+uA
From: "Zeugswetter Andreas DCP SD" <ZeugswetterA@spardat.at>
To: "Bruce Momjian" <pgman@candle.pha.pa.us>
cc: "Csaba Nagy" <nagy@ecircle-ag.com>,
   "Martijn van Oosterhout" <kleptog@svana.org>,
   "Dann Corbit" <DCorbit@connx.com>, "Simon Riggs" <simon@2ndquadrant.com>,
   "Rick Gigger" <rick@alpinenetworking.com>, "Tom Lane" <tgl@sss.pgh.pa.us>,
   "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, <josh@agliodbs.com>,
   <pgsql-hackers@postgresql.org>, "Jaime Casanova" <systemguards@gmail.com>,
   "Peter Eisentraut" <peter_e@gmx.net>
X-OriginalArrivalTime: 18 Nov 2005 10:33:38.0046 (UTC) FILETIME=[8941B1E0:01C5EC2B]
Content-Transfer-Encoding: 8bit
X-MIME-Autoconverted: from quoted-printable to 8bit by candle.pha.pa.us id jAIAWFO17231
Status: OR


> Unless you have a table lock, INSERT has to be before UPDATE, think
UPDATE, UPDATE (both fail), INSERT, INSERT.

> > update
> > if no rows updated
> >   insert
> >   if duplicate key
> >     update
> >     if no rows updated goto insert

That is why you have the loop. This is not a problem with above code,
because only one insert succeeds
while the others then do the update.

Andreas

From pgsql-hackers-owner+M76266@postgresql.org Fri Nov 18 13:23:17 2005
Return-path: <pgsql-hackers-owner+M76266@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAIINGO19600
	for <pgman@candle.pha.pa.us>; Fri, 18 Nov 2005 13:23:17 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 33CABC4BB56;
	Fri, 18 Nov 2005 18:23:14 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 54076DBA92
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Fri, 18 Nov 2005 11:35:26 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 41216-03
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Fri, 18 Nov 2005 15:35:29 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from sss.pgh.pa.us (sss.pgh.pa.us [66.207.139.130])
	by svr1.postgresql.org (Postfix) with ESMTP id 84C42DBAAE
	for <pgsql-hackers@postgresql.org>; Fri, 18 Nov 2005 11:35:23 -0400 (AST)
Received: from sss2.sss.pgh.pa.us (tgl@localhost [127.0.0.1])
	by sss.pgh.pa.us (8.13.1/8.13.1) with ESMTP id jAIFYZcu006411;
	Fri, 18 Nov 2005 10:34:35 -0500 (EST)
To: Bruce Momjian <pgman@candle.pha.pa.us>
cc: Dennis Bjorklund <db@zigo.dhs.org>,
   Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Csaba Nagy <nagy@ecircle-ag.com>,
   Martijn van Oosterhout <kleptog@svana.org>, Dann Corbit <DCorbit@connx.com>,
   Simon Riggs <simon@2ndquadrant.com>,
   Rick Gigger <rick@alpinenetworking.com>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
Subject: Re: [HACKERS] MERGE vs REPLACE 
In-Reply-To: <200511181520.jAIFKpW02114@candle.pha.pa.us> 
References: <200511181520.jAIFKpW02114@candle.pha.pa.us>
Comments: In-reply-to Bruce Momjian <pgman@candle.pha.pa.us>
	message dated "Fri, 18 Nov 2005 10:20:51 -0500"
Date: Fri, 18 Nov 2005 10:34:35 -0500
Message-ID: <6410.1132328075@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.005 required=5 tests=[AWL=0.005]
X-Spam-Score: 0.005
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: ORr

Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Oh, good point.  I was thinking just about concurrent MERGEs.  However,
> it is more complicated than that.  By definitaion you can not see
> changes from other transactions while your statement is being run (even
> if you increment CommandCounter), so to be atomic, you would still see
> the row even though some other transaction had deleted it.

We would have to use the same semantics we use now for read-committed
UPDATE, that is look at the latest version of the row even though this
would not normally be visible to the transaction's snapshot.

In the case of a serializable transaction, no doubt we should fail if
any concurrent change actually happens.

			regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

From pgsql-hackers-owner+M76315@postgresql.org Sun Nov 20 12:35:46 2005
Return-path: <pgsql-hackers-owner+M76315@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAKHZjO09346
	for <pgman@candle.pha.pa.us>; Sun, 20 Nov 2005 12:35:46 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 463E1C4B337;
	Sun, 20 Nov 2005 17:35:44 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 63416D7E05
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Sun, 20 Nov 2005 13:27:09 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 12345-02
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Sun, 20 Nov 2005 17:27:07 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from candle.pha.pa.us (candle.pha.pa.us [64.139.89.126])
	by svr1.postgresql.org (Postfix) with ESMTP id 264B4D7E3B
	for <pgsql-hackers@postgresql.org>; Sun, 20 Nov 2005 13:27:05 -0400 (AST)
Received: (from pgman@localhost)
	by candle.pha.pa.us (8.11.6/8.11.6) id jAKHQI007897;
	Sun, 20 Nov 2005 12:26:18 -0500 (EST)
From: Bruce Momjian <pgman@candle.pha.pa.us>
Message-ID: <200511201726.jAKHQI007897@candle.pha.pa.us>
Subject: Re: [HACKERS] MERGE vs REPLACE
In-Reply-To: <6410.1132328075@sss.pgh.pa.us>
To: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 20 Nov 2005 12:26:18 -0500 (EST)
cc: Dennis Bjorklund <db@zigo.dhs.org>,
   Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Csaba Nagy <nagy@ecircle-ag.com>,
   Martijn van Oosterhout <kleptog@svana.org>, Dann Corbit <DCorbit@connx.com>,
   Simon Riggs <simon@2ndquadrant.com>,
   Rick Gigger <rick@alpinenetworking.com>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>,
   "Jim C. Nasby" <jnasby@pervasive.com>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
X-Mailer: ELM [version 2.4ME+ PL121 (25)]
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.034 required=5 tests=[AWL=0.034]
X-Spam-Score: 0.034
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Oh, good point.  I was thinking just about concurrent MERGEs.  However,
> > it is more complicated than that.  By definitaion you can not see
> > changes from other transactions while your statement is being run (even
> > if you increment CommandCounter), so to be atomic, you would still see
> > the row even though some other transaction had deleted it.
> 
> We would have to use the same semantics we use now for read-committed
> UPDATE, that is look at the latest version of the row even though this
> would not normally be visible to the transaction's snapshot.
> 
> In the case of a serializable transaction, no doubt we should fail if
> any concurrent change actually happens.

I have some psaudocode to explain what we want for this feature,
whatever syntax we choose:

	Start
	Check unique index
	Found
		lock row for update
		if zero rows, return to start
		if more than one row, fail
		update row
	Notfound
		create savepoint
		insert row into heap
		lock index page
		if conflicting index entry, abort savepoint, return to start
		add index entry
		unlock index page

While the "notfound" case might look strange, we actually use this exact
method for inserts now, see ExecInsert() and _bt_doinsert(). 
Particularly see this comment in the second function:

    /*
     * If we're not allowing duplicates, make sure the key isn't already in
     * the index.
     *
     * NOTE: obviously,_bt_check_unique can only detect keys that are already in
     * the index; so it cannot defend against concurrent insertions of the
     * same key.  We protect against that by means of holding a write lock on
     * the target page.  Any other would-be inserter of the same key must
     * acquire a write lock on the same target page, so only one would-be
     * inserter can be making the check at one time.  Furthermore, once we are
     * past the check we hold write locks continuously until we have performed
     * our insertion, so no later inserter can fail to see our insertion.
     * (This requires some care in _bt_insertonpg.)
     *
     * If we must wait for another xact, we release the lock while waiting, and
     * then must start over completely.
     */

Here is the unique check error from _bt_check_unique():

                    ereport(ERROR,
                            (errcode(ERRCODE_UNIQUE_VIOLATION),
                    errmsg("duplicate key violates unique constraint \"%s\"",
                           RelationGetRelationName(rel))));

I think the problem here is that it is going to longjump() back to
postgres.c (and out of your code loop).  While we have savepoints, I
think they only work coming from client applications, rather than inside
our code.  Ideally you would like to be able to say:

	savepoint();
	func();
	rollback_to_savepoint();

but you can't, so I think you are going to have to factor out that
unique error callback and return a failure code to the caller.  I
suppose some boolean flag need to be added to _bt_doinsert(), but that
is called via a function pointer for the index type, so you are going to
have to update the insert function signatures for all access methods. 
The good news is that only btree supports unique indexes, according to
the documentation ("Only B-tree currently supports unique indexes") so
for the other access methods the extra parameter is just ignored.

Another issue is multiple unique indexes.  What if the first unique
index matches one row, but a different row matches the second unique
indexed column?  Fail because unique checks do not identify exactly one
row?

Or the _new_ value for the second indexed column conflicts with the
second unique index. The MERGE/REPLACE should fail.  The UPDATE block
will handle this on its own, but the INSERT block will need to check for
that an really error out, rather than return to the caller, so the loop
in ExecInsertIndexTuples() has to restart on unique failure _only_ on
the first index check, not the subsequent ones.

One simplification would be to allow MERGE/REPLACE only on a table that
has a single unique index.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

From pgsql-hackers-owner+M76369@postgresql.org Mon Nov 21 16:49:26 2005
Return-path: <pgsql-hackers-owner+M76369@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jALLnPO11702
	for <pgman@candle.pha.pa.us>; Mon, 21 Nov 2005 16:49:25 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id E0EF1C4BBF9;
	Mon, 21 Nov 2005 21:49:23 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 788FADA584
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Mon, 21 Nov 2005 17:44:39 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 70913-06
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Mon, 21 Nov 2005 21:44:40 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from flake.decibel.org (flake.decibel.org [67.100.216.10])
	by svr1.postgresql.org (Postfix) with ESMTP id 128D5DA48D
	for <pgsql-hackers@postgresql.org>; Mon, 21 Nov 2005 17:44:35 -0400 (AST)
Received: by flake.decibel.org (Postfix, from userid 1001)
	id AD10B1525F; Mon, 21 Nov 2005 15:44:36 -0600 (CST)
Date: Mon, 21 Nov 2005 15:44:36 -0600
From: "Jim C. Nasby" <jnasby@pervasive.com>
To: Bruce Momjian <pgman@candle.pha.pa.us>
cc: mark@mark.mielke.cc, Tom Lane <tgl@sss.pgh.pa.us>,
   Csaba Nagy <nagy@ecircle-ag.com>,
   Martijn van Oosterhout <kleptog@svana.org>,
   Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Dann Corbit <DCorbit@connx.com>, Simon Riggs <simon@2ndquadrant.com>,
   Rick Gigger <rick@alpinenetworking.com>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
Subject: Re: [HACKERS] MERGE vs REPLACE
Message-ID: <20051121214436.GL19279@pervasive.com>
References: <20051117173117.GA27563@mark.mielke.cc> <200511180230.jAI2Uh406548@candle.pha.pa.us>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200511180230.jAI2Uh406548@candle.pha.pa.us>
X-Operating-System: FreeBSD 4.11-RELEASE-p10 i386
X-Distributed: Join the Effort!  http://www.distributed.net
User-Agent: Mutt/1.5.9i
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.019 required=5 tests=[AWL=0.019]
X-Spam-Score: 0.019
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

On Thu, Nov 17, 2005 at 09:30:43PM -0500, Bruce Momjian wrote:
> > Is the requirement for predicate locking, over and above a unique
> > constraint on an index that involves the record key, to deal with
> > the scenario of two inserts executing at the same time, both before
> > commit?
> 
> No.  If you have a primary key you can easily prevent duplicates.  You
> need a table lock or predicate locking to prevent duplicates if you do
> not have a primary key.

AFAIK you can also accomplish this without a table lock as long as you
have a unique index on the right set of fields and those fields are also
NOT NULL. ISTM it would be good to support that case as well, since you
might want to MERGE based on something other than the PK.
-- 
Jim C. Nasby, Sr. Engineering Consultant      jnasby@pervasive.com
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461

---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings

From decibel@decibel.org Mon Nov 21 16:46:33 2005
Return-path: <decibel@decibel.org>
Received: from flake.decibel.org (flake.decibel.org [67.100.216.10])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jALLkWO11195
	for <pgman@candle.pha.pa.us>; Mon, 21 Nov 2005 16:46:32 -0500 (EST)
Received: by flake.decibel.org (Postfix, from userid 1001)
	id 78F981525F; Mon, 21 Nov 2005 15:46:30 -0600 (CST)
Date: Mon, 21 Nov 2005 15:46:30 -0600
From: "Jim C. Nasby" <jnasby@pervasive.com>
To: Tom Lane <tgl@sss.pgh.pa.us>, Csaba Nagy <nagy@ecircle-ag.com>,
   Martijn van Oosterhout <kleptog@svana.org>,
   Zeugswetter Andreas DCP SD <ZeugswetterA@spardat.at>,
   Dann Corbit <DCorbit@connx.com>, Simon Riggs <simon@2ndquadrant.com>,
   Bruce Momjian <pgman@candle.pha.pa.us>,
   Rick Gigger <rick@alpinenetworking.com>,
   Christopher Kings-Lynne <chriskl@familyhealth.com.au>, josh@agliodbs.com,
   pgsql-hackers@postgresql.org, Jaime Casanova <systemguards@gmail.com>,
   Peter Eisentraut <peter_e@gmx.net>
Subject: Re: [HACKERS] MERGE vs REPLACE
Message-ID: <20051121214630.GM19279@pervasive.com>
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de> <25849.1132238470@sss.pgh.pa.us> <20051117151530.GU6026@ns.snowman.net>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20051117151530.GU6026@ns.snowman.net>
X-Operating-System: FreeBSD 4.11-RELEASE-p10 i386
X-Distributed: Join the Effort!  http://www.distributed.net
User-Agent: Mutt/1.5.9i
Status: OR

On Thu, Nov 17, 2005 at 10:15:30AM -0500, Stephen Frost wrote:
> I don't think MERGE can really be made to be both though, in which case
> it should really be the SQL2003 MERGE and we can make REPLACE/INSERT ON
> DUPLICATE UPDATE something else.  Perhaps a special form of MERGE where
> you know it's going to be doing that locking.  I really don't like the
> idea of making the SQL2003 version of MERGE be the MERGE special case
> (by requiring someone to take a table lock ahead of time or do something
> else odd).

Anyone know off-hand what the big 3 do? If the industry consensus is
that merge should actually be REPLACE/INSERT ON DUPLICATE UPDATE then
it's probably better to follow that lead.
-- 
Jim C. Nasby, Sr. Engineering Consultant      jnasby@pervasive.com
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461

From pgsql-hackers-owner+M76416@postgresql.org Mon Nov 21 22:20:45 2005
Return-path: <pgsql-hackers-owner+M76416@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAM3KiO01066
	for <pgman@candle.pha.pa.us>; Mon, 21 Nov 2005 22:20:45 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 16D40C4BC0E;
	Tue, 22 Nov 2005 03:20:42 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 19544D6E94
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Mon, 21 Nov 2005 23:20:13 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 65279-06
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Tue, 22 Nov 2005 03:20:16 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from gatekeeper.pjmodos.bounceme.net (5.176.broadband4.iol.cz [85.71.176.5])
	by svr1.postgresql.org (Postfix) with ESMTP id 63160DA4D8
	for <pgsql-hackers@postgresql.org>; Mon, 21 Nov 2005 23:20:10 -0400 (AST)
Received: from modos ([10.12.0.96] ident=PJMODOS)
	by gatekeeper.pjmodos.bounceme.net
 with esmtp (Exim 4.50)
	id 1EeOhc-0004vs-1V; Tue, 22 Nov 2005 04:20:16 +0100
Message-ID: <43828E6C.60406@seznam.cz>
Date: Tue, 22 Nov 2005 04:20:12 +0100
From: Petr Jelinek <pjmodos@seznam.cz>
User-Agent: Mozilla Thunderbird 1.0 (Windows/20041206)
X-Accept-Language: cs, en, en-us
MIME-Version: 1.0
To: "Jim C. Nasby" <jnasby@pervasive.com>
cc: PostgreSQL-development <pgsql-hackers@postgresql.org>
Subject: Re: [HACKERS] MERGE vs REPLACE
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de> <25849.1132238470@sss.pgh.pa.us> <20051117151530.GU6026@ns.snowman.net> <20051121214630.GM19279@pervasive.com>
In-Reply-To: <20051121214630.GM19279@pervasive.com>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-Virus-Scanned: by amavisd-new at hub.org
X-Amavis-Alert: BAD HEADER Improper use of control character (char 0D hex) in message header 'Received': Received: ...keeper.pjmodos.bounceme.net\r with esmtp (Ex...
X-Spam-Status: No, score=1.44 required=5 tests=[DNS_FROM_RFC_POST=1.44]
X-Spam-Score: 1.44
X-Spam-Level: *
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

Jim C. Nasby wrote:
> On Thu, Nov 17, 2005 at 10:15:30AM -0500, Stephen Frost wrote:
> 
>>I don't think MERGE can really be made to be both though, in which case
>>it should really be the SQL2003 MERGE and we can make REPLACE/INSERT ON
>>DUPLICATE UPDATE something else.  Perhaps a special form of MERGE where
>>you know it's going to be doing that locking.  I really don't like the
>>idea of making the SQL2003 version of MERGE be the MERGE special case
>>(by requiring someone to take a table lock ahead of time or do something
>>else odd).
> 
> 
> Anyone know off-hand what the big 3 do? If the industry consensus is
> that merge should actually be REPLACE/INSERT ON DUPLICATE UPDATE then
> it's probably better to follow that lead.

It was already said here that oracle and db2 both use MERGE, dunno about 
mssql.

And yes merge CAN be used to do REPLACE (oracle uses their dummy table 
for this, we can use the fact that FROM clause isn't required in postgres).

-- 
Regards
Petr Jelinek (PJMODOS)

---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings

From pgsql-hackers-owner+M76436@postgresql.org Tue Nov 22 05:58:26 2005
Return-path: <pgsql-hackers-owner+M76436@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAMAwPO08019
	for <pgman@candle.pha.pa.us>; Tue, 22 Nov 2005 05:58:25 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 73C27C4A48E;
	Tue, 22 Nov 2005 10:58:21 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 0E86EDAFA6
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Tue, 22 Nov 2005 06:57:56 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 82600-10
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Tue, 22 Nov 2005 10:57:57 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from svana.org (svana.org [203.20.62.76])
	by svr1.postgresql.org (Postfix) with ESMTP id EE3F8DAFA1
	for <pgsql-hackers@postgresql.org>; Tue, 22 Nov 2005 06:57:51 -0400 (AST)
Received: from kleptog by svana.org with local (Exim 3.35 #1 (Debian))
	id 1EeVqO-0003kj-00; Tue, 22 Nov 2005 21:57:48 +1100
Date: Tue, 22 Nov 2005 11:57:48 +0100
From: Martijn van Oosterhout <kleptog@svana.org>
To: Petr Jelinek <pjmodos@seznam.cz>
cc: "Jim C. Nasby" <jnasby@pervasive.com>,
   PostgreSQL-development <pgsql-hackers@postgresql.org>
Subject: Re: [HACKERS] MERGE vs REPLACE
Message-ID: <20051122105747.GC12548@svana.org>
Reply-To: Martijn van Oosterhout <kleptog@svana.org>
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de> <25849.1132238470@sss.pgh.pa.us> <20051117151530.GU6026@ns.snowman.net> <20051121214630.GM19279@pervasive.com> <43828E6C.60406@seznam.cz>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="aT9PWwzfKXlsBJM1"
Content-Disposition: inline
In-Reply-To: <43828E6C.60406@seznam.cz>
User-Agent: Mutt/1.3.28i
X-PGP-Key-ID: Length=1024; ID=0x0DC67BE6
X-PGP-Key-Fingerprint: 295F A899 A81A 156D B522  48A7 6394 F08A 0DC6 7BE6
X-PGP-Key-URL: <http://svana.org/kleptog/0DC67BE6.pgp.asc>
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0 required=5 tests=[AWL=0.000]
X-Spam-Score: 0
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR


--aT9PWwzfKXlsBJM1
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Tue, Nov 22, 2005 at 04:20:12AM +0100, Petr Jelinek wrote:
> It was already said here that oracle and db2 both use MERGE, dunno about=
=20
> mssql.
>=20
> And yes merge CAN be used to do REPLACE (oracle uses their dummy table=20
> for this, we can use the fact that FROM clause isn't required in postgres=
).

Statements about MERGE on the web:

http://www.dba-oracle.com/oracle_tips_rittman_merge.htm
http://databasejournal.com/features/db2/article.php/3322041
http://certcities.com/editorial/columns/story.asp?EditorialsID=3D51
http://publib.boulder.ibm.com/infocenter/ids9help/index.jsp?topic=3D/com.ib=
m.sqls.doc/sqls578.htm
http://www.jdixon.dotnetdevelopersjournal.com/i_want_my_sql_2005_merge_stat=
ement.htm
http://publib.boulder.ibm.com/infocenter/db2help/topic/com.ibm.db2.udb.doc/=
admin/r0010873.htm
http://expertanswercenter.techtarget.com/eac/knowledgebaseAnswer/0,295199,s=
id63_gci978700,00.html

Not one (*not one!*) of these mentions any special handling of
duplicate keys. They even go to pains to say that any errors cause
everything to rollback. The last one is especially interesting:

: Is there any way to capture errors from a MERGE statement? Also, is
: there any way to know how many records were inserted or updated for the
: MERGE statement like SQL%ROWCOUNT? Any assistance greatly appreciated.=20
:
: You capture errors the same way you would if you were doing regular
: INSERT and UPDATE statements....with exception handlers. Just include a
: WHEN OTHERS exception handler in the block where your MERGE statement
: is and have to display SQLCODE and SQLERRM if an error occurs. Then you
: can figure out which specific errors are occurring and create
: individual exception handlers for those.=20

There are even places that tell you how to decompose your MERGE into an
INSERT plus UPDATE statement. The real advantage of MERGE is that the
semantics prevent your updating a row you just inserted, which is
harder in the general case but easy if the executor is handling the
rows one at a time.

Rather than trying to make MERGE do something it wasn't designed for,
we should probably be spending our efforts on triggers for error
conditions. Maybe something like:

CREATE TRIGGER foo AFTER ERROR ON bar EXECUTE baz();

Where baz would be passed NEW and OLD just like a normal trigger and if
the trigger return NULL, the update is ignored. In the meantime the
function can divert the insert to another table if it likes. This seems
like a much more workable and useful addition.

Have a nice day,
--=20
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.

--aT9PWwzfKXlsBJM1
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQFDgvmqIB7bNG8LQkwRAr0eAKCBybl6qs2NN6kXG15tiGg+nObK0QCeP+2S
+S9F/7PZ70V8CQmZqqMn6sE=
=QsDZ
-----END PGP SIGNATURE-----

--aT9PWwzfKXlsBJM1--

From pgsql-hackers-owner+M76466@postgresql.org Tue Nov 22 15:31:18 2005
Return-path: <pgsql-hackers-owner+M76466@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAMKVHO11734
	for <pgman@candle.pha.pa.us>; Tue, 22 Nov 2005 15:31:17 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id A1AC1C4BC25;
	Tue, 22 Nov 2005 20:31:15 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 354D0DB257
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Tue, 22 Nov 2005 16:30:47 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 15163-07-3
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Tue, 22 Nov 2005 20:30:47 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from flake.decibel.org (flake.decibel.org [67.100.216.10])
	by svr1.postgresql.org (Postfix) with ESMTP id 3E9B9DBA86
	for <pgsql-hackers@postgresql.org>; Tue, 22 Nov 2005 16:30:43 -0400 (AST)
Received: by flake.decibel.org (Postfix, from userid 1001)
	id 781A61525F; Tue, 22 Nov 2005 14:30:45 -0600 (CST)
Date: Tue, 22 Nov 2005 14:30:45 -0600
From: "Jim C. Nasby" <jnasby@pervasive.com>
To: Martijn van Oosterhout <kleptog@svana.org>
cc: Petr Jelinek <pjmodos@seznam.cz>,
   PostgreSQL-development <pgsql-hackers@postgresql.org>
Subject: Re: [HACKERS] MERGE vs REPLACE
Message-ID: <20051122203045.GC99429@pervasive.com>
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de> <25849.1132238470@sss.pgh.pa.us> <20051117151530.GU6026@ns.snowman.net> <20051121214630.GM19279@pervasive.com> <43828E6C.60406@seznam.cz> <20051122105747.GC12548@svana.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20051122105747.GC12548@svana.org>
X-Operating-System: FreeBSD 4.11-RELEASE-p10 i386
X-Distributed: Join the Effort!  http://www.distributed.net
User-Agent: Mutt/1.5.9i
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.012 required=5 tests=[AWL=0.012]
X-Spam-Score: 0.012
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

On Tue, Nov 22, 2005 at 11:57:48AM +0100, Martijn van Oosterhout wrote:
<excellent research snipped>

> Rather than trying to make MERGE do something it wasn't designed for,
> we should probably be spending our efforts on triggers for error
> conditions. Maybe something like:
> 
> CREATE TRIGGER foo AFTER ERROR ON bar EXECUTE baz();
> 
> Where baz would be passed NEW and OLD just like a normal trigger and if
> the trigger return NULL, the update is ignored. In the meantime the
> function can divert the insert to another table if it likes. This seems
> like a much more workable and useful addition.

I agree that we shouldn't try and distort MERGE into something fancy.
The AFTER ERROR trigger is a very interesting idea, since it could
handle many different cases. But I'm worried that people might not want
that behavior on by default for everything done against some table. I
think it'd be better to have some way to specify in a command that
you want to use some kind of error-handling trigger. Though presumably
the underlying framework would be same, so it shouldn't be hard to
support both.
-- 
Jim C. Nasby, Sr. Engineering Consultant      jnasby@pervasive.com
Pervasive Software      http://pervasive.com    work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf       cell: 512-569-9461

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

From pgsql-hackers-owner+M76499@postgresql.org Wed Nov 23 04:10:09 2005
Return-path: <pgsql-hackers-owner+M76499@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAN9A8O01978
	for <pgman@candle.pha.pa.us>; Wed, 23 Nov 2005 04:10:09 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 8270EC4BC25;
	Wed, 23 Nov 2005 09:10:04 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 39862DB27A
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Wed, 23 Nov 2005 05:09:40 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 89452-02
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Wed, 23 Nov 2005 09:09:40 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from svana.org (svana.org [203.20.62.76])
	by svr1.postgresql.org (Postfix) with ESMTP id C6404DB088
	for <pgsql-hackers@postgresql.org>; Wed, 23 Nov 2005 05:09:36 -0400 (AST)
Received: from kleptog by svana.org with local (Exim 3.35 #1 (Debian))
	id 1Eeqd7-0002FD-00; Wed, 23 Nov 2005 20:09:29 +1100
Date: Wed, 23 Nov 2005 10:09:29 +0100
From: Martijn van Oosterhout <kleptog@svana.org>
To: Petr Jelinek <pjmodos@seznam.cz>
cc: Jaime Casanova <systemguards@gmail.com>,
   PostgreSQL-development <pgsql-hackers@postgresql.org>,
   "Jim C. Nasby" <jnasby@pervasive.com>
Subject: Re: [HACKERS] MERGE vs REPLACE
Message-ID: <20051123090926.GA8374@svana.org>
Reply-To: Martijn van Oosterhout <kleptog@svana.org>
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de> <25849.1132238470@sss.pgh.pa.us> <20051117151530.GU6026@ns.snowman.net> <20051121214630.GM19279@pervasive.com> <43828E6C.60406@seznam.cz> <c2d9e70e0511212307p2cd340fer113de21002be1e94@mail.gmail.com> <4383A8A8.30805@seznam.cz>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="fdj2RfSjLxBAspz7"
Content-Disposition: inline
In-Reply-To: <4383A8A8.30805@seznam.cz>
User-Agent: Mutt/1.3.28i
X-PGP-Key-ID: Length=1024; ID=0x0DC67BE6
X-PGP-Key-Fingerprint: 295F A899 A81A 156D B522  48A7 6394 F08A 0DC6 7BE6
X-PGP-Key-URL: <http://svana.org/kleptog/0DC67BE6.pgp.asc>
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0 required=5 tests=[AWL=0.000]
X-Spam-Score: 0
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR


--fdj2RfSjLxBAspz7
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Wed, Nov 23, 2005 at 12:24:24AM +0100, Petr Jelinek wrote:
> Btw about that keys, oracle gives error on many-to-one or many-to-many=20
> relationship between the source and target tables.

The standard has something called a "cardinality violation" if the
to-be-merged table doesn't match 1-1 with the rest of the statement. If
I had access to an Oracle I'd run two tests on MERGE:

1. Does the joining column have to have an index? For example, make a
column that's full of unique values but no unique index. According to
my reading of the the standard, this should still work (just slower).

2. Additionally, only the rows involved in the MERGE need to be
uniquely referenced, so if you add duplicate values but add a WHERE
clause to exclude those, it should also work.

My feeling is that requiring an index will limit it's usefulness as a
general tool.

Have a nice day,
--=20
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.

--fdj2RfSjLxBAspz7
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQFDhDHFIB7bNG8LQkwRAq+3AJ4kprR3WbWOegJGf9JTVsNLa11/jQCfTmH8
6o2CsvPgg1g8uOnjbHoGMHo=
=D4Cr
-----END PGP SIGNATURE-----

--fdj2RfSjLxBAspz7--

From pgsql-hackers-owner+M76510@postgresql.org Wed Nov 23 14:25:05 2005
Return-path: <pgsql-hackers-owner+M76510@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jANJP4O22462
	for <pgman@candle.pha.pa.us>; Wed, 23 Nov 2005 14:25:04 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 3EF3EC4BBCD;
	Wed, 23 Nov 2005 19:25:02 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 94C5FDB839
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Wed, 23 Nov 2005 15:24:39 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 81352-06
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Wed, 23 Nov 2005 19:24:39 +0000 (GMT)
X-Greylist: delayed 00:31:59.455806 by SQLgrey-
Received: from mecho.sysmaster.com (unknown [65.119.37.45])
	by svr1.postgresql.org (Postfix) with ESMTP id 5078FDA7A5
	for <pgsql-hackers@postgresql.org>; Wed, 23 Nov 2005 15:24:36 -0400 (AST)
Received: from [127.0.0.1] (office.sysmaster.com [65.113.143.60])
	by mecho.sysmaster.com (8.11.6/8.11.6) with ESMTP id jANIqMB22433;
	Wed, 23 Nov 2005 10:52:22 -0800
Message-ID: <4384BA5F.4080402@sysmaster.com>
Date: Wed, 23 Nov 2005 10:52:15 -0800
From: Lyubomir Petrov <lpetrov@sysmaster.com>
User-Agent: Thunderbird 1.5 (Windows/20051025)
MIME-Version: 1.0
To: Martijn van Oosterhout <kleptog@svana.org>
cc: PostgreSQL-development <pgsql-hackers@postgresql.org>
Subject: Re: [HACKERS] MERGE vs REPLACE
References: <E1539E0ED7043848906A8FF995BDA5799A524D@m0143.s-mxs.net> <1132228373.10890.313.camel@coppola.muc.ecircle.de> <20051117123250.GC22933@svana.org> <1132231474.10890.317.camel@coppola.muc.ecircle.de> <25849.1132238470@sss.pgh.pa.us> <20051117151530.GU6026@ns.snowman.net> <20051121214630.GM19279@pervasive.com> <43828E6C.60406@seznam.cz> <c2d9e70e0511212307p2cd340fer113de21002be1e94@mail.gmail.com> <4383A8A8.30805@seznam.cz> <20051123090926.GA8374@svana.org>
In-Reply-To: <20051123090926.GA8374@svana.org>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0 required=5 tests=[none]
X-Spam-Score: 0
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

Martijn,

Here is a quick test (Oracle 10.1.0.3/Linux):


SQL> select banner from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 - Prod
PL/SQL Release 10.1.0.3.0 - Production
CORE    10.1.0.3.0      Production
TNS for Linux: Version 10.1.0.3.0 - Production
NLSRTL Version 10.1.0.3.0 - Production

SQL> select * from merge_test_1;
        ID NAME
---------- --------------------
         1 aaa
         2 bbb
         3 ccc
         4 ddd
         5 eee
         1 xxx
6 rows selected.

SQL> select * from merge_test_2;
        ID NAME
---------- --------------------
         1 AAA
         2 BBB
         6 FFF

SQL> select index_name from user_indexes where table_name like 
'merge_test%';
no rows selected

SQL> merge into merge_test_1 a1
  2  using merge_test_2 a2
  3      on (a1.id = a2.id)
  4  when matched then
  5      update set a1.name = a2.name
  6  when not matched then
  7      insert (id, name) values (a2.id, a2.name);
4 rows merged.

SQL> select * from merge_test_1;
        ID NAME
---------- --------------------
         1 AAA
         2 BBB
         3 ccc
         4 ddd
         5 eee
         1 AAA
         6 FFF
7 rows selected.



Regards,
Lubomir Petrov



Martijn van Oosterhout wrote:
> On Wed, Nov 23, 2005 at 12:24:24AM +0100, Petr Jelinek wrote:
>   
>> Btw about that keys, oracle gives error on many-to-one or many-to-many 
>> relationship between the source and target tables.
>>     
>
> The standard has something called a "cardinality violation" if the
> to-be-merged table doesn't match 1-1 with the rest of the statement. If
> I had access to an Oracle I'd run two tests on MERGE:
>
> 1. Does the joining column have to have an index? For example, make a
> column that's full of unique values but no unique index. According to
> my reading of the the standard, this should still work (just slower).
>
> 2. Additionally, only the rows involved in the MERGE need to be
> uniquely referenced, so if you add duplicate values but add a WHERE
> clause to exclude those, it should also work.
>
> My feeling is that requiring an index will limit it's usefulness as a
> general tool.
>
> Have a nice day,
>   


---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

From pgsql-hackers-owner+M76513@postgresql.org Wed Nov 23 17:23:34 2005
Return-path: <pgsql-hackers-owner+M76513@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jANMNXO20323
	for <pgman@candle.pha.pa.us>; Wed, 23 Nov 2005 17:23:33 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id C020EC4A48E;
	Wed, 23 Nov 2005 22:23:30 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 03F71DBAA3
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Wed, 23 Nov 2005 18:23:06 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 92598-01
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Wed, 23 Nov 2005 22:23:06 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from smtp018.mail.yahoo.com (smtp018.mail.yahoo.com [216.136.174.115])
	by svr1.postgresql.org (Postfix) with SMTP id 121D3DBA93
	for <pgsql-hackers@postgresql.org>; Wed, 23 Nov 2005 18:23:01 -0400 (AST)
Received: (qmail 47652 invoked from network); 23 Nov 2005 22:22:56 -0000
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws;
  s=s1024; d=Yahoo.com;
  h=Received:Message-ID:Date:From:User-Agent:X-Accept-Language:MIME-Version:To:CC:Subject:References:In-Reply-To:Content-Type:Content-Transfer-Encoding;
  b=ikj/Ob+3p22lsO9ikWyS1RkIbs6fq47zO2HF4jU7ZStjg5F/smOj0F+YkTeoepYDBoiKtd5pr0vxODe6iSXdUmQgXKe4BvzaypEm8KFqgR2kKtlpW/QAy1arUUnD1DoFpx/SJgPFt1V4S//lgGTpWw5v99EeoYfapzNmNV0hgQI=  ;
Received: from unknown (HELO jupiter.black-lion.info) (janwieck@68.80.245.191 with login)
  by smtp018.mail.yahoo.com with SMTP; 23 Nov 2005 22:22:55 -0000
Received: from [172.21.8.23] (mars.black-lion.info [192.168.192.101])
	(authenticated bits=0)
	by jupiter.black-lion.info (8.12.10/8.12.9) with ESMTP id jANLtT1o054955;
	Wed, 23 Nov 2005 16:55:29 -0500 (EST)
	(envelope-from JanWieck@Yahoo.com)
Message-ID: <4384E54D.8000500@Yahoo.com>
Date: Wed, 23 Nov 2005 16:55:25 -0500
From: Jan Wieck <JanWieck@Yahoo.com>
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: Tom Lane <tgl@sss.pgh.pa.us>
cc: Peter Eisentraut <peter_e@gmx.net>, pgsql-hackers@postgresql.org,
   Josh Berkus <josh@agliodbs.com>, Jaime Casanova <systemguards@gmail.com>
Subject: Re: [HACKERS] someone working to add merge?
References: <c2d9e70e0511110603q1799d811u6e4564be516b10ce@mail.gmail.com> <200511111924.41532.peter_e@gmx.net> <20561.1131734697@sss.pgh.pa.us> <200511112004.35876.peter_e@gmx.net> <20899.1131736841@sss.pgh.pa.us>
In-Reply-To: <20899.1131736841@sss.pgh.pa.us>
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.359 required=5 tests=[AWL=-0.120,
	DNS_FROM_RFC_ABUSE=0.479]
X-Spam-Score: 0.359
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

On 11/11/2005 2:20 PM, Tom Lane wrote:

> Peter Eisentraut <peter_e@gmx.net> writes:
>> Tom Lane wrote:
>>> Surely they require a unique constraint --- else the behavior isn't
>>> even well defined, is it?
> 
>> They require that the merge condition does not match for more than one 
>> row, but since the merge condition can do just about anything, there is 
>> no guarantee that a unique constraint encompasses it.
> 
> ISTM to be a reasonable implementation restriction that there be a
> constraint by which the system can prove that there is at most one
> matching row.  Per other comments in this thread, we'd not be the only
> implementation making such a restriction.
> 
> (Certainly, if I were a DBA and were told that the performance of MERGE
> would go to hell in a handbasket if I had no such constraint, I'd make
> sure there was one.  I don't think there is very much of a use-case for
> the general scenario.)

Such restriction does look reasonable. Especially because ...

The largest problem I see with MERGE is the question of BEFORE triggers. 
Consider a BEFORE INSERT trigger that modifies a third table, after 
which the constraint or whatever post-heap_insert-attempt we might use 
detects a conflict. How do we undo the actions of the BEFORE trigger? 
The only way to do that is to plan the query as a nestloop, with the 
USING part as the outer loop. If the (updating) scan of the INTO 
relation did not hit any tuple, then do the INSERT. We can only undo the 
side effects of any BEFORE trigger by wrapping each and evey nested INTO 
relation insert attempt into its own subtransaction.

Sure, we "could" of course do the insert and then rescan the whole thing 
with read-committed to see if our row is now the only one ... needless 
to say that in the case of a sequential scan inside the loop, that 
nestloop will suck big times even without that second scan. But ... hmmm 
... we could get away with that and if we don't find a constraint that 
will ensure uniqueness, then we do a rescan to check for it. But I would 
vote for a "please_no_notice_about_stupid_usage_of_merge" runtime option 
that suppresses the corresponding NOTICE.


Jan

-- 
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

From pgsql-hackers-owner+M76524@postgresql.org Thu Nov 24 01:31:30 2005
Return-path: <pgsql-hackers-owner+M76524@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAO6VTO16396
	for <pgman@candle.pha.pa.us>; Thu, 24 Nov 2005 01:31:30 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id D9160C4A48E;
	Thu, 24 Nov 2005 06:31:25 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 42FE3DBC43
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Thu, 24 Nov 2005 02:31:01 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 56362-10
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Thu, 24 Nov 2005 06:31:00 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from svana.org (svana.org [203.20.62.76])
	by svr1.postgresql.org (Postfix) with ESMTP id A1169DBC30
	for <pgsql-hackers@postgresql.org>; Thu, 24 Nov 2005 02:30:58 -0400 (AST)
Received: from kleptog by svana.org with local (Exim 3.35 #1 (Debian))
	id 1EfAcw-0004xu-00; Thu, 24 Nov 2005 17:30:38 +1100
Date: Thu, 24 Nov 2005 07:30:37 +0100
From: Martijn van Oosterhout <kleptog@svana.org>
To: Jan Wieck <JanWieck@Yahoo.com>
cc: Tom Lane <tgl@sss.pgh.pa.us>, Peter Eisentraut <peter_e@gmx.net>,
   pgsql-hackers@postgresql.org, Josh Berkus <josh@agliodbs.com>,
   Jaime Casanova <systemguards@gmail.com>
Subject: Re: [HACKERS] someone working to add merge?
Message-ID: <20051124063034.GA18750@svana.org>
Reply-To: Martijn van Oosterhout <kleptog@svana.org>
References: <c2d9e70e0511110603q1799d811u6e4564be516b10ce@mail.gmail.com> <200511111924.41532.peter_e@gmx.net> <20561.1131734697@sss.pgh.pa.us> <200511112004.35876.peter_e@gmx.net> <20899.1131736841@sss.pgh.pa.us> <4384E54D.8000500@Yahoo.com>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="45Z9DzgjV8m4Oswq"
Content-Disposition: inline
In-Reply-To: <4384E54D.8000500@Yahoo.com>
User-Agent: Mutt/1.3.28i
X-PGP-Key-ID: Length=1024; ID=0x0DC67BE6
X-PGP-Key-Fingerprint: 295F A899 A81A 156D B522  48A7 6394 F08A 0DC6 7BE6
X-PGP-Key-URL: <http://svana.org/kleptog/0DC67BE6.pgp.asc>
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0 required=5 tests=[AWL=0.000]
X-Spam-Score: 0
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR


--45Z9DzgjV8m4Oswq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Wed, Nov 23, 2005 at 04:55:25PM -0500, Jan Wieck wrote:
> The largest problem I see with MERGE is the question of BEFORE triggers.=
=20
> Consider a BEFORE INSERT trigger that modifies a third table, after=20
> which the constraint or whatever post-heap_insert-attempt we might use=20
> detects a conflict. How do we undo the actions of the BEFORE trigger?=20
> The only way to do that is to plan the query as a nestloop, with the=20
> USING part as the outer loop. If the (updating) scan of the INTO=20
> relation did not hit any tuple, then do the INSERT. We can only undo the=
=20
> side effects of any BEFORE trigger by wrapping each and evey nested INTO=
=20
> relation insert attempt into its own subtransaction.

Umm, if there are any errors you abort the transaction, just like any
other case. ACID requires that either the whole statement is done, or
none. If a trigger causes the INSERT or UPDATE to fail you have no
choice but to abort the transaction.

Besides, someone posted an example on Oracle, they don't require an
index so I don't think we realistically can say that people need one.
If two concurrent MERGEs, which can't see eachothers output, both end
up INSERTing, that not an error unless the user has a UNIQUE
constraint, so the problem vanishes.

Have a nice day,
--=20
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.

--45Z9DzgjV8m4Oswq
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQFDhV4HIB7bNG8LQkwRAgXZAKCBD3QOdBVT3GmCqEQj9tfapJq38QCeOdvW
VXixm+YDkCCWkSLEQcUtixM=
=3H5a
-----END PGP SIGNATURE-----

--45Z9DzgjV8m4Oswq--

From pgsql-hackers-owner+M76549@postgresql.org Thu Nov 24 11:12:14 2005
Return-path: <pgsql-hackers-owner+M76549@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAOGCDO07384
	for <pgman@candle.pha.pa.us>; Thu, 24 Nov 2005 11:12:13 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 305F4C4A48E;
	Thu, 24 Nov 2005 16:12:12 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 6A539DBC1D
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Thu, 24 Nov 2005 12:11:46 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 60324-06-2
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Thu, 24 Nov 2005 16:11:44 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from smtp011.mail.yahoo.com (smtp011.mail.yahoo.com [216.136.173.31])
	by svr1.postgresql.org (Postfix) with SMTP id 11B74DBBF3
	for <pgsql-hackers@postgresql.org>; Thu, 24 Nov 2005 12:11:42 -0400 (AST)
Received: (qmail 72237 invoked from network); 24 Nov 2005 16:11:41 -0000
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws;
  s=s1024; d=Yahoo.com;
  h=Received:Message-ID:Date:From:User-Agent:X-Accept-Language:MIME-Version:To:CC:Subject:References:In-Reply-To:Content-Type:Content-Transfer-Encoding;
  b=dgj7516dhcBQJ4gSnC2f7PmbQi7TxXH8v8ahOhOPDm/53Yj9wVKNG2jTbp+j2crVe+Tw7VA5EEhS2YqaHTmD8Fs3np6yVP4J1VN/SF7+aywZkiiRJUSEAe3qYpGIGRFxtnKr3K3M6TufdeJZuEKu4O3YCW+IZi8SCulBwKV5jfM=  ;
Received: from unknown (HELO jupiter.black-lion.info) (janwieck@68.80.245.191 with login)
  by smtp011.mail.yahoo.com with SMTP; 24 Nov 2005 16:11:41 -0000
Received: from [172.21.8.23] (mars.black-lion.info [192.168.192.101])
	(authenticated bits=0)
	by jupiter.black-lion.info (8.12.10/8.12.9) with ESMTP id jAOGBc1o058226;
	Thu, 24 Nov 2005 11:11:38 -0500 (EST)
	(envelope-from JanWieck@Yahoo.com)
Message-ID: <4385E636.4070503@Yahoo.com>
Date: Thu, 24 Nov 2005 11:11:34 -0500
From: Jan Wieck <JanWieck@Yahoo.com>
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: Martijn van Oosterhout <kleptog@svana.org>
cc: Tom Lane <tgl@sss.pgh.pa.us>, Peter Eisentraut <peter_e@gmx.net>,
   pgsql-hackers@postgresql.org, Josh Berkus <josh@agliodbs.com>,
   Jaime Casanova <systemguards@gmail.com>
Subject: Re: [HACKERS] someone working to add merge?
References: <c2d9e70e0511110603q1799d811u6e4564be516b10ce@mail.gmail.com> <200511111924.41532.peter_e@gmx.net> <20561.1131734697@sss.pgh.pa.us> <200511112004.35876.peter_e@gmx.net> <20899.1131736841@sss.pgh.pa.us> <4384E54D.8000500@Yahoo.com> <20051124063034.GA18750@svana.org>
In-Reply-To: <20051124063034.GA18750@svana.org>
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.359 required=5 tests=[AWL=-0.120,
	DNS_FROM_RFC_ABUSE=0.479]
X-Spam-Score: 0.359
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

On 11/24/2005 1:30 AM, Martijn van Oosterhout wrote:

> On Wed, Nov 23, 2005 at 04:55:25PM -0500, Jan Wieck wrote:
>> The largest problem I see with MERGE is the question of BEFORE triggers. 
>> Consider a BEFORE INSERT trigger that modifies a third table, after 
>> which the constraint or whatever post-heap_insert-attempt we might use 
>> detects a conflict. How do we undo the actions of the BEFORE trigger? 
>> The only way to do that is to plan the query as a nestloop, with the 
>> USING part as the outer loop. If the (updating) scan of the INTO 
>> relation did not hit any tuple, then do the INSERT. We can only undo the 
>> side effects of any BEFORE trigger by wrapping each and evey nested INTO 
>> relation insert attempt into its own subtransaction.
> 
> Umm, if there are any errors you abort the transaction, just like any
> other case. ACID requires that either the whole statement is done, or
> none. If a trigger causes the INSERT or UPDATE to fail you have no
> choice but to abort the transaction.

I guess you misunderstood. What I am talking about is a problem in the 
order of execution. since we don't have predicate locking, there is a 
possibility that our implementation of MERGE decides to do an INSERT 
while another transaction does the same. What has to happen is that the 
BEFORE INSERT trigger is called, then the heap tuple inserted, then the 
index tuples created. At this time, the duplicate key error occurs, 
telling us that we had a conflict and that we have to try an UPDATE 
instead. That means, in the end this particular row's INSERT has never 
happened and we have to undo the BEFORE INSERT triggers actions too.

> 
> Besides, someone posted an example on Oracle, they don't require an
> index so I don't think we realistically can say that people need one.
> If two concurrent MERGEs, which can't see eachothers output, both end
> up INSERTing, that not an error unless the user has a UNIQUE
> constraint, so the problem vanishes.

Not following the semantics is an error. MERGE is not supposed to do 
multiple inserts for the same match, concurrency or not.


Jan

-- 
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #

---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

From pgsql-hackers-owner+M76581@postgresql.org Fri Nov 25 07:14:48 2005
Return-path: <pgsql-hackers-owner+M76581@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAPCElB26143
	for <pgman@candle.pha.pa.us>; Fri, 25 Nov 2005 07:14:47 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id 46071C4BC79;
	Fri, 25 Nov 2005 12:14:46 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id A32A1D72AA
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Fri, 25 Nov 2005 08:14:18 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 86344-02
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Fri, 25 Nov 2005 12:14:19 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from svana.org (svana.org [203.20.62.76])
	by svr1.postgresql.org (Postfix) with ESMTP id 14D00D6FFA
	for <pgsql-hackers@postgresql.org>; Fri, 25 Nov 2005 08:14:14 -0400 (AST)
Received: from kleptog by svana.org with local (Exim 3.35 #1 (Debian))
	id 1EfcSp-00058u-00; Fri, 25 Nov 2005 23:14:03 +1100
Date: Fri, 25 Nov 2005 13:14:03 +0100
From: Martijn van Oosterhout <kleptog@svana.org>
To: Jan Wieck <JanWieck@Yahoo.com>
cc: Tom Lane <tgl@sss.pgh.pa.us>, Peter Eisentraut <peter_e@gmx.net>,
   pgsql-hackers@postgresql.org, Josh Berkus <josh@agliodbs.com>,
   Jaime Casanova <systemguards@gmail.com>
Subject: Re: [HACKERS] someone working to add merge?
Message-ID: <20051125121402.GB16970@svana.org>
Reply-To: Martijn van Oosterhout <kleptog@svana.org>
References: <c2d9e70e0511110603q1799d811u6e4564be516b10ce@mail.gmail.com> <200511111924.41532.peter_e@gmx.net> <20561.1131734697@sss.pgh.pa.us> <200511112004.35876.peter_e@gmx.net> <20899.1131736841@sss.pgh.pa.us> <4384E54D.8000500@Yahoo.com> <20051124063034.GA18750@svana.org> <4385E636.4070503@Yahoo.com>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="2B/JsCI69OhZNC5r"
Content-Disposition: inline
In-Reply-To: <4385E636.4070503@Yahoo.com>
User-Agent: Mutt/1.3.28i
X-PGP-Key-ID: Length=1024; ID=0x0DC67BE6
X-PGP-Key-Fingerprint: 295F A899 A81A 156D B522  48A7 6394 F08A 0DC6 7BE6
X-PGP-Key-URL: <http://svana.org/kleptog/0DC67BE6.pgp.asc>
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0 required=5 tests=[AWL=0.000]
X-Spam-Score: 0
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR


--2B/JsCI69OhZNC5r
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Thu, Nov 24, 2005 at 11:11:34AM -0500, Jan Wieck wrote:
> On 11/24/2005 1:30 AM, Martijn van Oosterhout wrote:
> >Umm, if there are any errors you abort the transaction, just like any
> >other case. ACID requires that either the whole statement is done, or
> >none. If a trigger causes the INSERT or UPDATE to fail you have no
> >choice but to abort the transaction.
>=20
> I guess you misunderstood. What I am talking about is a problem in the=20
> order of execution. since we don't have predicate locking, there is a=20
> possibility that our implementation of MERGE decides to do an INSERT=20
> while another transaction does the same. What has to happen is that the=
=20
> BEFORE INSERT trigger is called, then the heap tuple inserted, then the=
=20
> index tuples created. At this time, the duplicate key error occurs,=20
> telling us that we had a conflict and that we have to try an UPDATE=20
> instead. That means, in the end this particular row's INSERT has never=20
> happened and we have to undo the BEFORE INSERT triggers actions too.

But I'm not sure we're supposed to handle that case anyway. Oracle at
least doesn't require an index on the table being merged. And if I look
at it from a visibility view point, if someone else does an INSERT in
another transaction, then MERGE cannot see it and thus it will INSERT
too. This isn't an error.

Consider the case of a deferred unique constraint (Postgres doesn't
support these yet but bear with me). Say in one session you start a
transaction, do a MERGE and then a few other statements. In the
meantime in another session someone inserts a row on the table you
merged. Are you asserting that the first session should undo
everything, do an UPDATE instead of an INSERT and redo all your queries
since? Obviously not.

Though the above relies on something Postgres doesn't support, but you
would be able to emulate the some without a unique key. For example:

Session 1:
CREATE TEMP TABLE foo (id integer, val integer);

BEGIN;
SELECT * FROM foo;

Session 2:
BEGIN;

INSERT INTO foo (1,3);

Session 1:
MERGE INTO foo
  USING (SELECT 1)
  ON (foo.id =3D 1)
  WHEN MATCHED THEN UPDATE SET val =3D 1
  WHEN NOT MATCHED THEN INSERT (id,val) VALUES (1,2);

Session 2:
COMMIT;

Session 1:
COMMIT;

Now, (IMO) in serializable mode, the MERGE should block on reading the
row inserted by the second session and when that commits do the UPDATE,
thus leaving you with a table with one row (1.1).

In read committed mode, the MERGE shouldn't block and you should end up
with a table with two rows (1,3) and (1,2).

If you switch the order of the insert and merge you should get the same
results in both cases, (1,2) and (1,3).

I think you are arguing that the result should be (1,1) in all cases. I
honestly don't see how that is feasible and certainly not supported by
my reading of the standard. I would be interested to know how other
databases handle the above case.

> Not following the semantics is an error. MERGE is not supposed to do=20
> multiple inserts for the same match, concurrency or not.

Yes, any single MERGE cannot insert twice. However, two MERGEs running
concurrently, or a MERGE with an INSERT/UPDATE/DELETE in another
session could very well end up with multiple rows on the same key. I
maintain that MERGE has no special rules w.r.t. visibility or locking
and we should not be acting as if it does. If at the end of the
transaction there a duplicate key we should throw the error and let the
client deal with it.

Have a nice day,
--=20
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.

--2B/JsCI69OhZNC5r
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQFDhwAKIB7bNG8LQkwRAvpQAJsHNO/wnfcH0QwNQ7AKXkV5CzCz9wCfVJBH
/iCYKxdxjTOkw6+M2PgPAjY=
=ERXt
-----END PGP SIGNATURE-----

--2B/JsCI69OhZNC5r--

From pgsql-hackers-owner+M76584@postgresql.org Fri Nov 25 09:15:33 2005
Return-path: <pgsql-hackers-owner+M76584@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAPEFWB13482
	for <pgman@candle.pha.pa.us>; Fri, 25 Nov 2005 09:15:32 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id AFCB6C4BC79;
	Fri, 25 Nov 2005 14:15:30 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 039CCD774A
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Fri, 25 Nov 2005 10:14:59 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 13125-10
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Fri, 25 Nov 2005 14:15:01 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from smtp015.mail.yahoo.com (smtp015.mail.yahoo.com [216.136.173.59])
	by svr1.postgresql.org (Postfix) with SMTP id 55EA1D6822
	for <pgsql-hackers@postgresql.org>; Fri, 25 Nov 2005 10:14:55 -0400 (AST)
Received: (qmail 6658 invoked from network); 25 Nov 2005 14:14:55 -0000
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws;
  s=s1024; d=Yahoo.com;
  h=Received:Message-ID:Date:From:User-Agent:X-Accept-Language:MIME-Version:To:CC:Subject:References:In-Reply-To:Content-Type:Content-Transfer-Encoding;
  b=3IYwOeJgAhkmP/C6LDpv1wsSJCeqr4E0XFCc+cW2u3ZWf6NbmJ19+1NqiyPs/4RVzSH0M8FIPcRZDB1e3bkKQHt3wxdGJrfdxMi5d7DjlC59xirRpZGzUAD3yusU8lg3uE2G/TraLtC6VVpbJo8+rYerPOg+daspmuRqhlcXUjg=  ;
Received: from unknown (HELO jupiter.black-lion.info) (janwieck@68.80.245.191 with login)
  by smtp015.mail.yahoo.com with SMTP; 25 Nov 2005 14:14:55 -0000
Received: from [172.21.8.23] (mars.black-lion.info [192.168.192.101])
	(authenticated bits=0)
	by jupiter.black-lion.info (8.12.10/8.12.9) with ESMTP id jAPEEq1o062023;
	Fri, 25 Nov 2005 09:14:52 -0500 (EST)
	(envelope-from JanWieck@Yahoo.com)
Message-ID: <43871C57.6060000@Yahoo.com>
Date: Fri, 25 Nov 2005 09:14:47 -0500
From: Jan Wieck <JanWieck@Yahoo.com>
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: Martijn van Oosterhout <kleptog@svana.org>
cc: Tom Lane <tgl@sss.pgh.pa.us>, Peter Eisentraut <peter_e@gmx.net>,
   pgsql-hackers@postgresql.org, Josh Berkus <josh@agliodbs.com>,
   Jaime Casanova <systemguards@gmail.com>
Subject: Re: [HACKERS] someone working to add merge?
References: <c2d9e70e0511110603q1799d811u6e4564be516b10ce@mail.gmail.com> <200511111924.41532.peter_e@gmx.net> <20561.1131734697@sss.pgh.pa.us> <200511112004.35876.peter_e@gmx.net> <20899.1131736841@sss.pgh.pa.us> <4384E54D.8000500@Yahoo.com> <20051124063034.GA18750@svana.org> <4385E636.4070503@Yahoo.com> <20051125121402.GB16970@svana.org>
In-Reply-To: <20051125121402.GB16970@svana.org>
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0.359 required=5 tests=[AWL=-0.120,
	DNS_FROM_RFC_ABUSE=0.479]
X-Spam-Score: 0.359
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR

On 11/25/2005 7:14 AM, Martijn van Oosterhout wrote:
> On Thu, Nov 24, 2005 at 11:11:34AM -0500, Jan Wieck wrote:
>> I guess you misunderstood. [...]
> 
> But I'm not sure we're supposed to handle that case anyway. Oracle at
> least doesn't require an index on the table being merged. And if I look
> at it from a visibility view point, if someone else does an INSERT in
> another transaction, then MERGE cannot see it and thus it will INSERT
> too. This isn't an error.

Hmmm ... so you maintain that MERGE without an explicit LOCK TABLE, done 
by the user before performing the MERGE, can create duplicate rows (WRT 
the merge condition) and consequently raise a duplicate key error if 
there is a UNIQUE constraint.

If that is what the standard describes, then it can be implemented 
without any sort of index or constraint requirement. The query tree for 
MERGE will have the INTO relation as a left outer join. In the case of a 
match of this outer join, one set of targetlist expressions is used to 
form the result tuple containing the INTO-relations ctid. That result 
tuple us useable for heap_update() or heap_delete(). In the case of 
no-match another set of target list expressions is used, suitable for 
heap_insert(). This way, MERGE will work with one single sequential scan 
of the INTO relation in case there is no suitable index.


Jan

-- 
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

From pgsql-hackers-owner+M76588@postgresql.org Fri Nov 25 09:55:41 2005
Return-path: <pgsql-hackers-owner+M76588@postgresql.org>
Received: from ams.hub.org (ams.hub.org [200.46.204.13])
	by candle.pha.pa.us (8.11.6/8.11.6) with ESMTP id jAPEtfB01898
	for <pgman@candle.pha.pa.us>; Fri, 25 Nov 2005 09:55:41 -0500 (EST)
Received: from postgresql.org (svr1.postgresql.org [200.46.204.71])
	by ams.hub.org (Postfix) with ESMTP id D0574C4BCA2;
	Fri, 25 Nov 2005 14:55:39 +0000 (GMT)
X-Original-To: pgsql-hackers-postgresql.org@localhost.postgresql.org
Received: from localhost (av.hub.org [200.46.204.144])
	by svr1.postgresql.org (Postfix) with ESMTP id 9BABBD7693
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>; Fri, 25 Nov 2005 10:55:13 -0400 (AST)
Received: from svr1.postgresql.org ([200.46.204.71])
	by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024)
	with ESMTP id 21958-02
	for <pgsql-hackers-postgresql.org@localhost.postgresql.org>;
	Fri, 25 Nov 2005 14:55:16 +0000 (GMT)
X-Greylist: from auto-whitelisted by SQLgrey-
Received: from svana.org (svana.org [203.20.62.76])
	by svr1.postgresql.org (Postfix) with ESMTP id C3689D7121
	for <pgsql-hackers@postgresql.org>; Fri, 25 Nov 2005 10:55:08 -0400 (AST)
Received: from kleptog by svana.org with local (Exim 3.35 #1 (Debian))
	id 1Efeyd-0005xQ-00; Sat, 26 Nov 2005 01:55:03 +1100
Date: Fri, 25 Nov 2005 15:55:03 +0100
From: Martijn van Oosterhout <kleptog@svana.org>
To: Jan Wieck <JanWieck@Yahoo.com>
cc: Tom Lane <tgl@sss.pgh.pa.us>, Peter Eisentraut <peter_e@gmx.net>,
   pgsql-hackers@postgresql.org, Josh Berkus <josh@agliodbs.com>,
   Jaime Casanova <systemguards@gmail.com>
Subject: Re: [HACKERS] someone working to add merge?
Message-ID: <20051125145501.GD16970@svana.org>
Reply-To: Martijn van Oosterhout <kleptog@svana.org>
References: <c2d9e70e0511110603q1799d811u6e4564be516b10ce@mail.gmail.com> <200511111924.41532.peter_e@gmx.net> <20561.1131734697@sss.pgh.pa.us> <200511112004.35876.peter_e@gmx.net> <20899.1131736841@sss.pgh.pa.us> <4384E54D.8000500@Yahoo.com> <20051124063034.GA18750@svana.org> <4385E636.4070503@Yahoo.com> <20051125121402.GB16970@svana.org> <43871C57.6060000@Yahoo.com>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="NklN7DEeGtkPCoo3"
Content-Disposition: inline
In-Reply-To: <43871C57.6060000@Yahoo.com>
User-Agent: Mutt/1.3.28i
X-PGP-Key-ID: Length=1024; ID=0x0DC67BE6
X-PGP-Key-Fingerprint: 295F A899 A81A 156D B522  48A7 6394 F08A 0DC6 7BE6
X-PGP-Key-URL: <http://svana.org/kleptog/0DC67BE6.pgp.asc>
X-Virus-Scanned: by amavisd-new at hub.org
X-Spam-Status: No, score=0 required=5 tests=[AWL=0.000]
X-Spam-Score: 0
X-Mailing-List: pgsql-hackers
List-Archive: <http://archives.postgresql.org/pgsql-hackers>
List-Help: <mailto:majordomo@postgresql.org?body=help>
List-Id: <pgsql-hackers.postgresql.org>
List-Owner: <mailto:pgsql-hackers-owner@postgresql.org>
List-Post: <mailto:pgsql-hackers@postgresql.org>
List-Subscribe: <mailto:majordomo@postgresql.org?body=sub%20pgsql-hackers>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Precedence: bulk
Sender: pgsql-hackers-owner@postgresql.org
Status: OR


--NklN7DEeGtkPCoo3
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Fri, Nov 25, 2005 at 09:14:47AM -0500, Jan Wieck wrote:
> Hmmm ... so you maintain that MERGE without an explicit LOCK TABLE, done=
=20
> by the user before performing the MERGE, can create duplicate rows (WRT=
=20
> the merge condition) and consequently raise a duplicate key error if=20
> there is a UNIQUE constraint.
>=20
> If that is what the standard describes, then it can be implemented=20
> without any sort of index or constraint requirement. The query tree for=
=20
> MERGE will have the INTO relation as a left outer join. In the case of a=
=20
> match of this outer join, one set of targetlist expressions is used to=20
> form the result tuple containing the INTO-relations ctid. That result=20
> tuple us useable for heap_update() or heap_delete(). In the case of=20
> no-match another set of target list expressions is used, suitable for=20
> heap_insert(). This way, MERGE will work with one single sequential scan=
=20
> of the INTO relation in case there is no suitable index.

Yes, that's the way I read the standard and how I was thinking it could
be implemented. It does simplify the case suggested by people that want
atomic REPLACE, because you only have one statement to repeat until you
get success.

do
   MERGE ...;
while( not error and modified_rows <> 1 )

I was thinking that we could make a seperate REPLACE command which can
only insert or update one row, but can do it atomically. Basically a
loop like above with builtin savepoints.

Alternativly, we could special case the MERGE-without-USING case, in
the cases where the plan simply devolves into an Index Scan, but I
don't like special casing. If we're going to have special semantics we
should have a seperate statement so it's clear that it's special.

Have a nice day,
--=20
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.

--NklN7DEeGtkPCoo3
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQFDhyXEIB7bNG8LQkwRAlxiAJ4tVMSPKRELg0H7na778cppeU1opACgkawW
xsYY7O6aMVjdXT4ye3fS6KI=
=XS8K
-----END PGP SIGNATURE-----

--NklN7DEeGtkPCoo3--