Skip to content

Commit

Permalink
implemented the rds_json_root directive.
Browse files Browse the repository at this point in the history
  • Loading branch information
agentzh committed Sep 15, 2011
1 parent e635e13 commit 6fc2697
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 14 deletions.
66 changes: 65 additions & 1 deletion src/ngx_http_rds_json_filter_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ ngx_http_output_body_filter_pt ngx_http_rds_json_next_body_filter;

static char *ngx_http_rds_json_ret(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);

static void *ngx_http_rds_json_create_conf(ngx_conf_t *cf);
static char *ngx_http_rds_json_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_int_t ngx_http_rds_json_filter_init(ngx_conf_t *cf);
static char * ngx_http_rds_json_root(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);


static ngx_command_t ngx_http_rds_json_commands[] = {
Expand All @@ -50,6 +51,15 @@ static ngx_command_t ngx_http_rds_json_commands[] = {
offsetof(ngx_http_rds_json_conf_t, enabled),
NULL },

{ ngx_string("rds_json_root"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_http_rds_json_root,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },

{ ngx_string("rds_json_format"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
Expand Down Expand Up @@ -310,6 +320,9 @@ ngx_http_rds_json_create_conf(ngx_conf_t *cf)
* set by ngx_pcalloc():
*
* conf->content_type = { 0, NULL };
* conf->root = { 0, NULL };
* conf->errcode = { 0, NULL };
* conf->errstr = NULL;
*/

conf->enabled = NGX_CONF_UNSET;
Expand Down Expand Up @@ -413,3 +426,54 @@ ngx_http_rds_json_ret(ngx_conf_t *cf, ngx_command_t *cmd,
return NGX_CONF_OK;
}


static char *
ngx_http_rds_json_root(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_rds_json_conf_t *jlcf = conf;
ngx_str_t *value;
uintptr_t escape;
u_char *p;

value = cf->args->elts;

if (jlcf->root.len) {
return "is duplicate";
}

if (value[1].len == 0) {
return "takes an empty value";
}

escape = ngx_http_rds_json_escape_json_str(NULL, value[1].data,
value[1].len);

jlcf->root.len = value[1].len + escape + sizeof("\"\"") - 1;

p = ngx_palloc(cf->pool, jlcf->root.len);
if (p == NULL) {
return NGX_CONF_ERROR;
}

jlcf->root.data = p;

*p++ = '"';

if (escape == 0) {
p = ngx_copy(p, value[1].data, value[1].len);

} else {
p = (u_char *) ngx_http_rds_json_escape_json_str(p, value[1].data,
value[1].len);
}

*p++ = '"';

if (p - jlcf->root.data != (ssize_t) jlcf->root.len) {
return " sees buffer error";
}

return NGX_CONF_OK;
}

6 changes: 4 additions & 2 deletions src/ngx_http_rds_json_filter_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ typedef struct {
ngx_flag_t enabled;
ngx_uint_t format;
ngx_str_t content_type;
ngx_str_t root;

size_t buf_size;

/* for rds_json_ret */
ngx_str_t errcode;
ngx_http_complex_value_t *errstr;

size_t buf_size;
} ngx_http_rds_json_conf_t;


Expand Down
34 changes: 33 additions & 1 deletion src/ngx_http_rds_json_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ ngx_http_rds_json_output_header(ngx_http_request_t *r,
if (escape == 0) {
last = ngx_copy(last, header->errstr.data,
header->errstr.len);

} else {
last = (u_char *) ngx_http_rds_json_escape_json_str(last,
header->errstr.data, header->errstr.len);
Expand Down Expand Up @@ -211,6 +212,38 @@ ngx_http_rds_json_output_header(ngx_http_request_t *r,
}


ngx_int_t
ngx_http_rds_json_output_props_begin(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx, ngx_http_rds_json_conf_t *conf)
{
size_t size;
u_char *pos, *last;

size = sizeof("{:") - 1 + conf->root.len;

pos = ngx_http_rds_json_request_mem(r, ctx, size);
if (pos == NULL) {
return NGX_ERROR;
}

last = pos;

*last++ = '{';
last = ngx_copy(last, conf->root.data, conf->root.len);
*last++ = ':';

if (last - pos != (ssize_t) size) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"rds_json: output props begin: buffer error: %O != %uz",
(off_t) (last - pos), size);

return NGX_ERROR;
}

return ngx_http_rds_json_submit_mem(r, ctx, size, 0);
}


ngx_int_t
ngx_http_rds_json_output_cols(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx)
Expand Down Expand Up @@ -249,7 +282,6 @@ ngx_http_rds_json_output_cols(ngx_http_request_t *r,

last = pos;


*last++ = '[';

for (i = 0; i < ctx->col_count; i++) {
Expand Down
7 changes: 2 additions & 5 deletions src/ngx_http_rds_json_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,20 @@

ngx_int_t ngx_http_rds_json_output_header(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx, ngx_http_rds_header_t *header);

ngx_int_t ngx_http_rds_json_output_cols(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx);

ngx_int_t ngx_http_rds_json_output_literal(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx, u_char *data, size_t len,
ngx_flag_t last_buf);

ngx_int_t ngx_http_rds_json_output_bufs(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx);

ngx_int_t ngx_http_rds_json_output_field(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx, u_char *data, size_t len,
ngx_flag_t is_null);

ngx_int_t ngx_http_rds_json_output_more_field_data(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx, u_char *data, size_t len);
ngx_int_t ngx_http_rds_json_output_props_begin(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx, ngx_http_rds_json_conf_t *conf);


#endif /* NGX_HTTP_RDS_JSON_OUTPUT_H */
Expand Down
30 changes: 25 additions & 5 deletions src/ngx_http_rds_json_processor.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,17 +191,27 @@ ngx_http_rds_json_process_col(ngx_http_request_t *r,

dd("before output literal");

conf = ngx_http_get_module_loc_conf(r, ngx_http_rds_json_filter_module);

if (conf->root.len) {
rc = ngx_http_rds_json_output_props_begin(r, ctx, conf);

dd("after output literal");

if (rc == NGX_ERROR || rc > NGX_OK) {
return rc;
}
}

rc = ngx_http_rds_json_output_literal(r, ctx,
(u_char *)"[", sizeof("[") - 1, 0 /* last buf */);

dd("after output literal");

if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
if (rc == NGX_ERROR || rc > NGX_OK) {
return rc;
}

conf = ngx_http_get_module_loc_conf(r, ngx_http_rds_json_filter_module);

if (conf->format == json_format_compact) {
rc = ngx_http_rds_json_output_cols(r, ctx);

Expand Down Expand Up @@ -232,6 +242,8 @@ ngx_http_rds_json_process_row(ngx_http_request_t *r,
ngx_buf_t *b;
ngx_int_t rc;

ngx_http_rds_json_conf_t *conf;

if (in == NULL) {
return NGX_OK;
}
Expand Down Expand Up @@ -278,8 +290,16 @@ ngx_http_rds_json_process_row(ngx_http_request_t *r,
return NGX_ERROR;
}

rc = ngx_http_rds_json_output_literal(r, ctx,
(u_char *)"]", sizeof("]") - 1, 1 /* last buf*/);
conf = ngx_http_get_module_loc_conf(r, ngx_http_rds_json_filter_module);

if (conf->root.len) {
rc = ngx_http_rds_json_output_literal(r, ctx,
(u_char *)"]}", sizeof("]}") - 1, 1 /* last buf*/);

} else {
rc = ngx_http_rds_json_output_literal(r, ctx,
(u_char *)"]", sizeof("]") - 1, 1 /* last buf*/);
}

if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
Expand Down
110 changes: 110 additions & 0 deletions t/property.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# vi:filetype=

use lib 'lib';
use Test::Nginx::Socket;

repeat_each(2);

plan tests => repeat_each() * 2 * blocks();

$ENV{TEST_NGINX_MYSQL_PORT} ||= 3306;

our $http_config = <<'_EOC_';
upstream backend {
drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql
dbname=ngx_test user=ngx_test password=ngx_test;
}
_EOC_

no_diff();
no_long_string();

run_tests();

__DATA__
=== TEST 1: sanity
--- http_config eval: $::http_config
--- config
location /mysql {
drizzle_query '
select * from cats order by id asc
';
drizzle_pass backend;
rds_json on;
rds_json_root rows;
}
--- request
GET /mysql
--- response_body chomp
{"rows":[{"id":2,"name":null},{"id":3,"name":"bob"}]}
=== TEST 2: update
--- http_config eval: $::http_config
--- config
location /mysql {
drizzle_pass backend;
#drizzle_dbname $dbname;
drizzle_query "update cats set name='bob' where name='bob'";
rds_json on;
rds_json_root data;
}
--- request
GET /mysql
--- response_body chop
{"errcode":0,"errstr":"Rows matched: 1 Changed: 0 Warnings: 0"}
=== TEST 3: select empty result
--- http_config eval: $::http_config
--- config
location /mysql {
drizzle_pass backend;
drizzle_query "select * from cats where name='tom'";
rds_json on;
rds_json_root data;
}
--- request
GET /mysql
--- response_body chop
{"data":[]}
=== TEST 4: sanity + compact
--- http_config eval: $::http_config
--- config
location /mysql {
drizzle_query '
select * from cats order by id asc
';
drizzle_pass backend;
rds_json on;
rds_json_root rows;
rds_json_format compact;
}
--- request
GET /mysql
--- response_body chomp
{"rows":[["id","name"],[2,null],[3,"bob"]]}
=== TEST 5: select empty result + compact
--- http_config eval: $::http_config
--- config
location /mysql {
drizzle_pass backend;
drizzle_query "select * from cats where name='tom'";
rds_json on;
rds_json_root data;
rds_json_format compact;
}
--- request
GET /mysql
--- response_body chop
{"data":[["id","name"]]}

0 comments on commit 6fc2697

Please sign in to comment.