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 1icdUX-0002Tp-Ur for psycopg@arkaria.postgresql.org; Wed, 04 Dec 2019 22:51:30 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1icdTY-0001kk-6i for psycopg@arkaria.postgresql.org; Wed, 04 Dec 2019 22:50:28 +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 1icdTX-0001kX-TS for psycopg@lists.postgresql.org; Wed, 04 Dec 2019 22:50:28 +0000 Received: from mail-lj1-x241.google.com ([2a00:1450:4864:20::241]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1icdTV-0004NT-ED for psycopg@lists.postgresql.org; Wed, 04 Dec 2019 22:50:27 +0000 Received: by mail-lj1-x241.google.com with SMTP id e28so1171186ljo.9 for ; Wed, 04 Dec 2019 14:50:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=pofwrcyBh6NZQQGVZJiJNWLeIVJp0vj4kIsZqxASzY8=; b=tthqr4i0FPDcFhtx0wEl9XP75uNs8QJzbJLW5AjerAawZn32E88VsOTSmEXtOmIRMX 81AfBlvtBZEGypt77+TU/OOSl3F5lRj+H18KC497hDKnFJ4TN/fhM2IKR/pXMBthUBvi mALJyqUXWXOKBfdi2nHlW0qeGSbCUIFPlI4yE40LjfS/c4u6dqgVpzisC8XtLLOgoizg vc0DrAVsNEAP9WdOJnB/tzoC86jNZ+NeHeioZQF/S9kWy8FxEJCycxtMGuROIqHJkx3N 4r+iUjWr1UczAhY4ICz4SbYvxCZ9j+hZ1xT5BNKeJ1iipqP4y5Lxvp4AGcO10DuWmTCv MeHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=pofwrcyBh6NZQQGVZJiJNWLeIVJp0vj4kIsZqxASzY8=; b=nTN5v5xPvgUeDbwEBj44bVAUYijhG82jLrK8+PBfn8aFZ085/tuvcnb0xxa9Ue+xW8 SiIQ2i4ktLhNliFxUI89lo/xxB0FcI0QT/i4hohTbnjx7VghKQmHXPBfmAflwJn8sxJy 4cPJt4ESqa5syBoGMh7+bSkEGwBja8cKS2IMLQ+dK6GNAH2nDZK4BSojgucH6YM2y2mK oNuuQZR7Ka58EIi2hP8sD0fZPCpFgTm3FUWJOkVxLCFpNcdLrMPMU+SeYbOfbQbu25+P zRYUliq6deilnLngSp3EAMItG5L/FYfmXp3gbNFzUNUEcGVDGkFK+Bd1BnoIIcjizrF9 8eOw== X-Gm-Message-State: APjAAAW4jvcx5xxrD62fDmJXCUWRaB/feZHsYpXfnl0ouP+Tg2D4vLr/ vlKj2F7ytQApSeSzhmC9KnpLSddrCxpaSLIYqA8= X-Google-Smtp-Source: APXvYqwJGUIr0JFQAwba3682hz8TVGADL57rFdoJi2a458Uau8vwjdCTa6ZD3cVAcXwbVZJTHP/23N5DfgQtE/e8Cj8= X-Received: by 2002:a2e:95c4:: with SMTP id y4mr3595609ljh.38.1575499823286; Wed, 04 Dec 2019 14:50:23 -0800 (PST) MIME-Version: 1.0 References: <25c3598a-698f-8d0e-3659-791253b903ec@aklaver.com> <55fa8796-a91b-6560-604c-83dd77b17980@aklaver.com> In-Reply-To: From: Daniele Varrazzo Date: Wed, 4 Dec 2019 22:50:11 +0000 Message-ID: Subject: Re: Array of tuples as a parameter, with type casts To: Vladimir Ryabtsev Cc: Adrian Klaver , psycopg@lists.postgresql.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Wed, Dec 4, 2019 at 9:33 PM Vladimir Ryabtsev wro= te: > > Yes, I know it can be done with Json, too. I was particularly interested = if it can be controlled in psycopg2 module, because the serialization to AR= RAY[...] string is performed be the module and in this particular case expl= icit specification of types is required, but it seems like the module does = not provide any control over it... You can have control adding casts next to the placeholders, such as '%s::type'. For your case you can create a postgres composite type and cast the placeholder to '%s::mytype[]'. The problem in mapping Python lists to Postgres arrays is that in Python the list is _the_ type, whereas in Postgres arrays are "array of a type". In Python "type([1]) =3D=3D type(['a'])"; in Postgres they are not the same: "pg_typeof('{}'::text[]) !=3D pg_typeof('{}'::int[])". arrays are of homogeneous types different each other. There is no sane or efficient algorithm to attach a Postgres cast looking at a generic Python list. Do you look at the first argument? What if it's None (which in Python is always the same NoneType, whereas in Postgres NULL are typed)? What if the array is empty? The whole idea of attaching a cast to the values, as psycopg does for dates - typing in '2019-12-31'::date in the query, is actually a bad idea because that's passing a sql snippet to the query rather than a value, so it couldn't be used in server-side placeholder etc. However you can use the same trick, subclassing some of your type to make it adapt into a typed expression and solve types mismatches or ambigiuties. If instead of a tuple you use a type of yours, e.g. a namedtuple, you can make it adapt like super() does and appending a '::type', and ARRAY[] will work because it will try to sniff the type from the first argument (bets are off if it's None - no idea if Postgres will look at the first non-NULL, or will barf, and if it does what if your list is empty...). Or you can subclass the list instead and make its spew a '::mytype[]', which would work even if it's empty or contains None. Using a '%s::mytype[]' *into the query* is the best option IMO: usually if you are writing a certain query you know what types are involved, whereas values might be coming from far away. -- Daniele