Today, with a great sense of relief, I committed the second of my major JSON patches for this release cycle, just beating the imminent close of the current commit-fest.
Most of the attention has focussed on the new JSON processing functions, which you can see details of in the dev docs. But the most important part in my mind is really the less visible part, the scaffolding on which these new functions were build. Essentially this took the original (and very good, for its purpose) JSON parser that Robert Haas wrote for release 9.1, which was stack based, and turned it into a classic recursive descent parser. In doing that it provided the ability of functions calling the parser to supply callback hooks for certain parsing events, such as the beginning or end of a JSON object or array. It's kind of the JSON equivalent of an XML SAX parser. That means it's quite easy to construct new JSON processing functions without having to worry at all about the nitty gritty of JSON parsing. I expect to see a number of JSON processing extensions based in this (and I expect to write a few myself).
I'm hoping to give a talk at a conference later in the year about how to build these processing functions.
Friday, March 29, 2013
Sunday, March 24, 2013
Parallel pg_dump committed
Today I committed Joachim Wieland's patch to add a parallel option to pg_dump when outputting directory format. Barring some unexpected and evil occurrence, this should be in the forthcoming 9.3 release. This is the culmination of several years of work. I started talking about this shortly after I did the parallel pg_restore work for release 8.4.
This was a lot more difficult and complex than parallel pg_restore. The three pieces that were required to make this work were: an archive format that we could sensibly write to in parallel, a way of making sure that a dump done in parallel was consistent, and then the actual code to use those features to achieve parallel dumping. The first piece was directory archive format, that was introduced with Release 9.1. The second piece was snapshot cloning, that was introduced in Release 9.2. This final piece builds on those two earlier pieces of work to make parallel dumps a reality.
This development throws away some of my earlier work, We now have a common parallel processing infrastructure that is used for both pg_dump and pg_restore, The new code pre-creates the required number of workers (threads on Windows, processes on Unix) and farms out multiple pieces of work to them. This is quite different from the earlier way pg_restore worked, which created workers on demand and allocated exactly one piece of work to them.
Congratulations to Joachim on this milestone..
This was a lot more difficult and complex than parallel pg_restore. The three pieces that were required to make this work were: an archive format that we could sensibly write to in parallel, a way of making sure that a dump done in parallel was consistent, and then the actual code to use those features to achieve parallel dumping. The first piece was directory archive format, that was introduced with Release 9.1. The second piece was snapshot cloning, that was introduced in Release 9.2. This final piece builds on those two earlier pieces of work to make parallel dumps a reality.
This development throws away some of my earlier work, We now have a common parallel processing infrastructure that is used for both pg_dump and pg_restore, The new code pre-creates the required number of workers (threads on Windows, processes on Unix) and farms out multiple pieces of work to them. This is quite different from the earlier way pg_restore worked, which created workers on demand and allocated exactly one piece of work to them.
Congratulations to Joachim on this milestone..
Friday, March 15, 2013
Recent feature requests
In the last few days customers have wanted the following PostgreSQL features:
- A time zone setting of "system" which will just pick up whatever the system's time zone setting is at server start. This would be useful for appliance makers who pre-install a database and then ship the appliance to a customer who can change the time zone, as one of our customers does.
- The ability to set a default tablespace for a schema, and to move all the objects in the schema to that tablespace. This was apparently something that got ripped out in the very late stages of the 8.0 development cycle, but it doesn't seem like a terribly bad idea at first glance.
Wednesday, March 13, 2013
Writeable Foreign Tables
There are lots of cool things coming in 9.3, but the one I'm licking my lips over is one that was committed the other day by Tom Lane: Writeable Foreign Tables by KaiGai Kohei. As soon as I get done with the work I have in hand for core 9.3 I will be an early adopter, adding this to the Redis FDW. This is going to be very cool.
Saturday, March 9, 2013
Loading Useful Modules in PLV8
PLV8 is a trusted language. In fact it arguably safer than pretty much any non-core loadable language, since the interpreter is naturally sandboxed. So there's no way to load external processing modules from the file system. However, pure JavaScript modules can be cleanly loaded from the database itself. A couple of extremely useful ones I have found are Underscore and node-jPath. The former can be loaded with no modification whatever. The latter is written for use with node.js and needs a small amount of adjustment before it's loaded in plv8.
So how do you do this? Well, first you need to grab the code:
Then you'll need a table to load the modules from, and to put the modules in this table. You'll also need a function to load them. These can be accomplished with the following psql script:
Now test it out:
So how do you do this? Well, first you need to grab the code:
Then edit jpath.js so that, at the bottom, instead of assigning to module.exports it creates an object called jpath and adds the select and filter methods to it.curl -o underscore.js http://underscorejs.org/underscore-min.js curl -o jpath.js https://raw.github.com/stsvilik/node-jpath/master/lib/node-jpath.js
Then you'll need a table to load the modules from, and to put the modules in this table. You'll also need a function to load them. These can be accomplished with the following psql script:
\set underscore `cat underscore-min.js`
\set jpath `cat jpath.js`
create table plv8_modules(modname text primary key, load_on_start boolean, code text);
insert into plv8_modules values ('underscore',true,:'underscore'),
('jpath',true,:'jpath');
create or replace function plv8_startup()
returns void
language plv8
as
$$
load_module = function(modname)
{
var rows = plv8.execute("SELECT code from plv8_modules " +
" where modname = $1", [modname]);
for (var r = 0; r < rows.length; r++)
{
var code = rows[r].code;
eval("(function() { " + code + "})")();
}
};
$$;
Now test it out:
select plv8_startup();
do language plv8 ' load_module("underscore"); load_module("jpath"); ';
-- test the underscore module's extend function
do language plv8 $$
x = {'a':1};
y=_.extend(x,{'a':2,'b':3},{'b':4,'c':5});
plv8.elog(NOTICE,JSON.stringify(y));
$$;
-- test jpath module's filter function
do language plv8 $$
var jsonData = {
people: [
{name: "John", age:26, gender:"male"},
{name: "Steve", age:24, gender:"male"},
{name: "Susan", age:22, gender:"female"},
{name: "Linda", age:30, gender:"female"},
{name: "Adam", age:32, gender:"male"}
]
};
//We want to get all males younger then 25
var match = jpath.filter(jsonData, "people[gender=male && age < 25]");
plv8.elog(NOTICE,JSON.stringify(match));
$$;
You should see output like: NOTICE: {"a":2,"b":4,"c":5}
DO
NOTICE: [{"name":"Steve","age":24,"gender":"male"}]
DO
Now, the final step is to make these get loaded automatically. Alter your plv8_startup() function by adding to following at the end: // now load all the modules marked for loading on start
var rows = plv8.execute("SELECT modname, code from plv8_modules where load_on_start");
for (var r = 0; r < rows.length; r++)
{
var code = rows[r].code;
eval("(function() { " + code + "})")();
}
and finally add to you postgresql.conf file, and restart. You should now be able to use these modules anywhere in your PLv8 code.plv8.start_proc = 'plv8_startup'
Monday, February 25, 2013
A few notes from the field on git
Any time a source code management system gets in your way it's not doing its job. It's really something you should have to think about as little as possible. One thing I found out by doing it the wrong way the other day is that of you create a pull request on bitbucket or github, you really need to do it on a topic branch created just for the purpose. After the upstream repo you have sent the pull request to has merged your changes you can delete the branch. Cleaning up after I unthinkingly sent a pull request for the node-postgres driver from a long-lived branch was rather ugly.
I also wish it were possibly to exclude certain files (e.g. regression test result files) from having trailing whitespace colored. But if it is possible I have yet to find that way.
I also wish it were possibly to exclude certain files (e.g. regression test result files) from having trailing whitespace colored. But if it is possible I have yet to find that way.
Saturday, February 23, 2013
Learning new technology
One of my oldest clients is switching to a new technology stack. After many years of using AOLServer, OpenACS and Postgres as their preferred basis for applications they have switched to using nginx, Redis, node.js and Postgres with plv8.
I'll be talking about some of this, especially the use of Redis with Postgres, at pgcon. in May.
I can't say I really like the node.js style of programming, but needs must when the devil drives. One thing worth noting is that there is quite a good node.js driver for Postgres, and that the maintainer was very responsive in merging in a patch I sent. I've sent in another one (to fix a bug connecting to Unix domain sockets) and I hope it too will be picked up very promptly.
I'll be talking about some of this, especially the use of Redis with Postgres, at pgcon. in May.
I can't say I really like the node.js style of programming, but needs must when the devil drives. One thing worth noting is that there is quite a good node.js driver for Postgres, and that the maintainer was very responsive in merging in a patch I sent. I've sent in another one (to fix a bug connecting to Unix domain sockets) and I hope it too will be picked up very promptly.
Friday, February 15, 2013
PostgreSQL doc epub
The other day Peter Eisentraut made a small commit that was probably little noticed, but I think is very useful. He added a few lines to the documentation system to enable building the Postgres documentation as an epub document. This is really quite nice. The great advantage of epub documents over things like PDFs is that they are reflowable, so that they are adaptable to devices with a wide range of form factors. They are also typically much smaller than PDFs. So now I can put the PostgreSQL docs on my Ebook device. I can scale the font up if necessary and still have it look sane. And I can put the same file on an Android device, or an iPhone or iPad. There are free epub readers for almost every smart mobile device around. It won't work on a Kindle but you can convert it to Kindle format using some free software. There is also an epub plugin for Firefox. So this is cool.
Monday, February 4, 2013
Binding keys in psql
The psql client has a nasty habit of being a bit over-aggressive about when it routes output through the pager. So I oten find myself typing \pset pager to turn it off or on. Or I did up to today, when I finally got tired of it and added these lines to my .inputrc file:
This binds the command to my F12 key, so now I can turn the pager on or off with a single key stroke.$if psql "\e[24~": "\\pset pager\n" $endif
Thursday, January 31, 2013
Json object from an array of key value pairs
I mentioned this the other day, and I now have an extension with a simple function to turn an array of key value pairs into a json object, much as you can turn such a thing into an hstore.
The motivation for this came from a discussion on what to do with structured data returned by the Redis Foreign Data Wrapper. Originally we discussed making it json or an hstore, but on reflection it seemed best to me simply to return it as a standard SQL array and use the database utilities to transform it into whatever is needed. So this function works pretty much like the hstore function except that here it is the caller's responsibility to ensure that the keys are unique. When used with the Redis FDW that won't be a problem - they will always be unique.
The motivation for this came from a discussion on what to do with structured data returned by the Redis Foreign Data Wrapper. Originally we discussed making it json or an hstore, but on reflection it seemed best to me simply to return it as a standard SQL array and use the database utilities to transform it into whatever is needed. So this function works pretty much like the hstore function except that here it is the caller's responsibility to ensure that the keys are unique. When used with the Redis FDW that won't be a problem - they will always be unique.
Tuesday, January 29, 2013
Redis FDW update.
Today I've published a major revision to the Redis Foreign Data Wrapper code for use with PostgreSQL versions 9.2 and later. There are two new features: support for Redis structured data types and support for restricted keyspace search.
The structured data type support is enabled by using the table option "tabletype", which can take one of the values "hash", "list", "set" or "zset". If this option is used the data comes back as an array rather than as a simple scalar value. In the case of "hash" tables, the values are a sequence of key/value pairs. For the other types they are simply the elements of the relevant structure. If the values column of these tables is defined to be of type "text[]"(i.e. array of text) then an actual array is returned. If the column is a plain text column an array literal is returned. Hash table arrays in particular can be turned into records via hstore's "populate_record" functionality, or transformed in other useful ways.
Restricted keyspace search is enabled by using one of the table options "tablekeyprefix" or "tablekeyset". These are mutually exclusive. "tablekeyprefix" restricts the search to keys with the given prefix. However, in a very large Redis database this might still be expensive. In that case, it might be better to keep a list of the keys in a separate set, and this is supported using the "tablekeyset" option. When this is used the global keyspace isn't searched at all, and the list of keys is simply taken as the members of the set.
The new functionality is demonstrated in the test script (which is also new).
I am also working on some facilities to push data into Redis and similar things, but these fall outside the current possibility of a Foreign Data Wrapper, and will be announced separately.
Credit note: this work was supported by IVC
Monday, January 28, 2013
Array of Key Value pairs to Json
As I'm working on making the Redis Foreign Data Wrapper actually do something useful, it's occurred to me that one of the Json functions we're missing is the ability to turn key value arrays into Json, as we can with hstore. There's a bit of a mismatch in that Json's treatment of numbers and booleans involves distinguishing these from strings, but it would be possible to have a "use heuristics" option as I recently did with hstore to Json conversion.
When I get done with the Foreign Data Wrapper I will probably whip up a quick extension to add this functionality.
When I get done with the Foreign Data Wrapper I will probably whip up a quick extension to add this functionality.
Subscribe to:
Posts (Atom)