From 2fac96d01e0097bbd47f0c4fb2bd14e84fd5bdaf Mon Sep 17 00:00:00 2001
From: "simpl.it" <fbk.eugaia@gmail.com>
Date: Sat, 16 Apr 2011 04:14:34 +0300
Subject: [PATCH 1/3] Add drizzle_return_error_code and
 drizzle_no_log_error_codes directives

---
 README                           | 16 +++++++
 src/ngx_http_drizzle_module.c    | 80 +++++++++++++++++++++++++++++++-
 src/ngx_http_drizzle_module.h    |  3 ++
 src/ngx_http_drizzle_processor.c | 56 ++++++++++++++++------
 4 files changed, 140 insertions(+), 15 deletions(-)

diff --git a/README b/README
index 8a4862b..48898c5 100644
--- a/README
+++ b/README
@@ -222,6 +222,22 @@ Directives
               servers: 1
               peers: 1
 
+    drizzle_return_error_code on|off
+        Returns the drizzle / mysql error code when an error occurs, rather
+        than 500 (internal server error).
+
+        This can be useful for example if you are using ngx_lua to process the
+        returned data, and wish to handle specific error situations, such as
+        when there is a duplicate entry on INSERT queries (see example below).
+
+    drizzle_no_log_error_codes <num> [<num> ...]
+        Do not log error information for the error codes listed
+
+        e.g.
+
+        drizzle_return_error_code   on;
+        drizzle_no_log_error_codes  1062;   # doesn't log duplicate entries
+
 Output
     This module generates binary query results in a format
     that will be shared among the various nginx database
diff --git a/src/ngx_http_drizzle_module.c b/src/ngx_http_drizzle_module.c
index c6d469f..0b66955 100644
--- a/src/ngx_http_drizzle_module.c
+++ b/src/ngx_http_drizzle_module.c
@@ -30,7 +30,9 @@ static ngx_int_t ngx_http_drizzle_tid_variable(ngx_http_request_t *r,
         ngx_http_variable_value_t *v, uintptr_t data);
 static char * ngx_http_drizzle_enable_status(ngx_conf_t *cf,
         ngx_command_t *cmd, void *conf);
-
+static char * ngx_http_drizzle_error_codes(ngx_conf_t *cf, 
+        ngx_command_t *cmd, void *conf);
+        
 
 static ngx_http_variable_t ngx_http_drizzle_variables[] = {
 
@@ -136,6 +138,22 @@ static ngx_command_t ngx_http_drizzle_cmds[] = {
       0,
       NULL },
 
+    { ngx_string("drizzle_return_error_code"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
+          |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_drizzle_loc_conf_t, return_error_code),
+      NULL },
+
+    { ngx_string("drizzle_no_log_error_codes"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
+          |NGX_HTTP_LIF_CONF|NGX_CONF_1MORE,
+      ngx_http_drizzle_error_codes,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_drizzle_loc_conf_t, no_log_error_codes),
+      NULL },
+
     ngx_null_command
 };
 
@@ -229,13 +247,15 @@ ngx_http_drizzle_create_loc_conf(ngx_conf_t *cf)
     /* set by ngx_pcalloc:
      *      conf->dbname = NULL
      *      conf->query  = NULL
+     *      conf->no_log_error_codes = NULL
      */
 
+    conf->return_error_code = NGX_CONF_UNSET;
     conf->complex_target = NGX_CONF_UNSET_PTR;
 
     conf->buf_size = NGX_CONF_UNSET_SIZE;
     conf->tid_var_index = NGX_CONF_UNSET;
-
+    
     return conf;
 }
 
@@ -271,6 +291,11 @@ ngx_http_drizzle_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
         conf->queries = prev->queries;
     }
 
+    ngx_conf_merge_value(conf->return_error_code, prev->return_error_code, 0);
+
+    if (conf->no_log_error_codes == NULL)
+        conf->no_log_error_codes = prev->no_log_error_codes;
+    
     ngx_conf_merge_size_value(conf->buf_size, prev->buf_size,
             (size_t) ngx_pagesize);
 
