prestogres 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,4 +1,7 @@
1
1
  *~
2
2
  *.pyc
3
3
  .bundle
4
+ .so
4
5
  pkg
6
+ vendor/bundle
7
+ Gemfile.lock
data/ChangeLog CHANGED
@@ -1,4 +1,18 @@
1
1
 
2
+ 2014-02-07 version 0.3.0:
3
+
4
+ * Fixed system catalog queries to support multiple schemas
5
+ * Removed presto_schema parameter from pgpool.conf
6
+ * Use connecting database name as the default schema name
7
+ * Updated type mapping to map varchar type of Presto to varchar(100)
8
+ * Implemented query cache for system catalog queries
9
+ * Improved prestogres-setup command to not listen on TCP socket
10
+ * Improved prestogres-setup command to support -P option
11
+ * Fixed build scripts to work with bundler
12
+ * Fixed build scripts to work with RubyGems >= 1.8.26
13
+ * Fixed "rake install" task
14
+
15
+
2
16
  2014-01-24 version 0.2.0:
3
17
 
4
18
  * Authentication mechanisms support pg_database and pg_user options to
@@ -10,6 +24,7 @@
10
24
  * Queries to system catalogs delete created tables by rollbacking
11
25
  subtransaction so that other sessions does not conflict
12
26
 
27
+
13
28
  2014-01-15 version 0.1.0:
14
29
 
15
30
  * First release
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # ![Prestogres](https://gist.github.com/frsyuki/8328440/raw/6c3a19b7132fbbf975155669f308854f70fff1e8/prestogres.png)
2
2
  ## PostgreSQL protocol gateway for Presto
3
3
 
4
- **Prestogres** is a gateway server that allows clients to use PostgreSQL protocol to run Presto queries.
4
+ **Prestogres** is a gateway server that allows clients to use PostgreSQL protocol to run queries on Presto.
5
5
 
