prestogres 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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