 a58f944f23
			
		
	
	a58f944f23
	
	
	
		
			
			The process and thread initialization/finalization of the query classifier plugins is handled using the process and thread initialization/finalization functions in the module object. However, the top-level query classifier will also need to perform process and thread initialization when transaction boundaries are detected using regular expressions.
		
			
				
	
	
		
			342 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2016 MariaDB Corporation Ab
 | |
|  *
 | |
|  * Use of this software is governed by the Business Source License included
 | |
|  * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | |
|  *
 | |
|  * Change Date: 2019-07-01
 | |
|  *
 | |
|  * On the date above, in accordance with the Business Source License, use
 | |
|  * of this software will be governed by version 2 or later of the General
 | |
|  * Public License.
 | |
|  */
 | |
| 
 | |
| #include <my_config.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <string.h>
 | |
| #include <maxscale/query_classifier.h>
 | |
| #include <maxscale/buffer.h>
 | |
| #include <mysql.h>
 | |
| #include <unistd.h>
 | |
| #include <maxscale/paths.h>
 | |
| #include <maxscale/log_manager.h>
 | |
| 
 | |
| char* append(char* types, const char* type_name, size_t* lenp)
 | |
| {
 | |
|     size_t len = strlen(type_name) + 1;
 | |
| 
 | |
|     if (types)
 | |
|     {
 | |
|         len += 1;
 | |
|     }
 | |
| 
 | |
|     *lenp += len;
 | |
| 
 | |
|     char* tmp = realloc(types, *lenp);
 | |
| 
 | |
|     if (types)
 | |
|     {
 | |
|         types = tmp;
 | |
|         strcat(types, "|");
 | |
|         strcat(types, type_name);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         types = tmp;
 | |
|         strcpy(types, type_name);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     return types;
 | |
| }
 | |
| 
 | |
| char* get_types_as_string(uint32_t types)
 | |
| {
 | |
|     char* s = NULL;
 | |
|     size_t len = 0;
 | |
| 
 | |
|     if (types & QUERY_TYPE_LOCAL_READ)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_LOCAL_READ", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_READ)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_READ", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_WRITE)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_WRITE", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_MASTER_READ)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_MASTER_READ", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_SESSION_WRITE)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_SESSION_WRITE", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_USERVAR_READ)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_USERVAR_READ", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_SYSVAR_READ)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_SYSVAR_READ", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_GSYSVAR_READ)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_GSYSVAR_READ", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_GSYSVAR_WRITE)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_GSYSVAR_WRITE", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_BEGIN_TRX)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_BEGIN_TRX", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_ENABLE_AUTOCOMMIT)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_ENABLE_AUTOCOMMIT", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_DISABLE_AUTOCOMMIT)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_DISABLE_AUTOCOMMIT", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_ROLLBACK)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_ROLLBACK", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_COMMIT)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_COMMIT", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_PREPARE_NAMED_STMT)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_PREPARE_NAMED_STMT", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_PREPARE_STMT)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_PREPARE_STMT", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_EXEC_STMT)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_EXEC_STMT", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_CREATE_TMP_TABLE)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_CREATE_TMP_TABLE", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_READ_TMP_TABLE)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_READ_TMP_TABLE", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_SHOW_DATABASES)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_SHOW_DATABASES", &len);
 | |
|     }
 | |
|     if (types & QUERY_TYPE_SHOW_TABLES)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_SHOW_TABLES", &len);
 | |
|     }
 | |
| 
 | |
|     if (!s)
 | |
|     {
 | |
|         s = append(s, "QUERY_TYPE_UNKNOWN", &len);
 | |
|     }
 | |
| 
 | |
|     return s;
 | |
| }
 | |
| 
 | |
| int test(FILE* input, FILE* expected)
 | |
