Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1r5D2N-00CMJ5-6x for psycopg@arkaria.postgresql.org; Mon, 20 Nov 2023 22:46:39 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1r5D2L-00BI6L-Rh for psycopg@arkaria.postgresql.org; Mon, 20 Nov 2023 22:46:37 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1r5D2L-00BI6C-Kn for psycopg@lists.postgresql.org; Mon, 20 Nov 2023 22:46:37 +0000 Received: from mail-oa1-x30.google.com ([2001:4860:4864:20::30]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1r5D2I-006XqX-Ef for psycopg@postgresql.org; Mon, 20 Nov 2023 22:46:36 +0000 Received: by mail-oa1-x30.google.com with SMTP id 586e51a60fabf-1f5b92bba54so1548210fac.0 for ; Mon, 20 Nov 2023 14:46:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1700520394; x=1701125194; darn=postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=4cs9SU0iyqGDg11HuDSlwwdUNILtMv+ihSY/3/vDYGk=; b=dTux/BNObP8tCVZwPzRXSO8p1WccOdH/9vgaVLN7TavnzdOfeNsu1dkMU6ZHLyRoEH p4pnitTtk+A2+Fn2A2WCIbB1a/iPwwgQrS4ffkuHlgqYwVG2287vzsr42EarGe42KwJ2 vuO79KOmyry6tAT+O89pHju3S5rKJIiubn3Nk31LaNAVgDsO3Igvk3iMzE9E/sP1GERa 1sqxi+qn5EN2VelOnw196iBnA4jvHz1KWWNJcB9vS+k7BIe+NNfjbc5j4/4PfZmYHUGr 8AG+MzsEVPMI0trwOiuWkxM3hFTkr/V3CboihyrsnhjH3Z9j1g5niLv1DCjfr1wt4Xl2 QGRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700520394; x=1701125194; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=4cs9SU0iyqGDg11HuDSlwwdUNILtMv+ihSY/3/vDYGk=; b=MmVxQ8kBVryFan0PSV2uP+hJHIAz/mPHsdqzNWpg9KW8LxTHXB/c7AnWr3brwBheQb Etr3jKJ85dJe8UbIs16Bd2F7ZG4w3QXOFO5cysIVdWh+LW4ZPMeVjDl5u9+5MnrwWWU1 pL4MoRgwRt2pSYtuk5HqJyMq/XwPbugcjhU/FJgFUlPEykh5EDnESUfoTZ5wUSnlskU7 gK2X5s7K0xVETuXy8KUC3EN/Wt2xLd05s3B8t3oIfn++g6hQ7vPZJ+Xb1fFLNYVX7HYV veIpALjCNlsioaFBWbBhSsq/4VpLfC4gu6LyWeR5rwfnVFU9ouyodID6Hq1RMijyVXyK hUwA== X-Gm-Message-State: AOJu0YzrEplfXapFkK41Hq+o+meAUKIocv45S9EvfHDLGUvkJSVbNRLO JLvJoyuOK/yEzTTq1hBF56+vb6lGe949hsl1K3I= X-Google-Smtp-Source: AGHT+IHAHiQxDcTffrzLvQP2ENzd5Pg01VN9KDs80QDb8Lr6q20qs1ahElRdZ8GI6oayx29kmE4rv7EMrEAGpLudR6g= X-Received: by 2002:a05:6870:7d89:b0:1f4:d069:cb02 with SMTP id oq9-20020a0568707d8900b001f4d069cb02mr392848oab.21.1700520393694; Mon, 20 Nov 2023 14:46:33 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Daniele Varrazzo Date: Mon, 20 Nov 2023 22:46:21 +0000 Message-ID: Subject: Re: 2-to-3 Question about adapter using AsIs To: Ams Fwd Cc: psycopg@postgresql.org Content-Type: text/plain; charset="UTF-8" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hello, On Mon, 20 Nov 2023 at 19:58, Ams Fwd wrote: > As far as I can tell from the documentation the `sql.DEFAULT` should > be the appropriate thing to put in the dumper so that generated query > uses `'DEFAULT'` in the correct place during query generation. > > However when I do use this I run into > > > ??? > E TypeError: bytes or buffer expected, got > > psycopg_binary/pq/pqbuffer.pyx:111: TypeError > > which in some ways makes sense as `AsIs` previously did something > special and it's not the same? Looking at the code, it should merely > be doing `PyUnicode_AsUTF8String` but I am assuming that `sql.DEFAULT` > is not generating the appropriate quoted string? Psycopg 3 uses server-side binding (https://www.psycopg.org/psycopg3/docs/basic/from_pg2.html#server-side-binding); as a consequence, the DEFAULT value cannot be passed as a query argument, because it is an SQL construct, not a value. You can force client-side binding (like psycopg2 does) by using a ClientCursor instead of the ordinary Cursor class (https://www.psycopg.org/psycopg3/docs/advanced/cursors.html#client-side-binding-cursors). The ClientCursor will call the `quote()` method on the dumper (https://www.psycopg.org/psycopg3/docs/api/abc.html#psycopg.abc.Dumper.quote), which should return the value's literal (so, a normal SQL literal would need to be single-quoted; the DEFAULT singleton doesn't want quotes as it's not a value). So, your attempt was always right: your dumper should look like: class PostgresDefaultValueTypeDumper(Dumper): def dump(self, obj): raise NotImplementedError("can't represent DEFAULT as server-side value") def quote(self, obj): return b"DEFAULT" but you can only use `PostgresDefaultValueType` with a ClientCursor (or in a `sql.Literal()`); you can visualize the query that a client cursor would execute using the classic `mogrify()`: >>> cur = psycopg.ClientCursor(conn) >>> cur.mogrify("INSERT INTO tbl (f1, f2) VALUES (%s, %s)", [PostgresDefaultValueType(), "hell'o"]) "INSERT INTO tbl (f1, f2) VALUES (DEFAULT, 'hell''o')" However you need to negotiate with Django the creation of a client-side cursor. I don't know if Django normally uses, or allows to use them. It's easy to create one one-off, as you see from the example, but integration with the Django ORM is... left as exercise (you may ask Django people about it, they would be more informed than I am). The `sql.DEFAULT` object is not designed to be passed as value for a query. It can only participate in query composition using the psycopg.sql objects (https://www.psycopg.org/psycopg3/docs/api/sql.html), but using it would require coding a query execution in a way much more different than the normal query, for instance using `{}` placeholders, for instance: cur.execute(sql.SQL("INSERT INTO tbl (f1, f2) VALUES ({}, {})").format(sql.DEFAULT, "hell'o")) I would rather go the ClientCursor way in this case. Cheers -- Daniele