Explorar el Código

HPCC-15478 MySQL embed supports setting various MySQL options

See documentation for mysql_options for the options that are
available and their meanings...

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman hace 9 años
padre
commit
68acf36f8a
Se han modificado 1 ficheros con 153 adiciones y 24 borrados
  1. 153 24
      plugins/mysql/mysqlembed.cpp

+ 153 - 24
plugins/mysql/mysqlembed.cpp

@@ -963,27 +963,19 @@ protected:
 
 static __thread ThreadTermFunc threadHookChain;
 static __thread MySQLConnection *cachedConnection = NULL;
-static __thread const char *cachedServer = NULL;
-static __thread const char *cachedUser = NULL;
-static __thread const char *cachedPassword = NULL;
-static __thread const char *cachedDatabase = NULL;
-static __thread unsigned cachedPort = 0;
+static __thread const char *cachedOptions = NULL;
 
-static bool cachedConnectionMatches(const char *server, unsigned port, const char *user, const char *password, const char *database)
+static bool cachedConnectionMatches(const char *options)
 {
-    return streq(server, cachedServer) && port==cachedPort && streq(user, cachedUser) && streq(password, cachedPassword) && streq(database, cachedDatabase);
+    return streq(options, cachedOptions);
 }
 
 static void clearCache()
 {
     ::Release(cachedConnection);
     cachedConnection = NULL;
-    free((void *) cachedServer);
-    free((void *) cachedUser);
-    free((void *) cachedPassword);
-    free((void *) cachedDatabase);
-    cachedServer = cachedUser = cachedPassword = cachedDatabase = NULL;
-    cachedPort = 0;
+    free((void *) cachedOptions);
+    cachedOptions = NULL;
 }
 
 static bool mysqlInitialized = false;
@@ -1020,17 +1012,96 @@ static void initializeMySqlThread()
     }
 }
 
-static void cacheConnection(MySQLConnection *connection, const char *server, unsigned port, const char *user, const char *password, const char *database)
+static void cacheConnection(MySQLConnection *connection, const char *options)
 {
     clearCache();
-    cachedServer = strdup(server);
-    cachedUser = strdup(user);
-    cachedPassword = strdup(password);
-    cachedDatabase = strdup(database);
-    cachedPort = port;
+    cachedOptions = strdup(options);
     cachedConnection = LINK(connection);
 }
 
+enum MySQLOptionParamType
+{
+    ParamTypeNone,
+    ParamTypeString,
+    ParamTypeUInt,
+    ParamTypeULong,
+    ParamTypeBool
+};
+
+struct MySQLOptionDefinition
+{
+    const char *name;
+    enum mysql_option option;
+    MySQLOptionParamType paramType;
+};
+
+#define addoption(a,b) { #a, a, b }
+
+MySQLOptionDefinition options[] =
+{
+  addoption(MYSQL_DEFAULT_AUTH, ParamTypeString),
+  addoption(MYSQL_ENABLE_CLEARTEXT_PLUGIN, ParamTypeBool),
+  addoption(MYSQL_INIT_COMMAND, ParamTypeString),
+  addoption(MYSQL_OPT_BIND, ParamTypeString),
+  addoption(MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, ParamTypeBool),
+  addoption(MYSQL_OPT_COMPRESS, ParamTypeNone),
+  addoption(MYSQL_OPT_CONNECT_ATTR_DELETE, ParamTypeString),
+  addoption(MYSQL_OPT_CONNECT_ATTR_RESET, ParamTypeNone),
+  addoption(MYSQL_OPT_CONNECT_TIMEOUT, ParamTypeUInt),
+  addoption(MYSQL_OPT_GUESS_CONNECTION, ParamTypeNone),
+  addoption(MYSQL_OPT_LOCAL_INFILE, ParamTypeUInt),
+  addoption(MYSQL_OPT_NAMED_PIPE, ParamTypeNone),
+#if (MYSQL_VERSION_ID >= 50709)
+  addoption(MYSQL_OPT_MAX_ALLOWED_PACKET, ParamTypeULong),
+  addoption(MYSQL_OPT_NET_BUFFER_LENGTH, ParamTypeULong),
+#endif
+  addoption(MYSQL_OPT_PROTOCOL, ParamTypeUInt),
+  addoption(MYSQL_OPT_READ_TIMEOUT, ParamTypeUInt),
+  addoption(MYSQL_OPT_RECONNECT, ParamTypeBool),
+  addoption(MYSQL_OPT_SSL_CA, ParamTypeString),
+  addoption(MYSQL_OPT_SSL_CAPATH, ParamTypeString),
+  addoption(MYSQL_OPT_SSL_CERT, ParamTypeString),
+  addoption(MYSQL_OPT_SSL_CIPHER, ParamTypeString),
+  addoption(MYSQL_OPT_SSL_CRL, ParamTypeString),
+  addoption(MYSQL_OPT_SSL_CRLPATH, ParamTypeString),
+#if (MYSQL_VERSION_ID >= 50703)
+  addoption(MYSQL_OPT_SSL_ENFORCE, ParamTypeBool),
+#endif
+  addoption(MYSQL_OPT_SSL_KEY, ParamTypeString),
+#if (MYSQL_VERSION_ID >= 50711)
+  addoption(MYSQL_OPT_SSL_MODE, ParamTypeUInt),
+#endif
+  addoption(MYSQL_OPT_SSL_VERIFY_SERVER_CERT, ParamTypeBool),
+#if (MYSQL_VERSION_ID >= 50710)
+  addoption(MYSQL_OPT_TLS_VERSION, ParamTypeString),
+#endif
+  addoption(MYSQL_OPT_USE_EMBEDDED_CONNECTION, ParamTypeNone),
+  addoption(MYSQL_OPT_USE_REMOTE_CONNECTION, ParamTypeNone),
+  addoption(MYSQL_OPT_USE_RESULT, ParamTypeNone),
+  addoption(MYSQL_OPT_WRITE_TIMEOUT, ParamTypeUInt),
+  addoption(MYSQL_PLUGIN_DIR, ParamTypeString),
+  addoption(MYSQL_READ_DEFAULT_FILE, ParamTypeString),
+  addoption(MYSQL_READ_DEFAULT_GROUP, ParamTypeString),
+  addoption(MYSQL_REPORT_DATA_TRUNCATION, ParamTypeBool),
+  addoption(MYSQL_SECURE_AUTH, ParamTypeBool),
+  addoption(MYSQL_SERVER_PUBLIC_KEY, ParamTypeString),
+  addoption(MYSQL_SET_CHARSET_DIR, ParamTypeString),
+  addoption(MYSQL_SET_CHARSET_NAME, ParamTypeString),
+  addoption(MYSQL_SET_CLIENT_IP, ParamTypeString),
+  addoption(MYSQL_SHARED_MEMORY_BASE_NAME, ParamTypeString),
+  { nullptr, (enum mysql_option) 0, ParamTypeNone }
+};
+
+static MySQLOptionDefinition &lookupOption(const char *optName)
+{
+    for (MySQLOptionDefinition *optDef = options; optDef->name != nullptr; optDef++)
+    {
+        if (stricmp(optName, optDef->name)==0)
+            return *optDef;
+    }
+    failx("Unknown option %s", optName);
+}
+
 class MySQLEmbedFunctionContext : public CInterfaceOf<IEmbedFunctionContext>
 {
 public:
@@ -1041,6 +1112,7 @@ public:
         const char *user = "";
         const char *password = "";
         const char *database = "";
+        bool hasMySQLOpt = false;
         bool caching = true;
         unsigned port = 0;
         StringArray opts;
@@ -1065,10 +1137,14 @@ public:
                     database = val;
                 else if (stricmp(optName, "cache")==0)
                     caching = clipStrToBool(val);
+                else if (strnicmp(optName, "MYSQL_", 6)==0)
+                    hasMySQLOpt = true;
+                else
+                    failx("Unknown option %s", optName.str());
             }
         }
         initializeMySqlThread();
