From kleptog@svana.org Thu Nov 17 07:33:25 2005 Return-path: 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 ; 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 To: Csaba Nagy cc: Zeugswetter Andreas DCP SD , Dann Corbit , Simon Riggs , Bruce Momjian , Rick Gigger , Tom Lane , Christopher Kings-Lynne , "Jim C. Nasby" , josh@agliodbs.com, pgsql-hackers@postgresql.org, Jaime Casanova , Peter Eisentraut Subject: Re: [HACKERS] MERGE vs REPLACE Message-ID: <20051117123250.GC22933@svana.org> Reply-To: Martijn van Oosterhout References: <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: 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 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: 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 ; 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 ; 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 ; 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 ; 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 cc: Martijn van Oosterhout , Zeugswetter Andreas DCP SD , Dann Corbit , Simon Riggs , Bruce Momjian , 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 In-Reply-To: <1132231474.10890.317.camel@coppola.muc.ecircle.de> References: <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 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 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Precedence: bulk Sender: pgsql-hackers-owner@postgresql.org Status: ORr Csaba Nagy 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: 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 ; 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 ; 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 ; 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 ; 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 ; 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 To: Tom Lane cc: Csaba Nagy , Martijn van Oosterhout , Zeugswetter Andreas DCP SD , Dann Corbit , Simon Riggs , Bruce Momjian , 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 Message-ID: <20051117151530.GU6026@ns.snowman.net> Mail-Followup-To: Tom Lane , Csaba Nagy , Martijn van Oosterhout , Zeugswetter Andreas DCP SD , Dann Corbit , Simon Riggs , Bruce Momjian , Rick Gigger , Christopher Kings-Lynne , "Jim C. Nasby" , josh@agliodbs.com, pgsql-hackers@postgresql.org, Jaime Casanova , Peter Eisentraut References: <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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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: 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 ; 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 To: Tom Lane cc: Csaba Nagy , Martijn van Oosterhout , Zeugswetter Andreas DCP SD , Dann Corbit , Simon Riggs , Bruce Momjian , 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 Message-ID: <20051117151530.GU6026@ns.snowman.net> Mail-Followup-To: Tom Lane , Csaba Nagy , Martijn van Oosterhout , Zeugswetter Andreas DCP SD , Dann Corbit , Simon Riggs , Bruce Momjian , Rick Gigger , Christopher Kings-Lynne , "Jim C. Nasby" , josh@agliodbs.com, pgsql-hackers@postgresql.org, Jaime Casanova , Peter Eisentraut References: <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: 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 ; 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 ; 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 ; 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 ; 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 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 Date: Thu, 17 Nov 2005 22:11:33 -0500 (EST) 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 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Precedence: bulk Sender: pgsql-hackers-owner@postgresql.org Status: OR Tom Lane wrote: > Csaba Nagy 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: 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 ; 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: Thread-Topic: [HACKERS] MERGE vs REPLACE Thread-Index: AcXr7dUIILx3WyhrREu/dEAzLwToBgABFVZw From: "Dann Corbit" To: "Bruce Momjian" , "Tom Lane" cc: "Csaba Nagy" , "Martijn van Oosterhout" , "Zeugswetter Andreas DCP SD" , "Simon Riggs" , "Rick Gigger" , "Christopher Kings-Lynne" , "Jim C. Nasby" , , , "Jaime Casanova" , "Peter Eisentraut" 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 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: 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 ; 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 ; 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 ; 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 ; 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 To: Bruce Momjian cc: Zeugswetter Andreas DCP SD , Csaba Nagy , Martijn van Oosterhout , Dann Corbit , Simon Riggs , Rick Gigger , Tom Lane , Christopher Kings-Lynne , "Jim C. Nasby" , , , Jaime Casanova , Peter Eisentraut Subject: Re: [HACKERS] MERGE vs REPLACE In-Reply-To: <200511180218.jAI2IPF04976@candle.pha.pa.us> Message-ID: 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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: 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 ; 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: Thread-Topic: [HACKERS] MERGE vs REPLACE Thread-Index: AcXr5pYcJO3ZR4d/RwebJDquaJx6SQARC+uA From: "Zeugswetter Andreas DCP SD" To: "Bruce Momjian" cc: "Csaba Nagy" , "Martijn van Oosterhout" , "Dann Corbit" , "Simon Riggs" , "Rick Gigger" , "Tom Lane" , "Christopher Kings-Lynne" , "Jim C. Nasby" , , , "Jaime Casanova" , "Peter Eisentraut" 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: 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 ; 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 ; 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 ; 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 ; 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 cc: Dennis Bjorklund , Zeugswetter Andreas DCP SD , Csaba Nagy , Martijn van Oosterhout , 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 In-Reply-To: <200511181520.jAIFKpW02114@candle.pha.pa.us> References: <200511181520.jAIFKpW02114@candle.pha.pa.us> Comments: In-reply-to Bruce Momjian 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 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Precedence: bulk Sender: pgsql-hackers-owner@postgresql.org Status: ORr Bruce Momjian 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: 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 ; 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 ; 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 ; 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 ; 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 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 Date: Sun, 20 Nov 2005 12:26:18 -0500 (EST) cc: Dennis Bjorklund , Zeugswetter Andreas DCP SD , Csaba Nagy , Martijn van Oosterhout , Dann Corbit , Simon Riggs , Rick Gigger , Christopher Kings-Lynne , "Jim C. Nasby" , josh@agliodbs.com, pgsql-hackers@postgresql.org, Jaime Casanova , Peter Eisentraut 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Precedence: bulk Sender: pgsql-hackers-owner@postgresql.org Status: OR Tom Lane wrote: > Bruce Momjian 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: 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 ; 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 ; 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 ; 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 ; 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" To: Bruce Momjian cc: mark@mark.mielke.cc, Tom Lane , Csaba Nagy , Martijn van Oosterhout , Zeugswetter Andreas DCP SD , Dann Corbit , Simon Riggs , Rick Gigger , Christopher Kings-Lynne , josh@agliodbs.com, pgsql-hackers@postgresql.org, Jaime Casanova , Peter Eisentraut 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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: 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 ; 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" To: Tom Lane , Csaba Nagy , Martijn van Oosterhout , Zeugswetter Andreas DCP SD , Dann Corbit , Simon Riggs , Bruce Momjian , Rick Gigger , Christopher Kings-Lynne , josh@agliodbs.com, pgsql-hackers@postgresql.org, Jaime Casanova , Peter Eisentraut Subject: Re: [HACKERS] MERGE vs REPLACE Message-ID: <20051121214630.GM19279@pervasive.com> References: <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: 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 ; 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 ; 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 ; 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 ; 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 User-Agent: Mozilla Thunderbird 1.0 (Windows/20041206) X-Accept-Language: cs, en, en-us MIME-Version: 1.0 To: "Jim C. Nasby" cc: PostgreSQL-development Subject: Re: [HACKERS] MERGE vs REPLACE References: <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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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: 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 ; 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 ; 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 ; 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 ; 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 To: Petr Jelinek cc: "Jim C. Nasby" , PostgreSQL-development Subject: Re: [HACKERS] MERGE vs REPLACE Message-ID: <20051122105747.GC12548@svana.org> Reply-To: Martijn van Oosterhout References: <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: 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 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: 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 ; 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 ; 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 ; 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 ; 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" To: Martijn van Oosterhout cc: Petr Jelinek , PostgreSQL-development Subject: Re: [HACKERS] MERGE vs REPLACE Message-ID: <20051122203045.GC99429@pervasive.com> References: <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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Precedence: bulk Sender: pgsql-hackers-owner@postgresql.org Status: OR On Tue, Nov 22, 2005 at 11:57:48AM +0100, Martijn van Oosterhout wrote: > 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: 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 ; 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 ; 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 ; 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 ; 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 To: Petr Jelinek cc: Jaime Casanova , PostgreSQL-development , "Jim C. Nasby" Subject: Re: [HACKERS] MERGE vs REPLACE Message-ID: <20051123090926.GA8374@svana.org> Reply-To: Martijn van Oosterhout References: <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> <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: 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 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: 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 ; 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 ; 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 ; 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 ; 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 User-Agent: Thunderbird 1.5 (Windows/20051025) MIME-Version: 1.0 To: Martijn van Oosterhout cc: PostgreSQL-development Subject: Re: [HACKERS] MERGE vs REPLACE References: <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> <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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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: 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 ; 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 ; 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 ; 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 ; 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 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 cc: Peter Eisentraut , pgsql-hackers@postgresql.org, Josh Berkus , Jaime Casanova Subject: Re: [HACKERS] someone working to add merge? References: <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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Precedence: bulk Sender: pgsql-hackers-owner@postgresql.org Status: OR On 11/11/2005 2:20 PM, Tom Lane wrote: > Peter Eisentraut 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: 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 ; 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 ; 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 ; 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 ; 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 To: Jan Wieck cc: Tom Lane , Peter Eisentraut , pgsql-hackers@postgresql.org, Josh Berkus , Jaime Casanova Subject: Re: [HACKERS] someone working to add merge? Message-ID: <20051124063034.GA18750@svana.org> Reply-To: Martijn van Oosterhout References: <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: 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 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: 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 ; 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 ; 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 ; 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 ; 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 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 cc: Tom Lane , Peter Eisentraut , pgsql-hackers@postgresql.org, Josh Berkus , Jaime Casanova Subject: Re: [HACKERS] someone working to add merge? References: <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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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: 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 ; 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 ; 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 ; 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 ; 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 To: Jan Wieck cc: Tom Lane , Peter Eisentraut , pgsql-hackers@postgresql.org, Josh Berkus , Jaime Casanova Subject: Re: [HACKERS] someone working to add merge? Message-ID: <20051125121402.GB16970@svana.org> Reply-To: Martijn van Oosterhout References: <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: 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 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: 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 ; 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 ; 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 ; 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 ; 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 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 cc: Tom Lane , Peter Eisentraut , pgsql-hackers@postgresql.org, Josh Berkus , Jaime Casanova Subject: Re: [HACKERS] someone working to add merge? References: <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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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: 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 ; 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 ; 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 ; 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 ; 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 To: Jan Wieck cc: Tom Lane , Peter Eisentraut , pgsql-hackers@postgresql.org, Josh Berkus , Jaime Casanova Subject: Re: [HACKERS] someone working to add merge? Message-ID: <20051125145501.GD16970@svana.org> Reply-To: Martijn van Oosterhout References: <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: 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: List-Help: List-Id: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 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--