@@ -560,3 +585,54 @@ ngx_http_drizzle_enable_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
     return NGX_CONF_OK;
 }
 
+
+static char *
+ngx_http_drizzle_error_codes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+    
+    ngx_array_t     **ap;
+    ngx_str_t        *value, *e;
+    ngx_int_t         i, *c;
+    
+    ap = (ngx_array_t **) (p + cmd->offset);
+    if (*ap) {
+        return  "is duplicate";
+    }
+    
+    *ap = ngx_array_create (cf->pool, cf->args->nelts - 1, sizeof (ngx_int_t));
+    if (*ap == NULL)
+        return  NGX_CONF_ERROR;
+    
+    value = cf->args->elts;
+    value++;
+    
+    e = value + cf->args->nelts - 1;
+    
+    for ( ;value<e; value++) {
+        
+        c = ngx_array_push (*ap);
+        if (c == NULL)
+            return  NGX_CONF_ERROR;
+        
+        *c = ngx_atoi (value->data, value->len);
+        if (*c == NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                "\"%V\" is not a valid drizzle error code", value);
+                
+            return  NGX_CONF_ERROR;
+        }
+        
+        if (*c < 0 || *c > 0xffff) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                "\"%V\" is not a valid drizzle error code", value);
+                
+            return  NGX_CONF_ERROR;
+        }
+        
+        /* TODO: further check that numbers are valid error codes? */
+    }
+    
+    return NGX_CONF_OK;
+}
+
diff --git a/src/ngx_http_drizzle_module.h b/src/ngx_http_drizzle_module.h
index 3af2ce8..751b42b 100644
--- a/src/ngx_http_drizzle_module.h
+++ b/src/ngx_http_drizzle_module.h
@@ -55,6 +55,9 @@ typedef struct {
     ngx_array_t                         *user_types;
                 /* of ngx_http_drizzle_var_type_t */
 
+    ngx_flag_t                           return_error_code;
+    ngx_array_t                         *no_log_error_codes;
+                
     ngx_http_complex_value_t            *complex_target;
 
     size_t                               buf_size;
diff --git a/src/ngx_http_drizzle_processor.c b/src/ngx_http_drizzle_processor.c
index 194de4d..2ad850d 100644
--- a/src/ngx_http_drizzle_processor.c
+++ b/src/ngx_http_drizzle_processor.c
@@ -158,6 +158,7 @@ ngx_http_upstream_drizzle_send_query(ngx_http_request_t *r,
         ngx_connection_t *c, ngx_http_upstream_drizzle_peer_data_t *dp,
         drizzle_con_st *dc)
 {
+    ngx_http_drizzle_loc_conf_t *dlcf;
     ngx_http_upstream_t         *u = r->upstream;
     drizzle_return_t             ret;
     ngx_int_t                    rc;
@@ -165,7 +166,9 @@ ngx_http_upstream_drizzle_send_query(ngx_http_request_t *r,
     size_t                       query_len;
     ngx_flag_t                   has_set_names = 0;
     ngx_flag_t                   enable_charset = 0;
-
+    ngx_flag_t                   log_error;
+    ngx_int_t                    error_code, *codep, *codepe;
+    
     dd("enable charset: %d", (int) dp->enable_charset);
 
     if (dp->enable_charset && ! dp->has_set_names) {
@@ -202,16 +205,37 @@ ngx_http_upstream_drizzle_send_query(ngx_http_request_t *r,
     }
 
     if (ret != DRIZZLE_RETURN_OK) {
+        
+        error_code = drizzle_error_code(dc->drizzle);
+        
+        dlcf = ngx_http_get_module_loc_conf (r, ngx_http_drizzle_module);
+        
+        log_error = 1;
+        
+        if (dlcf->no_log_error_codes) {
+            codep = dlcf->no_log_error_codes->elts;
+            codepe = codep + dlcf->no_log_error_codes->nelts;
+            
+            for ( ; codep < codepe; codep++) {
+                if (*codep == error_code) {
+                    log_error = 0;
+                    break;
+                }
+            }
+        }
 #if 1
         if (ret == DRIZZLE_RETURN_ERROR_CODE) {
-            if (drizzle_error_code(dc->drizzle) == MYSQL_ER_NO_SUCH_TABLE) {
-                dd("XXX no such talbe");
-
-                ngx_log_error(NGX_LOG_NOTICE, c->log, 0,
-                               "failed to send query: %d (%d): %s",
-                               (int) ret, drizzle_error_code(dc->drizzle),
-                               drizzle_error(dc->drizzle));
-
+            if (error_code == MYSQL_ER_NO_SUCH_TABLE) {
+                dd("XXX no such table");
+
+                if (log_error) {
+                
+                    ngx_log_error(NGX_LOG_NOTICE, c->log, 0,
+                                "failed to send query: %d (%ui): %s",
+                                (int) ret, error_code,
+                                drizzle_error(dc->drizzle));
+                }
+                
                 if (dp->enable_charset && ! dp->has_set_names) {
                     c->log->action = "sending query to drizzle upstream";
                     dp->has_set_names = 1;
@@ -226,11 +250,17 @@ ngx_http_upstream_drizzle_send_query(ngx_http_request_t *r,
         }
 #endif
 
-        ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                       "failed to send query: %d (%d): %s",
-                       (int) ret, drizzle_error_code(dc->drizzle),
-                       drizzle_error(dc->drizzle));
+        if (log_error) {
 
+            ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                        "failed to send query: %d (%ui): %s",
+                        (int) ret, error_code,
+                        drizzle_error(dc->drizzle));
+        }
+        
+        if (dlcf->return_error_code)
+            return  error_code;
+        
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 

From 7fbaef10fea2fe26b488755dee1cf4cdcb85131d Mon Sep 17 00:00:00 2001
From: "simpl.it" <fbk.eugaia@gmail.com>
Date: Sat, 16 Apr 2011 04:23:47 +0300
Subject: [PATCH 2/3] update conf logging of error in
 ngx_http_drizzle_error_codes()

---
 src/ngx_http_drizzle_module.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/ngx_http_drizzle_module.c b/src/ngx_http_drizzle_module.c
index 0b66955..fc46505 100644
--- a/src/ngx_http_drizzle_module.c
+++ b/src/ngx_http_drizzle_module.c
@@ -618,14 +618,14 @@ ngx_http_drizzle_error_codes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         *c = ngx_atoi (value->data, value->len);
         if (*c == NGX_ERROR) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                "\"%V\" is not a valid drizzle error code", value);
+                "\"%V\" is not a valid drizzle error code (it must be an integer)", value);
                 
             return  NGX_CONF_ERROR;
         }
         
-        if (*c < 0 || *c > 0xffff) {
+        if (*c <= 0 || *c > 0xffff) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                "\"%V\" is not a valid drizzle error code", value);
+                "\"%V\" is not a valid drizzle error code (it must be an integer between 1 and 65536)", value);
                 
             return  NGX_CONF_ERROR;
         }

From eb90e78f332710111e9939940bdd33dc0bc51602 Mon Sep 17 00:00:00 2001
From: "simpl.it" <fbk.eugaia@gmail.com>
Date: Sat, 16 Apr 2011 04:26:49 +0300
Subject: [PATCH 3/3] update conf logging of error in
 ngx_http_drizzle_error_codes()

---
 src/ngx_http_drizzle_module.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/ngx_http_drizzle_module.c b/src/ngx_http_drizzle_module.c
index fc46505..58e96c1 100644
--- a/src/ngx_http_drizzle_module.c
+++ b/src/ngx_http_drizzle_module.c
@@ -618,7 +618,7 @@ ngx_http_drizzle_error_codes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         *c = ngx_atoi (value->data, value->len);
         if (*c == NGX_ERROR) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                "\"%V\" is not a valid drizzle error code (it must be an integer)", value);
+                "\"%V\" is not a valid drizzle error code (it must be an integer between 1 and 65536)", value);
                 
             return  NGX_CONF_ERROR;
         }