Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add "postgres_rewrite" directive.

  • Loading branch information...
commit d2a539234eddc19f162db6a95b324def1e147c9c 1 parent 12c2710
@PiotrSikora PiotrSikora authored
View
17 README
@@ -37,8 +37,8 @@ CONFIGURATION DIRECTIVES:
default: none
- postgres_query [method .. method] query (context: http, server, location)
- -------------------------------------------------------------------------
+ postgres_query [methods] query (context: http, server, location)
+ ----------------------------------------------------------------
Set query string (it can include variables). When methods are specified
then query is used only for them, otherwise it's used for all methods.
@@ -47,6 +47,19 @@ CONFIGURATION DIRECTIVES:
default: none
+ postgres_rewrite [methods] condition status (context: http, server, location)
+ -----------------------------------------------------------------------------
+ Rewrite response status code when given condition is met (first one wins!):
+ - no_changes - no rows were affected by SQL query (by design this applies only to
+ INSERT, UPDATE, DELETE, MOVE, FETCH and COPY SQL queries),
+ - changes - at least one row was affected by SQL query (by design this applies
+ only to INSERT, UPDATE, DELETE, MOVE, FETCH and COPY SQL queries),
+ - no_rows - no rows were returned in the result-set,
+ - rows - at least one row was returned in the result-set.
+
+ default: none
+
+
postgres_output none|value|row|rds [row] [column] (context: http, server, location)
-----------------------------------------------------------------------------------
Set output format:
View
4 config
@@ -89,7 +89,7 @@ fi
ngx_addon_name=ngx_postgres_module
HTTP_MODULES="$HTTP_MODULES ngx_postgres_module"
-NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_postgres_handler.c $ngx_addon_dir/src/ngx_postgres_keepalive.c $ngx_addon_dir/src/ngx_postgres_module.c $ngx_addon_dir/src/ngx_postgres_output.c $ngx_addon_dir/src/ngx_postgres_processor.c $ngx_addon_dir/src/ngx_postgres_upstream.c $ngx_addon_dir/src/ngx_postgres_util.c $ngx_addon_dir/src/ngx_postgres_variable.c"
-NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ngx_postgres_handler.h $ngx_addon_dir/src/ngx_postgres_keepalive.h $ngx_addon_dir/src/ngx_postgres_module.h $ngx_addon_dir/src/ngx_postgres_output.h $ngx_addon_dir/src/ngx_postgres_processor.h $ngx_addon_dir/src/ngx_postgres_upstream.h $ngx_addon_dir/src/ngx_postgres_util.h $ngx_addon_dir/src/ngx_postgres_variable.h $ngx_addon_dir/src/ngx_postgres_ddebug.h $ngx_addon_dir/src/resty_dbd_stream.h"
+NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_postgres_handler.c $ngx_addon_dir/src/ngx_postgres_keepalive.c $ngx_addon_dir/src/ngx_postgres_module.c $ngx_addon_dir/src/ngx_postgres_output.c $ngx_addon_dir/src/ngx_postgres_processor.c $ngx_addon_dir/src/ngx_postgres_rewrite.c $ngx_addon_dir/src/ngx_postgres_upstream.c $ngx_addon_dir/src/ngx_postgres_util.c $ngx_addon_dir/src/ngx_postgres_variable.c"
+NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ngx_postgres_handler.h $ngx_addon_dir/src/ngx_postgres_keepalive.h $ngx_addon_dir/src/ngx_postgres_module.h $ngx_addon_dir/src/ngx_postgres_output.h $ngx_addon_dir/src/ngx_postgres_processor.h $ngx_addon_dir/src/ngx_postgres_rewrite.h $ngx_addon_dir/src/ngx_postgres_upstream.h $ngx_addon_dir/src/ngx_postgres_util.h $ngx_addon_dir/src/ngx_postgres_variable.h $ngx_addon_dir/src/ngx_postgres_ddebug.h $ngx_addon_dir/src/resty_dbd_stream.h"
have=NGX_POSTGRES_MODULE . auto/have
View
5 src/ngx_postgres_handler.c
@@ -63,8 +63,8 @@ ngx_postgres_handler(ngx_http_request_t *r)
pglcf = ngx_http_get_module_loc_conf(r, ngx_postgres_module);
- if ((pglcf->default_query == NULL) && !(pglcf->methods_set & r->method)) {
- if (pglcf->methods_set != 0) {
+ if ((pglcf->query.def == NULL) && !(pglcf->query.methods_set & r->method)) {
+ if (pglcf->query.methods_set != 0) {
dd("returning NGX_HTTP_NOT_ALLOWED");
return NGX_HTTP_NOT_ALLOWED;
}
@@ -155,6 +155,7 @@ ngx_postgres_handler(ngx_http_request_t *r)
* pgctx->response = NULL
* pgctx->var_query = { 0, NULL }
* pgctx->variables = NULL
+ * pgctx->status = 0
*/
pgctx->var_cols = NGX_ERROR;
View
257 src/ngx_postgres_module.c
@@ -35,6 +35,10 @@
#include "ngx_postgres_upstream.h"
#include "ngx_postgres_util.h"
#include "ngx_postgres_variable.h"
+#include "ngx_postgres_rewrite.h"
+
+
+#define NGX_CONF_TAKE34 (NGX_CONF_TAKE3|NGX_CONF_TAKE4)
static ngx_command_t ngx_postgres_module_commands[] = {
@@ -67,6 +71,13 @@ static ngx_command_t ngx_postgres_module_commands[] = {
0,
NULL },
+ { ngx_string("postgres_rewrite"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
+ ngx_postgres_conf_rewrite,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("postgres_output"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
ngx_postgres_conf_output,
@@ -75,8 +86,7 @@ static ngx_command_t ngx_postgres_module_commands[] = {
NULL },
{ ngx_string("postgres_set"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
- |NGX_CONF_TAKE3|NGX_CONF_TAKE4,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE34,
ngx_postgres_conf_set,
NGX_HTTP_LOC_CONF_OFFSET,
0,
@@ -187,7 +197,15 @@ ngx_conf_enum_t ngx_postgres_requirement_options[] = {
{ ngx_null_string, 0 }
};
-ngx_postgres_output_handler_enum_t ngx_postgres_output_handlers[] = {
+ngx_postgres_handler_enum_t ngx_postgres_rewrite_handlers[] = {
+ { ngx_string("no_changes"), 0, ngx_postgres_rewrite_changes },
+ { ngx_string("changes"), 1, ngx_postgres_rewrite_changes },
+ { ngx_string("no_rows"), 2, ngx_postgres_rewrite_rows },
+ { ngx_string("rows"), 3, ngx_postgres_rewrite_rows },
+ { ngx_null_string, 0, NULL }
+};
+
+ngx_postgres_handler_enum_t ngx_postgres_output_handlers[] = {
{ ngx_string("none"), 0, NULL },
{ ngx_string("value"), 2, ngx_postgres_output_value },
{ ngx_string("row"), 1, ngx_postgres_output_row },
@@ -276,17 +294,18 @@ ngx_postgres_create_loc_conf(ngx_conf_t *cf)
*
* conf->upstream.* = 0 / NULL
* conf->upstream_cv = NULL
- * conf->default_query = NULL
- * conf->methods_set = 0
- * conf->queries = NULL
+ * conf->query.methods_set = 0
+ * conf->query.methods = NULL
+ * conf->query.def = NULL
* conf->output_value = NULL
- * conf->variables = NULL
*/
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
+ conf->rewrites = NGX_CONF_UNSET_PTR;
conf->output_handler = NGX_CONF_UNSET_PTR;
+ conf->variables = NGX_CONF_UNSET_PTR;
/* the hardcoded values */
conf->upstream.cyclic_temp_file = 0;
@@ -325,12 +344,14 @@ ngx_postgres_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
conf->upstream_cv = prev->upstream_cv;
}
- if ((conf->default_query == NULL) && (conf->queries == NULL)) {
- conf->default_query = prev->default_query;
- conf->methods_set = prev->methods_set;
- conf->queries = prev->queries;
+ if ((conf->query.def == NULL) && (conf->query.methods == NULL)) {
+ conf->query.methods_set = prev->query.methods_set;
+ conf->query.methods = prev->query.methods;
+ conf->query.def = prev->query.def;
}
+ ngx_conf_merge_ptr_value(conf->rewrites, prev->rewrites, NULL);
+
if (conf->output_handler == NGX_CONF_UNSET_PTR) {
if (prev->output_handler == NGX_CONF_UNSET_PTR) {
/* default */
@@ -343,9 +364,7 @@ ngx_postgres_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
}
}
- if (conf->variables == NULL) {
- conf->variables = prev->variables;
- }
+ ngx_conf_merge_ptr_value(conf->variables, prev->variables, NULL);
dd("returning NGX_CONF_OK");
return NGX_CONF_OK;
@@ -654,7 +673,7 @@ ngx_postgres_conf_query(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_postgres_loc_conf_t *pglcf = conf;
ngx_http_compile_complex_value_t ccv;
ngx_postgres_mixed_t *query;
- ngx_conf_bitmask_t *e;
+ ngx_conf_bitmask_t *b;
ngx_uint_t methods, i, j;
dd("entering");
@@ -672,20 +691,19 @@ ngx_postgres_conf_query(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
/* default query */
dd("default query");
- if (pglcf->default_query != NULL) {
+ if (pglcf->query.def != NULL) {
dd("returning");
return "is duplicate";
}
- pglcf->default_query = ngx_palloc(cf->pool,
- sizeof(ngx_postgres_mixed_t));
- if (pglcf->default_query == NULL) {
+ pglcf->query.def = ngx_palloc(cf->pool, sizeof(ngx_postgres_mixed_t));
+ if (pglcf->query.def == NULL) {
dd("returning NGX_CONF_ERROR");
return NGX_CONF_ERROR;
}
methods = 0xFFFF;
- query = pglcf->default_query;
+ query = pglcf->query.def;
} else {
/* method-specific query */
dd("method-specific query");
@@ -693,12 +711,12 @@ ngx_postgres_conf_query(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
methods = 0;
for (i = 1; i < cf->args->nelts - 1; i++) {
- e = ngx_postgres_http_methods;
- for (j = 0; e[j].name.len; j++) {
- if ((e[j].name.len == value[i].len)
- && (ngx_strcasecmp(e[j].name.data, value[i].data) == 0))
+ b = ngx_postgres_http_methods;
+ for (j = 0; b[j].name.len; j++) {
+ if ((b[j].name.len == value[i].len)
+ && (ngx_strcasecmp(b[j].name.data, value[i].data) == 0))
{
- if (pglcf->methods_set & e[j].mask) {
+ if (pglcf->query.methods_set & b[j].mask) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"postgres: method \"%V\" is"
" duplicate in \"%V\" directive",
@@ -708,12 +726,12 @@ ngx_postgres_conf_query(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
- methods |= e[j].mask;
+ methods |= b[j].mask;
break;
}
}
- if (e[j].name.len == 0) {
+ if (b[j].name.len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"postgres: invalid method \"%V\""
" in \"%V\" directive",
@@ -724,22 +742,22 @@ ngx_postgres_conf_query(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
}
- if (pglcf->queries == NULL) {
- pglcf->queries = ngx_array_create(cf->pool, 4,
- sizeof(ngx_postgres_mixed_t));
- if (pglcf->queries == NULL) {
+ if (pglcf->query.methods == NULL) {
+ pglcf->query.methods = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_postgres_mixed_t));
+ if (pglcf->query.methods == NULL) {
dd("returning NGX_CONF_ERROR");
return NGX_CONF_ERROR;
}
}
- query = ngx_array_push(pglcf->queries);
+ query = ngx_array_push(pglcf->query.methods);
if (query == NULL) {
dd("returning NGX_CONF_ERROR");
return NGX_CONF_ERROR;
}
- pglcf->methods_set |= methods;
+ pglcf->query.methods_set |= methods;
}
if (ngx_http_script_variables_count(&sql)) {
@@ -778,12 +796,169 @@ ngx_postgres_conf_query(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
char *
+ngx_postgres_conf_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_str_t *value = cf->args->elts;
+ ngx_str_t what = value[cf->args->nelts - 2];
+ ngx_str_t to = value[cf->args->nelts - 1];
+ ngx_postgres_loc_conf_t *pglcf = conf;
+ ngx_postgres_rewrite_conf_t *pgrcf;
+ ngx_postgres_rewrite_t *rewrite;
+ ngx_postgres_handler_enum_t *e;
+ ngx_conf_bitmask_t *b;
+ ngx_uint_t methods, i, j;
+
+ dd("entering");
+
+ e = ngx_postgres_rewrite_handlers;
+ for (i = 0; e[i].name.len; i++) {
+ if ((e[i].name.len == what.len)
+ && (ngx_strcasecmp(e[i].name.data, what.data) == 0))
+ {
+ break;
+ }
+ }
+
+ if (e[i].name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "postgres: invalid condition \"%V\""
+ " in \"%V\" directive", &what, &cmd->name);
+
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+
+ if (pglcf->rewrites == NGX_CONF_UNSET_PTR) {
+ pglcf->rewrites = ngx_array_create(cf->pool, 2,
+ sizeof(ngx_postgres_rewrite_conf_t));
+ if (pglcf->rewrites == NULL) {
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+ } else {
+ pgrcf = pglcf->rewrites->elts;
+ for (j = 0; j < pglcf->rewrites->nelts; j++) {
+ if (pgrcf[j].key == e[i].param) {
+ pgrcf = &pgrcf[j];
+ goto found;
+ }
+ }
+ }
+
+ pgrcf = ngx_array_push(pglcf->rewrites);
+ if (pgrcf == NULL) {
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memzero(pgrcf, sizeof(ngx_postgres_rewrite_conf_t));
+
+ pgrcf->key = e[i].param;
+ pgrcf->handler = e[i].handler;
+
+found:
+ if (cf->args->nelts == 3) {
+ /* default rewrite */
+ dd("default rewrite");
+
+ if (pgrcf->def != NULL) {
+ dd("returning");
+ return "is duplicate";
+ }
+
+ pgrcf->def = ngx_palloc(cf->pool, sizeof(ngx_postgres_rewrite_t));
+ if (pgrcf->def == NULL) {
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+
+ methods = 0xFFFF;
+ rewrite = pgrcf->def;
+ } else {
+ /* method-specific rewrite */
+ dd("method-specific rewrite");
+
+ methods = 0;
+
+ for (i = 1; i < cf->args->nelts - 2; i++) {
+ b = ngx_postgres_http_methods;
+ for (j = 0; b[j].name.len; j++) {
+ if ((b[j].name.len == value[i].len)
+ && (ngx_strcasecmp(b[j].name.data, value[i].data) == 0))
+ {
+ if (pgrcf->methods_set & b[j].mask) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "postgres: method \"%V\" for"
+ " condition \"%V\" is duplicate"
+ " in \"%V\" directive",
+ &value[i], &what, &cmd->name);
+
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+
+ methods |= b[j].mask;
+ break;
+ }
+ }
+
+ if (b[j].name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "postgres: invalid method \"%V\" for"
+ " condition \"%V\" in \"%V\" directive",
+ &value[i], &what, &cmd->name);
+
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ if (pgrcf->methods == NULL) {
+ pgrcf->methods = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_postgres_rewrite_t));
+ if (pgrcf->methods == NULL) {
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ rewrite = ngx_array_push(pgrcf->methods);
+ if (rewrite == NULL) {
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+
+ pgrcf->methods_set |= methods;
+ }
+
+ rewrite->key = methods;
+ rewrite->status = ngx_atoi(to.data, to.len);
+ if ((rewrite->status == NGX_ERROR)
+ || (rewrite->status < NGX_HTTP_OK)
+ || (rewrite->status > NGX_HTTP_INSUFFICIENT_STORAGE)
+ || ((rewrite->status >= NGX_HTTP_SPECIAL_RESPONSE)
+ && (rewrite->status < NGX_HTTP_BAD_REQUEST)))
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "postgres: invalid status value \"%V\" for"
+ " condition \"%V\" in \"%V\" directive",
+ &to, &what, &cmd->name);
+
+ dd("returning NGX_CONF_ERROR");
+ return NGX_CONF_ERROR;
+ }
+
+ dd("returning NGX_CONF_OK");
+ return NGX_CONF_OK;
+}
+
+char *
ngx_postgres_conf_output(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
- ngx_str_t *value = cf->args->elts;
- ngx_postgres_loc_conf_t *pglcf = conf;
- ngx_postgres_output_handler_enum_t *e;
- ngx_uint_t i;
+ ngx_str_t *value = cf->args->elts;
+ ngx_postgres_loc_conf_t *pglcf = conf;
+ ngx_postgres_handler_enum_t *e;
+ ngx_uint_t i;
dd("entering");
@@ -811,7 +986,7 @@ ngx_postgres_conf_output(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
- if (e[i].args != cf->args->nelts - 2) {
+ if (e[i].param != cf->args->nelts - 2) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"postgres: invalid number of arguments"
" in \"%V\" directive", &cmd->name);
@@ -820,7 +995,7 @@ ngx_postgres_conf_output(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
- if (e[i].args == 0) {
+ if (e[i].param == 0) {
dd("returning NGX_CONF_OK");
return NGX_CONF_OK;
}
@@ -841,7 +1016,7 @@ ngx_postgres_conf_output(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
- if (e[i].args == 1) {
+ if (e[i].param == 1) {
dd("returning NGX_CONF_OK");
return NGX_CONF_OK;
}
@@ -884,7 +1059,7 @@ ngx_postgres_conf_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
value[1].len--;
value[1].data++;
- if (pglcf->variables == NULL) {
+ if (pglcf->variables == NGX_CONF_UNSET_PTR) {
pglcf->variables = ngx_array_create(cf->pool, 4,
sizeof(ngx_postgres_variable_t));
if (pglcf->variables == NULL) {
View
44 src/ngx_postgres_module.h
@@ -45,6 +45,11 @@ typedef struct {
} ngx_postgres_mixed_t;
typedef struct {
+ ngx_uint_t key;
+ ngx_int_t status;
+} ngx_postgres_rewrite_t;
+
+typedef struct {
ngx_int_t row;
ngx_int_t column;
ngx_uint_t required;
@@ -56,14 +61,32 @@ typedef struct {
ngx_postgres_value_t value;
} ngx_postgres_variable_t;
-typedef ngx_int_t (*ngx_postgres_output_handler_pt) (ngx_http_request_t *,
- PGresult *, ngx_postgres_value_t *);
+typedef struct {
+ ngx_uint_t methods_set;
+ ngx_array_t *methods; /* method-specific */
+ ngx_postgres_mixed_t *def; /* default */
+} ngx_postgres_query_conf_t;
+
+typedef struct ngx_postgres_rewrite_conf_s ngx_postgres_rewrite_conf_t;
+
+typedef ngx_int_t (*ngx_postgres_rewrite_handler_pt)
+ (ngx_http_request_t *, ngx_postgres_rewrite_conf_t *);
+
+struct ngx_postgres_rewrite_conf_s {
+ /* condition */
+ ngx_uint_t key;
+ ngx_postgres_rewrite_handler_pt handler;
+ /* methods */
+ ngx_uint_t methods_set;
+ ngx_array_t *methods; /* method-specific */
+ ngx_postgres_rewrite_t *def; /* default */
+};
typedef struct {
ngx_str_t name;
- ngx_uint_t args;
- ngx_postgres_output_handler_pt handler;
-} ngx_postgres_output_handler_enum_t;
+ ngx_uint_t param;
+ void *handler;
+} ngx_postgres_handler_enum_t;
typedef struct {
#if defined(nginx_version) && (nginx_version >= 8022)
@@ -110,14 +133,17 @@ typedef struct {
ngx_uint_t reject;
} ngx_postgres_upstream_srv_conf_t;
+typedef ngx_int_t (*ngx_postgres_output_handler_pt)
+ (ngx_http_request_t *, PGresult *, ngx_postgres_value_t *);
+
typedef struct {
/* upstream */
ngx_http_upstream_conf_t upstream;
ngx_http_complex_value_t *upstream_cv;
/* queries */
- ngx_postgres_mixed_t *default_query;
- ngx_uint_t methods_set;
- ngx_array_t *queries;
+ ngx_postgres_query_conf_t query;
+ /* rewrites */
+ ngx_array_t *rewrites;
/* output */
ngx_postgres_output_handler_pt output_handler;
ngx_postgres_value_t *output_value;
@@ -132,6 +158,7 @@ typedef struct {
ngx_int_t var_affected;
ngx_str_t var_query;
ngx_array_t *variables;
+ ngx_int_t status;
} ngx_postgres_ctx_t;
@@ -143,6 +170,7 @@ char *ngx_postgres_conf_server(ngx_conf_t *, ngx_command_t *, void *);
char *ngx_postgres_conf_keepalive(ngx_conf_t *, ngx_command_t *, void *);
char *ngx_postgres_conf_pass(ngx_conf_t *, ngx_command_t *, void *);
char *ngx_postgres_conf_query(ngx_conf_t *, ngx_command_t *, void *);
+char *ngx_postgres_conf_rewrite(ngx_conf_t *, ngx_command_t *, void *);
char *ngx_postgres_conf_output(ngx_conf_t *, ngx_command_t *, void *);
char *ngx_postgres_conf_set(ngx_conf_t *, ngx_command_t *, void *);
View
54 src/ngx_postgres_output.c
@@ -45,8 +45,10 @@ ngx_postgres_output_value(ngx_http_request_t *r, PGresult *res,
dd("entering");
- col_count = PQnfields(res);
- row_count = PQntuples(res);
+ pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+
+ col_count = pgctx->var_cols;
+ row_count = pgctx->var_rows;
col = pgv->column;
@@ -111,7 +113,7 @@ ngx_postgres_output_value(ngx_http_request_t *r, PGresult *res,
cl->next = NULL;
- pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+ /* set output response */
pgctx->response = cl;
dd("returning NGX_DONE");
@@ -131,8 +133,10 @@ ngx_postgres_output_row(ngx_http_request_t *r, PGresult *res,
dd("entering");
- col_count = PQnfields(res);
- row_count = PQntuples(res);
+ pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+
+ 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);
@@ -205,7 +209,7 @@ ngx_postgres_output_row(ngx_http_request_t *r, PGresult *res,
cl->next = NULL;
- pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+ /* set output response */
pgctx->response = cl;
dd("returning NGX_DONE");
@@ -218,15 +222,19 @@ ngx_postgres_output_rds(ngx_http_request_t *r, PGresult *res,
{
ngx_postgres_ctx_t *pgctx;
ngx_chain_t *first, *last;
- ngx_int_t col_count, row_count, row;
+ ngx_int_t col_count, row_count, aff_count, row;
dd("entering");
- col_count = PQnfields(res);
- row_count = PQntuples(res);
+ pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+
+ col_count = pgctx->var_cols;
+ row_count = pgctx->var_rows;
+ aff_count = (pgctx->var_affected == NGX_ERROR) ? 0 : pgctx->var_affected;
/* render header */
- first = last = ngx_postgres_render_rds_header(r, r->pool, res, col_count);
+ first = last = ngx_postgres_render_rds_header(r, r->pool, res, col_count,
+ aff_count);
if (last == NULL) {
dd("returning NGX_ERROR");
return NGX_ERROR;
@@ -266,7 +274,7 @@ ngx_postgres_output_rds(ngx_http_request_t *r, PGresult *res,
done:
last->next = NULL;
- pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+ /* set output response */
pgctx->response = first;
dd("returning NGX_DONE");
@@ -275,28 +283,19 @@ ngx_postgres_output_rds(ngx_http_request_t *r, PGresult *res,
ngx_chain_t *
ngx_postgres_render_rds_header(ngx_http_request_t *r, ngx_pool_t *pool,
- PGresult *res, ngx_int_t col_count)
+ PGresult *res, ngx_int_t col_count, ngx_int_t aff_count)
{
ngx_chain_t *cl;
ngx_buf_t *b;
size_t size;
- char *errstr, *affected;
- size_t errstr_len, affected_len;
- ngx_int_t affected_int;
+ char *errstr;
+ size_t errstr_len;
dd("entering");
errstr = PQresultErrorMessage(res);
errstr_len = ngx_strlen(errstr);
- affected = PQcmdTuples(res);
- affected_len = ngx_strlen(affected);
- if (affected_len) {
- affected_int = ngx_atoi((u_char *) affected, affected_len);
- } else {
- affected_int = 0;
- }
-
size = sizeof(uint8_t) /* endian type */
+ sizeof(uint32_t) /* format version */
+ sizeof(uint8_t) /* result type */
@@ -350,7 +349,7 @@ ngx_postgres_render_rds_header(ngx_http_request_t *r, ngx_pool_t *pool,
b->last = ngx_copy(b->last, (u_char *) errstr, errstr_len);
}
- *(uint64_t *) b->last = (uint64_t) affected_int;
+ *(uint64_t *) b->last = (uint64_t) aff_count;
b->last += sizeof(uint64_t);
*(uint64_t *) b->last = (uint64_t) PQoidValue(res);
@@ -542,6 +541,7 @@ ngx_postgres_output_chain(ngx_http_request_t *r, ngx_chain_t *cl)
{
ngx_http_upstream_t *u = r->upstream;
ngx_postgres_loc_conf_t *pglcf;
+ ngx_postgres_ctx_t *pgctx;
ngx_int_t rc;
dd("entering");
@@ -549,16 +549,16 @@ ngx_postgres_output_chain(ngx_http_request_t *r, ngx_chain_t *cl)
if (!r->header_sent) {
ngx_http_clear_content_length(r);
- r->headers_out.status = NGX_HTTP_OK;
-
pglcf = ngx_http_get_module_loc_conf(r, ngx_postgres_module);
+ pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+
+ r->headers_out.status = pgctx->status ? pgctx->status : NGX_HTTP_OK;
if (pglcf->output_handler == &ngx_postgres_output_rds) {
r->headers_out.content_type.data = (u_char *) rds_content_type;
r->headers_out.content_type.len = rds_content_type_len;
r->headers_out.content_type_len = rds_content_type_len;
r->headers_out.content_type_lowcase = NULL;
-
} else if (pglcf->output_handler != NULL) {
if (ngx_http_set_content_type(r) != NGX_OK) {
dd("returning NGX_HTTP_INTERNAL_SERVER_ERROR");
View
2  src/ngx_postgres_output.h
@@ -44,7 +44,7 @@ ngx_int_t ngx_postgres_output_row(ngx_http_request_t *, PGresult *,
ngx_int_t ngx_postgres_output_rds(ngx_http_request_t *, PGresult *,
ngx_postgres_value_t *);
ngx_chain_t *ngx_postgres_render_rds_header(ngx_http_request_t *,
- ngx_pool_t *, PGresult *, ngx_int_t);
+ ngx_pool_t *, PGresult *, ngx_int_t, ngx_int_t);
ngx_chain_t *ngx_postgres_render_rds_columns(ngx_http_request_t *,
ngx_pool_t *, PGresult *, ngx_int_t);
ngx_chain_t *ngx_postgres_render_rds_row(ngx_http_request_t *, ngx_pool_t *,
View
40 src/ngx_postgres_processor.c
@@ -320,23 +320,25 @@ ngx_postgres_upstream_get_result(ngx_http_request_t *r, ngx_connection_t *pgxc,
ngx_int_t
ngx_postgres_process_response(ngx_http_request_t *r, PGresult *res)
{
- ngx_postgres_loc_conf_t *pglcf;
- ngx_postgres_ctx_t *pgctx;
- ngx_postgres_variable_t *pgvar;
- ngx_str_t *store;
- char *affected;
- size_t affected_len;
- ngx_uint_t i;
+ ngx_postgres_loc_conf_t *pglcf;
+ ngx_postgres_ctx_t *pgctx;
+ ngx_postgres_rewrite_conf_t *pgrcf;
+ ngx_postgres_variable_t *pgvar;
+ ngx_str_t *store;
+ char *affected;
+ size_t affected_len;
+ ngx_uint_t i;
+ ngx_int_t rc;
dd("entering");
pglcf = ngx_http_get_module_loc_conf(r, ngx_postgres_module);
pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
- /* set $postgres_column_count */
+ /* set $postgres_columns */
pgctx->var_cols = PQnfields(res);
- /* set $postgres_row_count */
+ /* set $postgres_rows */
pgctx->var_rows = PQntuples(res);
/* set $postgres_affected */
@@ -346,7 +348,24 @@ ngx_postgres_process_response(ngx_http_request_t *r, PGresult *res)
pgctx->var_affected = ngx_atoi((u_char *) affected, affected_len);
}
- if (pglcf->variables != NULL) {
+ if (pglcf->rewrites) {
+ /* process rewrites */
+ pgrcf = pglcf->rewrites->elts;
+ for (i = 0; i < pglcf->rewrites->nelts; i++) {
+ rc = pgrcf[i].handler(r, &pgrcf[i]);
+ if (rc != NGX_DECLINED) {
+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+ dd("returning rc:%d", (int) rc);
+ return rc;
+ }
+
+ pgctx->status = rc;
+ break;
+ }
+ }
+ }
+
+ if (pglcf->variables) {
/* set custom variables */
pgvar = pglcf->variables->elts;
store = pgctx->variables->elts;
@@ -361,6 +380,7 @@ ngx_postgres_process_response(ngx_http_request_t *r, PGresult *res)
}
if (pglcf->output_handler) {
+ /* generate output */
dd("returning");
return pglcf->output_handler(r, res, pglcf->output_value);
}
View
111 src/ngx_postgres_rewrite.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2010, FRiCKLE Piotr Sikora <info@frickle.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DDEBUG 0
+#include "ngx_postgres_ddebug.h"
+#include "ngx_postgres_module.h"
+#include "ngx_postgres_rewrite.h"
+
+
+ngx_int_t
+ngx_postgres_rewrite(ngx_http_request_t *r,
+ ngx_postgres_rewrite_conf_t *pgrcf)
+{
+ ngx_postgres_rewrite_t *rewrite;
+ ngx_uint_t i;
+
+ dd("entering");
+
+ if (pgrcf->methods_set & r->method) {
+ /* method-specific */
+ rewrite = pgrcf->methods->elts;
+ for (i = 0; i < pgrcf->methods->nelts; i++) {
+ if (rewrite[i].key & r->method) {
+ dd("returning status:%d", (int) rewrite[i].status);
+ return rewrite[i].status;
+ }
+ }
+ } else if (pgrcf->def) {
+ /* default */
+ dd("returning status:%d", (int) pgrcf->def->status);
+ return pgrcf->def->status;
+ }
+
+ dd("returning NGX_DECLINED");
+ return NGX_DECLINED;
+}
+
+ngx_int_t
+ngx_postgres_rewrite_changes(ngx_http_request_t *r,
+ ngx_postgres_rewrite_conf_t *pgrcf)
+{
+ ngx_postgres_ctx_t *pgctx;
+
+ dd("entering");
+
+ pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+
+ if ((pgrcf->key % 2 == 0) && (pgctx->var_affected == 0)) {
+ /* no_changes */
+ dd("returning");
+ return ngx_postgres_rewrite(r, pgrcf);
+ }
+
+ if ((pgrcf->key % 2 == 1) && (pgctx->var_affected > 0)) {
+ /* changes */
+ dd("returning");
+ return ngx_postgres_rewrite(r, pgrcf);
+ }
+
+ dd("returning NGX_DECLINED");
+ return NGX_DECLINED;
+}
+
+ngx_int_t
+ngx_postgres_rewrite_rows(ngx_http_request_t *r,
+ ngx_postgres_rewrite_conf_t *pgrcf)
+{
+ ngx_postgres_ctx_t *pgctx;
+
+ dd("entering");
+
+ pgctx = ngx_http_get_module_ctx(r, ngx_postgres_module);
+
+ if ((pgrcf->key % 2 == 0) && (pgctx->var_rows == 0)) {
+ /* no_rows */
+ dd("returning");
+ return ngx_postgres_rewrite(r, pgrcf);
+ }
+
+ if ((pgrcf->key % 2 == 1) && (pgctx->var_rows > 0)) {
+ /* rows */
+ dd("returning");
+ return ngx_postgres_rewrite(r, pgrcf);
+ }
+
+ dd("returning NGX_DECLINED");
+ return NGX_DECLINED;
+}
View
43 src/ngx_postgres_rewrite.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, FRiCKLE Piotr Sikora <info@frickle.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NGX_POSTGRES_REWRITE_H_
+#define _NGX_POSTGRES_REWRITE_H_
+
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+#include "ngx_postgres_module.h"
+
+
+ngx_int_t ngx_postgres_rewrite(ngx_http_request_t *,
+ ngx_postgres_rewrite_conf_t *);
+ngx_int_t ngx_postgres_rewrite_changes(ngx_http_request_t *,
+ ngx_postgres_rewrite_conf_t *);
+ngx_int_t ngx_postgres_rewrite_rows(ngx_http_request_t *,
+ ngx_postgres_rewrite_conf_t *);
+
+#endif /* _NGX_POSTGRES_REWRITE_H_ */
View
10 src/ngx_postgres_upstream.c
@@ -160,19 +160,19 @@ ngx_postgres_upstream_init_peer(ngx_http_request_t *r,
u->peer.get = ngx_postgres_upstream_get_peer;
u->peer.free = ngx_postgres_upstream_free_peer;
- if (pglcf->methods_set & r->method) {
+ if (pglcf->query.methods_set & r->method) {
/* method-specific query */
dd("using method-specific query");
- query = pglcf->queries->elts;
- for (i = 0; i < pglcf->queries->nelts; i++) {
+ query = pglcf->query.methods->elts;
+ for (i = 0; i < pglcf->query.methods->nelts; i++) {
if (query[i].key & r->method) {
query = &query[i];
break;
}
}
- if (i == pglcf->queries->nelts) {
+ if (i == pglcf->query.methods->nelts) {
dd("returning NGX_ERROR");
return NGX_ERROR;
}
@@ -180,7 +180,7 @@ ngx_postgres_upstream_init_peer(ngx_http_request_t *r,
/* default query */
dd("using default query");
- query = pglcf->default_query;
+ query = pglcf->query.def;
}
if (query->cv) {
View
127 test/t/auth.t
@@ -0,0 +1,127 @@
+# vi:filetype=perl
+
+use lib 'lib';
+use Test::Nginx::Socket;
+
+repeat_each(2);
+
+plan tests => repeat_each() * (blocks() * 3 - 2 * 1);
+
+worker_connections(128);
+run_tests();
+
+no_diff();
+
+__DATA__
+
+=== TEST 1: authorized (auth basic)
+db init:
+
+create table users (login text, pass text);
+insert into users (login, pass) values ('monty', 'some_pass');
+
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location = /auth {
+ internal;
+ set_quote_sql_str $user $remote_user;
+ set_quote_sql_str $pass $remote_passwd;
+ postgres_pass database;
+ postgres_query "select login from users where login=$user and pass=$pass";
+ postgres_rewrite no_rows 403;
+ postgres_set $login 0 0 required;
+ postgres_output none;
+ }
+
+ location /test {
+ auth_request /auth;
+ auth_request_set $auth_user $login;
+ echo -n "hi, $auth_user!";
+ }
+--- more_headers
+Authorization: Basic bW9udHk6c29tZV9wYXNz
+--- request
+GET /test
+--- error_code: 200
+--- response_headers
+Content-Type: text/plain
+--- response_body eval
+"hi, monty!"
+--- timeout: 10
+
+
+
+=== TEST 2: unauthorized (auth basic)
+db init:
+
+create table users (login text, pass text);
+insert into users (login, pass) values ('monty', 'some_pass');
+
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location = /auth {
+ internal;
+ set_quote_sql_str $user $remote_user;
+ set_quote_sql_str $pass $remote_passwd;
+ postgres_pass database;
+ postgres_query "select login from users where login=$user and pass=$pass";
+ postgres_rewrite no_rows 403;
+ postgres_set $login 0 0 required;
+ postgres_output none;
+ }
+
+ location /test {
+ auth_request /auth;
+ auth_request_set $auth_user $login;
+ echo -n "hi, $auth_user!";
+ }
+--- more_headers
+Authorization: Basic bW9udHk6cGFzcw==
+--- request
+GET /test
+--- error_code: 403
+--- response_headers
+Content-Type: text/html
+--- timeout: 10
+
+
+
+=== TEST 3: unauthorized (no authorization header)
+db init:
+
+create table users (login text, pass text);
+insert into users (login, pass) values ('monty', 'some_pass');
+
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location = /auth {
+ internal;
+ set_quote_sql_str $user $remote_user;
+ set_quote_sql_str $pass $remote_passwd;
+ postgres_pass database;
+ postgres_query "select login from users where login=$user and pass=$pass";
+ postgres_rewrite no_rows 403;
+ postgres_set $login 0 0 required;
+ postgres_output none;
+ }
+
+ location /test {
+ auth_request /auth;
+ auth_request_set $auth_user $login;
+ echo -n "hi, $auth_user!";
+ }
+--- request
+GET /test
+--- error_code: 403
+--- response_headers
+Content-Type: text/html
+--- timeout: 10
View
2  test/t/methods.t
@@ -317,7 +317,7 @@ Content-Type: application/x-resty-dbd-stream
-=== TEST 9: inheritance (mixed, not inherited)
+=== TEST 9: inheritance (mixed, don't inherit)
little-endian systems only
--- http_config
View
4 test/t/output.t
@@ -251,7 +251,7 @@ Content-Type: application/x-resty-dbd-stream
-=== TEST 10: inheritance (inherit)
+=== TEST 10: inheritance
--- http_config
upstream database {
postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
@@ -275,7 +275,7 @@ Content-Type: text/plain
-=== TEST 11: inheritance (don't inherit)
+=== TEST 11: inheritance (mixed, don't inherit)
--- http_config
upstream database {
postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
View
293 test/t/rewrites.t
@@ -0,0 +1,293 @@
+# vi:filetype=perl
+
+use lib 'lib';
+use Test::Nginx::Socket;
+
+repeat_each(2);
+
+plan tests => repeat_each() * (blocks() * 2);
+
+worker_connections(128);
+run_tests();
+
+no_diff();
+
+__DATA__
+
+=== TEST 1: no changes (INSERT)
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats";
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 500;
+ }
+--- request
+GET /postgres
+--- error_code: 200
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
+
+
+
+=== TEST 2: no changes (UPDATE)
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location /postgres {
+ postgres_pass database;
+ postgres_query "update cats set id=3 where name='noone'";
+ postgres_rewrite no_changes 202;
+ postgres_rewrite changes 500;
+ }
+--- request
+GET /postgres
+--- error_code: 202
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
+
+
+
+=== TEST 3: one change
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location /postgres {
+ postgres_pass database;
+ postgres_query "update cats set id=3 where name='bob'";
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 202;
+ }
+--- request
+GET /postgres
+--- error_code: 202
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
+
+
+
+=== TEST 4: rows
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats";
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 500;
+ postgres_rewrite no_rows 410;
+ postgres_rewrite rows 202;
+ }
+--- request
+GET /postgres
+--- error_code: 202
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
+
+
+
+=== TEST 5: no rows
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats where name='noone'";
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 500;
+ postgres_rewrite no_rows 410;
+ postgres_rewrite rows 202;
+ }
+--- request
+GET /postgres
+--- error_code: 410
+--- response_headers
+Content-Type: text/html
+--- timeout: 10
+
+
+
+=== TEST 6: inheritance
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 500;
+ postgres_rewrite no_rows 410;
+ postgres_rewrite rows 202;
+
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats";
+ }
+--- request
+GET /postgres
+--- error_code: 202
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
+
+
+
+=== TEST 7: inheritance (mixed, don't inherit)
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 500;
+ postgres_rewrite no_rows 410;
+ postgres_rewrite rows 202;
+
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats";
+ postgres_rewrite rows 206;
+ }
+--- request
+GET /postgres
+--- error_code: 206
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
+
+
+
+=== TEST 8: rows (method-specific)
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats";
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 500;
+ postgres_rewrite no_rows 410;
+ postgres_rewrite POST PUT rows 201;
+ postgres_rewrite HEAD GET rows 202;
+ postgres_rewrite rows 206;
+ }
+--- request
+GET /postgres
+--- error_code: 202
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
+
+
+
+=== TEST 9: rows (default)
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats";
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 500;
+ postgres_rewrite no_rows 410;
+ postgres_rewrite POST PUT rows 201;
+ postgres_rewrite rows 206;
+ }
+--- request
+GET /postgres
+--- error_code: 206
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
+
+
+
+=== TEST 10: rows (none)
+db init:
+
+create table cats (id integer, name text);
+insert into cats (id) values (2);
+insert into cats (id, name) values (3, 'bob');
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select * from cats";
+ postgres_rewrite no_changes 500;
+ postgres_rewrite changes 500;
+ postgres_rewrite no_rows 410;
+ postgres_rewrite POST PUT rows 201;
+ }
+--- request
+GET /postgres
+--- error_code: 200
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+--- timeout: 10
View
46 test/t/variables.t
@@ -5,7 +5,7 @@ use Test::Nginx::Socket;
repeat_each(2);
-plan tests => repeat_each() * (blocks() * 3 + 1 * 4 + 1 * 1 - 3 * 2);
+plan tests => repeat_each() * (blocks() * 3 + 1 * 4 + 1 * 1 - 4 * 2);
worker_connections(128);
run_tests();
@@ -358,3 +358,47 @@ GET /postgres
Content-Type: application/x-resty-dbd-stream
X-Affected: 1
--- timeout: 10
+
+
+
+=== TEST 16: inheritance
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ postgres_set $test 0 0 required;
+
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select NULL as echo";
+ add_header "X-Test" $test;
+ }
+--- request
+GET /postgres
+--- error_code: 500
+--- timeout: 10
+
+
+
+=== TEST 17: inheritance (mixed, don't inherit)
+--- http_config
+ upstream database {
+ postgres_server 127.0.0.1 dbname=test user=monty password=some_pass;
+ }
+--- config
+ postgres_set $test 0 0 required;
+
+ location /postgres {
+ postgres_pass database;
+ postgres_query "select NULL as echo";
+ postgres_set $test2 2 2;
+ add_header "X-Test" $test2;
+ }
+--- request
+GET /postgres
+--- error_code: 200
+--- response_headers
+Content-Type: application/x-resty-dbd-stream
+! X-Test
+--- timeout: 10
Please sign in to comment.
Something went wrong with that request. Please try again.