Search code examples
postgresqlproxymiddleware

Looking for a way to rewrite Postgresql query before executing it


I have a Postgres client sending queries like

SELECT ... FROM "public"."mycontent" "mycontent"
WHERE (strpos(substring("mycontent"."summary" from 1), 'search_string') + 1 - 1 > 0)

to our Postgres server. I want the client to use my full text search function, but I have no access to the client's code. So I am looking for a way to rewrite all incoming query in the above form to something like:

SELECT ... FROM "public"."mycontent" "mycontent"
WHERE id in full_text_search('search_string')

Note the extraction of the 'search_string', so Postgres Rules cannot be used here because they don't do such extraction. I hope anyone knows of any postgres middleware or proxy that can do query rewrite, or is there any other better idea? Thank you.


Solution

  • I guess I have to answer my own question. I implemented a postgres proxy server for rewriting query, using python gevent socket programming. Note this doesn't work if connection uses SSL.

    from gevent import socket, server, Greenlet, joinall
    
    def pipe(source_socket, destination_socket, modify=False):
        while True:
            try:
                data = source_socket.recv(1024)
            except socket.error, e:
                break
            else:
                if data:
                    if modify: data = data.replace("limit 10", "limit 1 ")
                    destination_socket.send(data)
                else:
                    break
    
    def pg_proxy(client_socket, address):
        pg_socket = socket.create_connection(("localhost", 5432))
        pg_socket.settimeout(300.0)
        client_socket.settimeout(300.0)
        joinall((
            Greenlet.spawn(pipe, client_socket, pg_socket, modify=True),
            Greenlet.spawn(pipe, pg_socket, client_socket, modify=False)
        ))
        pg_socket.close()
        client_socket.close()
    
    if __name__ == '__main__':
        s = server.StreamServer(("localhost", 5433), pg_proxy)
        s.serve_forever()