Extensibility of the PostgreSQL wire protocol
The following is a request for discussion and comments, not a refined
proposal accompanied by a working patch.
As recently publicly announced Amazon Web Services is working on Babelfish,
a set of extensions that will allow PostgreSQL to be compatible with other
database systems. One part of this will be an extension that allows
PostgreSQL to listen on a secondary port and process a different wire
protocol. The first extension we are creating in this direction is handling
of the Tabular Data Stream (TDS), used by Sybase and Microsoft SQL-Server
databases. It is more efficient to build an extension, that can handle the
TDS protocol inside the backend, than creating a proxy process that
translates from TDS to libpq protocol and back.
Creating the necessary infrastructure in the postmaster and backend will
open up more possibilities, that are not tied to our compatibility efforts.
Possible use cases for wire protocol extensibility include the development
of a completely new, not backwards compatible PostgreSQL protocol or
extending the existing wire protocol with things like 3rd party connection
pool specific features (like transfer of file descriptors between pool and
working backend for example).
Our current plan is to create a new set of API calls and hooks that allow
to register additional wire protocols. The existing backend libpq
implementation will be modified to register itself using the new API. This
will serve as a proof of concept as well as ensure that the API definition
is not slanted towards a specific protocol. It is also similar to the way
table access methods and compression methods are added.
A wire protocol extension will be a standard PostgreSQL dynamic loadable
extension module. The wire protocol extensions to load will be listed in
the shared_preload_libraries GUC. The extension's Init function will
register a hook function to be called where the postmaster is currently
creating the libpq server sockets. This hook callback will then create the
server sockets and register them for monitoring via select(2) in the
postmaster main loop, using a new API function. Part of the registration
information are callback functions to invoke for accepting and
authenticating incoming connections, error reporting as well as a function
that will implement the TCOP loop for the protocol. Ongoing work on the TDS
protocol has shown us that different protocols make it desirable to have
separate implementations of the TCOP loop. The TCOP function will return
only after the connection has been terminated. Fortunately half the
interface already exists since the sending of result sets is implemented
via callback functions that are registered as the dest receiver, which
works pretty well in our current code.
Regards, Jan
--
Jan Wieck
Principal Database Engineer
Amazon Web Services
On Mon, Jan 25, 2021 at 10:07 AM Jan Wieck <jan@wi3ck.info> wrote:
The following is a request for discussion and comments, not a refined
proposal accompanied by a working patch.
After implementing this three different ways inside the backend over the
years, I landed on almost this identical approach for handling the MySQL,
TDS, MongoDB, and Oracle protocols for NEXTGRES.
Initially, each was implemented as an background worker extension which had
to handle its own networking, passing the fd off to new protocol-specific
connections, etc. This worked, but duplicate a good amount of logic. It
would be great to have a standard, loadable, way to add support for a new
protocol.
--
Jonah H. Harris
Hi Jonah,
On Mon, Jan 25, 2021 at 10:18 AM Jonah H. Harris <jonah.harris@gmail.com>
wrote:
On Mon, Jan 25, 2021 at 10:07 AM Jan Wieck <jan@wi3ck.info> wrote:
The following is a request for discussion and comments, not a refined
proposal accompanied by a working patch.After implementing this three different ways inside the backend over the
years, I landed on almost this identical approach for handling the MySQL,
TDS, MongoDB, and Oracle protocols for NEXTGRES.
Could any of that be open sourced? It would be an excellent addition to add
one of those as example code.
Regards, Jan
Initially, each was implemented as an background worker extension which
had to handle its own networking, passing the fd off to new
protocol-specific connections, etc. This worked, but duplicate a good
amount of logic. It would be great to have a standard, loadable, way to add
support for a new protocol.--
Jonah H. Harris
--
Jan Wieck
On Mon, Jan 25, 2021 at 10:07 AM Jan Wieck <jan@wi3ck.info> wrote:
Our current plan is to create a new set of API calls and hooks that allow to register additional wire protocols. The existing backend libpq implementation will be modified to register itself using the new API. This will serve as a proof of concept as well as ensure that the API definition is not slanted towards a specific protocol. It is also similar to the way table access methods and compression methods are added.
If we're going to end up with an open source implementation of
something useful in contrib or whatever, then I think this is fine.
But, if not, then we're just making it easier for Amazon to do
proprietary stuff without getting any benefit for the open-source
project. In fact, in that case PostgreSQL would ensure have to somehow
ensure that the hooks don't get broken without having any code that
actually uses them, so not only would the project get no benefit, but
it would actually incur a small tax. I wouldn't say that's an
absolutely show-stopper, but it definitely isn't my first choice.
--
Robert Haas
EDB: http://www.enterprisedb.com
On Wed, Feb 10, 2021 at 1:43 PM Robert Haas <robertmhaas@gmail.com> wrote:
On Mon, Jan 25, 2021 at 10:07 AM Jan Wieck <jan@wi3ck.info> wrote:
Our current plan is to create a new set of API calls and hooks that
allow to register additional wire protocols. The existing backend libpq
implementation will be modified to register itself using the new API. This
will serve as a proof of concept as well as ensure that the API definition
is not slanted towards a specific protocol. It is also similar to the way
table access methods and compression methods are added.
If we're going to end up with an open source implementation of
something useful in contrib or whatever, then I think this is fine.
But, if not, then we're just making it easier for Amazon to do
proprietary stuff without getting any benefit for the open-source
project. In fact, in that case PostgreSQL would ensure have to somehow
ensure that the hooks don't get broken without having any code that
actually uses them, so not only would the project get no benefit, but
it would actually incur a small tax. I wouldn't say that's an
absolutely show-stopper, but it definitely isn't my first choice.
As far I understood Jan's proposal is to add enough hooks on PostgreSQL to
enable us to extend the wire protocol and add a contrib module as an
example (maybe TDS, HTTP or just adding new capabilities to current
implementation).
Regards,
--
Fabrízio de Royes Mello
PostgreSQL Developer at OnGres Inc. - https://ongres.com
On Wed, Feb 10, 2021 at 11:43 AM Robert Haas <robertmhaas@gmail.com> wrote:
On Mon, Jan 25, 2021 at 10:07 AM Jan Wieck <jan@wi3ck.info> wrote:
Our current plan is to create a new set of API calls and hooks that
allow to register additional wire protocols. The existing backend libpq
implementation will be modified to register itself using the new API. This
will serve as a proof of concept as well as ensure that the API definition
is not slanted towards a specific protocol. It is also similar to the way
table access methods and compression methods are added.If we're going to end up with an open source implementation of
something useful in contrib or whatever, then I think this is fine.
But, if not, then we're just making it easier for Amazon to do
proprietary stuff without getting any benefit for the open-source
project. In fact, in that case PostgreSQL would ensure have to somehow
ensure that the hooks don't get broken without having any code that
actually uses them, so not only would the project get no benefit, but
it would actually incur a small tax. I wouldn't say that's an
absolutely show-stopper, but it definitely isn't my first choice.
Agreed on adding substantial hooks if they're not likely to be used. While
I haven't yet seen AWS' implementation or concrete proposal, given the
people involved, I assume it's fairly similar to how I implemented it.
Assuming that's correct and it doesn't require substantial redevelopment,
I'd certainly open-source my MySQL-compatible protocol and parser
implementation. From my perspective, it would be awesome if these could be
done as extensions.
While I'm not planning to open source it as of yet, for my
Oracle-compatible stuff, I don't think I'd be able to do anything other
than the protocol as an extension given the core-related changes similar to
what EDB has to do. I don't think there's any easy way to get around that.
But, for the protocol and any type of simple translation to Postgres'
dialect, I think that could easily be hook-based.
--
Jonah H. Harris
Robert Haas <robertmhaas@gmail.com> writes:
If we're going to end up with an open source implementation of
something useful in contrib or whatever, then I think this is fine.
But, if not, then we're just making it easier for Amazon to do
proprietary stuff without getting any benefit for the open-source
project. In fact, in that case PostgreSQL would ensure have to somehow
ensure that the hooks don't get broken without having any code that
actually uses them, so not only would the project get no benefit, but
it would actually incur a small tax. I wouldn't say that's an
absolutely show-stopper, but it definitely isn't my first choice.
As others noted, a test module could be built to add some coverage here.
What I'm actually more concerned about, in this whole line of development,
is the follow-on requests that will surely occur to kluge up Postgres
to make its behavior more like $whatever. As in "well, now that we
can serve MySQL clients protocol-wise, can't we pretty please have a
mode that makes the parser act more like MySQL". If we start having
modes for MySQL identifier quoting, Oracle outer join syntax, yadda
yadda, it's going to be way more of a maintenance nightmare than some
hook functions. So if we accept any patch along this line, I want to
drive a hard stake in the ground that the answer to that sort of thing
will be NO.
Assuming we're going to keep to that, though, it seems like people
doing this sort of thing will inevitably end up with a fork anyway.
So maybe we should just not bother with the first step either.
regards, tom lane
On Wed, Feb 10, 2021 at 1:10 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
What I'm actually more concerned about, in this whole line of development,
is the follow-on requests that will surely occur to kluge up Postgres
to make its behavior more like $whatever. As in "well, now that we
can serve MySQL clients protocol-wise, can't we pretty please have a
mode that makes the parser act more like MySQL". If we start having
modes for MySQL identifier quoting, Oracle outer join syntax, yadda
yadda, it's going to be way more of a maintenance nightmare than some
hook functions. So if we accept any patch along this line, I want to
drive a hard stake in the ground that the answer to that sort of thing
will be NO.
Actually, a substantial amount can be done with hooks. For Oracle, which is
substantially harder than MySQL, I have a completely separate parser that
generates a PG-compatible parse tree packaged up as an extension. To handle
autonomous transactions, database links, hierarchical query conversion,
hints, and some execution-related items requires core changes. But, the
protocol and parsing can definitely be done with hooks. And, as was
mentioned previously, this isn't tied directly to emulating another
database - it would enable us to support an HTTP-ish interface directly in
the server as an extension as well. A lot of this can be done with
background worker extensions now, which is how my stuff was primarily
architected, but it's hacky when it comes to areas where the items Jan
discussed could clean things up and make them more pluggable.
Assuming we're going to keep to that, though, it seems like people
doing this sort of thing will inevitably end up with a fork anyway.
So maybe we should just not bother with the first step either.
Perhaps I'm misunderstanding you, but I wouldn't throw this entire idea out
(which enables a substantial addition of extensible functionality with a
limited set of touchpoints) on the premise of future objections.
--
Jonah H. Harris
"Jonah H. Harris" <jonah.harris@gmail.com> writes:
On Wed, Feb 10, 2021 at 1:10 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
... If we start having
modes for MySQL identifier quoting, Oracle outer join syntax, yadda
yadda, it's going to be way more of a maintenance nightmare than some
hook functions. So if we accept any patch along this line, I want to
drive a hard stake in the ground that the answer to that sort of thing
will be NO.
Actually, a substantial amount can be done with hooks. For Oracle, which is
substantially harder than MySQL, I have a completely separate parser that
generates a PG-compatible parse tree packaged up as an extension. To handle
autonomous transactions, database links, hierarchical query conversion,
hints, and some execution-related items requires core changes.
That is a spot-on definition of where I do NOT want to end up. Hooks
everywhere and enormous extensions that break anytime we change anything
in the core. It's not really clear that anybody is going to find that
more maintainable than a straight fork, except to the extent that it
enables the erstwhile forkers to shove some of their work onto the PG
community.
My feeling about this is if you want to use Oracle, go use Oracle.
Don't ask PG to take on a ton of maintenance issues so you can have
a frankenOracle.
regards, tom lane
On Wed, Feb 10, 2021 at 2:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
That is a spot-on definition of where I do NOT want to end up. Hooks
everywhere and enormous extensions that break anytime we change anything
in the core. It's not really clear that anybody is going to find that
more maintainable than a straight fork, except to the extent that it
enables the erstwhile forkers to shove some of their work onto the PG
community.
Given the work over the last few major releases to make several other
aspects of Postgres pluggable, how is implementing a pluggable protocol API
any different?
To me, this sounds more like a philosophical disagreement with how people
could potentially use Postgres than a technical one. My point is only that,
using current PG functionality, I could equally write a pluggable storage
interface for my Oracle and InnoDB data file readers/writers, which would
similarly allow for the creation of a Postgres franken-Oracle by extension
only.
I don't think anyone is asking for hooks for all the things I mentioned - a
pluggable transaction manager, for example, doesn't make much sense. But,
when it comes to having actually done this vs. posited about its
usefulness, I'd say it has some merit and doesn't really introduce that
much complexity or maintenance overhead to core - whether the extensions
still work properly is up to the extension authors... isn't that the whole
point of extensions?
--
Jonah H. Harris
On Wed, Feb 10, 2021 at 11:43 AM Robert Haas <robertmhaas@gmail.com> wrote:
On Mon, Jan 25, 2021 at 10:07 AM Jan Wieck <jan@wi3ck.info> wrote:
Our current plan is to create a new set of API calls and hooks that
allow to register additional wire protocols. The existing backend libpq
implementation will be modified to register itself using the new API. This
will serve as a proof of concept as well as ensure that the API definition
is not slanted towards a specific protocol. It is also similar to the way
table access methods and compression methods are added.If we're going to end up with an open source implementation of
something useful in contrib or whatever, then I think this is fine.
But, if not, then we're just making it easier for Amazon to do
proprietary stuff without getting any benefit for the open-source
project. In fact, in that case PostgreSQL would ensure have to somehow
ensure that the hooks don't get broken without having any code that
actually uses them, so not only would the project get no benefit, but
it would actually incur a small tax. I wouldn't say that's an
absolutely show-stopper, but it definitely isn't my first choice.
At this very moment there are several parts to this. One is the hooks to
make wire protocols into loadable modules, which is what this effort is
about. Another is the TDS protocol as it is being implemented for Babelfish
and third is the Babelfish extension itself. Both will require additional
hooks and APIs I am not going to address here. I consider them not material
to my effort.
As for making the wire protocol itself expandable I really see a lot of
potential outside of what Amazon wants here. And I would not be advertising
it if it would be for Babelfish alone. As I laid out, just the ability for
a third party to add additional messages for special connection pool
support would be enough to make it useful. There also have been discussions
in the JDBC subproject to combine certain messages into one single message.
Why not allow the JDBC project to develop their own, JDBC-optimized backend
side? Last but not least, what would be wrong with listening for MariaDB
clients?
I am planning on a follow up project to this, demoting libpq itself to just
another loadable protocol. Just the way procedural languages are all on the
same level because that is how I developed the loadable, procedural
language handler all those years ago.
Considering how spread out and quite frankly unorganized our wire protocol
handling is, this is not a small order.
Regards, Jan
--
Robert Haas
EDB: http://www.enterprisedb.com
--
Jan Wieck
On Wed, Feb 10, 2021 at 2:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
That is a spot-on definition of where I do NOT want to end up. Hooks
everywhere and enormous extensions that break anytime we change anything
in the core. It's not really clear that anybody is going to find that
more maintainable than a straight fork, except to the extent that it
enables the erstwhile forkers to shove some of their work onto the PG
community.
+1.
Making the lexer and parser extensible seems desirable to me. It would
be beneficial not only for companies like EDB and Amazon that might
want to extend the grammar in various ways, but also for extension
authors. However, it's vastly harder than Jan's proposal to make the
wire protocol pluggable. The wire protocol is pretty well-isolated
from the rest of the system. As long as you can get queries out of the
packets the client sends and package up the results to send back, it's
all good. The parser, on the other hand, is not at all well-isolated
from the rest of the system. There's a LOT of code that knows a whole
lot of stuff about the structure of parse trees, so your variant
parser can't produce parse trees for new kinds of DDL, or for new
query constructs. And if it parsed some completely different syntax
where, say, joins were not explicit, it would still have to figure out
how to represent them in a way that looked just like it came out of
the regular parser -- otherwise, parse analysis and query planning and
so forth are not going to work, unless you go and change a lot of
other code too, and I don't really have any idea how we could solve
that, even in theory. But that kind of thing just isn't a problem for
the proposal on this thread.
That being said, I'm not in favor of transferring maintenance work to
the community for this set of hooks any more than I am for something
on the parsing side. In general, I'm in favor of as much extensibility
as we can reasonably create, but with a complicated proposal like this
one, the community should expect to be able to get something out of
it. And so far what I hear Jan saying is that these hooks could in
theory be used for things other than Amazon's proprietary efforts and
those things could in theory bring benefits to the community, but
there are no actual plans to do anything with this that would benefit
anyone other than Amazon. Which seems to bring us right back to
expecting the community to maintain things for the benefit of
third-party forks.
--
Robert Haas
EDB: http://www.enterprisedb.com
On Thu, Feb 11, 2021 at 9:28 AM Robert Haas <robertmhaas@gmail.com> wrote:
That being said, I'm not in favor of transferring maintenance work to
the community for this set of hooks any more than I am for something
on the parsing side. In general, I'm in favor of as much extensibility
as we can reasonably create, but with a complicated proposal like this
one, the community should expect to be able to get something out of
it. And so far what I hear Jan saying is that these hooks could in
theory be used for things other than Amazon's proprietary efforts and
those things could in theory bring benefits to the community, but
there are no actual plans to do anything with this that would benefit
anyone other than Amazon. Which seems to bring us right back to
expecting the community to maintain things for the benefit of
third-party forks.
I'm quite sure I said I'd open source my MySQL implementation, which allows
Postgres to appear to MySQL clients as a MySQL/MariaDB server. This is
neither proprietary nor Amazon-related and makes Postgres substantially
more useful for a large number of applications.
As Jan said in his last email, they're not proposing all the different
aspects needed. In fact, nothing has actually been proposed yet. This is an
entirely philosophical debate. I don't even know what's being proposed at
this point - I just know it *could* be useful. Let's just wait and see what
is actually proposed before shooting it down, yes?
--
Jonah H. Harris
On Thu, Feb 11, 2021 at 9:42 AM Jonah H. Harris <jonah.harris@gmail.com> wrote:
I'm quite sure I said I'd open source my MySQL implementation, which allows Postgres to appear to MySQL clients as a MySQL/MariaDB server. This is neither proprietary nor Amazon-related and makes Postgres substantially more useful for a large number of applications.
OK. There's stuff to think about there, too: do we want that in
contrib? Is it in good enough shape to be in contrib even if we did?
If it's not in contrib, how do we incorporate it into, say, the
buildfarm, so that we know if we break something? Is it actively
maintained and stable, so that if it needs adjustment for upstream
changes we can count on that getting addressed in a timely fashion? I
don't know the answers to these questions and am not trying to
prejudge, but I think they are important and relevant questions.
As Jan said in his last email, they're not proposing all the different aspects needed. In fact, nothing has actually been proposed yet. This is an entirely philosophical debate. I don't even know what's being proposed at this point - I just know it *could* be useful. Let's just wait and see what is actually proposed before shooting it down, yes?
I don't think I'm trying to shoot anything down, because as I said, I
like extensibility and am generally in favor of it. Rather, I'm
expressing a concern which seems to me to be justified, based on what
was posted. I'm sorry that my tone seems to have aggravated you, but
it wasn't intended to do so.
--
Robert Haas
EDB: http://www.enterprisedb.com
Robert Haas <robertmhaas@gmail.com> writes:
On Thu, Feb 11, 2021 at 9:42 AM Jonah H. Harris <jonah.harris@gmail.com> wrote:
As Jan said in his last email, they're not proposing all the different
aspects needed. In fact, nothing has actually been proposed yet. This
is an entirely philosophical debate. I don't even know what's being
proposed at this point - I just know it *could* be useful. Let's just
wait and see what is actually proposed before shooting it down, yes?
I don't think I'm trying to shoot anything down, because as I said, I
like extensibility and am generally in favor of it. Rather, I'm
expressing a concern which seems to me to be justified, based on what
was posted. I'm sorry that my tone seems to have aggravated you, but
it wasn't intended to do so.
Likewise, the point I was trying to make is that a "pluggable wire
protocol" is only a tiny part of what would be needed to have a credible
MySQL, Oracle, or whatever clone. There are large semantic differences
from those products; there are maintenance issues arising from the fact
that we whack structures like parse trees around all the time; and so on.
Maybe there is some useful thing that can be accomplished here, but we
need to consider the bigger picture rather than believing (without proof)
that a few hook variables will be enough to do anything.
regards, tom lane
On 2/11/21 10:06 AM, Tom Lane wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Thu, Feb 11, 2021 at 9:42 AM Jonah H. Harris <jonah.harris@gmail.com> wrote:
As Jan said in his last email, they're not proposing all the different
aspects needed. In fact, nothing has actually been proposed yet. This
is an entirely philosophical debate. I don't even know what's being
proposed at this point - I just know it *could* be useful. Let's just
wait and see what is actually proposed before shooting it down, yes?I don't think I'm trying to shoot anything down, because as I said, I
like extensibility and am generally in favor of it. Rather, I'm
expressing a concern which seems to me to be justified, based on what
was posted. I'm sorry that my tone seems to have aggravated you, but
it wasn't intended to do so.Likewise, the point I was trying to make is that a "pluggable wire
protocol" is only a tiny part of what would be needed to have a credible
MySQL, Oracle, or whatever clone. There are large semantic differences
from those products; there are maintenance issues arising from the fact
that we whack structures like parse trees around all the time; and so on.
Maybe there is some useful thing that can be accomplished here, but we
need to consider the bigger picture rather than believing (without proof)
that a few hook variables will be enough to do anything.
Yeah. I think we'd need a fairly fully worked implementation to see
where it goes. Is Amazon going to release (under TPL) its TDS
implementation of this? That might go a long way to convincing me this
is worth considering.
cheers
andrew
--
Andrew Dunstan
EDB: https://www.enterprisedb.com
On Thu, Feb 11, 2021 at 10:29 AM Andrew Dunstan <andrew@dunslane.net> wrote:
On 2/11/21 10:06 AM, Tom Lane wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Thu, Feb 11, 2021 at 9:42 AM Jonah H. Harris <jonah.harris@gmail.com>
wrote:
As Jan said in his last email, they're not proposing all the different
aspects needed. In fact, nothing has actually been proposed yet. This
is an entirely philosophical debate. I don't even know what's being
proposed at this point - I just know it *could* be useful. Let's just
wait and see what is actually proposed before shooting it down, yes?I don't think I'm trying to shoot anything down, because as I said, I
like extensibility and am generally in favor of it. Rather, I'm
expressing a concern which seems to me to be justified, based on what
was posted. I'm sorry that my tone seems to have aggravated you, but
it wasn't intended to do so.Likewise, the point I was trying to make is that a "pluggable wire
protocol" is only a tiny part of what would be needed to have a credible
MySQL, Oracle, or whatever clone. There are large semantic differences
from those products; there are maintenance issues arising from the fact
that we whack structures like parse trees around all the time; and so on.
Maybe there is some useful thing that can be accomplished here, but we
need to consider the bigger picture rather than believing (without proof)
that a few hook variables will be enough to do anything.Yeah. I think we'd need a fairly fully worked implementation to see
where it goes. Is Amazon going to release (under TPL) its TDS
implementation of this? That might go a long way to convincing me this
is worth considering.Everything is planned to be released under the Apache 2.0 license so
people are free to do with it as they choose.
On Wed, Feb 10, 2021 at 11:04 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
"Jonah H. Harris" <jonah.harris@gmail.com> writes:
On Wed, Feb 10, 2021 at 1:10 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
... If we start having
modes for MySQL identifier quoting, Oracle outer join syntax, yadda
yadda, it's going to be way more of a maintenance nightmare than some
hook functions. So if we accept any patch along this line, I want to
drive a hard stake in the ground that the answer to that sort of thing
will be NO.Actually, a substantial amount can be done with hooks. For Oracle, which
is
substantially harder than MySQL, I have a completely separate parser that
generates a PG-compatible parse tree packaged up as an extension. Tohandle
autonomous transactions, database links, hierarchical query conversion,
hints, and some execution-related items requires core changes.That is a spot-on definition of where I do NOT want to end up. Hooks
everywhere and enormous extensions that break anytime we change anything
in the core. It's not really clear that anybody is going to find that
more maintainable than a straight fork, except to the extent that it
enables the erstwhile forkers to shove some of their work onto the PG
community.My feeling about this is if you want to use Oracle, go use Oracle.
Don't ask PG to take on a ton of maintenance issues so you can have
a frankenOracle.
PostgreSQL over the last decade spent a considerable amount of time
allowing it to become extensible outside of core. We are now useful in
workloads nobody would have considered in 2004 or 2008.
The more extensibility we add, the LESS we maintain. It is a lot easier to
maintain an API than it is an entire kernel. When I look at all the
interesting features coming from the ecosystem, they are all built on the
hooks that this community worked so hard to create. This idea is an
extension of that and a result of the community's success.
The more extensible we make PostgreSQL, the more the hacker community can
innovate without damaging the PostgreSQL reputation as a rock solid
database system.
Features like these only enable the entire community to innovate. Is the
real issue that the more extensible PostgreSQL is, the more boring it will
become?
JD
Show quoted text
regards, tom lane
On Thu, Feb 11, 2021 at 12:07 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Thu, Feb 11, 2021 at 9:42 AM Jonah H. Harris <jonah.harris@gmail.com>
wrote:
As Jan said in his last email, they're not proposing all the different
aspects needed. In fact, nothing has actually been proposed yet. This
is an entirely philosophical debate. I don't even know what's being
proposed at this point - I just know it *could* be useful. Let's just
wait and see what is actually proposed before shooting it down, yes?I don't think I'm trying to shoot anything down, because as I said, I
like extensibility and am generally in favor of it. Rather, I'm
expressing a concern which seems to me to be justified, based on what
was posted. I'm sorry that my tone seems to have aggravated you, but
it wasn't intended to do so.Likewise, the point I was trying to make is that a "pluggable wire
protocol" is only a tiny part of what would be needed to have a credible
MySQL, Oracle, or whatever clone. There are large semantic differences
from those products; there are maintenance issues arising from the fact
that we whack structures like parse trees around all the time; and so on.
Maybe there is some useful thing that can be accomplished here, but we
need to consider the bigger picture rather than believing (without proof)
that a few hook variables will be enough to do anything.
Just to don't miss the point, creating a compat protocol to mimic others
(TDS,
MySQL, etc) is just one use case.
There are other use cases to make wire protocol extensible, for example for
telemetry I can use some hooks to propagate context [1]https://www.w3.org/TR/trace-context/ and get more
detailed
tracing information about the negotiation between frontend and backend and
being able to implement a truly query tracing tool, for example.
Another use case is extending the current protocol to, for example, send
more
information about query execution on CommandComplete command instead of
just the number of affected rows.
About the HTTP protocol I think PG should have it, maybe pure HTTP (no
REST,
just HTTP) because it's the most interoperable. Performance can still be
very good
with HTTP2, and you have a huge ecosystem of tools and proxies (like Envoy)
that
would do wonders with this. You could safely query a db from a web page
(passing
through proxies that would do auth, TLS, etc). Or maybe a higher performing
gRPC
version (which is also HTTP2 and is amazing), but this makes it a bit more
difficult
to query from a web page. In either case, context propagation is already
built-in, and
in a standard way.
Regards,
[1]: https://www.w3.org/TR/trace-context/
--
Fabrízio de Royes Mello
PostgreSQL Developer at OnGres Inc. - https://ongres.com
On Thu, 11 Feb 2021 at 09:28, Robert Haas <robertmhaas@gmail.com> wrote:
On Wed, Feb 10, 2021 at 2:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
That is a spot-on definition of where I do NOT want to end up. Hooks
everywhere and enormous extensions that break anytime we change anything
in the core. It's not really clear that anybody is going to find that
more maintainable than a straight fork, except to the extent that it
enables the erstwhile forkers to shove some of their work onto the PG
community.+1.
Making the lexer and parser extensible seems desirable to me. It would
be beneficial not only for companies like EDB and Amazon that might
want to extend the grammar in various ways, but also for extension
authors. However, it's vastly harder than Jan's proposal to make the
wire protocol pluggable. The wire protocol is pretty well-isolated
from the rest of the system. As long as you can get queries out of the
packets the client sends and package up the results to send back, it's
all good.
I would have to disagree that the wire protocol is well-isolated. Sending
and receiving are not in a single file
The codes are not even named constants so trying to find a specific one is
difficult.
Anything that would clean this up would be a benefit
That being said, I'm not in favor of transferring maintenance work to
the community for this set of hooks any more than I am for something
on the parsing side. In general, I'm in favor of as much extensibility
as we can reasonably create, but with a complicated proposal like this
one, the community should expect to be able to get something out of
it. And so far what I hear Jan saying is that these hooks could in
theory be used for things other than Amazon's proprietary efforts and
those things could in theory bring benefits to the community, but
there are no actual plans to do anything with this that would benefit
anyone other than Amazon. Which seems to bring us right back to
expecting the community to maintain things for the benefit of
third-party forks.
if this proposal brought us the ability stream results that would be a huge
plus!
Dave Cramer
www.postgres.rocks
Show quoted text
Attached are a first patch and a functioning extension that implements a
telnet protocol server.
The extension needs to be loaded via shared_preload_libraries and
configured for a port number and listen_addresses as follows:
shared_preload_libraries = 'telnet_srv'
telnet_srv.listen_addresses = '*'
telnet_srv.port = 54323
It is incomplete in that it doesn't address things like the COPY protocol.
But it is enough to give a more detailed idea of what this interface will
look like and what someone would do to implement their own protocol or
extend an existing one.
The overall idea here is to route all functions, that communicate with the
frontend, through function pointers that hang off of MyProcPort. Since we
are performing socket communication in them I believe one extra function
pointer indirection is unlikely to have significant performance impact.
Best Regards, Jan
On behalf of Amazon Web Services
On Sun, Feb 14, 2021 at 12:36 PM Dave Cramer <davecramer@postgres.rocks>
wrote:
On Thu, 11 Feb 2021 at 09:28, Robert Haas <robertmhaas@gmail.com> wrote:
On Wed, Feb 10, 2021 at 2:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
That is a spot-on definition of where I do NOT want to end up. Hooks
everywhere and enormous extensions that break anytime we change anything
in the core. It's not really clear that anybody is going to find that
more maintainable than a straight fork, except to the extent that it
enables the erstwhile forkers to shove some of their work onto the PG
community.+1.
Making the lexer and parser extensible seems desirable to me. It would
be beneficial not only for companies like EDB and Amazon that might
want to extend the grammar in various ways, but also for extension
authors. However, it's vastly harder than Jan's proposal to make the
wire protocol pluggable. The wire protocol is pretty well-isolated
from the rest of the system. As long as you can get queries out of the
packets the client sends and package up the results to send back, it's
all good.I would have to disagree that the wire protocol is well-isolated. Sending
and receiving are not in a single file
The codes are not even named constants so trying to find a specific one is
difficult.Anything that would clean this up would be a benefit
That being said, I'm not in favor of transferring maintenance work to
the community for this set of hooks any more than I am for something
on the parsing side. In general, I'm in favor of as much extensibility
as we can reasonably create, but with a complicated proposal like this
one, the community should expect to be able to get something out of
it. And so far what I hear Jan saying is that these hooks could in
theory be used for things other than Amazon's proprietary efforts and
those things could in theory bring benefits to the community, but
there are no actual plans to do anything with this that would benefit
anyone other than Amazon. Which seems to bring us right back to
expecting the community to maintain things for the benefit of
third-party forks.if this proposal brought us the ability stream results that would be a
huge plus!Dave Cramer
www.postgres.rocks
--
Jan Wieck
Attachments:
telnet_srv_2021-02-18_1.tgzapplication/x-compressed-tar; name=telnet_srv_2021-02-18_1.tgzDownload
� ��.` �\{s�F������0�M�)��|e�v)��-��Hmr�P 0$� �$�6���������:Im]X�D�����=�P,�@���n{�~��.>/^�������������g��0no��p��8��0*|���~����n������~�������Y� >���g��{���=;���^<���
�����m�|�OSl��(����{���g�~h��Ow^$�*
�� }!?�2P^�Dy�� ��|�W��7_���t�������
U<�����8�����y+�p��A,��0Y��'����t�?�//�N��7�mP =�s�����?q�h�4���h5��ofN����B�<Z���S�[n�Q��&���J���A�cj- ���c�K/ l
8���b��8R����t8�ri����>p������j�SD�]��t�8�zj��{~����}���A��������*D���b�� ?������C�[���*l��KP�B�� W=�A�]I���7O��f������Y����\�������<�v�*�b��������,����S�j9���bo)����v���f��:��/OnF���l�?j6{[�H3o�DvL�$\�/��G�x� ����hOGi���#���"X��F�v ����B����������+��d#��8�9Y-���~!a!��7 � AlR�FO��%���}?t��B���v<�1[4�Z��B�W�b8��,��$p�Z�t|[SN ���m����z{����sTh��9mMW������a ��U����;S2���5s��G�����J�:~�d��5�����C���
�b����K�f�Ta�v�����!sg��*������:b5���|LK+#'Q�.C��\k �
�DQ���-���_����H���5#�}"��v_�� v���F
�`+����Y��o���"�F:�P��u�<9��{l��l�*�n:$��.��X��{���a���(��U{�`� �c?$���mA+\KGz`��*�0�9�9P����Y!4�%=E���U1���J���C�I��wA����(���D
_34W�w� �*����R�Lr/0�n�3�� x..'����a�F��w��MFzh�h��%"���mq���E� ��lot`FS�`��%��"�:�{M��+gd����������v2�`�����5.��42��x
���9�����Ye*�b��)H�W���TOWsD��Q/�E�=��!L���q�Or�y�����FCo�H�T?�V��R�����6�Uf��
��q������������$(�*��������Y�|���w��d1K��*��H1zW�������I���d�<�pD��@M��T�����,��;����:F]53El��h�`��R�&�YX�@��4�@1�a���*y���^�>�I��fOAX!��� X��dc<Mff��h����� �!&���+J) ���r����B/��;�i�
�&�D����wje;R���:� �����J��/����\����[$�U$o�^9w�W&~�����79��+I�|�v3s��+sP-�T��:O3����rq3mg��,~�Yf�?p�/��{&���A]�n)x1������:�j�1��fc���fq'��\2-��$Y����x��Vl���B,�A\%#4,���:�r
���M|�y3[�������`�������v"aR$B�"�x�'A*�g7�\x�4�Gv���y�0��a���BVL�2���p� �uv�^�l����YC�yow�y�pxp��0{�:�[W�����x2���w�WZ{ �Z�������H�T�n�T����ll�4���W����n�0zv�V��)����<D�����|������I�7dqU�H�����b����x��F�K�������U<x�� O�#E���!�
��uf���=��n!G� ����Q���aO�L{�`k�NG%���U��}�n!�#�p��>i�K��|h�N��q����:Dp�e�r2��r���:������-y WMQ��{t���#��V�p�����P�i��1����L�_D�`I�A4�B��������<�u��xda���g����pC��>�P� ��� �A���(n�����^�l�VG��� �YXH�*��!(�g�) �]S�f!�%�J=� $� ,�(x�9�]P��C�����KD���lP?�Q����t��g!����X�.L|�
6��l'N���3>z�����A��~7B�uz7|��oK5?����B|�{2:�hxd0H�����fz�h�� `;����������C�}g���Fo����{ ��>�������A�{�.%��u^��0��g~�m�0��/P�H��� ����:,#���eB�FRaF� ����y��@���1D�YL��$\�:
��y]�WXJ`�&���r�����,�#����h�}N"oI�*t���D��M14y
�SX�cHY�.� �mO����cd�n��L��O�N�Q��wv�������O�j�����e���K�]���0#}��=k}E�1}<9�����������MG�dr�6<ke+U�
~8wel{>�#:���%~�n��[c`����W��0Z��d���
�2�8E�
��Z��}�U��� �F*tgR����`�:�m��:g���3��(:�����+"S�'>s��v��s�f��z�{�WL��� ��(����J��x����5�`2r@F�����KFK���0}[��?7�k��lHn���������x���,=�%c���m�k��%f�.��f*�����jIYj����H�Q8/DP)9*�e@��=U �]�R�^�`��;���n�k�� =� a�=��Z�:�M��^?Z��7j�JG�-�Is^{ty�-da��R���Ad�V�����d,63���2i��s�u��
�qT@�9��w>"�1���8=.St��������H�5O�0~�*�����T���N������t�U8q��3+�pC��'1�y��;�9VbW�l`���ra�zt�=K+;�90iw��"��>�����y��4l-�������@=L"�Uu�,`N�pi=��y�b%Z�w��}���������B�\�y����u��)�9D�A���>���t�
'�oo��^���������������FB���"���W����,|���������U@�������2����^\N��Ae�n�������"G�<[��pp1�C���6��������������V7���b������_k��1����-_�\�K�������c[�e`������G�g �/_�,4���w�$��,����5����z�����z�]Xkrv�z-��}����&�0����L�|w&�|�j�6�A`��E���{�o���|������ts5��P�������#��28���(l����0�� E������~�u)��*�U�9cbe���������ZF�����J:��=��y~5P��59>���9�{�05+`P#�).��h_����n�GDn�A^�{�%���9r���o�XR���!;.r�D������7@d��.����N�}u��!�dH�u"F��/=�M�W�H�[� Ud�����������a��s�>�.�L2�(,��i
������1�_�mh��;[���������t�|'L����y���b@<�������*�l��
"=��Cw�;;��L*�L�I��e�s��6�t��
f&ZhM�;dw� �<����K��
�Jq�.�0��V��x��%��'�;�����7i/bT$Y-qu>|n�^^�OD�M�xYU?����i�N9'��4��'��6^���,pf�+�LJYj5�z�kaPV�9M��������eT�Y�8��Z��6:��L�2��Fi�\ld���*^�/���D����m�N�E;����S����f���#i��v�p�
�T?�-���th$K*�P���;� T��Pbb ���� ;�MWv�aN8(����Z�E�����-�NHc��h��+M�iL�'�A_���D]��t��C����Wb7w�%�����J}PAu��9�-�������Z`)]o�1�����79J�{��8����d�*2���TxG�c*���moL����I��Fi�)��bm�.zy��-�.��V�������b'�����d��
Ae�PQ��W>. ���6vg�X��l9��x�)M��RT�(�h~j����������:t��@"VV�vSqSa�:%$��;��$���%C��&U�t-��:8�\���\Zoy��*�V\Q��kglS�����b}��'~�ETU��kD�%��O.Rz����~'�JLH�D|w���9GjT�f�$zS��c��������� ��J������g��k*}}���i��f!����p��5n�)VcR+2�\��[3k��)�>��Kpb����0
�K��]��43�=�Z�����9���eK�J��u�q9dO� ����${������ �k4N`:�k���Wl�0$C��%��}H@{M�����d��I&)���9r-!n���T��u�C7�t=Q�\ms�����qe�^�jL�����n�����k�7������.��H-4�j-tMl�F��lX��F���a�2-��DA�\��� =��
}��o�i����e�)Q��^�H�N��S�H� "��N*E���7�NJR�N9i��j��05��:5#T�"�"-DNj`�W34�tw6�Iq|D/��r��e���P�L�q#-;�����B�|k*��M$��D�����'��`�;�>�F�L������n��h��(B<[����>�T
Z������?L������hbQ
0.���B^�~49�\z1������_:���kfJ�Q��8��X_5�U�Y�j#��F��Rr�|����1B�(bG�_L�V#[��|s���B���lQ5�1_�����}sD�� �:j}$�G
�::6��#��������.��B��# 3/��>f�e��6k�>d�V`�K���%��� �H�y
��)zp��|�! �
W�L�e&`U�#��&<iQ���� ������;:���� R�;#D�5�����X�sQ2���Y ��\`�1P��B�m?^�����LmzG V{[�Y�O�u�^��U��F��O��{��(Y��I��������*0���l}����R�� ^�Qb�p�H_�r�O�`�56E������5��� ����w���;;{���z��5~�w��.���{�������v�w��������meo����$�I���:��k���'rt^
����6&��_�Xa�v�`���E�zp<������^�+�E(n`u[����h���BY6����x�>����)���)�?��D����G����\�w���|��/��#>_��!�T�M������G4/���1Z�6_��^<��FhO��w�f3W������q�%�.�����hp2���;A��������~�RW�4�����������W��6vB�������h����i6�g�yl]^Mh';;�������j�!b��q������
��Zy�_�O��"�h��pd)�'�;����]:4#g����'�����4~+��O�^�3/8�r]���q���-�h��w�{�;����'R�3/.��h�����A���y���f����x`]��0�?����8��-�����.��h���W�l\\�?�N3}��:w�|Y��)H `��l�O=���u�(��N<���;�?�R[�����w���H"��_~�?�e������}t$Yy^����8cj���=��F��"1�h5=�:h$��f��)u�����vu�F������c`��`�N�c��L l�8���1q��8vL��?n���jI;�yt��V�Uuo�������{����������459�zD�~cY�F
bd�[�����\���o��?y�H�������c���n��H�:@.���(�/�k������BB�9P�c��>�����`��=n�/4�T\�� !���C�#qY�?AAp���{�?z������81951��������G�����zz[[����+�8Y�����^������M���@����3A��~-�|�r�:�Y���m�n�u��Spl��-��VE[w��E�o6<�^D-Q��n}�k�/����}��S~��~�2���uU�/��9�=9�����w��+����)���^P\-�q/
��i~����>y[�Ok�#-Z�!����M-��C�I�aN���2�A��i�j%p����um�v��_� m���qF �,��r��.�9��{, c m�I���P��(1�]���)��9G�:d��kdF�����IK��(�E>7�@z�7���l�����`����Qo�i��n2�&�e�M���u�2L��HH�H)�K���9�6G����)8#���3l2��_��j��q/���&��J�b{l���,�*9�Ha�������by~�������������jq���kEs�M���|1������x�@R�:��@�����&/g���,���V�Vp�l�\�u\����hQ�z����o�f�G��*�VN_.8C���b�#f����#e��UZ.��\2�8�� �w�dB�^Z����*i���$�L}�R���(q�O��t��n�lP�#��v����W6�5n�LU������IJ3���RS��,z�*9��H��i�-`�*����0�H�+����N���$��MY�t��^9`�V��'z�X�4}�[ e���J�dXR���?k�d5y��}���vOV������lz:��guny|~��H; �P�=��{E�G��%�X�mJ��@�[D*�}!�x^��2%X�����$2�e8�����m|���
}$G��[��x�@X�Y
��%������=�:u:�������*�����q��z�C����36c�a��zf�������($2n�MQ;n-kC��0����*��F�M][9_���92Q�II"?�����knPD5����r�����|��?H?m5��@6;�����3 ��`�R\][Y,MGc�����1P�6�u%r���h��6U/q�"I*'?��mW/H�-E�-B�W~<��*"f7��":i���{��C���Et0Q�P,��L^H����X$�ugw����d�b���8_>;{�]K���3Q���
��b���5[�pT��p���t3��-d.��4P���������{I\>�<�z�#�R�A!���_�������sS�sSt�6o@�a'��0
�D�o��Cly���U���p�����0=*8��D��q��1��e�Nhc����M*��yP������� paV�����R�=�k�a�v��y*�����n4^�JM
��c���Xb���33-�k�=N,UH.������������
&V2��N,f:��P\E>�!1�!�h�ID!�eXy(h�h��C'�����u�VLd<��f�DV�mc�N.-q��� <����L�Ye��V{�^�,�� ���n��������r�K8<<�&����s��C��� ���������:F��j>�� K�r�f��������7��{4�H<���8R��,��`i.aL�!F(tT=j.)���.���VZ�X�6��0������y*"Sd�^6Y��W@l+8a��iyW��1�O��3�G���FO"���>��:8_
��|���Zw����Z���s�Yj��(f��;���6�gC��!_����������-�j��z\t�
�Ma}����>��sj�O8y�50��u������+��L@�!�rN������Ip���0K��l��g�j��4#:s�}�fxlA�7����.���e���������_974�|���.�4-��D�l2���1M%c
'�>3]1�O�����x�q��hx��J�������-e7���,}�����r��Mq�+�TGm�X�+w������T�.h:����� ��&�g�g�hd��V�jT��Z�,����d�4�?l���H�gv
����� z���������I�R V&5���;�Ar���&��`f�T�G���R
���iDU�B���������.�n�u����@�*v��Z�H�����5�����$����Qs�!��e���0�V��f���K�������,-�W�k�")]|J�y'�3����3��P�M�1���������v��>�(���5&p�a�xC��8�v
��c���g
g�o����6��(��n��D���t<���X����5�)s�#�4�S�r^�������q��mkY�1u �]�|����#Z������_�=i�d�|���:CN���[����HD������}rz�;s�A���5[������7��
�FC;��X�����t�� K������IW����de��B^ ��C!������*���:�lT�M���z�J�D���Z��:����D%�//�,�.��]���\��RO��U����j)
�N�\u�(I���&��Ri}��_$
]�{����i >9vtlrb=�HA�O9��&�4JX�5��8�b�mID~���� �6�35��1����
\��r����Y��N��f�@`�\�UnO���g>��y��"MS6�H�^fw��������:�R��j?���(
c�:��2�Hs��8�]��%J-� =��\!+�fR3����6D-~k���^��B��|O�����
���v����� ? �>SL,������I�3�
)��W�z�7����LQ���L���B���K>� �=����w�6����.%����{�����D�=�aAU����_�����[o�,����� �����0t%Rs����]�"� �E���j*G�\!���;w��Q@���J�^�S���pf��w���X��8���#�;m��xx�w�#��8�oW3X<B�}7�S�UGy��:&�*��/{��G S�R�E����2-��g��-��.�������/8 �����lZ >m�()r�a\w��0�o%����>v���8�bnM"m}�/�5�5
�C��|���u��]]��n���Il��@Ms��#�ECe�0�i�����[���� ��l�:��r���D"Xt0���4�������L�����B���Q?QZ�=m�6�$�:8M�����=�{i�#`�S�����,�gHzs@�����:�g���F��~�K@�G�E��K�6�+S,����e�GJ>��H����C�MX KJg
�a �H�nx��D��{-�CV�$=(�%����+�V.�4&�bFnh����&������.V����+�\bH+�nO��B*{��lM�Es��B�Z!���t��IcE�^j9VJ�����E�3�`X�����-����#OGIon7�v��������DE ��`zl46��6Y������m�c��M�pIeQ%���q�
"�!���"D�A8&b�1
_�ZU��4�Mf�(���A���M
�E����������>�}*��i�#�@��� +�Q���!���M�p����[e��V��,/�l���W��������
%5cd�Q���������,g�*5�n��j6�:E��������p?+
(���VK�$h�4�jX�����f[ l�#����Z����Z"�#�eF��\<,Y��������V� �������.smD{��-�> ;X�� �e����Gl�n�P������cF;<� �����>����� S��7�vn����2x�������>����]���a�-�������-w��5����G,���0�:������anD���l����{T<Jcw5["��i�D����a4k4��4e��'�9�+\�wIC�:UF��D��P�!���l�������U��uv����[�[���_��D!��\��j���(;�=���O�n����F��*�<����&g�� ����-T���f�vMF�>�����Q{w�T�lJW����D��fee��&���
�&-R)�UT�����'����D���Jk�&'3��u�J� �x�F���xG<v*GH$]j�A@6]i��y�[^+��J�L?;F&QQ_��Hrd@����]D�pedX�<�k�-�U}�dbC��5�����J[?��{��d��-O��Gnh�Yu���|�s�J��<�����jyqE�Z��c����}m6���E9:�XKk���m����7E+O����������
}���y���m�2�[ 0�Q;��\d ��t��0�"nq/(����U��{����
Fk81���{���XXil�v�3I�S���pt.?P�o�H~�,�"ie���]�{���*
����X�C������'���C����5���j��C��S�����dX��T��o���xC��Vc:�:w�����S�_�����M&��Tv���]����v�fDa����y�C�X>)9=g�IjQ��%N�hU�1��
���1�A����W�����V���9( xd�,����v������zB�w$�&�"�n>�i�!v�n�m�D,a��xC�������� ������)2�<]\aQ�=�.�
G&/�i�2UbE�E������)��� -���5��m�(m��jhV���-"�5]_�N����<<1Ig�TN�*P�I��D1K���-����Q��H�C�,D5Go���F�m�X|a�t�K1�V�BJk�L!d B�u��Y�O�x�e�F#�!�!�Uw0���������gRbX�T*>�GP"�v���P`��Vk���Dz����MHX�v���I���$"�M���o�+���v��n72&��tZ���9?����As�3Vi��/���>y��������Zi����&\=�6���h7F������G��}����_:q)������s���P���&��e:
5 ��oM�Y�,G
����}���{������Z3�FTz�69�+:�g_��JA���.���ai�C�����(�]�i[����z�N��_�(����_x��� aQf��^:f��*�Q�k���8������ ����wum`j�LN��;��Z�G���i�:lJ���9.��<�.�i(��`�����2��xG��h<��� � vx.�#��(n�*!�mw1(�u$����iy���Z�r�J��*���x�������zB���cP_A����(=,�%�7R��9(��Q�+}��i����M 4l�������q����G�>z�(��;>ul���H\�������|�~<9���k�^����2�����{�'���1����1����^!/��Tb��6��w��W��\������������� Vo:�<�)k�v���\�kp
��5���\���i��y%�^�����1����������o�������������'�������������\�kp
��5���\�kp
��u��[�d�����z�����W���|��^�<��3����?����(�����7���L��� ��t���i`x:��'d2��<����0 ���L��_� ����0
�<�x�@&�k���{�Y�q�C�L������ ~
x)px*����|xp��M���N��1�� �\��a`��
��o��
�hG��},�
�8
L�� ]�p�}�1`�*��=�:PV������I�^w]z���z\�o��2[��(7�j{�����3�N��5�K���8�s��L��9���S ��1�������G�t0������5b���}���<�d :#����1
�j4;���5r��,k�f;��<3+��rN��[�b[Urx�N�K��>�9����� YZ%��D~�5���hs�h[��+� e��bWY2���~kFNC4��Js[�����p�u[wH�<{M����f_���
�=.z��e�a
s@���kP���Wj;���F���i5�����d��P+ y9OB��,I���&�3�����6������c����R�D����)��)�?Qw;V~8tvJm�|:�\��V)�/� -��5\.F���8z���D�:�R6��O��4��j�c����[�������z#��'��x���r�o`n�������T<h��|�QB\6�e9��,u��r��������,$�j,���1l�5to:pl�C����AB-����%�>D������KL�K�����c��CN�Qf�����?���L��� _����N.�f���L�@�V�S�����L������2�[���Rb,�u;y�C�7I+�o��\���8��TZ��%����P�V��o�\zGY��7���2��sU%/xa����\�I[��Rp���4WP�fu�Df�a<�H��D ��Ujf��5�G��%���`z�$W$cd�yU�����moV
�M��y���<1Y��L���5��>����,L-$�q�tT�C�<��(2-n�/�~��Q(�\lOTzTs/oV����W�}e2�,[^>SF�����n��}8���*�v,�/�P���"h�XK0��C��q��""��HU},<����i� �KrX��g��MXc���6�]�1T�G�f��;#��s�(�L���������CA�b<Qu;~-�yhlk���m�=
n�i��VP�@���u/� ��O�*���<�{u�G��Z�THdJ{Hi�7����N����%T��r���D��h���X��5:��y��V"!5�u�x����`��f�}���7��^���-?����fc\:J�#��{�l0�;�D������n%� 9h6�{�K�Z������C����'���B�.�o��j��f���Qitjt+QdN���w�<.�����1fh��!RB^��I���Eu�K�����m���UW$9Ip�D^K�����z�m7��������o@(T�� \�!����$�1��p�l]�?������� �kX���A���&0�~x&����|x/�&�'�
�� �����?� �|W��?�(�J�
� �� E�����X���!���[� xpx&����_�������o�I��
�����Q�_�1}=>���\��^W2�iQ��y9b�����L�`��QR-��������>�?#=�6�_��������n��o��^�~Ic��L��0[�)�g�d�,UOs��)nO1�d.%����8����������/H{���1|`�gT�a|�3Q����<����FL�
�����������f#Y5}�Q�u���4�^�EV���YE�����F�?��_%_��6���Q��� bi��E�����z7#���-���H�'�4�'��D�F�&�v2wtH����u�A�Do� v&���==��M�.�!�L����v�K�Y���N>r�D��F3#�:�:�d�2�4��GN�it�'T����i���6R�f7JUH�B������L6U������v����]��g�q�!~��3���s���:�<� �#����;'���@�q#������O���!O�=8V
y����m�eB�(��sF+Zp|
uF\���C�����z������m���F\����oX�C�_�
xG�x�5�����{���GP��+�������\�f��J���������U&�(Y_��L�*��fI_U�::� �onN�]l,D�U��8�&���>G'��
/P����� �1��gL#����3o�Z���D?DwB�F���M,!�m�xoj�{�8W��e,��C�=M�����6aj~4!nh6�2�+����&Eb��
�C2�)��<��I���RV�!F�B��AJ@��F�)�_2;xB��|<�E���e
�f�^�gM+m��3�������7�z'e?�g|Wvv�I���P���Qco����j��Q�w���Y�o�H��G'��\�u�-*o��J4���_��4�?9���}��?�$����o^���)�9�SU�u����;��~�
���+�*P��2p�N��(����L������x���u��,p~�������:����� `�a���?z|&�K�O
���)����6;����U�n�,�| <x
p�7�L���x���/ &�� O|�q��7��|^u
dW�z�u��5`� ��
0
<
x
����
�8�+j����?��$p����g?|��L�� �%�~�=���WW�
�/. ���j��:�n`�8��a�I�w����i���o�~x=��y�px�m��?� |x7�6������6�����e |���Ct��+��xf����J_N��:�6��7���b����<Sci�����^�� #7�������{s�#
��f(;��$7d��}��O;C3�����%�0+��������*��7^�ILbQi&e���"�(���y���d5��D��]!$69�!d�rG����@k�Hu�Y����6[m�LM,I�:��@����u+��[[������&S�&Zz��O)����-O�g��PVw�_�)H)����G��G;�o�ZtzL���pS��C��DL�����nR�K2w.���#��dW2����$6VN���}�Ku7����|�"��QnU���7�@w]|����t��llm��F,�o���m� �"���a��x��Si(r���(}�5v��3I���ST�{H��Z,OK7�Y.+,i FN�{���Z��:$�1;��Tj|[:c'�l�������*�
���^��������`�X:K^l��L���qo�������3s��������jqe�`���v 0�� ������)���u�N�.��9���
Y[F=FX��x�R���O�?~<����d)X���_����=e��e����[��(6 �`�*���6+�G�Tl���Q�,t��p���$��~���c��L��&O
��I���n��+��t�]�^�t��ATm��!~��
GA$��q��2�[�N���;��fB(Y&�#���~������L��*Y,^�����<�%�5Of��L��`&�<��I3����_�]���-��N��p]IM��#���We�Bt�5����aD���������-����p�'�>������Z�a�X2��#�:��/����/���9��i]�w�5`�7��:������^?������o�,��_�|���/���?��{���pp�,�b��w���?>�
��5@XF�'