-`
-end
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id HAA05591
- for ; Mon, 19 Oct 1998 07:31:09 -0400 (EDT)
-Received: from hub.org (
[email protected] [209.47.148.200]) by renoir.op.net (o1/$ Revision: 1.18 $) with ESMTP id HAA13574 for
; Mon, 19 Oct 1998 07:12:57 -0400 (EDT)
-Received: from localhost (majordom@localhost)
- by hub.org (8.8.8/8.8.8) with SMTP id GAA13957;
- Mon, 19 Oct 1998 06:25:09 -0400 (EDT)
-Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Mon, 19 Oct 1998 06:22:35 +0000 (EDT)
-Received: (from majordom@localhost)
- by hub.org (8.8.8/8.8.8) id GAA13581
- for pgsql-hackers-outgoing; Mon, 19 Oct 1998 06:22:33 -0400 (EDT)
-X-Authentication-Warning: hub.org: majordom set sender to
[email protected] using -f
- by hub.org (8.8.8/8.8.8) with ESMTP id GAA13566
- for
; Mon, 19 Oct 1998 06:22:27 -0400 (EDT)
-Received: by dsh.de; id MAA13918; Mon, 19 Oct 1998 12:21:16 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma013635; Mon, 19 Oct 98 12:20:55 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id MAA11037;
- Mon, 19 Oct 1998 12:18:27 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id MAA29382;
- Mon, 19 Oct 1998 12:20:49 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zVA2V-000B5AC; Mon, 19 Oct 98 09:47 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zVCaT-000EBPC; Mon, 19 Oct 98 12:30 MET DST
-Message-Id:
-Subject: Re: [HACKERS] What about LIMIT in SELECT ?
-Date: Mon, 19 Oct 1998 12:30:52 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Precedence: bulk
-Status: RO
-
-Hiroshi Inoue wrote:
-
-> When using cursors,in most cases the response to get first(next) rows
-> is necessary for me,not the throughput.
-> How can we tell PostgreSQL optimzer that the response is necessary ?
-
- With my LIMIT patch, the offset and the row count are part of
- the querytree. And if a LIMIT is given, the limitCount elemet
- of the querytree (a Node *) isn't NULL what it is by default.
-
- When a LIMIT is given, the optimizer could assume that first
- rows is wanted (even if the limit is ALL maybe - but I have
- to think about this some more). And this assumption might let
- it decide to use an index to resolve an ORDER BY even if no
- qualification was given.
-
- Telling the optimizer that first rows wanted in a cursor
- operation would read
-
- DECLARE CURSOR c FOR SELECT * FROM mytab ORDER BY a LIMIT ALL;
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id GAA02483
- for ; Tue, 20 Oct 1998 06:01:48 -0400 (EDT)
-Received: from hub.org (
[email protected] [209.47.148.200]) by renoir.op.net (o1/$ Revision: 1.18 $) with ESMTP id FAA07799 for
; Tue, 20 Oct 1998 05:51:19 -0400 (EDT)
-Received: from localhost (majordom@localhost)
- by hub.org (8.8.8/8.8.8) with SMTP id FAA00108;
- Tue, 20 Oct 1998 05:17:58 -0400 (EDT)
-Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Tue, 20 Oct 1998 05:16:37 +0000 (EDT)
-Received: (from majordom@localhost)
- by hub.org (8.8.8/8.8.8) id FAA29953
- for pgsql-hackers-outgoing; Tue, 20 Oct 1998 05:16:35 -0400 (EDT)
-X-Authentication-Warning: hub.org: majordom set sender to
[email protected] using -f
- by hub.org (8.8.8/8.8.8) with ESMTP id FAA29939
- for ; Tue, 20 Oct 1998 05:16:27 -0400 (EDT)
-Received: by dsh.de; id LAA04585; Tue, 20 Oct 1998 11:15:05 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma004337; Tue, 20 Oct 98 11:14:46 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id LAA14628;
- Tue, 20 Oct 1998 11:12:27 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id LAA03564;
- Tue, 20 Oct 1998 11:14:52 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zVVUa-000B5AC; Tue, 20 Oct 98 08:42 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zVY2c-000EBPC; Tue, 20 Oct 98 11:25 MET DST
-Message-Id:
-Subject: Re: [HACKERS] What about LIMIT in SELECT ?
-Date: Tue, 20 Oct 1998 11:25:22 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Precedence: bulk
-Status: RO
-
-Hiroshi Inoue wrote:
-
-> > * Prevent psort() usage when query already using index matching ORDER BY
-> >
-> >
->
-> I can't find the reference to descending order cases except my posting.
-> If we use an index scan to remove sorts in those cases,backward positioning
-> and scanning are necessary.
-
- I think it's only thought as a reminder that the optimizer
- needs some optimization.
-
- That topic, and the LIMIT stuff too I think, is past 6.4 work
- and may go into a 6.4.1 performance release. So when we are
- after 6.4, we have enough time to work out a real solution,
- instead of just throwing in a patch as a quick shot.
-
- What we two did where steps in the same direction. Your one
- covers more situations, but after all if multiple people have
- the same idea there is a good chance that it is the right
- thing to do.
-
->
-> Let t be a table with 2 indices, index1(key1,key2), index2(key1,key3).
-> i.e. key1 is common to index1 and index2.
->
-> And for the query
-> select * from t where key1>....;
->
-> If PosgreSQL optimizer choose [ index scan on index1 ] we can't remove
-> sorts from the following query.
-> select * from t where key1>... order by key1,key3;
->
-> Similarly if [ index scan on index2 ] are chosen we can't remove sorts
-> from the following query.
-> select * from t where key1>... order by key1,key2;
->
-> But in both cases (clever) optimizer can choose another index for scan.
-
- Right. As I remember, your solution does basically the same
- as my one. It does not change the optimizers decision about
- the index or if an index at all is used. So I assume they
- hook into the same position where depending on the order by
- clause the sort node is added. And that is at the very end of
- the optimizer.
-
- What you describe above requires changes in upper levels of
- optimization. Doing that is far away from my knowledge about
- the optimizer. And some of your earlier statements let me
- think you aren't familiar enough with it too. We need at
- least help from others to do it well.
-
- I don't want to dive that deep into the optimizer. There was
- a far too long time where the rule system was broken and got
- out of sync with the parser/optimizer capabilities. I fixed
- many things in it for 6.4. My first priority now is, not to
- let such a situation come up again.
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id NAA08269
- for ; Tue, 20 Oct 1998 13:00:01 -0400 (EDT)
-Received: by dsh.de; id TAA14203; Tue, 20 Oct 1998 19:02:15 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma014037; Tue, 20 Oct 98 19:01:39 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id SAA24445;
- Tue, 20 Oct 1998 18:59:16 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id TAA06159;
- Tue, 20 Oct 1998 19:01:40 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zVcmS-000B5AC; Tue, 20 Oct 98 16:29 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zVfKV-000EBPC; Tue, 20 Oct 98 19:12 MET DST
-Message-Id:
-Subject: Re: [HACKERS] What about LIMIT in SELECT ?
-Date: Tue, 20 Oct 1998 19:12:19 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Status: ROr
-
->
-> I agree. Another good thing is that the LIMIT thing will not require a
-> dump/reload, so it is a good candidate for a minor release.
-
- That's wrong, sorry.
-
- The limit thing as I implemented it adds 2 new variables to
- the Query structure. Rewrite rules are stored as querytrees
- and in the existing pg_rewrite entries that would be missing.
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id NAA08484
- for ; Tue, 20 Oct 1998 13:24:45 -0400 (EDT)
-Received: from localhost (majordom@localhost)
- by hub.org (8.8.8/8.8.8) with SMTP id NAA01878;
- Tue, 20 Oct 1998 13:00:06 -0400 (EDT)
-Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Tue, 20 Oct 1998 12:59:59 +0000 (EDT)
-Received: (from majordom@localhost)
- by hub.org (8.8.8/8.8.8) id MAA01579
- for pgsql-hackers-outgoing; Tue, 20 Oct 1998 12:59:58 -0400 (EDT)
-X-Authentication-Warning: hub.org: majordom set sender to
[email protected] using -f
- by hub.org (8.8.8/8.8.8) with ESMTP id MAA01557
- for ; Tue, 20 Oct 1998 12:59:52 -0400 (EDT)
-Received: by dsh.de; id TAA14203; Tue, 20 Oct 1998 19:02:15 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma014037; Tue, 20 Oct 98 19:01:39 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id SAA24445;
- Tue, 20 Oct 1998 18:59:16 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id TAA06159;
- Tue, 20 Oct 1998 19:01:40 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zVcmS-000B5AC; Tue, 20 Oct 98 16:29 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zVfKV-000EBPC; Tue, 20 Oct 98 19:12 MET DST
-Message-Id:
-Subject: Re: [HACKERS] What about LIMIT in SELECT ?
-Date: Tue, 20 Oct 1998 19:12:19 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Precedence: bulk
-Status: ROr
-
->
-> I agree. Another good thing is that the LIMIT thing will not require a
-> dump/reload, so it is a good candidate for a minor release.
-
- That's wrong, sorry.
-
- The limit thing as I implemented it adds 2 new variables to
- the Query structure. Rewrite rules are stored as querytrees
- and in the existing pg_rewrite entries that would be missing.
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id NAA08339
- for ; Tue, 20 Oct 1998 13:10:18 -0400 (EDT)
-Received: by dsh.de; id TAA17171; Tue, 20 Oct 1998 19:12:30 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma017064; Tue, 20 Oct 98 19:12:00 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id TAA24806;
- Tue, 20 Oct 1998 19:09:37 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id TAA06212;
- Tue, 20 Oct 1998 19:12:01 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zVcwS-000B5AC; Tue, 20 Oct 98 16:39 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zVfUW-000EBPC; Tue, 20 Oct 98 19:22 MET DST
-Message-Id:
-Subject: Re: [HACKERS] What about LIMIT in SELECT ?
-Date: Tue, 20 Oct 1998 19:22:40 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Status: RO
-
->
-> > >
-> > > I agree. Another good thing is that the LIMIT thing will not require a
-> > > dump/reload, so it is a good candidate for a minor release.
-> >
-> > That's wrong, sorry.
-> >
-> > The limit thing as I implemented it adds 2 new variables to
-> > the Query structure. Rewrite rules are stored as querytrees
-> > and in the existing pg_rewrite entries that would be missing.
->
-> Oh, sorry. I forgot. That could be tough.
-
- But it wouldn't hurt to add them now to have them in
- place. The required out-, read- and copyfuncs are in
- my patch too. This would prevent dump/load when we
- later add the real LIMIT functionality. And it does
- not change anything now.
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id OAA11449
- for ; Tue, 20 Oct 1998 14:57:34 -0400 (EDT)
-Received: from localhost (majordom@localhost)
- by hub.org (8.8.8/8.8.8) with SMTP id NAA03547;
- Tue, 20 Oct 1998 13:10:38 -0400 (EDT)
-Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Tue, 20 Oct 1998 13:10:23 +0000 (EDT)
-Received: (from majordom@localhost)
- by hub.org (8.8.8/8.8.8) id NAA03488
- for pgsql-hackers-outgoing; Tue, 20 Oct 1998 13:10:21 -0400 (EDT)
-X-Authentication-Warning: hub.org: majordom set sender to
[email protected] using -f
- by hub.org (8.8.8/8.8.8) with ESMTP id NAA03455
- for ; Tue, 20 Oct 1998 13:10:10 -0400 (EDT)
-Received: by dsh.de; id TAA17171; Tue, 20 Oct 1998 19:12:30 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma017064; Tue, 20 Oct 98 19:12:00 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id TAA24806;
- Tue, 20 Oct 1998 19:09:37 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id TAA06212;
- Tue, 20 Oct 1998 19:12:01 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zVcwS-000B5AC; Tue, 20 Oct 98 16:39 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zVfUW-000EBPC; Tue, 20 Oct 98 19:22 MET DST
-Message-Id:
-Subject: Re: [HACKERS] What about LIMIT in SELECT ?
-Date: Tue, 20 Oct 1998 19:22:40 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Precedence: bulk
-Status: ROr
-
->
-> > >
-> > > I agree. Another good thing is that the LIMIT thing will not require a
-> > > dump/reload, so it is a good candidate for a minor release.
-> >
-> > That's wrong, sorry.
-> >
-> > The limit thing as I implemented it adds 2 new variables to
-> > the Query structure. Rewrite rules are stored as querytrees
-> > and in the existing pg_rewrite entries that would be missing.
->
-> Oh, sorry. I forgot. That could be tough.
-
- But it wouldn't hurt to add them now to have them in
- place. The required out-, read- and copyfuncs are in
- my patch too. This would prevent dump/load when we
- later add the real LIMIT functionality. And it does
- not change anything now.
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id CAA29494
- for ; Wed, 21 Oct 1998 02:35:53 -0400 (EDT)
-Received: from localhost (majordom@localhost)
- by hub.org (8.8.8/8.8.8) with SMTP id CAA13326;
- Wed, 21 Oct 1998 02:10:42 -0400 (EDT)
-Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Wed, 21 Oct 1998 02:09:35 +0000 (EDT)
-Received: (from majordom@localhost)
- by hub.org (8.8.8/8.8.8) id CAA12900
- for pgsql-hackers-outgoing; Wed, 21 Oct 1998 02:09:33 -0400 (EDT)
-X-Authentication-Warning: hub.org: majordom set sender to
[email protected] using -f
- by hub.org (8.8.8/8.8.8) with ESMTP id CAA12871
- for ; Wed, 21 Oct 1998 02:09:26 -0400 (EDT)
-Received: (from maillist@localhost)
- by candle.pha.pa.us (8.9.0/8.9.0) id CAA27774;
- Wed, 21 Oct 1998 02:09:27 -0400 (EDT)
-From: Bruce Momjian
-Subject: Re: [HACKERS] What about LIMIT in SELECT ?
-In-Reply-To: from Jan Wieck at "Oct 20, 1998 7:22:40 pm"
-Date: Wed, 21 Oct 1998 02:09:26 -0400 (EDT)
-X-Mailer: ELM [version 2.4ME+ PL47 (25)]
-MIME-Version: 1.0
-Content-Type: text/plain; charset=US-ASCII
-Content-Transfer-Encoding: 7bit
-Precedence: bulk
-Status: RO
-
-> >
-> > > >
-> > > > I agree. Another good thing is that the LIMIT thing will not require a
-> > > > dump/reload, so it is a good candidate for a minor release.
-> > >
-> > > That's wrong, sorry.
-> > >
-> > > The limit thing as I implemented it adds 2 new variables to
-> > > the Query structure. Rewrite rules are stored as querytrees
-> > > and in the existing pg_rewrite entries that would be missing.
-> >
-> > Oh, sorry. I forgot. That could be tough.
->
-> But it wouldn't hurt to add them now to have them in
-> place. The required out-, read- and copyfuncs are in
-> my patch too. This would prevent dump/load when we
-> later add the real LIMIT functionality. And it does
-> not change anything now.
->
-
-Jan, we found that I am having to require an initdb for the INET/CIDR
-type, so if you want stuff to change the views/rules for the limit
-addition post 6.4, please send them in and I will apply them.
-
-You clearly have the syntax down, so I think you should go ahead.
-
-
---
- Bruce Momjian | http://www.op.net/~candle
- + If your life is a hard drive, | 830 Blythe Avenue
- + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id KAA20566
- for ; Thu, 22 Oct 1998 10:20:54 -0400 (EDT)
-Received: by dsh.de; id QAA09067; Thu, 22 Oct 1998 16:23:14 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma008719; Thu, 22 Oct 98 16:22:40 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id QAA01558;
- Thu, 22 Oct 1998 16:19:55 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id QAA18978;
- Thu, 22 Oct 1998 16:22:20 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zWJG2-000B5AC; Thu, 22 Oct 98 13:50 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zWLoE-000EBPC; Thu, 22 Oct 98 16:33 MET DST
-Message-Id:
-Subject: Re: [HACKERS] psql's help (the LIMIT stuff)
-Date: Thu, 22 Oct 1998 16:33:50 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Status: ROr
-
-> >
-> > I hope the QUERY_LIMIT too.
->
-> I still have that cnfify() possible fix to review for KQSO. Are you
-> still thinking limit for 6.4 final, or a minor release after that?
-
- I posted the part that is the minimum applied to 6.4 to make
- adding LIMIT later non-initdb earlier. Anyway, here it's
- again.
-
- My LIMIT implementation that does it like the SET in the
- toplevel executor (but via parsetree values) is ready for
- production. I only held it back because it's feature, not
- bugfix.
-
- Do you want it in 6.4 final?
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-diff -cr src.orig/backend/nodes/copyfuncs.c src/backend/nodes/copyfuncs.c
-*** src.orig/backend/nodes/copyfuncs.c Fri Oct 16 11:53:40 1998
---- src/backend/nodes/copyfuncs.c Fri Oct 16 13:32:35 1998
-***************
-*** 1578,1583 ****
---- 1578,1586 ----
- newnode->unionClause = temp_list;
- }
-
-+ Node_Copy(from, newnode, limitOffset);
-+ Node_Copy(from, newnode, limitCount);
-+
- return newnode;
- }
-
-diff -cr src.orig/backend/nodes/outfuncs.c src/backend/nodes/outfuncs.c
-*** src.orig/backend/nodes/outfuncs.c Fri Oct 16 11:53:40 1998
---- src/backend/nodes/outfuncs.c Fri Oct 16 13:30:50 1998
-***************
-*** 259,264 ****
---- 259,268 ----
- appendStringInfo(str, (node->hasSubLinks ? "true" : "false"));
- appendStringInfo(str, " :unionClause ");
- _outNode(str, node->unionClause);
-+ appendStringInfo(str, " :limitOffset ");
-+ _outNode(str, node->limitOffset);
-+ appendStringInfo(str, " :limitCount ");
-+ _outNode(str, node->limitCount);
- }
-
- static void
-diff -cr src.orig/backend/nodes/readfuncs.c src/backend/nodes/readfuncs.c
-*** src.orig/backend/nodes/readfuncs.c Fri Oct 16 11:53:40 1998
---- src/backend/nodes/readfuncs.c Fri Oct 16 13:31:43 1998
-***************
-*** 163,168 ****
---- 163,174 ----
- token = lsptok(NULL, &length); /* skip :unionClause */
- local_node->unionClause = nodeRead(true);
-
-+ token = lsptok(NULL, &length); /* skip :limitOffset */
-+ local_node->limitOffset = nodeRead(true);
-+
-+ token = lsptok(NULL, &length); /* skip :limitCount */
-+ local_node->limitCount = nodeRead(true);
-+
- return local_node;
- }
-
-diff -cr src.orig/include/nodes/parsenodes.h src/include/nodes/parsenodes.h
-*** src.orig/include/nodes/parsenodes.h Fri Oct 16 11:53:58 1998
---- src/include/nodes/parsenodes.h Fri Oct 16 13:35:32 1998
-***************
-*** 60,65 ****
---- 60,67 ----
-
- List *unionClause; /* unions are linked under the previous
- * query */
-+ Node *limitOffset; /* # of result tuples to skip */
-+ Node *limitCount; /* # of result tuples to return */
-
- /* internal to planner */
- List *base_rel_list; /* base relation list */
-***************
-*** 639,644 ****
---- 641,648 ----
- char *portalname; /* the portal (cursor) to create */
- bool binary; /* a binary (internal) portal? */
- bool unionall; /* union without unique sort */
-+ Node *limitOffset; /* # of result tuples to skip */
-+ Node *limitCount; /* # of result tuples to return */
- } SelectStmt;
-
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id LAA01724
- for ; Thu, 22 Oct 1998 11:33:31 -0400 (EDT)
-Received: from hub.org (
[email protected] [209.47.148.200]) by renoir.op.net (o1/$ Revision: 1.18 $) with ESMTP id LAA12702 for
; Thu, 22 Oct 1998 11:25:02 -0400 (EDT)
-Received: from localhost (majordom@localhost)
- by hub.org (8.9.1/8.8.8) with SMTP id KAA11023;
- Thu, 22 Oct 1998 10:22:13 -0400 (EDT)
-Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Thu, 22 Oct 1998 10:21:07 +0000 (EDT)
-Received: (from majordom@localhost)
- by hub.org (8.9.1/8.8.8) id KAA10873
- for pgsql-hackers-outgoing; Thu, 22 Oct 1998 10:21:05 -0400 (EDT)
-X-Authentication-Warning: hub.org: majordom set sender to
[email protected] using -f
- by hub.org (8.9.1/8.8.8) with ESMTP id KAA10847
- for
; Thu, 22 Oct 1998 10:21:00 -0400 (EDT)
-Received: by dsh.de; id QAA09067; Thu, 22 Oct 1998 16:23:14 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma008719; Thu, 22 Oct 98 16:22:40 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id QAA01558;
- Thu, 22 Oct 1998 16:19:55 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id QAA18978;
- Thu, 22 Oct 1998 16:22:20 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zWJG2-000B5AC; Thu, 22 Oct 98 13:50 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zWLoE-000EBPC; Thu, 22 Oct 98 16:33 MET DST
-Message-Id:
-Subject: Re: [HACKERS] psql's help (the LIMIT stuff)
-Date: Thu, 22 Oct 1998 16:33:50 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Precedence: bulk
-Status: RO
-
-> >
-> > I hope the QUERY_LIMIT too.
->
-> I still have that cnfify() possible fix to review for KQSO. Are you
-> still thinking limit for 6.4 final, or a minor release after that?
-
- I posted the part that is the minimum applied to 6.4 to make
- adding LIMIT later non-initdb earlier. Anyway, here it's
- again.
-
- My LIMIT implementation that does it like the SET in the
- toplevel executor (but via parsetree values) is ready for
- production. I only held it back because it's feature, not
- bugfix.
-
- Do you want it in 6.4 final?
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-diff -cr src.orig/backend/nodes/copyfuncs.c src/backend/nodes/copyfuncs.c
-*** src.orig/backend/nodes/copyfuncs.c Fri Oct 16 11:53:40 1998
---- src/backend/nodes/copyfuncs.c Fri Oct 16 13:32:35 1998
-***************
-*** 1578,1583 ****
---- 1578,1586 ----
- newnode->unionClause = temp_list;
- }
-
-+ Node_Copy(from, newnode, limitOffset);
-+ Node_Copy(from, newnode, limitCount);
-+
- return newnode;
- }
-
-diff -cr src.orig/backend/nodes/outfuncs.c src/backend/nodes/outfuncs.c
-*** src.orig/backend/nodes/outfuncs.c Fri Oct 16 11:53:40 1998
---- src/backend/nodes/outfuncs.c Fri Oct 16 13:30:50 1998
-***************
-*** 259,264 ****
---- 259,268 ----
- appendStringInfo(str, (node->hasSubLinks ? "true" : "false"));
- appendStringInfo(str, " :unionClause ");
- _outNode(str, node->unionClause);
-+ appendStringInfo(str, " :limitOffset ");
-+ _outNode(str, node->limitOffset);
-+ appendStringInfo(str, " :limitCount ");
-+ _outNode(str, node->limitCount);
- }
-
- static void
-diff -cr src.orig/backend/nodes/readfuncs.c src/backend/nodes/readfuncs.c
-*** src.orig/backend/nodes/readfuncs.c Fri Oct 16 11:53:40 1998
---- src/backend/nodes/readfuncs.c Fri Oct 16 13:31:43 1998
-***************
-*** 163,168 ****
---- 163,174 ----
- token = lsptok(NULL, &length); /* skip :unionClause */
- local_node->unionClause = nodeRead(true);
-
-+ token = lsptok(NULL, &length); /* skip :limitOffset */
-+ local_node->limitOffset = nodeRead(true);
-+
-+ token = lsptok(NULL, &length); /* skip :limitCount */
-+ local_node->limitCount = nodeRead(true);
-+
- return local_node;
- }
-
-diff -cr src.orig/include/nodes/parsenodes.h src/include/nodes/parsenodes.h
-*** src.orig/include/nodes/parsenodes.h Fri Oct 16 11:53:58 1998
---- src/include/nodes/parsenodes.h Fri Oct 16 13:35:32 1998
-***************
-*** 60,65 ****
---- 60,67 ----
-
- List *unionClause; /* unions are linked under the previous
- * query */
-+ Node *limitOffset; /* # of result tuples to skip */
-+ Node *limitCount; /* # of result tuples to return */
-
- /* internal to planner */
- List *base_rel_list; /* base relation list */
-***************
-*** 639,644 ****
---- 641,648 ----
- char *portalname; /* the portal (cursor) to create */
- bool binary; /* a binary (internal) portal? */
- bool unionall; /* union without unique sort */
-+ Node *limitOffset; /* # of result tuples to skip */
-+ Node *limitCount; /* # of result tuples to return */
- } SelectStmt;
-
-
-
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id LAA21185
- for ; Thu, 22 Oct 1998 11:01:00 -0400 (EDT)
-Received: from dsh.de (
[email protected] [53.122.101.2]) by renoir.op.net (o1/$ Revision: 1.18 $) with ESMTP id KAA09646 for
; Thu, 22 Oct 1998 10:44:36 -0400 (EDT)
-Received: by dsh.de; id QAA19394; Thu, 22 Oct 1998 16:43:42 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma017268; Thu, 22 Oct 98 16:39:44 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id QAA02988;
- Thu, 22 Oct 1998 16:36:46 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id QAA19155;
- Thu, 22 Oct 1998 16:39:10 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zWJWL-000B5DC; Thu, 22 Oct 98 14:07 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zWM4W-000EBPC; Thu, 22 Oct 98 16:50 MET DST
-Message-Id:
-Subject: Re: [HACKERS] psql's help (the LIMIT stuff)
-Date: Thu, 22 Oct 1998 16:50:40 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Status: RO
-
->
-> > > >
-> > > > I hope the QUERY_LIMIT too.
-> > >
-> > > I still have that cnfify() possible fix to review for KQSO. Are you
-> > > still thinking limit for 6.4 final, or a minor release after that?
-> >
-> > I posted the part that is the minimum applied to 6.4 to make
-> > adding LIMIT later non-initdb earlier. Anyway, here it's
-> > again.
->
-> Already applied. I assume it is the same as the one I applied.
-
- Seen, thanks. Your 'Applied' just arrived after I packed it
- again. It's the same.
-
-> We are close to final, and can easily put it in 6.4.1, which I am sure
-> we will need, and if we split CVS trees, you'll have lots of minor
-> versions to pick from. :-)
->
-> Seems like it would be a nice minor release item, but the problem is
-> that minor releases aren't tested as much as major ones. How confident
-> are you in the code? What do others thing?
-
- I regression tested it, and did additional tests in the
- SPI/PL area. It works. It only touches the parser and the
- executor. Rules, planner/optimizer just bypass the values in
- the parsetree. The parser and the executor are parts of
- Postgres I feel very familiar with (not so in the optimizer).
- I trust in the code and would use it in a production
- environment.
-
- It's below.
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-diff -cr src.orig/backend/commands/command.c src/backend/commands/command.c
-*** src.orig/backend/commands/command.c Fri Oct 16 11:53:38 1998
---- src/backend/commands/command.c Fri Oct 16 12:56:44 1998
-***************
-*** 39,44 ****
---- 39,45 ----
- #include "utils/mcxt.h"
- #include "utils/portal.h"
- #include "utils/syscache.h"
-+ #include "string.h"
-
- /* ----------------
- * PortalExecutorHeapMemory stuff
-***************
-*** 101,106 ****
---- 102,108 ----
- int feature;
- QueryDesc *queryDesc;
- MemoryContext context;
-+ Const limcount;
-
- /* ----------------
- * sanity checks
-***************
-*** 113,118 ****
---- 115,134 ----
- }
-
- /* ----------------
-+ * Create a const node from the given count value
-+ * ----------------
-+ */
-+ memset(&limcount, 0, sizeof(limcount));
-+ limcount.type = T_Const;
-+ limcount.consttype = INT4OID;
-+ limcount.constlen = sizeof(int4);
-+ limcount.constvalue = (Datum)count;
-+ limcount.constisnull = FALSE;
-+ limcount.constbyval = TRUE;
-+ limcount.constisset = FALSE;
-+ limcount.constiscast = FALSE;
-+
-+ /* ----------------
- * get the portal from the portal name
- * ----------------
- */
-***************
-*** 176,182 ****
- PortalExecutorHeapMemory = (MemoryContext)
- PortalGetHeapMemory(portal);
-
-! ExecutorRun(queryDesc, PortalGetState(portal), feature, count);
-
- if (dest == None) /* MOVE */
- pfree(queryDesc);
---- 192,198 ----
- PortalExecutorHeapMemory = (MemoryContext)
- PortalGetHeapMemory(portal);
-
-! ExecutorRun(queryDesc, PortalGetState(portal), feature, (Node *)NULL, (Node *)&limcount);
-
- if (dest == None) /* MOVE */
- pfree(queryDesc);
-diff -cr src.orig/backend/executor/execMain.c src/backend/executor/execMain.c
-*** src.orig/backend/executor/execMain.c Fri Oct 16 11:53:38 1998
---- src/backend/executor/execMain.c Fri Oct 16 20:05:19 1998
-***************
-*** 64,69 ****
---- 64,70 ----
- static void EndPlan(Plan *plan, EState *estate);
- static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
- Query *parseTree, CmdType operation,
-+ int offsetTuples,
- int numberTuples, ScanDirection direction,
- void (*printfunc) ());
- static void ExecRetrieve(TupleTableSlot *slot, void (*printfunc) (),
-***************
-*** 163,169 ****
- * ----------------------------------------------------------------
- */
- TupleTableSlot *
-! ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
- {
- CmdType operation;
- Query *parseTree;
---- 164,170 ----
- * ----------------------------------------------------------------
- */
- TupleTableSlot *
-! ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, Node *limoffset, Node *limcount)
- {
- CmdType operation;
- Query *parseTree;
-***************
-*** 171,176 ****
---- 172,179 ----
- TupleTableSlot *result;
- CommandDest dest;
- void (*destination) ();
-+ int offset = 0;
-+ int count = 0;
-
- /******************
- * sanity checks
-***************
-*** 191,196 ****
---- 194,289 ----
- estate->es_processed = 0;
- estate->es_lastoid = InvalidOid;
-
-+ /******************
-+ * if given get the offset of the LIMIT clause
-+ ******************
-+ */
-+ if (limoffset != NULL)
-+ {
-+ Const *coffset;
-+ Param *poffset;
-+ ParamListInfo paramLI;
-+ int i;
-+
-+ switch (nodeTag(limoffset))
-+ {
-+ case T_Const:
-+ coffset = (Const *)limoffset;
-+ offset = (int)(coffset->constvalue);
-+ break;
-+
-+ case T_Param:
-+ poffset = (Param *)limoffset;
-+ paramLI = estate->es_param_list_info;
-+
-+ if (paramLI == NULL)
-+ elog(ERROR, "parameter for limit offset not in executor state");
-+ for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
-+ {
-+ if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == poffset->paramid)
-+ break;
-+ }
-+ if (paramLI[i].kind == PARAM_INVALID)
-+ elog(ERROR, "parameter for limit offset not in executor state");
-+ if (paramLI[i].isnull)
-+ elog(ERROR, "limit offset cannot be NULL value");
-+ offset = (int)(paramLI[i].value);
-+
-+ break;
-+
-+ default:
-+ elog(ERROR, "unexpected node type %d as limit offset", nodeTag(limoffset));
-+ }
-+
-+ if (offset < 0)
-+ elog(ERROR, "limit offset cannot be negative");
-+ }
-+
-+ /******************
-+ * if given get the count of the LIMIT clause
-+ ******************
-+ */
-+ if (limcount != NULL)
-+ {
-+ Const *ccount;
-+ Param *pcount;
-+ ParamListInfo paramLI;
-+ int i;
-+
-+ switch (nodeTag(limcount))
-+ {
-+ case T_Const:
-+ ccount = (Const *)limcount;
-+ count = (int)(ccount->constvalue);
-+ break;
-+
-+ case T_Param:
-+ pcount = (Param *)limcount;
-+ paramLI = estate->es_param_list_info;
-+
-+ if (paramLI == NULL)
-+ elog(ERROR, "parameter for limit count not in executor state");
-+ for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
-+ {
-+ if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == pcount->paramid)
-+ break;
-+ }
-+ if (paramLI[i].kind == PARAM_INVALID)
-+ elog(ERROR, "parameter for limit count not in executor state");
-+ if (paramLI[i].isnull)
-+ elog(ERROR, "limit count cannot be NULL value");
-+ count = (int)(paramLI[i].value);
-+
-+ break;
-+
-+ default:
-+ elog(ERROR, "unexpected node type %d as limit count", nodeTag(limcount));
-+ }
-+
-+ if (count < 0)
-+ elog(ERROR, "limit count cannot be negative");
-+ }
-+
- switch (feature)
- {
-
-***************
-*** 199,205 ****
- plan,
- parseTree,
- operation,
-! ALL_TUPLES,
- ForwardScanDirection,
- destination);
- break;
---- 292,299 ----
- plan,
- parseTree,
- operation,
-! offset,
-! count,
- ForwardScanDirection,
- destination);
- break;
-***************
-*** 208,213 ****
---- 302,308 ----
- plan,
- parseTree,
- operation,
-+ offset,
- count,
- ForwardScanDirection,
- destination);
-***************
-*** 222,227 ****
---- 317,323 ----
- plan,
- parseTree,
- operation,
-+ offset,
- count,
- BackwardScanDirection,
- destination);
-***************
-*** 237,242 ****
---- 333,339 ----
- plan,
- parseTree,
- operation,
-+ 0,
- ONE_TUPLE,
- ForwardScanDirection,
- destination);
-***************
-*** 691,696 ****
---- 788,794 ----
- Plan *plan,
- Query *parseTree,
- CmdType operation,
-+ int offsetTuples,
- int numberTuples,
- ScanDirection direction,
- void (*printfunc) ())
-***************
-*** 742,747 ****
---- 840,859 ----
- {
- result = NULL;
- break;
-+ }
-+
-+ /******************
-+ * For now we completely execute the plan and skip
-+ * result tuples if requested by LIMIT offset.
-+ * Finally we should try to do it in deeper levels
-+ * if possible (during index scan)
-+ * - Jan
-+ ******************
-+ */
-+ if (offsetTuples > 0)
-+ {
-+ --offsetTuples;
-+ continue;
- }
-
- /******************
-diff -cr src.orig/backend/executor/functions.c src/backend/executor/functions.c
-*** src.orig/backend/executor/functions.c Fri Oct 16 11:53:38 1998
---- src/backend/executor/functions.c Fri Oct 16 19:01:02 1998
-***************
-*** 130,135 ****
---- 130,138 ----
- None);
- estate = CreateExecutorState();
-
-+ if (queryTree->limitOffset != NULL || queryTree->limitCount != NULL)
-+ elog(ERROR, "LIMIT clause from SQL functions not yet implemented");
-+
- if (nargs > 0)
- {
- int i;
-***************
-*** 200,206 ****
-
- feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
-
-! return ExecutorRun(es->qd, es->estate, feature, 0);
- }
-
- static void
---- 203,209 ----
-
- feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
-
-! return ExecutorRun(es->qd, es->estate, feature, (Node *)NULL, (Node *)NULL);
- }
-
- static void
-diff -cr src.orig/backend/executor/spi.c src/backend/executor/spi.c
-*** src.orig/backend/executor/spi.c Fri Oct 16 11:53:39 1998
---- src/backend/executor/spi.c Fri Oct 16 19:25:33 1998
-***************
-*** 791,796 ****
---- 791,798 ----
- bool isRetrieveIntoRelation = false;
- char *intoName = NULL;
- int res;
-+ Const tcount_const;
-+ Node *count = NULL;
-
- switch (operation)
- {
-***************
-*** 825,830 ****
---- 827,865 ----
- return SPI_ERROR_OPUNKNOWN;
- }
-
-+ /* ----------------
-+ * Get the query LIMIT tuple count
-+ * ----------------
-+ */
-+ if (parseTree->limitCount != NULL)
-+ {
-+ /* ----------------
-+ * A limit clause in the parsetree overrides the
-+ * tcount parameter
-+ * ----------------
-+ */
-+ count = parseTree->limitCount;
-+ }
-+ else
-+ {
-+ /* ----------------
-+ * No LIMIT clause in parsetree. Use a local Const node
-+ * to put tcount into it
-+ * ----------------
-+ */
-+ memset(&tcount_const, 0, sizeof(tcount_const));
-+ tcount_const.type = T_Const;
-+ tcount_const.consttype = INT4OID;
-+ tcount_const.constlen = sizeof(int4);
-+ tcount_const.constvalue = (Datum)tcount;
-+ tcount_const.constisnull = FALSE;
-+ tcount_const.constbyval = TRUE;
-+ tcount_const.constisset = FALSE;
-+ tcount_const.constiscast = FALSE;
-+
-+ count = (Node *)&tcount_const;
-+ }
-+
- if (state == NULL) /* plan preparation */
- return res;
- #ifdef SPI_EXECUTOR_STATS
-***************
-*** 845,851 ****
- return SPI_OK_CURSOR;
- }
-
-! ExecutorRun(queryDesc, state, EXEC_FOR, tcount);
-
- _SPI_current->processed = state->es_processed;
- if (operation == CMD_SELECT && queryDesc->dest == SPI)
---- 880,886 ----
- return SPI_OK_CURSOR;
- }
-
-! ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
-
- _SPI_current->processed = state->es_processed;
- if (operation == CMD_SELECT && queryDesc->dest == SPI)
-diff -cr src.orig/backend/parser/analyze.c src/backend/parser/analyze.c
-*** src.orig/backend/parser/analyze.c Fri Oct 16 11:53:41 1998
---- src/backend/parser/analyze.c Fri Oct 16 13:29:27 1998
-***************
-*** 180,186 ****
---- 180,190 ----
-
- case T_SelectStmt:
- if (!((SelectStmt *) parseTree)->portalname)
-+ {
- result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
-+ result->limitOffset = ((SelectStmt *)parseTree)->limitOffset;
-+ result->limitCount = ((SelectStmt *)parseTree)->limitCount;
-+ }
- else
- result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
- break;
-diff -cr src.orig/backend/parser/gram.y src/backend/parser/gram.y
-*** src.orig/backend/parser/gram.y Fri Oct 16 11:53:42 1998
---- src/backend/parser/gram.y Sun Oct 18 22:20:36 1998
-***************
-*** 45,50 ****
---- 45,51 ----
- #include "catalog/catname.h"
- #include "utils/elog.h"
- #include "access/xact.h"
-+ #include "catalog/pg_type.h"
-
- #ifdef MULTIBYTE
- #include "mb/pg_wchar.h"
-***************
-*** 163,169 ****
- sort_clause, sortby_list, index_params, index_list, name_list,
- from_clause, from_list, opt_array_bounds, nest_array_bounds,
- expr_list, attrs, res_target_list, res_target_list2,
-! def_list, opt_indirection, group_clause, TriggerFuncArgs
-
- %type func_return
- %type set_opt
---- 164,171 ----
- sort_clause, sortby_list, index_params, index_list, name_list,
- from_clause, from_list, opt_array_bounds, nest_array_bounds,
- expr_list, attrs, res_target_list, res_target_list2,
-! def_list, opt_indirection, group_clause, TriggerFuncArgs,
-! opt_select_limit
-
- %type func_return
- %type set_opt
-***************
-*** 192,197 ****
---- 194,201 ----
-
- %type fetch_how_many
-
-+ %type select_limit_value select_offset_value
-+
- %type OptSeqList
- %type OptSeqElem
-
-***************
-*** 267,273 ****
- FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
- GRANT, GROUP, HAVING, HOUR_P,
- IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
-! JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LOCAL,
- MATCH, MINUTE_P, MONTH_P, NAMES,
- NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL_P, NUMERIC,
- OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
---- 271,277 ----
- FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
- GRANT, GROUP, HAVING, HOUR_P,
- IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
-! JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LIMIT, LOCAL,
- MATCH, MINUTE_P, MONTH_P, NAMES,
- NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL_P, NUMERIC,
- OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
-***************
-*** 299,305 ****
- INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
- LANCOMPILER, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
- NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
-! OIDS, OPERATOR, PASSWORD, PROCEDURAL,
- RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
- SEQUENCE, SERIAL, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
- UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
---- 303,309 ----
- INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
- LANCOMPILER, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
- NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
-! OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL,
- RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
- SEQUENCE, SERIAL, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
- UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
-***************
-*** 2591,2596 ****
---- 2595,2601 ----
- result from_clause where_clause
- group_clause having_clause
- union_clause sort_clause
-+ opt_select_limit
- {
- SelectStmt *n = makeNode(SelectStmt);
- n->unique = $2;
-***************
-*** 2602,2607 ****
---- 2607,2622 ----
- n->havingClause = $8;
- n->unionClause = $9;
- n->sortClause = $10;
-+ if ($11 != NIL)
-+ {
-+ n->limitOffset = nth(0, $11);
-+ n->limitCount = nth(1, $11);
-+ }
-+ else
-+ {
-+ n->limitOffset = NULL;
-+ n->limitCount = NULL;
-+ }
- $$ = (Node *)n;
- }
- ;
-***************
-*** 2699,2704 ****
---- 2714,2794 ----
- | ASC { $$ = "<"; }
- | DESC { $$ = ">"; }
- | /*EMPTY*/ { $$ = "<"; /*default*/ }
-+ ;
-+
-+ opt_select_limit: LIMIT select_offset_value ',' select_limit_value
-+ { $$ = lappend(lappend(NIL, $2), $4); }
-+ | LIMIT select_limit_value OFFSET select_offset_value
-+ { $$ = lappend(lappend(NIL, $4), $2); }
-+ | LIMIT select_limit_value
-+ { $$ = lappend(lappend(NIL, NULL), $2); }
-+ | OFFSET select_offset_value LIMIT select_limit_value
-+ { $$ = lappend(lappend(NIL, $2), $4); }
-+ | OFFSET select_offset_value
-+ { $$ = lappend(lappend(NIL, $2), NULL); }
-+ | /* EMPTY */
-+ { $$ = NIL; }
-+ ;
-+
-+ select_limit_value: Iconst
-+ {
-+ Const *n = makeNode(Const);
-+
-+ if ($1 < 1)
-+ elog(ERROR, "selection limit must be ALL or a positive integer value > 0");
-+
-+ n->consttype = INT4OID;
-+ n->constlen = sizeof(int4);
-+ n->constvalue = (Datum)$1;
-+ n->constisnull = FALSE;
-+ n->constbyval = TRUE;
-+ n->constisset = FALSE;
-+ n->constiscast = FALSE;
-+ $$ = (Node *)n;
-+ }
-+ | ALL
-+ {
-+ Const *n = makeNode(Const);
-+ n->consttype = INT4OID;
-+ n->constlen = sizeof(int4);
-+ n->constvalue = (Datum)0;
-+ n->constisnull = FALSE;
-+ n->constbyval = TRUE;
-+ n->constisset = FALSE;
-+ n->constiscast = FALSE;
-+ $$ = (Node *)n;
-+ }
-+ | PARAM
-+ {
-+ Param *n = makeNode(Param);
-+ n->paramkind = PARAM_NUM;
-+ n->paramid = $1;
-+ n->paramtype = INT4OID;
-+ $$ = (Node *)n;
-+ }
-+ ;
-+
-+ select_offset_value: Iconst
-+ {
-+ Const *n = makeNode(Const);
-+
-+ n->consttype = INT4OID;
-+ n->constlen = sizeof(int4);
-+ n->constvalue = (Datum)$1;
-+ n->constisnull = FALSE;
-+ n->constbyval = TRUE;
-+ n->constisset = FALSE;
-+ n->constiscast = FALSE;
-+ $$ = (Node *)n;
-+ }
-+ | PARAM
-+ {
-+ Param *n = makeNode(Param);
-+ n->paramkind = PARAM_NUM;
-+ n->paramid = $1;
-+ n->paramtype = INT4OID;
-+ $$ = (Node *)n;
-+ }
- ;
-
- /*
-diff -cr src.orig/backend/parser/keywords.c src/backend/parser/keywords.c
-*** src.orig/backend/parser/keywords.c Fri Oct 16 11:53:42 1998
---- src/backend/parser/keywords.c Sun Oct 18 22:13:29 1998
-***************
-*** 128,133 ****
---- 128,134 ----
- {"leading", LEADING},
- {"left", LEFT},
- {"like", LIKE},
-+ {"limit", LIMIT},
- {"listen", LISTEN},
- {"load", LOAD},
- {"local", LOCAL},
-***************
-*** 156,161 ****
---- 157,163 ----
- {"null", NULL_P},
- {"numeric", NUMERIC},
- {"of", OF},
-+ {"offset", OFFSET},
- {"oids", OIDS},
- {"old", CURRENT},
- {"on", ON},
-diff -cr src.orig/backend/rewrite/rewriteDefine.c src/backend/rewrite/rewriteDefine.c
-*** src.orig/backend/rewrite/rewriteDefine.c Fri Oct 16 11:53:46 1998
---- src/backend/rewrite/rewriteDefine.c Fri Oct 16 13:48:55 1998
-***************
-*** 312,317 ****
---- 312,323 ----
- heap_close(event_relation);
-
- /*
-+ * LIMIT in view is not supported
-+ */
-+ if (query->limitOffset != NULL || query->limitCount != NULL)
-+ elog(ERROR, "LIMIT clause not supported in views");
-+
-+ /*
- * ... and finally the rule must be named _RETviewname.
- */
- sprintf(expected_name, "_RET%s", event_obj->relname);
-diff -cr src.orig/backend/tcop/pquery.c src/backend/tcop/pquery.c
-*** src.orig/backend/tcop/pquery.c Fri Oct 16 11:53:47 1998
---- src/backend/tcop/pquery.c Fri Oct 16 14:02:36 1998
-***************
-*** 40,46 ****
- #include "commands/command.h"
-
- static char *CreateOperationTag(int operationType);
-! static void ProcessQueryDesc(QueryDesc *queryDesc);
-
-
- /* ----------------------------------------------------------------
---- 40,46 ----
- #include "commands/command.h"
-
- static char *CreateOperationTag(int operationType);
-! static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount);
-
-
- /* ----------------------------------------------------------------
-***************
-*** 205,211 ****
- * ----------------------------------------------------------------
- */
- static void
-! ProcessQueryDesc(QueryDesc *queryDesc)
- {
- Query *parseTree;
- Plan *plan;
---- 205,211 ----
- * ----------------------------------------------------------------
- */
- static void
-! ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
- {
- Query *parseTree;
- Plan *plan;
-***************
-*** 330,336 ****
- * actually run the plan..
- * ----------------
- */
-! ExecutorRun(queryDesc, state, EXEC_RUN, 0);
-
- /* save infos for EndCommand */
- UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
---- 330,336 ----
- * actually run the plan..
- * ----------------
- */
-! ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);
-
- /* save infos for EndCommand */
- UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
-***************
-*** 373,377 ****
- print_plan(plan, parsetree);
- }
- else
-! ProcessQueryDesc(queryDesc);
- }
---- 373,377 ----
- print_plan(plan, parsetree);
- }
- else
-! ProcessQueryDesc(queryDesc, parsetree->limitOffset, parsetree->limitCount);
- }
-diff -cr src.orig/include/executor/executor.h src/include/executor/executor.h
-*** src.orig/include/executor/executor.h Fri Oct 16 11:53:56 1998
---- src/include/executor/executor.h Fri Oct 16 12:04:17 1998
-***************
-*** 83,89 ****
- * prototypes from functions in execMain.c
- */
- extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
-! extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count);
- extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
- extern HeapTuple ExecConstraints(char *caller, Relation rel, HeapTuple tuple);
- #ifdef QUERY_LIMIT
---- 83,89 ----
- * prototypes from functions in execMain.c
- */
- extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
-! extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, Node *limoffset, Node *limcount);
- extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
- extern HeapTuple ExecConstraints(char *caller, Relation rel, HeapTuple tuple);
- #ifdef QUERY_LIMIT
-
- by candle.pha.pa.us (8.9.0/8.9.0) with ESMTP id NAA01350
- for ; Thu, 22 Oct 1998 13:12:29 -0400 (EDT)
-Received: from hub.org (
[email protected] [209.47.148.200]) by renoir.op.net (o1/$ Revision: 1.18 $) with ESMTP id MAA17808 for
; Thu, 22 Oct 1998 12:35:22 -0400 (EDT)
-Received: from localhost (majordom@localhost)
- by hub.org (8.9.1/8.8.8) with SMTP id KAA14887;
- Thu, 22 Oct 1998 10:49:09 -0400 (EDT)
-Received: by hub.org (TLB v0.10a (1.23 tibbs 1997/01/09 00:29:32)); Thu, 22 Oct 1998 10:44:59 +0000 (EDT)
-Received: (from majordom@localhost)
- by hub.org (8.9.1/8.8.8) id KAA14445
- for pgsql-hackers-outgoing; Thu, 22 Oct 1998 10:44:57 -0400 (EDT)
-X-Authentication-Warning: hub.org: majordom set sender to
[email protected] using -f
- by hub.org (8.9.1/8.8.8) with ESMTP id KAA14431
- for
; Thu, 22 Oct 1998 10:44:47 -0400 (EDT)
-Received: by dsh.de; id QAA19394; Thu, 22 Oct 1998 16:43:42 +0200 (MET DST)
-Received: from dshmail.dsh.de(53.47.15.3) by neptun.dsh.de via smap (3.2)
- id xma017268; Thu, 22 Oct 98 16:39:44 +0200
-Received: from mail1.hh1.dsh.de (mail1.hh1.dsh.de [53.47.9.5])
- by dshmail.dsh.de (8.8.7/8.8.7) with ESMTP id QAA02988;
- Thu, 22 Oct 1998 16:36:46 +0200 (MET DST)
- by mail1.hh1.dsh.de (8.8.7/8.8.7) with SMTP id QAA19155;
- Thu, 22 Oct 1998 16:39:10 +0200
-Received: from orion.SAPserv.Hamburg.dsh.de
- by mars.SAPserv.Hamburg.dsh.de with smtp
- for <>
- id m0zWJWL-000B5DC; Thu, 22 Oct 98 14:07 MET DST
-Received: by orion.SAPserv.Hamburg.dsh.de
- id m0zWM4W-000EBPC; Thu, 22 Oct 98 16:50 MET DST
-Message-Id:
-Subject: Re: [HACKERS] psql's help (the LIMIT stuff)
-Date: Thu, 22 Oct 1998 16:50:40 +0200 (MET DST)
-X-Mailer: ELM [version 2.4 PL25]
-Content-Type: text
-Precedence: bulk
-Status: ROr
-
->
-> > > >
-> > > > I hope the QUERY_LIMIT too.
-> > >
-> > > I still have that cnfify() possible fix to review for KQSO. Are you
-> > > still thinking limit for 6.4 final, or a minor release after that?
-> >
-> > I posted the part that is the minimum applied to 6.4 to make
-> > adding LIMIT later non-initdb earlier. Anyway, here it's
-> > again.
->
-> Already applied. I assume it is the same as the one I applied.
-
- Seen, thanks. Your 'Applied' just arrived after I packed it
- again. It's the same.
-
-> We are close to final, and can easily put it in 6.4.1, which I am sure
-> we will need, and if we split CVS trees, you'll have lots of minor
-> versions to pick from. :-)
->
-> Seems like it would be a nice minor release item, but the problem is
-> that minor releases aren't tested as much as major ones. How confident
-> are you in the code? What do others thing?
-
- I regression tested it, and did additional tests in the
- SPI/PL area. It works. It only touches the parser and the
- executor. Rules, planner/optimizer just bypass the values in
- the parsetree. The parser and the executor are parts of
- Postgres I feel very familiar with (not so in the optimizer).
- I trust in the code and would use it in a production
- environment.
-
- It's below.
-
-
-Jan
-
---
-
-#======================================================================#
-# It's easier to get forgiveness for being wrong than for being right. #
-# Let's break this rule - forgive me. #
-
-
-diff -cr src.orig/backend/commands/command.c src/backend/commands/command.c
-*** src.orig/backend/commands/command.c Fri Oct 16 11:53:38 1998
---- src/backend/commands/command.c Fri Oct 16 12:56:44 1998
-***************
-*** 39,44 ****
---- 39,45 ----
- #include "utils/mcxt.h"
- #include "utils/portal.h"
- #include "utils/syscache.h"
-+ #include "string.h"
-
- /* ----------------
- * PortalExecutorHeapMemory stuff
-***************
-*** 101,106 ****
---- 102,108 ----
- int feature;
- QueryDesc *queryDesc;
- MemoryContext context;
-+ Const limcount;
-
- /* ----------------
- * sanity checks
-***************
-*** 113,118 ****
---- 115,134 ----
- }
-
- /* ----------------
-+ * Create a const node from the given count value
-+ * ----------------
-+ */
-+ memset(&limcount, 0, sizeof(limcount));
-+ limcount.type = T_Const;
-+ limcount.consttype = INT4OID;
-+ limcount.constlen = sizeof(int4);
-+ limcount.constvalue = (Datum)count;
-+ limcount.constisnull = FALSE;
-+ limcount.constbyval = TRUE;
-+ limcount.constisset = FALSE;
-+ limcount.constiscast = FALSE;
-+
-+ /* ----------------
- * get the portal from the portal name
- * ----------------
- */
-***************
-*** 176,182 ****
- PortalExecutorHeapMemory = (MemoryContext)
- PortalGetHeapMemory(portal);
-
-! ExecutorRun(queryDesc, PortalGetState(portal), feature, count);
-
- if (dest == None) /* MOVE */
- pfree(queryDesc);
---- 192,198 ----
- PortalExecutorHeapMemory = (MemoryContext)
- PortalGetHeapMemory(portal);
-
-! ExecutorRun(queryDesc, PortalGetState(portal), feature, (Node *)NULL, (Node *)&limcount);
-
- if (dest == None) /* MOVE */
- pfree(queryDesc);
-diff -cr src.orig/backend/executor/execMain.c src/backend/executor/execMain.c
-*** src.orig/backend/executor/execMain.c Fri Oct 16 11:53:38 1998
---- src/backend/executor/execMain.c Fri Oct 16 20:05:19 1998
-***************
-*** 64,69 ****
---- 64,70 ----
- static void EndPlan(Plan *plan, EState *estate);
- static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
- Query *parseTree, CmdType operation,
-+ int offsetTuples,
- int numberTuples, ScanDirection direction,
- void (*printfunc) ());
- static void ExecRetrieve(TupleTableSlot *slot, void (*printfunc) (),
-***************
-*** 163,169 ****
- * ----------------------------------------------------------------
- */
- TupleTableSlot *
-! ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
- {
- CmdType operation;
- Query *parseTree;
---- 164,170 ----
- * ----------------------------------------------------------------
- */
- TupleTableSlot *
-! ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, Node *limoffset, Node *limcount)
- {
- CmdType operation;
- Query *parseTree;
-***************
-*** 171,176 ****
---- 172,179 ----
- TupleTableSlot *result;
- CommandDest dest;
- void (*destination) ();
-+ int offset = 0;
-+ int count = 0;
-
- /******************
- * sanity checks
-***************
-*** 191,196 ****
---- 194,289 ----
- estate->es_processed = 0;
- estate->es_lastoid = InvalidOid;
-
-+ /******************
-+ * if given get the offset of the LIMIT clause
-+ ******************
-+ */
-+ if (limoffset != NULL)
-+ {
-+ Const *coffset;
-+ Param *poffset;
-+ ParamListInfo paramLI;
-+ int i;
-+
-+ switch (nodeTag(limoffset))
-+ {
-+ case T_Const:
-+ coffset = (Const *)limoffset;
-+ offset = (int)(coffset->constvalue);
-+ break;
-+
-+ case T_Param:
-+ poffset = (Param *)limoffset;
-+ paramLI = estate->es_param_list_info;
-+
-+ if (paramLI == NULL)
-+ elog(ERROR, "parameter for limit offset not in executor state");
-+ for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
-+ {
-+ if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == poffset->paramid)
-+ break;
-+ }
-+ if (paramLI[i].kind == PARAM_INVALID)
-+ elog(ERROR, "parameter for limit offset not in executor state");
-+ if (paramLI[i].isnull)
-+ elog(ERROR, "limit offset cannot be NULL value");
-+ offset = (int)(paramLI[i].value);
-+
-+ break;
-+
-+ default:
-+ elog(ERROR, "unexpected node type %d as limit offset", nodeTag(limoffset));
-+ }
-+
-+ if (offset < 0)
-+ elog(ERROR, "limit offset cannot be negative");
-+ }
-+
-+ /******************
-+ * if given get the count of the LIMIT clause
-+ ******************
-+ */
-+ if (limcount != NULL)
-+ {
-+ Const *ccount;
-+ Param *pcount;
-+ ParamListInfo paramLI;
-+ int i;
-+
-+ switch (nodeTag(limcount))
-+ {
-+ case T_Const:
-+ ccount = (Const *)limcount;
-+ count = (int)(ccount->constvalue);
-+ break;
-+
-+ case T_Param:
-+ pcount = (Param *)limcount;
-+ paramLI = estate->es_param_list_info;
-+
-+ if (paramLI == NULL)
-+ elog(ERROR, "parameter for limit count not in executor state");
-+ for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
-+ {
-+ if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == pcount->paramid)
-+ break;
-+ }
-+ if (paramLI[i].kind == PARAM_INVALID)
-+ elog(ERROR, "parameter for limit count not in executor state");
-+ if (paramLI[i].isnull)
-+ elog(ERROR, "limit count cannot be NULL value");
-+ count = (int)(paramLI[i].value);
-+
-+ break;
-+
-+ default:
-+ elog(ERROR, "unexpected node type %d as limit count", nodeTag(limcount));
-+ }
-+
-+ if (count < 0)
-+ elog(ERROR, "limit count cannot be negative");
-+ }
-+
- switch (feature)
- {
-
-***************
-*** 199,205 ****
- plan,
- parseTree,
- operation,
-! ALL_TUPLES,
- ForwardScanDirection,
- destination);
- break;
---- 292,299 ----
- plan,
- parseTree,
- operation,
-! offset,
-! count,
- ForwardScanDirection,
- destination);
- break;
-***************
-*** 208,213 ****
---- 302,308 ----
- plan,
- parseTree,
- operation,
-+ offset,
- count,
- ForwardScanDirection,
- destination);
-***************
-*** 222,227 ****
---- 317,323 ----
- plan,
- parseTree,
- operation,
-+ offset,
- count,
- BackwardScanDirection,
- destination);
-***************
-*** 237,242 ****
---- 333,339 ----
- plan,
- parseTree,
- operation,
-+ 0,
- ONE_TUPLE,
- ForwardScanDirection,
- destination);
-***************
-*** 691,696 ****
---- 788,794 ----
- Plan *plan,
- Query *parseTree,
- CmdType operation,
-+ int offsetTuples,
- int numberTuples,
- ScanDirection direction,
- void (*printfunc) ())
-***************
-*** 742,747 ****
---- 840,859 ----
- {
- result = NULL;
- break;
-+ }
-+
-+ /******************
-+ * For now we completely execute the plan and skip
-+ * result tuples if requested by LIMIT offset.
-+ * Finally we should try to do it in deeper levels
-+ * if possible (during index scan)
-+ * - Jan
-+ ******************
-+ */
-+ if (offsetTuples > 0)
-+ {
-+ --offsetTuples;
-+ continue;
- }
-
- /******************
-diff -cr src.orig/backend/executor/functions.c src/backend/executor/functions.c
-*** src.orig/backend/executor/functions.c Fri Oct 16 11:53:38 1998
---- src/backend/executor/functions.c Fri Oct 16 19:01:02 1998
-***************
-*** 130,135 ****
---- 130,138 ----
- None);
- estate = CreateExecutorState();
-
-+ if (queryTree->limitOffset != NULL || queryTree->limitCount != NULL)
-+ elog(ERROR, "LIMIT clause from SQL functions not yet implemented");
-+
- if (nargs > 0)
- {
- int i;
-***************
-*** 200,206 ****
-
- feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
-
-! return ExecutorRun(es->qd, es->estate, feature, 0);
- }
-
- static void
---- 203,209 ----
-
- feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
-
-! return ExecutorRun(es->qd, es->estate, feature, (Node *)NULL, (Node *)NULL);
- }
-
- static void
-diff -cr src.orig/backend/executor/spi.c src/backend/executor/spi.c
-*** src.orig/backend/executor/spi.c Fri Oct 16 11:53:39 1998
---- src/backend/executor/spi.c Fri Oct 16 19:25:33 1998
-***************
-*** 791,796 ****
---- 791,798 ----
- bool isRetrieveIntoRelation = false;
- char *intoName = NULL;
- int res;
-+ Const tcount_const;
-+ Node *count = NULL;
-
- switch (operation)
- {
-***************
-*** 825,830 ****
---- 827,865 ----
- return SPI_ERROR_OPUNKNOWN;
- }
-
-+ /* ----------------
-+ * Get the query LIMIT tuple count
-+ * ----------------
-+ */
-+ if (parseTree->limitCount != NULL)
-+ {
-+ /* ----------------
-+ * A limit clause in the parsetree overrides the
-+ * tcount parameter
-+ * ----------------
-+ */
-+ count = parseTree->limitCount;
-+ }
-+ else
-+ {
-+ /* ----------------
-+ * No LIMIT clause in parsetree. Use a local Const node
-+ * to put tcount into it
-+ * ----------------
-+ */
-+ memset(&tcount_const, 0, sizeof(tcount_const));
-+ tcount_const.type = T_Const;
-+ tcount_const.consttype = INT4OID;
-+ tcount_const.constlen = sizeof(int4);
-+ tcount_const.constvalue = (Datum)tcount;
-+ tcount_const.constisnull = FALSE;
-+ tcount_const.constbyval = TRUE;
-+ tcount_const.constisset = FALSE;
-+ tcount_const.constiscast = FALSE;
-+
-+ count = (Node *)&tcount_const;
-+ }
-+
- if (state == NULL) /* plan preparation */
- return res;
- #ifdef SPI_EXECUTOR_STATS
-***************
-*** 845,851 ****
- return SPI_OK_CURSOR;
- }
-
-! ExecutorRun(queryDesc, state, EXEC_FOR, tcount);
-
- _SPI_current->processed = state->es_processed;
- if (operation == CMD_SELECT && queryDesc->dest == SPI)
---- 880,886 ----
- return SPI_OK_CURSOR;
- }
-
-! ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
-
- _SPI_current->processed = state->es_processed;
- if (operation == CMD_SELECT && queryDesc->dest == SPI)
-diff -cr src.orig/backend/parser/analyze.c src/backend/parser/analyze.c
-*** src.orig/backend/parser/analyze.c Fri Oct 16 11:53:41 1998
---- src/backend/parser/analyze.c Fri Oct 16 13:29:27 1998
-***************
-*** 180,186 ****
---- 180,190 ----
-
- case T_SelectStmt:
- if (!((SelectStmt *) parseTree)->portalname)
-+ {
- result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
-+ result->limitOffset = ((SelectStmt *)parseTree)->limitOffset;
-+ result->limitCount = ((SelectStmt *)parseTree)->limitCount;
-+ }
- else
- result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
- break;
-diff -cr src.orig/backend/parser/gram.y src/backend/parser/gram.y
-*** src.orig/backend/parser/gram.y Fri Oct 16 11:53:42 1998
---- src/backend/parser/gram.y Sun Oct 18 22:20:36 1998
-***************
-*** 45,50 ****
---- 45,51 ----
- #include "catalog/catname.h"
- #include "utils/elog.h"
- #include "access/xact.h"
-+ #include "catalog/pg_type.h"
-
- #ifdef MULTIBYTE
- #include "mb/pg_wchar.h"
-***************
-*** 163,169 ****
- sort_clause, sortby_list, index_params, index_list, name_list,
- from_clause, from_list, opt_array_bounds, nest_array_bounds,
- expr_list, attrs, res_target_list, res_target_list2,
-! def_list, opt_indirection, group_clause, TriggerFuncArgs
-
- %type func_return
- %type set_opt
---- 164,171 ----
- sort_clause, sortby_list, index_params, index_list, name_list,
- from_clause, from_list, opt_array_bounds, nest_array_bounds,
- expr_list, attrs, res_target_list, res_target_list2,
-! def_list, opt_indirection, group_clause, TriggerFuncArgs,
-! opt_select_limit
-
- %type func_return
- %type set_opt
-***************
-*** 192,197 ****
---- 194,201 ----
-
- %type fetch_how_many
-
-+ %type select_limit_value select_offset_value
-+
- %type OptSeqList
- %type OptSeqElem
-
-***************
-*** 267,273 ****
- FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
- GRANT, GROUP, HAVING, HOUR_P,
- IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
-! JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LOCAL,
- MATCH, MINUTE_P, MONTH_P, NAMES,
- NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL_P, NUMERIC,
- OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
---- 271,277 ----
- FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
- GRANT, GROUP, HAVING, HOUR_P,
- IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
-! JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LIMIT, LOCAL,
- MATCH, MINUTE_P, MONTH_P, NAMES,
- NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL_P, NUMERIC,
- OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
-***************
-*** 299,305 ****
- INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
- LANCOMPILER, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
- NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
-! OIDS, OPERATOR, PASSWORD, PROCEDURAL,
- RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
- SEQUENCE, SERIAL, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
- UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
---- 303,309 ----
- INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
- LANCOMPILER, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
- NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
-! OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL,
- RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
- SEQUENCE, SERIAL, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
- UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
-***************
-*** 2591,2596 ****
---- 2595,2601 ----
- result from_clause where_clause
- group_clause having_clause
- union_clause sort_clause
-+ opt_select_limit
- {
- SelectStmt *n = makeNode(SelectStmt);
- n->unique = $2;
-***************
-*** 2602,2607 ****
---- 2607,2622 ----
- n->havingClause = $8;
- n->unionClause = $9;
- n->sortClause = $10;
-+ if ($11 != NIL)
-+ {
-+ n->limitOffset = nth(0, $11);
-+ n->limitCount = nth(1, $11);
-+ }
-+ else
-+ {
-+ n->limitOffset = NULL;
-+ n->limitCount = NULL;
-+ }
- $$ = (Node *)n;
- }
- ;
-***************
-*** 2699,2704 ****
---- 2714,2794 ----
- | ASC { $$ = "<"; }
- | DESC { $$ = ">"; }
- | /*EMPTY*/ { $$ = "<"; /*default*/ }
-+ ;
-+
-+ opt_select_limit: LIMIT select_offset_value ',' select_limit_value
-+ { $$ = lappend(lappend(NIL, $2), $4); }
-+ | LIMIT select_limit_value OFFSET select_offset_value
-+ { $$ = lappend(lappend(NIL, $4), $2); }
-+ | LIMIT select_limit_value
-+ { $$ = lappend(lappend(NIL, NULL), $2); }
-+ | OFFSET select_offset_value LIMIT select_limit_value
-+ { $$ = lappend(lappend(NIL, $2), $4); }
-+ | OFFSET select_offset_value
-+ { $$ = lappend(lappend(NIL, $2), NULL); }
-+ | /* EMPTY */
-+ { $$ = NIL; }
-+ ;
-+
-+ select_limit_value: Iconst
-+ {
-+ Const *n = makeNode(Const);
-+
-+ if ($1 < 1)
-+ elog(ERROR, "selection limit must be ALL or a positive integer value > 0");
-+
-+ n->consttype = INT4OID;
-+ n->constlen = sizeof(int4);
-+ n->constvalue = (Datum)$1;
-+ n->constisnull = FALSE;
-+ n->constbyval = TRUE;
-+ n->constisset = FALSE;
-+ n->constiscast = FALSE;
-+ $$ = (Node *)n;
-+ }
-+ | ALL
-+ {
-+ Const *n = makeNode(Const);
-+ n->consttype = INT4OID;
-+ n->constlen = sizeof(int4);
-+ n->constvalue = (Datum)0;
-+ n->constisnull = FALSE;
-+ n->constbyval = TRUE;
-+ n->constisset = FALSE;
-+ n->constiscast = FALSE;
-+ $$ = (Node *)n;
-+ }
-+ | PARAM
-+ {
-+ Param *n = makeNode(Param);
-+ n->paramkind = PARAM_NUM;
-+ n->paramid = $1;
-+ n->paramtype = INT4OID;
-+ $$ = (Node *)n;
-+ }
-+ ;
-+
-+ select_offset_value: Iconst
-+ {
-+ Const *n = makeNode(Const);
-+
-+ n->consttype = INT4OID;
-+ n->constlen = sizeof(int4);
-+ n->constvalue = (Datum)$1;
-+ n->constisnull = FALSE;
-+ n->constbyval = TRUE;
-+ n->constisset = FALSE;
-+ n->constiscast = FALSE;
-+ $$ = (Node *)n;
-+ }
-+ | PARAM
-+ {
-+ Param *n = makeNode(Param);
-+ n->paramkind = PARAM_NUM;
-+ n->paramid = $1;
-+ n->paramtype = INT4OID;
-+ $$ = (Node *)n;
-+ }
- ;
-
- /*
-diff -cr src.orig/backend/parser/keywords.c src/backend/parser/keywords.c
-*** src.orig/backend/parser/keywords.c Fri Oct 16 11:53:42 1998
---- src/backend/parser/keywords.c Sun Oct 18 22:13:29 1998
-***************
-*** 128,133 ****
---- 128,134 ----
- {"leading", LEADING},
- {"left", LEFT},
- {"like", LIKE},
-+ {"limit", LIMIT},
- {"listen", LISTEN},
- {"load", LOAD},
- {"local", LOCAL},
-***************
-*** 156,161 ****
---- 157,163 ----
- {"null", NULL_P},
- {"numeric", NUMERIC},
- {"of", OF},
-+ {"offset", OFFSET},
- {"oids", OIDS},
- {"old", CURRENT},
- {"on", ON},
-diff -cr src.orig/backend/rewrite/rewriteDefine.c src/backend/rewrite/rewriteDefine.c
-*** src.orig/backend/rewrite/rewriteDefine.c Fri Oct 16 11:53:46 1998
---- src/backend/rewrite/rewriteDefine.c Fri Oct 16 13:48:55 1998
-***************
-*** 312,317 ****
---- 312,323 ----
- heap_close(event_relation);
-
- /*
-+ * LIMIT in view is not supported
-+ */
-+ if (query->limitOffset != NULL || query->limitCount != NULL)
-+ elog(ERROR, "LIMIT clause not supported in views");
-+
-+ /*
- * ... and finally the rule must be named _RETviewname.
- */
- sprintf(expected_name, "_RET%s", event_obj->relname);
-diff -cr src.orig/backend/tcop/pquery.c src/backend/tcop/pquery.c
-*** src.orig/backend/tcop/pquery.c Fri Oct 16 11:53:47 1998
---- src/backend/tcop/pquery.c Fri Oct 16 14:02:36 1998
-***************
-*** 40,46 ****
- #include "commands/command.h"
-
- static char *CreateOperationTag(int operationType);
-! static void ProcessQueryDesc(QueryDesc *queryDesc);
-
-
- /* ----------------------------------------------------------------
---- 40,46 ----
- #include "commands/command.h"
-
- static char *CreateOperationTag(int operationType);
-! static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount);
-
-
- /* ----------------------------------------------------------------
-***************
-*** 205,211 ****
- * ----------------------------------------------------------------
- */
- static void
-! ProcessQueryDesc(QueryDesc *queryDesc)
- {
- Query *parseTree;
- Plan *plan;
---- 205,211 ----
- * ----------------------------------------------------------------
- */
- static void
-! ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
- {
- Query *parseTree;
- Plan *plan;
-***************
-*** 330,336 ****
- * actually run the plan..
- * ----------------
- */
-! ExecutorRun(queryDesc, state, EXEC_RUN, 0);
-
- /* save infos for EndCommand */
- UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
---- 330,336 ----
- * actually run the plan..
- * ----------------
- */
-! ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);
-
- /* save infos for EndCommand */
- UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
-***************
-*** 373,377 ****
- print_plan(plan, parsetree);
- }
- else
-! ProcessQueryDesc(queryDesc);
- }
---- 373,377 ----
- print_plan(plan, parsetree);
- }
- else
-! ProcessQueryDesc(queryDesc, parsetree->limitOffset, parsetree->limitCount);
- }
-diff -cr src.orig/include/executor/executor.h src/include/executor/executor.h
-*** src.orig/include/executor/executor.h Fri Oct 16 11:53:56 1998
---- src/include/executor/executor.h Fri Oct 16 12:04:17 1998
-***************
-*** 83,89 ****
- * prototypes from functions in execMain.c
- */
- extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
-! extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count);
- extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
- extern HeapTuple ExecConstraints(char *caller, Relation rel, HeapTuple tuple);
- #ifdef QUERY_LIMIT
---- 83,89 ----
- * prototypes from functions in execMain.c
- */
- extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
-! extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, Node *limoffset, Node *limcount);
- extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
- extern HeapTuple ExecConstraints(char *caller, Relation rel, HeapTuple tuple);
- #ifdef QUERY_LIMIT
-
-