prestogres 0.1.0 → 0.2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fdbbafba90e2dde6d7340746b30d369eda073ed9
4
+ data.tar.gz: 57d91cbb2bb74c2ce53132ea9309eb9a0cb47e09
5
+ SHA512:
6
+ metadata.gz: f166e0435a473ec6930522f0a139733f24227a8b0045725fc1e89f4afda25c6fd589c2dc121a46e99c82f79bba135c601b42fec45651c66c185a0aaae6f52eb6
7
+ data.tar.gz: c351d1a8fe7c59cc7b9a2ec603935766141958df839d4f7179a9921e9410b2da513f6b05beab2f6b5d3d96be309542df876b01fce42f4021f0692d40ceb84652
data/ChangeLog ADDED
@@ -0,0 +1,16 @@
1
+
2
+ 2014-01-24 version 0.2.0:
3
+
4
+ * Authentication mechanisms support pg_database and pg_user options to
5
+ overwrite connecting PostgreSQL database and role name
6
+ * Forward error message from PostgreSQL to clients instead of killing the
7
+ session so that clients can know the reason
8
+ * Reject 'P' (Parse) command to reject extended query protocol immediately
9
+ * Enabled timeout in Presto HTTP client
10
+ * Queries to system catalogs delete created tables by rollbacking
11
+ subtransaction so that other sessions does not conflict
12
+
13
+ 2014-01-15 version 0.1.0:
14
+
15
+ * First release
16
+
data/README.md CHANGED
@@ -12,7 +12,7 @@ With Prestogres, you can use PostgreSQL clients to run queries on Presto:
12
12
  * [PostgreSQL JDBC driver](http://jdbc.postgresql.org/)
13
13
  * other PostgreSQL client libraries
14
14
 
15
- Prestogres also offers password-based authorization (Presto doesn't have authorization by default).
15
+ Prestogres also offers password-based authentication and SSL.
16
16
 
17
17
  ## How it works?
18
18
 
@@ -130,6 +130,8 @@ host altdb pg 0.0.0.0/0 prestogres_md5 s
130
130
  host all all 0.0.0.0/0 prestogres_external auth_prog:/opt/prestogres/auth.py
131
131
  ```
132
132
 
133
+ See also *Creating database* section.
134
+
133
135
  #### prestogres_md5 method
134
136
 
135
137
  This authentication method uses a password file **\<data_dir\>/pgpool2/pool_passwd** to authenticate an user. You can use `prestogres passwd` command to add an user to this file:
@@ -145,6 +147,8 @@ In pool_hba.conf file, you can set following options to OPTIONS field:
145
147
  * **catalog**: Catalog (connector) name of Presto, which overwrites `presto_catalog` parameter in pgpool.conf.
146
148
  * **schema**: Schema name of Presto, which overwrites `presto_schema` parameter in pgpool.conf.
147
149
  * **user**: User name to run queries on Presto. By default, Prestogres uses the same user name used to login to pgpool-II.
150
+ * **pg_database**: Overwrite database to connect to PostgreSQL.
151
+ * **pg_user**: Overwrite user name to connect to PostgreSQL.
148
152
 
149
153
 
150
154
  #### prestogres_external method
@@ -164,18 +168,41 @@ address:IPADDR
164
168
 
165
169
  ```
166
170
 
167
- If you want to allow this connection, the program optionally prints following lines to STDOUT, and exists with status code 0:
171
+ If you want to allow this connection, the program optionally prints parameters as following to STDOUT, and exists with status code 0:
168
172
 
169
173
  ```
170
174
  server:PRESTO_SERVER_ADDRESS
171
175
  catalog:PRESTO_CATALOG_NAME
172
176
  schema:PRESTO_SCHEMA_NAME
177
+ user:USER_NAME
178
+ pg_database:DATABASE
179
+ pg_user:USER_NAME
173
180
 
174
181
  ```
175
182
 
183
+ See *pgool.conf file* section for available parameters.
184
+
176
185
  If you want to reject this connection, the program exists with non-0 status code.
177
186
 
178
187
 
188
+ ### Creating database on PostgreSQL
189
+
190
+ Prestogres setups a database named *postgres* on PostgreSQL by default. But you may want to create other databases
191
+ to take advantage of above authentication mechanism.
192
+
193
+ To create new databases:
194
+
195
+ 1. Create a new PostgreSQL database using `createdb` command. Port number is **6432** because you login to PostgreSQL directly:
196
+ ```
197
+ $ createdb -h localhost -p 6432 -U pg newdb
198
+ ```
199
+
200
+ 2. Initialize the database using statements shown by `prestogres show_init_sql` command:
201
+ ```
202
+ $ prestogres show_init_sql | psql -h localhost -p 6432 -U pg newdb
203
+ ```
204
+
205
+
179
206
  ### prestogres command
180
207
 
181
208
  Usage of `prestogres` command:
@@ -191,6 +218,7 @@ commands:
191
218
  pg_ctl stop stop postgres server daemon process
192
219
  postgres start postgres server as a foreground process
193
220
  passwd <USER NAME> add new md5 password entry for an user
221
+ show_init_sql display statements to initialize a new PostgreSQL database
194
222
  ```
195
223
 
196
224
  ## Development
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/bin/prestogres CHANGED
@@ -17,6 +17,7 @@ def usage(error=nil)
17
17
  puts " pg_ctl stop stop postgres server daemon process"
18
18
  puts " postgres start postgres server as a foreground process"
19
19
  puts " passwd <USER NAME> add new md5 password entry for an user"
20
+ puts " show_init_sql display statements to initialize a new PostgreSQL database"
20
21
  puts ""
21
22
  puts "error: #{error}" if error
22
23
  exit 0
@@ -53,6 +54,9 @@ ARGV.each_with_index do |a,i|
53
54
  when "passwd"
54
55
  config[:command] = :passwd
55
56
  break
57
+ when "show_init_sql"
58
+ config[:command] = :show_init_sql
59
+ break
56
60
  end
57
61
  end
58
62
 
@@ -97,13 +101,14 @@ when :setup
97
101
  puts "** setup failed **"
98
102
  puts "******************"
99
103
  puts ""
100
- puts "-D directory is inconsistent."
101
- puts "If you're running command on Mac OS X, you might need to run following commands:"
104
+ puts " * -D directory is inconsistent."
105
+ puts ""
106
+ puts " * If you're running command on Mac OS X, you might need to run following commands:"
102
107
  puts ""
103
- puts " $ sudo sysctl -w kern.sysv.shmmax=1073741824"
104
- puts " $ sudo sysctl -w kern.sysv.shmall=1073741824"
108
+ puts " $ sudo sysctl -w kern.sysv.shmmax=1073741824"
109
+ puts " $ sudo sysctl -w kern.sysv.shmall=1073741824"
105
110
  puts ""
106
- puts "Please delete the directory (rm -rf) first before retrying."
111
+ puts " * Please delete the directory (rm -rf) first before retrying."
107
112
  puts ""
108
113
  exit 1
109
114
  end
@@ -143,8 +148,7 @@ when :setup
143
148
  begin
144
149
  sleep 1
145
150
 
146
- run_setup_command "psql -h 127.0.0.1 -p #{setup_params[:backend_port]} -U pg postgres < #{File.join(pgsql_dir, "setup_language.sql")}"
147
- run_setup_command "psql -h 127.0.0.1 -p #{setup_params[:backend_port]} -U pg postgres < #{File.join(pgsql_dir, "setup_functions.sql")}"
151
+ run_setup_command "psql -h 127.0.0.1 -p #{setup_params[:backend_port]} -U pg postgres < #{File.join(pgsql_dir, "setup.sql")}"
148
152
  ensure
149
153
  run_setup_command %w[pg_ctl -D] + [File.join(data_dir, 'postgres')] + %w[stop]
150
154
  end
@@ -210,6 +214,10 @@ when :passwd
210
214
  exit $?.exitstatus
211
215
  end
212
216
 
217
+ when :show_init_sql
218
+ pgsql_dir = File.join(File.dirname(__FILE__), "..", "pgsql")
219
+ STDOUT.write File.read(File.join(pgsql_dir, "setup.sql"))
220
+
213
221
  else
214
222
  unless config[:data_dir]
215
223
  usage "-D option is required"
data/pgpool2/child.c CHANGED
@@ -95,6 +95,46 @@ volatile sig_atomic_t got_sighup = 0;
95
95
  char remote_host[NI_MAXHOST]; /* client host */
96
96
  char remote_port[NI_MAXSERV]; /* client port */
97
97
 
98
+ static void rebuild_startup_packet(StartupPacket *sp)
99
+ {
100
+ if (sp->major == PROTO_MAJOR_V2) {
101
+ StartupPacket_v2 *sp2 = (StartupPacket_v2 *)(sp->startup_packet);
102
+ strncpy(sp2->database, sp2->database, SM_DATABASE);
103
+ strncpy(sp2->user, sp->user, SM_USER);
104
+
105
+ } else if (sp->major == PROTO_MAJOR_V3) {
106
+ int append_size;
107
+ char *data, *p;
108
+
109
+ append_size = strlen("database") + strlen("user") + strlen(sp->database) + strlen(sp->user) + 4;
110
+
111
+ data = malloc(sp->len + append_size);
112
+ if (data == NULL) {
113
+ pool_error("rebuild_startup_packet: out of memory");
114
+ exit(1);
115
+ }
116
+ memcpy(data, sp->startup_packet, sp->len);
117
+ p = data + sp->len - 1; /* remove last terminator byte */
118
+
119
+ strcpy(p, "database");
120
+ p += (strlen("database") + 1);
121
+ strcpy(p, sp->database);
122
+ p += (strlen(sp->database) + 1);
123
+
124
+ strcpy(p, "user");
125
+ p += (strlen("user") + 1);
126
+ strcpy(p, sp->user);
127
+ p += (strlen(sp->user) + 1);
128
+
129
+ *p = '\0'; /* add terminator byte */
130
+
131
+ free(sp->startup_packet);
132
+ sp->startup_packet = data;
133
+
134
+ sp->len = sp->len + append_size;
135
+ }
136
+ }
137
+
98
138
  /*
99
139
  * child main loop
100
140
  */
@@ -276,6 +316,20 @@ void do_child(int unix_fd, int inet_fd)
276
316
  child_exit(1);
277
317
  }
278
318
  ClientAuthentication(frontend);
319
+
320
+ /* ClientAuthentication can overwrite database and user */
321
+ if (strcmp(sp->database, frontend->database) || strcmp(sp->user, frontend->username)) {
322
+ free(sp->database);
323
+ sp->database = strdup(frontend->database);
324
+ free(sp->user);
325
+ sp->user = strdup(frontend->username);
326
+ if (frontend->username == NULL)
327
+ {
328
+ pool_error("do_child: strdup failed: %s\n", strerror(errno));
329
+ child_exit(1);
330
+ }
331
+ rebuild_startup_packet(sp);
332
+ }
279
333
  }
280
334
 
281
335
  /* this should run after ClientAuthentication */
data/pgpool2/pool.h CHANGED
@@ -605,9 +605,11 @@ extern void reset_connection(void);
605
605
  extern void per_node_statement_log(POOL_CONNECTION_POOL *backend, int node_id, char *query);
606
606
  extern void per_node_error_log(POOL_CONNECTION_POOL *backend, int node_id, char *query, char *prefix, bool unread);
607
607
  extern int pool_extract_error_message(bool read_kind, POOL_CONNECTION *backend, int major, bool unread, char **message);
608
+ extern int pool_extract_error_message_with_errcode(bool read_kind, POOL_CONNECTION *backend, int major, bool unread, char **message, char **errcode);
608
609
  extern POOL_STATUS do_command(POOL_CONNECTION *frontend, POOL_CONNECTION *backend,
609
610
  char *query, int protoMajor, int pid, int key, int no_ready_for_query);
610
611
  extern POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major);
612
+ extern POOL_STATUS do_query_or_get_error_message(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major, char **error_message, char **errcode);
611
613
  extern void free_select_result(POOL_SELECT_RESULT *result);
612
614
  extern int compare(const void *p1, const void *p2);
613
615
  extern POOL_STATUS do_error_execute_command(POOL_CONNECTION_POOL *backend, int node_id, int major);
data/pgpool2/pool_hba.c CHANGED
@@ -75,8 +75,8 @@ const char* presto_catalog = NULL;
75
75
  const char* presto_schema = NULL;
76
76
  const char* presto_external_auth_prog = NULL;
77
77
 
78
- static bool prestogres_hba_set_session_info(const char* key, const char* value);
79
- static void prestogres_hba_parse_arg(const char* arg);
78
+ static bool prestogres_hba_set_session_info(POOL_CONNECTION *frontend, const char* key, const char* value);
79
+ static void prestogres_hba_parse_arg(POOL_CONNECTION *frontend, const char* arg);
80
80
  static POOL_STATUS pool_prestogres_hba_auth_md5(POOL_CONNECTION *frontend);
81
81
  static POOL_STATUS pool_prestogres_hba_auth_external(POOL_CONNECTION *frontend);
82
82
 
@@ -1497,9 +1497,9 @@ static POOL_STATUS CheckMd5Auth(char *username)
1497
1497
  return POOL_CONTINUE;
1498
1498
  }
1499
1499
 
1500
- static bool prestogres_hba_set_session_info(const char* key, const char* value)
1500
+ static bool prestogres_hba_set_session_info(POOL_CONNECTION *frontend, const char* key, const char* value)
1501
1501
  {
1502
- pool_debug("presto_external_auth_prog: key:%s value:%s", key, value);
1502
+ pool_debug("presto_external_auth_prog: key '%s' value '%s'", key, value);
1503
1503
 
1504
1504
  if (strcmp(key, "server") == 0) {
1505
1505
  presto_server = value;
@@ -1513,6 +1513,14 @@ static bool prestogres_hba_set_session_info(const char* key, const char* value)
1513
1513
  } else if (strcmp(key, "schema") == 0) {
1514
1514
  presto_schema = value;
1515
1515
  return true;
1516
+ } else if (strcmp(key, "pg_user") == 0) {
1517
+ free(frontend->username);
1518
+ frontend->username = strdup(value);
1519
+ return true;
1520
+ } else if (strcmp(key, "pg_database") == 0) {
1521
+ free(frontend->database);
1522
+ frontend->database = strdup(value);
1523
+ return true;
1516
1524
  } else if (strcmp(key, "auth_prog") == 0) {
1517
1525
  presto_external_auth_prog = value;
1518
1526
  return true;
@@ -1522,7 +1530,7 @@ static bool prestogres_hba_set_session_info(const char* key, const char* value)
1522
1530
  return false;
1523
1531
  }
1524
1532
 
1525
- static void prestogres_hba_parse_arg(const char* arg)
1533
+ static void prestogres_hba_parse_arg(POOL_CONNECTION *frontend, const char* arg)
1526
1534
  {
1527
1535
  char *str, *tok;
1528
1536
 
@@ -1539,7 +1547,7 @@ static void prestogres_hba_parse_arg(const char* arg)
1539
1547
  break;
1540
1548
  }
1541
1549
  *p = '\0';
1542
- prestogres_hba_set_session_info(tok, p + 1);
1550
+ prestogres_hba_set_session_info(frontend, tok, p + 1);
1543
1551
  }
1544
1552
  }
1545
1553
 
@@ -1551,7 +1559,7 @@ static POOL_STATUS pool_prestogres_hba_auth_md5(POOL_CONNECTION *frontend)
1551
1559
  static char encbuf[POOL_PASSWD_LEN+1];
1552
1560
  char salt[4];
1553
1561
 
1554
- prestogres_hba_parse_arg(frontend->auth_arg);
1562
+ prestogres_hba_parse_arg(frontend, frontend->auth_arg);
1555
1563
 
1556
1564
  pool_passwd = pool_get_passwd(frontend->username);
1557
1565
  pool_random_salt(salt);
@@ -1659,7 +1667,7 @@ static bool do_external_auth(POOL_CONNECTION* frontend, const char* password)
1659
1667
  pos += strlen(line);
1660
1668
  }
1661
1669
 
1662
- prestogres_hba_parse_arg(buffer);
1670
+ prestogres_hba_parse_arg(frontend, buffer);
1663
1671
 
1664
1672
  if (waitpid(pid, &status, 0) < 0) {
1665
1673
  pool_error("waitpid() failed. reason: %s", strerror(errno));
@@ -1673,12 +1681,12 @@ static POOL_STATUS pool_prestogres_hba_auth_external(POOL_CONNECTION *frontend)
1673
1681
  {
1674
1682
  char *passwd;
1675
1683
 
1676
- prestogres_hba_parse_arg(frontend->auth_arg);
1684
+ prestogres_hba_parse_arg(frontend, frontend->auth_arg);
1677
1685
 
1678
1686
  if (presto_external_auth_prog == NULL) {
1679
1687
  presto_external_auth_prog = pool_config->presto_external_auth_prog;
1680
1688
  if (presto_external_auth_prog == NULL) {
1681
- pool_error("pool_prestogres_hba_auth_external: 'prog:' argument is not set to pool_hba entry for user '%s'", frontend->username);
1689
+ pool_error("pool_prestogres_hba_auth_external: 'auth_prog:' argument is not set to pool_hba entry for user '%s'", frontend->username);
1682
1690
  exit(1);
1683
1691
  }
1684
1692
  }
@@ -2367,6 +2367,11 @@ void free_select_result(POOL_SELECT_RESULT *result)
2367
2367
  * insert_lock(), and the qury is either LOCK or SELECT for UPDATE.
2368
2368
  */
2369
2369
  POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major)
2370
+ {
2371
+ return do_query_or_get_error_message(backend, query, result, major, NULL, NULL);
2372
+ }
2373
+
2374
+ POOL_STATUS do_query_or_get_error_message(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT **result, int major, char **error_message, char **errcode)
2370
2375
  {
2371
2376
  #define DO_QUERY_ALLOC_NUM 1024 /* memory allocation unit for POOL_SELECT_RESULT */
2372
2377
 
@@ -2586,23 +2591,27 @@ POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_RESULT *
2586
2591
  {
2587
2592
  char *message;
2588
2593
 
2589
- if (pool_extract_error_message(false, backend, major, true, &message))
2594
+ if (pool_extract_error_message_with_errcode(false, backend, major, true, &message, errcode))
2590
2595
  {
2591
- pool_error("do_query: error message from backend: %s. Exit this session.", message);
2592
- /*
2593
- * This is fatal. Because: If we operate extended
2594
- * query, backend would not accept subsequent commands
2595
- * until "sync" message issued. However, if sync
2596
- * message issued, unnamed statement/unnamed portal
2597
- * will disappear and will cause lots of problems. If
2598
- * we do not operate extended query, ongoing
2599
- * transaction is aborted, and subsequent query would
2600
- * not accepted. In summary there's no transparent
2601
- * way for frontend to handle error case. The only way
2602
- * is closing this session.
2603
- */
2604
- child_exit(1);
2605
- return POOL_END;
2596
+ if (error_message != NULL) {
2597
+ *error_message = message;
2598
+ } else {
2599
+ pool_error("do_query: error message from backend: %s. Exit this session.", message);
2600
+ /*
2601
+ * This is fatal. Because: If we operate extended
2602
+ * query, backend would not accept subsequent commands
2603
+ * until "sync" message issued. However, if sync
2604
+ * message issued, unnamed statement/unnamed portal
2605
+ * will disappear and will cause lots of problems. If
2606
+ * we do not operate extended query, ongoing
2607
+ * transaction is aborted, and subsequent query would
2608
+ * not accepted. In summary there's no transparent
2609
+ * way for frontend to handle error case. The only way
2610
+ * is closing this session.
2611
+ */
2612
+ child_exit(1);
2613
+ return POOL_END;
2614
+ }
2606
2615
  }
2607
2616
  }
2608
2617
 
@@ -4585,6 +4594,11 @@ static int detect_error(POOL_CONNECTION *backend, char *error_code, int major, c
4585
4594
  * extract error message -1: error)
4586
4595
  */
4587
4596
  int pool_extract_error_message(bool read_kind, POOL_CONNECTION *backend, int major, bool unread, char **message)
4597
+ {
4598
+ return pool_extract_error_message_with_errcode(read_kind, backend, major, unread, message, NULL);
4599
+ }
4600
+
4601
+ int pool_extract_error_message_with_errcode(bool read_kind, POOL_CONNECTION *backend, int major, bool unread, char **message, char **errcode)
4588
4602
  {
4589
4603
  char kind;
4590
4604
  int readlen = 0, len;
@@ -4617,6 +4631,7 @@ int pool_extract_error_message(bool read_kind, POOL_CONNECTION *backend, int maj
4617
4631
  if (major == PROTO_MAJOR_V3)
4618
4632
  {
4619
4633
  char *e;
4634
+ char *bufpos, *bufpos_end;
4620
4635
 
4621
4636
  if (pool_read(backend, &len, sizeof(len)) < 0)
4622
4637
  return -1;
@@ -4649,15 +4664,27 @@ int pool_extract_error_message(bool read_kind, POOL_CONNECTION *backend, int maj
4649
4664
  * (xxxxxx is error message).
4650
4665
  */
4651
4666
  e = str;
4667
+ *message = message_buf;
4668
+ bufpos = message_buf;
4669
+ bufpos_end = message_buf + sizeof(message_buf);
4670
+ bufpos[0] = '\0';
4652
4671
  while (*e)
4653
4672
  {
4654
4673
  if (*e == 'M')
4655
4674
  {
4656
4675
  e++;
4657
- strncpy(message_buf, e, sizeof(message_buf)-1);
4658
- message_buf[sizeof(message_buf)-1] = '\0';
4676
+ strlcpy(bufpos, e, bufpos_end - bufpos - 1);
4677
+ *message = bufpos;
4678
+ bufpos += strlen(bufpos) + 1;
4659
4679
  break;
4660
4680
  }
4681
+ else if (errcode != NULL && *e == 'C')
4682
+ {
4683
+ e++;
4684
+ strlcpy(bufpos, e, bufpos_end - bufpos - 1);
4685
+ *errcode = bufpos;
4686
+ bufpos += strlen(bufpos) + 1;
4687
+ }
4661
4688
  else
4662
4689
  e = e + strlen(e) + 1;
4663
4690
  }
@@ -4678,6 +4705,7 @@ int pool_extract_error_message(bool read_kind, POOL_CONNECTION *backend, int maj
4678
4705
  memcpy(p, str, len);
4679
4706
  memcpy(message_buf, str, len);
4680
4707
  message_buf[len] = '\0';
4708
+ *message = message_buf;
4681
4709
  }
4682
4710
 
4683
4711
  if (unread)
@@ -4687,7 +4715,6 @@ int pool_extract_error_message(bool read_kind, POOL_CONNECTION *backend, int maj
4687
4715
  return -1;
4688
4716
  }
4689
4717
 
4690
- *message = message_buf;
4691
4718
  return 1;
4692
4719
  }
4693
4720