-        if (caching && cachedConnection && cachedConnectionMatches(server, port, user, password, database))
+        if (caching && cachedConnection && cachedConnectionMatches(options))
         {
             conn.set(cachedConnection);
         }
@@ -1080,14 +1156,67 @@ public:
                 cachedConnection = NULL;
             }
             conn.setown(new MySQLConnection(mysql_init(NULL)));
-            if (!mysql_real_connect(*conn, server, user, password, database, port, NULL, 0))
+            if (hasMySQLOpt)
             {
-                VStringBuffer err("mysql: failed to connect (%s)", mysql_error(*conn));
-                rtlFail(0, err.str());
+                ForEachItemIn(idx, opts)
+                {
+                    const char *opt = opts.item(idx);
+                    if (strnicmp(opt, "MYSQL_", 6)==0)
+                    {
+                        const char *val = strchr(opt, '=');
+                        StringBuffer optName(opt);
+                        if (val)
+                        {
+                            optName.setLength(val-opt);
+                            val++;
+                        }
+                        MySQLOptionDefinition &optDef = lookupOption(optName);
+                        int rc;
+                        if (optDef.paramType == ParamTypeNone)
+                        {
+                            if (val)
+                                failx("Option %s does not take a value", optName.str());
+                            rc = mysql_options(*conn, optDef.option, nullptr);
+                        }
+                        else
+                        {
+                            if (!val)
+                                failx("Option %s requires a value", optName.str());
+                            switch (optDef.paramType)
+                            {
+                            case ParamTypeString:
+                                rc = mysql_options(*conn, optDef.option, val);
+                                break;
+                            case ParamTypeUInt:
+                                {
+                                    unsigned int oval = strtoul(val, nullptr, 10);
+                                    rc = mysql_options(*conn, optDef.option, &oval);
+                                    break;
+                                }
+                            case ParamTypeULong:
+                                {
+                                    unsigned long oval = strtoul(val, nullptr, 10);
+                                    rc = mysql_options(*conn, optDef.option, &oval);
+                                    break;
+                                }
+                            case ParamTypeBool:
+                                {
+                                    my_bool oval = clipStrToBool(val);
+                                    rc = mysql_options(*conn, optDef.option, &oval);
+                                    break;
+                                }
+                            }
+                        }
+                        if (rc)
+                            failx("Failed to set option %s (%s)", optName.str(), mysql_error(*conn));
+                    }
+                }
             }
+            if (!mysql_real_connect(*conn, server, user, password, database, port, NULL, 0))
+                failx("Failed to connect (%s)", mysql_error(*conn));
             if (caching)
             {
-                cacheConnection(conn, server, port, user, password, database);
+                cacheConnection(conn, options);
             }
         }
     }