knngist - 0.8
http://www.sigaev.ru/misc/builtin_knngist_core-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_itself-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_proc-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_pg_trgm-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_btree_gist-0.8.gz
Changes:
* pg_amop has boolean column amoporder which points to clause's usage of
operator
* Syntax of CREATE OPERATOR CLASS
CREATE OPERATOR CLASS ...
[ORDER] OPERATOR ....
ORDER OPERATOR is marked with pg_amop.amoporder = true
* Bool-returning operator could not be used as ORDER OPERATOR, but type of
returning value still should have a default Btree operator class.
* Added flag SK_ORDER to SkanKey flag to indicate order operation, so access
methods (only GiST right now) should check this flag (in previous versions of
patch GiST checked returned value of operator's function)
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
2010/7/22 Teodor Sigaev <teodor@sigaev.ru>:
http://www.sigaev.ru/misc/builtin_knngist_core-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_itself-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_proc-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_pg_trgm-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_btree_gist-0.8.gzChanges:
* pg_amop has boolean column amoporder which points to clause's usage of
operator
* Syntax of CREATE OPERATOR CLASS
CREATE OPERATOR CLASS ...
[ORDER] OPERATOR ....
ORDER OPERATOR is marked with pg_amop.amoporder = true
* Bool-returning operator could not be used as ORDER OPERATOR, but type of
returning value still should have a default Btree operator class.
* Added flag SK_ORDER to SkanKey flag to indicate order operation, so access
methods (only GiST right now) should check this flag (in previous versions
of
patch GiST checked returned value of operator's function)
AFAICS, these patches include no documentation. That's pretty much a
fatal flaw for a feature of this magnitude. At an absolute minimum,
you need to update the system catalog documentation and the
documentation on CREATE / ALTER OPERATOR CLASS. There might be some
other places that need to be touched, also.
+ if (opform->oprresult == BOOLOID)
+ ereport(ERROR,
+
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("index ordering
operators must not return boolean")));
My first thought was that this code was there to prevent people from
doing the wrong thing by accident. But I have a niggling feeling that
you're actually relying on this for the correctness of the system. I
hope I'm wrong, because I don't think that would be a very good idea.
The GIST code code use more comments; and perhaps the names of some of
the functions and structures could be chosen to be more descriptive.
I think that what used to be called GISTSearchStack has apparently
been replaced with DataPointer; it's not obvious to me that it's good
to change the name, but if it is I don't think DataPointer is a good
choice. gistindex_keytest has been replaced (sort of) by
processIndexTuple, which again seems more generic than what it
replaced.
Minor nit: the word "shoould" is mis-spelled.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise Postgres Company
http://www.sigaev.ru/misc/builtin_knngist_core-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_itself-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_proc-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_pg_trgm-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_btree_gist-0.8.gz
New version, synced with CVS HEAD
http://www.sigaev.ru/misc/builtin_knngist_itself-0.8.2.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_btree_gist-0.8.1.gz
AFAICS, these patches include no documentation. That's pretty much a
fatal flaw for a feature of this magnitude. At an absolute minimum,
you need to update the system catalog documentation and the
documentation on CREATE / ALTER OPERATOR CLASS. There might be some
other places that need to be touched, also.
Oleg promised to do that
+ if (opform->oprresult == BOOLOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("index ordering operators must not return boolean")));My first thought was that this code was there to prevent people from
doing the wrong thing by accident. But I have a niggling feeling that
you're actually relying on this for the correctness of the system. I
hope I'm wrong, because I don't think that would be a very good idea.
This play is around do we really want to have support of boolean-distance in
GiST? I think no, because it's a strange idea to measure distance in true/false
measurement units. I can't imagine such real-life distance definition and never
heard about that.
Next, pg_amop_opr_fam_index requires uniqueness of operation in operation family
and a lot of places in planner believes in that. Suppose, changing that requires
a lot of work which has the single aim to support boolean distance in ORDER BY
clause.
The GIST code code use more comments; and perhaps the names of some of
the functions and structures could be chosen to be more descriptive.
I think that what used to be called GISTSearchStack has apparently
been replaced with DataPointer; it's not obvious to me that it's good
to change the name, but if it is I don't think DataPointer is a good
GISTSearchStack is replaced by RBTree (GISTScanOpaqueData->stack), tree's nodes
contain a StackElem struct which represents list of pointers at the same
distance. Each pointer could be a pointer to the inner index's page or to the
heap's tuple and this struct is a DataPointer.
Note, list of DataPointer in StackElem struct is organized by non-obvious way:
we keep pointer to the head of list and pointer to the middle of list. New
pointer-to-heap is inserted in the beginning of list, pointers-to-index-page -
in the middle. That's done because we would like to:
1) pop pointers-to-heap as fast as possible, before any pointers-to-index-page
2) pop pointers-to-index-page to deep page (which is closer to leaf pages)
first. That's good for KNN performance and emulates classical first-depth
search in ordinary search.
choice. gistindex_keytest has been replaced (sort of) by
processIndexTuple, which again seems more generic than what it
replaced.
Renamed, comments are improved
Minor nit: the word "shoould" is mis-spelled.
fixed
BTW, now consistentFn is able to "manage" tree traversal - even for for ordinary
search, GiST will choose child page with minimal distance.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
2010/9/7 Teodor Sigaev <teodor@sigaev.ru>:
AFAICS, these patches include no documentation. That's pretty much a
fatal flaw for a feature of this magnitude. At an absolute minimum,
you need to update the system catalog documentation and the
documentation on CREATE / ALTER OPERATOR CLASS. There might be some
other places that need to be touched, also.Oleg promised to do that
Fair enough, but where is it? It's kind of difficult even to review
this without some documentation, and you wrote this patch in 2009.
And as Tom pointed out the last time we reviewed this, lack of
documentation is sufficient grounds for rejection in and of itself.
http://archives.postgresql.org/pgsql-hackers/2010-02/msg00820.php
+ if (opform->oprresult == BOOLOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("index ordering operators must not return boolean")));My first thought was that this code was there to prevent people from
doing the wrong thing by accident. But I have a niggling feeling that
you're actually relying on this for the correctness of the system. I
hope I'm wrong, because I don't think that would be a very good idea.This play is around do we really want to have support of boolean-distance in
GiST? I think no, because it's a strange idea to measure distance in
true/false measurement units. I can't imagine such real-life distance
definition and never heard about that.Next, pg_amop_opr_fam_index requires uniqueness of operation in operation
family and a lot of places in planner believes in that. Suppose, changing
that requires a lot of work which has the single aim to support boolean
distance in ORDER BY clause.
Tom and I both expressed the opinion 7 months ago that we don't think
this design is acceptable.
http://archives.postgresql.org/pgsql-hackers/2010-02/msg01063.php
I'm not sure why you expect it to be acceptable now if it wasn't
acceptable then. I'm sort of surprised that you haven't taken the
intervening 7 months to rework it along the lines discussed. We had a
very long and detailed discussion about how to make it work, and
committed a huge, invasive patch that Tom's going to be grumpy about
for years to provide the infrastructure for 5-key syscaches --
specifically so you'd be able change pg_amop_fam_strat_index to use a
5-part key. I would actually think that would be a fairly mechanical
transformation.
It seems to me that there is not very much point in reviewing this
further until you incorporate the feedback that was given last time,
and specifically the two major points discussed above.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise Postgres Company
http://www.sigaev.ru/misc/builtin_knngist_core-0.9.gz
http://www.sigaev.ru/misc/builtin_knngist_itself-0.8.2.gz
http://www.sigaev.ru/misc/builtin_knngist_proc-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_pg_trgm-0.8.gz
http://www.sigaev.ru/misc/builtin_knngist_contrib_btree_gist-0.8.1.gz
+ if (opform->oprresult == BOOLOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("index ordering operators must not return boolean")));
New version allows to use boolean distance, i.e. the same operator could be used
both in WHERE and ORDER BY clauses. Now operator could present in operator
family twice, but with different StrategyNumber: as ordinary search operator (in
WHERE clause) and as an order operator (ORDER BY).
So, list of changes:
1) "pg_amop_opr_fam_index" UNIQUE, btree (amopopr, amopfamily) =>
"pg_amop_opr_fam_index" UNIQUE, btree (amopopr, amopfamily, amoporder)
2) op_in_opfamily, get_op_opfamily_strategy, get_op_opfamily_properties accept
one more argument, bool orderop, to point which kind of operator we need to
find
3) bool OpExpr.orderop. This field is needed to correctly set SK_ORDER flags
for index scan (ExecIndexBuildScanKeys function). SK_ORDER flag points type
of tree traversal algorithm to GiST core.
Introducing two fields, per Tom's suggestion, doesn't resolve following issues:
- we still need to distinguish WHERE and ORDER BY operator in
ExecIndexBuildScanKey, as it done in new version of patch
- When we execute AMOPOPID cache request we still need to check pg_amop.amorder
or introduce two new indexes (amopopr, amopfamily, amopcanwhere) and
(amopopr, amopfamily, amopcanorder) and the same changes in lsyscache's
functions
- If one operation could be used for both usage type then it will be good to
distinguish them in consistent method. New version requires to use
different strategy number for each usage type.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
2010/9/13 Teodor Sigaev <teodor@sigaev.ru>:
[updated patch]
I realize I'm repeating myself, but... this patch needs
documentation. It's not optional.
It seems to me that you need to do something about AMOPSTRATEGY.
Hence the five-key syscaches patches I wrote that is sitting in queue.
And also LookupOpClassInfo(). Am I confused?
Is there a reason we're using a boolean 'amoporder' distinguish
ordering operators from regular old operators? Tom and I were talking
about some kind of an integer field, in case we need more categories
later. You know, like 'amopcategory' or something like that. It
could be just one byte, perhaps, but one bit seems unduly narrow. You
could define constants OPCAT_QUAL and OPCAT_ORDER, or something like
that.
This error message seems like it ought to be complaining about the
access method, not the index:
+ if (!pg_am->amcanorderbyop)
+ ereport(ERROR,
+
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("index doesn't support
ordering operations")));
I sort of understand the reasons behind the following restriction, but
is this truly the best we can do?
+ /*
+ * Currently, only descending and nulls last ordering
is supported
+ */
+ if (!(pathkey->pk_strategy == BTLessStrategyNumber &&
pathkey->pk_nulls_first == false))
+ return;
What happens if we have an index strategy that can efficiently return
the points most distant from the bright center of the universe?
By the way:
gistproc.c: In function ‘gist_point_consistent’:
gistproc.c:1023: error: ‘distance’ may be used uninitialized in this function
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise Postgres Company
I haven't quite finished reviewing this, but here is the position so
far. I'm going to continue with some performance and other tests, but
I'm posting this for discussion in the mean time.
1) General patch issues
- applies cleanly and passes regression
- one small warning with ecpg parser build, which I assume is just due
to the patch having touched the main parser in a way the ecpg build
doesn't expect (presumably this will be cleaned up at some later stage)
- *no* documentation (see below)
2) Design questions
Reading through the previous discussion on -hackers, I didn't get the
impression that there was agreement on the question of how to
represent the ordering operators in the catalog. This patch takes the
approach of adding a boolean column pg_amop.amoporder and doing
changes that require touching unrelated code in a fair number of places.
In addition there are the points Robert Haas expressed in his earlier
response.
This approach doesn't feel right to me, but I don't know enough about
it (especially any possible other features that might want to do
something similar) to express a strong opinion on it. So that point is
open for discussion.
3) Documentation
There are problems with the GiST docs that go much deeper than this
patch alone; the manual sections on writing GiST support functions are
wholly inadequate, and many features that have been around for a long
time, such as secondary split in GiST picksplit functions, are essentially
undocumented other than as (uncommented!) example code in contrib modules.
This patch would, as it stands, make that issue worse.
My opinion is that the gist-implementation section of the docs needs
to be substantially expanded so that it explains, for each support
function, exactly what the function is expected to do.
If it would help, I'm prepared to put some time towards actually
writing something up for this.
--
Andrew (irc:RhodiumToad)
Andrew Gierth <andrew@tao11.riddles.org.uk> writes:
My opinion is that the gist-implementation section of the docs needs
to be substantially expanded so that it explains, for each support
function, exactly what the function is expected to do.
Yes, the GIST (and GIN) parts of the docs are really pretty bad.
If it would help, I'm prepared to put some time towards actually
writing something up for this.
That would be outstanding.
regards, tom lane
On Wed, Sep 22, 2010 at 10:30 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
If it would help, I'm prepared to put some time towards actually
writing something up for this.That would be outstanding.
+1. Or really, plus several.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise Postgres Company
Robert,
Are you sure postgres doesn't have limitation at all ? There are a lot ot them.
Of course, there are limitation and limitation and we should avoid limitations,
which will require incompatible changes in future in user's code, or which
prevent future improvements (getting rid limitation). We suggested
implementation of k-nn search, which has limitations, but in my opinion,
they are rather small and doesn't prevent in future to
write a descent patch, based on your five-key syscaches patches,
which will touch a lot of places in the pg source.
Who need boolean distance ? Ok, you insisted, we now support it.
Teodor wrote arguments (http://archives.postgresql.org/message-id/4C8E2590.6040802@sigaev.ru)
why two fields solution doesn't really helped.
You want "the points most distant from the bright center of the universe?",
sorry, for now. I think, this is a limitation we can live with for now.
It's k-nearest neighbourhood search, and not k-furthest outliers search.
You want documentation for review, I don't believe a reviewer can't review
without users documentation like CREATE/ALTER OPERATOR CLASS, etc.
Andrew Gierth was true,
that GiST documentation needed to be rewritten and he suggested to do that if
I understand him. I'd love to help, but I don't have any message from him.
If he changed his mind, I'll describe these changes.
We're not full-time pg-employers and it's not easy for us to follow
new cleaner-way. I think there is a risk, that there are will be lesser big
features introduced by non-pg employers in the future and eventually,
pg will be open-source database developed by pg-employers with some
amount cosmetic changes and fixes.
I suggest to find a sensible consensus on implementation, taking into
account Pareto Rule, and leave place for future improvement.
Oleg
On Tue, 14 Sep 2010, Robert Haas wrote:
2010/9/13 Teodor Sigaev <teodor@sigaev.ru>:
[updated patch]
I realize I'm repeating myself, but... this patch needs
documentation. It's not optional.It seems to me that you need to do something about AMOPSTRATEGY.
Hence the five-key syscaches patches I wrote that is sitting in queue.
And also LookupOpClassInfo(). Am I confused?Is there a reason we're using a boolean 'amoporder' distinguish
ordering operators from regular old operators? Tom and I were talking
about some kind of an integer field, in case we need more categories
later. You know, like 'amopcategory' or something like that. It
could be just one byte, perhaps, but one bit seems unduly narrow. You
could define constants OPCAT_QUAL and OPCAT_ORDER, or something like
that.This error message seems like it ought to be complaining about the
access method, not the index:+ if (!pg_am->amcanorderbyop) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("index doesn't support ordering operations")));I sort of understand the reasons behind the following restriction, but
is this truly the best we can do?+ /* + * Currently, only descending and nulls last ordering is supported + */ + if (!(pathkey->pk_strategy == BTLessStrategyNumber && pathkey->pk_nulls_first == false)) + return;What happens if we have an index strategy that can efficiently return
the points most distant from the bright center of the universe?By the way:
gistproc.c: In function ?gist_point_consistent?:
gistproc.c:1023: error: ?distance? may be used uninitialized in this function
Regards,
Oleg
_____________________________________________________________
Oleg Bartunov, Research Scientist, Head of AstroNet (www.astronet.ru),
Sternberg Astronomical Institute, Moscow University, Russia
Internet: oleg@sai.msu.su, http://www.sai.msu.su/~megera/
phone: +007(495)939-16-83, +007(495)939-23-83
On Tue, Oct 5, 2010 at 5:05 PM, Oleg Bartunov <oleg@sai.msu.su> wrote:
Are you sure postgres doesn't have limitation at all ? There are a lot ot
them. Of course, there are limitation and limitation and we should avoid
limitations, which will require incompatible changes in future in user's
code, or which prevent future improvements (getting rid limitation). We
suggested implementation of k-nn search, which has limitations, but in my
opinion, they are rather small and doesn't prevent in future to
write a descent patch, based on your five-key syscaches patches,
which will touch a lot of places in the pg source.Who need boolean distance ? Ok, you insisted, we now support it. Teodor
wrote arguments
(http://archives.postgresql.org/message-id/4C8E2590.6040802@sigaev.ru)
why two fields solution doesn't really helped.You want "the points most distant from the bright center of the universe?",
sorry, for now. I think, this is a limitation we can live with for now. It's
k-nearest neighbourhood search, and not k-furthest outliers search.You want documentation for review, I don't believe a reviewer can't review
without users documentation like CREATE/ALTER OPERATOR CLASS, etc. Andrew
Gierth was true,
that GiST documentation needed to be rewritten and he suggested to do that
if I understand him. I'd love to help, but I don't have any message from
him.
If he changed his mind, I'll describe these changes.We're not full-time pg-employers and it's not easy for us to follow new
cleaner-way. I think there is a risk, that there are will be lesser big
features introduced by non-pg employers in the future and eventually, pg
will be open-source database developed by pg-employers with some amount
cosmetic changes and fixes.I suggest to find a sensible consensus on implementation, taking into
account Pareto Rule, and leave place for future improvement.
I am sorry my review pissed you off, as it seems to have done.
Looking back on it, I realize now that it was phrased more harshly
than it needed to be. That having been said, it seems to me that we
really are at an impasse and I am not sure what to propose as a way
forward. Tom and I laid out a technical design back in January and I
still think it's a good one, even though I know you think it's silly.
We may just have to agree to disagree on this point.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise Postgres Company
forward. Tom and I laid out a technical design back in January and I
still think it's a good one, even though I know you think it's silly.
We may just have to agree to disagree on this point.
As I remember, there were several suggested designs:
1) 5-th boolean column (amopfamily, amoplefttype, amoprighttype, amopstrategy,
amoporder) to point kind of operator (search or order)
+ saves one record for operator in pg_amop
- operator could not be used in both roles
- increase number of arguments for syscache machinery
2) 5-th combined column, which contains some kind of flag for each role
+ saves one record for operator in pg_amop
+ operator could be used in both roles
- strategy number for operator is the same for both roles, it's unacceptable
because GiST's consistentFn will not have information about role. GiST
itself could distinguish them by invented SK_ORDER flag. So, this
requires to introduce one more argument for consistentFn, while it
already has 5 arguments.
- increase number of arguments for syscache machinery
3) 3-rd boolean column (amopopr, amopfamily, amoporder)
- could be two records per operator
+ operator could be used in both roles
+ strategy number could be different for different roles
All three options require to add flag of role
op_in_opfamily/get_op_opfamily_strategy/get_op_opfamily_properties to check
applicability of operation in current code path. First two options could do not
change of interface of op_in_opfamily/get_op_opfamily_strategy but it will be
needed to check actual role of operator later.
Basing on this comparison, I think, that 2) is worse and 3) is better.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
Teodor Sigaev <teodor@sigaev.ru> writes:
As I remember, there were several suggested designs: 1) 5-th boolean column (amopfamily, amoplefttype, amoprighttype, amopstrategy, amoporder) to point kind of operator (search or order) + saves one record for operator in pg_amop - operator could not be used in both roles - increase number of arguments for syscache machinery 2) 5-th combined column, which contains some kind of flag for each role + saves one record for operator in pg_amop + operator could be used in both roles - strategy number for operator is the same for both roles, it's unacceptable because GiST's consistentFn will not have information about role. GiST itself could distinguish them by invented SK_ORDER flag. So, this requires to introduce one more argument for consistentFn, while it already has 5 arguments. - increase number of arguments for syscache machinery 3) 3-rd boolean column (amopopr, amopfamily, amoporder) - could be two records per operator + operator could be used in both roles + strategy number could be different for different roles
How can #3 work at all? It's ignoring a couple of critical index
columns. In particular, I believe the sticking point here is this
unique index:
"pg_amop_fam_strat_index" UNIQUE, btree (amopfamily, amoplefttype, amoprighttype, amopstrategy)
#3 doesn't explain what to do about this index. If we extend it to
five columns, as we'd logically have to do to preserve uniqueness,
then the associated syscache has to have five key columns as well,
and now we're at solution #1.
I'm not terribly thrilled with using a boolean here in any case.
Now that we have two "roles" an operator might play in an opclass,
who's to say there might not be more roles someday? We should use
a column type that will support more than two roles without basic
rejiggering.
BTW, have we discussed the idea of embedding the role in the strategy
number? For example, require regular operators to have strategy
numbers 1-9999, while ordering operators have numbers 10000-19999,
leaving room for a couple more roles before we have to rethink the
assignment or widen amopstrategy to an int. That's a bit ugly but
might be better than adding a separate role column.
regards, tom lane
On Fri, Oct 15, 2010 at 12:02 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
BTW, have we discussed the idea of embedding the role in the strategy
number? For example, require regular operators to have strategy
numbers 1-9999, while ordering operators have numbers 10000-19999,
leaving room for a couple more roles before we have to rethink the
assignment or widen amopstrategy to an int. That's a bit ugly but
might be better than adding a separate role column.
Yeah, we talked about it.
http://archives.postgresql.org/pgsql-hackers/2010-02/msg01075.php
http://archives.postgresql.org/pgsql-hackers/2010-02/msg01079.php
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Fri, Oct 15, 2010 at 5:35 PM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Oct 15, 2010 at 12:02 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
BTW, have we discussed the idea of embedding the role in the strategy
number? For example, require regular operators to have strategy
numbers 1-9999, while ordering operators have numbers 10000-19999,
leaving room for a couple more roles before we have to rethink the
assignment or widen amopstrategy to an int. That's a bit ugly but
might be better than adding a separate role column.Yeah, we talked about it.
http://archives.postgresql.org/pgsql-hackers/2010-02/msg01075.php
http://archives.postgresql.org/pgsql-hackers/2010-02/msg01079.php
Having said that, I'm not wild on having 5-key syscaches, even though
the patch is ready to go (modulo whatever rebasing is needed, which
probably isn't much). So if you can figure out a way to avoid it,
let's do that.
I still feel vaguely uneasy about the fact that the proposed patch
can't handle ASC/DESC or NULLS FIRST/LAST, and that unease grew a bit
more last night when I read Peter's patch to add collation support.
We could possibly cram ASC/DESC and NULLS FIRST/LAST in by defining
four new categories of operator strategies rather than one, but
there's no way that's going to work for collations. Is there some
other way to approach this problem? Can we leave pg_amop as it is,
and pass the context (sort vs. qual, ASC/DESC, NULLS FIRST/LAST,
collation, whatever...) to the index via some sort of side channel?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
I still feel vaguely uneasy about the fact that the proposed patch
can't handle ASC/DESC or NULLS FIRST/LAST, and that unease grew a bit
more last night when I read Peter's patch to add collation support.
Good point.
We could possibly cram ASC/DESC and NULLS FIRST/LAST in by defining
four new categories of operator strategies rather than one, but
there's no way that's going to work for collations. Is there some
other way to approach this problem? Can we leave pg_amop as it is,
and pass the context (sort vs. qual, ASC/DESC, NULLS FIRST/LAST,
collation, whatever...) to the index via some sort of side channel?
Well, we cannot avoid changing pg_amop, or at least changing its
interpretation, because the current scheme simply can't represent
indexable operators that are used for anything except simple boolean
WHERE tests. I agree though that we do *not* want pg_amop involved
in the details of exactly what sort ordering is referenced by a sortable
operator. Somehow that needs to be passed in a side channel.
Maybe we should think in terms of a side channel for Peter's patch
as well. I share your feeling that trying to propagate collation
the same way we now propagate typmod is a recipe for serious pain.
regards, tom lane
On Fri, Oct 15, 2010 at 7:10 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
I still feel vaguely uneasy about the fact that the proposed patch
can't handle ASC/DESC or NULLS FIRST/LAST, and that unease grew a bit
more last night when I read Peter's patch to add collation support.Good point.
We could possibly cram ASC/DESC and NULLS FIRST/LAST in by defining
four new categories of operator strategies rather than one, but
there's no way that's going to work for collations. Is there some
other way to approach this problem? Can we leave pg_amop as it is,
and pass the context (sort vs. qual, ASC/DESC, NULLS FIRST/LAST,
collation, whatever...) to the index via some sort of side channel?Well, we cannot avoid changing pg_amop, or at least changing its
interpretation, because the current scheme simply can't represent
indexable operators that are used for anything except simple boolean
WHERE tests.
What exactly do you mean by that?
It has always seemed to me that the operator class mechanism is a
complicated abstraction mechanism that actually adds only a very small
amount of abstraction. Instead of referring to operators by name or
OID we refer to them by a number that maps onto a name or OID. That
allows the user to change the name or OID without breaking anything,
but that's about it. Perhaps we should think of pg_amop not so much
as a way to tell the AM what to do, but just a way to tell it what
operator is logically involved without relying on the name or OID.
I agree though that we do *not* want pg_amop involved
in the details of exactly what sort ordering is referenced by a sortable
operator. Somehow that needs to be passed in a side channel.
Yeah.
Maybe we should think in terms of a side channel for Peter's patch
as well. I share your feeling that trying to propagate collation
the same way we now propagate typmod is a recipe for serious pain.
I'm not sure what you're thinking of here. I think we can have the
idea of a FullySpecifiedType = <typid, typmod, collationoid>, but
that's not so much a side channel as an abstraction layer. It
absolutely won't work to stuff the collations in a global variable or
something like that, if that's what you're imagining.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Fri, Oct 15, 2010 at 7:10 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Well, we cannot avoid changing pg_amop, or at least changing its
interpretation, because the current scheme simply can't represent
indexable operators that are used for anything except simple boolean
WHERE tests.
What exactly do you mean by that?
It has always seemed to me that the operator class mechanism is a
complicated abstraction mechanism that actually adds only a very small
amount of abstraction. Instead of referring to operators by name or
OID we refer to them by a number that maps onto a name or OID.
Well, the amount of abstraction might be minimal, but the point is to be
able to understand which operators are related to an index and exactly
what the relationship is. There might be a better way to represent
"this operator acts as <= for btree int4 indexes" than "this operator
has strategy number 2 for btree int4 indexes", but it doesn't seem to me
that there's a lot of win available there. C code certainly finds it
more convenient to work with numbers than names, so I'm not excited
about replacing the strategy numbers with strategy names, if that's what
you're thinking.
Perhaps we should think of pg_amop not so much
as a way to tell the AM what to do, but just a way to tell it what
operator is logically involved without relying on the name or OID.
I already think of it that way ...
Maybe we should think in terms of a side channel for Peter's patch
as well. �I share your feeling that trying to propagate collation
the same way we now propagate typmod is a recipe for serious pain.
I'm not sure what you're thinking of here.
I'm not either. I'm dissatisfied with the direction he's heading
because of the amount of code it's going to break, but I don't have a
better idea. It may well be impossible to have this feature without
breaking everything in sight. (And, if we are going to break everything
in sight, now would be a good time to think about changing typmod to
something more flexible than one int32.)
regards, tom lane
On Fri, Oct 15, 2010 at 8:10 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Perhaps we should think of pg_amop not so much
as a way to tell the AM what to do, but just a way to tell it what
operator is logically involved without relying on the name or OID.I already think of it that way ...
OK.
Maybe we should think in terms of a side channel for Peter's patch
as well. I share your feeling that trying to propagate collation
the same way we now propagate typmod is a recipe for serious pain.I'm not sure what you're thinking of here.
I'm not either. I'm dissatisfied with the direction he's heading
because of the amount of code it's going to break, but I don't have a
better idea. It may well be impossible to have this feature without
breaking everything in sight. (And, if we are going to break everything
in sight, now would be a good time to think about changing typmod to
something more flexible than one int32.)
I assume I don't need to tell you my vote on that.
But I'm also not sure how far this gets us with KNNGIST, where the
issue is not the typmods but the auxilliary information about the
context of the sort and/or whether this is a sort or qual.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Fri, Oct 15, 2010 at 8:45 PM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Oct 15, 2010 at 8:10 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Perhaps we should think of pg_amop not so much
as a way to tell the AM what to do, but just a way to tell it what
operator is logically involved without relying on the name or OID.I already think of it that way ...
OK.
Thinking about it that way, perhaps we could add an integer column
amop_whats_it_good_for that gets used as a bit field. That wouldn't
require changing the index structure, although it might break some
other things.
The core KNNGIST patch is actually quite small, actually. Excluding a
lot of not-very-interesting changes to pg_amop.h, it's just over 300
lines of new code, about half of which is in indxpath.c. If we could
get this issue of how to structure the catalogs resolved, it seems to
me that we might be able to see our way to committing that part of
this work fairly quickly.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Fri, Oct 15, 2010 at 08:45:26PM -0400, Robert Haas wrote:
But I'm also not sure how far this gets us with KNNGIST, where the
issue is not the typmods but the auxilliary information about the
context of the sort and/or whether this is a sort or qual.
ISTM there are two issues here. With Btree you have the issue where the
index is of a particular collation and at planning time you're given a
collation and either it's compatable or it's not.
With Gist you have the situation where index isn't of a specific
collation but it can be used in different ways to get different
collection as output. (I'm here thinking of that Gist can in some
circumstance be asked to return tuples in a certain order.)
Actually, NULLS FIRST/LAST, ASC/DESC are just variations on collations
and my original patch many years back for each locale made *four*
collation IDs, one for each of the combinations of the above. Not
terribly scalable, but I never did get the planning code to work. :)
What you're going for here I think is a sort of cross-collation
operators, or something, that tells the planner how to get the
particular collation out of the given index. So you have something
like:
Input: en_US, NULLS FIRST, ASC
Output: en_US, NULLS_LAST, DESC
-> Reverse index scan
Input: en_US, NULLS FIRST, ASC
Output: en_US, NULLS LAST, ASC
-> Index scan, add x IS NOT NULL test
-> Append output of x IS NULL.
Input: Gist
Output: KnnGist
-> Index scan with scan type 10000
Input: Gist
Output: Gist
-> Index scan with scan type 0
Obviously this doesn't solve the problem of being able to represent the
required collation in the first place, and if this is at all compatable
with what the SQL standard calls a collation. I just don't think you
can make hard and fast rules about how to make this work and that
perhaps we should be looking for a way to push that to the index
implementation code, with the default rule being: same collection yes,
different no.
Just some thoughts,
Have a nice day,
--
Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/
Show quoted text
Patriotism is when love of your own people comes first; nationalism,
when hate for people other than your own comes first.
- Charles de Gaulle
(And, if we are going to break everything
in sight, now would be a good time to think about changing typmod to
something more flexible than one int32.)
As someone who is jamming geometry type, spatial reference number and dimensionality into said 32bit typmod, let me say emphatically ... Amen!
P
On lör, 2010-10-16 at 09:23 -0700, Paul Ramsey wrote:
(And, if we are going to break everything
in sight, now would be a good time to think about changing typmod to
something more flexible than one int32.)As someone who is jamming geometry type, spatial reference number and
dimensionality into said 32bit typmod, let me say emphatically ...
Amen!
So what kind of data structure would you like for a typmod?
On Sat, Oct 16, 2010 at 10:17 AM, Peter Eisentraut <peter_e@gmx.net> wrote:
On lör, 2010-10-16 at 09:23 -0700, Paul Ramsey wrote:
(And, if we are going to break everything
in sight, now would be a good time to think about changing typmod to
something more flexible than one int32.)As someone who is jamming geometry type, spatial reference number and
dimensionality into said 32bit typmod, let me say emphatically ...
Amen!So what kind of data structure would you like for a typmod?
I'm a primitive enough beast that just having 64-bits would make me
happy. As a general matter though, a bytea?
P
On Sat, Oct 16, 2010 at 6:13 PM, Paul Ramsey <pramsey@cleverelephant.ca> wrote:
On Sat, Oct 16, 2010 at 10:17 AM, Peter Eisentraut <peter_e@gmx.net> wrote:
On lör, 2010-10-16 at 09:23 -0700, Paul Ramsey wrote:
(And, if we are going to break everything
in sight, now would be a good time to think about changing typmod to
something more flexible than one int32.)As someone who is jamming geometry type, spatial reference number and
dimensionality into said 32bit typmod, let me say emphatically ...
Amen!So what kind of data structure would you like for a typmod?
I'm a primitive enough beast that just having 64-bits would make me
happy. As a general matter though, a bytea?
Yeah. It strikes me that there are three main kinds of things people
might want to represent:
1. An integer. e.g. for a numeric, precision or scale; for a varchar,
length; for an array, number of dimensions.
2. An OID. e.g. for varchar or text, a collation OID.
3. Recursive structure. So you might have an array (which is
one-dimensional) containing strings (which are limited to 80
characters and collated in Klingon). You want to hold onto all of
those details somehow.
There might be use cases for even crazier things - like packing all
the field names and types for a record object in there... but maybe
that's too crazy to be workable.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Fri, Oct 15, 2010 at 9:39 PM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Oct 15, 2010 at 8:45 PM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Oct 15, 2010 at 8:10 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Perhaps we should think of pg_amop not so much
as a way to tell the AM what to do, but just a way to tell it what
operator is logically involved without relying on the name or OID.I already think of it that way ...
OK.
Thinking about it that way, perhaps we could add an integer column
amop_whats_it_good_for that gets used as a bit field. That wouldn't
require changing the index structure, although it might break some
other things.
I gave this a shot (though I called it amoppurpose rather than
amop_whats_it_good_for) and I think it's a reasonable way to proceed.
Proof-of-concept patch attached. This just adds the column (using the
existing padding space), defines AMOP_SEARCH and AMOP_ORDER, and makes
just about everything ignore anything not marked AMOP_SEARCH,
attached. This would obviously need some more hacking to pay
attention to AMOP_ORDER where relevant, etc. and to create some actual
syntax around it. Currently CREATE OPERATOR CLASS / ALTER OPERATOR
FAMILY have this bit:
OPERATOR strategy_number ( op_type [ , op_type ] )
knngist-0.9 implements this:
[ORDER] OPERATOR strategy_number ( op_type [, op_type ] )
...but with the design proposed above that's not quite what we'd want,
because amoppurpose is a bit field, so you could have one or both of
the two possible purposes. Perhaps:
OPERATOR strategy_number ( op_type [ , op_type ] ) [ FOR { SEARCH |
ORDER } [, ...] ]
With the default being FOR SEARCH.
Comments?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Sat, Oct 16, 2010 at 9:54 PM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Oct 15, 2010 at 9:39 PM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Oct 15, 2010 at 8:45 PM, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Oct 15, 2010 at 8:10 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Perhaps we should think of pg_amop not so much
as a way to tell the AM what to do, but just a way to tell it what
operator is logically involved without relying on the name or OID.I already think of it that way ...
OK.
Thinking about it that way, perhaps we could add an integer column
amop_whats_it_good_for that gets used as a bit field. That wouldn't
require changing the index structure, although it might break some
other things.I gave this a shot (though I called it amoppurpose rather than
amop_whats_it_good_for) and I think it's a reasonable way to proceed.
Proof-of-concept patch attached. This just adds the column (using the
existing padding space), defines AMOP_SEARCH and AMOP_ORDER, and makes
just about everything ignore anything not marked AMOP_SEARCH,
attached. This would obviously need some more hacking to pay
attention to AMOP_ORDER where relevant, etc. and to create some actual
syntax around it. Currently CREATE OPERATOR CLASS / ALTER OPERATOR
FAMILY have this bit:OPERATOR strategy_number ( op_type [ , op_type ] )
knngist-0.9 implements this:
[ORDER] OPERATOR strategy_number ( op_type [, op_type ] )
...but with the design proposed above that's not quite what we'd want,
because amoppurpose is a bit field, so you could have one or both of
the two possible purposes. Perhaps:OPERATOR strategy_number ( op_type [ , op_type ] ) [ FOR { SEARCH |
ORDER } [, ...] ]With the default being FOR SEARCH.
Comments?
And here's the attachment, sorry.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachments:
amoppurpose-v1.patchtext/x-patch; charset=US-ASCII; name=amoppurpose-v1.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index bf695ed..e51a80d 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -646,6 +646,13 @@
</row>
<row>
+ <entry><structfield>amoppurpose</structfield></entry>
+ <entry><type>int2</type></entry>
+ <entry></entry>
+ <entry>Bit field indicating valid purposes of operator within operator family (1 = search, 2 = ordering)</entry>
+ </row>
+
+ <row>
<entry><structfield>amopopr</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 8f0f226..238e9dc 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -21,6 +21,7 @@
#include "access/nbtree.h"
#include "access/reloptions.h"
#include "access/relscan.h"
+#include "catalog/pg_amop.h"
#include "executor/execdebug.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
@@ -622,7 +623,8 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
cmp_op = get_opfamily_member(rel->rd_opfamily[leftarg->sk_attno - 1],
lefttype,
righttype,
- strat);
+ strat,
+ AMOP_SEARCH);
if (OidIsValid(cmp_op))
{
RegProcedure cmp_proc = get_opcode(cmp_op);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 9407d0f..c512792 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -24,6 +24,7 @@
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_tablespace.h"
@@ -988,10 +989,11 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
errdetail("Only commutative operators can be used in exclusion constraints.")));
/*
- * Operator must be a member of the right opfamily, too
+ * Operator must be a member of the right opfamily, too.
+ * And should be useful for search.
*/
opfamily = get_opclass_family(classOidP[attn]);
- strat = get_op_opfamily_strategy(opid, opfamily);
+ strat = get_op_opfamily_strategy(opid, opfamily, AMOP_SEARCH);
if (strat == 0)
{
HeapTuple opftuple;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c009711..4afba2f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -26,6 +26,7 @@
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_inherits.h"
@@ -5184,7 +5185,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
* We'll use it for PK = PK comparisons.
*/
ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
- eqstrategy);
+ eqstrategy, AMOP_SEARCH);
if (!OidIsValid(ppeqop))
elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
@@ -5197,10 +5198,10 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
fktyped = getBaseType(fktype);
pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
- eqstrategy);
+ eqstrategy, AMOP_SEARCH);
if (OidIsValid(pfeqop))
ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
- eqstrategy);
+ eqstrategy, AMOP_SEARCH);
else
ffeqop = InvalidOid; /* keep compiler quiet */
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 7d7c1a1..a72fc9f 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -38,6 +38,7 @@
#include "access/nbtree.h"
#include "access/tupconvert.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "executor/execdebug.h"
@@ -4712,7 +4713,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
Oid righttype;
Oid proc;
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&strategy,
&lefttype,
&righttype);
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index ee5fc72..9ccd5ec 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -27,6 +27,7 @@
#include "access/genam.h"
#include "access/nbtree.h"
#include "access/relscan.h"
+#include "catalog/pg_amop.h"
#include "executor/execdebug.h"
#include "executor/nodeIndexscan.h"
#include "optimizer/clauses.h"
@@ -742,7 +743,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
*/
opfamily = index->rd_opfamily[varattno - 1];
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -832,7 +833,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
elog(ERROR, "bogus RowCompare index qualification");
opfamily = index->rd_opfamily[varattno - 1];
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -935,7 +936,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
*/
opfamily = index->rd_opfamily[varattno - 1];
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index e8ce5bc..d0836c4 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -201,7 +201,7 @@ MJExamineQuals(List *mergeclauses,
clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent);
/* Extract the operator's declared left/right datatypes */
- get_op_opfamily_properties(qual->opno, opfamily,
+ get_op_opfamily_properties(qual->opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index e44e960..704fdb7 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -17,6 +17,7 @@
#include "postgres.h"
#include "access/skey.h"
+#include "catalog/pg_amop.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
@@ -1023,7 +1024,7 @@ select_equality_operator(EquivalenceClass *ec, Oid lefttype, Oid righttype)
Oid opno;
opno = get_opfamily_member(opfamily, lefttype, righttype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber, AMOP_SEARCH);
if (OidIsValid(opno))
return opno;
}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 38b0930..0101abc 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -19,6 +19,7 @@
#include "access/skey.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_type.h"
@@ -87,7 +88,7 @@ static bool match_clause_to_indexcol(IndexOptInfo *index,
RestrictInfo *rinfo,
Relids outer_relids,
SaOpControl saop_control);
-static bool is_indexable_operator(Oid expr_op, Oid opfamily,
+static bool is_indexable_operator(Oid expr_op, Oid opfamily, int purpose,
bool indexkey_on_left);
static bool match_rowcompare_to_indexcol(IndexOptInfo *index,
int indexcol,
@@ -1272,7 +1273,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
bms_is_subset(right_relids, outer_relids) &&
!contain_volatile_functions(rightop))
{
- if (is_indexable_operator(expr_op, opfamily, true))
+ if (is_indexable_operator(expr_op, opfamily, AMOP_SEARCH, true))
return true;
/*
@@ -1290,7 +1291,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
bms_is_subset(left_relids, outer_relids) &&
!contain_volatile_functions(leftop))
{
- if (is_indexable_operator(expr_op, opfamily, false))
+ if (is_indexable_operator(expr_op, opfamily, AMOP_SEARCH, false))
return true;
/*
@@ -1314,7 +1315,8 @@ match_clause_to_indexcol(IndexOptInfo *index,
* the opfamily.
*/
static bool
-is_indexable_operator(Oid expr_op, Oid opfamily, bool indexkey_on_left)
+is_indexable_operator(Oid expr_op, Oid opfamily, int purpose,
+ bool indexkey_on_left)
{
/* Get the commuted operator if necessary */
if (!indexkey_on_left)
@@ -1325,7 +1327,7 @@ is_indexable_operator(Oid expr_op, Oid opfamily, bool indexkey_on_left)
}
/* OK if the (commuted) operator is a member of the index's opfamily */
- return op_in_opfamily(expr_op, opfamily);
+ return op_in_opfamily(expr_op, opfamily, purpose);
}
/*
@@ -1384,7 +1386,7 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
return false;
/* We're good if the operator is the right type of opfamily member */
- switch (get_op_opfamily_strategy(expr_op, opfamily))
+ switch (get_op_opfamily_strategy(expr_op, opfamily, AMOP_SEARCH))
{
case BTLessStrategyNumber:
case BTLessEqualStrategyNumber:
@@ -2552,7 +2554,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_BPCHAR_LIKE_OP:
case OID_NAME_LIKE_OP:
case OID_BYTEA_LIKE_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,
&prefix, &rest);
@@ -2563,7 +2565,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_TEXT_ICLIKE_OP:
case OID_BPCHAR_ICLIKE_OP:
case OID_NAME_ICLIKE_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
@@ -2575,7 +2577,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_TEXT_REGEXEQ_OP:
case OID_BPCHAR_REGEXEQ_OP:
case OID_NAME_REGEXEQ_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,
@@ -2587,7 +2589,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_TEXT_ICREGEXEQ_OP:
case OID_BPCHAR_ICREGEXEQ_OP:
case OID_NAME_ICREGEXEQ_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
@@ -2598,7 +2600,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_INET_SUB_OP:
case OID_INET_SUBEQ_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
return network_prefix_quals(leftop, expr_op, opfamily,
patt->constvalue);
@@ -2656,7 +2658,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
expr_op = linitial_oid(clause->opnos);
if (!var_on_left)
expr_op = get_commutator(expr_op);
- get_op_opfamily_properties(expr_op, index->opfamily[indexcol],
+ get_op_opfamily_properties(expr_op, index->opfamily[indexcol], AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -2719,12 +2721,12 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
break; /* no match found */
/* Now, do we have the right operator for this column? */
- if (get_op_opfamily_strategy(expr_op, index->opfamily[i])
+ if (get_op_opfamily_strategy(expr_op, index->opfamily[i], AMOP_SEARCH)
!= op_strategy)
break;
/* Add opfamily and datatypes to lists */
- get_op_opfamily_properties(expr_op, index->opfamily[i],
+ get_op_opfamily_properties(expr_op, index->opfamily[i], AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -2776,7 +2778,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
Oid righttype = lfirst_oid(righttypes_cell);
expr_op = get_opfamily_member(opfam, lefttype, righttype,
- op_strategy);
+ op_strategy, AMOP_SEARCH);
if (!OidIsValid(expr_op)) /* should not happen */
elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
op_strategy, lefttype, righttype, opfam);
@@ -2900,7 +2902,7 @@ prefix_quals(Node *leftop, Oid opfamily,
if (pstatus == Pattern_Prefix_Exact)
{
oproid = get_opfamily_member(opfamily, datatype, datatype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber, AMOP_SEARCH);
if (oproid == InvalidOid)
elog(ERROR, "no = operator for opfamily %u", opfamily);
expr = make_opclause(oproid, BOOLOID, false,
@@ -2915,7 +2917,7 @@ prefix_quals(Node *leftop, Oid opfamily,
* We can always say "x >= prefix".
*/
oproid = get_opfamily_member(opfamily, datatype, datatype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber, AMOP_SEARCH);
if (oproid == InvalidOid)
elog(ERROR, "no >= operator for opfamily %u", opfamily);
expr = make_opclause(oproid, BOOLOID, false,
@@ -2928,7 +2930,7 @@ prefix_quals(Node *leftop, Oid opfamily,
*-------
*/
oproid = get_opfamily_member(opfamily, datatype, datatype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber, AMOP_SEARCH);
if (oproid == InvalidOid)
elog(ERROR, "no < operator for opfamily %u", opfamily);
fmgr_info(get_opcode(oproid), <proc);
@@ -2982,14 +2984,16 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
if (is_eq)
{
opr1oid = get_opfamily_member(opfamily, datatype, datatype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber,
+ AMOP_SEARCH);
if (opr1oid == InvalidOid)
elog(ERROR, "no >= operator for opfamily %u", opfamily);
}
else
{
opr1oid = get_opfamily_member(opfamily, datatype, datatype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
if (opr1oid == InvalidOid)
elog(ERROR, "no > operator for opfamily %u", opfamily);
}
@@ -3005,7 +3009,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
/* create clause "key <= network_scan_last( rightop )" */
opr2oid = get_opfamily_member(opfamily, datatype, datatype,
- BTLessEqualStrategyNumber);
+ BTLessEqualStrategyNumber, AMOP_SEARCH);
if (opr2oid == InvalidOid)
elog(ERROR, "no <= operator for opfamily %u", opfamily);
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 643d57a..753ee8b 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -18,6 +18,7 @@
#include "postgres.h"
#include "access/skey.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -266,7 +267,8 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
equality_op = get_opfamily_member(opfamily,
opcintype,
opcintype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (!OidIsValid(equality_op)) /* shouldn't happen */
elog(ERROR, "could not find equality operator for ordering operator %u",
ordering_op);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 52dd27b..fe2c650 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -20,6 +20,7 @@
#include <math.h>
#include "access/skey.h"
+#include "catalog/pg_amop.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -3403,7 +3404,8 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
sortop = get_opfamily_member(pathkey->pk_opfamily,
pk_datatype,
pk_datatype,
- pathkey->pk_strategy);
+ pathkey->pk_strategy,
+ AMOP_SEARCH);
if (!OidIsValid(sortop)) /* should not happen */
elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
pathkey->pk_strategy, pk_datatype, pk_datatype,
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index e590ee0..7b605de 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -16,6 +16,7 @@
#include "catalog/pg_aggregate.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -390,7 +391,8 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
continue;
strategy =
get_op_opfamily_strategy(((OpExpr *) rinfo->clause)->opno,
- index->opfamily[prevcol]);
+ index->opfamily[prevcol],
+ AMOP_SEARCH);
if (strategy == BTEqualStrategyNumber)
break;
}
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index 5ab4a31..bb013af 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -1640,8 +1640,9 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
HeapTuple clause_tuple;
- /* Must be btree */
- if (pred_form->amopmethod != BTREE_AM_OID)
+ /* Must be btree operator, usable for searching */
+ if (pred_form->amopmethod != BTREE_AM_OID
+ || (pred_form->amoppurpose & AMOP_SEARCH) == 0)
continue;
/* Get the predicate operator's btree strategy number */
@@ -1664,7 +1665,7 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
clause_tuple = SearchSysCache2(AMOPOPID,
ObjectIdGetDatum(clause_op),
ObjectIdGetDatum(opfamily_id));
- if (HeapTupleIsValid(clause_tuple))
+ if (HeapTupleIsValid(clause_tuple)) /* ZZZ */
{
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
@@ -1725,7 +1726,8 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
test_op = get_opfamily_member(opfamily_id,
pred_form->amoprighttype,
clause_righttype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (OidIsValid(test_op))
test_op = get_negator(test_op);
}
@@ -1734,7 +1736,8 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
test_op = get_opfamily_member(opfamily_id,
pred_form->amoprighttype,
clause_righttype,
- test_strategy);
+ test_strategy,
+ AMOP_SEARCH);
}
if (OidIsValid(test_op))
{
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 34369e5..c436b28 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -93,6 +93,7 @@
#include "access/sysattr.h"
#include "catalog/index.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
@@ -1214,7 +1215,8 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate)
* Pattern specifies an exact match, so pretend operator is '='
*/
Oid eqopr = get_opfamily_member(opfamily, vartype, vartype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (eqopr == InvalidOid)
elog(ERROR, "no = operator for opfamily %u", opfamily);
@@ -2630,7 +2632,7 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
examine_variable(root, right, 0, &rightvar);
/* Extract the operator's declared left/right datatypes */
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -2652,10 +2654,12 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
/* easy case */
ltop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
leop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTLessEqualStrategyNumber);
+ BTLessEqualStrategyNumber,
+ AMOP_SEARCH);
lsortop = ltop;
rsortop = ltop;
lstatop = lsortop;
@@ -2667,24 +2671,30 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
{
ltop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
leop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTLessEqualStrategyNumber);
+ BTLessEqualStrategyNumber,
+ AMOP_SEARCH);
lsortop = get_opfamily_member(opfamily,
op_lefttype, op_lefttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
rsortop = get_opfamily_member(opfamily,
op_righttype, op_righttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
lstatop = lsortop;
rstatop = rsortop;
revltop = get_opfamily_member(opfamily,
op_righttype, op_lefttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
revleop = get_opfamily_member(opfamily,
op_righttype, op_lefttype,
- BTLessEqualStrategyNumber);
+ BTLessEqualStrategyNumber,
+ AMOP_SEARCH);
}
break;
case BTGreaterStrategyNumber:
@@ -2695,15 +2705,18 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
/* easy case */
ltop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
leop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber,
+ AMOP_SEARCH);
lsortop = ltop;
rsortop = ltop;
lstatop = get_opfamily_member(opfamily,
op_lefttype, op_lefttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
rstatop = lstatop;
revltop = ltop;
revleop = leop;
@@ -2712,28 +2725,36 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
{
ltop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
leop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber,
+ AMOP_SEARCH);
lsortop = get_opfamily_member(opfamily,
op_lefttype, op_lefttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
rsortop = get_opfamily_member(opfamily,
op_righttype, op_righttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
lstatop = get_opfamily_member(opfamily,
op_lefttype, op_lefttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
rstatop = get_opfamily_member(opfamily,
op_righttype, op_righttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
revltop = get_opfamily_member(opfamily,
op_righttype, op_lefttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
revleop = get_opfamily_member(opfamily,
op_righttype, op_lefttype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber,
+ AMOP_SEARCH);
}
break;
default:
@@ -5085,7 +5106,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
Selectivity eq_sel;
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber, AMOP_SEARCH);
if (cmpopr == InvalidOid)
elog(ERROR, "no >= operator for opfamily %u", opfamily);
fmgr_info(get_opcode(cmpopr), &opproc);
@@ -5106,7 +5127,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
*-------
*/
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber, AMOP_SEARCH);
if (cmpopr == InvalidOid)
elog(ERROR, "no < operator for opfamily %u", opfamily);
fmgr_info(get_opcode(cmpopr), &opproc);
@@ -5146,7 +5167,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
* small estimate from the >= condition; so we still need to clamp.
*/
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber, AMOP_SEARCH);
if (cmpopr == InvalidOid)
elog(ERROR, "no = operator for opfamily %u", opfamily);
eq_sel = var_eq_const(vardata, cmpopr, prefixcon->constvalue,
@@ -6017,7 +6038,8 @@ btcostestimate(PG_FUNCTION_ARGS)
if (OidIsValid(clause_op))
{
op_strategy = get_op_opfamily_strategy(clause_op,
- index->opfamily[indexcol]);
+ index->opfamily[indexcol],
+ AMOP_SEARCH);
Assert(op_strategy != 0); /* not a member of opfamily?? */
if (op_strategy == BTEqualStrategyNumber)
eqQualHere = true;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 6fae618..3a2dd82 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -44,24 +44,36 @@ get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
/*
* op_in_opfamily
*
- * Return t iff operator 'opno' is in operator family 'opfamily'.
+ * Return t iff operator 'opno' is in operator family 'opfamily'
+ * with purpose 'purpose'.
*/
bool
-op_in_opfamily(Oid opno, Oid opfamily)
+op_in_opfamily(Oid opno, Oid opfamily, int purpose)
{
- return SearchSysCacheExists2(AMOPOPID,
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(opfamily));
+ HeapTuple tp;
+ Form_pg_amop amop_tup;
+ int amop_purpose;
+
+ tp = SearchSysCache2(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ ObjectIdGetDatum(opfamily));
+ if (!HeapTupleIsValid(tp))
+ return 0;
+ amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+ amop_purpose = amop_tup->amoppurpose;
+ ReleaseSysCache(tp);
+ return (amop_purpose & purpose) != 0;
}
/*
* get_op_opfamily_strategy
*
* Get the operator's strategy number within the specified opfamily,
- * or 0 if it's not a member of the opfamily.
+ * or 0 if it's not a member of the opfamily or not useful for the
+ * specified purpose.
*/
int
-get_op_opfamily_strategy(Oid opno, Oid opfamily)
+get_op_opfamily_strategy(Oid opno, Oid opfamily, int purpose)
{
HeapTuple tp;
Form_pg_amop amop_tup;
@@ -73,7 +85,10 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
if (!HeapTupleIsValid(tp))
return 0;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
- result = amop_tup->amopstrategy;
+ if ((amop_tup->amoppurpose & purpose) != 0)
+ result = amop_tup->amopstrategy;
+ else
+ result = 0;
ReleaseSysCache(tp);
return result;
}
@@ -88,7 +103,7 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
* therefore we raise an error if the tuple is not found.
*/
void
-get_op_opfamily_properties(Oid opno, Oid opfamily,
+get_op_opfamily_properties(Oid opno, Oid opfamily, int purpose,
int *strategy,
Oid *lefttype,
Oid *righttype)
@@ -103,6 +118,9 @@ get_op_opfamily_properties(Oid opno, Oid opfamily,
elog(ERROR, "operator %u is not a member of opfamily %u",
opno, opfamily);
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+ if ((amop_tup->amoppurpose & purpose) == 0)
+ elog(ERROR, "operator %u in opfamily %u can't be used for purpose %d",
+ opno, opfamily, purpose);
*strategy = amop_tup->amopstrategy;
*lefttype = amop_tup->amoplefttype;
*righttype = amop_tup->amoprighttype;
@@ -114,11 +132,12 @@ get_op_opfamily_properties(Oid opno, Oid opfamily,
* Get the OID of the operator that implements the specified strategy
* with the specified datatypes for the specified opfamily.
*
- * Returns InvalidOid if there is no pg_amop entry for the given keys.
+ * Returns InvalidOid if there is no pg_amop entry for the given keys, or
+ * if the operator is not useful for the specified purpose.
*/
Oid
get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
- int16 strategy)
+ int16 strategy, int16 purpose)
{
HeapTuple tp;
Form_pg_amop amop_tup;
@@ -132,7 +151,10 @@ get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
if (!HeapTupleIsValid(tp))
return InvalidOid;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
- result = amop_tup->amopopr;
+ if ((amop_tup->amoppurpose & purpose) != 0)
+ result = amop_tup->amopopr;
+ else
+ result = InvalidOid;
ReleaseSysCache(tp);
return result;
}
@@ -181,8 +203,9 @@ get_ordering_op_properties(Oid opno,
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
- /* must be btree */
- if (aform->amopmethod != BTREE_AM_OID)
+ /* must be btree search op */
+ if (aform->amopmethod != BTREE_AM_OID
+ && (aform->amoppurpose & AMOP_SEARCH) != 0)
continue;
if (aform->amopstrategy == BTLessStrategyNumber ||
@@ -276,7 +299,8 @@ get_equality_op_for_ordering_op(Oid opno, bool *reverse)
result = get_opfamily_member(opfamily,
opcintype,
opcintype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (reverse)
*reverse = (strategy == BTGreaterStrategyNumber);
}
@@ -316,8 +340,9 @@ get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
- /* must be btree */
- if (aform->amopmethod != BTREE_AM_OID)
+ /* must be btree search op */
+ if (aform->amopmethod != BTREE_AM_OID
+ && (aform->amoppurpose & AMOP_SEARCH) != 0)
continue;
if (aform->amopstrategy == BTEqualStrategyNumber)
@@ -328,7 +353,8 @@ get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
result = get_opfamily_member(aform->amopfamily,
typid, typid,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
if (OidIsValid(result))
break;
/* failure probably shouldn't happen, but keep looking if so */
@@ -379,6 +405,7 @@ get_mergejoin_opfamilies(Oid opno)
/* must be btree equality */
if (aform->amopmethod == BTREE_AM_OID &&
+ (aform->amoppurpose & AMOP_SEARCH) != 0 &&
aform->amopstrategy == BTEqualStrategyNumber)
result = lappend_oid(result, aform->amopfamily);
}
@@ -430,6 +457,7 @@ get_compatible_hash_operators(Oid opno,
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopmethod == HASH_AM_OID &&
+ (aform->amoppurpose & AMOP_SEARCH) != 0 &&
aform->amopstrategy == HTEqualStrategyNumber)
{
/* No extra lookup needed if given operator is single-type */
@@ -453,7 +481,8 @@ get_compatible_hash_operators(Oid opno,
*lhs_opno = get_opfamily_member(aform->amopfamily,
aform->amoplefttype,
aform->amoplefttype,
- HTEqualStrategyNumber);
+ HTEqualStrategyNumber,
+ AMOP_SEARCH);
if (!OidIsValid(*lhs_opno))
continue;
/* Matching LHS found, done if caller doesn't want RHS */
@@ -468,7 +497,8 @@ get_compatible_hash_operators(Oid opno,
*rhs_opno = get_opfamily_member(aform->amopfamily,
aform->amoprighttype,
aform->amoprighttype,
- HTEqualStrategyNumber);
+ HTEqualStrategyNumber,
+ AMOP_SEARCH);
if (!OidIsValid(*rhs_opno))
{
/* Forget any LHS operator from this opfamily */
@@ -530,6 +560,7 @@ get_op_hash_functions(Oid opno,
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopmethod == HASH_AM_OID &&
+ (aform->amoppurpose & AMOP_SEARCH) != 0 &&
aform->amopstrategy == HTEqualStrategyNumber)
{
/*
@@ -635,8 +666,9 @@ get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
Oid opfamily_id;
StrategyNumber op_strategy;
- /* must be btree */
- if (op_form->amopmethod != BTREE_AM_OID)
+ /* must be btree search op */
+ if (op_form->amopmethod != BTREE_AM_OID
+ && (op_form->amoppurpose & AMOP_SEARCH) != 0)
continue;
/* Get the operator's btree strategy number */
@@ -692,11 +724,12 @@ equality_ops_are_compatible(Oid opno1, Oid opno2)
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
- /* must be btree or hash */
- if (op_form->amopmethod == BTREE_AM_OID ||
- op_form->amopmethod == HASH_AM_OID)
+ /* must be btree or hash search op */
+ if ((op_form->amopmethod == BTREE_AM_OID ||
+ op_form->amopmethod == HASH_AM_OID) &&
+ (op_form->amoppurpose & AMOP_SEARCH) != 0)
{
- if (op_in_opfamily(opno2, op_form->amopfamily))
+ if (op_in_opfamily(opno2, op_form->amopfamily, AMOP_SEARCH))
{
result = true;
break;
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 2a44303..04e8f61 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3828,7 +3828,8 @@ RelationGetExclusionInfo(Relation indexRelation,
{
funcs[i] = get_opcode(ops[i]);
strats[i] = get_op_opfamily_strategy(ops[i],
- indexRelation->rd_opfamily[i]);
+ indexRelation->rd_opfamily[i],
+ AMOP_SEARCH);
/* shouldn't fail, since it was checked at index creation */
if (strats[i] == InvalidStrategy)
elog(ERROR, "could not find strategy for operator %u in family %u",
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index 2009614..be151a8 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -45,6 +45,7 @@
#include "access/hash.h"
#include "access/heapam.h"
#include "access/nbtree.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "utils/builtins.h"
@@ -216,13 +217,15 @@ lookup_type_cache(Oid type_id, int flags)
typentry->eq_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (typentry->eq_opr == InvalidOid &&
typentry->hash_opf != InvalidOid)
typentry->eq_opr = get_opfamily_member(typentry->hash_opf,
typentry->hash_opintype,
typentry->hash_opintype,
- HTEqualStrategyNumber);
+ HTEqualStrategyNumber,
+ AMOP_SEARCH);
}
if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid)
{
@@ -230,7 +233,8 @@ lookup_type_cache(Oid type_id, int flags)
typentry->lt_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
}
if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid)
{
@@ -238,7 +242,8 @@ lookup_type_cache(Oid type_id, int flags)
typentry->gt_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
}
if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
typentry->cmp_proc == InvalidOid)
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index d5cf859..baee0ff 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -22,6 +22,15 @@
* This implies that the same operator cannot be listed for multiple strategy
* numbers within a single opfamily.
*
+ * amoppurpose is specifies the purpose(s) of this operator within the
+ * operator family, and is interpreted as a bit-field. AMOP_SEARCH operators
+ * are useful for queries of the form SELECT ... FROM table WHERE col OP val;
+ * AMOP_ORDER operators are useful for queries of the form SELECT ... FROM
+ * table ORDER BY col OP val. In theory, an operator could be useful for
+ * both purposes, although in practice this is not very likely since a
+ * search operator must return bool, which is not necessarily useful for
+ * ordering.
+ *
* amopmethod is a copy of the owning opfamily's opfmethod field. This is an
* intentional denormalization of the catalogs to buy lookup speed.
*
@@ -49,12 +58,16 @@
*/
#define AccessMethodOperatorRelationId 2602
+#define AMOP_SEARCH 1
+#define AMOP_ORDER 2
+
CATALOG(pg_amop,2602)
{
Oid amopfamily; /* the index opfamily this entry is for */
Oid amoplefttype; /* operator's left input data type */
Oid amoprighttype; /* operator's right input data type */
int2 amopstrategy; /* operator strategy number */
+ int2 amoppurpose; /* operator's purpose */
Oid amopopr; /* the operator's pg_operator OID */
Oid amopmethod; /* the index access method this entry is for */
} FormData_pg_amop;
@@ -70,13 +83,14 @@ typedef FormData_pg_amop *Form_pg_amop;
* compiler constants for pg_amop
* ----------------
*/
-#define Natts_pg_amop 6
+#define Natts_pg_amop 7
#define Anum_pg_amop_amopfamily 1
#define Anum_pg_amop_amoplefttype 2
#define Anum_pg_amop_amoprighttype 3
#define Anum_pg_amop_amopstrategy 4
-#define Anum_pg_amop_amopopr 5
-#define Anum_pg_amop_amopmethod 6
+#define Anum_pg_amop_amoppurpose 5
+#define Anum_pg_amop_amopopr 6
+#define Anum_pg_amop_amopmethod 7
/* ----------------
* initial contents of pg_amop
@@ -88,610 +102,610 @@ typedef FormData_pg_amop *Form_pg_amop;
*/
/* default operators int2 */
-DATA(insert ( 1976 21 21 1 95 403 ));
-DATA(insert ( 1976 21 21 2 522 403 ));
-DATA(insert ( 1976 21 21 3 94 403 ));
-DATA(insert ( 1976 21 21 4 524 403 ));
-DATA(insert ( 1976 21 21 5 520 403 ));
+DATA(insert ( 1976 21 21 1 1 95 403 ));
+DATA(insert ( 1976 21 21 2 1 522 403 ));
+DATA(insert ( 1976 21 21 3 1 94 403 ));
+DATA(insert ( 1976 21 21 4 1 524 403 ));
+DATA(insert ( 1976 21 21 5 1 520 403 ));
/* crosstype operators int24 */
-DATA(insert ( 1976 21 23 1 534 403 ));
-DATA(insert ( 1976 21 23 2 540 403 ));
-DATA(insert ( 1976 21 23 3 532 403 ));
-DATA(insert ( 1976 21 23 4 542 403 ));
-DATA(insert ( 1976 21 23 5 536 403 ));
+DATA(insert ( 1976 21 23 1 1 534 403 ));
+DATA(insert ( 1976 21 23 2 1 540 403 ));
+DATA(insert ( 1976 21 23 3 1 532 403 ));
+DATA(insert ( 1976 21 23 4 1 542 403 ));
+DATA(insert ( 1976 21 23 5 1 536 403 ));
/* crosstype operators int28 */
-DATA(insert ( 1976 21 20 1 1864 403 ));
-DATA(insert ( 1976 21 20 2 1866 403 ));
-DATA(insert ( 1976 21 20 3 1862 403 ));
-DATA(insert ( 1976 21 20 4 1867 403 ));
-DATA(insert ( 1976 21 20 5 1865 403 ));
+DATA(insert ( 1976 21 20 1 1 1864 403 ));
+DATA(insert ( 1976 21 20 2 1 1866 403 ));
+DATA(insert ( 1976 21 20 3 1 1862 403 ));
+DATA(insert ( 1976 21 20 4 1 1867 403 ));
+DATA(insert ( 1976 21 20 5 1 1865 403 ));
/* default operators int4 */
-DATA(insert ( 1976 23 23 1 97 403 ));
-DATA(insert ( 1976 23 23 2 523 403 ));
-DATA(insert ( 1976 23 23 3 96 403 ));
-DATA(insert ( 1976 23 23 4 525 403 ));
-DATA(insert ( 1976 23 23 5 521 403 ));
+DATA(insert ( 1976 23 23 1 1 97 403 ));
+DATA(insert ( 1976 23 23 2 1 523 403 ));
+DATA(insert ( 1976 23 23 3 1 96 403 ));
+DATA(insert ( 1976 23 23 4 1 525 403 ));
+DATA(insert ( 1976 23 23 5 1 521 403 ));
/* crosstype operators int42 */
-DATA(insert ( 1976 23 21 1 535 403 ));
-DATA(insert ( 1976 23 21 2 541 403 ));
-DATA(insert ( 1976 23 21 3 533 403 ));
-DATA(insert ( 1976 23 21 4 543 403 ));
-DATA(insert ( 1976 23 21 5 537 403 ));
+DATA(insert ( 1976 23 21 1 1 535 403 ));
+DATA(insert ( 1976 23 21 2 1 541 403 ));
+DATA(insert ( 1976 23 21 3 1 533 403 ));
+DATA(insert ( 1976 23 21 4 1 543 403 ));
+DATA(insert ( 1976 23 21 5 1 537 403 ));
/* crosstype operators int48 */
-DATA(insert ( 1976 23 20 1 37 403 ));
-DATA(insert ( 1976 23 20 2 80 403 ));
-DATA(insert ( 1976 23 20 3 15 403 ));
-DATA(insert ( 1976 23 20 4 82 403 ));
-DATA(insert ( 1976 23 20 5 76 403 ));
+DATA(insert ( 1976 23 20 1 1 37 403 ));
+DATA(insert ( 1976 23 20 2 1 80 403 ));
+DATA(insert ( 1976 23 20 3 1 15 403 ));
+DATA(insert ( 1976 23 20 4 1 82 403 ));
+DATA(insert ( 1976 23 20 5 1 76 403 ));
/* default operators int8 */
-DATA(insert ( 1976 20 20 1 412 403 ));
-DATA(insert ( 1976 20 20 2 414 403 ));
-DATA(insert ( 1976 20 20 3 410 403 ));
-DATA(insert ( 1976 20 20 4 415 403 ));
-DATA(insert ( 1976 20 20 5 413 403 ));
+DATA(insert ( 1976 20 20 1 1 412 403 ));
+DATA(insert ( 1976 20 20 2 1 414 403 ));
+DATA(insert ( 1976 20 20 3 1 410 403 ));
+DATA(insert ( 1976 20 20 4 1 415 403 ));
+DATA(insert ( 1976 20 20 5 1 413 403 ));
/* crosstype operators int82 */
-DATA(insert ( 1976 20 21 1 1870 403 ));
-DATA(insert ( 1976 20 21 2 1872 403 ));
-DATA(insert ( 1976 20 21 3 1868 403 ));
-DATA(insert ( 1976 20 21 4 1873 403 ));
-DATA(insert ( 1976 20 21 5 1871 403 ));
+DATA(insert ( 1976 20 21 1 1 1870 403 ));
+DATA(insert ( 1976 20 21 2 1 1872 403 ));
+DATA(insert ( 1976 20 21 3 1 1868 403 ));
+DATA(insert ( 1976 20 21 4 1 1873 403 ));
+DATA(insert ( 1976 20 21 5 1 1871 403 ));
/* crosstype operators int84 */
-DATA(insert ( 1976 20 23 1 418 403 ));
-DATA(insert ( 1976 20 23 2 420 403 ));
-DATA(insert ( 1976 20 23 3 416 403 ));
-DATA(insert ( 1976 20 23 4 430 403 ));
-DATA(insert ( 1976 20 23 5 419 403 ));
+DATA(insert ( 1976 20 23 1 1 418 403 ));
+DATA(insert ( 1976 20 23 2 1 420 403 ));
+DATA(insert ( 1976 20 23 3 1 416 403 ));
+DATA(insert ( 1976 20 23 4 1 430 403 ));
+DATA(insert ( 1976 20 23 5 1 419 403 ));
/*
* btree oid_ops
*/
-DATA(insert ( 1989 26 26 1 609 403 ));
-DATA(insert ( 1989 26 26 2 611 403 ));
-DATA(insert ( 1989 26 26 3 607 403 ));
-DATA(insert ( 1989 26 26 4 612 403 ));
-DATA(insert ( 1989 26 26 5 610 403 ));
+DATA(insert ( 1989 26 26 1 1 609 403 ));
+DATA(insert ( 1989 26 26 2 1 611 403 ));
+DATA(insert ( 1989 26 26 3 1 607 403 ));
+DATA(insert ( 1989 26 26 4 1 612 403 ));
+DATA(insert ( 1989 26 26 5 1 610 403 ));
/*
* btree tid_ops
*/
-DATA(insert ( 2789 27 27 1 2799 403 ));
-DATA(insert ( 2789 27 27 2 2801 403 ));
-DATA(insert ( 2789 27 27 3 387 403 ));
-DATA(insert ( 2789 27 27 4 2802 403 ));
-DATA(insert ( 2789 27 27 5 2800 403 ));
+DATA(insert ( 2789 27 27 1 1 2799 403 ));
+DATA(insert ( 2789 27 27 2 1 2801 403 ));
+DATA(insert ( 2789 27 27 3 1 387 403 ));
+DATA(insert ( 2789 27 27 4 1 2802 403 ));
+DATA(insert ( 2789 27 27 5 1 2800 403 ));
/*
* btree oidvector_ops
*/
-DATA(insert ( 1991 30 30 1 645 403 ));
-DATA(insert ( 1991 30 30 2 647 403 ));
-DATA(insert ( 1991 30 30 3 649 403 ));
-DATA(insert ( 1991 30 30 4 648 403 ));
-DATA(insert ( 1991 30 30 5 646 403 ));
+DATA(insert ( 1991 30 30 1 1 645 403 ));
+DATA(insert ( 1991 30 30 2 1 647 403 ));
+DATA(insert ( 1991 30 30 3 1 649 403 ));
+DATA(insert ( 1991 30 30 4 1 648 403 ));
+DATA(insert ( 1991 30 30 5 1 646 403 ));
/*
* btree float_ops
*/
/* default operators float4 */
-DATA(insert ( 1970 700 700 1 622 403 ));
-DATA(insert ( 1970 700 700 2 624 403 ));
-DATA(insert ( 1970 700 700 3 620 403 ));
-DATA(insert ( 1970 700 700 4 625 403 ));
-DATA(insert ( 1970 700 700 5 623 403 ));
+DATA(insert ( 1970 700 700 1 1 622 403 ));
+DATA(insert ( 1970 700 700 2 1 624 403 ));
+DATA(insert ( 1970 700 700 3 1 620 403 ));
+DATA(insert ( 1970 700 700 4 1 625 403 ));
+DATA(insert ( 1970 700 700 5 1 623 403 ));
/* crosstype operators float48 */
-DATA(insert ( 1970 700 701 1 1122 403 ));
-DATA(insert ( 1970 700 701 2 1124 403 ));
-DATA(insert ( 1970 700 701 3 1120 403 ));
-DATA(insert ( 1970 700 701 4 1125 403 ));
-DATA(insert ( 1970 700 701 5 1123 403 ));
+DATA(insert ( 1970 700 701 1 1 1122 403 ));
+DATA(insert ( 1970 700 701 2 1 1124 403 ));
+DATA(insert ( 1970 700 701 3 1 1120 403 ));
+DATA(insert ( 1970 700 701 4 1 1125 403 ));
+DATA(insert ( 1970 700 701 5 1 1123 403 ));
/* default operators float8 */
-DATA(insert ( 1970 701 701 1 672 403 ));
-DATA(insert ( 1970 701 701 2 673 403 ));
-DATA(insert ( 1970 701 701 3 670 403 ));
-DATA(insert ( 1970 701 701 4 675 403 ));
-DATA(insert ( 1970 701 701 5 674 403 ));
+DATA(insert ( 1970 701 701 1 1 672 403 ));
+DATA(insert ( 1970 701 701 2 1 673 403 ));
+DATA(insert ( 1970 701 701 3 1 670 403 ));
+DATA(insert ( 1970 701 701 4 1 675 403 ));
+DATA(insert ( 1970 701 701 5 1 674 403 ));
/* crosstype operators float84 */
-DATA(insert ( 1970 701 700 1 1132 403 ));
-DATA(insert ( 1970 701 700 2 1134 403 ));
-DATA(insert ( 1970 701 700 3 1130 403 ));
-DATA(insert ( 1970 701 700 4 1135 403 ));
-DATA(insert ( 1970 701 700 5 1133 403 ));
+DATA(insert ( 1970 701 700 1 1 1132 403 ));
+DATA(insert ( 1970 701 700 2 1 1134 403 ));
+DATA(insert ( 1970 701 700 3 1 1130 403 ));
+DATA(insert ( 1970 701 700 4 1 1135 403 ));
+DATA(insert ( 1970 701 700 5 1 1133 403 ));
/*
* btree char_ops
*/
-DATA(insert ( 429 18 18 1 631 403 ));
-DATA(insert ( 429 18 18 2 632 403 ));
-DATA(insert ( 429 18 18 3 92 403 ));
-DATA(insert ( 429 18 18 4 634 403 ));
-DATA(insert ( 429 18 18 5 633 403 ));
+DATA(insert ( 429 18 18 1 1 631 403 ));
+DATA(insert ( 429 18 18 2 1 632 403 ));
+DATA(insert ( 429 18 18 3 1 92 403 ));
+DATA(insert ( 429 18 18 4 1 634 403 ));
+DATA(insert ( 429 18 18 5 1 633 403 ));
/*
* btree name_ops
*/
-DATA(insert ( 1986 19 19 1 660 403 ));
-DATA(insert ( 1986 19 19 2 661 403 ));
-DATA(insert ( 1986 19 19 3 93 403 ));
-DATA(insert ( 1986 19 19 4 663 403 ));
-DATA(insert ( 1986 19 19 5 662 403 ));
+DATA(insert ( 1986 19 19 1 1 660 403 ));
+DATA(insert ( 1986 19 19 2 1 661 403 ));
+DATA(insert ( 1986 19 19 3 1 93 403 ));
+DATA(insert ( 1986 19 19 4 1 663 403 ));
+DATA(insert ( 1986 19 19 5 1 662 403 ));
/*
* btree text_ops
*/
-DATA(insert ( 1994 25 25 1 664 403 ));
-DATA(insert ( 1994 25 25 2 665 403 ));
-DATA(insert ( 1994 25 25 3 98 403 ));
-DATA(insert ( 1994 25 25 4 667 403 ));
-DATA(insert ( 1994 25 25 5 666 403 ));
+DATA(insert ( 1994 25 25 1 1 664 403 ));
+DATA(insert ( 1994 25 25 2 1 665 403 ));
+DATA(insert ( 1994 25 25 3 1 98 403 ));
+DATA(insert ( 1994 25 25 4 1 667 403 ));
+DATA(insert ( 1994 25 25 5 1 666 403 ));
/*
* btree bpchar_ops
*/
-DATA(insert ( 426 1042 1042 1 1058 403 ));
-DATA(insert ( 426 1042 1042 2 1059 403 ));
-DATA(insert ( 426 1042 1042 3 1054 403 ));
-DATA(insert ( 426 1042 1042 4 1061 403 ));
-DATA(insert ( 426 1042 1042 5 1060 403 ));
+DATA(insert ( 426 1042 1042 1 1 1058 403 ));
+DATA(insert ( 426 1042 1042 2 1 1059 403 ));
+DATA(insert ( 426 1042 1042 3 1 1054 403 ));
+DATA(insert ( 426 1042 1042 4 1 1061 403 ));
+DATA(insert ( 426 1042 1042 5 1 1060 403 ));
/*
* btree bytea_ops
*/
-DATA(insert ( 428 17 17 1 1957 403 ));
-DATA(insert ( 428 17 17 2 1958 403 ));
-DATA(insert ( 428 17 17 3 1955 403 ));
-DATA(insert ( 428 17 17 4 1960 403 ));
-DATA(insert ( 428 17 17 5 1959 403 ));
+DATA(insert ( 428 17 17 1 1 1957 403 ));
+DATA(insert ( 428 17 17 2 1 1958 403 ));
+DATA(insert ( 428 17 17 3 1 1955 403 ));
+DATA(insert ( 428 17 17 4 1 1960 403 ));
+DATA(insert ( 428 17 17 5 1 1959 403 ));
/*
* btree abstime_ops
*/
-DATA(insert ( 421 702 702 1 562 403 ));
-DATA(insert ( 421 702 702 2 564 403 ));
-DATA(insert ( 421 702 702 3 560 403 ));
-DATA(insert ( 421 702 702 4 565 403 ));
-DATA(insert ( 421 702 702 5 563 403 ));
+DATA(insert ( 421 702 702 1 1 562 403 ));
+DATA(insert ( 421 702 702 2 1 564 403 ));
+DATA(insert ( 421 702 702 3 1 560 403 ));
+DATA(insert ( 421 702 702 4 1 565 403 ));
+DATA(insert ( 421 702 702 5 1 563 403 ));
/*
* btree datetime_ops
*/
/* default operators date */
-DATA(insert ( 434 1082 1082 1 1095 403 ));
-DATA(insert ( 434 1082 1082 2 1096 403 ));
-DATA(insert ( 434 1082 1082 3 1093 403 ));
-DATA(insert ( 434 1082 1082 4 1098 403 ));
-DATA(insert ( 434 1082 1082 5 1097 403 ));
+DATA(insert ( 434 1082 1082 1 1 1095 403 ));
+DATA(insert ( 434 1082 1082 2 1 1096 403 ));
+DATA(insert ( 434 1082 1082 3 1 1093 403 ));
+DATA(insert ( 434 1082 1082 4 1 1098 403 ));
+DATA(insert ( 434 1082 1082 5 1 1097 403 ));
/* crosstype operators vs timestamp */
-DATA(insert ( 434 1082 1114 1 2345 403 ));
-DATA(insert ( 434 1082 1114 2 2346 403 ));
-DATA(insert ( 434 1082 1114 3 2347 403 ));
-DATA(insert ( 434 1082 1114 4 2348 403 ));
-DATA(insert ( 434 1082 1114 5 2349 403 ));
+DATA(insert ( 434 1082 1114 1 1 2345 403 ));
+DATA(insert ( 434 1082 1114 2 1 2346 403 ));
+DATA(insert ( 434 1082 1114 3 1 2347 403 ));
+DATA(insert ( 434 1082 1114 4 1 2348 403 ));
+DATA(insert ( 434 1082 1114 5 1 2349 403 ));
/* crosstype operators vs timestamptz */
-DATA(insert ( 434 1082 1184 1 2358 403 ));
-DATA(insert ( 434 1082 1184 2 2359 403 ));
-DATA(insert ( 434 1082 1184 3 2360 403 ));
-DATA(insert ( 434 1082 1184 4 2361 403 ));
-DATA(insert ( 434 1082 1184 5 2362 403 ));
+DATA(insert ( 434 1082 1184 1 1 2358 403 ));
+DATA(insert ( 434 1082 1184 2 1 2359 403 ));
+DATA(insert ( 434 1082 1184 3 1 2360 403 ));
+DATA(insert ( 434 1082 1184 4 1 2361 403 ));
+DATA(insert ( 434 1082 1184 5 1 2362 403 ));
/* default operators timestamp */
-DATA(insert ( 434 1114 1114 1 2062 403 ));
-DATA(insert ( 434 1114 1114 2 2063 403 ));
-DATA(insert ( 434 1114 1114 3 2060 403 ));
-DATA(insert ( 434 1114 1114 4 2065 403 ));
-DATA(insert ( 434 1114 1114 5 2064 403 ));
+DATA(insert ( 434 1114 1114 1 1 2062 403 ));
+DATA(insert ( 434 1114 1114 2 1 2063 403 ));
+DATA(insert ( 434 1114 1114 3 1 2060 403 ));
+DATA(insert ( 434 1114 1114 4 1 2065 403 ));
+DATA(insert ( 434 1114 1114 5 1 2064 403 ));
/* crosstype operators vs date */
-DATA(insert ( 434 1114 1082 1 2371 403 ));
-DATA(insert ( 434 1114 1082 2 2372 403 ));
-DATA(insert ( 434 1114 1082 3 2373 403 ));
-DATA(insert ( 434 1114 1082 4 2374 403 ));
-DATA(insert ( 434 1114 1082 5 2375 403 ));
+DATA(insert ( 434 1114 1082 1 1 2371 403 ));
+DATA(insert ( 434 1114 1082 2 1 2372 403 ));
+DATA(insert ( 434 1114 1082 3 1 2373 403 ));
+DATA(insert ( 434 1114 1082 4 1 2374 403 ));
+DATA(insert ( 434 1114 1082 5 1 2375 403 ));
/* crosstype operators vs timestamptz */
-DATA(insert ( 434 1114 1184 1 2534 403 ));
-DATA(insert ( 434 1114 1184 2 2535 403 ));
-DATA(insert ( 434 1114 1184 3 2536 403 ));
-DATA(insert ( 434 1114 1184 4 2537 403 ));
-DATA(insert ( 434 1114 1184 5 2538 403 ));
+DATA(insert ( 434 1114 1184 1 1 2534 403 ));
+DATA(insert ( 434 1114 1184 2 1 2535 403 ));
+DATA(insert ( 434 1114 1184 3 1 2536 403 ));
+DATA(insert ( 434 1114 1184 4 1 2537 403 ));
+DATA(insert ( 434 1114 1184 5 1 2538 403 ));
/* default operators timestamptz */
-DATA(insert ( 434 1184 1184 1 1322 403 ));
-DATA(insert ( 434 1184 1184 2 1323 403 ));
-DATA(insert ( 434 1184 1184 3 1320 403 ));
-DATA(insert ( 434 1184 1184 4 1325 403 ));
-DATA(insert ( 434 1184 1184 5 1324 403 ));
+DATA(insert ( 434 1184 1184 1 1 1322 403 ));
+DATA(insert ( 434 1184 1184 2 1 1323 403 ));
+DATA(insert ( 434 1184 1184 3 1 1320 403 ));
+DATA(insert ( 434 1184 1184 4 1 1325 403 ));
+DATA(insert ( 434 1184 1184 5 1 1324 403 ));
/* crosstype operators vs date */
-DATA(insert ( 434 1184 1082 1 2384 403 ));
-DATA(insert ( 434 1184 1082 2 2385 403 ));
-DATA(insert ( 434 1184 1082 3 2386 403 ));
-DATA(insert ( 434 1184 1082 4 2387 403 ));
-DATA(insert ( 434 1184 1082 5 2388 403 ));
+DATA(insert ( 434 1184 1082 1 1 2384 403 ));
+DATA(insert ( 434 1184 1082 2 1 2385 403 ));
+DATA(insert ( 434 1184 1082 3 1 2386 403 ));
+DATA(insert ( 434 1184 1082 4 1 2387 403 ));
+DATA(insert ( 434 1184 1082 5 1 2388 403 ));
/* crosstype operators vs timestamp */
-DATA(insert ( 434 1184 1114 1 2540 403 ));
-DATA(insert ( 434 1184 1114 2 2541 403 ));
-DATA(insert ( 434 1184 1114 3 2542 403 ));
-DATA(insert ( 434 1184 1114 4 2543 403 ));
-DATA(insert ( 434 1184 1114 5 2544 403 ));
+DATA(insert ( 434 1184 1114 1 1 2540 403 ));
+DATA(insert ( 434 1184 1114 2 1 2541 403 ));
+DATA(insert ( 434 1184 1114 3 1 2542 403 ));
+DATA(insert ( 434 1184 1114 4 1 2543 403 ));
+DATA(insert ( 434 1184 1114 5 1 2544 403 ));
/*
* btree time_ops
*/
-DATA(insert ( 1996 1083 1083 1 1110 403 ));
-DATA(insert ( 1996 1083 1083 2 1111 403 ));
-DATA(insert ( 1996 1083 1083 3 1108 403 ));
-DATA(insert ( 1996 1083 1083 4 1113 403 ));
-DATA(insert ( 1996 1083 1083 5 1112 403 ));
+DATA(insert ( 1996 1083 1083 1 1 1110 403 ));
+DATA(insert ( 1996 1083 1083 2 1 1111 403 ));
+DATA(insert ( 1996 1083 1083 3 1 1108 403 ));
+DATA(insert ( 1996 1083 1083 4 1 1113 403 ));
+DATA(insert ( 1996 1083 1083 5 1 1112 403 ));
/*
* btree timetz_ops
*/
-DATA(insert ( 2000 1266 1266 1 1552 403 ));
-DATA(insert ( 2000 1266 1266 2 1553 403 ));
-DATA(insert ( 2000 1266 1266 3 1550 403 ));
-DATA(insert ( 2000 1266 1266 4 1555 403 ));
-DATA(insert ( 2000 1266 1266 5 1554 403 ));
+DATA(insert ( 2000 1266 1266 1 1 1552 403 ));
+DATA(insert ( 2000 1266 1266 2 1 1553 403 ));
+DATA(insert ( 2000 1266 1266 3 1 1550 403 ));
+DATA(insert ( 2000 1266 1266 4 1 1555 403 ));
+DATA(insert ( 2000 1266 1266 5 1 1554 403 ));
/*
* btree interval_ops
*/
-DATA(insert ( 1982 1186 1186 1 1332 403 ));
-DATA(insert ( 1982 1186 1186 2 1333 403 ));
-DATA(insert ( 1982 1186 1186 3 1330 403 ));
-DATA(insert ( 1982 1186 1186 4 1335 403 ));
-DATA(insert ( 1982 1186 1186 5 1334 403 ));
+DATA(insert ( 1982 1186 1186 1 1 1332 403 ));
+DATA(insert ( 1982 1186 1186 2 1 1333 403 ));
+DATA(insert ( 1982 1186 1186 3 1 1330 403 ));
+DATA(insert ( 1982 1186 1186 4 1 1335 403 ));
+DATA(insert ( 1982 1186 1186 5 1 1334 403 ));
/*
* btree macaddr
*/
-DATA(insert ( 1984 829 829 1 1222 403 ));
-DATA(insert ( 1984 829 829 2 1223 403 ));
-DATA(insert ( 1984 829 829 3 1220 403 ));
-DATA(insert ( 1984 829 829 4 1225 403 ));
-DATA(insert ( 1984 829 829 5 1224 403 ));
+DATA(insert ( 1984 829 829 1 1 1222 403 ));
+DATA(insert ( 1984 829 829 2 1 1223 403 ));
+DATA(insert ( 1984 829 829 3 1 1220 403 ));
+DATA(insert ( 1984 829 829 4 1 1225 403 ));
+DATA(insert ( 1984 829 829 5 1 1224 403 ));
/*
* btree network
*/
-DATA(insert ( 1974 869 869 1 1203 403 ));
-DATA(insert ( 1974 869 869 2 1204 403 ));
-DATA(insert ( 1974 869 869 3 1201 403 ));
-DATA(insert ( 1974 869 869 4 1206 403 ));
-DATA(insert ( 1974 869 869 5 1205 403 ));
+DATA(insert ( 1974 869 869 1 1 1203 403 ));
+DATA(insert ( 1974 869 869 2 1 1204 403 ));
+DATA(insert ( 1974 869 869 3 1 1201 403 ));
+DATA(insert ( 1974 869 869 4 1 1206 403 ));
+DATA(insert ( 1974 869 869 5 1 1205 403 ));
/*
* btree numeric
*/
-DATA(insert ( 1988 1700 1700 1 1754 403 ));
-DATA(insert ( 1988 1700 1700 2 1755 403 ));
-DATA(insert ( 1988 1700 1700 3 1752 403 ));
-DATA(insert ( 1988 1700 1700 4 1757 403 ));
-DATA(insert ( 1988 1700 1700 5 1756 403 ));
+DATA(insert ( 1988 1700 1700 1 1 1754 403 ));
+DATA(insert ( 1988 1700 1700 2 1 1755 403 ));
+DATA(insert ( 1988 1700 1700 3 1 1752 403 ));
+DATA(insert ( 1988 1700 1700 4 1 1757 403 ));
+DATA(insert ( 1988 1700 1700 5 1 1756 403 ));
/*
* btree bool
*/
-DATA(insert ( 424 16 16 1 58 403 ));
-DATA(insert ( 424 16 16 2 1694 403 ));
-DATA(insert ( 424 16 16 3 91 403 ));
-DATA(insert ( 424 16 16 4 1695 403 ));
-DATA(insert ( 424 16 16 5 59 403 ));
+DATA(insert ( 424 16 16 1 1 58 403 ));
+DATA(insert ( 424 16 16 2 1 1694 403 ));
+DATA(insert ( 424 16 16 3 1 91 403 ));
+DATA(insert ( 424 16 16 4 1 1695 403 ));
+DATA(insert ( 424 16 16 5 1 59 403 ));
/*
* btree bit
*/
-DATA(insert ( 423 1560 1560 1 1786 403 ));
-DATA(insert ( 423 1560 1560 2 1788 403 ));
-DATA(insert ( 423 1560 1560 3 1784 403 ));
-DATA(insert ( 423 1560 1560 4 1789 403 ));
-DATA(insert ( 423 1560 1560 5 1787 403 ));
+DATA(insert ( 423 1560 1560 1 1 1786 403 ));
+DATA(insert ( 423 1560 1560 2 1 1788 403 ));
+DATA(insert ( 423 1560 1560 3 1 1784 403 ));
+DATA(insert ( 423 1560 1560 4 1 1789 403 ));
+DATA(insert ( 423 1560 1560 5 1 1787 403 ));
/*
* btree varbit
*/
-DATA(insert ( 2002 1562 1562 1 1806 403 ));
-DATA(insert ( 2002 1562 1562 2 1808 403 ));
-DATA(insert ( 2002 1562 1562 3 1804 403 ));
-DATA(insert ( 2002 1562 1562 4 1809 403 ));
-DATA(insert ( 2002 1562 1562 5 1807 403 ));
+DATA(insert ( 2002 1562 1562 1 1 1806 403 ));
+DATA(insert ( 2002 1562 1562 2 1 1808 403 ));
+DATA(insert ( 2002 1562 1562 3 1 1804 403 ));
+DATA(insert ( 2002 1562 1562 4 1 1809 403 ));
+DATA(insert ( 2002 1562 1562 5 1 1807 403 ));
/*
* btree text pattern
*/
-DATA(insert ( 2095 25 25 1 2314 403 ));
-DATA(insert ( 2095 25 25 2 2315 403 ));
-DATA(insert ( 2095 25 25 3 98 403 ));
-DATA(insert ( 2095 25 25 4 2317 403 ));
-DATA(insert ( 2095 25 25 5 2318 403 ));
+DATA(insert ( 2095 25 25 1 1 2314 403 ));
+DATA(insert ( 2095 25 25 2 1 2315 403 ));
+DATA(insert ( 2095 25 25 3 1 98 403 ));
+DATA(insert ( 2095 25 25 4 1 2317 403 ));
+DATA(insert ( 2095 25 25 5 1 2318 403 ));
/*
* btree bpchar pattern
*/
-DATA(insert ( 2097 1042 1042 1 2326 403 ));
-DATA(insert ( 2097 1042 1042 2 2327 403 ));
-DATA(insert ( 2097 1042 1042 3 1054 403 ));
-DATA(insert ( 2097 1042 1042 4 2329 403 ));
-DATA(insert ( 2097 1042 1042 5 2330 403 ));
+DATA(insert ( 2097 1042 1042 1 1 2326 403 ));
+DATA(insert ( 2097 1042 1042 2 1 2327 403 ));
+DATA(insert ( 2097 1042 1042 3 1 1054 403 ));
+DATA(insert ( 2097 1042 1042 4 1 2329 403 ));
+DATA(insert ( 2097 1042 1042 5 1 2330 403 ));
/*
* btree money_ops
*/
-DATA(insert ( 2099 790 790 1 902 403 ));
-DATA(insert ( 2099 790 790 2 904 403 ));
-DATA(insert ( 2099 790 790 3 900 403 ));
-DATA(insert ( 2099 790 790 4 905 403 ));
-DATA(insert ( 2099 790 790 5 903 403 ));
+DATA(insert ( 2099 790 790 1 1 902 403 ));
+DATA(insert ( 2099 790 790 2 1 904 403 ));
+DATA(insert ( 2099 790 790 3 1 900 403 ));
+DATA(insert ( 2099 790 790 4 1 905 403 ));
+DATA(insert ( 2099 790 790 5 1 903 403 ));
/*
* btree reltime_ops
*/
-DATA(insert ( 2233 703 703 1 568 403 ));
-DATA(insert ( 2233 703 703 2 570 403 ));
-DATA(insert ( 2233 703 703 3 566 403 ));
-DATA(insert ( 2233 703 703 4 571 403 ));
-DATA(insert ( 2233 703 703 5 569 403 ));
+DATA(insert ( 2233 703 703 1 1 568 403 ));
+DATA(insert ( 2233 703 703 2 1 570 403 ));
+DATA(insert ( 2233 703 703 3 1 566 403 ));
+DATA(insert ( 2233 703 703 4 1 571 403 ));
+DATA(insert ( 2233 703 703 5 1 569 403 ));
/*
* btree tinterval_ops
*/
-DATA(insert ( 2234 704 704 1 813 403 ));
-DATA(insert ( 2234 704 704 2 815 403 ));
-DATA(insert ( 2234 704 704 3 811 403 ));
-DATA(insert ( 2234 704 704 4 816 403 ));
-DATA(insert ( 2234 704 704 5 814 403 ));
+DATA(insert ( 2234 704 704 1 1 813 403 ));
+DATA(insert ( 2234 704 704 2 1 815 403 ));
+DATA(insert ( 2234 704 704 3 1 811 403 ));
+DATA(insert ( 2234 704 704 4 1 816 403 ));
+DATA(insert ( 2234 704 704 5 1 814 403 ));
/*
* btree array_ops
*/
-DATA(insert ( 397 2277 2277 1 1072 403 ));
-DATA(insert ( 397 2277 2277 2 1074 403 ));
-DATA(insert ( 397 2277 2277 3 1070 403 ));
-DATA(insert ( 397 2277 2277 4 1075 403 ));
-DATA(insert ( 397 2277 2277 5 1073 403 ));
+DATA(insert ( 397 2277 2277 1 1 1072 403 ));
+DATA(insert ( 397 2277 2277 2 1 1074 403 ));
+DATA(insert ( 397 2277 2277 3 1 1070 403 ));
+DATA(insert ( 397 2277 2277 4 1 1075 403 ));
+DATA(insert ( 397 2277 2277 5 1 1073 403 ));
/*
* btree record_ops
*/
-DATA(insert ( 2994 2249 2249 1 2990 403 ));
-DATA(insert ( 2994 2249 2249 2 2992 403 ));
-DATA(insert ( 2994 2249 2249 3 2988 403 ));
-DATA(insert ( 2994 2249 2249 4 2993 403 ));
-DATA(insert ( 2994 2249 2249 5 2991 403 ));
+DATA(insert ( 2994 2249 2249 1 1 2990 403 ));
+DATA(insert ( 2994 2249 2249 2 1 2992 403 ));
+DATA(insert ( 2994 2249 2249 3 1 2988 403 ));
+DATA(insert ( 2994 2249 2249 4 1 2993 403 ));
+DATA(insert ( 2994 2249 2249 5 1 2991 403 ));
/*
* btree uuid_ops
*/
-DATA(insert ( 2968 2950 2950 1 2974 403 ));
-DATA(insert ( 2968 2950 2950 2 2976 403 ));
-DATA(insert ( 2968 2950 2950 3 2972 403 ));
-DATA(insert ( 2968 2950 2950 4 2977 403 ));
-DATA(insert ( 2968 2950 2950 5 2975 403 ));
+DATA(insert ( 2968 2950 2950 1 1 2974 403 ));
+DATA(insert ( 2968 2950 2950 2 1 2976 403 ));
+DATA(insert ( 2968 2950 2950 3 1 2972 403 ));
+DATA(insert ( 2968 2950 2950 4 1 2977 403 ));
+DATA(insert ( 2968 2950 2950 5 1 2975 403 ));
/*
* hash index _ops
*/
/* bpchar_ops */
-DATA(insert ( 427 1042 1042 1 1054 405 ));
+DATA(insert ( 427 1042 1042 1 1 1054 405 ));
/* char_ops */
-DATA(insert ( 431 18 18 1 92 405 ));
+DATA(insert ( 431 18 18 1 1 92 405 ));
/* date_ops */
-DATA(insert ( 435 1082 1082 1 1093 405 ));
+DATA(insert ( 435 1082 1082 1 1 1093 405 ));
/* float_ops */
-DATA(insert ( 1971 700 700 1 620 405 ));
-DATA(insert ( 1971 701 701 1 670 405 ));
-DATA(insert ( 1971 700 701 1 1120 405 ));
-DATA(insert ( 1971 701 700 1 1130 405 ));
+DATA(insert ( 1971 700 700 1 1 620 405 ));
+DATA(insert ( 1971 701 701 1 1 670 405 ));
+DATA(insert ( 1971 700 701 1 1 1120 405 ));
+DATA(insert ( 1971 701 700 1 1 1130 405 ));
/* network_ops */
-DATA(insert ( 1975 869 869 1 1201 405 ));
+DATA(insert ( 1975 869 869 1 1 1201 405 ));
/* integer_ops */
-DATA(insert ( 1977 21 21 1 94 405 ));
-DATA(insert ( 1977 23 23 1 96 405 ));
-DATA(insert ( 1977 20 20 1 410 405 ));
-DATA(insert ( 1977 21 23 1 532 405 ));
-DATA(insert ( 1977 21 20 1 1862 405 ));
-DATA(insert ( 1977 23 21 1 533 405 ));
-DATA(insert ( 1977 23 20 1 15 405 ));
-DATA(insert ( 1977 20 21 1 1868 405 ));
-DATA(insert ( 1977 20 23 1 416 405 ));
+DATA(insert ( 1977 21 21 1 1 94 405 ));
+DATA(insert ( 1977 23 23 1 1 96 405 ));
+DATA(insert ( 1977 20 20 1 1 410 405 ));
+DATA(insert ( 1977 21 23 1 1 532 405 ));
+DATA(insert ( 1977 21 20 1 1 1862 405 ));
+DATA(insert ( 1977 23 21 1 1 533 405 ));
+DATA(insert ( 1977 23 20 1 1 15 405 ));
+DATA(insert ( 1977 20 21 1 1 1868 405 ));
+DATA(insert ( 1977 20 23 1 1 416 405 ));
/* interval_ops */
-DATA(insert ( 1983 1186 1186 1 1330 405 ));
+DATA(insert ( 1983 1186 1186 1 1 1330 405 ));
/* macaddr_ops */
-DATA(insert ( 1985 829 829 1 1220 405 ));
+DATA(insert ( 1985 829 829 1 1 1220 405 ));
/* name_ops */
-DATA(insert ( 1987 19 19 1 93 405 ));
+DATA(insert ( 1987 19 19 1 1 93 405 ));
/* oid_ops */
-DATA(insert ( 1990 26 26 1 607 405 ));
+DATA(insert ( 1990 26 26 1 1 607 405 ));
/* oidvector_ops */
-DATA(insert ( 1992 30 30 1 649 405 ));
+DATA(insert ( 1992 30 30 1 1 649 405 ));
/* text_ops */
-DATA(insert ( 1995 25 25 1 98 405 ));
+DATA(insert ( 1995 25 25 1 1 98 405 ));
/* time_ops */
-DATA(insert ( 1997 1083 1083 1 1108 405 ));
+DATA(insert ( 1997 1083 1083 1 1 1108 405 ));
/* timestamptz_ops */
-DATA(insert ( 1999 1184 1184 1 1320 405 ));
+DATA(insert ( 1999 1184 1184 1 1 1320 405 ));
/* timetz_ops */
-DATA(insert ( 2001 1266 1266 1 1550 405 ));
+DATA(insert ( 2001 1266 1266 1 1 1550 405 ));
/* timestamp_ops */
-DATA(insert ( 2040 1114 1114 1 2060 405 ));
+DATA(insert ( 2040 1114 1114 1 1 2060 405 ));
/* bool_ops */
-DATA(insert ( 2222 16 16 1 91 405 ));
+DATA(insert ( 2222 16 16 1 1 91 405 ));
/* bytea_ops */
-DATA(insert ( 2223 17 17 1 1955 405 ));
+DATA(insert ( 2223 17 17 1 1 1955 405 ));
/* int2vector_ops */
-DATA(insert ( 2224 22 22 1 386 405 ));
+DATA(insert ( 2224 22 22 1 1 386 405 ));
/* xid_ops */
-DATA(insert ( 2225 28 28 1 352 405 ));
+DATA(insert ( 2225 28 28 1 1 352 405 ));
/* cid_ops */
-DATA(insert ( 2226 29 29 1 385 405 ));
+DATA(insert ( 2226 29 29 1 1 385 405 ));
/* abstime_ops */
-DATA(insert ( 2227 702 702 1 560 405 ));
+DATA(insert ( 2227 702 702 1 1 560 405 ));
/* reltime_ops */
-DATA(insert ( 2228 703 703 1 566 405 ));
+DATA(insert ( 2228 703 703 1 1 566 405 ));
/* text_pattern_ops */
-DATA(insert ( 2229 25 25 1 98 405 ));
+DATA(insert ( 2229 25 25 1 1 98 405 ));
/* bpchar_pattern_ops */
-DATA(insert ( 2231 1042 1042 1 1054 405 ));
+DATA(insert ( 2231 1042 1042 1 1 1054 405 ));
/* aclitem_ops */
-DATA(insert ( 2235 1033 1033 1 974 405 ));
+DATA(insert ( 2235 1033 1033 1 1 974 405 ));
/* uuid_ops */
-DATA(insert ( 2969 2950 2950 1 2972 405 ));
+DATA(insert ( 2969 2950 2950 1 1 2972 405 ));
/* numeric_ops */
-DATA(insert ( 1998 1700 1700 1 1752 405 ));
+DATA(insert ( 1998 1700 1700 1 1 1752 405 ));
/*
* gist box_ops
*/
-DATA(insert ( 2593 603 603 1 493 783 ));
-DATA(insert ( 2593 603 603 2 494 783 ));
-DATA(insert ( 2593 603 603 3 500 783 ));
-DATA(insert ( 2593 603 603 4 495 783 ));
-DATA(insert ( 2593 603 603 5 496 783 ));
-DATA(insert ( 2593 603 603 6 499 783 ));
-DATA(insert ( 2593 603 603 7 498 783 ));
-DATA(insert ( 2593 603 603 8 497 783 ));
-DATA(insert ( 2593 603 603 9 2571 783 ));
-DATA(insert ( 2593 603 603 10 2570 783 ));
-DATA(insert ( 2593 603 603 11 2573 783 ));
-DATA(insert ( 2593 603 603 12 2572 783 ));
-DATA(insert ( 2593 603 603 13 2863 783 ));
-DATA(insert ( 2593 603 603 14 2862 783 ));
+DATA(insert ( 2593 603 603 1 1 493 783 ));
+DATA(insert ( 2593 603 603 2 1 494 783 ));
+DATA(insert ( 2593 603 603 3 1 500 783 ));
+DATA(insert ( 2593 603 603 4 1 495 783 ));
+DATA(insert ( 2593 603 603 5 1 496 783 ));
+DATA(insert ( 2593 603 603 6 1 499 783 ));
+DATA(insert ( 2593 603 603 7 1 498 783 ));
+DATA(insert ( 2593 603 603 8 1 497 783 ));
+DATA(insert ( 2593 603 603 9 1 2571 783 ));
+DATA(insert ( 2593 603 603 10 1 2570 783 ));
+DATA(insert ( 2593 603 603 11 1 2573 783 ));
+DATA(insert ( 2593 603 603 12 1 2572 783 ));
+DATA(insert ( 2593 603 603 13 1 2863 783 ));
+DATA(insert ( 2593 603 603 14 1 2862 783 ));
/*
* gist point_ops
*/
-DATA(insert ( 1029 600 600 11 506 783 ));
-DATA(insert ( 1029 600 600 1 507 783 ));
-DATA(insert ( 1029 600 600 5 508 783 ));
-DATA(insert ( 1029 600 600 10 509 783 ));
-DATA(insert ( 1029 600 600 6 510 783 ));
-DATA(insert ( 1029 603 600 27 433 783 ));
-DATA(insert ( 1029 600 603 28 511 783 ));
-DATA(insert ( 1029 604 600 47 757 783 ));
-DATA(insert ( 1029 600 604 48 756 783 ));
-DATA(insert ( 1029 718 600 67 759 783 ));
-DATA(insert ( 1029 600 718 68 758 783 ));
+DATA(insert ( 1029 600 600 11 1 506 783 ));
+DATA(insert ( 1029 600 600 1 1 507 783 ));
+DATA(insert ( 1029 600 600 5 1 508 783 ));
+DATA(insert ( 1029 600 600 10 1 509 783 ));
+DATA(insert ( 1029 600 600 6 1 510 783 ));
+DATA(insert ( 1029 603 600 27 1 433 783 ));
+DATA(insert ( 1029 600 603 28 1 511 783 ));
+DATA(insert ( 1029 604 600 47 1 757 783 ));
+DATA(insert ( 1029 600 604 48 1 756 783 ));
+DATA(insert ( 1029 718 600 67 1 759 783 ));
+DATA(insert ( 1029 600 718 68 1 758 783 ));
/*
* gist poly_ops (supports polygons)
*/
-DATA(insert ( 2594 604 604 1 485 783 ));
-DATA(insert ( 2594 604 604 2 486 783 ));
-DATA(insert ( 2594 604 604 3 492 783 ));
-DATA(insert ( 2594 604 604 4 487 783 ));
-DATA(insert ( 2594 604 604 5 488 783 ));
-DATA(insert ( 2594 604 604 6 491 783 ));
-DATA(insert ( 2594 604 604 7 490 783 ));
-DATA(insert ( 2594 604 604 8 489 783 ));
-DATA(insert ( 2594 604 604 9 2575 783 ));
-DATA(insert ( 2594 604 604 10 2574 783 ));
-DATA(insert ( 2594 604 604 11 2577 783 ));
-DATA(insert ( 2594 604 604 12 2576 783 ));
-DATA(insert ( 2594 604 604 13 2861 783 ));
-DATA(insert ( 2594 604 604 14 2860 783 ));
+DATA(insert ( 2594 604 604 1 1 485 783 ));
+DATA(insert ( 2594 604 604 2 1 486 783 ));
+DATA(insert ( 2594 604 604 3 1 492 783 ));
+DATA(insert ( 2594 604 604 4 1 487 783 ));
+DATA(insert ( 2594 604 604 5 1 488 783 ));
+DATA(insert ( 2594 604 604 6 1 491 783 ));
+DATA(insert ( 2594 604 604 7 1 490 783 ));
+DATA(insert ( 2594 604 604 8 1 489 783 ));
+DATA(insert ( 2594 604 604 9 1 2575 783 ));
+DATA(insert ( 2594 604 604 10 1 2574 783 ));
+DATA(insert ( 2594 604 604 11 1 2577 783 ));
+DATA(insert ( 2594 604 604 12 1 2576 783 ));
+DATA(insert ( 2594 604 604 13 1 2861 783 ));
+DATA(insert ( 2594 604 604 14 1 2860 783 ));
/*
* gist circle_ops
*/
-DATA(insert ( 2595 718 718 1 1506 783 ));
-DATA(insert ( 2595 718 718 2 1507 783 ));
-DATA(insert ( 2595 718 718 3 1513 783 ));
-DATA(insert ( 2595 718 718 4 1508 783 ));
-DATA(insert ( 2595 718 718 5 1509 783 ));
-DATA(insert ( 2595 718 718 6 1512 783 ));
-DATA(insert ( 2595 718 718 7 1511 783 ));
-DATA(insert ( 2595 718 718 8 1510 783 ));
-DATA(insert ( 2595 718 718 9 2589 783 ));
-DATA(insert ( 2595 718 718 10 1515 783 ));
-DATA(insert ( 2595 718 718 11 1514 783 ));
-DATA(insert ( 2595 718 718 12 2590 783 ));
-DATA(insert ( 2595 718 718 13 2865 783 ));
-DATA(insert ( 2595 718 718 14 2864 783 ));
+DATA(insert ( 2595 718 718 1 1 1506 783 ));
+DATA(insert ( 2595 718 718 2 1 1507 783 ));
+DATA(insert ( 2595 718 718 3 1 1513 783 ));
+DATA(insert ( 2595 718 718 4 1 1508 783 ));
+DATA(insert ( 2595 718 718 5 1 1509 783 ));
+DATA(insert ( 2595 718 718 6 1 1512 783 ));
+DATA(insert ( 2595 718 718 7 1 1511 783 ));
+DATA(insert ( 2595 718 718 8 1 1510 783 ));
+DATA(insert ( 2595 718 718 9 1 2589 783 ));
+DATA(insert ( 2595 718 718 10 1 1515 783 ));
+DATA(insert ( 2595 718 718 11 1 1514 783 ));
+DATA(insert ( 2595 718 718 12 1 2590 783 ));
+DATA(insert ( 2595 718 718 13 1 2865 783 ));
+DATA(insert ( 2595 718 718 14 1 2864 783 ));
/*
* gin array_ops (these anyarray operators are used with all the opclasses
* of the family)
*/
-DATA(insert ( 2745 2277 2277 1 2750 2742 ));
-DATA(insert ( 2745 2277 2277 2 2751 2742 ));
-DATA(insert ( 2745 2277 2277 3 2752 2742 ));
-DATA(insert ( 2745 2277 2277 4 1070 2742 ));
+DATA(insert ( 2745 2277 2277 1 1 2750 2742 ));
+DATA(insert ( 2745 2277 2277 2 1 2751 2742 ));
+DATA(insert ( 2745 2277 2277 3 1 2752 2742 ));
+DATA(insert ( 2745 2277 2277 4 1 1070 2742 ));
/*
* btree enum_ops
*/
-DATA(insert ( 3522 3500 3500 1 3518 403 ));
-DATA(insert ( 3522 3500 3500 2 3520 403 ));
-DATA(insert ( 3522 3500 3500 3 3516 403 ));
-DATA(insert ( 3522 3500 3500 4 3521 403 ));
-DATA(insert ( 3522 3500 3500 5 3519 403 ));
+DATA(insert ( 3522 3500 3500 1 1 3518 403 ));
+DATA(insert ( 3522 3500 3500 2 1 3520 403 ));
+DATA(insert ( 3522 3500 3500 3 1 3516 403 ));
+DATA(insert ( 3522 3500 3500 4 1 3521 403 ));
+DATA(insert ( 3522 3500 3500 5 1 3519 403 ));
/*
* hash enum_ops
*/
-DATA(insert ( 3523 3500 3500 1 3516 405 ));
+DATA(insert ( 3523 3500 3500 1 1 3516 405 ));
/*
* btree tsvector_ops
*/
-DATA(insert ( 3626 3614 3614 1 3627 403 ));
-DATA(insert ( 3626 3614 3614 2 3628 403 ));
-DATA(insert ( 3626 3614 3614 3 3629 403 ));
-DATA(insert ( 3626 3614 3614 4 3631 403 ));
-DATA(insert ( 3626 3614 3614 5 3632 403 ));
+DATA(insert ( 3626 3614 3614 1 1 3627 403 ));
+DATA(insert ( 3626 3614 3614 2 1 3628 403 ));
+DATA(insert ( 3626 3614 3614 3 1 3629 403 ));
+DATA(insert ( 3626 3614 3614 4 1 3631 403 ));
+DATA(insert ( 3626 3614 3614 5 1 3632 403 ));
/*
* GiST tsvector_ops
*/
-DATA(insert ( 3655 3614 3615 1 3636 783 ));
+DATA(insert ( 3655 3614 3615 1 1 3636 783 ));
/*
* GIN tsvector_ops
*/
-DATA(insert ( 3659 3614 3615 1 3636 2742 ));
-DATA(insert ( 3659 3614 3615 2 3660 2742 ));
+DATA(insert ( 3659 3614 3615 1 1 3636 2742 ));
+DATA(insert ( 3659 3614 3615 2 1 3660 2742 ));
/*
* btree tsquery_ops
*/
-DATA(insert ( 3683 3615 3615 1 3674 403 ));
-DATA(insert ( 3683 3615 3615 2 3675 403 ));
-DATA(insert ( 3683 3615 3615 3 3676 403 ));
-DATA(insert ( 3683 3615 3615 4 3678 403 ));
-DATA(insert ( 3683 3615 3615 5 3679 403 ));
+DATA(insert ( 3683 3615 3615 1 1 3674 403 ));
+DATA(insert ( 3683 3615 3615 2 1 3675 403 ));
+DATA(insert ( 3683 3615 3615 3 1 3676 403 ));
+DATA(insert ( 3683 3615 3615 4 1 3678 403 ));
+DATA(insert ( 3683 3615 3615 5 1 3679 403 ));
/*
* GiST tsquery_ops
*/
-DATA(insert ( 3702 3615 3615 7 3693 783 ));
-DATA(insert ( 3702 3615 3615 8 3694 783 ));
+DATA(insert ( 3702 3615 3615 7 1 3693 783 ));
+DATA(insert ( 3702 3615 3615 8 1 3694 783 ));
#endif /* PG_AMOP_H */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 136bf38..f23890b 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -30,14 +30,14 @@ typedef enum IOFuncSelector
typedef int32 (*get_attavgwidth_hook_type) (Oid relid, AttrNumber attnum);
extern PGDLLIMPORT get_attavgwidth_hook_type get_attavgwidth_hook;
-extern bool op_in_opfamily(Oid opno, Oid opfamily);
-extern int get_op_opfamily_strategy(Oid opno, Oid opfamily);
-extern void get_op_opfamily_properties(Oid opno, Oid opfamily,
+extern bool op_in_opfamily(Oid opno, Oid opfamily, int purpose);
+extern int get_op_opfamily_strategy(Oid opno, Oid opfamily, int purpose);
+extern void get_op_opfamily_properties(Oid opno, Oid opfamily, int purpose,
int *strategy,
Oid *lefttype,
Oid *righttype);
extern Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
- int16 strategy);
+ int16 strategy, int16 purpose);
extern bool get_ordering_op_properties(Oid opno,
Oid *opfamily, Oid *opcintype, int16 *strategy);
extern bool get_compare_function_for_ordering_op(Oid opno,
On Fri, Oct 15, 2010 at 7:10 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
I still feel vaguely uneasy about the fact that the proposed patch
can't handle ASC/DESC or NULLS FIRST/LAST, and that unease grew a bit
more last night when I read Peter's patch to add collation support.Good point.
We could possibly cram ASC/DESC and NULLS FIRST/LAST in by defining
four new categories of operator strategies rather than one, but
there's no way that's going to work for collations. Is there some
other way to approach this problem? Can we leave pg_amop as it is,
and pass the context (sort vs. qual, ASC/DESC, NULLS FIRST/LAST,
collation, whatever...) to the index via some sort of side channel?Well, we cannot avoid changing pg_amop, or at least changing its
interpretation, because the current scheme simply can't represent
indexable operators that are used for anything except simple boolean
WHERE tests. I agree though that we do *not* want pg_amop involved
in the details of exactly what sort ordering is referenced by a sortable
operator. Somehow that needs to be passed in a side channel.
I spent some time tonight looking at how this is handled in
builtin_knngist_core-0.9. It looks like the requested sort, if there
is one, just gets tossed into the indexquals list and eventually
transformed into a scankey with a new flag SK_ORDER set. I think what
we should do instead is add an additional IndexPath field which can
point to a node indicating the desired ordering properties. This node
might look similar to a scan key but having it be a separate node type
will allow us to add in whatever, ahem, miscellaneous crap we want to
pass: currently ASC/DESC and NULLS FIRST/LAST, and eventually
collation and so forth. That can then get propagated into the
IndexScan and passed to index_beginscan, where it can be passed to the
AM's ambeginscan function (i.e. we'll add an additional argument to
the signatures of those functions).
There's a second problem, too. If we assume that we want to treat
this problem with some degree of generality - that is, we really do
care about things like ASC/DESC and NULLS FIRST/LAST and eventually
collation - then the proposed amcanorderbyop flag isn't really
sufficient. The AM will need to be able to indicate whether a given
combination of parameters is one that it can handle. I'm thinking
perhaps in lieu of a boolean, we can add another indexam method which,
if not InvalidOid, gets called when we're wondering about whether a
given clause is something that the index can order by. Although
knngist focuses on a the ORDER BY col OP constant case, which
certainly seems like the most useful one, there's no theoretical
reason why an AM couldn't allow ordering by some more complex clause.
I don't know whether anyone will ever feel like writing code to do
something like that, but if we set the API up this way then it should
be at least theoretically possible.
Comments?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Paul Ramsey wrote:
So what kind of data structure would you like for a typmod?
I'm a primitive enough beast that just having 64-bits would make me
happy. As a general matter though, a bytea?P
For my vote, I'd prefer either the Oid of a custom type or an array of
Oid, Datum pairs - i.e. something we can extend in the future if required.
ATB,
Mark.
--
Mark Cave-Ayland - Senior Technical Architect
PostgreSQL - PostGIS
Sirius Corporation plc - control through freedom
http://www.siriusit.co.uk
t: +44 870 608 0063
Sirius Labs: http://www.siriusit.co.uk/labs
On Mon, Oct 18, 2010 at 11:41:06AM +0100, Mark Cave-Ayland wrote:
Paul Ramsey wrote:
So what kind of data structure would you like for a typmod?
I'm a primitive enough beast that just having 64-bits would make me
happy. As a general matter though, a bytea?P
For my vote, I'd prefer either the Oid of a custom type or an array
of Oid, Datum pairs - i.e. something we can extend in the future if
required.
This sounds a lot like a foreign key to another table. Are you not
proposing doing that because of performance considerations?
Cheers,
David.
--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david.fetter@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
David Fetter wrote:
For my vote, I'd prefer either the Oid of a custom type or an array
of Oid, Datum pairs - i.e. something we can extend in the future if
required.This sounds a lot like a foreign key to another table. Are you not
proposing doing that because of performance considerations?Cheers,
David.
Well, in PostGIS a typmod contains 3 pieces of information:
1) the SRID
2) the dimension
3) the geometry type
The SRID is technically already a foreign key into another table, with
dimension and SRID as other information. At the moment, we bit-pack the
dimension and geometry type into the SRID and use that as the typmod but
this only leaves 21 bits IIRC for the SRID. The additional complication
is that SRIDs at the higher end of the range are allowed for anyone to
use, and so people may have their own customised spheroids defined in
this region of the table.
If we had a foreign key into another table, we'd need to ensure that no
one could tamper with it as otherwise all chaos would break lose, e.g.
breaking the geometry type constraint on a column. Heck, we even have
people deleting the geometry_columns table sometimes because they are
not aware of what it does. By storing this information in the PG catalog
then this can't happen, plus the information is available easily in
Form_pg_attribute without having to implement our own cache, with its
own related problems such as how/when to invalidate etc.
There is also a chance that we'd want to include additional information
in the future related to geometry validity, for example, which would
mean further reducing the range allowed within the spatial_ref_sys table
in its existing form.
ATB,
Mark.
--
Mark Cave-Ayland - Senior Technical Architect
PostgreSQL - PostGIS
Sirius Corporation plc - control through freedom
http://www.siriusit.co.uk
t: +44 870 608 0063
Sirius Labs: http://www.siriusit.co.uk/labs
On mån, 2010-10-18 at 11:41 +0100, Mark Cave-Ayland wrote:
Paul Ramsey wrote:
So what kind of data structure would you like for a typmod?
I'm a primitive enough beast that just having 64-bits would make me
happy. As a general matter though, a bytea?P
For my vote, I'd prefer either the Oid of a custom type or an array of
Oid, Datum pairs - i.e. something we can extend in the future if required.
I think if we really wanted to design this generally, we'd give a type
function arguments. So, numeric would get (int default = 0, int default
= 0). That can easily get very complicated, of course.
In any case, for the shorter term, it's clear that refactoring the
passing around of type + typmod would help this endeavor, so I'm going
to give it a try.
On Mon, Oct 18, 2010 at 3:33 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
On mån, 2010-10-18 at 11:41 +0100, Mark Cave-Ayland wrote:
Paul Ramsey wrote:
So what kind of data structure would you like for a typmod?
I'm a primitive enough beast that just having 64-bits would make me
happy. As a general matter though, a bytea?P
For my vote, I'd prefer either the Oid of a custom type or an array of
Oid, Datum pairs - i.e. something we can extend in the future if required.I think if we really wanted to design this generally, we'd give a type
function arguments. So, numeric would get (int default = 0, int default
= 0). That can easily get very complicated, of course.In any case, for the shorter term, it's clear that refactoring the
passing around of type + typmod would help this endeavor, so I'm going
to give it a try.
By "this endeavor" do you mean KNNGIST, or per-column collation?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On mån, 2010-10-18 at 15:36 -0400, Robert Haas wrote:
On Mon, Oct 18, 2010 at 3:33 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
On mån, 2010-10-18 at 11:41 +0100, Mark Cave-Ayland wrote:
Paul Ramsey wrote:
So what kind of data structure would you like for a typmod?
I'm a primitive enough beast that just having 64-bits would make me
happy. As a general matter though, a bytea?P
For my vote, I'd prefer either the Oid of a custom type or an array of
Oid, Datum pairs - i.e. something we can extend in the future if required.I think if we really wanted to design this generally, we'd give a type
function arguments. So, numeric would get (int default = 0, int default
= 0). That can easily get very complicated, of course.In any case, for the shorter term, it's clear that refactoring the
passing around of type + typmod would help this endeavor, so I'm going
to give it a try.By "this endeavor" do you mean KNNGIST, or per-column collation?
No, I was referring to the talk about a different/better/more flexible
typmod. Per-column collation could also benefit, as you have observed.
Frankly, I have no idea what knngist has to do with any of this, as I
haven't followed that topic at all.
On Mon, Oct 18, 2010 at 3:40 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
On mån, 2010-10-18 at 15:36 -0400, Robert Haas wrote:
On Mon, Oct 18, 2010 at 3:33 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
On mån, 2010-10-18 at 11:41 +0100, Mark Cave-Ayland wrote:
Paul Ramsey wrote:
So what kind of data structure would you like for a typmod?
I'm a primitive enough beast that just having 64-bits would make me
happy. As a general matter though, a bytea?P
For my vote, I'd prefer either the Oid of a custom type or an array of
Oid, Datum pairs - i.e. something we can extend in the future if required.I think if we really wanted to design this generally, we'd give a type
function arguments. So, numeric would get (int default = 0, int default
= 0). That can easily get very complicated, of course.In any case, for the shorter term, it's clear that refactoring the
passing around of type + typmod would help this endeavor, so I'm going
to give it a try.By "this endeavor" do you mean KNNGIST, or per-column collation?
No, I was referring to the talk about a different/better/more flexible
typmod. Per-column collation could also benefit, as you have observed.
Frankly, I have no idea what knngist has to do with any of this, as I
haven't followed that topic at all.
Me neither, except for the fact that the PostGIS guys are interested
in both things. I think this thread has been hijacked OT.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Oct 18, 2010 at 3:40 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
Frankly, I have no idea what knngist has to do with any of this, as I
haven't followed that topic at all.
Me neither, except for the fact that the PostGIS guys are interested
in both things. I think this thread has been hijacked OT.
We got there by discussing how ordering information could be passed
around for knngist operators. Robert said something about side
channels, and I mentioned that maybe collation information should
pass through a side channel as well instead of trying to make it work
like typmods, and then it drifted to rethinking typmods as long as we
were thinking about having to touch everyplace that deals in typmods.
I agree the thread is far OT --- most of the recent messages belong
in discussion of the collation patch more than they do with knngist.
But there is some overlap if you think about whether these problems
could be solved together.
regards, tom lane
On Mon, Oct 18, 2010 at 04:13:04PM +0100, Mark Cave-Ayland wrote:
David Fetter wrote:
For my vote, I'd prefer either the Oid of a custom type or an array
of Oid, Datum pairs - i.e. something we can extend in the future if
required.This sounds a lot like a foreign key to another table. Are you not
proposing doing that because of performance considerations?Cheers,
David.Well, in PostGIS a typmod contains 3 pieces of information:
1) the SRID
2) the dimension
3) the geometry typeThe SRID is technically already a foreign key into another table,
with dimension and SRID as other information. At the moment, we
bit-pack the dimension and geometry type into the SRID and use that
as the typmod but this only leaves 21 bits IIRC for the SRID. The
additional complication is that SRIDs at the higher end of the range
are allowed for anyone to use, and so people may have their own
customised spheroids defined in this region of the table.
Sounds like you need space for all of these separately, and once you
have that, you'll probably start thinking about other possible pieces
of information you could store, especially as you start to store new
data types and have new operators on them.
It sounds to me as thought the typemod, or something like it, needs to
be able to store, in general, completely arbitrary information,
although not likely much over a page or two of memory. Cf. Robert
Haas's recent comment about Klingon. While we could make this a
completely opaque structure from the SQL level, I'm not sure it's a
good idea.
If we had a foreign key into another table, we'd need to ensure that
no one could tamper with it as otherwise all chaos would break lose,
e.g. breaking the geometry type constraint on a column.
Our system catalog tables have the nice property that no one can
accidentally modify them by hand, and "all chaos," as you put it, can
reasonably be expected to occur should they choose to do so.
Heck, we even have people deleting the geometry_columns table
sometimes because they are not aware of what it does. By storing
this information in the PG catalog then this can't happen, plus the
information is available easily in Form_pg_attribute without having
to implement our own cache, with its own related problems such as
how/when to invalidate etc.
:)
There is also a chance that we'd want to include additional
information in the future related to geometry validity, for example,
which would mean further reducing the range allowed within the
spatial_ref_sys table in its existing form.
Right.
Cheers,
David.
--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david.fetter@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
3) 3-rd boolean column (amopopr, amopfamily, amoporder) - could be two records per operator + operator could be used in both roles + strategy number could be different for different roles
How can #3 work at all? It's ignoring a couple of critical index
columns. In particular, I believe the sticking point here is this
unique index:"pg_amop_fam_strat_index" UNIQUE, btree (amopfamily, amoplefttype, amoprighttype, amopstrategy)
I believe, that columns (amoplefttype, amoprighttype) are fixed for operation
and could not be changed. So, two operations in one opfamily should be differ in
strategy number for different roles. It also gives a direct way to transfer
knowledge abot role to consistent method of GiST.
I'm not terribly thrilled with using a boolean here in any case.
Now that we have two "roles" an operator might play in an opclass,
who's to say there might not be more roles someday? We should use
a column type that will support more than two roles without basic
rejiggering.
It's easy to change to char type, for now only 's'search and 'o'order characters
will be allowed.
BTW, have we discussed the idea of embedding the role in the strategy
number? For example, require regular operators to have strategy
In this schema, one operator could not be used in more than one role. Right now
it's not strict limitation, because the we still don't have an example of
boolean distance.
Anyhow, it needs to distinguish roles while IndexPath is built. So,
op_in_opfamily/get_op_opfamily_strategy/get_op_opfamily_properties and friends
will accept extra argument pointing to interested role.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
Thinking about it that way, perhaps we could add an integer column
amop_whats_it_good_for that gets used as a bit field. That wouldn't
require changing the index structure, although it might break some
other things.
OPERATOR strategy_number ( op_type [ , op_type ] ) [ FOR { SEARCH |
ORDER } [, ...] ]
It's very desirable thing to be able to distinguish roles in consistent method
of GiST: computation of distance could be very expensive and. The single way to
provide it in current GiST interface is a strategy number. Of course, we could
add 6-th argument to consistent to point role, but I don't think that's good
decision.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
combination of parameters is one that it can handle. I'm thinking
perhaps in lieu of a boolean, we can add another indexam method which,
if not InvalidOid, gets called when we're wondering about whether a
given clause is something that the index can order by. Although
knngist focuses on a the ORDER BY col OP constant case, which
Hmm, interesting idea. To be more general, amcanorder (without byop suffix)
could be eliminated too.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
2010/10/19 Teodor Sigaev <teodor@sigaev.ru>:
Thinking about it that way, perhaps we could add an integer column
amop_whats_it_good_for that gets used as a bit field. That wouldn't
require changing the index structure, although it might break some
other things.OPERATOR strategy_number ( op_type [ , op_type ] ) [ FOR { SEARCH |
ORDER } [, ...] ]It's very desirable thing to be able to distinguish roles in consistent
method of GiST: computation of distance could be very expensive and. The
single way to provide it in current GiST interface is a strategy number. Of
course, we could add 6-th argument to consistent to point role, but I don't
think that's good decision.
To me, adding an additional argument (or maybe providing a whole
separate support function, separate from consistent) seems quite
natural, because now you have a way to pass all the other little bits
that might matter... ASC/DESC, NULLS FIRST/LAST, collation OID, etc.
You can define the additional argument as providing all of the extra
info about how the operator is being used, and, if it's being used for
ordering, the details of the requested order. What is your thinking
on the matter?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
You can define the additional argument as providing all of the extra
info about how the operator is being used, and, if it's being used for
ordering, the details of the requested order. What is your thinking
on the matter?
Maby be useful, but it seems to me to be a bit overengineering for now. GiST
will not support knn-search with different than ASC NULLS LAST order in foresee
future, because it stores NULLs in unmaintainable manner for different ordering:
NULLs could be everywhere in tree. So, implementation of ASC NULLS FIRST
requires to read whole tree to find all NULLs value first. I can imagine, how to
reorganize tree to store NULLs together for single-column index, but not for
multi-column index. Orders DESC NULLS LAST/FIRST requires to introduce two more
"infinite" values: one to notion of distance more than +INF and another,
non-negative, but less than zero distance.
Again, it could be useful for modification of GiST known as ordered GiST. But
ordered GiST uses completely different tree traversal algorithm for search and
insert, and it hasn't any benefits comparing with B-Tree and GiST. It's looks
like an autogiro which successfully combines disadvantages of airplanes and
helicopters :)
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
2010/10/22 Teodor Sigaev <teodor@sigaev.ru>:
You can define the additional argument as providing all of the extra
info about how the operator is being used, and, if it's being used for
ordering, the details of the requested order. What is your thinking
on the matter?Maby be useful, but it seems to me to be a bit overengineering for now. GiST
will not support knn-search with different than ASC NULLS LAST order in
foresee future, because it stores NULLs in unmaintainable manner for
different ordering: NULLs could be everywhere in tree. So, implementation of
ASC NULLS FIRST requires to read whole tree to find all NULLs value first. I
can imagine, how to reorganize tree to store NULLs together for
single-column index, but not for multi-column index. Orders DESC NULLS
LAST/FIRST requires to introduce two more "infinite" values: one to notion
of distance more than +INF and another, non-negative, but less than zero
distance.
I don't think it's overengineering, just because making core changes
to the planner is such a pain in the neck that we don't want to have
to come back and do it again any too soon, or at least we'd like them
to be as minor as possible. It's better to have one API break and be
done with it than maybe have to come back and do a second round of
code changes. And from what I can see it's not going to be that ugly.
I'm trying to drum up some time to hack on it...
Again, it could be useful for modification of GiST known as ordered GiST.
But ordered GiST uses completely different tree traversal algorithm for
search and insert, and it hasn't any benefits comparing with B-Tree and
GiST. It's looks like an autogiro which successfully combines disadvantages
of airplanes and helicopters :)
Heh. :-)
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Sat, Oct 16, 2010 at 9:54 PM, Robert Haas <robertmhaas@gmail.com> wrote:
Thinking about it that way, perhaps we could add an integer column
amop_whats_it_good_for that gets used as a bit field. That wouldn't
require changing the index structure, although it might break some
other things.I gave this a shot (though I called it amoppurpose rather than
amop_whats_it_good_for) and I think it's a reasonable way to proceed.
Proof-of-concept patch attached. This just adds the column (using the
existing padding space), defines AMOP_SEARCH and AMOP_ORDER, and makes
just about everything ignore anything not marked AMOP_SEARCH,
attached. This would obviously need some more hacking to pay
attention to AMOP_ORDER where relevant, etc. and to create some actual
syntax around it. Currently CREATE OPERATOR CLASS / ALTER OPERATOR
FAMILY have this bit:OPERATOR strategy_number ( op_type [ , op_type ] )
knngist-0.9 implements this:
[ORDER] OPERATOR strategy_number ( op_type [, op_type ] )
...but with the design proposed above that's not quite what we'd want,
because amoppurpose is a bit field, so you could have one or both of
the two possible purposes. Perhaps:OPERATOR strategy_number ( op_type [ , op_type ] ) [ FOR { SEARCH |
ORDER } [, ...] ]With the default being FOR SEARCH.
Slightly-more-fleshed out proof of concept patch attached, with actual
syntax, documentation, and pg_dump support added. This might be
thought of as a subset of the builtin_knngist_core patch, without the
parts that make it actually do something useful (which is mostly
match_pathkey_to_index - which I'm still rather hoping to abstract in
some way via the access method interface, though I'm currently unsure
what the best way to do that is).
I notice that builtin_knngist_core checks whether the return type of
an ordering operator has a built-in btree opclass. I'm not sure
whether we should bother checking that, because even if it's true I
don't think there's anything preventing it from becoming false later.
I think it's probably sufficient to just check this condition at plan
time and silently skip trying to build knn-type index paths if it's
not met.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachments:
amoppurpose-v2.patchtext/x-patch; charset=US-ASCII; name=amoppurpose-v2.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 9a8729b..9bd3169 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -646,6 +646,13 @@
</row>
<row>
+ <entry><structfield>amoppurpose</structfield></entry>
+ <entry><type>int2</type></entry>
+ <entry></entry>
+ <entry>Bit field indicating valid purposes of operator within operator family (1 = search, 2 = ordering)</entry>
+ </row>
+
+ <row>
<entry><structfield>amopopr</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
diff --git a/doc/src/sgml/ref/alter_opfamily.sgml b/doc/src/sgml/ref/alter_opfamily.sgml
index ed4877d..aa1655b 100644
--- a/doc/src/sgml/ref/alter_opfamily.sgml
+++ b/doc/src/sgml/ref/alter_opfamily.sgml
@@ -22,7 +22,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> ADD
- { OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> )
+ { OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) [ FOR ( <replaceable class="parameter">op_purpose</replaceable> [, ...] ) ]
| FUNCTION <replaceable class="parameter">support_number</replaceable> [ ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] ) ] <replaceable class="parameter">function_name</replaceable> ( <replaceable class="parameter">argument_type</replaceable> [, ...] )
} [, ... ]
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> DROP
@@ -155,6 +155,24 @@ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
</varlistentry>
<varlistentry>
+ <term><replaceable class="parameter">op_purpose</replaceable></term>
+ <listitem>
+ <para>
+ The purpose of the operator within the operator class. An operator
+ may serve more than one purpose. <literal>SEARCH</literal> indicates
+ that the operator class supports index searches based on this operator,
+ while <literal>ORDER</literal> indicates that the operator class can
+ be used to retrieve results in order in a query containing a clause
+ of the form <literal>ORDER BY <replaceable>column</replaceable>
+ <replaceable>operator_name</replaceable>
+ <replaceable>value</replaceable></literal>. More than one purpose
+ may be specified. If the clause is omitted, the default is
+ <literal>SEARCH</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable class="parameter">support_number</replaceable></term>
<listitem>
<para>
diff --git a/doc/src/sgml/ref/create_opclass.sgml b/doc/src/sgml/ref/create_opclass.sgml
index d7372aa..d3cfca6 100644
--- a/doc/src/sgml/ref/create_opclass.sgml
+++ b/doc/src/sgml/ref/create_opclass.sgml
@@ -23,7 +23,7 @@ PostgreSQL documentation
<synopsis>
CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAULT ] FOR TYPE <replaceable class="parameter">data_type</replaceable>
USING <replaceable class="parameter">index_method</replaceable> [ FAMILY <replaceable class="parameter">family_name</replaceable> ] AS
- { OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> [ ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) ]
+ { OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> [ ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) ] [ FOR ( <replaceable class="parameter">op_purpose</replaceable> [, ...] ) ]
| FUNCTION <replaceable class="parameter">support_number</replaceable> [ ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] ) ] <replaceable class="parameter">function_name</replaceable> ( <replaceable class="parameter">argument_type</replaceable> [, ...] )
| STORAGE <replaceable class="parameter">storage_type</replaceable>
} [, ... ]
@@ -181,6 +181,24 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
</varlistentry>
<varlistentry>
+ <term><replaceable class="parameter">op_purpose</replaceable></term>
+ <listitem>
+ <para>
+ The purpose of the operator within the operator class. An operator
+ may serve more than one purpose. <literal>SEARCH</literal> indicates
+ that the operator class supports index searches based on this operator,
+ while <literal>ORDER</literal> indicates that the operator class can
+ be used to retrieve results in order in a query containing a clause
+ of the form <literal>ORDER BY <replaceable>column</replaceable>
+ <replaceable>operator_name</replaceable>
+ <replaceable>value</replaceable></literal>. More than one purpose
+ may be specified. If the clause is omitted, the default is
+ <literal>SEARCH</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable class="parameter">support_number</replaceable></term>
<listitem>
<para>
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 8f0f226..238e9dc 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -21,6 +21,7 @@
#include "access/nbtree.h"
#include "access/reloptions.h"
#include "access/relscan.h"
+#include "catalog/pg_amop.h"
#include "executor/execdebug.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
@@ -622,7 +623,8 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
cmp_op = get_opfamily_member(rel->rd_opfamily[leftarg->sk_attno - 1],
lefttype,
righttype,
- strat);
+ strat,
+ AMOP_SEARCH);
if (OidIsValid(cmp_op))
{
RegProcedure cmp_proc = get_opcode(cmp_op);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 9407d0f..c512792 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -24,6 +24,7 @@
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_tablespace.h"
@@ -988,10 +989,11 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
errdetail("Only commutative operators can be used in exclusion constraints.")));
/*
- * Operator must be a member of the right opfamily, too
+ * Operator must be a member of the right opfamily, too.
+ * And should be useful for search.
*/
opfamily = get_opclass_family(classOidP[attn]);
- strat = get_op_opfamily_strategy(opid, opfamily);
+ strat = get_op_opfamily_strategy(opid, opfamily, AMOP_SEARCH);
if (strat == 0)
{
HeapTuple opftuple;
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index ea66e95..a0f375b 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -54,6 +54,7 @@ typedef struct
int number; /* strategy or support proc number */
Oid lefttype; /* lefttype */
Oid righttype; /* righttype */
+ int purpose; /* purpose */
} OpFamilyMember;
@@ -502,6 +503,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = operOid;
member->number = item->number;
+ member->purpose = item->purpose;
assignOperTypes(member, amoid, typeoid);
addFamilyMember(&operators, member, false);
break;
@@ -870,6 +872,7 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = operOid;
member->number = item->number;
+ member->purpose = item->purpose;
assignOperTypes(member, amoid, InvalidOid);
addFamilyMember(&operators, member, false);
break;
@@ -1029,6 +1032,9 @@ processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
/*
* Determine the lefttype/righttype to assign to an operator,
* and do any validity checking we can manage.
+ *
+ * member->object and member->purpose should already be initialized
+ * when this function is called.
*/
static void
assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
@@ -1049,10 +1055,10 @@ assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("index operators must be binary")));
- if (opform->oprresult != BOOLOID)
+ if (opform->oprresult != BOOLOID && (member->purpose & AMOP_SEARCH) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("index operators must return boolean")));
+ errmsg("index search operators must return boolean")));
/*
* If lefttype/righttype isn't specified, use the operator's input types
@@ -1235,6 +1241,7 @@ storeOperators(List *opfamilyname, Oid amoid,
values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
+ values[Anum_pg_amop_amoppurpose - 1] = Int32GetDatum(op->purpose);
tup = heap_form_tuple(rel->rd_att, values, nulls);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c009711..4afba2f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -26,6 +26,7 @@
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_inherits.h"
@@ -5184,7 +5185,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
* We'll use it for PK = PK comparisons.
*/
ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
- eqstrategy);
+ eqstrategy, AMOP_SEARCH);
if (!OidIsValid(ppeqop))
elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
@@ -5197,10 +5198,10 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
fktyped = getBaseType(fktype);
pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
- eqstrategy);
+ eqstrategy, AMOP_SEARCH);
if (OidIsValid(pfeqop))
ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
- eqstrategy);
+ eqstrategy, AMOP_SEARCH);
else
ffeqop = InvalidOid; /* keep compiler quiet */
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 7d7c1a1..a72fc9f 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -38,6 +38,7 @@
#include "access/nbtree.h"
#include "access/tupconvert.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "executor/execdebug.h"
@@ -4712,7 +4713,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
Oid righttype;
Oid proc;
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&strategy,
&lefttype,
&righttype);
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index ee5fc72..9ccd5ec 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -27,6 +27,7 @@
#include "access/genam.h"
#include "access/nbtree.h"
#include "access/relscan.h"
+#include "catalog/pg_amop.h"
#include "executor/execdebug.h"
#include "executor/nodeIndexscan.h"
#include "optimizer/clauses.h"
@@ -742,7 +743,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
*/
opfamily = index->rd_opfamily[varattno - 1];
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -832,7 +833,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
elog(ERROR, "bogus RowCompare index qualification");
opfamily = index->rd_opfamily[varattno - 1];
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -935,7 +936,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
*/
opfamily = index->rd_opfamily[varattno - 1];
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index e8ce5bc..d0836c4 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -201,7 +201,7 @@ MJExamineQuals(List *mergeclauses,
clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent);
/* Extract the operator's declared left/right datatypes */
- get_op_opfamily_properties(qual->opno, opfamily,
+ get_op_opfamily_properties(qual->opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 5346c72..801e018 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2974,6 +2974,7 @@ _copyCreateOpClassItem(CreateOpClassItem *from)
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(number);
COPY_NODE_FIELD(class_args);
+ COPY_NODE_FIELD(purpose);
COPY_NODE_FIELD(storedtype);
return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7cb2192..58c81ba 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1453,6 +1453,7 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
COMPARE_NODE_FIELD(args);
COMPARE_SCALAR_FIELD(number);
COMPARE_NODE_FIELD(class_args);
+ COMPARE_NODE_FIELD(purpose);
COMPARE_NODE_FIELD(storedtype);
return true;
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index e44e960..704fdb7 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -17,6 +17,7 @@
#include "postgres.h"
#include "access/skey.h"
+#include "catalog/pg_amop.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
@@ -1023,7 +1024,7 @@ select_equality_operator(EquivalenceClass *ec, Oid lefttype, Oid righttype)
Oid opno;
opno = get_opfamily_member(opfamily, lefttype, righttype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber, AMOP_SEARCH);
if (OidIsValid(opno))
return opno;
}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 38b0930..0101abc 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -19,6 +19,7 @@
#include "access/skey.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_type.h"
@@ -87,7 +88,7 @@ static bool match_clause_to_indexcol(IndexOptInfo *index,
RestrictInfo *rinfo,
Relids outer_relids,
SaOpControl saop_control);
-static bool is_indexable_operator(Oid expr_op, Oid opfamily,
+static bool is_indexable_operator(Oid expr_op, Oid opfamily, int purpose,
bool indexkey_on_left);
static bool match_rowcompare_to_indexcol(IndexOptInfo *index,
int indexcol,
@@ -1272,7 +1273,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
bms_is_subset(right_relids, outer_relids) &&
!contain_volatile_functions(rightop))
{
- if (is_indexable_operator(expr_op, opfamily, true))
+ if (is_indexable_operator(expr_op, opfamily, AMOP_SEARCH, true))
return true;
/*
@@ -1290,7 +1291,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
bms_is_subset(left_relids, outer_relids) &&
!contain_volatile_functions(leftop))
{
- if (is_indexable_operator(expr_op, opfamily, false))
+ if (is_indexable_operator(expr_op, opfamily, AMOP_SEARCH, false))
return true;
/*
@@ -1314,7 +1315,8 @@ match_clause_to_indexcol(IndexOptInfo *index,
* the opfamily.
*/
static bool
-is_indexable_operator(Oid expr_op, Oid opfamily, bool indexkey_on_left)
+is_indexable_operator(Oid expr_op, Oid opfamily, int purpose,
+ bool indexkey_on_left)
{
/* Get the commuted operator if necessary */
if (!indexkey_on_left)
@@ -1325,7 +1327,7 @@ is_indexable_operator(Oid expr_op, Oid opfamily, bool indexkey_on_left)
}
/* OK if the (commuted) operator is a member of the index's opfamily */
- return op_in_opfamily(expr_op, opfamily);
+ return op_in_opfamily(expr_op, opfamily, purpose);
}
/*
@@ -1384,7 +1386,7 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
return false;
/* We're good if the operator is the right type of opfamily member */
- switch (get_op_opfamily_strategy(expr_op, opfamily))
+ switch (get_op_opfamily_strategy(expr_op, opfamily, AMOP_SEARCH))
{
case BTLessStrategyNumber:
case BTLessEqualStrategyNumber:
@@ -2552,7 +2554,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_BPCHAR_LIKE_OP:
case OID_NAME_LIKE_OP:
case OID_BYTEA_LIKE_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,
&prefix, &rest);
@@ -2563,7 +2565,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_TEXT_ICLIKE_OP:
case OID_BPCHAR_ICLIKE_OP:
case OID_NAME_ICLIKE_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
@@ -2575,7 +2577,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_TEXT_REGEXEQ_OP:
case OID_BPCHAR_REGEXEQ_OP:
case OID_NAME_REGEXEQ_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,
@@ -2587,7 +2589,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_TEXT_ICREGEXEQ_OP:
case OID_BPCHAR_ICREGEXEQ_OP:
case OID_NAME_ICREGEXEQ_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
@@ -2598,7 +2600,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
case OID_INET_SUB_OP:
case OID_INET_SUBEQ_OP:
- if (!op_in_opfamily(expr_op, opfamily))
+ if (!op_in_opfamily(expr_op, opfamily, AMOP_SEARCH))
{
return network_prefix_quals(leftop, expr_op, opfamily,
patt->constvalue);
@@ -2656,7 +2658,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
expr_op = linitial_oid(clause->opnos);
if (!var_on_left)
expr_op = get_commutator(expr_op);
- get_op_opfamily_properties(expr_op, index->opfamily[indexcol],
+ get_op_opfamily_properties(expr_op, index->opfamily[indexcol], AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -2719,12 +2721,12 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
break; /* no match found */
/* Now, do we have the right operator for this column? */
- if (get_op_opfamily_strategy(expr_op, index->opfamily[i])
+ if (get_op_opfamily_strategy(expr_op, index->opfamily[i], AMOP_SEARCH)
!= op_strategy)
break;
/* Add opfamily and datatypes to lists */
- get_op_opfamily_properties(expr_op, index->opfamily[i],
+ get_op_opfamily_properties(expr_op, index->opfamily[i], AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -2776,7 +2778,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
Oid righttype = lfirst_oid(righttypes_cell);
expr_op = get_opfamily_member(opfam, lefttype, righttype,
- op_strategy);
+ op_strategy, AMOP_SEARCH);
if (!OidIsValid(expr_op)) /* should not happen */
elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
op_strategy, lefttype, righttype, opfam);
@@ -2900,7 +2902,7 @@ prefix_quals(Node *leftop, Oid opfamily,
if (pstatus == Pattern_Prefix_Exact)
{
oproid = get_opfamily_member(opfamily, datatype, datatype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber, AMOP_SEARCH);
if (oproid == InvalidOid)
elog(ERROR, "no = operator for opfamily %u", opfamily);
expr = make_opclause(oproid, BOOLOID, false,
@@ -2915,7 +2917,7 @@ prefix_quals(Node *leftop, Oid opfamily,
* We can always say "x >= prefix".
*/
oproid = get_opfamily_member(opfamily, datatype, datatype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber, AMOP_SEARCH);
if (oproid == InvalidOid)
elog(ERROR, "no >= operator for opfamily %u", opfamily);
expr = make_opclause(oproid, BOOLOID, false,
@@ -2928,7 +2930,7 @@ prefix_quals(Node *leftop, Oid opfamily,
*-------
*/
oproid = get_opfamily_member(opfamily, datatype, datatype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber, AMOP_SEARCH);
if (oproid == InvalidOid)
elog(ERROR, "no < operator for opfamily %u", opfamily);
fmgr_info(get_opcode(oproid), <proc);
@@ -2982,14 +2984,16 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
if (is_eq)
{
opr1oid = get_opfamily_member(opfamily, datatype, datatype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber,
+ AMOP_SEARCH);
if (opr1oid == InvalidOid)
elog(ERROR, "no >= operator for opfamily %u", opfamily);
}
else
{
opr1oid = get_opfamily_member(opfamily, datatype, datatype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
if (opr1oid == InvalidOid)
elog(ERROR, "no > operator for opfamily %u", opfamily);
}
@@ -3005,7 +3009,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
/* create clause "key <= network_scan_last( rightop )" */
opr2oid = get_opfamily_member(opfamily, datatype, datatype,
- BTLessEqualStrategyNumber);
+ BTLessEqualStrategyNumber, AMOP_SEARCH);
if (opr2oid == InvalidOid)
elog(ERROR, "no <= operator for opfamily %u", opfamily);
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 643d57a..753ee8b 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -18,6 +18,7 @@
#include "postgres.h"
#include "access/skey.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -266,7 +267,8 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
equality_op = get_opfamily_member(opfamily,
opcintype,
opcintype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (!OidIsValid(equality_op)) /* shouldn't happen */
elog(ERROR, "could not find equality operator for ordering operator %u",
ordering_op);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 52dd27b..fe2c650 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -20,6 +20,7 @@
#include <math.h>
#include "access/skey.h"
+#include "catalog/pg_amop.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -3403,7 +3404,8 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
sortop = get_opfamily_member(pathkey->pk_opfamily,
pk_datatype,
pk_datatype,
- pathkey->pk_strategy);
+ pathkey->pk_strategy,
+ AMOP_SEARCH);
if (!OidIsValid(sortop)) /* should not happen */
elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
pathkey->pk_strategy, pk_datatype, pk_datatype,
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index e590ee0..7b605de 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -16,6 +16,7 @@
#include "catalog/pg_aggregate.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -390,7 +391,8 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
continue;
strategy =
get_op_opfamily_strategy(((OpExpr *) rinfo->clause)->opno,
- index->opfamily[prevcol]);
+ index->opfamily[prevcol],
+ AMOP_SEARCH);
if (strategy == BTEqualStrategyNumber)
break;
}
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index 5ab4a31..bb013af 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -1640,8 +1640,9 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
HeapTuple clause_tuple;
- /* Must be btree */
- if (pred_form->amopmethod != BTREE_AM_OID)
+ /* Must be btree operator, usable for searching */
+ if (pred_form->amopmethod != BTREE_AM_OID
+ || (pred_form->amoppurpose & AMOP_SEARCH) == 0)
continue;
/* Get the predicate operator's btree strategy number */
@@ -1664,7 +1665,7 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
clause_tuple = SearchSysCache2(AMOPOPID,
ObjectIdGetDatum(clause_op),
ObjectIdGetDatum(opfamily_id));
- if (HeapTupleIsValid(clause_tuple))
+ if (HeapTupleIsValid(clause_tuple)) /* ZZZ */
{
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
@@ -1725,7 +1726,8 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
test_op = get_opfamily_member(opfamily_id,
pred_form->amoprighttype,
clause_righttype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (OidIsValid(test_op))
test_op = get_negator(test_op);
}
@@ -1734,7 +1736,8 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
test_op = get_opfamily_member(opfamily_id,
pred_form->amoprighttype,
clause_righttype,
- test_strategy);
+ test_strategy,
+ AMOP_SEARCH);
}
if (OidIsValid(test_op))
{
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1394b21..f4c434d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -51,6 +51,7 @@
#include <ctype.h>
#include <limits.h>
+#include "catalog/pg_amop.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_trigger.h"
@@ -341,6 +342,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
offset_clause select_offset_value
select_offset_value2 opt_select_fetch_first_value
%type <ival> row_or_rows first_or_next
+%type <ival> opclass_purpose opclass_purpose_list opclass_purpose_elt
%type <list> OptSeqOptList SeqOptList
%type <defelt> SeqOptElem
@@ -3933,22 +3935,25 @@ opclass_item_list:
;
opclass_item:
- OPERATOR Iconst any_operator opt_recheck
+ OPERATOR Iconst any_operator opt_recheck opclass_purpose
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->name = $3;
n->args = NIL;
n->number = $2;
+ n->purpose = $5;
$$ = (Node *) n;
}
| OPERATOR Iconst any_operator oper_argtypes opt_recheck
+ opclass_purpose
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->name = $3;
n->args = $4;
n->number = $2;
+ n->purpose = $6;
$$ = (Node *) n;
}
| FUNCTION Iconst func_name func_args
@@ -4004,6 +4009,25 @@ opt_recheck: RECHECK
| /*EMPTY*/ { $$ = FALSE; }
;
+opclass_purpose:
+ FOR '(' opclass_purpose_list ')'
+ { $$ = $3; }
+ | /*EMPTY*/ { $$ = AMOP_SEARCH; }
+ ;
+
+opclass_purpose_list:
+ opclass_purpose_elt { $$ = $1; }
+ | opclass_purpose_elt ',' opclass_purpose_list { $$ = $1 | $3; }
+ ;
+
+/*
+ * This could accept a ColId if we so wished; there's no need for these to
+ * be keywords. This way is simpler for now, though...
+ */
+opclass_purpose_elt:
+ SEARCH { $$ = AMOP_SEARCH; }
+ | ORDER { $$ = AMOP_ORDER; }
+ ;
CreateOpFamilyStmt:
CREATE OPERATOR FAMILY any_name USING access_method
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index c744221..8a2d702 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -94,6 +94,7 @@
#include "access/gin.h"
#include "access/sysattr.h"
#include "catalog/index.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
@@ -1215,7 +1216,8 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate)
* Pattern specifies an exact match, so pretend operator is '='
*/
Oid eqopr = get_opfamily_member(opfamily, vartype, vartype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (eqopr == InvalidOid)
elog(ERROR, "no = operator for opfamily %u", opfamily);
@@ -2631,7 +2633,7 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
examine_variable(root, right, 0, &rightvar);
/* Extract the operator's declared left/right datatypes */
- get_op_opfamily_properties(opno, opfamily,
+ get_op_opfamily_properties(opno, opfamily, AMOP_SEARCH,
&op_strategy,
&op_lefttype,
&op_righttype);
@@ -2653,10 +2655,12 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
/* easy case */
ltop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
leop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTLessEqualStrategyNumber);
+ BTLessEqualStrategyNumber,
+ AMOP_SEARCH);
lsortop = ltop;
rsortop = ltop;
lstatop = lsortop;
@@ -2668,24 +2672,30 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
{
ltop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
leop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTLessEqualStrategyNumber);
+ BTLessEqualStrategyNumber,
+ AMOP_SEARCH);
lsortop = get_opfamily_member(opfamily,
op_lefttype, op_lefttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
rsortop = get_opfamily_member(opfamily,
op_righttype, op_righttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
lstatop = lsortop;
rstatop = rsortop;
revltop = get_opfamily_member(opfamily,
op_righttype, op_lefttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
revleop = get_opfamily_member(opfamily,
op_righttype, op_lefttype,
- BTLessEqualStrategyNumber);
+ BTLessEqualStrategyNumber,
+ AMOP_SEARCH);
}
break;
case BTGreaterStrategyNumber:
@@ -2696,15 +2706,18 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
/* easy case */
ltop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
leop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber,
+ AMOP_SEARCH);
lsortop = ltop;
rsortop = ltop;
lstatop = get_opfamily_member(opfamily,
op_lefttype, op_lefttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
rstatop = lstatop;
revltop = ltop;
revleop = leop;
@@ -2713,28 +2726,36 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
{
ltop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
leop = get_opfamily_member(opfamily,
op_lefttype, op_righttype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber,
+ AMOP_SEARCH);
lsortop = get_opfamily_member(opfamily,
op_lefttype, op_lefttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
rsortop = get_opfamily_member(opfamily,
op_righttype, op_righttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
lstatop = get_opfamily_member(opfamily,
op_lefttype, op_lefttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
rstatop = get_opfamily_member(opfamily,
op_righttype, op_righttype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
revltop = get_opfamily_member(opfamily,
op_righttype, op_lefttype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
revleop = get_opfamily_member(opfamily,
op_righttype, op_lefttype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber,
+ AMOP_SEARCH);
}
break;
default:
@@ -5086,7 +5107,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
Selectivity eq_sel;
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
- BTGreaterEqualStrategyNumber);
+ BTGreaterEqualStrategyNumber, AMOP_SEARCH);
if (cmpopr == InvalidOid)
elog(ERROR, "no >= operator for opfamily %u", opfamily);
fmgr_info(get_opcode(cmpopr), &opproc);
@@ -5107,7 +5128,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
*-------
*/
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber, AMOP_SEARCH);
if (cmpopr == InvalidOid)
elog(ERROR, "no < operator for opfamily %u", opfamily);
fmgr_info(get_opcode(cmpopr), &opproc);
@@ -5147,7 +5168,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
* small estimate from the >= condition; so we still need to clamp.
*/
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber, AMOP_SEARCH);
if (cmpopr == InvalidOid)
elog(ERROR, "no = operator for opfamily %u", opfamily);
eq_sel = var_eq_const(vardata, cmpopr, prefixcon->constvalue,
@@ -6018,7 +6039,8 @@ btcostestimate(PG_FUNCTION_ARGS)
if (OidIsValid(clause_op))
{
op_strategy = get_op_opfamily_strategy(clause_op,
- index->opfamily[indexcol]);
+ index->opfamily[indexcol],
+ AMOP_SEARCH);
Assert(op_strategy != 0); /* not a member of opfamily?? */
if (op_strategy == BTEqualStrategyNumber)
eqQualHere = true;
@@ -6431,6 +6453,7 @@ gincostestimate(PG_FUNCTION_ARGS)
* within the index opfamily.
*/
get_op_opfamily_properties(clause_op, index->opfamily[indexcol],
+ AMOP_SEARCH,
&strategy_op, &lefttype, &righttype);
/*
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 740e8c4..a95a030 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -44,24 +44,36 @@ get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
/*
* op_in_opfamily
*
- * Return t iff operator 'opno' is in operator family 'opfamily'.
+ * Return t iff operator 'opno' is in operator family 'opfamily'
+ * with purpose 'purpose'.
*/
bool
-op_in_opfamily(Oid opno, Oid opfamily)
+op_in_opfamily(Oid opno, Oid opfamily, int purpose)
{
- return SearchSysCacheExists2(AMOPOPID,
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(opfamily));
+ HeapTuple tp;
+ Form_pg_amop amop_tup;
+ int amop_purpose;
+
+ tp = SearchSysCache2(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ ObjectIdGetDatum(opfamily));
+ if (!HeapTupleIsValid(tp))
+ return 0;
+ amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+ amop_purpose = amop_tup->amoppurpose;
+ ReleaseSysCache(tp);
+ return (amop_purpose & purpose) != 0;
}
/*
* get_op_opfamily_strategy
*
* Get the operator's strategy number within the specified opfamily,
- * or 0 if it's not a member of the opfamily.
+ * or 0 if it's not a member of the opfamily or not useful for the
+ * specified purpose.
*/
int
-get_op_opfamily_strategy(Oid opno, Oid opfamily)
+get_op_opfamily_strategy(Oid opno, Oid opfamily, int purpose)
{
HeapTuple tp;
Form_pg_amop amop_tup;
@@ -73,7 +85,10 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
if (!HeapTupleIsValid(tp))
return 0;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
- result = amop_tup->amopstrategy;
+ if ((amop_tup->amoppurpose & purpose) != 0)
+ result = amop_tup->amopstrategy;
+ else
+ result = 0;
ReleaseSysCache(tp);
return result;
}
@@ -88,7 +103,7 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
* therefore we raise an error if the tuple is not found.
*/
void
-get_op_opfamily_properties(Oid opno, Oid opfamily,
+get_op_opfamily_properties(Oid opno, Oid opfamily, int purpose,
int *strategy,
Oid *lefttype,
Oid *righttype)
@@ -103,6 +118,9 @@ get_op_opfamily_properties(Oid opno, Oid opfamily,
elog(ERROR, "operator %u is not a member of opfamily %u",
opno, opfamily);
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+ if ((amop_tup->amoppurpose & purpose) == 0)
+ elog(ERROR, "operator %u in opfamily %u can't be used for purpose %d",
+ opno, opfamily, purpose);
*strategy = amop_tup->amopstrategy;
*lefttype = amop_tup->amoplefttype;
*righttype = amop_tup->amoprighttype;
@@ -114,11 +132,12 @@ get_op_opfamily_properties(Oid opno, Oid opfamily,
* Get the OID of the operator that implements the specified strategy
* with the specified datatypes for the specified opfamily.
*
- * Returns InvalidOid if there is no pg_amop entry for the given keys.
+ * Returns InvalidOid if there is no pg_amop entry for the given keys, or
+ * if the operator is not useful for the specified purpose.
*/
Oid
get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
- int16 strategy)
+ int16 strategy, int16 purpose)
{
HeapTuple tp;
Form_pg_amop amop_tup;
@@ -132,7 +151,10 @@ get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
if (!HeapTupleIsValid(tp))
return InvalidOid;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
- result = amop_tup->amopopr;
+ if ((amop_tup->amoppurpose & purpose) != 0)
+ result = amop_tup->amopopr;
+ else
+ result = InvalidOid;
ReleaseSysCache(tp);
return result;
}
@@ -181,8 +203,9 @@ get_ordering_op_properties(Oid opno,
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
- /* must be btree */
- if (aform->amopmethod != BTREE_AM_OID)
+ /* must be btree search op */
+ if (aform->amopmethod != BTREE_AM_OID
+ && (aform->amoppurpose & AMOP_SEARCH) != 0)
continue;
if (aform->amopstrategy == BTLessStrategyNumber ||
@@ -276,7 +299,8 @@ get_equality_op_for_ordering_op(Oid opno, bool *reverse)
result = get_opfamily_member(opfamily,
opcintype,
opcintype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (reverse)
*reverse = (strategy == BTGreaterStrategyNumber);
}
@@ -316,8 +340,9 @@ get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
- /* must be btree */
- if (aform->amopmethod != BTREE_AM_OID)
+ /* must be btree search op */
+ if (aform->amopmethod != BTREE_AM_OID
+ && (aform->amoppurpose & AMOP_SEARCH) != 0)
continue;
if (aform->amopstrategy == BTEqualStrategyNumber)
@@ -328,7 +353,8 @@ get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
result = get_opfamily_member(aform->amopfamily,
typid, typid,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
if (OidIsValid(result))
break;
/* failure probably shouldn't happen, but keep looking if so */
@@ -379,6 +405,7 @@ get_mergejoin_opfamilies(Oid opno)
/* must be btree equality */
if (aform->amopmethod == BTREE_AM_OID &&
+ (aform->amoppurpose & AMOP_SEARCH) != 0 &&
aform->amopstrategy == BTEqualStrategyNumber)
result = lappend_oid(result, aform->amopfamily);
}
@@ -430,6 +457,7 @@ get_compatible_hash_operators(Oid opno,
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopmethod == HASH_AM_OID &&
+ (aform->amoppurpose & AMOP_SEARCH) != 0 &&
aform->amopstrategy == HTEqualStrategyNumber)
{
/* No extra lookup needed if given operator is single-type */
@@ -453,7 +481,8 @@ get_compatible_hash_operators(Oid opno,
*lhs_opno = get_opfamily_member(aform->amopfamily,
aform->amoplefttype,
aform->amoplefttype,
- HTEqualStrategyNumber);
+ HTEqualStrategyNumber,
+ AMOP_SEARCH);
if (!OidIsValid(*lhs_opno))
continue;
/* Matching LHS found, done if caller doesn't want RHS */
@@ -468,7 +497,8 @@ get_compatible_hash_operators(Oid opno,
*rhs_opno = get_opfamily_member(aform->amopfamily,
aform->amoprighttype,
aform->amoprighttype,
- HTEqualStrategyNumber);
+ HTEqualStrategyNumber,
+ AMOP_SEARCH);
if (!OidIsValid(*rhs_opno))
{
/* Forget any LHS operator from this opfamily */
@@ -530,6 +560,7 @@ get_op_hash_functions(Oid opno,
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopmethod == HASH_AM_OID &&
+ (aform->amoppurpose & AMOP_SEARCH) != 0 &&
aform->amopstrategy == HTEqualStrategyNumber)
{
/*
@@ -635,8 +666,9 @@ get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
Oid opfamily_id;
StrategyNumber op_strategy;
- /* must be btree */
- if (op_form->amopmethod != BTREE_AM_OID)
+ /* must be btree search op */
+ if (op_form->amopmethod != BTREE_AM_OID
+ && (op_form->amoppurpose & AMOP_SEARCH) != 0)
continue;
/* Get the operator's btree strategy number */
@@ -692,11 +724,12 @@ equality_ops_are_compatible(Oid opno1, Oid opno2)
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
- /* must be btree or hash */
- if (op_form->amopmethod == BTREE_AM_OID ||
- op_form->amopmethod == HASH_AM_OID)
+ /* must be btree or hash search op */
+ if ((op_form->amopmethod == BTREE_AM_OID ||
+ op_form->amopmethod == HASH_AM_OID) &&
+ (op_form->amoppurpose & AMOP_SEARCH) != 0)
{
- if (op_in_opfamily(opno2, op_form->amopfamily))
+ if (op_in_opfamily(opno2, op_form->amopfamily, AMOP_SEARCH))
{
result = true;
break;
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 2a44303..04e8f61 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3828,7 +3828,8 @@ RelationGetExclusionInfo(Relation indexRelation,
{
funcs[i] = get_opcode(ops[i]);
strats[i] = get_op_opfamily_strategy(ops[i],
- indexRelation->rd_opfamily[i]);
+ indexRelation->rd_opfamily[i],
+ AMOP_SEARCH);
/* shouldn't fail, since it was checked at index creation */
if (strats[i] == InvalidStrategy)
elog(ERROR, "could not find strategy for operator %u in family %u",
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index bc4abc4..762fda8 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -48,6 +48,7 @@
#include "access/heapam.h"
#include "access/nbtree.h"
#include "catalog/indexing.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
@@ -241,13 +242,15 @@ lookup_type_cache(Oid type_id, int flags)
typentry->eq_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
- BTEqualStrategyNumber);
+ BTEqualStrategyNumber,
+ AMOP_SEARCH);
if (typentry->eq_opr == InvalidOid &&
typentry->hash_opf != InvalidOid)
typentry->eq_opr = get_opfamily_member(typentry->hash_opf,
typentry->hash_opintype,
typentry->hash_opintype,
- HTEqualStrategyNumber);
+ HTEqualStrategyNumber,
+ AMOP_SEARCH);
}
if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid)
{
@@ -255,7 +258,8 @@ lookup_type_cache(Oid type_id, int flags)
typentry->lt_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
- BTLessStrategyNumber);
+ BTLessStrategyNumber,
+ AMOP_SEARCH);
}
if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid)
{
@@ -263,7 +267,8 @@ lookup_type_cache(Oid type_id, int flags)
typentry->gt_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
- BTGreaterStrategyNumber);
+ BTGreaterStrategyNumber,
+ AMOP_SEARCH);
}
if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
typentry->cmp_proc == InvalidOid)
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 55ea684..5c9929e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -45,6 +45,7 @@
#include "access/attnum.h"
#include "access/sysattr.h"
+#include "catalog/pg_amop.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_class.h"
#include "catalog/pg_default_acl.h"
@@ -198,6 +199,7 @@ static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
const char *tag, const char *nspname, const char *owner,
const char *acls);
+static void format_amoppurpose(PQExpBuffer q, int amoppurpose);
static void getDependencies(void);
static void getDomainConstraints(TypeInfo *tyinfo);
static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
@@ -8820,6 +8822,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
int i_amopstrategy;
int i_amopreqcheck;
int i_amopopr;
+ int i_amoppurpose;
int i_amprocnum;
int i_amproc;
char *opcintype;
@@ -8831,6 +8834,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
char *amopstrategy;
char *amopreqcheck;
char *amopopr;
+ int amoppurpose;
char *amprocnum;
char *amproc;
bool needComma;
@@ -8957,7 +8961,20 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
*/
resetPQExpBuffer(query);
- if (g_fout->remoteVersion >= 80400)
+ if (g_fout->remoteVersion >= 90100)
+ {
+ /* amoppurpose is new in PostgreSQL 9.1 */
+ appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
+ "amopopr::pg_catalog.regoperator, amoppurpose "
+ "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
+ "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
+ "AND refobjid = '%u'::pg_catalog.oid "
+ "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
+ "AND objid = ao.oid "
+ "ORDER BY amopstrategy",
+ opcinfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 80400)
{
/*
* Print only those opfamily members that are tied to the opclass by
@@ -8970,7 +8987,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
* away once 8.3 is so old as to not be of interest to anyone.
*/
appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
- "amopopr::pg_catalog.regoperator "
+ "amopopr::pg_catalog.regoperator, 1 AS amoppurpose "
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
"WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
"AND refobjid = '%u'::pg_catalog.oid "
@@ -8986,7 +9003,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
* pg_depend entries.
*/
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
- "amopopr::pg_catalog.regoperator "
+ "amopopr::pg_catalog.regoperator, 1 AS amoppurpose "
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
"WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
"AND refobjid = '%u'::pg_catalog.oid "
@@ -8998,7 +9015,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
else
{
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
- "amopopr::pg_catalog.regoperator "
+ "amopopr::pg_catalog.regoperator, 1 AS amoppurpose "
"FROM pg_catalog.pg_amop "
"WHERE amopclaid = '%u'::pg_catalog.oid "
"ORDER BY amopstrategy",
@@ -9013,11 +9030,13 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
i_amopstrategy = PQfnumber(res, "amopstrategy");
i_amopreqcheck = PQfnumber(res, "amopreqcheck");
i_amopopr = PQfnumber(res, "amopopr");
+ i_amoppurpose = PQfnumber(res, "amoppurpose");
for (i = 0; i < ntups; i++)
{
amopstrategy = PQgetvalue(res, i, i_amopstrategy);
amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
+ amoppurpose = atoi(PQgetvalue(res, i, i_amoppurpose));
amopopr = PQgetvalue(res, i, i_amopopr);
if (needComma)
@@ -9027,6 +9046,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
amopstrategy, amopopr);
if (strcmp(amopreqcheck, "t") == 0)
appendPQExpBuffer(q, " RECHECK");
+ format_amoppurpose(q, amoppurpose);
needComma = true;
}
@@ -9134,6 +9154,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
int i_amopstrategy;
int i_amopreqcheck;
int i_amopopr;
+ int i_amoppurpose;
int i_amprocnum;
int i_amproc;
int i_amproclefttype;
@@ -9142,6 +9163,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
char *amopstrategy;
char *amopreqcheck;
char *amopopr;
+ int amoppurpose;
char *amprocnum;
char *amproc;
char *amproclefttype;
@@ -9173,7 +9195,20 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
* Fetch only those opfamily members that are tied directly to the
* opfamily by pg_depend entries.
*/
- if (g_fout->remoteVersion >= 80400)
+ if (g_fout->remoteVersion >= 90100)
+ {
+ /* amoppurpose is new in PostgreSQL 9.1 */
+ appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
+ "amopopr::pg_catalog.regoperator, amoppurpose "
+ "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
+ "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+ "AND refobjid = '%u'::pg_catalog.oid "
+ "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
+ "AND objid = ao.oid "
+ "ORDER BY amopstrategy",
+ opfinfo->dobj.catId.oid);
+ }
+ else if (g_fout->remoteVersion >= 80400)
{
/*
* XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
@@ -9183,7 +9218,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
* away once 8.3 is so old as to not be of interest to anyone.
*/
appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
- "amopopr::pg_catalog.regoperator "
+ "amopopr::pg_catalog.regoperator, 1 AS amoppurpose "
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
"WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
"AND refobjid = '%u'::pg_catalog.oid "
@@ -9195,7 +9230,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
else
{
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
- "amopopr::pg_catalog.regoperator "
+ "amopopr::pg_catalog.regoperator, 1 AS amoppurpose "
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
"WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
"AND refobjid = '%u'::pg_catalog.oid "
@@ -9323,12 +9358,14 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
i_amopopr = PQfnumber(res_ops, "amopopr");
+ i_amoppurpose = PQfnumber(res_ops, "amoppurpose");
for (i = 0; i < ntups; i++)
{
amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
amopopr = PQgetvalue(res_ops, i, i_amopopr);
+ amoppurpose = atoi(PQgetvalue(res_ops, i, i_amoppurpose));
if (needComma)
appendPQExpBuffer(q, " ,\n ");
@@ -9337,6 +9374,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
amopstrategy, amopopr);
if (strcmp(amopreqcheck, "t") == 0)
appendPQExpBuffer(q, " RECHECK");
+ format_amoppurpose(q, amoppurpose);
needComma = true;
}
@@ -9399,6 +9437,30 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
destroyPQExpBuffer(delq);
}
+static void
+format_amoppurpose(PQExpBuffer q, int amoppurpose)
+{
+ bool didany = false;
+
+ /* Search is the default. */
+ if ((amoppurpose & (AMOP_SEARCH|AMOP_ORDER)) == AMOP_SEARCH)
+ return;
+
+ /* Otherwise go bit by bit. */
+ if ((amoppurpose & AMOP_SEARCH) != 0)
+ {
+ appendPQExpBuffer(q, didany ? ", SEARCH" : " FOR (SEARCH");
+ didany = true;
+ }
+ if ((amoppurpose & AMOP_ORDER) != 0)
+ {
+ appendPQExpBuffer(q, didany ? ", ORDER" : " FOR (ORDER");
+ didany = true;
+ }
+ if (didany)
+ appendPQExpBuffer(q, ")");
+}
+
/*
* dumpConversion
* write out a single conversion definition
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index d5cf859..baee0ff 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -22,6 +22,15 @@
* This implies that the same operator cannot be listed for multiple strategy
* numbers within a single opfamily.
*
+ * amoppurpose is specifies the purpose(s) of this operator within the
+ * operator family, and is interpreted as a bit-field. AMOP_SEARCH operators
+ * are useful for queries of the form SELECT ... FROM table WHERE col OP val;
+ * AMOP_ORDER operators are useful for queries of the form SELECT ... FROM
+ * table ORDER BY col OP val. In theory, an operator could be useful for
+ * both purposes, although in practice this is not very likely since a
+ * search operator must return bool, which is not necessarily useful for
+ * ordering.
+ *
* amopmethod is a copy of the owning opfamily's opfmethod field. This is an
* intentional denormalization of the catalogs to buy lookup speed.
*
@@ -49,12 +58,16 @@
*/
#define AccessMethodOperatorRelationId 2602
+#define AMOP_SEARCH 1
+#define AMOP_ORDER 2
+
CATALOG(pg_amop,2602)
{
Oid amopfamily; /* the index opfamily this entry is for */
Oid amoplefttype; /* operator's left input data type */
Oid amoprighttype; /* operator's right input data type */
int2 amopstrategy; /* operator strategy number */
+ int2 amoppurpose; /* operator's purpose */
Oid amopopr; /* the operator's pg_operator OID */
Oid amopmethod; /* the index access method this entry is for */
} FormData_pg_amop;
@@ -70,13 +83,14 @@ typedef FormData_pg_amop *Form_pg_amop;
* compiler constants for pg_amop
* ----------------
*/
-#define Natts_pg_amop 6
+#define Natts_pg_amop 7
#define Anum_pg_amop_amopfamily 1
#define Anum_pg_amop_amoplefttype 2
#define Anum_pg_amop_amoprighttype 3
#define Anum_pg_amop_amopstrategy 4
-#define Anum_pg_amop_amopopr 5
-#define Anum_pg_amop_amopmethod 6
+#define Anum_pg_amop_amoppurpose 5
+#define Anum_pg_amop_amopopr 6
+#define Anum_pg_amop_amopmethod 7
/* ----------------
* initial contents of pg_amop
@@ -88,610 +102,610 @@ typedef FormData_pg_amop *Form_pg_amop;
*/
/* default operators int2 */
-DATA(insert ( 1976 21 21 1 95 403 ));
-DATA(insert ( 1976 21 21 2 522 403 ));
-DATA(insert ( 1976 21 21 3 94 403 ));
-DATA(insert ( 1976 21 21 4 524 403 ));
-DATA(insert ( 1976 21 21 5 520 403 ));
+DATA(insert ( 1976 21 21 1 1 95 403 ));
+DATA(insert ( 1976 21 21 2 1 522 403 ));
+DATA(insert ( 1976 21 21 3 1 94 403 ));
+DATA(insert ( 1976 21 21 4 1 524 403 ));
+DATA(insert ( 1976 21 21 5 1 520 403 ));
/* crosstype operators int24 */
-DATA(insert ( 1976 21 23 1 534 403 ));
-DATA(insert ( 1976 21 23 2 540 403 ));
-DATA(insert ( 1976 21 23 3 532 403 ));
-DATA(insert ( 1976 21 23 4 542 403 ));
-DATA(insert ( 1976 21 23 5 536 403 ));
+DATA(insert ( 1976 21 23 1 1 534 403 ));
+DATA(insert ( 1976 21 23 2 1 540 403 ));
+DATA(insert ( 1976 21 23 3 1 532 403 ));
+DATA(insert ( 1976 21 23 4 1 542 403 ));
+DATA(insert ( 1976 21 23 5 1 536 403 ));
/* crosstype operators int28 */
-DATA(insert ( 1976 21 20 1 1864 403 ));
-DATA(insert ( 1976 21 20 2 1866 403 ));
-DATA(insert ( 1976 21 20 3 1862 403 ));
-DATA(insert ( 1976 21 20 4 1867 403 ));
-DATA(insert ( 1976 21 20 5 1865 403 ));
+DATA(insert ( 1976 21 20 1 1 1864 403 ));
+DATA(insert ( 1976 21 20 2 1 1866 403 ));
+DATA(insert ( 1976 21 20 3 1 1862 403 ));
+DATA(insert ( 1976 21 20 4 1 1867 403 ));
+DATA(insert ( 1976 21 20 5 1 1865 403 ));
/* default operators int4 */
-DATA(insert ( 1976 23 23 1 97 403 ));
-DATA(insert ( 1976 23 23 2 523 403 ));
-DATA(insert ( 1976 23 23 3 96 403 ));
-DATA(insert ( 1976 23 23 4 525 403 ));
-DATA(insert ( 1976 23 23 5 521 403 ));
+DATA(insert ( 1976 23 23 1 1 97 403 ));
+DATA(insert ( 1976 23 23 2 1 523 403 ));
+DATA(insert ( 1976 23 23 3 1 96 403 ));
+DATA(insert ( 1976 23 23 4 1 525 403 ));
+DATA(insert ( 1976 23 23 5 1 521 403 ));
/* crosstype operators int42 */
-DATA(insert ( 1976 23 21 1 535 403 ));
-DATA(insert ( 1976 23 21 2 541 403 ));
-DATA(insert ( 1976 23 21 3 533 403 ));
-DATA(insert ( 1976 23 21 4 543 403 ));
-DATA(insert ( 1976 23 21 5 537 403 ));
+DATA(insert ( 1976 23 21 1 1 535 403 ));
+DATA(insert ( 1976 23 21 2 1 541 403 ));
+DATA(insert ( 1976 23 21 3 1 533 403 ));
+DATA(insert ( 1976 23 21 4 1 543 403 ));
+DATA(insert ( 1976 23 21 5 1 537 403 ));
/* crosstype operators int48 */
-DATA(insert ( 1976 23 20 1 37 403 ));
-DATA(insert ( 1976 23 20 2 80 403 ));
-DATA(insert ( 1976 23 20 3 15 403 ));
-DATA(insert ( 1976 23 20 4 82 403 ));
-DATA(insert ( 1976 23 20 5 76 403 ));
+DATA(insert ( 1976 23 20 1 1 37 403 ));
+DATA(insert ( 1976 23 20 2 1 80 403 ));
+DATA(insert ( 1976 23 20 3 1 15 403 ));
+DATA(insert ( 1976 23 20 4 1 82 403 ));
+DATA(insert ( 1976 23 20 5 1 76 403 ));
/* default operators int8 */
-DATA(insert ( 1976 20 20 1 412 403 ));
-DATA(insert ( 1976 20 20 2 414 403 ));
-DATA(insert ( 1976 20 20 3 410 403 ));
-DATA(insert ( 1976 20 20 4 415 403 ));
-DATA(insert ( 1976 20 20 5 413 403 ));
+DATA(insert ( 1976 20 20 1 1 412 403 ));
+DATA(insert ( 1976 20 20 2 1 414 403 ));
+DATA(insert ( 1976 20 20 3 1 410 403 ));
+DATA(insert ( 1976 20 20 4 1 415 403 ));
+DATA(insert ( 1976 20 20 5 1 413 403 ));
/* crosstype operators int82 */
-DATA(insert ( 1976 20 21 1 1870 403 ));
-DATA(insert ( 1976 20 21 2 1872 403 ));
-DATA(insert ( 1976 20 21 3 1868 403 ));
-DATA(insert ( 1976 20 21 4 1873 403 ));
-DATA(insert ( 1976 20 21 5 1871 403 ));
+DATA(insert ( 1976 20 21 1 1 1870 403 ));
+DATA(insert ( 1976 20 21 2 1 1872 403 ));
+DATA(insert ( 1976 20 21 3 1 1868 403 ));
+DATA(insert ( 1976 20 21 4 1 1873 403 ));
+DATA(insert ( 1976 20 21 5 1 1871 403 ));
/* crosstype operators int84 */
-DATA(insert ( 1976 20 23 1 418 403 ));
-DATA(insert ( 1976 20 23 2 420 403 ));
-DATA(insert ( 1976 20 23 3 416 403 ));
-DATA(insert ( 1976 20 23 4 430 403 ));
-DATA(insert ( 1976 20 23 5 419 403 ));
+DATA(insert ( 1976 20 23 1 1 418 403 ));
+DATA(insert ( 1976 20 23 2 1 420 403 ));
+DATA(insert ( 1976 20 23 3 1 416 403 ));
+DATA(insert ( 1976 20 23 4 1 430 403 ));
+DATA(insert ( 1976 20 23 5 1 419 403 ));
/*
* btree oid_ops
*/
-DATA(insert ( 1989 26 26 1 609 403 ));
-DATA(insert ( 1989 26 26 2 611 403 ));
-DATA(insert ( 1989 26 26 3 607 403 ));
-DATA(insert ( 1989 26 26 4 612 403 ));
-DATA(insert ( 1989 26 26 5 610 403 ));
+DATA(insert ( 1989 26 26 1 1 609 403 ));
+DATA(insert ( 1989 26 26 2 1 611 403 ));
+DATA(insert ( 1989 26 26 3 1 607 403 ));
+DATA(insert ( 1989 26 26 4 1 612 403 ));
+DATA(insert ( 1989 26 26 5 1 610 403 ));
/*
* btree tid_ops
*/
-DATA(insert ( 2789 27 27 1 2799 403 ));
-DATA(insert ( 2789 27 27 2 2801 403 ));
-DATA(insert ( 2789 27 27 3 387 403 ));
-DATA(insert ( 2789 27 27 4 2802 403 ));
-DATA(insert ( 2789 27 27 5 2800 403 ));
+DATA(insert ( 2789 27 27 1 1 2799 403 ));
+DATA(insert ( 2789 27 27 2 1 2801 403 ));
+DATA(insert ( 2789 27 27 3 1 387 403 ));
+DATA(insert ( 2789 27 27 4 1 2802 403 ));
+DATA(insert ( 2789 27 27 5 1 2800 403 ));
/*
* btree oidvector_ops
*/
-DATA(insert ( 1991 30 30 1 645 403 ));
-DATA(insert ( 1991 30 30 2 647 403 ));
-DATA(insert ( 1991 30 30 3 649 403 ));
-DATA(insert ( 1991 30 30 4 648 403 ));
-DATA(insert ( 1991 30 30 5 646 403 ));
+DATA(insert ( 1991 30 30 1 1 645 403 ));
+DATA(insert ( 1991 30 30 2 1 647 403 ));
+DATA(insert ( 1991 30 30 3 1 649 403 ));
+DATA(insert ( 1991 30 30 4 1 648 403 ));
+DATA(insert ( 1991 30 30 5 1 646 403 ));
/*
* btree float_ops
*/
/* default operators float4 */
-DATA(insert ( 1970 700 700 1 622 403 ));
-DATA(insert ( 1970 700 700 2 624 403 ));
-DATA(insert ( 1970 700 700 3 620 403 ));
-DATA(insert ( 1970 700 700 4 625 403 ));
-DATA(insert ( 1970 700 700 5 623 403 ));
+DATA(insert ( 1970 700 700 1 1 622 403 ));
+DATA(insert ( 1970 700 700 2 1 624 403 ));
+DATA(insert ( 1970 700 700 3 1 620 403 ));
+DATA(insert ( 1970 700 700 4 1 625 403 ));
+DATA(insert ( 1970 700 700 5 1 623 403 ));
/* crosstype operators float48 */
-DATA(insert ( 1970 700 701 1 1122 403 ));
-DATA(insert ( 1970 700 701 2 1124 403 ));
-DATA(insert ( 1970 700 701 3 1120 403 ));
-DATA(insert ( 1970 700 701 4 1125 403 ));
-DATA(insert ( 1970 700 701 5 1123 403 ));
+DATA(insert ( 1970 700 701 1 1 1122 403 ));
+DATA(insert ( 1970 700 701 2 1 1124 403 ));
+DATA(insert ( 1970 700 701 3 1 1120 403 ));
+DATA(insert ( 1970 700 701 4 1 1125 403 ));
+DATA(insert ( 1970 700 701 5 1 1123 403 ));
/* default operators float8 */
-DATA(insert ( 1970 701 701 1 672 403 ));
-DATA(insert ( 1970 701 701 2 673 403 ));
-DATA(insert ( 1970 701 701 3 670 403 ));
-DATA(insert ( 1970 701 701 4 675 403 ));
-DATA(insert ( 1970 701 701 5 674 403 ));
+DATA(insert ( 1970 701 701 1 1 672 403 ));
+DATA(insert ( 1970 701 701 2 1 673 403 ));
+DATA(insert ( 1970 701 701 3 1 670 403 ));
+DATA(insert ( 1970 701 701 4 1 675 403 ));
+DATA(insert ( 1970 701 701 5 1 674 403 ));
/* crosstype operators float84 */
-DATA(insert ( 1970 701 700 1 1132 403 ));
-DATA(insert ( 1970 701 700 2 1134 403 ));
-DATA(insert ( 1970 701 700 3 1130 403 ));
-DATA(insert ( 1970 701 700 4 1135 403 ));
-DATA(insert ( 1970 701 700 5 1133 403 ));
+DATA(insert ( 1970 701 700 1 1 1132 403 ));
+DATA(insert ( 1970 701 700 2 1 1134 403 ));
+DATA(insert ( 1970 701 700 3 1 1130 403 ));
+DATA(insert ( 1970 701 700 4 1 1135 403 ));
+DATA(insert ( 1970 701 700 5 1 1133 403 ));
/*
* btree char_ops
*/
-DATA(insert ( 429 18 18 1 631 403 ));
-DATA(insert ( 429 18 18 2 632 403 ));
-DATA(insert ( 429 18 18 3 92 403 ));
-DATA(insert ( 429 18 18 4 634 403 ));
-DATA(insert ( 429 18 18 5 633 403 ));
+DATA(insert ( 429 18 18 1 1 631 403 ));
+DATA(insert ( 429 18 18 2 1 632 403 ));
+DATA(insert ( 429 18 18 3 1 92 403 ));
+DATA(insert ( 429 18 18 4 1 634 403 ));
+DATA(insert ( 429 18 18 5 1 633 403 ));
/*
* btree name_ops
*/
-DATA(insert ( 1986 19 19 1 660 403 ));
-DATA(insert ( 1986 19 19 2 661 403 ));
-DATA(insert ( 1986 19 19 3 93 403 ));
-DATA(insert ( 1986 19 19 4 663 403 ));
-DATA(insert ( 1986 19 19 5 662 403 ));
+DATA(insert ( 1986 19 19 1 1 660 403 ));
+DATA(insert ( 1986 19 19 2 1 661 403 ));
+DATA(insert ( 1986 19 19 3 1 93 403 ));
+DATA(insert ( 1986 19 19 4 1 663 403 ));
+DATA(insert ( 1986 19 19 5 1 662 403 ));
/*
* btree text_ops
*/
-DATA(insert ( 1994 25 25 1 664 403 ));
-DATA(insert ( 1994 25 25 2 665 403 ));
-DATA(insert ( 1994 25 25 3 98 403 ));
-DATA(insert ( 1994 25 25 4 667 403 ));
-DATA(insert ( 1994 25 25 5 666 403 ));
+DATA(insert ( 1994 25 25 1 1 664 403 ));
+DATA(insert ( 1994 25 25 2 1 665 403 ));
+DATA(insert ( 1994 25 25 3 1 98 403 ));
+DATA(insert ( 1994 25 25 4 1 667 403 ));
+DATA(insert ( 1994 25 25 5 1 666 403 ));
/*
* btree bpchar_ops
*/
-DATA(insert ( 426 1042 1042 1 1058 403 ));
-DATA(insert ( 426 1042 1042 2 1059 403 ));
-DATA(insert ( 426 1042 1042 3 1054 403 ));
-DATA(insert ( 426 1042 1042 4 1061 403 ));
-DATA(insert ( 426 1042 1042 5 1060 403 ));
+DATA(insert ( 426 1042 1042 1 1 1058 403 ));
+DATA(insert ( 426 1042 1042 2 1 1059 403 ));
+DATA(insert ( 426 1042 1042 3 1 1054 403 ));
+DATA(insert ( 426 1042 1042 4 1 1061 403 ));
+DATA(insert ( 426 1042 1042 5 1 1060 403 ));
/*
* btree bytea_ops
*/
-DATA(insert ( 428 17 17 1 1957 403 ));
-DATA(insert ( 428 17 17 2 1958 403 ));
-DATA(insert ( 428 17 17 3 1955 403 ));
-DATA(insert ( 428 17 17 4 1960 403 ));
-DATA(insert ( 428 17 17 5 1959 403 ));
+DATA(insert ( 428 17 17 1 1 1957 403 ));
+DATA(insert ( 428 17 17 2 1 1958 403 ));
+DATA(insert ( 428 17 17 3 1 1955 403 ));
+DATA(insert ( 428 17 17 4 1 1960 403 ));
+DATA(insert ( 428 17 17 5 1 1959 403 ));
/*
* btree abstime_ops
*/
-DATA(insert ( 421 702 702 1 562 403 ));
-DATA(insert ( 421 702 702 2 564 403 ));
-DATA(insert ( 421 702 702 3 560 403 ));
-DATA(insert ( 421 702 702 4 565 403 ));
-DATA(insert ( 421 702 702 5 563 403 ));
+DATA(insert ( 421 702 702 1 1 562 403 ));
+DATA(insert ( 421 702 702 2 1 564 403 ));
+DATA(insert ( 421 702 702 3 1 560 403 ));
+DATA(insert ( 421 702 702 4 1 565 403 ));
+DATA(insert ( 421 702 702 5 1 563 403 ));
/*
* btree datetime_ops
*/
/* default operators date */
-DATA(insert ( 434 1082 1082 1 1095 403 ));
-DATA(insert ( 434 1082 1082 2 1096 403 ));
-DATA(insert ( 434 1082 1082 3 1093 403 ));
-DATA(insert ( 434 1082 1082 4 1098 403 ));
-DATA(insert ( 434 1082 1082 5 1097 403 ));
+DATA(insert ( 434 1082 1082 1 1 1095 403 ));
+DATA(insert ( 434 1082 1082 2 1 1096 403 ));
+DATA(insert ( 434 1082 1082 3 1 1093 403 ));
+DATA(insert ( 434 1082 1082 4 1 1098 403 ));
+DATA(insert ( 434 1082 1082 5 1 1097 403 ));
/* crosstype operators vs timestamp */
-DATA(insert ( 434 1082 1114 1 2345 403 ));
-DATA(insert ( 434 1082 1114 2 2346 403 ));
-DATA(insert ( 434 1082 1114 3 2347 403 ));
-DATA(insert ( 434 1082 1114 4 2348 403 ));
-DATA(insert ( 434 1082 1114 5 2349 403 ));
+DATA(insert ( 434 1082 1114 1 1 2345 403 ));
+DATA(insert ( 434 1082 1114 2 1 2346 403 ));
+DATA(insert ( 434 1082 1114 3 1 2347 403 ));
+DATA(insert ( 434 1082 1114 4 1 2348 403 ));
+DATA(insert ( 434 1082 1114 5 1 2349 403 ));
/* crosstype operators vs timestamptz */
-DATA(insert ( 434 1082 1184 1 2358 403 ));
-DATA(insert ( 434 1082 1184 2 2359 403 ));
-DATA(insert ( 434 1082 1184 3 2360 403 ));
-DATA(insert ( 434 1082 1184 4 2361 403 ));
-DATA(insert ( 434 1082 1184 5 2362 403 ));
+DATA(insert ( 434 1082 1184 1 1 2358 403 ));
+DATA(insert ( 434 1082 1184 2 1 2359 403 ));
+DATA(insert ( 434 1082 1184 3 1 2360 403 ));
+DATA(insert ( 434 1082 1184 4 1 2361 403 ));
+DATA(insert ( 434 1082 1184 5 1 2362 403 ));
/* default operators timestamp */
-DATA(insert ( 434 1114 1114 1 2062 403 ));
-DATA(insert ( 434 1114 1114 2 2063 403 ));
-DATA(insert ( 434 1114 1114 3 2060 403 ));
-DATA(insert ( 434 1114 1114 4 2065 403 ));
-DATA(insert ( 434 1114 1114 5 2064 403 ));
+DATA(insert ( 434 1114 1114 1 1 2062 403 ));
+DATA(insert ( 434 1114 1114 2 1 2063 403 ));
+DATA(insert ( 434 1114 1114 3 1 2060 403 ));
+DATA(insert ( 434 1114 1114 4 1 2065 403 ));
+DATA(insert ( 434 1114 1114 5 1 2064 403 ));
/* crosstype operators vs date */
-DATA(insert ( 434 1114 1082 1 2371 403 ));
-DATA(insert ( 434 1114 1082 2 2372 403 ));
-DATA(insert ( 434 1114 1082 3 2373 403 ));
-DATA(insert ( 434 1114 1082 4 2374 403 ));
-DATA(insert ( 434 1114 1082 5 2375 403 ));
+DATA(insert ( 434 1114 1082 1 1 2371 403 ));
+DATA(insert ( 434 1114 1082 2 1 2372 403 ));
+DATA(insert ( 434 1114 1082 3 1 2373 403 ));
+DATA(insert ( 434 1114 1082 4 1 2374 403 ));
+DATA(insert ( 434 1114 1082 5 1 2375 403 ));
/* crosstype operators vs timestamptz */
-DATA(insert ( 434 1114 1184 1 2534 403 ));
-DATA(insert ( 434 1114 1184 2 2535 403 ));
-DATA(insert ( 434 1114 1184 3 2536 403 ));
-DATA(insert ( 434 1114 1184 4 2537 403 ));
-DATA(insert ( 434 1114 1184 5 2538 403 ));
+DATA(insert ( 434 1114 1184 1 1 2534 403 ));
+DATA(insert ( 434 1114 1184 2 1 2535 403 ));
+DATA(insert ( 434 1114 1184 3 1 2536 403 ));
+DATA(insert ( 434 1114 1184 4 1 2537 403 ));
+DATA(insert ( 434 1114 1184 5 1 2538 403 ));
/* default operators timestamptz */
-DATA(insert ( 434 1184 1184 1 1322 403 ));
-DATA(insert ( 434 1184 1184 2 1323 403 ));
-DATA(insert ( 434 1184 1184 3 1320 403 ));
-DATA(insert ( 434 1184 1184 4 1325 403 ));
-DATA(insert ( 434 1184 1184 5 1324 403 ));
+DATA(insert ( 434 1184 1184 1 1 1322 403 ));
+DATA(insert ( 434 1184 1184 2 1 1323 403 ));
+DATA(insert ( 434 1184 1184 3 1 1320 403 ));
+DATA(insert ( 434 1184 1184 4 1 1325 403 ));
+DATA(insert ( 434 1184 1184 5 1 1324 403 ));
/* crosstype operators vs date */
-DATA(insert ( 434 1184 1082 1 2384 403 ));
-DATA(insert ( 434 1184 1082 2 2385 403 ));
-DATA(insert ( 434 1184 1082 3 2386 403 ));
-DATA(insert ( 434 1184 1082 4 2387 403 ));
-DATA(insert ( 434 1184 1082 5 2388 403 ));
+DATA(insert ( 434 1184 1082 1 1 2384 403 ));
+DATA(insert ( 434 1184 1082 2 1 2385 403 ));
+DATA(insert ( 434 1184 1082 3 1 2386 403 ));
+DATA(insert ( 434 1184 1082 4 1 2387 403 ));
+DATA(insert ( 434 1184 1082 5 1 2388 403 ));
/* crosstype operators vs timestamp */
-DATA(insert ( 434 1184 1114 1 2540 403 ));
-DATA(insert ( 434 1184 1114 2 2541 403 ));
-DATA(insert ( 434 1184 1114 3 2542 403 ));
-DATA(insert ( 434 1184 1114 4 2543 403 ));
-DATA(insert ( 434 1184 1114 5 2544 403 ));
+DATA(insert ( 434 1184 1114 1 1 2540 403 ));
+DATA(insert ( 434 1184 1114 2 1 2541 403 ));
+DATA(insert ( 434 1184 1114 3 1 2542 403 ));
+DATA(insert ( 434 1184 1114 4 1 2543 403 ));
+DATA(insert ( 434 1184 1114 5 1 2544 403 ));
/*
* btree time_ops
*/
-DATA(insert ( 1996 1083 1083 1 1110 403 ));
-DATA(insert ( 1996 1083 1083 2 1111 403 ));
-DATA(insert ( 1996 1083 1083 3 1108 403 ));
-DATA(insert ( 1996 1083 1083 4 1113 403 ));
-DATA(insert ( 1996 1083 1083 5 1112 403 ));
+DATA(insert ( 1996 1083 1083 1 1 1110 403 ));
+DATA(insert ( 1996 1083 1083 2 1 1111 403 ));
+DATA(insert ( 1996 1083 1083 3 1 1108 403 ));
+DATA(insert ( 1996 1083 1083 4 1 1113 403 ));
+DATA(insert ( 1996 1083 1083 5 1 1112 403 ));
/*
* btree timetz_ops
*/
-DATA(insert ( 2000 1266 1266 1 1552 403 ));
-DATA(insert ( 2000 1266 1266 2 1553 403 ));
-DATA(insert ( 2000 1266 1266 3 1550 403 ));
-DATA(insert ( 2000 1266 1266 4 1555 403 ));
-DATA(insert ( 2000 1266 1266 5 1554 403 ));
+DATA(insert ( 2000 1266 1266 1 1 1552 403 ));
+DATA(insert ( 2000 1266 1266 2 1 1553 403 ));
+DATA(insert ( 2000 1266 1266 3 1 1550 403 ));
+DATA(insert ( 2000 1266 1266 4 1 1555 403 ));
+DATA(insert ( 2000 1266 1266 5 1 1554 403 ));
/*
* btree interval_ops
*/
-DATA(insert ( 1982 1186 1186 1 1332 403 ));
-DATA(insert ( 1982 1186 1186 2 1333 403 ));
-DATA(insert ( 1982 1186 1186 3 1330 403 ));
-DATA(insert ( 1982 1186 1186 4 1335 403 ));
-DATA(insert ( 1982 1186 1186 5 1334 403 ));
+DATA(insert ( 1982 1186 1186 1 1 1332 403 ));
+DATA(insert ( 1982 1186 1186 2 1 1333 403 ));
+DATA(insert ( 1982 1186 1186 3 1 1330 403 ));
+DATA(insert ( 1982 1186 1186 4 1 1335 403 ));
+DATA(insert ( 1982 1186 1186 5 1 1334 403 ));
/*
* btree macaddr
*/
-DATA(insert ( 1984 829 829 1 1222 403 ));
-DATA(insert ( 1984 829 829 2 1223 403 ));
-DATA(insert ( 1984 829 829 3 1220 403 ));
-DATA(insert ( 1984 829 829 4 1225 403 ));
-DATA(insert ( 1984 829 829 5 1224 403 ));
+DATA(insert ( 1984 829 829 1 1 1222 403 ));
+DATA(insert ( 1984 829 829 2 1 1223 403 ));
+DATA(insert ( 1984 829 829 3 1 1220 403 ));
+DATA(insert ( 1984 829 829 4 1 1225 403 ));
+DATA(insert ( 1984 829 829 5 1 1224 403 ));
/*
* btree network
*/
-DATA(insert ( 1974 869 869 1 1203 403 ));
-DATA(insert ( 1974 869 869 2 1204 403 ));
-DATA(insert ( 1974 869 869 3 1201 403 ));
-DATA(insert ( 1974 869 869 4 1206 403 ));
-DATA(insert ( 1974 869 869 5 1205 403 ));
+DATA(insert ( 1974 869 869 1 1 1203 403 ));
+DATA(insert ( 1974 869 869 2 1 1204 403 ));
+DATA(insert ( 1974 869 869 3 1 1201 403 ));
+DATA(insert ( 1974 869 869 4 1 1206 403 ));
+DATA(insert ( 1974 869 869 5 1 1205 403 ));
/*
* btree numeric
*/
-DATA(insert ( 1988 1700 1700 1 1754 403 ));
-DATA(insert ( 1988 1700 1700 2 1755 403 ));
-DATA(insert ( 1988 1700 1700 3 1752 403 ));
-DATA(insert ( 1988 1700 1700 4 1757 403 ));
-DATA(insert ( 1988 1700 1700 5 1756 403 ));
+DATA(insert ( 1988 1700 1700 1 1 1754 403 ));
+DATA(insert ( 1988 1700 1700 2 1 1755 403 ));
+DATA(insert ( 1988 1700 1700 3 1 1752 403 ));
+DATA(insert ( 1988 1700 1700 4 1 1757 403 ));
+DATA(insert ( 1988 1700 1700 5 1 1756 403 ));
/*
* btree bool
*/
-DATA(insert ( 424 16 16 1 58 403 ));
-DATA(insert ( 424 16 16 2 1694 403 ));
-DATA(insert ( 424 16 16 3 91 403 ));
-DATA(insert ( 424 16 16 4 1695 403 ));
-DATA(insert ( 424 16 16 5 59 403 ));
+DATA(insert ( 424 16 16 1 1 58 403 ));
+DATA(insert ( 424 16 16 2 1 1694 403 ));
+DATA(insert ( 424 16 16 3 1 91 403 ));
+DATA(insert ( 424 16 16 4 1 1695 403 ));
+DATA(insert ( 424 16 16 5 1 59 403 ));
/*
* btree bit
*/
-DATA(insert ( 423 1560 1560 1 1786 403 ));
-DATA(insert ( 423 1560 1560 2 1788 403 ));
-DATA(insert ( 423 1560 1560 3 1784 403 ));
-DATA(insert ( 423 1560 1560 4 1789 403 ));
-DATA(insert ( 423 1560 1560 5 1787 403 ));
+DATA(insert ( 423 1560 1560 1 1 1786 403 ));
+DATA(insert ( 423 1560 1560 2 1 1788 403 ));
+DATA(insert ( 423 1560 1560 3 1 1784 403 ));
+DATA(insert ( 423 1560 1560 4 1 1789 403 ));
+DATA(insert ( 423 1560 1560 5 1 1787 403 ));
/*
* btree varbit
*/
-DATA(insert ( 2002 1562 1562 1 1806 403 ));
-DATA(insert ( 2002 1562 1562 2 1808 403 ));
-DATA(insert ( 2002 1562 1562 3 1804 403 ));
-DATA(insert ( 2002 1562 1562 4 1809 403 ));
-DATA(insert ( 2002 1562 1562 5 1807 403 ));
+DATA(insert ( 2002 1562 1562 1 1 1806 403 ));
+DATA(insert ( 2002 1562 1562 2 1 1808 403 ));
+DATA(insert ( 2002 1562 1562 3 1 1804 403 ));
+DATA(insert ( 2002 1562 1562 4 1 1809 403 ));
+DATA(insert ( 2002 1562 1562 5 1 1807 403 ));
/*
* btree text pattern
*/
-DATA(insert ( 2095 25 25 1 2314 403 ));
-DATA(insert ( 2095 25 25 2 2315 403 ));
-DATA(insert ( 2095 25 25 3 98 403 ));
-DATA(insert ( 2095 25 25 4 2317 403 ));
-DATA(insert ( 2095 25 25 5 2318 403 ));
+DATA(insert ( 2095 25 25 1 1 2314 403 ));
+DATA(insert ( 2095 25 25 2 1 2315 403 ));
+DATA(insert ( 2095 25 25 3 1 98 403 ));
+DATA(insert ( 2095 25 25 4 1 2317 403 ));
+DATA(insert ( 2095 25 25 5 1 2318 403 ));
/*
* btree bpchar pattern
*/
-DATA(insert ( 2097 1042 1042 1 2326 403 ));
-DATA(insert ( 2097 1042 1042 2 2327 403 ));
-DATA(insert ( 2097 1042 1042 3 1054 403 ));
-DATA(insert ( 2097 1042 1042 4 2329 403 ));
-DATA(insert ( 2097 1042 1042 5 2330 403 ));
+DATA(insert ( 2097 1042 1042 1 1 2326 403 ));
+DATA(insert ( 2097 1042 1042 2 1 2327 403 ));
+DATA(insert ( 2097 1042 1042 3 1 1054 403 ));
+DATA(insert ( 2097 1042 1042 4 1 2329 403 ));
+DATA(insert ( 2097 1042 1042 5 1 2330 403 ));
/*
* btree money_ops
*/
-DATA(insert ( 2099 790 790 1 902 403 ));
-DATA(insert ( 2099 790 790 2 904 403 ));
-DATA(insert ( 2099 790 790 3 900 403 ));
-DATA(insert ( 2099 790 790 4 905 403 ));
-DATA(insert ( 2099 790 790 5 903 403 ));
+DATA(insert ( 2099 790 790 1 1 902 403 ));
+DATA(insert ( 2099 790 790 2 1 904 403 ));
+DATA(insert ( 2099 790 790 3 1 900 403 ));
+DATA(insert ( 2099 790 790 4 1 905 403 ));
+DATA(insert ( 2099 790 790 5 1 903 403 ));
/*
* btree reltime_ops
*/
-DATA(insert ( 2233 703 703 1 568 403 ));
-DATA(insert ( 2233 703 703 2 570 403 ));
-DATA(insert ( 2233 703 703 3 566 403 ));
-DATA(insert ( 2233 703 703 4 571 403 ));
-DATA(insert ( 2233 703 703 5 569 403 ));
+DATA(insert ( 2233 703 703 1 1 568 403 ));
+DATA(insert ( 2233 703 703 2 1 570 403 ));
+DATA(insert ( 2233 703 703 3 1 566 403 ));
+DATA(insert ( 2233 703 703 4 1 571 403 ));
+DATA(insert ( 2233 703 703 5 1 569 403 ));
/*
* btree tinterval_ops
*/
-DATA(insert ( 2234 704 704 1 813 403 ));
-DATA(insert ( 2234 704 704 2 815 403 ));
-DATA(insert ( 2234 704 704 3 811 403 ));
-DATA(insert ( 2234 704 704 4 816 403 ));
-DATA(insert ( 2234 704 704 5 814 403 ));
+DATA(insert ( 2234 704 704 1 1 813 403 ));
+DATA(insert ( 2234 704 704 2 1 815 403 ));
+DATA(insert ( 2234 704 704 3 1 811 403 ));
+DATA(insert ( 2234 704 704 4 1 816 403 ));
+DATA(insert ( 2234 704 704 5 1 814 403 ));
/*
* btree array_ops
*/
-DATA(insert ( 397 2277 2277 1 1072 403 ));
-DATA(insert ( 397 2277 2277 2 1074 403 ));
-DATA(insert ( 397 2277 2277 3 1070 403 ));
-DATA(insert ( 397 2277 2277 4 1075 403 ));
-DATA(insert ( 397 2277 2277 5 1073 403 ));
+DATA(insert ( 397 2277 2277 1 1 1072 403 ));
+DATA(insert ( 397 2277 2277 2 1 1074 403 ));
+DATA(insert ( 397 2277 2277 3 1 1070 403 ));
+DATA(insert ( 397 2277 2277 4 1 1075 403 ));
+DATA(insert ( 397 2277 2277 5 1 1073 403 ));
/*
* btree record_ops
*/
-DATA(insert ( 2994 2249 2249 1 2990 403 ));
-DATA(insert ( 2994 2249 2249 2 2992 403 ));
-DATA(insert ( 2994 2249 2249 3 2988 403 ));
-DATA(insert ( 2994 2249 2249 4 2993 403 ));
-DATA(insert ( 2994 2249 2249 5 2991 403 ));
+DATA(insert ( 2994 2249 2249 1 1 2990 403 ));
+DATA(insert ( 2994 2249 2249 2 1 2992 403 ));
+DATA(insert ( 2994 2249 2249 3 1 2988 403 ));
+DATA(insert ( 2994 2249 2249 4 1 2993 403 ));
+DATA(insert ( 2994 2249 2249 5 1 2991 403 ));
/*
* btree uuid_ops
*/
-DATA(insert ( 2968 2950 2950 1 2974 403 ));
-DATA(insert ( 2968 2950 2950 2 2976 403 ));
-DATA(insert ( 2968 2950 2950 3 2972 403 ));
-DATA(insert ( 2968 2950 2950 4 2977 403 ));
-DATA(insert ( 2968 2950 2950 5 2975 403 ));
+DATA(insert ( 2968 2950 2950 1 1 2974 403 ));
+DATA(insert ( 2968 2950 2950 2 1 2976 403 ));
+DATA(insert ( 2968 2950 2950 3 1 2972 403 ));
+DATA(insert ( 2968 2950 2950 4 1 2977 403 ));
+DATA(insert ( 2968 2950 2950 5 1 2975 403 ));
/*
* hash index _ops
*/
/* bpchar_ops */
-DATA(insert ( 427 1042 1042 1 1054 405 ));
+DATA(insert ( 427 1042 1042 1 1 1054 405 ));
/* char_ops */
-DATA(insert ( 431 18 18 1 92 405 ));
+DATA(insert ( 431 18 18 1 1 92 405 ));
/* date_ops */
-DATA(insert ( 435 1082 1082 1 1093 405 ));
+DATA(insert ( 435 1082 1082 1 1 1093 405 ));
/* float_ops */
-DATA(insert ( 1971 700 700 1 620 405 ));
-DATA(insert ( 1971 701 701 1 670 405 ));
-DATA(insert ( 1971 700 701 1 1120 405 ));
-DATA(insert ( 1971 701 700 1 1130 405 ));
+DATA(insert ( 1971 700 700 1 1 620 405 ));
+DATA(insert ( 1971 701 701 1 1 670 405 ));
+DATA(insert ( 1971 700 701 1 1 1120 405 ));
+DATA(insert ( 1971 701 700 1 1 1130 405 ));
/* network_ops */
-DATA(insert ( 1975 869 869 1 1201 405 ));
+DATA(insert ( 1975 869 869 1 1 1201 405 ));
/* integer_ops */
-DATA(insert ( 1977 21 21 1 94 405 ));
-DATA(insert ( 1977 23 23 1 96 405 ));
-DATA(insert ( 1977 20 20 1 410 405 ));
-DATA(insert ( 1977 21 23 1 532 405 ));
-DATA(insert ( 1977 21 20 1 1862 405 ));
-DATA(insert ( 1977 23 21 1 533 405 ));
-DATA(insert ( 1977 23 20 1 15 405 ));
-DATA(insert ( 1977 20 21 1 1868 405 ));
-DATA(insert ( 1977 20 23 1 416 405 ));
+DATA(insert ( 1977 21 21 1 1 94 405 ));
+DATA(insert ( 1977 23 23 1 1 96 405 ));
+DATA(insert ( 1977 20 20 1 1 410 405 ));
+DATA(insert ( 1977 21 23 1 1 532 405 ));
+DATA(insert ( 1977 21 20 1 1 1862 405 ));
+DATA(insert ( 1977 23 21 1 1 533 405 ));
+DATA(insert ( 1977 23 20 1 1 15 405 ));
+DATA(insert ( 1977 20 21 1 1 1868 405 ));
+DATA(insert ( 1977 20 23 1 1 416 405 ));
/* interval_ops */
-DATA(insert ( 1983 1186 1186 1 1330 405 ));
+DATA(insert ( 1983 1186 1186 1 1 1330 405 ));
/* macaddr_ops */
-DATA(insert ( 1985 829 829 1 1220 405 ));
+DATA(insert ( 1985 829 829 1 1 1220 405 ));
/* name_ops */
-DATA(insert ( 1987 19 19 1 93 405 ));
+DATA(insert ( 1987 19 19 1 1 93 405 ));
/* oid_ops */
-DATA(insert ( 1990 26 26 1 607 405 ));
+DATA(insert ( 1990 26 26 1 1 607 405 ));
/* oidvector_ops */
-DATA(insert ( 1992 30 30 1 649 405 ));
+DATA(insert ( 1992 30 30 1 1 649 405 ));
/* text_ops */
-DATA(insert ( 1995 25 25 1 98 405 ));
+DATA(insert ( 1995 25 25 1 1 98 405 ));
/* time_ops */
-DATA(insert ( 1997 1083 1083 1 1108 405 ));
+DATA(insert ( 1997 1083 1083 1 1 1108 405 ));
/* timestamptz_ops */
-DATA(insert ( 1999 1184 1184 1 1320 405 ));
+DATA(insert ( 1999 1184 1184 1 1 1320 405 ));
/* timetz_ops */
-DATA(insert ( 2001 1266 1266 1 1550 405 ));
+DATA(insert ( 2001 1266 1266 1 1 1550 405 ));
/* timestamp_ops */
-DATA(insert ( 2040 1114 1114 1 2060 405 ));
+DATA(insert ( 2040 1114 1114 1 1 2060 405 ));
/* bool_ops */
-DATA(insert ( 2222 16 16 1 91 405 ));
+DATA(insert ( 2222 16 16 1 1 91 405 ));
/* bytea_ops */
-DATA(insert ( 2223 17 17 1 1955 405 ));
+DATA(insert ( 2223 17 17 1 1 1955 405 ));
/* int2vector_ops */
-DATA(insert ( 2224 22 22 1 386 405 ));
+DATA(insert ( 2224 22 22 1 1 386 405 ));
/* xid_ops */
-DATA(insert ( 2225 28 28 1 352 405 ));
+DATA(insert ( 2225 28 28 1 1 352 405 ));
/* cid_ops */
-DATA(insert ( 2226 29 29 1 385 405 ));
+DATA(insert ( 2226 29 29 1 1 385 405 ));
/* abstime_ops */
-DATA(insert ( 2227 702 702 1 560 405 ));
+DATA(insert ( 2227 702 702 1 1 560 405 ));
/* reltime_ops */
-DATA(insert ( 2228 703 703 1 566 405 ));
+DATA(insert ( 2228 703 703 1 1 566 405 ));
/* text_pattern_ops */
-DATA(insert ( 2229 25 25 1 98 405 ));
+DATA(insert ( 2229 25 25 1 1 98 405 ));
/* bpchar_pattern_ops */
-DATA(insert ( 2231 1042 1042 1 1054 405 ));
+DATA(insert ( 2231 1042 1042 1 1 1054 405 ));
/* aclitem_ops */
-DATA(insert ( 2235 1033 1033 1 974 405 ));
+DATA(insert ( 2235 1033 1033 1 1 974 405 ));
/* uuid_ops */
-DATA(insert ( 2969 2950 2950 1 2972 405 ));
+DATA(insert ( 2969 2950 2950 1 1 2972 405 ));
/* numeric_ops */
-DATA(insert ( 1998 1700 1700 1 1752 405 ));
+DATA(insert ( 1998 1700 1700 1 1 1752 405 ));
/*
* gist box_ops
*/
-DATA(insert ( 2593 603 603 1 493 783 ));
-DATA(insert ( 2593 603 603 2 494 783 ));
-DATA(insert ( 2593 603 603 3 500 783 ));
-DATA(insert ( 2593 603 603 4 495 783 ));
-DATA(insert ( 2593 603 603 5 496 783 ));
-DATA(insert ( 2593 603 603 6 499 783 ));
-DATA(insert ( 2593 603 603 7 498 783 ));
-DATA(insert ( 2593 603 603 8 497 783 ));
-DATA(insert ( 2593 603 603 9 2571 783 ));
-DATA(insert ( 2593 603 603 10 2570 783 ));
-DATA(insert ( 2593 603 603 11 2573 783 ));
-DATA(insert ( 2593 603 603 12 2572 783 ));
-DATA(insert ( 2593 603 603 13 2863 783 ));
-DATA(insert ( 2593 603 603 14 2862 783 ));
+DATA(insert ( 2593 603 603 1 1 493 783 ));
+DATA(insert ( 2593 603 603 2 1 494 783 ));
+DATA(insert ( 2593 603 603 3 1 500 783 ));
+DATA(insert ( 2593 603 603 4 1 495 783 ));
+DATA(insert ( 2593 603 603 5 1 496 783 ));
+DATA(insert ( 2593 603 603 6 1 499 783 ));
+DATA(insert ( 2593 603 603 7 1 498 783 ));
+DATA(insert ( 2593 603 603 8 1 497 783 ));
+DATA(insert ( 2593 603 603 9 1 2571 783 ));
+DATA(insert ( 2593 603 603 10 1 2570 783 ));
+DATA(insert ( 2593 603 603 11 1 2573 783 ));
+DATA(insert ( 2593 603 603 12 1 2572 783 ));
+DATA(insert ( 2593 603 603 13 1 2863 783 ));
+DATA(insert ( 2593 603 603 14 1 2862 783 ));
/*
* gist point_ops
*/
-DATA(insert ( 1029 600 600 11 506 783 ));
-DATA(insert ( 1029 600 600 1 507 783 ));
-DATA(insert ( 1029 600 600 5 508 783 ));
-DATA(insert ( 1029 600 600 10 509 783 ));
-DATA(insert ( 1029 600 600 6 510 783 ));
-DATA(insert ( 1029 603 600 27 433 783 ));
-DATA(insert ( 1029 600 603 28 511 783 ));
-DATA(insert ( 1029 604 600 47 757 783 ));
-DATA(insert ( 1029 600 604 48 756 783 ));
-DATA(insert ( 1029 718 600 67 759 783 ));
-DATA(insert ( 1029 600 718 68 758 783 ));
+DATA(insert ( 1029 600 600 11 1 506 783 ));
+DATA(insert ( 1029 600 600 1 1 507 783 ));
+DATA(insert ( 1029 600 600 5 1 508 783 ));
+DATA(insert ( 1029 600 600 10 1 509 783 ));
+DATA(insert ( 1029 600 600 6 1 510 783 ));
+DATA(insert ( 1029 603 600 27 1 433 783 ));
+DATA(insert ( 1029 600 603 28 1 511 783 ));
+DATA(insert ( 1029 604 600 47 1 757 783 ));
+DATA(insert ( 1029 600 604 48 1 756 783 ));
+DATA(insert ( 1029 718 600 67 1 759 783 ));
+DATA(insert ( 1029 600 718 68 1 758 783 ));
/*
* gist poly_ops (supports polygons)
*/
-DATA(insert ( 2594 604 604 1 485 783 ));
-DATA(insert ( 2594 604 604 2 486 783 ));
-DATA(insert ( 2594 604 604 3 492 783 ));
-DATA(insert ( 2594 604 604 4 487 783 ));
-DATA(insert ( 2594 604 604 5 488 783 ));
-DATA(insert ( 2594 604 604 6 491 783 ));
-DATA(insert ( 2594 604 604 7 490 783 ));
-DATA(insert ( 2594 604 604 8 489 783 ));
-DATA(insert ( 2594 604 604 9 2575 783 ));
-DATA(insert ( 2594 604 604 10 2574 783 ));
-DATA(insert ( 2594 604 604 11 2577 783 ));
-DATA(insert ( 2594 604 604 12 2576 783 ));
-DATA(insert ( 2594 604 604 13 2861 783 ));
-DATA(insert ( 2594 604 604 14 2860 783 ));
+DATA(insert ( 2594 604 604 1 1 485 783 ));
+DATA(insert ( 2594 604 604 2 1 486 783 ));
+DATA(insert ( 2594 604 604 3 1 492 783 ));
+DATA(insert ( 2594 604 604 4 1 487 783 ));
+DATA(insert ( 2594 604 604 5 1 488 783 ));
+DATA(insert ( 2594 604 604 6 1 491 783 ));
+DATA(insert ( 2594 604 604 7 1 490 783 ));
+DATA(insert ( 2594 604 604 8 1 489 783 ));
+DATA(insert ( 2594 604 604 9 1 2575 783 ));
+DATA(insert ( 2594 604 604 10 1 2574 783 ));
+DATA(insert ( 2594 604 604 11 1 2577 783 ));
+DATA(insert ( 2594 604 604 12 1 2576 783 ));
+DATA(insert ( 2594 604 604 13 1 2861 783 ));
+DATA(insert ( 2594 604 604 14 1 2860 783 ));
/*
* gist circle_ops
*/
-DATA(insert ( 2595 718 718 1 1506 783 ));
-DATA(insert ( 2595 718 718 2 1507 783 ));
-DATA(insert ( 2595 718 718 3 1513 783 ));
-DATA(insert ( 2595 718 718 4 1508 783 ));
-DATA(insert ( 2595 718 718 5 1509 783 ));
-DATA(insert ( 2595 718 718 6 1512 783 ));
-DATA(insert ( 2595 718 718 7 1511 783 ));
-DATA(insert ( 2595 718 718 8 1510 783 ));
-DATA(insert ( 2595 718 718 9 2589 783 ));
-DATA(insert ( 2595 718 718 10 1515 783 ));
-DATA(insert ( 2595 718 718 11 1514 783 ));
-DATA(insert ( 2595 718 718 12 2590 783 ));
-DATA(insert ( 2595 718 718 13 2865 783 ));
-DATA(insert ( 2595 718 718 14 2864 783 ));
+DATA(insert ( 2595 718 718 1 1 1506 783 ));
+DATA(insert ( 2595 718 718 2 1 1507 783 ));
+DATA(insert ( 2595 718 718 3 1 1513 783 ));
+DATA(insert ( 2595 718 718 4 1 1508 783 ));
+DATA(insert ( 2595 718 718 5 1 1509 783 ));
+DATA(insert ( 2595 718 718 6 1 1512 783 ));
+DATA(insert ( 2595 718 718 7 1 1511 783 ));
+DATA(insert ( 2595 718 718 8 1 1510 783 ));
+DATA(insert ( 2595 718 718 9 1 2589 783 ));
+DATA(insert ( 2595 718 718 10 1 1515 783 ));
+DATA(insert ( 2595 718 718 11 1 1514 783 ));
+DATA(insert ( 2595 718 718 12 1 2590 783 ));
+DATA(insert ( 2595 718 718 13 1 2865 783 ));
+DATA(insert ( 2595 718 718 14 1 2864 783 ));
/*
* gin array_ops (these anyarray operators are used with all the opclasses
* of the family)
*/
-DATA(insert ( 2745 2277 2277 1 2750 2742 ));
-DATA(insert ( 2745 2277 2277 2 2751 2742 ));
-DATA(insert ( 2745 2277 2277 3 2752 2742 ));
-DATA(insert ( 2745 2277 2277 4 1070 2742 ));
+DATA(insert ( 2745 2277 2277 1 1 2750 2742 ));
+DATA(insert ( 2745 2277 2277 2 1 2751 2742 ));
+DATA(insert ( 2745 2277 2277 3 1 2752 2742 ));
+DATA(insert ( 2745 2277 2277 4 1 1070 2742 ));
/*
* btree enum_ops
*/
-DATA(insert ( 3522 3500 3500 1 3518 403 ));
-DATA(insert ( 3522 3500 3500 2 3520 403 ));
-DATA(insert ( 3522 3500 3500 3 3516 403 ));
-DATA(insert ( 3522 3500 3500 4 3521 403 ));
-DATA(insert ( 3522 3500 3500 5 3519 403 ));
+DATA(insert ( 3522 3500 3500 1 1 3518 403 ));
+DATA(insert ( 3522 3500 3500 2 1 3520 403 ));
+DATA(insert ( 3522 3500 3500 3 1 3516 403 ));
+DATA(insert ( 3522 3500 3500 4 1 3521 403 ));
+DATA(insert ( 3522 3500 3500 5 1 3519 403 ));
/*
* hash enum_ops
*/
-DATA(insert ( 3523 3500 3500 1 3516 405 ));
+DATA(insert ( 3523 3500 3500 1 1 3516 405 ));
/*
* btree tsvector_ops
*/
-DATA(insert ( 3626 3614 3614 1 3627 403 ));
-DATA(insert ( 3626 3614 3614 2 3628 403 ));
-DATA(insert ( 3626 3614 3614 3 3629 403 ));
-DATA(insert ( 3626 3614 3614 4 3631 403 ));
-DATA(insert ( 3626 3614 3614 5 3632 403 ));
+DATA(insert ( 3626 3614 3614 1 1 3627 403 ));
+DATA(insert ( 3626 3614 3614 2 1 3628 403 ));
+DATA(insert ( 3626 3614 3614 3 1 3629 403 ));
+DATA(insert ( 3626 3614 3614 4 1 3631 403 ));
+DATA(insert ( 3626 3614 3614 5 1 3632 403 ));
/*
* GiST tsvector_ops
*/
-DATA(insert ( 3655 3614 3615 1 3636 783 ));
+DATA(insert ( 3655 3614 3615 1 1 3636 783 ));
/*
* GIN tsvector_ops
*/
-DATA(insert ( 3659 3614 3615 1 3636 2742 ));
-DATA(insert ( 3659 3614 3615 2 3660 2742 ));
+DATA(insert ( 3659 3614 3615 1 1 3636 2742 ));
+DATA(insert ( 3659 3614 3615 2 1 3660 2742 ));
/*
* btree tsquery_ops
*/
-DATA(insert ( 3683 3615 3615 1 3674 403 ));
-DATA(insert ( 3683 3615 3615 2 3675 403 ));
-DATA(insert ( 3683 3615 3615 3 3676 403 ));
-DATA(insert ( 3683 3615 3615 4 3678 403 ));
-DATA(insert ( 3683 3615 3615 5 3679 403 ));
+DATA(insert ( 3683 3615 3615 1 1 3674 403 ));
+DATA(insert ( 3683 3615 3615 2 1 3675 403 ));
+DATA(insert ( 3683 3615 3615 3 1 3676 403 ));
+DATA(insert ( 3683 3615 3615 4 1 3678 403 ));
+DATA(insert ( 3683 3615 3615 5 1 3679 403 ));
/*
* GiST tsquery_ops
*/
-DATA(insert ( 3702 3615 3615 7 3693 783 ));
-DATA(insert ( 3702 3615 3615 8 3694 783 ));
+DATA(insert ( 3702 3615 3615 7 1 3693 783 ));
+DATA(insert ( 3702 3615 3615 8 1 3694 783 ));
#endif /* PG_AMOP_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 3cac54b..5acc1b7 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1769,6 +1769,7 @@ typedef struct CreateOpClassItem
List *args; /* argument types */
int number; /* strategy num or support proc num */
List *class_args; /* only used for functions */
+ int purpose; /* purpose */
/* fields used for a storagetype item: */
TypeName *storedtype; /* datatype stored in index */
} CreateOpClassItem;
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 02c0219..92e5b65 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -30,14 +30,14 @@ typedef enum IOFuncSelector
typedef int32 (*get_attavgwidth_hook_type) (Oid relid, AttrNumber attnum);
extern PGDLLIMPORT get_attavgwidth_hook_type get_attavgwidth_hook;
-extern bool op_in_opfamily(Oid opno, Oid opfamily);
-extern int get_op_opfamily_strategy(Oid opno, Oid opfamily);
-extern void get_op_opfamily_properties(Oid opno, Oid opfamily,
+extern bool op_in_opfamily(Oid opno, Oid opfamily, int purpose);
+extern int get_op_opfamily_strategy(Oid opno, Oid opfamily, int purpose);
+extern void get_op_opfamily_properties(Oid opno, Oid opfamily, int purpose,
int *strategy,
Oid *lefttype,
Oid *righttype);
extern Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
- int16 strategy);
+ int16 strategy, int16 purpose);
extern bool get_ordering_op_properties(Oid opno,
Oid *opfamily, Oid *opcintype, int16 *strategy);
extern bool get_compare_function_for_ordering_op(Oid opno,
Robert, it is great you are taking this on. This is really a well-known
area of the code for you, but not so much for Teodor and Oleg, so I am
sure they appreciate your assistance.
---------------------------------------------------------------------------
Robert Haas wrote:
On Sat, Oct 16, 2010 at 9:54 PM, Robert Haas <robertmhaas@gmail.com> wrote:
Thinking about it that way, perhaps we could add an integer column
amop_whats_it_good_for that gets used as a bit field. ?That wouldn't
require changing the index structure, although it might break some
other things.I gave this a shot (though I called it amoppurpose rather than
amop_whats_it_good_for) and I think it's a reasonable way to proceed.
Proof-of-concept patch attached. ?This just adds the column (using the
existing padding space), defines AMOP_SEARCH and AMOP_ORDER, and makes
just about everything ignore anything not marked AMOP_SEARCH,
attached. ?This would obviously need some more hacking to pay
attention to AMOP_ORDER where relevant, etc. and to create some actual
syntax around it. ?Currently CREATE OPERATOR CLASS / ALTER OPERATOR
FAMILY have this bit:OPERATOR strategy_number ( op_type [ , op_type ] )
knngist-0.9 implements this:
[ORDER] OPERATOR strategy_number ( op_type [, op_type ] )
...but with the design proposed above that's not quite what we'd want,
because amoppurpose is a bit field, so you could have one or both of
the two possible purposes. ?Perhaps:OPERATOR strategy_number ( op_type [ , op_type ] ) [ FOR { SEARCH |
ORDER } [, ...] ]With the default being FOR SEARCH.
Slightly-more-fleshed out proof of concept patch attached, with actual
syntax, documentation, and pg_dump support added. This might be
thought of as a subset of the builtin_knngist_core patch, without the
parts that make it actually do something useful (which is mostly
match_pathkey_to_index - which I'm still rather hoping to abstract in
some way via the access method interface, though I'm currently unsure
what the best way to do that is).I notice that builtin_knngist_core checks whether the return type of
an ordering operator has a built-in btree opclass. I'm not sure
whether we should bother checking that, because even if it's true I
don't think there's anything preventing it from becoming false later.
I think it's probably sufficient to just check this condition at plan
time and silently skip trying to build knn-type index paths if it's
not met.--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
[ Attachment, skipping... ]
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ It's impossible for everything to be true. +
Slightly-more-fleshed out proof of concept patch attached, with actual
syntax, documentation, and pg_dump support added. This might be
thought of as a subset of the builtin_knngist_core patch, without the
parts that make it actually do something useful (which is mostly
match_pathkey_to_index - which I'm still rather hoping to abstract in
some way via the access method interface, though I'm currently unsure
what the best way to do that is).
I don't see in your patch how to propagate knowledge of kind of operation
(AMOP_SEARCH or AMOP_ORDER) to GiST and consistent method. For both of them they
aren't distinguishable. That's not acceptably for both, because GiST needs to
choose right traversal algorithm, consistentFn needs role to decide return
infinity or false (-1) value.
My variants informs GiST by SK_ORDER flags and consistentFn looks at strategy
number (strategy numbers are different for different purposes).
I notice that builtin_knngist_core checks whether the return type of
an ordering operator has a built-in btree opclass. I'm not sure
Actually, GiST doesn't use that knowledge, check is done only to be sure that
operation returns orderable data type.
whether we should bother checking that, because even if it's true I
don't think there's anything preventing it from becoming false later.
I think it's probably sufficient to just check this condition at plan
time and silently skip trying to build knn-type index paths if it's
not met.
It's already do it: you can not ORDER BY over non-orderable data type. That
check just make diagnostic earlier.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
2010/11/12 Teodor Sigaev <teodor@sigaev.ru>:
Slightly-more-fleshed out proof of concept patch attached, with actual
syntax, documentation, and pg_dump support added. This might be
thought of as a subset of the builtin_knngist_core patch, without the
parts that make it actually do something useful (which is mostly
match_pathkey_to_index - which I'm still rather hoping to abstract in
some way via the access method interface, though I'm currently unsure
what the best way to do that is).I don't see in your patch how to propagate knowledge of kind of operation
(AMOP_SEARCH or AMOP_ORDER) to GiST and consistent method. For both of them
they aren't distinguishable. That's not acceptably for both, because GiST
needs to choose right traversal algorithm, consistentFn needs role to decide
return infinity or false (-1) value.
My version of the patch is suffering from a bad case of not being
done. It sort of started out as a proof-of-concept to show what the
syntax might look like and seems to be gradually growing into
something more real. I'm not sure what we'll end up with.
My variants informs GiST by SK_ORDER flags and consistentFn looks at
strategy number (strategy numbers are different for different purposes).
Yeah. At ten thousand feet, I think the open design question here is
to what extent it's OK to rely on the fact that the ORDER BY clauses
we wish to optimize happen to look a lot like the WHERE clauses we
already know how to optimize: namely, they're both binary opclauses of
the form <indexed-column> <op> <constant>. Your patch manages to
reuse a LOT of existing machinery by shoving ordering expressions
through the same code paths that quals take. Code reuse is generally
a good thing, but here's we're forming RestrictInfo and ScanKey
objects out of things that are neither restrictions nor keys, which
might lead to maintainability problems down the road. I'd like to get
some input from Tom on how he feels about that, and any alternatives
he sees.
It seems to me that our concept of ScanDirection is really woefully
under-expressive. For example, given:
CREATE TABLE foo (
id integer NOT NULL,
name character varying NOT NULL,
PRIMARY KEY (id)
);
We use the index for the first of these but not the second:
select * from foo order by id nulls last;
select * from foo order by id nulls first;
In an ideal world, we'd like to handle the second one by finding the
first non-NULL entry in the index, scanning away from the NULLs, and
then, when we run off the end, looping back around to spit out the
NULL entries. Or, similarly, if we have an index on (id, name), we
can handle the first two of the following with the index, but not the
second two:
select * from foo order by id, name;
select * from foo order by id desc, name desc;
select * from foo order by id, name desc;
select * from foo order by id, name nulls last;
(can't handle this last one even if name is marked NOT NULL!)
It seems like it might even be possible to handle these (albeit maybe
not real efficiently) via a sufficiently complicated scanning order,
but even if we had the code to do the scan, we have no way of telling
the index what scan direction we want: forward, backward, and no
movement don't really cut it. The idea that forward and backward mean
anything at all is really pretty btree-centric.
The trick, of course, is to come up with something better. I have a
vague notion of using something like an array or list of objects of
the form <index column, asc/desc, nulls first/last, value (null except
for knngist)>. That could easily be extended with collation or
whatever as needed. The trick is - you need to create this object and
then ask the index - hey, is this something you can support? And the
index needs to then respond by saying whether it can do that (and
maybe doing some sort of translation into what instructions should be
provided at execution time).
Trouble is, that sounds like a lot of work on code I'm not altogether
comfortable with, and I'd really like to get KNNGIST in shape for 9.1
if possible. I'm not real sure where to draw the line between, on the
one hand, not wanting to commit something that is excessively crufty
and, on the other hand, wanting to finish in finite time.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
2010/11/12 Teodor Sigaev <teodor@sigaev.ru>:
My variants informs GiST by SK_ORDER flags and consistentFn looks at
strategy number (strategy numbers are different for different purposes).
Yeah. At ten thousand feet, I think the open design question here is
to what extent it's OK to rely on the fact that the ORDER BY clauses
we wish to optimize happen to look a lot like the WHERE clauses we
already know how to optimize: namely, they're both binary opclauses of
the form <indexed-column> <op> <constant>. Your patch manages to
reuse a LOT of existing machinery by shoving ordering expressions
through the same code paths that quals take. Code reuse is generally
a good thing, but here's we're forming RestrictInfo and ScanKey
objects out of things that are neither restrictions nor keys, which
might lead to maintainability problems down the road. I'd like to get
some input from Tom on how he feels about that, and any alternatives
he sees.
I haven't spent any time on this patch yet (hope to start looking at it
next week). As for your specific question above, I don't have a big
problem with reusing ScanKey this way, but I do agree that using
RestrictInfo for this would be a crock. ISTM what we ought to have is
just the ability to match PathKeys with expressions of the form
"indexedcol op constant" to an index.
I'm undecided about the big-picture question of how much extra
generality ought to be put into the system along with this patch.
The argument not to is that with no candidate uses of additional
generality on the horizon, it's a waste of time to design something
more general, because we'll probably get it wrong anyway. I'm not
a fan of designing APIs without use-cases in mind. On the other hand,
there's an argument *for* doing something more general, which is
basically Polya's paradox: the more general problem may be easier to
solve. To support that argument, we'd need a design that is clearly
cleaner than bolting KNNGIST on according to the current patch.
AIUI we don't have that at the moment, but I still think it's worth
spending a bit more time looking for one.
It seems to me that our concept of ScanDirection is really woefully
under-expressive. For example, given:
CREATE TABLE foo (
id integer NOT NULL,
name character varying NOT NULL,
PRIMARY KEY (id)
);
We use the index for the first of these but not the second:
select * from foo order by id nulls last;
select * from foo order by id nulls first;
In an ideal world, we'd like to handle the second one by finding the
first non-NULL entry in the index, scanning away from the NULLs, and
then, when we run off the end, looping back around to spit out the
NULL entries.
This example leaves me totally cold, not least because it assumes a
specific storage implementation for nulls in an index. It is also,
I think, misunderstanding what ScanDirection is for. That's only
intended to allow executor plans to be run forward and then backed up
in the same fashion that fetching backwards from a cursor would do;
which is not a btree-specific concept, indeed not even index-specific.
If there is sufficient interest in doing what you suggest, what we'd
want to do is pass the PathKey representation to the index and let the
index AM figure out what it has to do to produce that sort order. But
that is way way down my priority list.
regards, tom lane
On Sun, Nov 21, 2010 at 5:24 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
I haven't spent any time on this patch yet (hope to start looking at it
next week). As for your specific question above, I don't have a big
problem with reusing ScanKey this way, but I do agree that using
RestrictInfo for this would be a crock. ISTM what we ought to have is
just the ability to match PathKeys with expressions of the form
"indexedcol op constant" to an index.
That doesn't seem very hard on its face. The trick is what to do with
that information once you've got it. As far as I can tell, you need
to drill some kind of hole that lets you pass "additional details
about the desired sort order" to the index AM. What I'd sort of like
to be able to do is throw the PathKeys at the index AM and say "you
want these?". Short of that, we're probably going to have to resign
ourselves to the core code basically knowing exactly what the
capabilities of KNNGIST are, making the index API pretty porous - not
that it already isn't. There's really nothing special about the
subset of the problem space KNNGIST happens to attack except that it
makes the GIS guys drool; the next problem someone wants to attack in
this area is as likely as not to look completely different.
This example leaves me totally cold, not least because it assumes a
specific storage implementation for nulls in an index. It is also,
I think, misunderstanding what ScanDirection is for. That's only
intended to allow executor plans to be run forward and then backed up
in the same fashion that fetching backwards from a cursor would do;
which is not a btree-specific concept, indeed not even index-specific.
Ah, OK.
If there is sufficient interest in doing what you suggest, what we'd
want to do is pass the PathKey representation to the index and let the
index AM figure out what it has to do to produce that sort order. But
that is way way down my priority list.
Yeah, this is basically what I'm wondering whether we can reasonably
do for KNNGIST; with hopes of later reuse. But it may be unworkable.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
That doesn't seem very hard on its face. The trick is what to do with
that information once you've got it. As far as I can tell, you need
to drill some kind of hole that lets you pass "additional details
about the desired sort order" to the index AM.
We clearly need to add additional information to IndexScan plan nodes
to tell the index AM which sort order is required. Up to now, an
indexscan has only had one possible resultant sort order (two if you
count backwards scan, but as I said I don't think generalizing that
particular feature is the way to approach this). I would imagine
that the best way to handle that is to add a PathKey list or something
equivalent to it, and add that to the arguments passed to ambeginscan.
The other issue is how the planner can figure out what the possible
orderings are when it's considering an index. You seem to be
contemplating adding a new index AM function that the planner would call
at the right point; but I'm not sure that that adds much of anything,
because the index AM can't have hard-wired behavior either. We really
have to have enough information in the system catalog entries about an
opclass to allow the possible orderings to be determined. Given that,
I think it makes more sense for the core planner to know what to do than
to put possibly duplicative code into multiple AMs.
I guess a third alternative would be to create per-opclass hook
functions for the planner to call, but I'm not thrilled with that
idea; it would still be largely duplicative code, and in a lot more
places. I think it would also bind our hands with respect to making
internal planner changes in future, because the data structures
representing pathkeys would be pretty well locked down by such a choice.
regards, tom lane
I've done some *very* preliminary review of this patch now. I think
that the way to move forward is to first commit the work surrounding
changes to pg_amop, including suitable changes to CREATE/ALTER OPERATOR
CLASS/FAMILY so that there's a way to put the new info into the table.
The system won't initially *do* anything useful with ordering-operator
entries, but this is necessary infrastructure before we can start to
do anything interesting.
After reviewing both Teodor's and Robert's patches for the issue,
I believe that Teodor has a better basic approach: if an operator
is useful for both searching and ordering, the way to handle that
is to make two pg_amop entries for it, with different strategy
numbers. This means in particular that we can continue to require
strategy numbers to be unique within an opclass, so right offhand
I see no need to widen pg_amop_fam_strat_index to five columns.
(Which means we don't need that patch to allow five-key syscaches.)
What we need instead is to add the "purpose" column to the existing
unique index on (amopopr, amopfamily). In English that means that
instead of allowing an operator to have only one entry per opfamily,
it can now have one entry per opfamily per purpose.
I do however concur with Robert that it's a bit silly to go to all this
work and not leave room in the design for additional operator "purposes"
later. So rather than using a boolean amoporder column, I think we want
an enumerated-type column "amoppurpose". Per our usual system catalog
conventions for "poor man's enums", I suggest declaring the column as
"char" with the two allowed values
AMOP_SEARCH 's'
AMOP_ORDER 'o'
Aside from leaving room for possible extension, I think that using
AMOP_SEARCH/AMOP_ORDER rather than true/false in the code will be more
readable and less error-prone.
As far as the syntax of CREATE/ALTER OPERATOR CLASS/FAMILY is concerned,
I like Robert's proposal (OPERATOR ... FOR ORDER or FOR SEARCH) better
than Teodor's, though we don't need the multiple-purposes-per-entry
aspect of it. This is mainly because it looks more easily extensible
if we ever do get around to having more purposes.
There's a lot more to be done after this, but if there are no objections
to this much, I'll go merge the relevant parts of the two patches and
commit.
regards, tom lane
I wrote:
As far as the syntax of CREATE/ALTER OPERATOR CLASS/FAMILY is concerned,
I like Robert's proposal (OPERATOR ... FOR ORDER or FOR SEARCH) better
than Teodor's, though we don't need the multiple-purposes-per-entry
aspect of it. This is mainly because it looks more easily extensible
if we ever do get around to having more purposes.
Although having said that ... I was poking around a bit more and noticed
how entirely bogus the current patch's matching of pathkeys is. It pays
no attention at all to which pk_opfamily is specified, which means it
will fail given a query like
SELECT ... ORDER BY indexable_col <-> constant USING <<<
where <<< represents some sort order that has nothing to do with the
order that GIST is expecting. The query will be considered to match the
index and then it will proceed to produce results in the wrong order.
We could perhaps kluge around that by insisting that the pathkey opclass
be the default btree opclass for the relevant datatype; but that's
fairly expensive to check for in match_pathkey_to_index, and it's
getting even further away from having a general-purpose solution.
I'm inclined to think that instead of just specifying "FOR ORDER",
the opclass definition ought to specify "FOR ORDER BY something",
where "something" could perhaps be a pre-existing btree opclass name.
Or maybe it could be a suitable sort operator, though then we'd have
to do a bit of reverse-engineering in match_pathkey_to_index, so that's
still no fun from a lookup-speed point of view. In any case what we'd
be specifying is a sort order for the datatype that the opclass member
operator yields, not the indexed datatype (so in practice it'd usually
be float8_ops or float8 <, no doubt).
The reason I bring this up now is that it affects the decision as to
what the unique key for pg_amop ought to be. Instead of having an
enum "purpose" column, maybe we should consider that the unique key
is (operator oid, opfamily oid, order-by-oid), where order-by-oid
is zero for a search operator and the OID of the btree opclass or sort
operator for an ordering operator. This would be of value if we
imagined that a single opclass could support ordering by more than one
distance ordering operator; which seems a bit far-fetched but perhaps
not impossible. On the other side of the coin it'd mean we aren't
leaving room for other sorts of operator "purposes".
On balance I'm inclined to leave the unique key as per previous proposal
(with a "purpose" column) and add the which-sort-order-is-that
information as payload columns that aren't part of the key.
Thoughts?
regards, tom lane
On Mon, Nov 22, 2010 at 8:32 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
The reason I bring this up now is that it affects the decision as to
what the unique key for pg_amop ought to be. Instead of having an
enum "purpose" column, maybe we should consider that the unique key
is (operator oid, opfamily oid, order-by-oid), where order-by-oid
is zero for a search operator and the OID of the btree opclass or sort
operator for an ordering operator. This would be of value if we
imagined that a single opclass could support ordering by more than one
distance ordering operator; which seems a bit far-fetched but perhaps
not impossible. On the other side of the coin it'd mean we aren't
leaving room for other sorts of operator "purposes".
Since the need for additional purposes is mostly hypothetical, this
wouldn't bother me any.
On balance I'm inclined to leave the unique key as per previous proposal
(with a "purpose" column) and add the which-sort-order-is-that
information as payload columns that aren't part of the key.
This is probably OK too, although I confess I'm a lot less happy about
it now that you've pointed out the need for those payload columns.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Nov 22, 2010 at 8:32 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
On balance I'm inclined to leave the unique key as per previous proposal
(with a "purpose" column) and add the which-sort-order-is-that
information as payload columns that aren't part of the key.
This is probably OK too, although I confess I'm a lot less happy about
it now that you've pointed out the need for those payload columns.
The reason I said "columns" is that I can foresee eventually wanting to
specify a pathkey in its entirety --- opfamily, asc/desc, nulls_first,
and whatever we come up with for collation. We don't currently need to
store more than the opfamily, since the others can never need to have
non-default values given the current implementation of KNNGIST. But the
idea that they might all be there eventually makes me feel that we don't
want to try to incorporate this data in pg_amop's unique key. I'm
satisfied to say that only one sort order can be associated with a
particular operator in a particular opclass, which is what would be
implied by using AMOP_SEARCH/AMOP_ORDER as the unique key component.
regards, tom lane
On Mon, Nov 22, 2010 at 11:05 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Nov 22, 2010 at 8:32 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
On balance I'm inclined to leave the unique key as per previous proposal
(with a "purpose" column) and add the which-sort-order-is-that
information as payload columns that aren't part of the key.This is probably OK too, although I confess I'm a lot less happy about
it now that you've pointed out the need for those payload columns.The reason I said "columns" is that I can foresee eventually wanting to
specify a pathkey in its entirety --- opfamily, asc/desc, nulls_first,
and whatever we come up with for collation. We don't currently need to
store more than the opfamily, since the others can never need to have
non-default values given the current implementation of KNNGIST. But the
idea that they might all be there eventually makes me feel that we don't
want to try to incorporate this data in pg_amop's unique key. I'm
satisfied to say that only one sort order can be associated with a
particular operator in a particular opclass, which is what would be
implied by using AMOP_SEARCH/AMOP_ORDER as the unique key component.
Does that imply that KNNGIST would only be able to support one
ordering per AMOP_ORDER-operator, or does it imply that each such
ordering would require a separate strategy number? The second might
be OK, but the first sounds bad.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Nov 22, 2010 at 11:05 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
I'm satisfied to say that only one sort order can be associated with a
particular operator in a particular opclass, which is what would be
implied by using AMOP_SEARCH/AMOP_ORDER as the unique key component.
Does that imply that KNNGIST would only be able to support one
ordering per AMOP_ORDER-operator, or does it imply that each such
ordering would require a separate strategy number? The second might
be OK, but the first sounds bad.
It would be the first, because simply assigning another strategy number
only satisfies one of the unique constraints on pg_amop. To allow
arbitrary flexibility here, we would have to include all components of
the ordering specification in the unique constraint that's presently
just (amopopr, amopfamily) and is proposed to become
(amopopr, amopfamily, amoppurpose). I think that's an undue amount of
complexity to support something that's most likely physically impossible
from the index's standpoint anyway.
regards, tom lane
On Tue, Nov 23, 2010 at 11:12 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Nov 22, 2010 at 11:05 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
I'm satisfied to say that only one sort order can be associated with a
particular operator in a particular opclass, which is what would be
implied by using AMOP_SEARCH/AMOP_ORDER as the unique key component.Does that imply that KNNGIST would only be able to support one
ordering per AMOP_ORDER-operator, or does it imply that each such
ordering would require a separate strategy number? The second might
be OK, but the first sounds bad.It would be the first, because simply assigning another strategy number
only satisfies one of the unique constraints on pg_amop. To allow
arbitrary flexibility here, we would have to include all components of
the ordering specification in the unique constraint that's presently
just (amopopr, amopfamily) and is proposed to become
(amopopr, amopfamily, amoppurpose). I think that's an undue amount of
complexity to support something that's most likely physically impossible
from the index's standpoint anyway.
Or, you'd need to pass these details separately to the AM, which seems
like a more more flexible way of doing it.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Tue, Nov 23, 2010 at 11:12 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
It would be the first, because simply assigning another strategy number
only satisfies one of the unique constraints on pg_amop. �To allow
arbitrary flexibility here, we would have to include all components of
the ordering specification in the unique constraint that's presently
just (amopopr, amopfamily) and is proposed to become
(amopopr, amopfamily, amoppurpose). �I think that's an undue amount of
complexity to support something that's most likely physically impossible
from the index's standpoint anyway.
Or, you'd need to pass these details separately to the AM, which seems
like a more more flexible way of doing it.
A more flexible way of doing what? The first requirement here is that
the catalog entries provide sufficient information to determine the
semantics. You can't just say "this opclass supports ordering", you
have to specify what that ordering is. Punting to the index AM helps
not at all, unless your proposal is to hard-wire this in GIST rather
than in the core planner.
We will probably *also* want to pass these details explicitly to the
index AM, but that doesn't solve the problem that some catalog somewhere
has to say what it is that the opclass can do.
regards, tom lane
I wrote:
We will probably *also* want to pass these details explicitly to the
index AM, but that doesn't solve the problem that some catalog somewhere
has to say what it is that the opclass can do.
... although having said that, the obvious question is why that catalog
has to be pg_amop. Maybe we should leave pg_amop alone (so that it
represents only search operators) and invent a new catalog pg_amorderop.
I envision it having the same columns as pg_amop, plus an ordering
opclass OID (and maybe we might as well stick in asc/desc and nulls_first).
The reason to do this instead of just adding those columns to pg_amop
is that then we can have a different set of unique indexes. I'm
thinking about (amopfamily, amoplefttype, amoprighttype, amopstrategy),
which would be the same as in pg_amop, plus
(amopopr, amopfamily, amopstrategy). This would allow a single operator
to be registered under multiple strategy numbers, which presumably would
carry different payload sort-order-specification columns.
This still seems like overkill to me, because I don't actually believe
that it's practical for an index to support multiple sort orders.
But if anyone would like to make an argument why that's not pie in the
sky, this might be the way to represent it.
regards, tom lane
On Tue, Nov 23, 2010 at 11:37 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Tue, Nov 23, 2010 at 11:12 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
It would be the first, because simply assigning another strategy number
only satisfies one of the unique constraints on pg_amop. To allow
arbitrary flexibility here, we would have to include all components of
the ordering specification in the unique constraint that's presently
just (amopopr, amopfamily) and is proposed to become
(amopopr, amopfamily, amoppurpose). I think that's an undue amount of
complexity to support something that's most likely physically impossible
from the index's standpoint anyway.Or, you'd need to pass these details separately to the AM, which seems
like a more more flexible way of doing it.A more flexible way of doing what? The first requirement here is that
the catalog entries provide sufficient information to determine the
semantics. You can't just say "this opclass supports ordering", you
have to specify what that ordering is. Punting to the index AM helps
not at all, unless your proposal is to hard-wire this in GIST rather
than in the core planner.
Eh, let's just do it the way you want to do it. It's probably going
to have to be redone the next time somebody wants to make an
enhancement in this area, but I guess it's going to be easy to do that
then than to figure where to go with it now.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
2010/9/13 Teodor Sigaev <teodor@sigaev.ru>:
[updated patch]
I realize I'm repeating myself, but... this patch needs
documentation. It's not optional.
I've applied all of this, and written documentation for all of it,
except for the contrib/btree_gist additions which still need to be
redone for the revised API (and then documented!). My patience ran out
somewhere around there, so I'm marking that part as returned with
feedback.
What we have at this point (pending contrib/btree_gist fixes) is
nearest-neighbor searching capability for point columns. And
trigram-based nearest-neighbor for text strings, if you install
contrib/pg_trgm. That doesn't seem like a lot of return for the
amount of work that went into it. Are there plans to add KNN support
for any other standard types?
regards, tom lane
Thanks to all for patience !
We'll sync contrib/btree_gist with current API. Also, we're thinking
about distance for ltree, boxes, circles. I'm not sure about polygons, though.
So, we'll have rather complete set of knn-fied data types.
Oleg
On Sat, 4 Dec 2010, Tom Lane wrote:
Robert Haas <robertmhaas@gmail.com> writes:
2010/9/13 Teodor Sigaev <teodor@sigaev.ru>:
[updated patch]
I realize I'm repeating myself, but... this patch needs
documentation. It's not optional.I've applied all of this, and written documentation for all of it,
except for the contrib/btree_gist additions which still need to be
redone for the revised API (and then documented!). My patience ran out
somewhere around there, so I'm marking that part as returned with
feedback.What we have at this point (pending contrib/btree_gist fixes) is
nearest-neighbor searching capability for point columns. And
trigram-based nearest-neighbor for text strings, if you install
contrib/pg_trgm. That doesn't seem like a lot of return for the
amount of work that went into it. Are there plans to add KNN support
for any other standard types?regards, tom lane
Regards,
Oleg
_____________________________________________________________
Oleg Bartunov, Research Scientist, Head of AstroNet (www.astronet.ru),
Sternberg Astronomical Institute, Moscow University, Russia
Internet: oleg@sai.msu.su, http://www.sai.msu.su/~megera/
phone: +007(495)939-16-83, +007(495)939-23-83
On Sat, Dec 4, 2010 at 6:07 PM, Oleg Bartunov <oleg@sai.msu.su> wrote:
We'll sync contrib/btree_gist with current API. Also, we're thinking
about distance for ltree, boxes, circles. I'm not sure about polygons,
though.
So, we'll have rather complete set of knn-fied data types.
I kind of assumed the natural client for KNN-gist was the tsearch full
text search indexes handling sorting by relevance. For example if I
search for "Postgres DBA" I should find documents where those words
appear adjacent first and documents where the two words appear far
apart in the document sorted further down. Is that not on the list of
operators supported or planned to be supported?
--
greg
Greg Stark <gsstark@mit.edu> writes:
I kind of assumed the natural client for KNN-gist was the tsearch full
text search indexes handling sorting by relevance. For example if I
search for "Postgres DBA" I should find documents where those words
appear adjacent first and documents where the two words appear far
apart in the document sorted further down. Is that not on the list of
operators supported or planned to be supported?
From the presentation I've seen, the typical use case is more searching
"PostgreSQL DBA" at 100 km around a known location. Or more typical yet,
Pizza restaurants around a known place :)
Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support
Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:
Greg Stark <gsstark@mit.edu> writes:
I kind of assumed the natural client for KNN-gist was the tsearch full
text search indexes handling sorting by relevance. For example if I
search for "Postgres DBA" I should find documents where those words
appear adjacent first and documents where the two words appear far
apart in the document sorted further down. Is that not on the list of
operators supported or planned to be supported?
From the presentation I've seen, the typical use case is more searching
"PostgreSQL DBA" at 100 km around a known location. Or more typical yet,
Pizza restaurants around a known place :)
Right offhand I don't see how KNNGIST could usefully be applied to the
problem Greg is thinking about. A KNNGIST search is only going to be
fast if the target items can be found in a reasonably small part of the
index. Nearest-neighbor in a geometrically organized index qualifies,
but I don't see how Greg's problem matches the structure of a tsearch
index.
regards, tom lane
On Sat, 4 Dec 2010, Greg Stark wrote:
On Sat, Dec 4, 2010 at 6:07 PM, Oleg Bartunov <oleg@sai.msu.su> wrote:
We'll sync contrib/btree_gist with current API. Also, we're thinking
about distance for ltree, boxes, circles. I'm not sure about polygons,
though.
So, we'll have rather complete set of knn-fied data types.I kind of assumed the natural client for KNN-gist was the tsearch full
text search indexes handling sorting by relevance. For example if I
search for "Postgres DBA" I should find documents where those words
appear adjacent first and documents where the two words appear far
apart in the document sorted further down. Is that not on the list of
operators supported or planned to be supported?
We'll start thinking about this once we know how to store coordinate
information in index :)
Regards,
Oleg
_____________________________________________________________
Oleg Bartunov, Research Scientist, Head of AstroNet (www.astronet.ru),
Sternberg Astronomical Institute, Moscow University, Russia
Internet: oleg@sai.msu.su, http://www.sai.msu.su/~megera/
phone: +007(495)939-16-83, +007(495)939-23-83
Tom Lane wrote:
Robert Haas <robertmhaas@gmail.com> writes:
2010/9/13 Teodor Sigaev <teodor@sigaev.ru>:
[updated patch]
I realize I'm repeating myself, but... this patch needs
documentation. It's not optional.I've applied all of this, and written documentation for all of it,
except for the contrib/btree_gist additions which still need to be
redone for the revised API (and then documented!). My patience ran out
somewhere around there, so I'm marking that part as returned with
feedback.What we have at this point (pending contrib/btree_gist fixes) is
nearest-neighbor searching capability for point columns. And
trigram-based nearest-neighbor for text strings, if you install
contrib/pg_trgm. That doesn't seem like a lot of return for the
amount of work that went into it. Are there plans to add KNN support
for any other standard types?
I was thinking /contrib/fuzzystrmatch could use it to find the words
that mostly closely match a string.
--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ It's impossible for everything to be true. +
On Wed, Dec 22, 2010 at 8:04 PM, Bruce Momjian <bruce@momjian.us> wrote:
Tom Lane wrote:
Robert Haas <robertmhaas@gmail.com> writes:
2010/9/13 Teodor Sigaev <teodor@sigaev.ru>:
[updated patch]
I realize I'm repeating myself, but... this patch needs
documentation. It's not optional.I've applied all of this, and written documentation for all of it,
except for the contrib/btree_gist additions which still need to be
redone for the revised API (and then documented!). My patience ran out
somewhere around there, so I'm marking that part as returned with
feedback.What we have at this point (pending contrib/btree_gist fixes) is
nearest-neighbor searching capability for point columns. And
trigram-based nearest-neighbor for text strings, if you install
contrib/pg_trgm. That doesn't seem like a lot of return for the
amount of work that went into it. Are there plans to add KNN support
for any other standard types?I was thinking /contrib/fuzzystrmatch could use it to find the words
that mostly closely match a string.
Seems unlikely to be feasible.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
2010/12/4 Tom Lane <tgl@sss.pgh.pa.us>:
What we have at this point (pending contrib/btree_gist fixes) is
nearest-neighbor searching capability for point columns. And
trigram-based nearest-neighbor for text strings, if you install
contrib/pg_trgm. That doesn't seem like a lot of return for the
amount of work that went into it. Are there plans to add KNN support
for any other standard types?
Catching up tonight, I wonder I could propose to add ordering
operators in btree, not in gist, for basic types. So far, we couldn't
optimize simple examples like:
regression=# create index ti on t using btree(i);
CREATE INDEX
regression=# explain select * from t order by i - 10 limit 10;
QUERY PLAN
--------------------------------------------------------------------
Limit (cost=405.10..405.12 rows=10 width=24)
-> Sort (cost=405.10..430.10 rows=10000 width=24)
Sort Key: ((i - 10))
-> Seq Scan on t (cost=0.00..189.00 rows=10000 width=24)
(4 rows)
While this looks too stupid at a glance, adding 2 strategies into
btree, "addition" and "subtraction", will help RANGE concept on data
types; we were stacked around how to implement RANGE in both of window
functions' frame and PARTITION because of lack of "addition" and
"subtraction" idea. If we have 2 more strategies in btree, they can be
solved IMHO. I know addition and subtraction is never relevant to
btree indexing but avoiding unnecessary seq scan and supporting RANGE
concept may buy somehow.
Regards,
--
Hitoshi Harada
Hitoshi Harada <umi.tanuki@gmail.com> writes:
Catching up tonight, I wonder I could propose to add ordering
operators in btree, not in gist, for basic types.
I thought about that for a bit while working on the knngist patch, but
couldn't really see any useful application. In particular, I don't see
a way to shoehorn + and - in there as ordering operators. They don't
match the structure. The RANGE problem wants to add operators that are
somehow related to a btree's operators, but they're not related in the
way that knngist uses.
regards, tom lane
On Sun, Dec 26, 2010 at 2:41 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Hitoshi Harada <umi.tanuki@gmail.com> writes:
Catching up tonight, I wonder I could propose to add ordering
operators in btree, not in gist, for basic types.I thought about that for a bit while working on the knngist patch, but
couldn't really see any useful application. In particular, I don't see
a way to shoehorn + and - in there as ordering operators. They don't
match the structure. The RANGE problem wants to add operators that are
somehow related to a btree's operators, but they're not related in the
way that knngist uses.
It's superficially syntactically similar (value op constant) but as
you say it's really a different problem. The KNNGIST case could occur
in combination with this case, too: ORDER BY (point-column +
zero-vector-constant) distance-from point-constant. What's really
going on here is that there's a class of operations which can be
applied to an ORDER-BY column without actually changing the ordering -
adding or subtracting a constant, multiplying by a positive value,
concatenating with the empty string, etc. In theory, we could try to
recognize such cases and avoid a sort, but it seems like a lot of work
in proportion to the likely benefit.
A far more valuable case to optimize would be the one where you have
ORDER BY a, b and can obtain input pre-sorted by a but not by a, b.
It'd be extremely useful to be able to take the data sorted by just a
and sort each group on b.
As far as window functions go, we clearly need some kind of type
interface feature, but I am unclear whether we should sandwhich it
into the btree opclass machinery or whether it might be better to
create a whole separate concept just for this purpose. Range types
might also like to have some of the same information (addition and
subtraction operators for a type, and perhaps also the identity and
unit if those exist).
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
2010/12/27 Robert Haas <robertmhaas@gmail.com>:
On Sun, Dec 26, 2010 at 2:41 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Hitoshi Harada <umi.tanuki@gmail.com> writes:
Catching up tonight, I wonder I could propose to add ordering
operators in btree, not in gist, for basic types.I thought about that for a bit while working on the knngist patch, but
couldn't really see any useful application. In particular, I don't see
a way to shoehorn + and - in there as ordering operators. They don't
match the structure. The RANGE problem wants to add operators that are
somehow related to a btree's operators, but they're not related in the
way that knngist uses.As far as window functions go, we clearly need some kind of type
interface feature, but I am unclear whether we should sandwhich it
into the btree opclass machinery or whether it might be better to
create a whole separate concept just for this purpose. Range types
might also like to have some of the same information (addition and
subtraction operators for a type, and perhaps also the identity and
unit if those exist).
I believe we should use btree opclass machinery to represent
add/subtract interfaces because in the RANGE case you eventually need
add constant to value and compare it with some boundary by using
btree. Or, btree operator set would be shared in the type interface
machinery. We will want to avoid duplication between them.
Regards,
--
Hitoshi Harada
Hitoshi Harada <umi.tanuki@gmail.com> writes:
2010/12/27 Robert Haas <robertmhaas@gmail.com>:
As far as window functions go, we clearly need some kind of type
interface feature, but I am unclear whether we should sandwhich it
into the btree opclass machinery or whether it might be better to
create a whole separate concept just for this purpose.
I believe we should use btree opclass machinery to represent
add/subtract interfaces because in the RANGE case you eventually need
add constant to value and compare it with some boundary by using
btree. Or, btree operator set would be shared in the type interface
machinery. We will want to avoid duplication between them.
The thing is, these operators have no arguable application in the
context of actual btree index searches. We could certainly stick them
into pg_amop anyway, using a third amoppurpose category to distinguish
them from searchable or orderable operators. But I share Robert's
discomfort with this --- it's unarguably an abuse of the original
intention of operator classes.
OTOH, operator classes are what we've got to represent the abstract
semantics of operators, and it's not real clear to me what we'd gain by
inventing an independent catalog structure to do more or less the same
sort of thing. One good reason *not* to do that is it'll represent even
more stuff that has to be cached during backend startup.
[ thinks for a bit... ] One reason for having a different structure
would be if we needed to represent abstract semantics for some operators
that couldn't be associated with a btree opclass. This is clearly not
an issue for what RANGE needs, since anything you can order by will
surely have a btree opclass for that, and in fact we probably need to
tie those operators to specific orderings if a datatype has more than
one sort ordering. But maybe there could be some other situation where
we'd need to describe operator behavior for a datatype independently of
any sort ordering. Can anyone come up with a plausible example?
regards, tom lane
On Sun, Dec 26, 2010 at 08:13:40PM -0500, Tom Lane wrote:
[ thinks for a bit... ] One reason for having a different structure
would be if we needed to represent abstract semantics for some operators
that couldn't be associated with a btree opclass. This is clearly not
an issue for what RANGE needs, since anything you can order by will
surely have a btree opclass for that, and in fact we probably need to
tie those operators to specific orderings if a datatype has more than
one sort ordering. But maybe there could be some other situation where
we'd need to describe operator behavior for a datatype independently of
any sort ordering. Can anyone come up with a plausible example?
One thing that comes to mind is the operators used for hash indexes,
namely the hash() function. It is closely related to the collation but
isn't actually used for sorting. For every btree class you can make a
hash class with the same equality operator and an appropriate hash
function.
I've had the idea of defining a parent object and deriving the btree
and hash operator classes from that, but it gets messy once you get
into cross-type operators (i.e. operator families).
With respect to the collation of strings I have thought it useful to be
able to define a sortkey() function, which would map the input space to
a 8 byte integer and satisfies the rule:
sortkey(a) < sortkey(b) implies a < b
The idea being that you can use this as an efficient first step to
speed up sorting strings, since adding it to the sort list implicitly
before the actual column doesn't change the result. In the case of
strings the sortkey() could be generated with strxfrm().
A similar idea could be used with other expensive comparison
operations, but I can't think of any at the moment. Actually, perhaps
you could use it with ints/floats/etc as well, since you could skip the
function call overhead. You'd be trading (n log n int compares + n
sortkeys) with (n log n comparisions).
Just some thoughts,
Have a nice day,
--
Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/
Show quoted text
Patriotism is when love of your own people comes first; nationalism,
when hate for people other than your own comes first.
- Charles de Gaulle
Martijn van Oosterhout <kleptog@svana.org> writes:
On Sun, Dec 26, 2010 at 08:13:40PM -0500, Tom Lane wrote:
[ thinks for a bit... ] One reason for having a different structure
would be if we needed to represent abstract semantics for some operators
that couldn't be associated with a btree opclass.
One thing that comes to mind is the operators used for hash indexes,
namely the hash() function.
The hash opclasses handle that fine. I cannot conceive of any reason
for shoehorning hash functions into btree opclasses.
With respect to the collation of strings I have thought it useful to be
able to define a sortkey() function, which would map the input space to
a 8 byte integer and satisfies the rule:
sortkey(a) < sortkey(b) implies a < b
I'm pretty dubious about the workability of that one, but again, there
isn't any obvious reason why we'd need a new catalog structure to
support it. If we did want it, it could be an optional support function
in btree opclasses.
regards, tom lane
I've applied all of this, and written documentation for all of it,
Thank you a lot
except for the contrib/btree_gist additions which still need to be
redone for the revised API (and then documented!). My patience ran out
Done, btree_gist is reworked for a new API.
I'm very sorry, but I'm rather busy now and will be accessible only after
January, 10.
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
Attachments:
Teodor Sigaev <teodor@sigaev.ru> writes:
I've applied all of this, and written documentation for all of it,
Thank you a lot
except for the contrib/btree_gist additions which still need to be
redone for the revised API (and then documented!). My patience ran out
Done, btree_gist is reworked for a new API.
I did a quick look at this patch. The major problem with it is of
course that it needs to be fixed for the recent extension-related
changes. I transposed the .sql.in changes into additions to
btree_gist--1.0.sql (attached), but haven't really sanity-checked
them beyond checking that the regression tests pass. The same mods
would need to be made in btree_gist--unpackaged--1.0.sql.
However, I feel that this is not ready to apply even given those fixes.
Problems yet to solve:
1. oid_dist() returns oid ... really? Oid is unsigned. I'd be inclined
to argue though that distance between Oids is a meaningless concept, so
you should remove this not just mess with the result type. Anybody who
actually wants to form a distance between Oids should have to cast them
to an arithmetic type first. Let the user figure out how wraparound
cases should be handled.
2. Beyond that, none of the distance routines have given any thought to
avoiding overflow. For instance, dist_int2 had better return something
wider than int2, and so on up. It looks to me like the internal gist
distance functions also suffer overflow risks, in that they tend to form
the difference first (in the source datatype) and only afterwards cast
to float8.
3. I was surprised that there wasn't a distance implementation for
numeric. I suppose that this might be difficult to do without risking
overflow in conversion to float8, though.
4. I didn't much care for changing the result type of gbt_num_consistent
from bool to float8; that's just messy, and I don't see any compensating
advantage. I suggest you leave gbt_num_consistent and its callers
alone, and add a separate gbt_num_distance routine that only handles the
KNNDistance case.
There might be more issues, I haven't read the patch in detail.
But anyway, I'm going to set it to Waiting on Author. I think it
needs at least a day or so's work, and I can't put in that kind of
time on it now.
regards, tom lane
On Fri, Feb 18, 2011 at 1:07 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
There might be more issues, I haven't read the patch in detail.
But anyway, I'm going to set it to Waiting on Author. I think it
needs at least a day or so's work, and I can't put in that kind of
time on it now.
Since no one has stepped up to fix these issues, I have marked this
patch Returned with Feedback.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Since no one has stepped up to fix these issues, I have marked this
patch Returned with Feedback.
This is just contrib/btree_GIST, yes?
--
-- Josh Berkus
PostgreSQL Experts Inc.
http://www.pgexperts.com
On Mon, Feb 28, 2011 at 1:53 PM, Josh Berkus <josh@agliodbs.com> wrote:
Since no one has stepped up to fix these issues, I have marked this
patch Returned with Feedback.This is just contrib/btree_GIST, yes?
Yes, core KNN was committed by Tom during the November CommitFest.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Feb 28, 2011 at 1:53 PM, Josh Berkus <josh@agliodbs.com> wrote:
Since no one has stepped up to fix these issues, I have marked this
patch Returned with Feedback.
This is just contrib/btree_GIST, yes?
Yes, core KNN was committed by Tom during the November CommitFest.
Right. However, it's disappointing that this isn't in, because the
number of use cases for KNN-gist in core isn't very large. We really
need support for KNN in btree_gist to make it useful.
Given that it is a contrib module, I personally wouldn't object to it
getting patched later, like during alpha or beta. But somebody's got
to do the work, and I've got a dozen higher-priority problems right now.
regards, tom lane
On Mon, Feb 28, 2011 at 2:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Feb 28, 2011 at 1:53 PM, Josh Berkus <josh@agliodbs.com> wrote:
Since no one has stepped up to fix these issues, I have marked this
patch Returned with Feedback.This is just contrib/btree_GIST, yes?
Yes, core KNN was committed by Tom during the November CommitFest.
Right. However, it's disappointing that this isn't in, because the
number of use cases for KNN-gist in core isn't very large. We really
need support for KNN in btree_gist to make it useful.Given that it is a contrib module, I personally wouldn't object to it
getting patched later, like during alpha or beta. But somebody's got
to do the work, and I've got a dozen higher-priority problems right now.
Well, we can argue about whether it's too late for 9.1 if and when a
patch shows up. Right now we don't have that problem.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
I did a quick look at this patch. The major problem with it is of
course that it needs to be fixed for the recent extension-related
changes. I transposed the .sql.in changes into additions to
btree_gist--1.0.sql (attached), but haven't really sanity-checked
them beyond checking that the regression tests pass. The same mods
would need to be made in btree_gist--unpackaged--1.0.sql.
Fixed
1. oid_dist() returns oid ... really? Oid is unsigned. I'd be inclined
to argue though that distance between Oids is a meaningless concept, so
Hmm, oid is often used as unsigned int.
you should remove this not just mess with the result type. Anybody who
actually wants to form a distance between Oids should have to cast them
to an arithmetic type first. Let the user figure out how wraparound
cases should be handled.
Distance between unsigned 32-bit integers could not be more than 2^32.
2. Beyond that, none of the distance routines have given any thought to
avoiding overflow. For instance, dist_int2 had better return something
wider than int2, and so on up. It looks to me like the internal gist
Just like other operations:
# select 32000::smallint + 32000::smallint;
ERROR: smallint out of range
distance functions also suffer overflow risks, in that they tend to form
the difference first (in the source datatype) and only afterwards cast
to float8.
fixed
3. I was surprised that there wasn't a distance implementation for
numeric. I suppose that this might be difficult to do without risking
overflow in conversion to float8, though.
Exactly
4. I didn't much care for changing the result type of gbt_num_consistent
from bool to float8; that's just messy, and I don't see any compensating
advantage. I suggest you leave gbt_num_consistent and its callers
alone, and add a separate gbt_num_distance routine that only handles the
KNNDistance case.
Done
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
Attachments:
builtin_knngist_contrib_btree_gist-0.12.gzapplication/x-tar; name=builtin_knngist_contrib_btree_gist-0.12.gzDownload
� ��^M �}{w�6�����@;�R��\�DA��s[v}��sm�wz���%���YrD�i=�w� A�$H�)��he�&��l�� 7��[����
�.�t�X�f���jv��d�r����[�N������������h��
���-#����^�>����-]�j��
�����gZ >�����5�B��Cm�^ ��tt���hxvy1:�8��l4�&kZ�h��-��yd���G�q>[��B=h�� ���io�p���
p����|Bo���I�d�5K�d:�er9�������hba���k�;N�G�<���U���I�2LTj�D\rJ��:��qB�u,
[\~{+w�Y-Pc6n����:D���w���Za�)��f�gSt;_���$D�� rZ������5$>N�@�o�/�t0��_������a��h�8F��*UZ&�e2fw����������K�
wY������'M|�������������h��H$��U���_���>"
D�G����a8AgT�^$�vEPa�At���������2����{{c��
/GG���:����$�����j�QMx������]�~F�{w�� ��H^�nQ���������E�jz��I+��&�����r��ucpuuy�������ZM�7.I=�<�.>�\��~���.?G�'�������� ����5�����������;��f���-�?\]�����k����^]�dV`�5D'j�M�������U�a��O�n��_�
�W�A75�������/�.����|��4�T x?�n����d���!�<;nX��~��*�c 5��|�����'A=h�N����l�vW
Z��!X����!�h�]!H�����1��D��K(����9���1���L*u���U �XlB���j07
���4D=:�OXk�zI�!Sn_�hi��"�+�+ws
�����z���������_�u�M�w3^�Y ���
���:����g�Lsk �� �(����� ��*<V�G kx�hraRT<j� ^DL��Qx��
<l��
G�v� o�zi�x��I�(5^�&\�p�z�X[����g+�'��t
v4���-�a��n�xYh��~��'G�9�d�l
>. ��=MV]� ��5C7#��C�h�Q�h�1�h��^I8���~f;!�������!��@�����#3����0$���A@J��&E�2D1(quB(��5��L�[��-�
���I�j9����������b#�!6��
�E[V��r��:\;�q
��j���6)'��$��6��LS��r9�����|B5��+�7�Z ��j(`8�4���)�� �������R�P ��D�\%E<'������u��15l�5e�
��U���Zg�t
��be��%��O�
K�{1���]G3=��V4�����9�e�:2���Q��9\�4�������48���s��L��<�����~���{�s�����U����2�5L�h��ft�t���yj n\�I���b��1�����0�p���x�����nX����[�@7�g���nX��"�
�n� t���
��p���B7\����
�n������
����[�1����>e�����o��p��L�$B
��q�����@&�pB���X���G`��8J�q���(
oN� Nv� 'qNV�h,UN�8�U�d�L/��G@��I�� ��N�-�I\��-�����Y��.8�S�$.'qN�op2N���/'����q�x����.BF� ���2����2�J��!���������U�t ��L�xp��~9���������� �u����? �����������{�,�����w�������O�w� ��q��T���{�a�{>@�������H���W}�4�[�Q]>�e�&��I����O���W�G��W��A����KZ&a�� �I����m
?��4�,��|�rCi��vib3��o�8���������-7�/>�`!Ul�P����B���h�h4�E����X�h\����&k2�K��1�6��XZp��A�������i��i3��--8���u-�L4�f�X3�����d3�j��T3���x4�>iAz��4m��f�H6=L�5?lCq Jc��?4�$���\Rj��<Il$�e���g~�%i��t+-<�� MliP�M������0
��BMf���;|i�W����X���B���_R P�4���B���)>.�]G3tC������.m6�n6� ���q�����1c}c>�*�A�u�.W��u ��H�CZZ��3d���4�q}?^���`0���F'�\�
����h�>��7��{�n6���A���n5�q��j��`�u�����P�N����Ad�F��|������S�����df���9{��6���sK�5������"o������ qyu%��=�����x��;�E��\'���5��(�RmJ�HQ�]3��
�ijV�|�V�
�j��h}wg\��[�i��i��g����KVh��s�VMI��a��T:�fu���]�E��"E�����+����$@H�j��k�%Z �jV� �n��`���-X@, gY V�:[Y���5i��5�v2,`kuI������� ��t����mG�g[���wk�~�,�(v����ae���Ih�m�mX&�����@@Q� ]�� .fV[���`m������/*��������u[B��l�b,�+��}��x�9tL���j�J��6�J��^nq
m�����5��B�����Y��'�wl[�6��m�j��k�������y8VWs�N�hQ�J�!P����D��Q0z�0������iw4����}���Q�g!wgtjOX�����9��&3��r�j8���O8�H��.DT��h�6 ���#����Jg�#���V.��F��|�y�C��Ys;�����i�p*�N%u9r^1����!��d�W�$����f]J&UL��������Z�]u|Rc
s�"A_Q5��K� $[���v �:aA�ci��v6����������2"S��$��c8�c�aj����?����}�f��������������nc���Uq E��Q��IP�mKs�X<���pg;�'��-�k�vgc��+5C���:�Um��VMI3�������1oWX������D�(5}&2Hh�h$��H��T��&������|
��)��4�S�V����qp�X���m�0Ufo���$&�M������X��r��\4�qJ(^l�9��n4�u�x����d��v���'�g��wg3�a�5�5f����Z7%����OZ���]��v� ���[H�&�6�k�aD$�J4 �4��oM�,����;�Fy��$U�����}%�u�g=S��G3��q�1\�C��nb�&��������B�F���+pr���&�����rL��u#�R���.9�#�6�a<�CJtG|N�r���t���r�V�A:A�G�E��FqyeG�|f��E��f����6YsG������("�[��T�@�������������
�5���%�������N+��V�YRm���j�����Ll���C���-!Y����n����.�n���qq�&�/�nvm�V�S\&X�n��]��-�V����mxK��Kh[[�"��l��+j�M�Jp��$X.����+��J���<�t�����hZ�9�;�9�T�ciN��� K�*k^Y^I��}��r3��:u:���N=TY�T�)���V��\XG��w��/+�?aIQ=zX��%k^�����\ BR��r������~�7(om����P�T'U�._0������:X'��� ��J���M�����'�45��Q��X(���R5�R������j3G]]w�t��wU
�S9+�e�n�u����h��7���<)�~R#��]����4,���\�fWQ��#}e�+�)>�|J�?��k��}D/����O���SF�������h
�7���q�6�/�-"��������z�N�t��WU��=�5:��e�����o`S3��S�Uq��N����fU��J9��U��o���g����UQE��v^��nL)�}��/��o&.����,�5���(������e�&��f_�]���)Y�����"2�@,�F~�`63�9}$O�+� y�\A���a�<��Hn��b�d��U�Q� X��Z"���A�sk�hu��7��h��l�q=z�O��G$ff]���������" �"��M���������p>9yN'������Qr�:����)�U8�����bR�d9�a�[/T����c��^^�7�����Lj�����a�]�����B _V��
;����V�A���1�Y���C�+Y!��z|��$f{k����5�,��&�T�Z���.I�
W�P�Z.$ E�{�GT<j��"��I�2���������S����������Pk3G�f$���G�����_�[Z��8'��U.���#�f��4q�G����zd���� T>_����bh8�2 �l"!cwIp���=Pp����������������5����\��^4����/Q����u��t�]�����1�����������V���KR�.�$����F?��?F������U��t��y�y����I/D�<-o�j��s�o6�e ������FJj��2k�%N~�-��d�,���^T�QJ0��"��>V�O��d�
��D��o��D����/��e"d����f���>�u�V����ttfA ��^%<�.-��}��������u�>����Q#/�
\,�J����s����si0�/��%�x#%D��EVvY�|U0p����`,C~��IS��-���>���3����N�}�)D|;�Y���{��>�'����!A���^��r����Er�� H��D�[����8 jQ Zf ��oH0���[����$�vC1#� Jo'n�m"A���g�
'���HP�V����&��.$�zqT<j���`���EQ��H����H��>�Q���PG�V�����@�R���)B���}�����
����@A�B~@���@��� d�)�� ��n$�+��VJ!�-�2Lk���(�;�Y�7$�@�_��|=K�i�n�2��x2�{�24u�>��GG>�!�'ud�T >)#�'Ud����&~�0����#�'ud�T>D�O���Sd�Tb���Q�m����!�P�l����zp��5���Sq,���k�hV&��F������� �]�b����,��Z_��� y�����\�F�q����x�����Z.��I CS�sc�d���Q��iE�����~�����������4�v���^M0��F�����J*���G�OQ��EOQ��T;:�� *���X����8B��C��0�x�m�o������zvW0
@��5D���c'{<��].����
���8�h<���B�T;`�r���qS��� ���PZ�=�nyaAI�FX��A^"S��?8�eF2u
���P��:4�g��^�pj�)�^���L��q��@
��"$���3�oD�R^�Af�F����0�6MS3�l��j���Q@V)n�R+ ��v����;� �SQ��������f���������f9+����(���B}b{�}V^�\��t]r��-��D�Z�)]��K������L8���?�!Tj���!���������:���9�@(����`��s"�a*�Dq��Um��<���Q�H��h\�(�����q�O<�FE� ��"Xlu�����1G�OD�b^�@���<HKp��$8T��Sx�w�C��=]K3�n�������2'���=��L��N%L��f���q�� R$�$����Bq�5��pE��i�PE���� ����F^P5`)�W��{��2����CBxv�g���=������K��y�0@�=���?��<
�W��';� {OuY�Qu(�CQ�������z�m��0�������Q�@0r�S.��1N
�U ���G�R�v5��G�5����P��,*I5��1z��
���Xj�WD��te���a��:� /6���v+13!e�}Z S��!d�����F,���X�d"��D������� �<�G[�0�� ����_��<CS��M�����J>$�W��*�U�4CD�?�4�G����z!+=�-��';��v���_$M�t ��r&v� ��7u\��B�|�t�Yu�������z��h�n����f�AG����9~�,�[����
�U)HJ*�_�I���R�*�� ���d�*����VxJ�^�5��`X�L�LU�����-�~�L���!_��������P�� �z����2[L��}xp����f=�{D�������<���W����l��������{qr�����a7��q.Z�T�����=e��)�t/���x
G�6H�{
�]D0o��O$`�S��^ ���^��B�W �����Wtn�0t����z�3j����:�'���S���ON�~�E��Q�����oQ����a������ptrvq6P��~��_NbS�wnp�:���b��,7�`W�?�b�*o��JZn�Qy�:eF�����=�{"|��\0� ��$���������\�MB�� >ar<���F��8tt&6� �P(J9I�4%��o�kxf7'�����`?�i#�j-�������� E�����?_��@A�����n `�����-���s��
���G�����k�$�k��#�� a����AY�P"}/�=��������>ek���%\At��-?�.GqS��;|NS��'��S����6T�+U�/S��� :6l�4�5]]�+k�$��4E��|�$p��gI��w;��m�$2��7������5��$X��Y��������2fk�T��3�PH�����~�5�<�UH�r>}RT������z�x��9��Gu����&� eA��%�w���dw^ m��I]�Qb6-uX_h�,�+��=��V+��>����������h�����&��@2�w���z�B�����������_ �.�����;^M���SN/6�/��zj�\�_�
�j�T;�H0���D?�
�:0^��YV�Ed0�OuH�3��A�i��������W��l=�G�}~`+����b�.�.=�|�^j����R���
&`q�������W&hQ�U�ux;r?5Q� N�r�5�Bq�w���.dsi�+���q*��\x��;�����=��B
8����$�� �hC�
A��kx]-'�"����z�vU��T%���T"��;�(1Y�s�\>m��x�����]Df)������%�����f�����[�)(F���F����g��Gh_pF������)iq&O�������%h����QG4Q���LH��3��S�l�����`0�?|;xG/��(�E��_� J���n;��#�Eo� �Q�?a����C���G�"� -�k��t���{�=�v�tD�k��0o�h������w�����su�-uf�����Dp(�?�j�����
��/����Dv�����Km�\��:�.�b ���{#�l�_R�������u��a�O��V���w~v������G���wtw�x���U���L����q��%��Q��9s�x�fF]�o��30D���&�?�G
,�{=8��\����4 h�g�" Zr��ZC���A��l���*���o,�
��khb����� 0 AS(R8�e�6�v�I|Z�1ab���G�������/O������=(d�o���K�������U����?e��m����l��X�f3�G���b5(|�M�G�@5!��'����?���u#-U����&�7� 3QD{ M_TYr�,n���|?�H�7_������r7a�|��x���HF�i�C�4b���x?��#�D���M-�_Wf�I�T��rT�Y�W��b��� ���#�8���E�7?����ZI�m�(3�'����lfEn"���2jx�����3���0�j�����zp>8������4��i������\]�c��������
��%Iw~��l�������}��o'������O�����1^�~%�/�����_Xm����������m�&�hX�e^������?�����?Y;f7�����M��.N�u� ������`���x2wG�����o����
�t�_�������4�� ������������s���9�KS�'-���?����.P���zx�.ON������\������X�*�H�����}����A��
�Ao���v��`�����[�H[B%�Bo��O��� Y���9������A)���e(�A]gE[�r���2��je�"����_�&}�v�������!�#�m��rV7���#�����T�`}��
{BG�;��64�
���\��yT��#d������L������vu:D��u�-��=�}
aU��'���8S;b�A���!2�h5�6m�l@�4i�Cr�� ��0��l�*����%58�����Dz=���L�����k��oK80�����<� mi�z+w<Wp~��j]��a5g�:;\��K����9
�w��Z`�Z�t ���!��@9�F�J|���
��k
?�����a�K��4'��:$QU�1�Qq�Xt��Ng���
�����7Lt��7���E\b)�X�7b�7b�
�x��@7���;�ydc������DAG:#���QN��D9u-.T���YD�����)�6������XIcA���'�V��i������0����xMk�}�������I/7���� �DO(;�b�M���� ���7��Q��;bU��_�^wB�WN�����J�}I'$��_��C'T�h���8�r�����bO|Y'd�N(w� u/�z�*m,�z����H���7��2���t�\�c;v�c�]�j��6���b���8zf�h����'N�bD0�P���?�k�t��c�c����j��M�ct�6;m��������;]=������5���gk.u|�F��Wt|����S,�:H:��qg�'�]^
N��Uq��>%W*�� G].[�p�n��v���7�R��*��L�$y2�v�L�)PD+K�sBi�
���P}t�������B�;��v��t������m2Z3ZJl8���9G���6�b���%F���|^��*C�Z�O�2|�X��-;���#N���D�����;�4�P�G�]�t��7)ZB��Z!r����Bf�A�P�>V�l�\���)��Yry���bN]K�2�3 w�Wz������e���|��k������~r���):�4�<���#l�
���B$"m��oV
���D.�^��.p���p*v���T*G� ����������y��'N�></*+��LVQ�i�-�<g@��>�,��P9�:)���_�[��2�c�5:��V1e�_2[��F�EX�qE��*a R���E��5*�H�C��,(�e ��Y@a�v����(�!�;����xA��m��������Ns��*~!�QS@��V�&���$J^.J$5Q}m���3�W`|������&P?�p�d�4;�T$��V��R6����#)�-KY�z���g�x����n����j�;
��-��
X��A�������?�- 5{������P�T��[��;�q8��~�I#�������R��
�_�� �VO7z%�����Y3�h��ep�M���`Q��(�Nl�o�"1w���������d����%���s��8��,�`��4�l�U��;W���W��Ee�L������Y�1�JD��������qPj���4g{��Y��gFi��JdN�S$�/��9�������m����������!�kN��"8�TQod[��
3`�jW[����nXt�q�a����� �����
+�o�0�o7��*�-�)��i�L�JH��tsiqr�L�����;u���fXYH�kg!iUKK��m[Kn=��C������
�^��$rx��&[J�a�"V^���*hR8����I��L*�i'&��@����T��l�O���p��b�-��2�_����Ff��Ew�eX�kW���UI�l�������T$XxGU�-x��~�f����W�e�Q�<2��b��8)��G|���������v`q�&�&+*.���y(����(d����W1�Z0����#"b�%�L���%������,e�R�rEL�>�o�W�"�O�m���I�5����L3�[�P�[!�D�_�^q��L6)�7y<���_S���v���MW�g�5�k����9K�l������e���[aq������H���d�{I1�������kdV������
��+������vab����)i3��mc�d�E�������(�B��C"<~n�F����v�~V�|F�n���6���+��������W�f�����|�_'W}�!3/Z[e�T��_b�X]�uo��:�.[���{zN:�4��k��51��\�V�}�R�x��L Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Feb 28, 2011 at 2:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Given that it is a contrib module, I personally wouldn't object to it
getting patched later, like during alpha or beta. �But somebody's got
to do the work, and I've got a dozen higher-priority problems right now.
Well, we can argue about whether it's too late for 9.1 if and when a
patch shows up. Right now we don't have that problem.
We do now ...
http://archives.postgresql.org/pgsql-hackers/2011-03/msg00038.php
Since we appear to be still holding the commitfest open for Sync Rep,
I guess this ought to get reviewed.
regards, tom lane
Teodor Sigaev <teodor@sigaev.ru> writes:
[ builtin_knngist_contrib_btree_gist-0.12 patch ]
Applied with some corrections --- mostly, that the upgrade script was
all wet. I added some documentation too.
regards, tom lane
Thanks, Tom !
Oleg
On Wed, 2 Mar 2011, Tom Lane wrote:
Teodor Sigaev <teodor@sigaev.ru> writes:
[ builtin_knngist_contrib_btree_gist-0.12 patch ]
Applied with some corrections --- mostly, that the upgrade script was
all wet. I added some documentation too.regards, tom lane
Regards,
Oleg
_____________________________________________________________
Oleg Bartunov, Research Scientist, Head of AstroNet (www.astronet.ru),
Sternberg Astronomical Institute, Moscow University, Russia
Internet: oleg@sai.msu.su, http://www.sai.msu.su/~megera/
phone: +007(495)939-16-83, +007(495)939-23-83