6
6
  * [Presto, a distributed SQL query engine for big data](https://github.com/facebook/presto)
7
7
 
8
- With Prestogres, you can use PostgreSQL clients to run queries on Presto:
8
+ You can use any PostgreSQL clients (see also *Limitation* section):
9
9
 
10
10
  * `psql` command
11
11
  * [PostgreSQL ODBC driver](http://psqlodbc.projects.pgfoundry.org/)
@@ -16,6 +16,9 @@ Prestogres also offers password-based authentication and SSL.
16
16
 
17
17
  ## How it works?
18
18
 
19
+ Prestogres uses modified **[pgpool-II](http://www.pgpool.net/)** to rewrite queries before sending them to PostgreSQL.
20
+ pgpool-II is originally an open-source middleware to provide connection pool and other features to PostgreSQL.
21
+
19
22
  ```
20
23
  PostgreSQL protocol Presto protocol (HTTP)
21
24
  / /
@@ -37,6 +40,7 @@ Prestogres also offers password-based authentication and SSL.
37
40
 
38
41
  * Extended query is not supported ([PostgreSQL Frontend/Backend Protocol](http://www.postgresql.org/docs/9.3/static/protocol.html))
39
42
  * ODBC driver needs to set **UseServerSidePrepare=0** (Server side prepare: no) property
43
+ * ODBC driver needs to use "Unicode" mode
40
44
  * JDBC driver needs to set **protocolVersion=2** property
41
45
  * DECLARE/FETCH is not supported
42
46
 
@@ -46,41 +50,38 @@ Prestogres also offers password-based authentication and SSL.
46
50
  $ gem install prestogres --no-ri --no-rdoc
47
51
  ```
48
52
 
49
- Prestogres package installs patched pgpool-II but doesn't install PostgreSQL. You need to install PostgreSQL server (with python support) separately.
53
+ Prestogres package installs patched pgpool-II but doesn't install PostgreSQL. You need to install PostgreSQL >= 9.3 (with python support) separately.
50
54
 
51
55
  * If you don't have **gem** command, install Ruby >= 1.9.0 first
52
56
  * If installation failed, you may need to install following packages using apt or yum:
53
57
  * basic toolchain (gcc, make, etc.)
54
- * OpenSSL (Debian/Ubuntu: **libssl-dev**, RedHat/CentOS: **openssl-dev**)
55
- * PostgreSQL server (Debian/Ubuntu: **postgresql-server-dev**, RedHat/CentOS: **postgresql-devel**)
58
+ * OpenSSL dev package (Debian/Ubuntu: **libssl-dev**, RedHat/CentOS: **openssl-dev**)
59
+ * PostgreSQL server dev package (Debian/Ubuntu: **postgresql-server-dev-9.3**, RedHat/CentOS: **postgresql-devel**)
60
+
61
+ ### Installation FAQ
62
+
56
63
 
57
64
  ## Runing servers
58
65
 
59
- You need to run 2 server programs: pgpool-II and PostgreSQL. You can use `prestogres` command to setup & run them.
66
+ You need to run 2 server programs: pgpool-II and PostgreSQL.
67
+ You can use `prestogres` command to setup & run them as following:
60
68
 
61
- 1. Create a data directory:
62
- ```
69
+ ```sh
70
+ # 1. Create a data directory:
63
71
  $ prestogres -D pgdata setup
64
- ```
65
72
 
66
- 2. Configure **presto_server** and **presto_catalog** parameters at least in pgpool.conf file:
67
- ```
73
+ # 2. Configure presto_server and presto_catalog parameters at least in pgpool.conf file:
68
74
  $ vi ./pgdata/pgpool/pgpool.conf
69
- ```
70
75
 
71
- 3. Run patched pgpool-II:
72
- ```
76
+ # 3. Run patched pgpool-II:
73
77
  $ prestogres -D pgdata pgpool
74
- ```
75
78
 
76
- 4. Run PostgreSQL:
77
- ```
79
+ # 4. Run PostgreSQL:
78
80
  $ prestogres -D pgdata pg_ctl start
79
- ```
80
81
 
81
- 5. Finally, you can connect to pgpool-II using `psql` command:
82
- ```
82
+ # 5. Finally, you can connect to pgpool-II using `psql` command:
83
83
  $ psql -h localhost -p 9900 -U pg postgres
84
+ > SELECT * FROM sys.node;
84
85
  ```
85
86
 
86
87
  If configuration is correct, you can run `SELECT * FROM sys.node;` query. Otherwise, see log files in **./pgdata/log/** directory.
@@ -111,7 +112,6 @@ Following parameters are unique to Prestogres:
111
112
 
112
113
  * **presto_server**: Default address:port of Presto server.
113
114
  * **presto_catalog**: Default catalog (connector) name of Presto such as `hive-cdh4`, `hive-hadoop1`, etc.
114
- * **presto_schema**: Default schema name of Presto. You can read other schemas by qualified name like `FROM myschema.table1`
115
115
  * **presto_external_auth_prog**: Default path to an external authentication program used by `prestogres_external` authentication moethd. See following Authentication section for details.
116
116
 
117
117
  You can overwrite these parameters for each connecting users. See also following *pool_hba.conf* section.
@@ -124,10 +124,10 @@ See [sample pool_hba.conf file](https://github.com/treasure-data/prestogres/blob
124
124
 
125
125
  ```conf
126
126
  # TYPE DATABASE USER CIDR-ADDRESS METHOD OPTIONS
127
- host all all 127.0.0.1/32 trust
128
- host all all 127.0.0.1/32,192.168.0.0/16 prestogres_md5
129
- host altdb pg 0.0.0.0/0 prestogres_md5 server:localhost:8190,user:prestogres
130
- host all all 0.0.0.0/0 prestogres_external auth_prog:/opt/prestogres/auth.py
127
+ host postgres pg 127.0.0.1/32 trust
128
+ host postgres pg 127.0.0.1/32,192.168.0.0/16 prestogres_md5
129
+ host altdb pg 0.0.0.0/0 prestogres_md5 server:localhost:8190,pg_database:postgres
130
+ host all all 0.0.0.0/0 prestogres_external auth_prog:/opt/prestogres/auth.py,pg_database:postgres,pg_user:pg
131
131
  ```
132
132
 
133
133
  See also *Creating database* section.
@@ -145,8 +145,8 @@ In pool_hba.conf file, you can set following options to OPTIONS field:
145
145
 
146
146
  * **server**: Address:port of Presto server, which overwrites `presto_servers` parameter in pgpool.conf.
147
147
  * **catalog**: Catalog (connector) name of Presto, which overwrites `presto_catalog` parameter in pgpool.conf.
148
- * **schema**: Schema name of Presto, which overwrites `presto_schema` parameter in pgpool.conf.
149
- * **user**: User name to run queries on Presto. By default, Prestogres uses the same user name used to login to pgpool-II.
148
+ * **schema**: Default schema name of Presto. By default, Prestogres uses the same name with the database name used to login to pgpool-II. Following `pg_database` parameter doesn't overwrite affect this parameter.
149
+ * **user**: User name to run queries on Presto. By default, Prestogres uses the same user name used to login to pgpool-II. Following `pg_user` parameter doesn't overwrite affect this parameter.
150
150
  * **pg_database**: Overwrite database to connect to PostgreSQL.
151
151
  * **pg_user**: Overwrite user name to connect to PostgreSQL.
152
152
 
@@ -223,7 +223,7 @@ commands:
223
223
 
224
224
  ## Development
225
225
 
226
- To install git HEAD, use following command to build:
226
+ To install git HEAD, use following commands to build:
227
227
 
228
228
  ```sh
229
229
  # 1. clone prestogres repository:
@@ -239,7 +239,6 @@ $ bundle
239
239
  $ bundle exec rake
240
240
 
241
241
  # 4. install the created package:
242
- $ gem install --no-ri --no-rdoc pkg/prestogres-0.1.0.gem
242
+ $ gem install --no-ri --no-rdoc pkg/prestogres-*.gem
243
243
  # if this command failed, you may need to install toolchain (gcc, etc.) to build pgpool-II
244
244
  ```
245
-
data/Rakefile CHANGED
@@ -4,9 +4,10 @@ Bundler::GemHelper.install_tasks
4
4
  require 'rake/extensiontask'
5
5
 
6
6
  spec = eval File.read("prestogres.gemspec")
7
- Rake::ExtensionTask.new('prestogres', spec) do |ext|
7
+ Rake::ExtensionTask.new('prestogres_config', spec) do |ext|
8
8
  ext.cross_compile = true
9
- ext.lib_dir = File.join(*['lib', 'prestogres', ENV['FAT_DIR']].compact)
9
+ ext.lib_dir = 'lib'
10
+ ext.ext_dir = 'ext'
10
11
  #ext.cross_platform = 'i386-mswin32'
11
12
  end
12
13
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
data/bin/prestogres CHANGED
@@ -7,7 +7,7 @@ config = {
7
7
  }
8
8
 
9
9
  def usage(error=nil)
10
- puts "usage: #{File.basename($0)} -D <data dir> <command>"
10
+ puts "usage: #{File.basename($0)} -D <data dir> [-P <postgresql bin path>] <command>"
11
11
  puts "commands:"
12
12
  puts " setup setup <data dir>"
13
13
  puts " pgpool start pgpool as a daemon process"
@@ -38,6 +38,8 @@ ARGV.each_with_index do |a,i|
38
38
  case a
39
39
  when "-D"
40
40
  config_key = :data_dir
41
+ when "-P"
42
+ config_key = :bin_path
41
43
  when "-h", "-?", "--help"
42
44
  config[:command] = :help
43
45
  when "setup"
@@ -73,6 +75,8 @@ setup_params = {
73
75
  unix_socket_directory: nil,
74
76
  }
75
77
 
78
+ ENV['PATH'] = "#{ENV['PATH']}:#{config[:bin_path]}"
79
+
76
80
  case config[:command]
77
81
  when :help
78
82
  usage nil
@@ -87,15 +91,11 @@ when :setup
87
91
 
88
92
  require "erb"
89
93
  require "fileutils"
94
+ require "shellwords"
90
95
 
91
- def run_setup_command(cmdline)
92
- if cmdline.is_a?(Array)
93
- puts "setup> #{cmdline.join(' ')}"
94
- system *cmdline
95
- else
96
- puts "setup> #{cmdline}"
97
- system cmdline
98
- end
96
+ def setup_cmd(cmdline)
97
+ puts "setup> #{cmdline}"
98
+ system cmdline
99
99
  unless $?.success?
100
100
  puts "******************"
101
101
  puts "** setup failed **"
@@ -114,44 +114,84 @@ when :setup
114
114
  end
115
115
  end
116
116
 
117
+ def se(raw)
118
+ Shellwords.escape(raw)
119
+ end
120
+
121
+ `which initdb && which postgres`
122
+ unless $?.success?
123
+ puts ""
124
+ puts "Can't find initdb or postgres command. Check following items:"
125
+ puts ""
126
+ puts " * You need to install PostgreSQL server. Use apt or yum to install postgresql package."
127
+ puts " * You need to set -P option to specify path to the commands. Example:"
128
+ puts ""
129
+ puts " $ prestogres -D data_dir -P /usr/lib/postgresql/9.1/bin setup"
130
+ puts ""
131
+ exit 1
132
+ end
133
+
134
+ # src files
117
135
  config_src_dir = File.join(File.dirname(__FILE__), "..", "config")
136
+ postgresql_conf_path = File.join(config_src_dir, "postgresql.conf")
118
137
  pgsql_dir = File.join(File.dirname(__FILE__), "..", "pgsql")
138
+ setup_sql_path = File.join(pgsql_dir, "setup.sql")
119
139
 
120
140
  puts "Setting up '#{config[:data_dir]}'..."
121
141
  data_dir = File.expand_path(config[:data_dir])
122
142
 
123
- @config = setup_params # used by erb files
124
- @config[:pgpool_pid_file] = File.join(data_dir, "run", "pgpool.pid")
125
- @config[:pgpool_status_dir] = File.join(data_dir, "run")
126
- @config[:unix_socket_directory] = File.join(data_dir, "run")
127
-
128
143
  # log & socket dirs
129
- FileUtils.mkdir_p File.join(data_dir, "log")
130
- FileUtils.mkdir_p File.join(data_dir, "run")
144
+ log_dir = File.join(data_dir, "log")
145
+ run_dir = File.join(data_dir, "run")
146
+ FileUtils.mkdir_p log_dir
147
+ FileUtils.mkdir_p run_dir
148
+
149
+ pgpool_dir = File.join(data_dir, "pgpool")
150
+ postgres_dir = File.join(data_dir, "postgres")
151
+
152
+ @config = setup_params # used by erb files
153
+ @config[:pgpool_pid_file] = File.join(run_dir, "pgpool.pid")
154
+ @config[:pgpool_status_dir] = run_dir
155
+ @config[:unix_socket_directory] = run_dir
131
156
 
132
157
  # pgpool
133
- FileUtils.mkdir_p File.join(data_dir, "pgpool")
158
+ FileUtils.mkdir_p pgpool_dir
134
159
  %w[pcp.conf.sample pgpool.conf pool_hba.conf pool_passwd].each do |fname|
135
- File.open(File.join(data_dir, "pgpool", fname), "w") {|f|
136
- f.write ERB.new(File.read(File.join(config_src_dir, fname))).result
160
+ # run ERB for each config files
161
+ dst_path = File.join(pgpool_dir, fname)
162
+ src_path = File.join(config_src_dir, fname)
163
+ File.open(dst_path, "w") {|f|
164
+ f.write ERB.new(File.read(src_path)).result
137
165
  }
138
166
  end
139
167
 
140
168
  # postgresql
141
- run_setup_command %w[initdb -U pg --no-locale -E UNICODE] + [File.join(data_dir, "postgres")]
169
+ # 1. initdb postgres_dir
170
+ setup_cmd "initdb -U pg --no-locale -E UNICODE #{se(postgres_dir)}"
142
171
  File.open(File.join(data_dir, "postgres", "postgresql.conf"), "a") {|f|
143
- f.write ERB.new(File.read(File.join(config_src_dir, "postgresql.conf"))).result
172
+ f.write ERB.new(File.read(postgresql_conf_path)).result
144
173
  }
145
174
 
146
- # setup functions
147
- run_setup_command %w[pg_ctl -D] + [File.join(data_dir, 'postgres')] + %w[start]
175
+ # 2. postgres -D postgres_dir -c listen_addresses=
176
+ # start postgres without listening on TCP
177
+ postgres_cmd = "postgres -D #{se(postgres_dir)} -c listen_addresses="
178
+ puts "setup> #{postgres_cmd}"
179
+ pid = spawn postgres_cmd
180
+
181
+ # 3. psql < pgsql/setup.sql
148
182
  begin
149
- sleep 1
183
+ # waits for spinup of postgres
184
+ sleep 2
185
+ puts "initializing database..."
186
+ sleep 8
150
187
 
151
- run_setup_command "psql -h 127.0.0.1 -p #{setup_params[:backend_port]} -U pg postgres < #{File.join(pgsql_dir, "setup.sql")}"
188
+ psql_cmd = "psql -h #{se(@config[:unix_socket_directory])} -p #{@config[:backend_port]} -U pg postgres"
189
+ setup_cmd "#{psql_cmd} < #{se(setup_sql_path)}"
152
190
  ensure
153
- run_setup_command %w[pg_ctl -D] + [File.join(data_dir, 'postgres')] + %w[stop]
191
+ # 4. shutdown postgres
192
+ Process.kill(:SIGQUIT, pid)
154
193
  end
194
+ Process.waitpid(pid)
155
195
 
156
196
  puts <<EOF
157
197
 
@@ -203,7 +243,9 @@ when :passwd
203
243
  binary = File.join(prefix, "bin", 'pg_md5')
204
244
 
205
245
  data_dir = config[:data_dir]
206
- args = ["-f", File.join(data_dir, "pgpool", "pgpool.conf"), "-p", "-m", "-u"].concat(args)
246
+ pgpool_conf_path = File.join(data_dir, "pgpool", "pgpool.conf")
247
+
248
+ args = ["-f", pgpool_conf_path, "-p", "-m", "-u"].concat(args)
207
249
 
208
250
  puts "#{binary} #{args.join(' ')}"
209
251
  system binary, *args
@@ -1,2 +1,2 @@
1
1
  port = <%= @config[:backend_port] %>
2
- unix_socket_directory = '<%= @config[:unix_socket_directory] %>'
2
+ unix_socket_directories = '<%= @config[:unix_socket_directory] %>'
data/ext/depend CHANGED
@@ -1,8 +1,16 @@
1
1
  # vim: ft=make noexpandtab
2
2
 
3
- INSTALL_DIR := $(if $(rubyarchdir),$(rubyarchdir),$(RUBYARCHDIR))/prestogres
3
+ # normalize rubyarchdir which is not available depending on rake or gem
4
+ narchdir = $(if $(rubyarchdir),$(rubyarchdir),$(RUBYARCHDIR))
4
5
 
5
- CFLAGS += -DPRESTOGRES_PREFIX="\"$(INSTALL_DIR)\""
6
+ # hack for RubyGems >= 1.8.26
7
+ final_archdir = $(if $(findstring .gem.,$(narchdir)),$(dir $(narchdir)),$(narchdir))
8
+
9
+ INSTALL_DATA = $(realpath $(final_archdir))/prestogres
10
+
11
+ PGPOOL2_PATH = $(realpath $(srcdir)/../pgpool2)
12
+
13
+ CFLAGS += -DPRESTOGRES_PREFIX="\"$(INSTALL_DATA)\""
6
14
 
7
15
  all: pgpool2
8
16
 
@@ -12,10 +20,10 @@ install: install-pgpool2
12
20
 
13
21
  pgpool2:
14
22
  mkdir -p build
15
- cd build && ../../pgpool2/configure \
16
- CFLAGS="-I$(CURDIR)/../pgpool2" \
23
+ cd build && "$(PGPOOL2_PATH)/configure" \
24
+ CFLAGS="-I$(PGPOOL2_PATH)" \
17
25
  --with-openssl \
18
- --prefix="$(INSTALL_DIR)"
26
+ --prefix="$(INSTALL_DATA)"
19
27
  cd build && make sysconfdir=/opt/prestogres/etc
20
28
 
21
29
  clean-pgpool2:
data/pgpool2/child.c CHANGED
@@ -295,6 +295,9 @@ void do_child(int unix_fd, int inet_fd)
295
295
  goto retry_startup;
296
296
  }
297
297
 
298
+ /* this should run before ClientAuthentication */
299
+ pool_prestogres_set_defaults(sp);
300
+
298
301
  if (pool_config->enable_pool_hba)
299
302
  {
300
303
  /*
@@ -332,9 +335,6 @@ void do_child(int unix_fd, int inet_fd)
332
335
  }
333
336
  }
334
337
 
335
- /* this should run after ClientAuthentication */
336
- pool_prestogres_init_session(frontend);
337
-
338
338
  /*
339
339
  * Ok, negotiation with frontend has been done. Let's go to the
340
340
  * next step. Connect to backend if there's no existing
data/pgpool2/pool.h CHANGED
@@ -652,6 +652,6 @@ extern const char* presto_external_auth_prog;
652
652
  int send_md5auth_request(POOL_CONNECTION *frontend, int protoMajor, char *salt);
653
653
  int read_password_packet(POOL_CONNECTION *frontend, int protoMajor, char *password, int *pwdSize);
654
654
 
655
- void pool_prestogres_init_session(POOL_CONNECTION *frontend);
655
+ void pool_prestogres_set_defaults(StartupPacket *sp);
656
656
 
657
657
  #endif /* POOL_H */
@@ -1896,7 +1896,6 @@ int pool_init_config(void)
1896
1896
 
1897
1897
  pool_config->presto_server = "";
1898
1898
  pool_config->presto_catalog = "";
1899
- pool_config->presto_schema = "default";
1900
1899
  pool_config->presto_external_auth_prog = NULL;
1901
1900
 
1902
1901
  pool_config->replication_mode = 0;
@@ -2599,24 +2598,6 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context)
2599
2598
  }
2600
2599
  pool_config->presto_catalog = str;
2601
2600
  }
2602
- else if (!strcmp(key, "presto_schema") && CHECK_CONTEXT(INIT_CONFIG, context))
2603
- {
2604
- char *str;
2605
-
2606
- if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY)
2607
- {
2608
- PARSE_ERROR();
2609
- fclose(fd);
2610
- return(-1);
2611
- }
2612
- str = extract_string(yytext, token);
2613
- if (str == NULL)
2614
- {
2615
- fclose(fd);
2616
- return(-1);
2617
- }
2618
- pool_config->presto_schema = str;
2619
- }
2620
2601
  else if (!strcmp(key, "presto_external_auth_prog") && CHECK_CONTEXT(INIT_CONFIG, context))
2621
2602
  {
2622
2603
  char *str;
data/pgpool2/pool_hba.c CHANGED
@@ -1709,23 +1709,23 @@ static POOL_STATUS pool_prestogres_hba_auth_external(POOL_CONNECTION *frontend)
1709
1709
  return POOL_CONTINUE;
1710
1710
  }
1711
1711
 
1712
- void pool_prestogres_init_session(POOL_CONNECTION *frontend)
1712
+ void pool_prestogres_set_defaults(StartupPacket *sp)
1713
1713
  {
1714
1714
  if (presto_server == NULL) {
1715
1715
  presto_server = pool_config->presto_server;
1716
1716
  }
1717
1717
  if (presto_user == NULL) {
1718
- presto_user = frontend->username;
1718
+ presto_user = strdup(sp->user);
1719
1719
  }
1720
1720
  if (presto_catalog == NULL) {
1721
1721
  presto_catalog = pool_config->presto_catalog;
1722
1722
  }
1723
1723
  if (presto_schema == NULL) {
1724
- presto_schema = pool_config->presto_schema;
1724
+ presto_schema = strdup(sp->database);
1725
1725
  }
1726
- pool_debug("pool_prestogres_init_session: presto_server: %s", presto_server);
1727
- pool_debug("pool_prestogres_init_session: presto_user: %s", presto_user);
1728
- pool_debug("pool_prestogres_init_session: presto_catalog: %s", presto_catalog);
1729
- pool_debug("pool_prestogres_init_session: presto_schema: %s", presto_schema);
1726
+ pool_debug("pool_prestogres_set_defaults: presto_server: %s", presto_server);
1727
+ pool_debug("pool_prestogres_set_defaults: presto_user: %s", presto_user);
1728
+ pool_debug("pool_prestogres_set_defaults: presto_catalog: %s", presto_catalog);
1729
+ pool_debug("pool_prestogres_set_defaults: presto_schema: %s", presto_schema);
1730
1730
  }
1731
1731
 
@@ -404,7 +404,31 @@ static void run_and_rewrite_system_catalog_query(POOL_SESSION_CONTEXT* session_c
404
404
  POOL_CONNECTION_POOL *backend = session_context->backend;
405
405
  con = CONNECTION(backend, session_context->load_balance_node_id);
406
406
 
407
- /* build query */
407
+ /* build SET query */
408
+ buffer = rewrite_query_string_buffer;
409
+ bufend = buffer + sizeof(rewrite_query_string_buffer);
410
+
411
+ buffer = strcpy_capped(buffer, bufend - buffer, "set search_path to E'");
412
+ buffer = strcpy_capped_escaped(buffer, bufend - buffer, presto_schema, "'\\");
413
+ buffer = strcpy_capped(buffer, bufend - buffer, "'");
414
+
415
+ if (buffer == NULL) {
416
+ rewrite_error_query(query_context, "schema name too long", NULL);
417
+ return;
418
+ }
419
+
420
+ /* run SET query */
421
+ status = do_query_or_get_error_message(con,
422
+ rewrite_query_string_buffer, &res, MAJOR(backend), &errmsg, &errcode);
423
+ free_select_result(res);
424
+
425
+ if (errmsg != NULL) {
426
+ rewrite_error_query(query_context, errmsg, errcode);
427
+ } else if (status != POOL_CONTINUE) {
428
+ rewrite_error_query(query_context, "Unknown execution error", NULL);
429
+ }
430
+
431
+ /* build run_system_catalog_as_temp_table query */
408
432
  buffer = rewrite_query_string_buffer;
409
433
  bufend = buffer + sizeof(rewrite_query_string_buffer);
410
434
 
@@ -415,6 +439,8 @@ static void run_and_rewrite_system_catalog_query(POOL_SESSION_CONTEXT* session_c
415
439
  buffer = strcpy_capped(buffer, bufend - buffer, "', E'");
416
440
  buffer = strcpy_capped_escaped(buffer, bufend - buffer, presto_catalog, "'\\");
417
441
  buffer = strcpy_capped(buffer, bufend - buffer, "', E'");
442
+ buffer = strcpy_capped_escaped(buffer, bufend - buffer, presto_schema, "'\\");
443
+ buffer = strcpy_capped(buffer, bufend - buffer, "', E'");
418
444
  buffer = strcpy_capped_escaped(buffer, bufend - buffer, PRESTO_RESULT_TABLE_NAME, "'\\");
419
445
  buffer = strcpy_capped(buffer, bufend - buffer, "', E'");
420
446
  buffer = strcpy_capped_escaped(buffer, bufend - buffer, query_context->original_query, "'\\");
@@ -425,7 +451,7 @@ static void run_and_rewrite_system_catalog_query(POOL_SESSION_CONTEXT* session_c
425
451
  return;
426
452
  }
427
453
 
428
- /* run query */
454
+ /* run run_system_catalog_as_temp_table query */
429
455
  status = do_query_or_get_error_message(con,
430
456
  rewrite_query_string_buffer, &res, MAJOR(backend), &errmsg, &errcode);
431
457
  free_select_result(res);
data/pgsql/prestogres.py CHANGED
@@ -6,7 +6,7 @@ import time
6
6
  # convert Presto query result type to PostgreSQL type
7
7
  def _pg_result_type(presto_type):
8
8
  if presto_type == "varchar":
9
- return "text"
9
+ return "varchar(255)"
10
10
  elif presto_type == "bigint":
11
11
  return "bigint"
12
12
  elif presto_type == "boolean":
@@ -19,7 +19,7 @@ def _pg_result_type(presto_type):
19
19
  # convert Presto type to PostgreSQL type
20
20
  def _pg_table_type(presto_type):
21
21
  if presto_type == "varchar":
22
- return "varchar(100)"
22
+ return "varchar(255)"
23
23
  elif presto_type == "bigint":
24
24
  return "bigint"
25
25
  elif presto_type == "boolean":
@@ -30,7 +30,7 @@ def _pg_table_type(presto_type):
30
30
  raise Exception("unknown table column type: " + plpy.quote_ident(presto_type))
31
31
 
32
32
  # build CREATE TEMPORARY TABLE statement
33
- def _build_create_temp_table_sql(table_name, column_names, column_types, not_nulls=None):
33
+ def _build_create_temp_table_sql(table_name, column_names, column_types):
34
34
  create_sql = "create temporary table %s (\n " % plpy.quote_ident(table_name)
35
35
 
36
36
  first = True
@@ -44,9 +44,26 @@ def _build_create_temp_table_sql(table_name, column_names, column_types, not_nul
44
44
  create_sql += " "
45
45
  create_sql += column_type
46
46
 
47
- # TODO not null
48
- #if not column.nullable:
49
- # create_sql += " not null"
47
+ create_sql += "\n)"
48
+ return create_sql
49
+
50
+ # build CREATE TABLE statement
51
+ def _build_create_table_sql(schema_name, table_name, column_names, column_types, not_nulls):
52
+ create_sql = "create table %s.%s (\n " % (plpy.quote_ident(schema_name), plpy.quote_ident(table_name))
53
+
54
+ first = True
55
+ for column_name, column_type, not_null in zip(column_names, column_types, not_nulls):
56
+ if first:
57
+ first = False
58
+ else:
59
+ create_sql += ",\n "
60
+
61
+ create_sql += plpy.quote_ident(column_name)
62
+ create_sql += " "
63
+ create_sql += column_type
64
+
65
+ if not_null:
66
+ create_sql += " not null"
50
67
 
51
68
  create_sql += "\n)"
52
69
  return create_sql
@@ -100,21 +117,28 @@ class SchemaCache(object):
100
117
  self.server = None
101
118
  self.user = None
102
119
  self.catalog = None
120
+ self.schema = None
103
121
  self.schema_names = None
104
122
  self.statements = None
105
123
  self.expire_time = None
124
+ self.query_cache = {}
106
125
 
107
- def is_cached(self, server, user, catalog, current_time):
108
- return self.server == server and self.user == user and self.catalog == catalog \
126
+ def is_cached(self, server, user, catalog, schema, current_time):
127
+ return self.server == server and self.user == user \
128
+ and self.catalog == catalog and self.schema == schema \
109
129
  and self.statements is not None and current_time < self.expire_time
110
130
 
111
- def set_cache(self, server, user, catalog, schema_names, statements, expire_time):
131
+ def set_cache(self, server, user, catalog, schema, schema_names, statements, expire_time):
112
132
  self.server = server
113
133
  self.user = user
114
134
  self.catalog = catalog
135
+ self.schema = schema
115
136
  self.schema_names = schema_names
116
137
  self.statements = statements
117
138
  self.expire_time = expire_time
139
+ self.query_cache = {}
140
+
141
+ QueryResult = namedtuple("QueryResult", ("column_names", "column_types", "result"))
118
142
 
119
143
  OidToTypeNameMapping = {}
120
144
 
@@ -171,14 +195,15 @@ def run_presto_as_temp_table(server, user, catalog, schema, result_table, query)
171
195
  e.__class__.__module__ = "__main__"
172
196
  raise
173
197
 
174
- def run_system_catalog_as_temp_table(server, user, catalog, result_table, query):
198
+ def run_system_catalog_as_temp_table(server, user, catalog, schema, result_table, query):
175
199
  try:
176
- client = presto_client.Client(server=server, user=user, catalog=catalog, schema="default")
200
+ client = presto_client.Client(server=server, user=user, catalog=catalog, schema=schema)
177
201
 
178
202
  # create SQL statements which put data to system catalogs
179
- if SchemaCacheEntry.is_cached(server, user, catalog, time.time()):
203
+ if SchemaCacheEntry.is_cached(server, user, catalog, schema, time.time()):
180
204
  schema_names = SchemaCacheEntry.schema_names
181
205
  statements = SchemaCacheEntry.statements
206
+ query_cache = SchemaCacheEntry.query_cache
182
207
 
183
208
  else:
184
209
  # get table list
@@ -223,57 +248,69 @@ def run_system_catalog_as_temp_table(server, user, catalog, result_table, query)
223
248
  column_types.append(_pg_table_type(column.type))
224
249
  not_nulls.append(not column.nullable)
225
250
 
226
- create_sql = _build_create_temp_table_sql(table_name, column_names, column_types, not_nulls)
251
+ create_sql = _build_create_table_sql(schema_name, table_name, column_names, column_types, not_nulls)
227
252
  statements.append(create_sql)
228
253
 
229
- # cache expires after 10 seconds
230
- SchemaCacheEntry.set_cache(server, user, catalog, schema_names, statements, time.time() + 10)
254
+ # cache expires after 60 seconds
255
+ SchemaCacheEntry.set_cache(server, user, catalog, schema, schema_names, statements, time.time() + 60)
256
+ query_cache = {}
231
257
 
232
- # enter subtransaction to rollback tables right after running the query
233
- subxact = plpy.subtransaction()
234
- subxact.enter()
235
- try:
236
- # delete all schemas excepting prestogres_catalog
237
- sql = "select n.nspname as schema_name from pg_catalog.pg_namespace n" \
238
- " where n.nspname not in ('prestogres_catalog', 'pg_catalog', 'information_schema', 'public')" \
239
- " and n.nspname !~ '^pg_toast'"
240
- for row in plpy.cursor(sql):
241
- plpy.execute("drop schema %s cascade" % plpy.quote_ident(row["schema_name"]))
242
-
243
- # delete all tables in prestogres_catalog
244
- # relkind = 'r' takes only tables and skip views, indexes, etc.
245
- sql = "select n.nspname as schema_name, c.relname as table_name from pg_catalog.pg_class c" \
246
- " left join pg_catalog.pg_namespace n on n.oid = c.relnamespace" \
247
- " where c.relkind in ('r')" \
248
- " and n.nspname in ('prestogres_catalog')" \
249
- " and n.nspname !~ '^pg_toast'"
250
- for row in plpy.cursor(sql):
251
- plpy.execute("drop table %s.%s" % (plpy.quote_ident(row["schema_name"]), plpy.quote_ident(row["table_name"])))
252
-
253
- # create schemas
254
- for schema_name in schema_names:
255
- try:
256
- plpy.execute("create schema %s" % plpy.quote_ident(schema_name))
257
- except:
258
- # ignore error
259
- pass
260
-
261
- # create tables
262
- for statement in statements:
263
- plpy.execute(statement)
264
-
265
- # run the actual query
266
- metadata = plpy.execute(query)
267
- result = map(lambda row: row.values(), metadata)
258
+ query_result = query_cache.get(query)
268
259
 
269
- finally:
270
- # rollback subtransaction
271
- subxact.exit("rollback subtransaction", None, None)
260
+ if query_result:
261
+ column_names = query_result.column_names
262
+ column_types = query_result.column_types
263
+ result = query_result.result
272
264
 
273
- # table schema
274
- oid_to_type_name = _load_oid_to_type_name_mapping(metadata.coltypes())
275
- column_names = metadata.colnames()
276
- column_types = map(oid_to_type_name.get, metadata.coltypes())
265
+ else:
266
+ # enter subtransaction to rollback tables right after running the query
267
+ subxact = plpy.subtransaction()
268
+ subxact.enter()
269
+ try:
270
+ # delete all schemas excepting prestogres_catalog
271
+ sql = "select n.nspname as schema_name from pg_catalog.pg_namespace n" \
272
+ " where n.nspname not in ('prestogres_catalog', 'pg_catalog', 'information_schema', 'public')" \
273
+ " and n.nspname !~ '^pg_toast'"
274
+ for row in plpy.cursor(sql):
275
+ plpy.execute("drop schema %s cascade" % plpy.quote_ident(row["schema_name"]))
276
+
277
+ # delete all tables in prestogres_catalog
278
+ # relkind = 'r' takes only tables and skip views, indexes, etc.
279
+ sql = "select n.nspname as schema_name, c.relname as table_name from pg_catalog.pg_class c" \
280
+ " left join pg_catalog.pg_namespace n on n.oid = c.relnamespace" \
281
+ " where c.relkind in ('r')" \
282
+ " and n.nspname in ('prestogres_catalog')" \
283
+ " and n.nspname !~ '^pg_toast'"
284
+ for row in plpy.cursor(sql):
285
+ plpy.execute("drop table %s.%s" % (plpy.quote_ident(row["schema_name"]), plpy.quote_ident(row["table_name"])))
286
+
287
+ # create schemas
288
+ for schema_name in schema_names:
289
+ try:
290
+ plpy.execute("create schema %s" % plpy.quote_ident(schema_name))
291
+ except:
292
+ # ignore error
293
+ pass
294
+
295
+ # create tables
296
+ for statement in statements:
297
+ plpy.execute(statement)
298
+
299
+ # run the actual query
300
+ metadata = plpy.execute(query)
301
+ column_names = metadata.colnames()
302
+ column_type_oids = metadata.coltypes()
303
+ result = map(lambda row: map(row.get, column_names), metadata)
304
+
305
+ # table schema
306
+ oid_to_type_name = _load_oid_to_type_name_mapping(column_type_oids)
307
+ column_types = map(oid_to_type_name.get, column_type_oids)
308
+
309
+ query_cache[query] = QueryResult(column_names, column_types, result)
310
+
311
+ finally:
312
+ # rollback subtransaction
313
+ subxact.exit("rollback subtransaction", None, None)
277
314
 
278
315
  create_sql = _build_create_temp_table_sql(result_table, column_names, column_types)
279
316
  insert_sql, values_sql_format = _build_insert_into_sql(result_table, column_names)
data/pgsql/setup.sql CHANGED
@@ -19,10 +19,11 @@ create or replace function prestogres_catalog.run_system_catalog_as_temp_table(
19
19
  "server" text,
20
20
  "user" text,
21
21
  "catalog" text,
22
+ "schema" text,
22
23
  "table_name" text,
23
24
  "query" text)
24
25
  returns void as $$
25
26
  import prestogres
26
- prestogres.run_system_catalog_as_temp_table(server, user, catalog, table_name, query)
27
+ prestogres.run_system_catalog_as_temp_table(server, user, catalog, schema, table_name, query)
27
28
  $$ language plpythonu;
28
29
 
metadata CHANGED
@@ -1,55 +1,62 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prestogres
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Sadayuki Furuhashi
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-01-25 00:00:00.000000000 Z
12
+ date: 2014-02-07 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - "~>"
19
+ - - ~>
18
20
  - !ruby/object:Gem::Version
19
21
  version: '1.0'
20
22
  type: :development
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - "~>"
27
+ - - ~>
25
28
  - !ruby/object:Gem::Version
26
29
  version: '1.0'
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: rake
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - "~>"
35
+ - - ~>
32
36
  - !ruby/object:Gem::Version
33
37
  version: 0.9.2
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - "~>"
43
+ - - ~>
39
44
  - !ruby/object:Gem::Version
40
45
  version: 0.9.2
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: rake-compiler
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
- - - "~>"
51
+ - - ~>
46
52
  - !ruby/object:Gem::Version
47
53
  version: 0.8.3
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
- - - "~>"
59
+ - - ~>
53
60
  - !ruby/object:Gem::Version
54
61
  version: 0.8.3
55
62
  description: Presto PostgreSQL protocol gateway
@@ -61,10 +68,9 @@ extensions:
61
68
  - ext/extconf.rb
62
69
  extra_rdoc_files: []
63
70
  files:
64
- - ".gitignore"
71
+ - .gitignore
65
72
  - ChangeLog
66
73
  - Gemfile
67
- - Gemfile.lock
68
74
  - LICENSE
69
75
  - NOTICE
70
76
  - README.md
@@ -463,25 +469,32 @@ files:
463
469
  homepage: https://github.com/treasure-data/prestogres
464
470
  licenses:
465
471
  - Apache 2.0
466
- metadata: {}
467
472
  post_install_message:
468
473
  rdoc_options: []
469
474
  require_paths:
470
475
  - lib
471
476
  required_ruby_version: !ruby/object:Gem::Requirement
477
+ none: false
472
478
  requirements:
473
- - - ">="
479
+ - - ! '>='
474
480
  - !ruby/object:Gem::Version
475
481
  version: '0'
482
+ segments:
483
+ - 0
484
+ hash: -1048444669451031740
476
485
  required_rubygems_version: !ruby/object:Gem::Requirement
486
+ none: false
477
487
  requirements:
478
- - - ">="
488
+ - - ! '>='
479
489
  - !ruby/object:Gem::Version
480
490
  version: '0'
491
+ segments:
492
+ - 0
493
+ hash: -1048444669451031740
481
494
  requirements: []
482
495
  rubyforge_project:
483
- rubygems_version: 2.2.0
496
+ rubygems_version: 1.8.23
484
497
  signing_key:
485
- specification_version: 4
498
+ specification_version: 3
486
499
  summary: Presto PostgreSQL protocol gateway
487
500
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: fdbbafba90e2dde6d7340746b30d369eda073ed9
4
- data.tar.gz: 57d91cbb2bb74c2ce53132ea9309eb9a0cb47e09
5
- SHA512:
6
- metadata.gz: f166e0435a473ec6930522f0a139733f24227a8b0045725fc1e89f4afda25c6fd589c2dc121a46e99c82f79bba135c601b42fec45651c66c185a0aaae6f52eb6
7
- data.tar.gz: c351d1a8fe7c59cc7b9a2ec603935766141958df839d4f7179a9921e9410b2da513f6b05beab2f6b5d3d96be309542df876b01fce42f4021f0692d40ceb84652
data/Gemfile.lock DELETED
@@ -1,20 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- prestogres (0.1.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- rake (0.9.6)
10
- rake-compiler (0.8.3)
11
- rake
12
-
13
- PLATFORMS
14
- ruby
15
-
16
- DEPENDENCIES
17
- bundler (~> 1.0)
18
- prestogres!
19
- rake (~> 0.9.2)
20
- rake-compiler (~> 0.8.3)