Permalink
Browse files

Replace "postgres_output row <row>" with "postgres_output text".

This is more general approach, which forces writing proper SQL queries
instead of filtering results on the nginx side and allows for sending
output from multiple rows to end-users.

Discussed with Silly Sad.
  • Loading branch information...
1 parent 2661184 commit 61af6a7cefefa4fc65ec3a21e0985a5fb1152ea5 @PiotrSikora PiotrSikora committed Jun 21, 2011
Showing with 87 additions and 51 deletions.
  1. +5 −5 README.md
  2. +1 −1 src/ngx_postgres_module.c
  3. +29 −41 src/ngx_postgres_output.c
  4. +1 −1 src/ngx_postgres_output.h
  5. +51 −3 t/output.t
View
@@ -89,16 +89,16 @@ This directive can be used more than once within same context.
postgres_output
---------------
-* **syntax**: `postgres_output rds|row|value|binary_value|none [row] [column]`
+* **syntax**: `postgres_output rds|text|value|binary_value|none [row] [column]`
* **default**: `rds`
* **context**: `http`, `server`, `location`, `if location`
Set output format:
-- `rds` - return output in `rds` format (with appropriate
- `Content-Type`),
-- `row` - return all values from a single row from the result-set
- in text format, values are separated by new line (with default `Content-Type`),
+- `rds` - return all values from the result-set in `rds` format
+ (with appropriate `Content-Type`),
+- `text` - return all values from the result-set in text format
+ (with default `Content-Type`), values are separated by new line,
- `value` - return single value from the result-set in text format
(with default `Content-Type`),
- `binary_value` - return single value from the result-set in binary format
@@ -219,7 +219,7 @@ ngx_postgres_rewrite_enum_t ngx_postgres_rewrite_handlers[] = {
ngx_postgres_output_enum_t ngx_postgres_output_handlers[] = {
{ ngx_string("none"), 0, 0, NULL },
{ ngx_string("rds"), 0, 0, ngx_postgres_output_rds },
- { ngx_string("row"), 1, 0, ngx_postgres_output_row },
+ { ngx_string("text") , 0, 0, ngx_postgres_output_text },
{ ngx_string("value"), 2, 0, ngx_postgres_output_value },
{ ngx_string("binary_value"), 2, 1, ngx_postgres_output_value },
{ ngx_null_string, 0, 0, NULL }
@@ -142,15 +142,14 @@ ngx_postgres_output_value(ngx_http_request_t *r, PGresult *res,
}
ngx_int_t
-ngx_postgres_output_row(ngx_http_request_t *r, PGresult *res,
+ngx_postgres_output_text(ngx_http_request_t *r, PGresult *res,
ngx_postgres_value_t *pgv)
{
ngx_postgres_ctx_t *pgctx;
- ngx_http_core_loc_conf_t *clcf;
ngx_chain_t *cl;
ngx_buf_t *b;
size_t size;
- ngx_int_t col_count, row_count, col;
+ ngx_int_t col_count, row_count, col, row;
dd("entering");
@@ -159,39 +158,25 @@ ngx_postgres_output_row(ngx_http_request_t *r, PGresult *res,
col_count = pgctx->var_cols;
row_count = pgctx->var_rows;
- if (pgv->row >= row_count) {
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "postgres: \"postgres_output row\" requires row out"
- " of range of the received result-set (rows:%d cols:%d)"
- " in location \"%V\"", row_count, col_count, &clcf->name);
-
- dd("returning NGX_DONE, status NGX_HTTP_INTERNAL_SERVER_ERROR");
- pgctx->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
- return NGX_DONE;
- }
-
/* pre-calculate total length up-front for single buffer allocation */
size = 0;
- for (col = 0; col < col_count; col++) {
- if (PQgetisnull(res, pgv->row, col)) {
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "postgres: \"postgres_output row\" received NULL"
- " value in location \"%V\"", &clcf->name);
-
- dd("returning NGX_DONE, status NGX_HTTP_INTERNAL_SERVER_ERROR");
- pgctx->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
- return NGX_DONE;
+ for (row = 0; row < row_count; row++) {
+ for (col = 0; col < col_count; col++) {
+ if (PQgetisnull(res, row, col)) {
+ size += sizeof("(null)") - 1;
+ } else {
+ size += PQgetlength(res, row, col); /* field string data */
+ }
}
-
- size += PQgetlength(res, pgv->row, col); /* field string data */
}
- size += col_count - 1; /* delimiters */
+ size += row_count * col_count - 1; /* delimiters */
+
+ if ((row_count == 0) || (size == 0)) {
+ dd("returning NGX_DONE (empty result)");
+ return NGX_DONE;
+ }
b = ngx_create_temp_buf(r->pool, size);
if (b == NULL) {
@@ -210,18 +195,21 @@ ngx_postgres_output_row(ngx_http_request_t *r, PGresult *res,
b->tag = r->upstream->output.tag;
/* fill data */
- for (col = 0; col < col_count - 1; col++) {
- size = PQgetlength(res, pgv->row, col);
- if (size) {
- b->last = ngx_copy(b->last, PQgetvalue(res, pgv->row, col), size);
- }
- b->last = ngx_copy(b->last, "\n", 1);
- }
+ for (row = 0; row < row_count; row++) {
+ for (col = 0; col < col_count; col++) {
+ if (PQgetisnull(res, row, col)) {
+ b->last = ngx_copy(b->last, "(null)", sizeof("(null)") - 1);
+ } else {
+ size = PQgetlength(res, row, col);
+ if (size) {
+ b->last = ngx_copy(b->last, PQgetvalue(res, row, col), size);
+ }
+ }
- /* last column without delimiter */
- size = PQgetlength(res, pgv->row, col);
- if (size) {
- b->last = ngx_copy(b->last, PQgetvalue(res, pgv->row, col), size);
+ if ((row != row_count - 1) || (col != col_count - 1)) {
+ b->last = ngx_copy(b->last, "\n", 1);
+ }
+ }
}
if (b->last != b->end) {
@@ -39,7 +39,7 @@
ngx_int_t ngx_postgres_output_value(ngx_http_request_t *, PGresult *,
ngx_postgres_value_t *);
-ngx_int_t ngx_postgres_output_row(ngx_http_request_t *, PGresult *,
+ngx_int_t ngx_postgres_output_text(ngx_http_request_t *, PGresult *,
ngx_postgres_value_t *);
ngx_int_t ngx_postgres_output_rds(ngx_http_request_t *, PGresult *,
ngx_postgres_value_t *);
View
@@ -132,15 +132,15 @@ GET /postgres
-=== TEST 7: row - sanity
+=== TEST 7: text - sanity
--- http_config eval: $::http_config
--- config
default_type text/plain;
location /postgres {
postgres_pass database;
postgres_query "select 'a', 'b', 'c', 'd'";
- postgres_output row 0;
+ postgres_output text;
}
--- request
GET /postgres
@@ -254,7 +254,7 @@ test
=== TEST 11: inheritance (mixed, don't inherit)
--- http_config eval: $::http_config
--- config
- postgres_output row 0;
+ postgres_output text;
location /postgres {
postgres_pass database;
@@ -417,3 +417,51 @@ Content-Type: text/plain
--- response_body chomp
2
--- timeout: 10
+
+
+
+=== TEST 19: text - NULL value
+--- http_config eval: $::http_config
+--- config
+ default_type text/plain;
+
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats order by id";
+ postgres_output text;
+ }
+--- request
+GET /postgres
+--- error_code: 200
+--- response_headers
+Content-Type: text/plain
+--- response_body eval
+"2".
+"\x{0a}". # new line - delimiter
+"(null)".
+"\x{0a}". # new line - delimiter
+"3".
+"\x{0a}". # new line - delimiter
+"bob"
+--- timeout: 10
+
+
+
+=== TEST 20: text - empty result
+--- http_config eval: $::http_config
+--- config
+ default_type text/plain;
+
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats where id=1";
+ postgres_output text;
+ }
+--- request
+GET /postgres
+--- error_code: 200
+--- response_headers
+Content-Type: text/plain
+--- response_body eval
+""
+--- timeout: 10

0 comments on commit 61af6a7

Please sign in to comment.