Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1ib4T9-0003EQ-ON for psycopg@arkaria.postgresql.org; Sat, 30 Nov 2019 15:15:35 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1ib4T8-0000V6-8h for psycopg@arkaria.postgresql.org; Sat, 30 Nov 2019 15:15:34 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1ib4T8-0000Uy-1j for psycopg@lists.postgresql.org; Sat, 30 Nov 2019 15:15:34 +0000 Received: from out4-smtp.messagingengine.com ([66.111.4.28]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1ib4T3-0000dz-Rf for psycopg@lists.postgresql.org; Sat, 30 Nov 2019 15:15:33 +0000 Received: from compute6.internal (compute6.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 59F3F22784; Sat, 30 Nov 2019 10:15:27 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute6.internal (MEProxy); Sat, 30 Nov 2019 10:15:27 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aklaver.com; h= subject:to:references:from:message-id:date:mime-version :in-reply-to:content-type:content-transfer-encoding; s=fm1; bh=N NT8PGV8fYXjSrEoA4EYjNKcm37n3fBRxcSlg1VDicI=; b=EAp+hFQCeNAtfF2Ep QrV263ammaYTvh+/M+m+Q4a0iLhK/J8nb8LX8i63V0k95Jg8V3VW8lX6gaNK4UfK u8IKORPi+wYyGJfh3uCNSsLuvJGaHKGu7x0wwYuocRDX3LcUmBCNvIPpdrM9RiT4 odQghKX+0Jjeggynn9hnZdQLuifGfC7phT1YGA7t5nDfovVrJCOFVnppTzOUTLCd 39z8VnJmpeoA9GPx3tO9fHbyr3PWozbYO7xmqFMkTvdF8jxybVXTzD1D9zSHYpSi D2pqy1TMV7zxHf0eQ6nlrw0FPfG9agKPF6ct8VoXlWsOJ2lt9RMlgCf5Mpk9YoGS Y7IJQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm1; bh=NNT8PGV8fYXjSrEoA4EYjNKcm37n3fBRxcSlg1VDi cI=; b=MhELuLJwnsMCUC8RootkW59EVVjeDCUKduVpTUfQOAlbPHUhZshoZ/ijK 5VgpAdg53ehlMB/QT3WdYGMNfTBOLtvPrnlIc0DZtligIfF60XA3Z2DVCvZweD1L qW6VJlY5dwGk/HPKucSKQPTukVDawik/8GzIwLacdotU5PA2F7ubbdR/7Y8y96P8 j9H9uBCPpyP2G4rmfnW9s9EJ8OtepnaXm6Q0NCl1fHnV52iIdqhguA+fFKDMkzAE QhvzxfpStyORSTDtZfQeeUfuqBSTRtJssGkXhnryXbnZo0b4ZZLNkoGE2NSMQ95X N/usgKt40aHVE5EOcvGP0PhbA/GIg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedufedrudejuddgjeehucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpefuvfhfhffkffgfgggjtgfgsehtke ertddtfeejnecuhfhrohhmpeetughrihgrnhcumfhlrghvvghruceorggurhhirghnrdhk lhgrvhgvrhesrghklhgrvhgvrhdrtghomheqnecukfhppedujeegrddvuddrieekrddvge efnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrughrihgrnhdrkhhlrghvvghrsegrkhhl rghvvghrrdgtohhmnecuvehluhhsthgvrhfuihiivgeptd X-ME-Proxy: Received: from [192.168.1.2] (174-21-68-243.tukw.qwest.net [174.21.68.243]) by mail.messagingengine.com (Postfix) with ESMTPA id A85BA80060; Sat, 30 Nov 2019 10:15:26 -0500 (EST) Subject: Re: Array of tuples as a parameter, with type casts To: Vladimir Ryabtsev , psycopg@lists.postgresql.org References: From: Adrian Klaver Message-ID: Date: Sat, 30 Nov 2019 07:15:25 -0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.7.2 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On 11/29/19 8:30 PM, Vladimir Ryabtsev wrote: > I have a query like this: > > query = ''' > insert into t > select * from unnest (%s) > as t1(c1 timestamp, c2 int) > ''' > > The reason of the approach is obviously reducing the number of server > roundtrips when inserting many rows. > Usage: > > from datetime import datetime > import psycopg2 > db = > psycopg2.connect('postgres://postgres:******@host/postgres?sslmode=prefer') > cur = db.cursor() > cur.execute(query, ([(datetime.now(), 1), (datetime.now(), 2)],)) > db.commit() > db.close() > > Recently they needed to extend the column set by a text and a bigint > columns. Neither of them works: > > from datetime import datetime > import psycopg2 > query = '''insert into t > select * from unnest (%s) > as t1(c1 timestamp, c2 int, c3 text, c4 bigint) > ''' > db = psycopg2.connect('postgres://postgres@localhost/postgres') > cur = db.cursor() > cur.execute(query, ([(datetime.now(), 1, 'abc', 100), (datetime.now(), > 2, 'xyz', 200)],)) > db.commit() > db.close() > > It throws: > psycopg2.errors.DatatypeMismatch: function return row and > query-specified return row do not match > DETAIL:  Returned type unknown at ordinal position 3, but query expects > text. > > The problem is that the library sends the following request to the DBMS: > > insert into t > select * from unnest (ARRAY[('2019-11-29T19:48:19.683310'::timestamp, 1, > 'abc', 100),('2019-11-29T19:48:19.683320'::timestamp, 2, 'xyz', 200)]) > as t1(c1 timestamp, c2 int, c3 text, c4 bigint) > > For whatever reason it fails with the above error, but OK, it is related > to Postgres, not to psycopg2. > I can make it work by specifying type casts for text and bigint columns: > > insert into t > select * from unnest (ARRAY[('2019-11-29T19:48:19.683310'::timestamp, 1, > 'abc'::text, 100::bigint),('2019-11-29T19:48:19.683320'::timestamp, 2, > 'xyz'::text, 200::bigint)]) > as t1(c1 timestamp, c2 int, c3 text, c4 bigint); On a hunch try changing: '''insert into t select * from unnest (%s) as t1(c1 timestamp, c2 int, c3 text, c4 bigint)''' to '''insert into t select * from unnest (%s) as t1(c1 timestamp, c2 int, c3 varchar, c4 bigint)''' > > But I need a way to make the psycopg2 module to do that. Another > workaround would be creation a row type for the desired set of columns > and casting %s to this type[], but I would not like to create additional > objects in the database because it is pretty much out of my control. > > Your help is very appreciated. > > P.S. I am aware of other solutions such as execute_batch(), > execute_values(), etc. Take this question as a theoretical one, I just > want to understand if user is able to control this particular aspect of > the module. > > psycopg2-binary==2.8.4 > Postgres ~ any -- Adrian Klaver adrian.klaver@aklaver.com