prestogres 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)