| {
 | |
|     int rc = EXIT_SUCCESS;
 | |
| 
 | |
|     int buffsz = getpagesize(), strsz = 0;
 | |
|     char buffer[1024], *strbuff = (char*)calloc(buffsz, sizeof(char));
 | |
| 
 | |
|     int rd;
 | |
| 
 | |
|     while ((rd = fread(buffer, sizeof(char), 1023, input)))
 | |
|     {
 | |
|         /**Fill the read buffer*/
 | |
| 
 | |
|         if (strsz + rd >= buffsz)
 | |
|         {
 | |
|             char* tmp = realloc(strbuff, (buffsz * 2) * sizeof(char));
 | |
| 
 | |
|             if (tmp == NULL)
 | |
|             {
 | |
|                 free(strbuff);
 | |
|                 fprintf(stderr, "Error: Memory allocation failed.");
 | |
|                 return 1;
 | |
|             }
 | |
|             strbuff = tmp;
 | |
|             buffsz *= 2;
 | |
|         }
 | |
| 
 | |
|         memcpy(strbuff + strsz, buffer, rd);
 | |
|         strsz += rd;
 | |
|         *(strbuff + strsz) = '\0';
 | |
| 
 | |
|         char *tok, *nlptr;
 | |
| 
 | |
|         /**Remove newlines*/
 | |
|         while ((nlptr = strpbrk(strbuff, "\n")) != NULL && (nlptr - strbuff) < strsz)
 | |
|         {
 | |
|             memmove(nlptr, nlptr + 1, strsz - (nlptr + 1 - strbuff));
 | |
|             strsz -= 1;
 | |
|         }
 | |
| 
 | |
|         /**Parse read buffer for full queries*/
 | |
| 
 | |
|         while (strpbrk(strbuff, ";") != NULL)
 | |
|         {
 | |
|             tok = strpbrk(strbuff, ";");
 | |
|             unsigned int qlen = tok - strbuff + 1;
 | |
|             unsigned int payload_len = qlen + 1;
 | |
|             unsigned int buf_len = payload_len + 4;
 | |
|             GWBUF* buff = gwbuf_alloc(buf_len);
 | |
|             *((unsigned char*)(GWBUF_DATA(buff))) = payload_len;
 | |
|             *((unsigned char*)(GWBUF_DATA(buff) + 1)) = (payload_len >> 8);
 | |
|             *((unsigned char*)(GWBUF_DATA(buff) + 2)) = (payload_len >> 16);
 | |
|             *((unsigned char*)(GWBUF_DATA(buff) + 3)) = 0x00;
 | |
|             *((unsigned char*)(GWBUF_DATA(buff) + 4)) = 0x03;
 | |
|             memcpy(GWBUF_DATA(buff) + 5, strbuff, qlen);
 | |
|             memmove(strbuff, tok + 1, strsz - qlen);
 | |
|             strsz -= qlen;
 | |
|             memset(strbuff + strsz, 0, buffsz - strsz);
 | |
|             qc_query_type_t type = qc_get_type_mask(buff);
 | |
|             char expbuff[256];
 | |
|             int expos = 0;
 | |
| 
 | |
|             while ((rd = fgetc(expected)) != '\n' && !feof(expected))
 | |
|             {
 | |
|                 expbuff[expos++] = rd;
 | |
|             }
 | |
|             expbuff[expos] = '\0';
 | |
| 
 | |
|             char *qtypestr = get_types_as_string(type);
 | |
|             const char* q = (const char*) GWBUF_DATA(buff) + 5;
 | |
| 
 | |
|             printf("Query   : %.*s\n", qlen, q);
 | |
|             printf("Reported: %s\n", qtypestr);
 | |
| 
 | |
|             if (strcmp(qtypestr, expbuff) == 0)
 | |
|             {
 | |
|                 printf("OK\n");
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 printf("ERROR   : %s\n", expbuff);
 | |
|                 rc = 1;
 | |
|             }
 | |
| 
 | |
|             printf("\n");
 | |
| 
 | |
|             free(qtypestr);
 | |
| 
 | |
|             gwbuf_free(buff);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     free(strbuff);
 | |
|     return rc;
 | |
| }
 | |
| 
 | |
| int run(const char* input_filename, const char* expected_filename)
 | |
| {
 | |
|     int rc = EXIT_FAILURE;
 | |
| 
 | |
|     FILE *input = fopen(input_filename, "rb");
 | |
| 
 | |
|     if (input)
 | |
|     {
 | |
|         FILE *expected = fopen(expected_filename, "rb");
 | |
| 
 | |
|         if (expected)
 | |
|         {
 | |
|             rc = test(input, expected);
 | |
|             fclose(expected);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             fprintf(stderr, "error: Failed to open file %s.", expected_filename);
 | |
|         }
 | |
| 
 | |
|         fclose(input);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         fprintf(stderr, "error: Failed to open file %s", input_filename);
 | |
|     }
 | |
| 
 | |
|     return rc;
 | |
| }
 | |
| 
 | |
| int main(int argc, char** argv)
 | |
| {
 | |
|     int rc = EXIT_FAILURE;
 | |
| 
 | |
|     if ((argc == 3) || (argc == 4))
 | |
|     {
 | |
|         const char* lib;
 | |
|         char* libdir;
 | |
|         const char* input_name;
 | |
|         const char* expected_name;
 | |
| 
 | |
|         if (argc == 3)
 | |
|         {
 | |
|             lib = "qc_mysqlembedded";
 | |
|             libdir = strdup("../qc_mysqlembedded");
 | |
|             input_name = argv[1];
 | |
|             expected_name = argv[2];
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             lib = argv[1];
 | |
|             input_name = argv[2];
 | |
|             expected_name = argv[3];
 | |
| 
 | |
|             size_t sz = strlen(lib);
 | |
|             char buffer[sz + 3 + 1]; // "../" and terminating NULL.
 | |
|             sprintf(buffer, "../%s", lib);
 | |
| 
 | |
|             libdir = strdup(buffer);
 | |
|         }
 | |
| 
 | |
|         set_libdir(libdir);
 | |
|         set_datadir(strdup("/tmp"));
 | |
|         set_langdir(strdup("."));
 | |
|         set_process_datadir(strdup("/tmp"));
 | |
| 
 | |
|         if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
 | |
|         {
 | |
|             if (qc_setup(lib, NULL) && qc_process_init(QC_INIT_BOTH))
 | |
|             {
 | |
|                 rc = run(input_name, expected_name);
 | |
|                 qc_process_end(QC_INIT_BOTH);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 fprintf(stderr, "error: %s: Could not initialize query classifier library %s.\n",
 | |
|                         argv[0], lib);
 | |
|             }
 | |
| 
 | |
|             mxs_log_finish();
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             fprintf(stderr, "error: %s: Could not initialize log.\n", argv[0]);
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         fprintf(stderr, "Usage: classify <input> <expected output>\n");
 | |
|     }
 | |
| 
 | |
|     return rc;
 | |
| }
 |