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.96) (envelope-from ) id 1wbde3-002j9d-28 for pgsql-hackers@arkaria.postgresql.org; Mon, 22 Jun 2026 12:20:56 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wbde2-006Ug4-1z for pgsql-hackers@arkaria.postgresql.org; Mon, 22 Jun 2026 12:20:54 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wbde2-006Ufv-0b for pgsql-hackers@lists.postgresql.org; Mon, 22 Jun 2026 12:20:54 +0000 Received: from mail-ed1-x532.google.com ([2a00:1450:4864:20::532]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wbddz-00000001kmv-1JKe for pgsql-hackers@postgresql.org; Mon, 22 Jun 2026 12:20:53 +0000 Received: by mail-ed1-x532.google.com with SMTP id 4fb4d7f45d1cf-693c69b97e7so7066982a12.2 for ; Mon, 22 Jun 2026 05:20:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb.com; s=google; t=1782130849; x=1782735649; darn=postgresql.org; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:from:to:cc:subject:date:message-id:reply-to; bh=HMCH3c0kRrALdqd1DF5MzYSJdhvx9HXVP3wENiFy7rk=; b=U/enipUqeTl2AuCEY/0xS3MvL2bIfASMGtMgexOyPqnzTJamK5gWbPxeqZXu9tTv8l rAUxDojFdy4emlLACeJEdu4TOQBigjVz7YFJ6FaxKuJUkv3IycjWpZuKW9Rvxray5f0Q qPUqgwIF0WJZzM7lAOdHxj0DRF9xq2tHZONX5+U4dDPbzdSV+53sCzJToZofUytB5LbR ZtWSWrib2CfX9+02fgkjRMX91jxZdp6MwU33OkpN/j7hiWDW1f14DstGBka9ln0cLaTA dafTlrPSLXdxA9dAxUPtEWDgzMUeMApQUdRW2R4uZEWZ0SDWtXt2eMVdKq41GQGMsFhr FGsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782130849; x=1782735649; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=HMCH3c0kRrALdqd1DF5MzYSJdhvx9HXVP3wENiFy7rk=; b=nFSw/16xNjyePtd16nBT0NuKEuwcTW8yYk5elOSV8JC8vbAiPwsrJlxWi3G3fpw/Da jkx1k8v/57PIXCdnqpUTe7onTbic1UQaalN6uJlT8kyoXWhmlPNEgwfC6LL0Revat94l Y0kldJVNktsKZmXIlnmrLbSkjxdAC8sYrwvk44ozkPnp8v9/ns3RvVhFFMw4GVphq+z2 5fEVpyU3IuaJo2zpka0icow9tiUTLy/mCchs8q04a2pSzCfwHozFxgLb53eCkDhXWURd u5Xw37SRK3gWJeLSv6/2WV6fupNxqYZLH958kzAphjVtOWXSJOfABZVvCteOjZUgveAX 9ryg== X-Forwarded-Encrypted: i=1; AFNElJ9z5I9HrTTEe1VGQKmrTEovNqXNIv9uxuG7bP/lRu1XM/NzODYx9gjOYYHmGNwDvc9rhjw9uDwYbeY3pLQZ@postgresql.org X-Gm-Message-State: AOJu0Yz0PR3XTjTgDcrD9nTG+WBlvUC6dSCJLjz1uqAHI9gZiYHXCB42 KWixzQLDa9WXppZOmVToR+aFbAb1YQjkjhRRP+dWnP4A/0JXj9duU4T+fSd2jHjnRSZM5uMzIFV 34R818/xhpsU= X-Gm-Gg: AfdE7clMQF9hA3QQFXQPT/bwaSB7oj+mkzHZgYKn9vwn+wKemYKfw/iS8WysB/7seba CtNij4V+0W2KenJJFYm8dED1YeASNHLa22tR9nclWBqj2NMItHJUkG10+5n3sdUOakfDd9b/y2/ hGB2vJoBZX/pYeaDArZToDbnKR/rL5ZD3RPHVCfA0cBRw/5ozksNU2Tv6Dd2YTPeMh45wvd7Xl5 mQeDMCIAmhkXPv10NzIAAF/w9pkOYbcw7I1Tg5CjAXubZIddvwyLDMoPA8+o6XiOjMfIp9deIW6 VWDNx9iZRnXAJCxIqAuDwztOSh9AKnEH6q1f7FUY/3TSjlgNF17UtlY1UJFEAbGJNJkJLkqx2zQ wf1hV56380+NW3gYD9YISecRyRHA59F5HGUYTX1XuUXkYJUFifNo0oYF21o9v4ejMwqTJfTdB7V 8+3BWMxeWL4V+eQqHl7sDB1tqtgTDnN5Qz1iAAeuJL21bFmAOLbaZD92Q0m9EMMSQRyystzB8TT Q== X-Received: by 2002:a17:907:3f86:b0:bfe:7147:2ed6 with SMTP id a640c23a62f3a-c097c9bbe3cmr700765966b.27.1782130848561; Mon, 22 Jun 2026 05:20:48 -0700 (PDT) Received: from smtpclient.apple ([2a02:a03f:61b7:f401:1d9e:8efc:f86d:c829]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c0c60ac92c6sm350504866b.41.2026.06.22.05.20.47 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 22 Jun 2026 05:20:48 -0700 (PDT) From: Maxime Schoemans Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_BEEF4960-8ACC-4524-9DA5-644B9C506315" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Re: [PATCH] btree_gist: add cross-type integer operator support for GiST Date: Mon, 22 Jun 2026 14:20:37 +0200 In-Reply-To: <80ef3b41-1a71-47a4-a320-29e118d7092c@Spark> Cc: Andrey Borodin , pgsql-hackers mailing list To: Alexander Nestorov References: <36b4f67d-5975-452c-a6b8-b6407f0924ee@Spark> <4B4B0998-7B43-4893-9603-0AF212036690@yandex-team.ru> <18e88767-6c31-402a-887e-37c38b366a6a@Spark> <80ef3b41-1a71-47a4-a320-29e118d7092c@Spark> X-Mailer: Apple Mail (2.3864.600.51.1.1) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_BEEF4960-8ACC-4524-9DA5-644B9C506315 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii Hi Alexander, Thank you for bringing this thread to my attention, this is a very interesting proposal. Personally, I have some doubts about the way cross-type operators are handled in GiST, but this is another issue. Within the current framework, this proposal implements things correctly, so I have no conceptual issue with it. Concerning the implementation itself, I have a couple comments: 1. In the consistent functions, I believe `subtype` can never be `InvalidOid` based on the current code. It probably doesn't hurt to keep it in the condition, but personally I'd drop it. Either way, I thought it was worth mentioning. 2. I'm not sure I like the approach of casting everything to an `int64` and using a new `gbt_int_consistent_x` function. It works, so if others have no problem with it I can accept it, but I have another suggestion: re-use `gbt_num_consistent` even for cross-type cases by creating cross-type `gbtree_ninfo` objects with cross-type `f_gt`, `f_ge`, `f_eq`, etc. functions. I have attached a v3 patchset with patch 0003 containing my suggestions. Feel free to take them or leave them as you see fit. This suggestion requires one important change in `gbt_num_consistent`: ``` else - retval = (tinfo->f_le(key->lower, query, flinfo) && + retval = (tinfo->f_ge(query, key->lower, flinfo) && tinfo->f_le(query, key->upper, flinfo)); break; ``` This is to make sure that `gbt_num_consistent` call all the comparison functions with `query` on the left and `key->lower/upper` on the right, to allow for cross-type comparison functions in `tinfo`. 0003 keeps your SQL/catalog work unchanged, compiles cleanly, and passes the existing btree_gist regression including the cross-type cases in 0002 (with the SRF-based catalog-drift check dropped, per point 3). 3. This is related to my suggestion in 2. as it removes the `gbt_int_crosstype_subtypes` SQL function (there is no `gbt_int_crosstype_table` anymore in C). Instead, the `switch` clause in the consistent functions raises an error in its default path, so RHS types that are not handled can be caught quickly. As you mention, I don't think there is a way to catch such issues at index validation time, so this is the best I could think of. Note that in theory we could put the `gbtree_ninfo` objects in a table and then write a function equivalent to `gbt_int_crosstype_subtypes` to still have the test you suggested, but I think that switch statements are a bit clearer and perhaps more efficient than looping through a table for the dispatch. To me this is similar to adding new same-type operators to a GiST opclass. Nothing checks at validation time that all the operators in the opclass are effectively handled by the given consistent function. So I don't see it as a problem to have the same behaviour for the cross-type operators. Other than that, this is a good proposal and definitely something worth having in postgres. Please let me know what you think of my suggestions. Best regards, Maxime --Apple-Mail=_BEEF4960-8ACC-4524-9DA5-644B9C506315 Content-Disposition: attachment; filename=v3-0001-Implement-cross-type-operators-for-GiST-indexes.patch Content-Type: application/applefile; name="v3-0001-Implement-cross-type-operators-for-GiST-indexes.patch" Content-Transfer-Encoding: base64 AAUWAAACAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAJAAAAMgAAAAoAAAADAAAAPAAAAD0AAAAAAAAA AAAAdjMtMDAwMS1JbXBsZW1lbnQtY3Jvc3MtdHlwZS1vcGVyYXRvcnMtZm9yLUdpU1QtaW5kZXhl cy5wYXRjaA== --Apple-Mail=_BEEF4960-8ACC-4524-9DA5-644B9C506315 Content-Disposition: attachment; filename=v3-0002-Add-tests-for-cross-type-operators-for-GiST-index.patch Content-Type: application/applefile; name="v3-0002-Add-tests-for-cross-type-operators-for-GiST-index.patch" Content-Transfer-Encoding: base64 AAUWAAACAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAJAAAAMgAAAAoAAAADAAAAPAAAAD8AAAAAAAAA AAAAdjMtMDAwMi1BZGQtdGVzdHMtZm9yLWNyb3NzLXR5cGUtb3BlcmF0b3JzLWZvci1HaVNULWlu ZGV4LnBhdGNo --Apple-Mail=_BEEF4960-8ACC-4524-9DA5-644B9C506315 Content-Disposition: attachment; filename=v3-0003-Reuse-gbt_num_consistent-for-cross-type-integer-c.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v3-0003-Reuse-gbt_num_consistent-for-cross-type-integer-c.patch" Content-Transfer-Encoding: quoted-printable =46rom=20347ed8923363a2ea0a7d4e348603825c6783cbf7=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Maxime=20Schoemans=20= =0ADate:=20Mon,=2022=20Jun=202026=20= 13:31:41=20+0200=0ASubject:=20[PATCH=20v3=203/3]=20Reuse=20= gbt_num_consistent=20for=20cross-type=20integer=0A=20comparisons=0A=0A= ---=0A=20contrib/btree_gist/btree_gist--1.9--1.10.sql=20=20|=20=2013=20= +-=0A=20contrib/btree_gist/btree_int2.c=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=2098=20+++++++---=0A=20contrib/btree_gist/btree_int4.c=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20|=20=2098=20+++++++---=0A=20= contrib/btree_gist/btree_int8.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=2098=20+++++++---=0A=20contrib/btree_gist/btree_utils_num.c=20=20= =20=20=20=20=20=20=20=20|=20169=20+-----------------=0A=20= contrib/btree_gist/btree_utils_num.h=20=20=20=20=20=20=20=20=20=20|=20=20= 55=20++++--=0A=20contrib/btree_gist/expected/int_crosstype.out=20|=20=20= 63=20+------=0A=20contrib/btree_gist/sql/int_crosstype.sql=20=20=20=20=20= =20|=20=2060=20+------=0A=208=20files=20changed,=20289=20insertions(+),=20= 365=20deletions(-)=0A=0Adiff=20--git=20= a/contrib/btree_gist/btree_gist--1.9--1.10.sql=20= b/contrib/btree_gist/btree_gist--1.9--1.10.sql=0Aindex=20= c9ff1955204..9cd57455086=20100644=0A---=20= a/contrib/btree_gist/btree_gist--1.9--1.10.sql=0A+++=20= b/contrib/btree_gist/btree_gist--1.9--1.10.sql=0A@@=20-10,8=20+10,8=20@@=0A= =20--=20left/right=20input=20types,=20so=20the=20catalog=20additions=20= below=20are=20deliberately=0A=20--=20pg_amop-only.=20The=20existing=20= consistent/distance=20support=20functions=20dispatch=0A=20--=20on=20the=20= subtype=20OID:=20same-type=20queries=20take=20the=20normal=20path,=20= while=20mixed-width=0A---=20integer=20queries=20are=20promoted=20to=20= int64=20and=20compared=20by=20the=20integer=20cross-type=0A---=20helpers=20= in=20btree_utils_num.c.=0A+--=20integer=20queries=20select=20a=20= cross-type=20comparison=20callback=20that=20reads=20the=20query=0A+--=20= and=20key=20sides=20at=20their=20own=20widths=20(see=20= btree_int{2,4,8}.c).=0A=20=0A=20CREATE=20FUNCTION=20int2_int4_dist(int2,=20= int4)=0A=20RETURNS=20int4=0A@@=20-43,15=20+43,6=20@@=20RETURNS=20int8=0A=20= AS=20'MODULE_PATHNAME'=0A=20LANGUAGE=20C=20IMMUTABLE=20STRICT=20PARALLEL=20= SAFE;=0A=20=0A---=20Introspection=20helper=20exposing=20the=20integer=20= query=20subtypes=20understood=20by=20the=20C=0A---=20cross-type=20= dispatch=20(gbt_int_crosstype_table=20in=20btree_utils_num.c).=20The=0A= ---=20regression=20tests=20use=20it=20to=20assert=20that=20the=20= cross-type=20pg_amop=20entries=20below=0A---=20never=20drift=20from=20= what=20the=20dispatch=20can=20handle.=0A-CREATE=20FUNCTION=20= gbt_int_crosstype_subtypes()=0A-RETURNS=20SETOF=20oid=0A-AS=20= 'MODULE_PATHNAME'=0A-LANGUAGE=20C=20IMMUTABLE=20PARALLEL=20SAFE;=0A-=0A=20= CREATE=20OPERATOR=20<->=20(=0A=20=09LEFTARG=20=3D=20int2,=0A=20=09= RIGHTARG=20=3D=20int4,=0Adiff=20--git=20= a/contrib/btree_gist/btree_int2.c=20b/contrib/btree_gist/btree_int2.c=0A= index=20d00b24d9a57..ea9c206e552=20100644=0A---=20= a/contrib/btree_gist/btree_int2.c=0A+++=20= b/contrib/btree_gist/btree_int2.c=0A@@=20-91,6=20+91,72=20@@=20static=20= const=20gbtree_ninfo=20tinfo=20=3D=0A=20=09gbt_int2_dist=0A=20};=0A=20=0A= +/*=0A+=20*=20Cross-type=20GiST=20callbacks:=20the=20indexed=20key=20is=20= int2,=20the=20query=20is=20int4=20or=0A+=20*=20int8.=20=20Both=20reuse=20= gbt_num_consistent()/gbt_num_distance()=20via=20a=20tinfo=20whose=0A+=20= *=20comparison/distance=20callbacks=20read=20the=20query=20(left)=20and=20= key=20(right)=20sides=20at=0A+=20*=20their=20own=20widths.=20=20f_cmp=20= is=20unused=20on=20these=20paths=20and=20left=20NULL.=0A+=20*/=0A= +GBT_INT_CMP_FNS(gbt_int2_q4_,=20int32,=20int16)=0A= +GBT_INT_CMP_FNS(gbt_int2_q8_,=20int64,=20int16)=0A+=0A+static=20const=20= gbtree_ninfo=20tinfo_q4=20=3D=0A+{=0A+=09gbt_t_int2,=0A+=09= sizeof(int16),=0A+=094,=0A+=09gbt_int2_q4_gt,=0A+=09gbt_int2_q4_ge,=0A+=09= gbt_int2_q4_eq,=0A+=09gbt_int2_q4_le,=0A+=09gbt_int2_q4_lt,=0A+=09NULL,=0A= +=09gbt_int2_q4_dist=0A+};=0A+=0A+static=20const=20gbtree_ninfo=20= tinfo_q8=20=3D=0A+{=0A+=09gbt_t_int2,=0A+=09sizeof(int16),=0A+=094,=0A+=09= gbt_int2_q8_gt,=0A+=09gbt_int2_q8_ge,=0A+=09gbt_int2_q8_eq,=0A+=09= gbt_int2_q8_le,=0A+=09gbt_int2_q8_lt,=0A+=09NULL,=0A+=09gbt_int2_q8_dist=0A= +};=0A+=0A+/*=0A+=20*=20Cross-type=20dispatch=20shared=20by=20= gbt_int2_consistent=20and=20gbt_int2_distance:=0A+=20*=20select=20the=20= tinfo=20for=20the=20query=20subtype=20and=20read=20the=20query=20value=20= at=20its=20own=0A+=20*=20width=20into=20caller-owned=20storage.=0A+=20*/=0A= +static=20const=20gbtree_ninfo=20*=0A+gbt_int2_crosstype(Oid=20subtype,=20= Datum=20d,=20gbt_intkey=20*q,=20const=20void=20**qp)=0A+{=0A+=09switch=20= (subtype)=0A+=09{=0A+=09=09case=20INT2OID:=0A+=09=09=09q->i2=20=3D=20= DatumGetInt16(d);=0A+=09=09=09*qp=20=3D=20&q->i2;=0A+=09=09=09return=20= &tinfo;=0A+=09=09case=20INT4OID:=0A+=09=09=09q->i4=20=3D=20= DatumGetInt32(d);=0A+=09=09=09*qp=20=3D=20&q->i4;=0A+=09=09=09return=20= &tinfo_q4;=0A+=09=09case=20INT8OID:=0A+=09=09=09q->i8=20=3D=20= DatumGetInt64(d);=0A+=09=09=09*qp=20=3D=20&q->i8;=0A+=09=09=09return=20= &tinfo_q8;=0A+=09=09default:=0A+=09=09=09elog(ERROR,=20"unrecognized=20= subtype=20%u=20for=20btree_gist=20int2=20cross-type=20comparison",=0A+=09= =09=09=09=20subtype);=0A+=09=09=09return=20NULL;=09=09/*=20keep=20= compiler=20quiet=20*/=0A+=09}=0A+}=0A+=0A=20=0A=20= PG_FUNCTION_INFO_V1(int2_dist);=0A=20Datum=0A@@=20-176,7=20+242,9=20@@=20= gbt_int2_consistent(PG_FUNCTION_ARGS)=0A=20=09Oid=09=09=09subtype=20=3D=20= PG_GETARG_OID(3);=0A=20=09bool=09=20=20=20*recheck=20=3D=20(bool=20*)=20= PG_GETARG_POINTER(4);=0A=20=09int16KEY=20=20=20*kkk=20=3D=20(int16KEY=20= *)=20DatumGetPointer(entry->key);=0A-=09int16=09=09query;=0A+=09const=20= gbtree_ninfo=20*ti;=0A+=09gbt_intkey=09query;=0A+=09const=20void=20*qp;=0A= =20=09GBT_NUMKEY_R=20key;=0A=20=0A=20=09/*=20All=20cases=20served=20by=20= this=20function=20are=20exact=20*/=0A@@=20-185,17=20+253,10=20@@=20= gbt_int2_consistent(PG_FUNCTION_ARGS)=0A=20=09key.lower=20=3D=20= (GBT_NUMKEY=20*)=20&kkk->lower;=0A=20=09key.upper=20=3D=20(GBT_NUMKEY=20= *)=20&kkk->upper;=0A=20=0A-=09if=20(likely(subtype=20=3D=3D=20InvalidOid=20= ||=20subtype=20=3D=3D=20INT2OID))=0A-=09{=0A-=09=09query=20=3D=20= DatumGetInt16(queryDatum);=0A-=09=09= PG_RETURN_BOOL(gbt_num_consistent(&key,=20&query,=20&strategy,=0A-=09=09=09= =09=09=09=09=09=09=09=20=20GIST_LEAF(entry),=20&tinfo,=0A-=09=09=09=09=09= =09=09=09=09=09=20=20fcinfo->flinfo));=0A-=09}=0A+=09ti=20=3D=20= gbt_int2_crosstype(subtype,=20queryDatum,=20&query,=20&qp);=0A=20=0A-=09= PG_RETURN_BOOL(gbt_int_consistent_x((int64)=20kkk->lower,=20(int64)=20= kkk->upper,=0A-=09=09=09=09=09=09=09=09=09=09queryDatum,=20subtype,=20= &strategy,=0A-=09=09=09=09=09=09=09=09=09=09GIST_LEAF(entry)));=0A+=09= PG_RETURN_BOOL(gbt_num_consistent(&key,=20qp,=20&strategy,=20= GIST_LEAF(entry),=0A+=09=09=09=09=09=09=09=09=09=20=20ti,=20= fcinfo->flinfo));=0A=20}=0A=20=0A=20Datum=0A@@=20-205,21=20+266,18=20@@=20= gbt_int2_distance(PG_FUNCTION_ARGS)=0A=20=09Datum=09=09queryDatum=20=3D=20= PG_GETARG_DATUM(1);=0A=20=09Oid=09=09=09subtype=20=3D=20= PG_GETARG_OID(3);=0A=20=09int16KEY=20=20=20*kkk=20=3D=20(int16KEY=20*)=20= DatumGetPointer(entry->key);=0A-=09int16=09=09query;=0A+=09const=20= gbtree_ninfo=20*ti;=0A+=09gbt_intkey=09query;=0A+=09const=20void=20*qp;=0A= =20=09GBT_NUMKEY_R=20key;=0A=20=0A=20=09key.lower=20=3D=20(GBT_NUMKEY=20= *)=20&kkk->lower;=0A=20=09key.upper=20=3D=20(GBT_NUMKEY=20*)=20= &kkk->upper;=0A=20=0A-=09if=20(likely(subtype=20=3D=3D=20InvalidOid=20||=20= subtype=20=3D=3D=20INT2OID))=0A-=09{=0A-=09=09query=20=3D=20= DatumGetInt16(queryDatum);=0A-=09=09= PG_RETURN_FLOAT8(gbt_num_distance(&key,=20&query,=20GIST_LEAF(entry),=0A= -=09=09=09=09=09=09=09=09=09=09=20=20&tinfo,=20fcinfo->flinfo));=0A-=09}=0A= +=09ti=20=3D=20gbt_int2_crosstype(subtype,=20queryDatum,=20&query,=20= &qp);=0A=20=0A-=09PG_RETURN_FLOAT8(gbt_int_distance_x((int64)=20= kkk->lower,=20(int64)=20kkk->upper,=0A-=09=09=09=09=09=09=09=09=09=09= queryDatum,=20subtype));=0A+=09PG_RETURN_FLOAT8(gbt_num_distance(&key,=20= qp,=20GIST_LEAF(entry),=0A+=09=09=09=09=09=09=09=09=09=20=20ti,=20= fcinfo->flinfo));=0A=20}=0A=20=0A=20Datum=0Adiff=20--git=20= a/contrib/btree_gist/btree_int4.c=20b/contrib/btree_gist/btree_int4.c=0A= index=204df91f2057c..7e566890143=20100644=0A---=20= a/contrib/btree_gist/btree_int4.c=0A+++=20= b/contrib/btree_gist/btree_int4.c=0A@@=20-89,6=20+89,72=20@@=20static=20= const=20gbtree_ninfo=20tinfo=20=3D=0A=20=09gbt_int4_dist=0A=20};=0A=20=0A= +/*=0A+=20*=20Cross-type=20GiST=20callbacks:=20the=20indexed=20key=20is=20= int4,=20the=20query=20is=20int2=20or=0A+=20*=20int8.=20=20Both=20reuse=20= gbt_num_consistent()/gbt_num_distance()=20via=20a=20tinfo=20whose=0A+=20= *=20comparison/distance=20callbacks=20read=20the=20query=20(left)=20and=20= key=20(right)=20sides=20at=0A+=20*=20their=20own=20widths.=20=20f_cmp=20= is=20unused=20on=20these=20paths=20and=20left=20NULL.=0A+=20*/=0A= +GBT_INT_CMP_FNS(gbt_int4_q2_,=20int16,=20int32)=0A= +GBT_INT_CMP_FNS(gbt_int4_q8_,=20int64,=20int32)=0A+=0A+static=20const=20= gbtree_ninfo=20tinfo_q2=20=3D=0A+{=0A+=09gbt_t_int4,=0A+=09= sizeof(int32),=0A+=098,=0A+=09gbt_int4_q2_gt,=0A+=09gbt_int4_q2_ge,=0A+=09= gbt_int4_q2_eq,=0A+=09gbt_int4_q2_le,=0A+=09gbt_int4_q2_lt,=0A+=09NULL,=0A= +=09gbt_int4_q2_dist=0A+};=0A+=0A+static=20const=20gbtree_ninfo=20= tinfo_q8=20=3D=0A+{=0A+=09gbt_t_int4,=0A+=09sizeof(int32),=0A+=098,=0A+=09= gbt_int4_q8_gt,=0A+=09gbt_int4_q8_ge,=0A+=09gbt_int4_q8_eq,=0A+=09= gbt_int4_q8_le,=0A+=09gbt_int4_q8_lt,=0A+=09NULL,=0A+=09gbt_int4_q8_dist=0A= +};=0A+=0A+/*=0A+=20*=20Cross-type=20dispatch=20shared=20by=20= gbt_int4_consistent=20and=20gbt_int4_distance:=0A+=20*=20select=20the=20= tinfo=20for=20the=20query=20subtype=20and=20read=20the=20query=20value=20= at=20its=20own=0A+=20*=20width=20into=20caller-owned=20storage.=0A+=20*/=0A= +static=20const=20gbtree_ninfo=20*=0A+gbt_int4_crosstype(Oid=20subtype,=20= Datum=20d,=20gbt_intkey=20*q,=20const=20void=20**qp)=0A+{=0A+=09switch=20= (subtype)=0A+=09{=0A+=09=09case=20INT2OID:=0A+=09=09=09q->i2=20=3D=20= DatumGetInt16(d);=0A+=09=09=09*qp=20=3D=20&q->i2;=0A+=09=09=09return=20= &tinfo_q2;=0A+=09=09case=20INT4OID:=0A+=09=09=09q->i4=20=3D=20= DatumGetInt32(d);=0A+=09=09=09*qp=20=3D=20&q->i4;=0A+=09=09=09return=20= &tinfo;=0A+=09=09case=20INT8OID:=0A+=09=09=09q->i8=20=3D=20= DatumGetInt64(d);=0A+=09=09=09*qp=20=3D=20&q->i8;=0A+=09=09=09return=20= &tinfo_q8;=0A+=09=09default:=0A+=09=09=09elog(ERROR,=20"unrecognized=20= subtype=20%u=20for=20btree_gist=20int4=20cross-type=20comparison",=0A+=09= =09=09=09=20subtype);=0A+=09=09=09return=20NULL;=09=09/*=20keep=20= compiler=20quiet=20*/=0A+=09}=0A+}=0A+=0A=20=0A=20= PG_FUNCTION_INFO_V1(int4_dist);=0A=20Datum=0A@@=20-174,7=20+240,9=20@@=20= gbt_int4_consistent(PG_FUNCTION_ARGS)=0A=20=09Oid=09=09=09subtype=20=3D=20= PG_GETARG_OID(3);=0A=20=09bool=09=20=20=20*recheck=20=3D=20(bool=20*)=20= PG_GETARG_POINTER(4);=0A=20=09int32KEY=20=20=20*kkk=20=3D=20(int32KEY=20= *)=20DatumGetPointer(entry->key);=0A-=09int32=09=09query;=0A+=09const=20= gbtree_ninfo=20*ti;=0A+=09gbt_intkey=09query;=0A+=09const=20void=20*qp;=0A= =20=09GBT_NUMKEY_R=20key;=0A=20=0A=20=09/*=20All=20cases=20served=20by=20= this=20function=20are=20exact=20*/=0A@@=20-183,17=20+251,10=20@@=20= gbt_int4_consistent(PG_FUNCTION_ARGS)=0A=20=09key.lower=20=3D=20= (GBT_NUMKEY=20*)=20&kkk->lower;=0A=20=09key.upper=20=3D=20(GBT_NUMKEY=20= *)=20&kkk->upper;=0A=20=0A-=09if=20(likely(subtype=20=3D=3D=20InvalidOid=20= ||=20subtype=20=3D=3D=20INT4OID))=0A-=09{=0A-=09=09query=20=3D=20= DatumGetInt32(queryDatum);=0A-=09=09= PG_RETURN_BOOL(gbt_num_consistent(&key,=20&query,=20&strategy,=0A-=09=09=09= =09=09=09=09=09=09=09=20=20GIST_LEAF(entry),=20&tinfo,=0A-=09=09=09=09=09= =09=09=09=09=09=20=20fcinfo->flinfo));=0A-=09}=0A+=09ti=20=3D=20= gbt_int4_crosstype(subtype,=20queryDatum,=20&query,=20&qp);=0A=20=0A-=09= PG_RETURN_BOOL(gbt_int_consistent_x((int64)=20kkk->lower,=20(int64)=20= kkk->upper,=0A-=09=09=09=09=09=09=09=09=09=09queryDatum,=20subtype,=20= &strategy,=0A-=09=09=09=09=09=09=09=09=09=09GIST_LEAF(entry)));=0A+=09= PG_RETURN_BOOL(gbt_num_consistent(&key,=20qp,=20&strategy,=20= GIST_LEAF(entry),=0A+=09=09=09=09=09=09=09=09=09=20=20ti,=20= fcinfo->flinfo));=0A=20}=0A=20=0A=20Datum=0A@@=20-203,21=20+264,18=20@@=20= gbt_int4_distance(PG_FUNCTION_ARGS)=0A=20=09Datum=09=09queryDatum=20=3D=20= PG_GETARG_DATUM(1);=0A=20=09Oid=09=09=09subtype=20=3D=20= PG_GETARG_OID(3);=0A=20=09int32KEY=20=20=20*kkk=20=3D=20(int32KEY=20*)=20= DatumGetPointer(entry->key);=0A-=09int32=09=09query;=0A+=09const=20= gbtree_ninfo=20*ti;=0A+=09gbt_intkey=09query;=0A+=09const=20void=20*qp;=0A= =20=09GBT_NUMKEY_R=20key;=0A=20=0A=20=09key.lower=20=3D=20(GBT_NUMKEY=20= *)=20&kkk->lower;=0A=20=09key.upper=20=3D=20(GBT_NUMKEY=20*)=20= &kkk->upper;=0A=20=0A-=09if=20(likely(subtype=20=3D=3D=20InvalidOid=20||=20= subtype=20=3D=3D=20INT4OID))=0A-=09{=0A-=09=09query=20=3D=20= DatumGetInt32(queryDatum);=0A-=09=09= PG_RETURN_FLOAT8(gbt_num_distance(&key,=20&query,=20GIST_LEAF(entry),=0A= -=09=09=09=09=09=09=09=09=09=09=20=20&tinfo,=20fcinfo->flinfo));=0A-=09}=0A= +=09ti=20=3D=20gbt_int4_crosstype(subtype,=20queryDatum,=20&query,=20= &qp);=0A=20=0A-=09PG_RETURN_FLOAT8(gbt_int_distance_x((int64)=20= kkk->lower,=20(int64)=20kkk->upper,=0A-=09=09=09=09=09=09=09=09=09=09= queryDatum,=20subtype));=0A+=09PG_RETURN_FLOAT8(gbt_num_distance(&key,=20= qp,=20GIST_LEAF(entry),=0A+=09=09=09=09=09=09=09=09=09=20=20ti,=20= fcinfo->flinfo));=0A=20}=0A=20=0A=20Datum=0Adiff=20--git=20= a/contrib/btree_gist/btree_int8.c=20b/contrib/btree_gist/btree_int8.c=0A= index=20ae01273b709..81c8bb364cf=20100644=0A---=20= a/contrib/btree_gist/btree_int8.c=0A+++=20= b/contrib/btree_gist/btree_int8.c=0A@@=20-91,6=20+91,72=20@@=20static=20= const=20gbtree_ninfo=20tinfo=20=3D=0A=20=09gbt_int8_dist=0A=20};=0A=20=0A= +/*=0A+=20*=20Cross-type=20GiST=20callbacks:=20the=20indexed=20key=20is=20= int8,=20the=20query=20is=20int2=20or=0A+=20*=20int4.=20=20Both=20reuse=20= gbt_num_consistent()/gbt_num_distance()=20via=20a=20tinfo=20whose=0A+=20= *=20comparison/distance=20callbacks=20read=20the=20query=20(left)=20and=20= key=20(right)=20sides=20at=0A+=20*=20their=20own=20widths.=20=20f_cmp=20= is=20unused=20on=20these=20paths=20and=20left=20NULL.=0A+=20*/=0A= +GBT_INT_CMP_FNS(gbt_int8_q2_,=20int16,=20int64)=0A= +GBT_INT_CMP_FNS(gbt_int8_q4_,=20int32,=20int64)=0A+=0A+static=20const=20= gbtree_ninfo=20tinfo_q2=20=3D=0A+{=0A+=09gbt_t_int8,=0A+=09= sizeof(int64),=0A+=0916,=0A+=09gbt_int8_q2_gt,=0A+=09gbt_int8_q2_ge,=0A+=09= gbt_int8_q2_eq,=0A+=09gbt_int8_q2_le,=0A+=09gbt_int8_q2_lt,=0A+=09NULL,=0A= +=09gbt_int8_q2_dist=0A+};=0A+=0A+static=20const=20gbtree_ninfo=20= tinfo_q4=20=3D=0A+{=0A+=09gbt_t_int8,=0A+=09sizeof(int64),=0A+=0916,=0A+=09= gbt_int8_q4_gt,=0A+=09gbt_int8_q4_ge,=0A+=09gbt_int8_q4_eq,=0A+=09= gbt_int8_q4_le,=0A+=09gbt_int8_q4_lt,=0A+=09NULL,=0A+=09gbt_int8_q4_dist=0A= +};=0A+=0A+/*=0A+=20*=20Cross-type=20dispatch=20shared=20by=20= gbt_int8_consistent=20and=20gbt_int8_distance:=0A+=20*=20select=20the=20= tinfo=20for=20the=20query=20subtype=20and=20read=20the=20query=20value=20= at=20its=20own=0A+=20*=20width=20into=20caller-owned=20storage.=0A+=20*/=0A= +static=20const=20gbtree_ninfo=20*=0A+gbt_int8_crosstype(Oid=20subtype,=20= Datum=20d,=20gbt_intkey=20*q,=20const=20void=20**qp)=0A+{=0A+=09switch=20= (subtype)=0A+=09{=0A+=09=09case=20INT2OID:=0A+=09=09=09q->i2=20=3D=20= DatumGetInt16(d);=0A+=09=09=09*qp=20=3D=20&q->i2;=0A+=09=09=09return=20= &tinfo_q2;=0A+=09=09case=20INT4OID:=0A+=09=09=09q->i4=20=3D=20= DatumGetInt32(d);=0A+=09=09=09*qp=20=3D=20&q->i4;=0A+=09=09=09return=20= &tinfo_q4;=0A+=09=09case=20INT8OID:=0A+=09=09=09q->i8=20=3D=20= DatumGetInt64(d);=0A+=09=09=09*qp=20=3D=20&q->i8;=0A+=09=09=09return=20= &tinfo;=0A+=09=09default:=0A+=09=09=09elog(ERROR,=20"unrecognized=20= subtype=20%u=20for=20btree_gist=20int8=20cross-type=20comparison",=0A+=09= =09=09=09=20subtype);=0A+=09=09=09return=20NULL;=09=09/*=20keep=20= compiler=20quiet=20*/=0A+=09}=0A+}=0A+=0A=20=0A=20= PG_FUNCTION_INFO_V1(int8_dist);=0A=20Datum=0A@@=20-176,7=20+242,9=20@@=20= gbt_int8_consistent(PG_FUNCTION_ARGS)=0A=20=09Oid=09=09=09subtype=20=3D=20= PG_GETARG_OID(3);=0A=20=09bool=09=20=20=20*recheck=20=3D=20(bool=20*)=20= PG_GETARG_POINTER(4);=0A=20=09int64KEY=20=20=20*kkk=20=3D=20(int64KEY=20= *)=20DatumGetPointer(entry->key);=0A-=09int64=09=09query;=0A+=09const=20= gbtree_ninfo=20*ti;=0A+=09gbt_intkey=09query;=0A+=09const=20void=20*qp;=0A= =20=09GBT_NUMKEY_R=20key;=0A=20=0A=20=09/*=20All=20cases=20served=20by=20= this=20function=20are=20exact=20*/=0A@@=20-185,17=20+253,10=20@@=20= gbt_int8_consistent(PG_FUNCTION_ARGS)=0A=20=09key.lower=20=3D=20= (GBT_NUMKEY=20*)=20&kkk->lower;=0A=20=09key.upper=20=3D=20(GBT_NUMKEY=20= *)=20&kkk->upper;=0A=20=0A-=09if=20(likely(subtype=20=3D=3D=20InvalidOid=20= ||=20subtype=20=3D=3D=20INT8OID))=0A-=09{=0A-=09=09query=20=3D=20= DatumGetInt64(queryDatum);=0A-=09=09= PG_RETURN_BOOL(gbt_num_consistent(&key,=20&query,=20&strategy,=0A-=09=09=09= =09=09=09=09=09=09=09=20=20GIST_LEAF(entry),=20&tinfo,=0A-=09=09=09=09=09= =09=09=09=09=09=20=20fcinfo->flinfo));=0A-=09}=0A+=09ti=20=3D=20= gbt_int8_crosstype(subtype,=20queryDatum,=20&query,=20&qp);=0A=20=0A-=09= PG_RETURN_BOOL(gbt_int_consistent_x(kkk->lower,=20kkk->upper,=0A-=09=09=09= =09=09=09=09=09=09=09queryDatum,=20subtype,=20&strategy,=0A-=09=09=09=09=09= =09=09=09=09=09GIST_LEAF(entry)));=0A+=09= PG_RETURN_BOOL(gbt_num_consistent(&key,=20qp,=20&strategy,=20= GIST_LEAF(entry),=0A+=09=09=09=09=09=09=09=09=09=20=20ti,=20= fcinfo->flinfo));=0A=20}=0A=20=0A=20Datum=0A@@=20-205,21=20+266,18=20@@=20= gbt_int8_distance(PG_FUNCTION_ARGS)=0A=20=09Datum=09=09queryDatum=20=3D=20= PG_GETARG_DATUM(1);=0A=20=09Oid=09=09=09subtype=20=3D=20= PG_GETARG_OID(3);=0A=20=09int64KEY=20=20=20*kkk=20=3D=20(int64KEY=20*)=20= DatumGetPointer(entry->key);=0A-=09int64=09=09query;=0A+=09const=20= gbtree_ninfo=20*ti;=0A+=09gbt_intkey=09query;=0A+=09const=20void=20*qp;=0A= =20=09GBT_NUMKEY_R=20key;=0A=20=0A=20=09key.lower=20=3D=20(GBT_NUMKEY=20= *)=20&kkk->lower;=0A=20=09key.upper=20=3D=20(GBT_NUMKEY=20*)=20= &kkk->upper;=0A=20=0A-=09if=20(likely(subtype=20=3D=3D=20InvalidOid=20||=20= subtype=20=3D=3D=20INT8OID))=0A-=09{=0A-=09=09query=20=3D=20= DatumGetInt64(queryDatum);=0A-=09=09= PG_RETURN_FLOAT8(gbt_num_distance(&key,=20&query,=20GIST_LEAF(entry),=0A= -=09=09=09=09=09=09=09=09=09=09=20=20&tinfo,=20fcinfo->flinfo));=0A-=09}=0A= +=09ti=20=3D=20gbt_int8_crosstype(subtype,=20queryDatum,=20&query,=20= &qp);=0A=20=0A-=09PG_RETURN_FLOAT8(gbt_int_distance_x(kkk->lower,=20= kkk->upper,=0A-=09=09=09=09=09=09=09=09=09=09queryDatum,=20subtype));=0A= +=09PG_RETURN_FLOAT8(gbt_num_distance(&key,=20qp,=20GIST_LEAF(entry),=0A= +=09=09=09=09=09=09=09=09=09=20=20ti,=20fcinfo->flinfo));=0A=20}=0A=20=0A= =20Datum=0Adiff=20--git=20a/contrib/btree_gist/btree_utils_num.c=20= b/contrib/btree_gist/btree_utils_num.c=0Aindex=20= cff47e2d876..91f253d880c=20100644=0A---=20= a/contrib/btree_gist/btree_utils_num.c=0A+++=20= b/contrib/btree_gist/btree_utils_num.c=0A@@=20-5,8=20+5,6=20@@=0A=20=0A=20= #include=20"btree_gist.h"=0A=20#include=20"btree_utils_num.h"=0A= -#include=20"catalog/pg_type.h"=0A-#include=20"funcapi.h"=0A=20#include=20= "utils/cash.h"=0A=20#include=20"utils/date.h"=0A=20#include=20= "utils/timestamp.h"=0A@@=20-271,6=20+269,12=20@@=20= gbt_num_consistent(const=20GBT_NUMKEY_R=20*key,=0A=20{=0A=20=09bool=09=09= retval;=0A=20=0A+=09/*=0A+=09=20*=20Every=20comparison=20callback=20is=20= invoked=20as=20f_xx(query,=20key):=20the=20query=20value=0A+=09=20*=20is=20= always=20the=20left=20argument=20and=20the=20indexed=20key=20bound=20the=20= right.=20=20The=0A+=09=20*=20integer=20opclasses=20rely=20on=20this=20= fixed=20order=20so=20their=20cross-type=20callbacks=0A+=09=20*=20can=20= read=20each=20side=20at=20its=20own=20width.=0A+=09=20*/=0A=20=09switch=20= (*strategy)=0A=20=09{=0A=20=09=09case=20BTLessEqualStrategyNumber:=0A@@=20= -286,7=20+290,7=20@@=20gbt_num_consistent(const=20GBT_NUMKEY_R=20*key,=0A= =20=09=09=09if=20(is_leaf)=0A=20=09=09=09=09retval=20=3D=20= tinfo->f_eq(query,=20key->lower,=20flinfo);=0A=20=09=09=09else=0A-=09=09=09= =09retval=20=3D=20(tinfo->f_le(key->lower,=20query,=20flinfo)=20&&=0A+=09= =09=09=09retval=20=3D=20(tinfo->f_ge(query,=20key->lower,=20flinfo)=20&&=0A= =20=09=09=09=09=09=09=20=20tinfo->f_le(query,=20key->upper,=20flinfo));=0A= =20=09=09=09break;=0A=20=09=09case=20BTGreaterStrategyNumber:=0A@@=20= -309,139=20+313,6=20@@=20gbt_num_consistent(const=20GBT_NUMKEY_R=20*key,=0A= =20=09return=20retval;=0A=20}=0A=20=0A-/*=0A-=20*=20Cross-type=20= dispatch=20table=20for=20the=20integer=20opclasses.=0A-=20*=0A-=20*=20= This=20is=20the=20single=20source=20of=20truth=20for=20which=20query=20= subtypes=20the=20integer=0A-=20*=20cross-type=20path=20understands.=20= gbt_int_query_to_int64()=20promotes=20exactly=20the=0A-=20*=20subtypes=20= listed=20here,=20and=20the=20SQL-visible=20gbt_int_crosstype_subtypes()=0A= -=20*=20exposes=20the=20same=20list=20so=20the=20regression=20tests=20= can=20assert=20that=20the=20cross-type=0A-=20*=20pg_amop=20entries=20in=20= gist_int{2,4,8}_ops=20never=20drift=20from=20what=20the=20C=20code=20can=0A= -=20*=20actually=20handle.=0A-=20*/=0A-typedef=20int64=20= (*gbt_int_promote_fn)=20(Datum=20query);=0A-=0A-static=20int64=0A= -gbt_int2_to_int64(Datum=20query)=0A-{=0A-=09return=20(int64)=20= DatumGetInt16(query);=0A-}=0A-=0A-static=20int64=0A= -gbt_int4_to_int64(Datum=20query)=0A-{=0A-=09return=20(int64)=20= DatumGetInt32(query);=0A-}=0A-=0A-static=20int64=0A= -gbt_int8_to_int64(Datum=20query)=0A-{=0A-=09return=20= DatumGetInt64(query);=0A-}=0A-=0A-typedef=20struct=0A-{=0A-=09Oid=09=09=09= subtype;=0A-=09gbt_int_promote_fn=20promote;=0A-}=09=09=09= gbt_int_crosstype;=0A-=0A-static=20const=20gbt_int_crosstype=20= gbt_int_crosstype_table[]=20=3D=20{=0A-=09{INT2OID,=20= gbt_int2_to_int64},=0A-=09{INT4OID,=20gbt_int4_to_int64},=0A-=09= {INT8OID,=20gbt_int8_to_int64},=0A-};=0A-=0A-/*=0A-=20*=20Promote=20a=20= cross-type=20integer=20query=20value=20to=20int64.=0A-=20*=0A-=20*=20A=20= subtype=20outside=20gbt_int_crosstype_table=20means=20the=20C=20dispatch=20= is=20out=20of=20sync=0A-=20*=20with=20the=20operator-family=20= registrations=20in=20pg_amop,=20so=20we=20treat=20it=20as=20an=0A-=20*=20= internal=20error.=20=20The=20regression=20tests=20assert=20this=20never=20= happens.=0A-=20*/=0A-static=20int64=0A-gbt_int_query_to_int64(Datum=20= query,=20Oid=20subtype)=0A-{=0A-=09int=09=09=09i;=0A-=0A-=09for=20(i=20=3D= =200;=20i=20<=20lengthof(gbt_int_crosstype_table);=20i++)=0A-=09{=0A-=09=09= if=20(gbt_int_crosstype_table[i].subtype=20=3D=3D=20subtype)=0A-=09=09=09= return=20gbt_int_crosstype_table[i].promote(query);=0A-=09}=0A-=0A-=09= elog(ERROR,=20"unrecognized=20subtype=20%u=20for=20btree_gist=20integer=20= cross-type=20comparison",=0A-=09=09=20subtype);=0A-=09return=200;=09=09=09= =09=09/*=20keep=20compiler=20quiet=20*/=0A-}=0A-=0A-/*=0A-=20*=20= gbt_int_crosstype_subtypes=0A-=20*=0A-=20*=20Expose=20the=20contents=20= of=20gbt_int_crosstype_table=20to=20SQL=20as=20a=20set=20of=20type=20= OIDs.=0A-=20*=20The=20btree_gist=20regression=20tests=20use=20this=20to=20= check=20that=20the=20cross-type=20pg_amop=0A-=20*=20entries=20in=20= gist_int{2,4,8}_ops=20stay=20in=20agreement=20with=20the=20C=20dispatch.=0A= -=20*/=0A-PG_FUNCTION_INFO_V1(gbt_int_crosstype_subtypes);=0A-Datum=0A= -gbt_int_crosstype_subtypes(PG_FUNCTION_ARGS)=0A-{=0A-=09FuncCallContext=20= *funcctx;=0A-=0A-=09if=20(SRF_IS_FIRSTCALL())=0A-=09=09funcctx=20=3D=20= SRF_FIRSTCALL_INIT();=0A-=0A-=09funcctx=20=3D=20SRF_PERCALL_SETUP();=0A-=0A= -=09if=20(funcctx->call_cntr=20<=20lengthof(gbt_int_crosstype_table))=0A= -=09{=0A-=09=09Oid=09=09=09subtype=20=3D=20= gbt_int_crosstype_table[funcctx->call_cntr].subtype;=0A-=0A-=09=09= SRF_RETURN_NEXT(funcctx,=20ObjectIdGetDatum(subtype));=0A-=09}=0A-=0A-=09= SRF_RETURN_DONE(funcctx);=0A-}=0A-=0A-/*=0A-=20*=20Cross-type=20= consistent=20method=20for=20the=20integer=20opclasses.=0A-=20*=0A-=20*=20= The=20key=20range=20[lower,=20upper]=20and=20the=20query=20value=20are=20= all=20compared=20as=20int64.=0A-=20*=20The=20strategy=20logic=20mirrors=20= the=20same-type=20path=20in=20gbt_num_consistent():=20the=0A-=20*=20= query=20value=20keeps=20its=20own=20width=20(no=20narrowing=20to=20the=20= indexed=20column=20type),=0A-=20*=20so=20out-of-range=20constants=20= behave=20according=20to=20normal=20integer=20comparison.=0A-=20*/=0A= -bool=0A-gbt_int_consistent_x(int64=20lower,=20int64=20upper,=20Datum=20= query,=20Oid=20subtype,=0A-=09=09=09=09=09=20const=20StrategyNumber=20= *strategy,=20bool=20is_leaf)=0A-{=0A-=09int64=09=09q=20=3D=20= gbt_int_query_to_int64(query,=20subtype);=0A-=0A-=09switch=20(*strategy)=0A= -=09{=0A-=09=09case=20BTLessEqualStrategyNumber:=0A-=09=09=09/*=20some=20= k=20in=20[lower,upper]=20has=20k=20<=3D=20q=20iff=20lower=20<=3D=20q=20= */=0A-=09=09=09return=20lower=20<=3D=20q;=0A-=09=09case=20= BTLessStrategyNumber:=0A-=09=09=09/*=20leaf:=20key=20<=20q.=20internal:=20= lower=20<=3D=20q=20(loose)=20*/=0A-=09=09=09return=20is_leaf=20?=20= (lower=20<=20q)=20:=20(lower=20<=3D=20q);=0A-=09=09case=20= BTEqualStrategyNumber:=0A-=09=09=09if=20(is_leaf)=0A-=09=09=09=09return=20= lower=20=3D=3D=20q;=0A-=09=09=09/*=20internal:=20lower=20<=3D=20q=20<=3D=20= upper=20*/=0A-=09=09=09return=20(lower=20<=3D=20q=20&&=20q=20<=3D=20= upper);=0A-=09=09case=20BTGreaterStrategyNumber:=0A-=09=09=09/*=20leaf:=20= key=20>=20q.=20internal:=20upper=20>=3D=20q=20(loose)=20*/=0A-=09=09=09= return=20is_leaf=20?=20(upper=20>=20q)=20:=20(upper=20>=3D=20q);=0A-=09=09= case=20BTGreaterEqualStrategyNumber:=0A-=09=09=09return=20upper=20>=3D=20= q;=0A-=09=09case=20BtreeGistNotEqualStrategyNumber:=0A-=09=09=09return=20= !(lower=20=3D=3D=20q=20&&=20upper=20=3D=3D=20q);=0A-=09=09default:=0A-=09= =09=09return=20false;=0A-=09}=0A-}=0A-=0A-=0A=20/*=0A=20=20*=20The=20= GiST=20distance=20method=20(for=20KNN-Gist)=0A=20=20*/=0A@@=20-468,32=20= +339,6=20@@=20gbt_num_distance(const=20GBT_NUMKEY_R=20*key,=0A=20=09= return=20retval;=0A=20}=0A=20=0A-/*=0A-=20*=20Cross-type=20distance=20= method=20for=20the=20integer=20opclasses.=0A-=20*=0A-=20*=20The=20= distance=20from=20the=20query=20value=20to=20the=20key=20range=20is=20= computed=20in=20int64=20and=0A-=20*=20returned=20as=20a=20float8,=20= matching=20the=20same-type=20integer=20distance=20behaviour.=0A-=20*=0A-=20= *=20Note=20that=20the=20subtraction=20is=20performed=20in=20float8,=20so=20= when=20the=20key=20bound=20and=0A-=20*=20the=20query=20value=20differ=20= by=20more=20than=202^53=20the=20returned=20distance=20loses=0A-=20*=20= precision.=20This=20only=20affects=20the=20ordering=20of=20KNN=20results=20= that=20are=20nearly=0A-=20*=20equidistant=20at=20that=20scale;=20it=20= never=20changes=20which=20rows=20are=20returned.=0A-=20*/=0A-float8=0A= -gbt_int_distance_x(int64=20lower,=20int64=20upper,=20Datum=20query,=20= Oid=20subtype)=0A-{=0A-=09int64=09=09q=20=3D=20= gbt_int_query_to_int64(query,=20subtype);=0A-=0A-=09/*=20query=20below=20= the=20range:=20distance=20to=20lower=20bound=20*/=0A-=09if=20(lower=20>=3D= =20q)=0A-=09=09return=20fabs((float8)=20lower=20-=20(float8)=20q);=0A-=09= /*=20query=20above=20the=20range:=20distance=20to=20upper=20bound=20*/=0A= -=09if=20(upper=20<=3D=20q)=0A-=09=09return=20fabs((float8)=20upper=20-=20= (float8)=20q);=0A-=09/*=20query=20inside=20the=20range=20*/=0A-=09return=20= 0.0;=0A-}=0A-=0A=20=0A=20GIST_SPLITVEC=20*=0A=20gbt_num_picksplit(const=20= GistEntryVector=20*entryvec,=20GIST_SPLITVEC=20*v,=0Adiff=20--git=20= a/contrib/btree_gist/btree_utils_num.h=20= b/contrib/btree_gist/btree_utils_num.h=0Aindex=20= d378b0df37e..be09bdb2581=20100644=0A---=20= a/contrib/btree_gist/btree_utils_num.h=0A+++=20= b/contrib/btree_gist/btree_utils_num.h=0A@@=20-27,6=20+27,18=20@@=20= typedef=20struct=0A=20=09GBT_NUMKEY=20*t;=0A=20}=20Nsrt;=0A=20=0A+/*=0A+=20= *=20Query-value=20storage=20for=20the=20integer=20opclasses'=20= cross-type=20path.=20=20The=20caller=0A+=20*=20owns=20one=20of=20these=20= and=20passes=20its=20address=20to=20the=20per-type=20cross-type=20= helper,=0A+=20*=20which=20fills=20the=20right=20width=20and=20points=20= the=20query=20pointer=20at=20it.=0A+=20*/=0A+typedef=20union=0A+{=0A+=09= int16=09=09i2;=0A+=09int32=09=09i4;=0A+=09int64=09=09i8;=0A+}=09=09=09= gbt_intkey;=0A+=0A=20=0A=20/*=20type=20description=20*/=0A=20=0A@@=20= -86,7=20+98,32=20@@=20typedef=20struct=0A=20=09=20(ivp)->day=20*=20(24.0=20= *=20SECS_PER_HOUR)=20+=20\=0A=20=09=20(ivp)->month=20*=20(30.0=20*=20= SECS_PER_DAY))=0A=20=0A-#define=20GET_FLOAT_DISTANCE(t,=20arg1,=20arg2)=09= fabs(=20((float8)=20*((const=20t=20*)=20(arg1)))=20-=20((float8)=20= *((const=20t=20*)=20(arg2)))=20)=0A+#define=20GET_FLOAT_DISTANCE2(t1,=20= t2,=20arg1,=20arg2)=09fabs(=20((float8)=20*((const=20t1=20*)=20(arg1)))=20= -=20((float8)=20*((const=20t2=20*)=20(arg2)))=20)=0A+#define=20= GET_FLOAT_DISTANCE(t,=20arg1,=20arg2)=09GET_FLOAT_DISTANCE2(t,=20t,=20= (arg1),=20(arg2))=0A+=0A+/*=0A+=20*=20Generate=20the=20= comparison/distance=20callbacks=20for=20a=20gbtree_ninfo=20whose=20query=0A= +=20*=20and=20key=20sides=20may=20be=20different=20(integer)=20types.=20=20= gbt_num_consistent()=20and=0A+=20*=20gbt_num_distance()=20always=20= invoke=20the=20callbacks=20as=20f_xx(query,=20key),=20so=20the=0A+=20*=20= first=20argument=20has=20the=20query=20type=20QT=20(the=20operator's=20= right-hand=20subtype)=20and=0A+=20*=20the=20second=20has=20the=20indexed=20= key=20type=20KT.=20=20Integer=20widening=20is=20value-preserving,=0A+=20= *=20so=20the=20comparisons=20need=20no=20explicit=20cast;=20the=20= distance=20widens=20to=20float8=20to=0A+=20*=20avoid=20overflow=20in=20= the=20subtraction.=20=20Invoked=20with=20QT=20=3D=3D=20KT=20this=20also=20= generates=0A+=20*=20the=20ordinary=20same-type=20callbacks.=0A+=20*/=0A= +#define=20GBT_INT_CMP_FNS(prefix,=20QT,=20KT)=20\=0A+static=20bool=20= prefix##gt(const=20void=20*a,=20const=20void=20*b,=20FmgrInfo=20*flinfo)=20= \=0A+{=20return=20*((const=20QT=20*)=20a)=20>=20*((const=20KT=20*)=20b);=20= }=20\=0A+static=20bool=20prefix##ge(const=20void=20*a,=20const=20void=20= *b,=20FmgrInfo=20*flinfo)=20\=0A+{=20return=20*((const=20QT=20*)=20a)=20= >=3D=20*((const=20KT=20*)=20b);=20}=20\=0A+static=20bool=20= prefix##eq(const=20void=20*a,=20const=20void=20*b,=20FmgrInfo=20*flinfo)=20= \=0A+{=20return=20*((const=20QT=20*)=20a)=20=3D=3D=20*((const=20KT=20*)=20= b);=20}=20\=0A+static=20bool=20prefix##le(const=20void=20*a,=20const=20= void=20*b,=20FmgrInfo=20*flinfo)=20\=0A+{=20return=20*((const=20QT=20*)=20= a)=20<=3D=20*((const=20KT=20*)=20b);=20}=20\=0A+static=20bool=20= prefix##lt(const=20void=20*a,=20const=20void=20*b,=20FmgrInfo=20*flinfo)=20= \=0A+{=20return=20*((const=20QT=20*)=20a)=20<=20*((const=20KT=20*)=20b);=20= }=20\=0A+static=20float8=20prefix##dist(const=20void=20*a,=20const=20= void=20*b,=20FmgrInfo=20*flinfo)=20\=0A+{=20return=20= GET_FLOAT_DISTANCE2(QT,=20KT,=20a,=20b);=20}=0A=20=0A=20=0A=20extern=20= Interval=20*abs_interval(Interval=20*a);=0A@@=20-98,22=20+135,6=20@@=20= extern=20bool=20gbt_num_consistent(const=20GBT_NUMKEY_R=20*key,=20const=20= void=20*query,=0A=20extern=20float8=20gbt_num_distance(const=20= GBT_NUMKEY_R=20*key,=20const=20void=20*query,=0A=20=09=09=09=09=09=09=09=20= =20=20bool=20is_leaf,=20const=20gbtree_ninfo=20*tinfo,=20FmgrInfo=20= *flinfo);=0A=20=0A-/*=0A-=20*=20Cross-type=20consistent/distance=20= helpers=20for=20the=20integer=20opclasses=0A-=20*=20(int2/int4/int8).=20=20= All=20three=20integer=20widths=20promote=20losslessly=20to=20int64,=20so=0A= -=20*=20a=20cross-type=20query=20reduces=20to=20a=20plain=20int64=20= comparison=20and=20there=20is=20no=20need=0A-=20*=20for=20the=20per-type=20= callback=20machinery=20the=20same-type=20path=20uses.=20=20These=20= helpers=0A-=20*=20are=20deliberately=20integer-specific=20rather=20than=20= a=20general=20cross-type=20framework;=0A-=20*=20other=20type=20families=20= should=20grow=20their=20own=20helpers=20shaped=20to=20their=20needs=20as=0A= -=20*=20the=20need=20arises.=0A-=20*/=0A-extern=20bool=20= gbt_int_consistent_x(int64=20lower,=20int64=20upper,=0A-=09=09=09=09=09=09= =09=09=20Datum=20query,=20Oid=20subtype,=0A-=09=09=09=09=09=09=09=09=20= const=20StrategyNumber=20*strategy,=20bool=20is_leaf);=0A-=0A-extern=20= float8=20gbt_int_distance_x(int64=20lower,=20int64=20upper,=0A-=09=09=09=09= =09=09=09=09=20Datum=20query,=20Oid=20subtype);=0A-=0A=20extern=20= GIST_SPLITVEC=20*gbt_num_picksplit(const=20GistEntryVector=20*entryvec,=20= GIST_SPLITVEC=20*v,=0A=20=09=09=09=09=09=09=09=09=09=09const=20= gbtree_ninfo=20*tinfo,=20FmgrInfo=20*flinfo);=0A=20=0Adiff=20--git=20= a/contrib/btree_gist/expected/int_crosstype.out=20= b/contrib/btree_gist/expected/int_crosstype.out=0Aindex=20= bd2b90bd3f6..af03cf84a40=20100644=0A---=20= a/contrib/btree_gist/expected/int_crosstype.out=0A+++=20= b/contrib/btree_gist/expected/int_crosstype.out=0A@@=20-6,66=20+6,11=20= @@=0A=20--=20index,=20and=20(c)=20values=20outside=20the=20smaller=20= subtype's=20range=20are=20handled=0A=20--=20according=20to=20normal=20= comparison=20semantics,=20without=20narrowing=20or=20erroring.=0A=20--=0A= ---=20Catalog=20invariant:=20the=20cross-type=20pg_amop=20entries=20in=20= gist_int{2,4,8}_ops=20must=0A---=20agree,=20in=20both=20directions,=20= with=20what=20the=20C=20cross-type=20dispatch=20can=20handle.=0A---=20= The=20set=20of=20supported=20query=20subtypes=20is=20read=20from=20the=20= C=20side=20via=0A---=20gbt_int_crosstype_subtypes(),=20so=20there=20is=20= no=20hand-maintained=20second=20copy=20of=0A---=20the=20list=20here:=20= registering=20a=20pg_amop=20row=20whose=20subtype=20the=20dispatch=20= does=20not=0A---=20handle=20(or=20dropping=20a=20dispatch=20entry=20= while=20its=20pg_amop=20rows=20remain,=20or=20vice=0A---=20versa)=20= shows=20up=20as=20a=20diff=20below.=20Cross-type=20pg_amproc=20rows=20= must=20also=20stay=0A---=20absent,=20since=20the=20dispatch=20reuses=20= the=20same-type=20support=20functions.=0A+--=20The=20integer=20= cross-type=20support=20is=20handled=20inside=20the=20existing=0A+--=20= consistent/distance=20support=20functions=20(which=20dispatch=20on=20the=20= subtype=20OID),=0A+--=20so=20the=20operator=20families=20must=20not=20= contain=20any=20cross-type=20(different=0A+--=20left/right=20input=20= type)=20support-function=20entries.=0A=20--=0A-WITH=20= dispatch_subtypes(typ)=20AS=20(=0A-=20=20=20=20SELECT=20= s.subtype::regtype=0A-=20=20=20=20FROM=20gbt_int_crosstype_subtypes()=20= AS=20s(subtype)=0A-),=0A-gist_int_opclasses(opfamily,=20indextype)=20AS=20= (=0A-=20=20=20=20SELECT=20opc.opcname::text,=20opc.opcintype::regtype=0A= -=20=20=20=20FROM=20pg_opclass=20opc=0A-=20=20=20=20=20=20=20=20=20JOIN=20= pg_am=20am=20ON=20am.oid=20=3D=20opc.opcmethod=0A-=20=20=20=20WHERE=20= am.amname=20=3D=20'gist'=0A-=20=20=20=20=20=20AND=20opc.opcname=20IN=20= ('gist_int2_ops',=20'gist_int4_ops',=20'gist_int8_ops')=0A-),=0A= -expected_pairs(opfamily,=20lefttype,=20righttype)=20AS=20(=0A-=20=20=20=20= SELECT=20oc.opfamily,=20oc.indextype,=20ds.typ=0A-=20=20=20=20FROM=20= gist_int_opclasses=20oc=0A-=20=20=20=20=20=20=20=20=20CROSS=20JOIN=20= dispatch_subtypes=20ds=0A-=20=20=20=20WHERE=20ds.typ=20<>=20oc.indextype=0A= -),=0A-expected_amop(opfamily,=20lefttype,=20righttype,=20strategy,=20= purpose)=20AS=20(=0A-=20=20=20=20SELECT=20opfamily,=20lefttype,=20= righttype,=20strategy,=20purpose=0A-=20=20=20=20FROM=20expected_pairs=0A= -=20=20=20=20=20=20=20=20=20CROSS=20JOIN=20(VALUES=0A-=20=20=20=20=20=20=20= =20=20=20=20=20=20(1,=20's'),=20(2,=20's'),=20(3,=20's'),=20(4,=20's'),=0A= -=20=20=20=20=20=20=20=20=20=20=20=20=20(5,=20's'),=20(6,=20's'),=20(15,=20= 'o')=0A-=20=20=20=20=20=20=20=20=20)=20AS=20strategy_purposes(strategy,=20= purpose)=0A-),=0A-actual_amop=20AS=20(=0A-=20=20=20=20SELECT=20= opf.opfname::text=20AS=20opfamily,=0A-=20=20=20=20=20=20=20=20=20=20=20= amop.amoplefttype::regtype=20AS=20lefttype,=0A-=20=20=20=20=20=20=20=20=20= =20=20amop.amoprighttype::regtype=20AS=20righttype,=0A-=20=20=20=20=20=20= =20=20=20=20=20amop.amopstrategy::int=20AS=20strategy,=0A-=20=20=20=20=20= =20=20=20=20=20=20amop.amoppurpose::text=20AS=20purpose=0A-=20=20=20=20= FROM=20pg_amop=20amop=0A-=20=20=20=20=20=20=20=20=20JOIN=20pg_opfamily=20= opf=20ON=20opf.oid=20=3D=20amop.amopfamily=0A-=20=20=20=20=20=20=20=20=20= JOIN=20pg_am=20am=20ON=20am.oid=20=3D=20opf.opfmethod=0A-=20=20=20=20= WHERE=20am.amname=20=3D=20'gist'=0A-=20=20=20=20=20=20AND=20opf.opfname=20= IN=20('gist_int2_ops',=20'gist_int4_ops',=20'gist_int8_ops')=0A-=20=20=20= =20=20=20AND=20amop.amoplefttype=20<>=20amop.amoprighttype=0A-)=0A= -SELECT=20*=0A-FROM=20(=0A-=20=20=20=20SELECT=20'missing=20from=20= pg_amop'=20AS=20status,=20*=0A-=20=20=20=20FROM=20(SELECT=20*=20FROM=20= expected_amop=20EXCEPT=20SELECT=20*=20FROM=20actual_amop)=20missing=0A-=20= =20=20=20UNION=20ALL=0A-=20=20=20=20SELECT=20'unexpected=20in=20pg_amop'=20= AS=20status,=20*=0A-=20=20=20=20FROM=20(SELECT=20*=20FROM=20actual_amop=20= EXCEPT=20SELECT=20*=20FROM=20expected_amop)=20unexpected=0A-)=20diff=0A= -ORDER=20BY=20status,=20opfamily,=20lefttype::text,=20righttype::text,=20= strategy,=20purpose;=0A-=20status=20|=20opfamily=20|=20lefttype=20|=20= righttype=20|=20strategy=20|=20purpose=20=0A= ---------+----------+----------+-----------+----------+---------=0A-(0=20= rows)=0A-=0A=20SELECT=20opf.opfname=20AS=20opfamily,=0A=20=20=20=20=20=20= =20=20amproc.amproclefttype::regtype=20AS=20lefttype,=0A=20=20=20=20=20=20= =20=20amproc.amprocrighttype::regtype=20AS=20righttype,=0Adiff=20--git=20= a/contrib/btree_gist/sql/int_crosstype.sql=20= b/contrib/btree_gist/sql/int_crosstype.sql=0Aindex=20= d38084f1941..b337e26a1af=20100644=0A---=20= a/contrib/btree_gist/sql/int_crosstype.sql=0A+++=20= b/contrib/btree_gist/sql/int_crosstype.sql=0A@@=20-7,63=20+7,11=20@@=0A=20= --=20according=20to=20normal=20comparison=20semantics,=20without=20= narrowing=20or=20erroring.=0A=20=0A=20--=0A---=20Catalog=20invariant:=20= the=20cross-type=20pg_amop=20entries=20in=20gist_int{2,4,8}_ops=20must=0A= ---=20agree,=20in=20both=20directions,=20with=20what=20the=20C=20= cross-type=20dispatch=20can=20handle.=0A---=20The=20set=20of=20supported=20= query=20subtypes=20is=20read=20from=20the=20C=20side=20via=0A---=20= gbt_int_crosstype_subtypes(),=20so=20there=20is=20no=20hand-maintained=20= second=20copy=20of=0A---=20the=20list=20here:=20registering=20a=20= pg_amop=20row=20whose=20subtype=20the=20dispatch=20does=20not=0A---=20= handle=20(or=20dropping=20a=20dispatch=20entry=20while=20its=20pg_amop=20= rows=20remain,=20or=20vice=0A---=20versa)=20shows=20up=20as=20a=20diff=20= below.=20Cross-type=20pg_amproc=20rows=20must=20also=20stay=0A---=20= absent,=20since=20the=20dispatch=20reuses=20the=20same-type=20support=20= functions.=0A+--=20The=20integer=20cross-type=20support=20is=20handled=20= inside=20the=20existing=0A+--=20consistent/distance=20support=20= functions=20(which=20dispatch=20on=20the=20subtype=20OID),=0A+--=20so=20= the=20operator=20families=20must=20not=20contain=20any=20cross-type=20= (different=0A+--=20left/right=20input=20type)=20support-function=20= entries.=0A=20--=0A-WITH=20dispatch_subtypes(typ)=20AS=20(=0A-=20=20=20=20= SELECT=20s.subtype::regtype=0A-=20=20=20=20FROM=20= gbt_int_crosstype_subtypes()=20AS=20s(subtype)=0A-),=0A= -gist_int_opclasses(opfamily,=20indextype)=20AS=20(=0A-=20=20=20=20= SELECT=20opc.opcname::text,=20opc.opcintype::regtype=0A-=20=20=20=20FROM=20= pg_opclass=20opc=0A-=20=20=20=20=20=20=20=20=20JOIN=20pg_am=20am=20ON=20= am.oid=20=3D=20opc.opcmethod=0A-=20=20=20=20WHERE=20am.amname=20=3D=20= 'gist'=0A-=20=20=20=20=20=20AND=20opc.opcname=20IN=20('gist_int2_ops',=20= 'gist_int4_ops',=20'gist_int8_ops')=0A-),=0A-expected_pairs(opfamily,=20= lefttype,=20righttype)=20AS=20(=0A-=20=20=20=20SELECT=20oc.opfamily,=20= oc.indextype,=20ds.typ=0A-=20=20=20=20FROM=20gist_int_opclasses=20oc=0A-=20= =20=20=20=20=20=20=20=20CROSS=20JOIN=20dispatch_subtypes=20ds=0A-=20=20=20= =20WHERE=20ds.typ=20<>=20oc.indextype=0A-),=0A-expected_amop(opfamily,=20= lefttype,=20righttype,=20strategy,=20purpose)=20AS=20(=0A-=20=20=20=20= SELECT=20opfamily,=20lefttype,=20righttype,=20strategy,=20purpose=0A-=20=20= =20=20FROM=20expected_pairs=0A-=20=20=20=20=20=20=20=20=20CROSS=20JOIN=20= (VALUES=0A-=20=20=20=20=20=20=20=20=20=20=20=20=20(1,=20's'),=20(2,=20= 's'),=20(3,=20's'),=20(4,=20's'),=0A-=20=20=20=20=20=20=20=20=20=20=20=20= =20(5,=20's'),=20(6,=20's'),=20(15,=20'o')=0A-=20=20=20=20=20=20=20=20=20= )=20AS=20strategy_purposes(strategy,=20purpose)=0A-),=0A-actual_amop=20= AS=20(=0A-=20=20=20=20SELECT=20opf.opfname::text=20AS=20opfamily,=0A-=20=20= =20=20=20=20=20=20=20=20=20amop.amoplefttype::regtype=20AS=20lefttype,=0A= -=20=20=20=20=20=20=20=20=20=20=20amop.amoprighttype::regtype=20AS=20= righttype,=0A-=20=20=20=20=20=20=20=20=20=20=20amop.amopstrategy::int=20= AS=20strategy,=0A-=20=20=20=20=20=20=20=20=20=20=20= amop.amoppurpose::text=20AS=20purpose=0A-=20=20=20=20FROM=20pg_amop=20= amop=0A-=20=20=20=20=20=20=20=20=20JOIN=20pg_opfamily=20opf=20ON=20= opf.oid=20=3D=20amop.amopfamily=0A-=20=20=20=20=20=20=20=20=20JOIN=20= pg_am=20am=20ON=20am.oid=20=3D=20opf.opfmethod=0A-=20=20=20=20WHERE=20= am.amname=20=3D=20'gist'=0A-=20=20=20=20=20=20AND=20opf.opfname=20IN=20= ('gist_int2_ops',=20'gist_int4_ops',=20'gist_int8_ops')=0A-=20=20=20=20=20= =20AND=20amop.amoplefttype=20<>=20amop.amoprighttype=0A-)=0A-SELECT=20*=0A= -FROM=20(=0A-=20=20=20=20SELECT=20'missing=20from=20pg_amop'=20AS=20= status,=20*=0A-=20=20=20=20FROM=20(SELECT=20*=20FROM=20expected_amop=20= EXCEPT=20SELECT=20*=20FROM=20actual_amop)=20missing=0A-=20=20=20=20UNION=20= ALL=0A-=20=20=20=20SELECT=20'unexpected=20in=20pg_amop'=20AS=20status,=20= *=0A-=20=20=20=20FROM=20(SELECT=20*=20FROM=20actual_amop=20EXCEPT=20= SELECT=20*=20FROM=20expected_amop)=20unexpected=0A-)=20diff=0A-ORDER=20= BY=20status,=20opfamily,=20lefttype::text,=20righttype::text,=20= strategy,=20purpose;=0A-=0A=20SELECT=20opf.opfname=20AS=20opfamily,=0A=20= =20=20=20=20=20=20=20amproc.amproclefttype::regtype=20AS=20lefttype,=0A=20= =20=20=20=20=20=20=20amproc.amprocrighttype::regtype=20AS=20righttype,=0A= --=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_BEEF4960-8ACC-4524-9DA5-644B9C506315--