Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kcIK1-00011x-F8 for psycopg@arkaria.postgresql.org; Tue, 10 Nov 2020 01:19:46 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1kcIJz-0007Xo-5B for psycopg@arkaria.postgresql.org; Tue, 10 Nov 2020 01:19:43 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kcIJy-0007Xh-40 for psycopg@lists.postgresql.org; Tue, 10 Nov 2020 01:19:42 +0000 Received: from wout1-smtp.messagingengine.com ([64.147.123.24]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kcIJq-0002Bz-Te for psycopg@postgresql.org; Tue, 10 Nov 2020 01:19:41 +0000 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 66ED1B55; Mon, 9 Nov 2020 20:19:32 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Mon, 09 Nov 2020 20:19:32 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aklaver.com; h= subject:to:cc:references:from:message-id:date:mime-version :in-reply-to:content-type:content-transfer-encoding; s=fm1; bh=r 0K/iPDLd0H5Emh5VXMc0litoJnNslHqLJlKw4Aq1bE=; b=IihV6yz69g3l3We9U qVM1jMcHIXUjDGbW4qewph/briQ7mSiP+rp0RstJdRjjlngI1NoUygfSlS7snJ8H vxlZ7XDm5jS/bq5qaoOMMRlWxl8N6MXx+bfgZnJW3wYOf8C7MMFwfeW1hOwtrVyD lRNGTwXXiqXHnY4jknw1LI6V/7/hkIEJeyHC9W6oJx/nF/ru6s9oitaFXlK5QIS9 0hY6DFkbF5eyGZ18azKUDOFgIX+A91eU/Y5zQpaEUQmtg4qU4tTq7nh+/ilIyNJx U/yp22/W1MJtZukwLjaOvjd+RxqIxzaMbcB2QBwWkpLYgfjdEMReRqNE2odHym1a /CJCg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc: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=r0K/iPDLd0H5Emh5VXMc0litoJnNslHqLJlKw4Aq1 bE=; b=E/uZoJROHoF2Xz31+5JEyzcHqJgM3liDT+PTSI1eqaigCkPssdAyXodGa 5kdYifU555eq9Y1rrEFdqPP0RXh8OEHnlikeTGjMeEFeq0f6lSeotlDnGLbuWLzh mLMybw78TvbHBye/vZSXkKJpeMbihoZpDRzPhq+uvU3HBY4oDfxrhkoGJN0B+w/k fUv4Ad5LtuPRpTlCq8Q2cGTjcMnpqZ5g/TGpKf1+noPEsoh5QG+lgp5DTuGP3YW+ ukVZqv2mKY2VQIeFuhH8i5fwLplJw3KklOYDrkd4JlCru3grWQJfr7dqeFpfWmO9 NsSsEngTfFmx0QjPvGcuM5HlVoolA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudduiedgfeegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepuffvfhfhkffffgggjggtgfesthejredttdefjeenucfhrhhomheptegurhhi rghnucfmlhgrvhgvrhcuoegrughrihgrnhdrkhhlrghvvghrsegrkhhlrghvvghrrdgtoh hmqeenucggtffrrghtthgvrhhnpeetjedvteffjeeuvdelieeffeehuedthffgvdfhhffh kedvudevgedvjedufefgveenucfkphepjeehrddujedvrdduledrudefleenucevlhhush htvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrughrihgrnhdrkhhl rghvvghrsegrkhhlrghvvghrrdgtohhm X-ME-Proxy: Received: from [192.168.1.4] (75-172-19-139.tukw.qwest.net [75.172.19.139]) by mail.messagingengine.com (Postfix) with ESMTPA id 455DA306307C; Mon, 9 Nov 2020 20:19:31 -0500 (EST) Subject: Re: psycopg3 and adaptation choices To: Daniele Varrazzo Cc: psycopg@postgresql.org References: <2b9859f0-0964-2baa-b6bc-13f975ae0f67@aklaver.com> <88fb7a7e-a182-a816-c1a7-8a1f54b65215@aklaver.com> From: Adrian Klaver Message-ID: <5d2207c6-cebb-082d-cf5b-a7a0fe8e58d4@aklaver.com> Date: Mon, 9 Nov 2020 17:19:30 -0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.4.1 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On 11/8/20 2:21 PM, Daniele Varrazzo wrote: > On Sun, 8 Nov 2020 at 20:35, Adrian Klaver wrote: > >> Alright I understand now. >> More below. >> >>> >>> In psycopg3 the idea is to use a more advanced protocol, which >>> separates query and parameters. It brings several benefits: can use >>> prepared statements (send a query once, several parameters later), >>> passing large data doesn't bloat the parser (the params don't hit the >>> lexer/parser), can use binary format (useful to pass large binary >>> blobs without escaping them in a textual form), the format of the data >>> is more homogeneous (no need to quoting), so we can use Python objects >>> in COPY instead of limiting the interface for the copy functions to >>> file-like objects only. >>> >>> Both in psycopg2 and 3 there is an adaptation from Python types to >>> Postgres string representation. In pg2 there is additional quoting, >>> because apart from numbers and bools you need to quote a literal >>> string to merge it to the query and make it syntactically valid. >> >> So the issue in the psycopg3 protocol is making the parameters that are >> passed in separately match up correctly in type to what the server is >> expecting(or can cast implicitly)? > > Yes, correct. What we have to choose is which Postgres oid to map to > each Python type. > > Sometimes the mapping is trivial (e.g. `datetime.date` -> `date` in > Postgres, `uuid.UUID` -> `uuid`...) > > Sometimes it might be ambiguous: is a `datetime.datetime` a > `timestamp` or a `timestamptz`? In some cases we don't care (here we > can say `timestamptz` no problem: if the Python datetime doesn't have > tzinfo, Postgres will use the `TimeZone` setting). > > Sometimes it's messy: what Python type corresponds to a Postgres > `jsonb`? It might be a dict, or a list, or types that have other > representations too (numbers, strings, bools). In this case, as in > psycopg2, there can be a wrapper, e.g. `Json`, to tell psycopg that > this dict, or list, or whatever else, must be jsonified for the db. > > When there are mismatches, sometimes the database cast rules help > (e.gi in the timestamp[tz] case). Sometimes not: if we say `text` to a > jsonb field, it will raise an error. Sometimes a cast is automatic on > inserting in a table but not on passing a function parameter. > > Numbers are messy, as they usually are: Python has int, float, > Decimal, Postgres has int2, int4, int8, float4, float8, numeric. The > mappings float -> float8 and Decimal -> numeric are more or less > straightforward. `int` is not, as in Python it's unbounded. If you say > `select 10` in psql, the server understands "unknown type, but a > number", and can try if either int* or numeric fit the context. But we > don't have the help from the syntax that psql has: because 10 doesn't > have quotes, Postgres is sure that it is a number, and not a string, > but executing query/params separately we lose that expressivity: we > cannot quote the strings and not the number. So choices are: > > 1. If we specify `numeric` or `int8` as oid, inserting in an int field > in a table will work ok, but some functions/operators won't (e.g. "1 What is not working here? >>> %s"). > 2. If we specify `int4` it would work for those few functions defined > as `integer`, but if we try to write a number that doesn't fit in 32 > bits into a Postgres bigint field I assume something will overflow > along the way, even if both python and postgres can handle it. > 3. If we specify `unknown` it might work more often, but > `cursor.execute("select %s", [10]) will return the string "10" instead > of a number. > > So I wonder what's the best compromise to do here: the less bad seems > 1. 3. might work in more contexts, but it's a very counterintuitive > behaviour, and roundtripping other objects (dates, uuid) works no > problem: they don't come back as strings. There is a lot to digest here. I'm going to have to do some thinking on this. > > -- Daniele > -- Adrian Klaver adrian.klaver@aklaver.com