Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

implemented the rds_json_root directive.

  • Loading branch information...
commit 6fc26970a14054261e9e647188f447cbb0da015c 1 parent e635e13
Yichun Zhang agentzh authored
66 src/ngx_http_rds_json_filter_module.c
View
@@ -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[] = {
@@ -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
@@ -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;
@@ -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 src/ngx_http_rds_json_filter_module.h
View
@@ -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;
34 src/ngx_http_rds_json_output.c
View
@@ -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);
@@ -212,6 +213,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)
{
@@ -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++) {
7 src/ngx_http_rds_json_output.h
View
@@ -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 */
30 src/ngx_http_rds_json_processor.c
View
@@ -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);
@@ -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;
}
@@ -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;
110 t/property.t
View
@@ -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"]]}
+
Please sign in to comment.
Something went wrong with that request. Please try again.