Support for the 'Collection.Options' property.

[GB.DB.MYSQL]
* NEW: Support for the 'Collection.Options' property.

[GB.DB.ODBC]
* NEW: Support for the 'Collection.Options' property.

[GB.DB.POSTGRESQL]
* NEW: Support for the 'Collection.Options' property.

[GB.DB.SQLITE2]
* NEW: Support for the 'Collection.Options' property.

[GB.DB.SQLITE3]
* NEW: Support for the 'Collection.Options' property.
This commit is contained in:
gambas 2022-04-09 13:30:42 +02:00
parent 740cff77aa
commit 9402047435
6 changed files with 228 additions and 35 deletions

View file

@ -689,12 +689,157 @@ static const char *get_quote(void)
Connect to a database.
<desc> points at a structure describing each connection parameter.
<db> points at the DB_DATABASE structure that must be initialized.
This function must return a database handle, or NULL if the connection
has failed.
This function must return TRUE if the connection has failed.
The name of the database can be NULL, meaning a default database.
*****************************************************************************/
static DB_MYSQL_OPTION _options[] = {
{ "DEFAULT_AUTH", MYSQL_DEFAULT_AUTH, GB_T_STRING },
{ "ENABLE_CLEARTEXT_PLUGIN", MYSQL_ENABLE_CLEARTEXT_PLUGIN, GB_T_BOOLEAN },
{ "INIT_COMMAND", MYSQL_INIT_COMMAND, GB_T_STRING },
{ "BIND", MYSQL_OPT_BIND, GB_T_STRING },
{ "CAN_HANDLE_EXPIRED_PASSWORDS", MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, GB_T_BOOLEAN },
{ "COMPRESSION_ALGORITHMS", MYSQL_OPT_COMPRESSION_ALGORITHMS, GB_T_STRING},
{ "CONNECT_TIMEOUT ", MYSQL_OPT_CONNECT_TIMEOUT , GB_T_INTEGER},
{ "GET_SERVER_PUBLIC_KEY", MYSQL_OPT_GET_SERVER_PUBLIC_KEY, GB_T_BOOLEAN},
{ "LOAD_DATA_LOCAL_DIR", MYSQL_OPT_LOAD_DATA_LOCAL_DIR, GB_T_STRING},
{ "LOCAL_INFILE", MYSQL_OPT_LOCAL_INFILE, GB_T_BOOLEAN},
{ "MAX_ALLOWED_PACKET", MYSQL_OPT_MAX_ALLOWED_PACKET, GB_T_INTEGER},
{ "NET_BUFFER_LENGTH", MYSQL_OPT_NET_BUFFER_LENGTH, GB_T_INTEGER},
{ "PROTOCOL", MYSQL_OPT_PROTOCOL, GB_T_STRING},
{ "READ_TIMEOUT", MYSQL_OPT_READ_TIMEOUT, GB_T_INTEGER},
{ "RECONNECT", MYSQL_OPT_RECONNECT, GB_T_BOOLEAN},
{ "RETRY_COUNT ", MYSQL_OPT_RETRY_COUNT , GB_T_INTEGER},
{ "SSL_CA", MYSQL_OPT_SSL_CA, GB_T_STRING},
{ "SSL_CAPATH", MYSQL_OPT_SSL_CAPATH, GB_T_STRING},
{ "SSL_CERT", MYSQL_OPT_SSL_CERT, GB_T_STRING},
{ "SSL_CIPHER", MYSQL_OPT_SSL_CIPHER, GB_T_STRING},
{ "SSL_CRL", MYSQL_OPT_SSL_CRL, GB_T_STRING},
{ "SSL_CRLPATH", MYSQL_OPT_SSL_CRLPATH, GB_T_STRING},
{ "SSL_FIPS_MODE", MYSQL_OPT_SSL_FIPS_MODE, GB_T_INTEGER},
{ "SSL_KEY", MYSQL_OPT_SSL_KEY, GB_T_STRING},
{ "SSL_MODE", MYSQL_OPT_SSL_MODE, GB_T_STRING},
{ "TLS_CIPHERSUITES", MYSQL_OPT_TLS_CIPHERSUITES, GB_T_STRING},
{ "TLS_VERSION", MYSQL_OPT_TLS_VERSION, GB_T_STRING},
{ "WRITE_TIMEOUT", MYSQL_OPT_WRITE_TIMEOUT, GB_T_INTEGER},
{ "ZSTD_COMPRESSION_LEVEL", MYSQL_OPT_ZSTD_COMPRESSION_LEVEL, GB_T_INTEGER},
{ "PLUGIN_DIR", MYSQL_PLUGIN_DIR, GB_T_STRING},
{ "READ_DEFAULT_FILE", MYSQL_READ_DEFAULT_FILE, GB_T_STRING},
{ "READ_DEFAULT_GROUP", MYSQL_READ_DEFAULT_GROUP, GB_T_STRING},
{ "REPORT_DATA_TRUNCATION", MYSQL_REPORT_DATA_TRUNCATION, GB_T_BOOLEAN},
{ "SERVER_PUBLIC_KEY", MYSQL_SERVER_PUBLIC_KEY, GB_T_STRING},
{ "SET_CHARSET_DIR", MYSQL_SET_CHARSET_DIR, GB_T_STRING},
{ "SET_CHARSET_NAME", MYSQL_SET_CHARSET_NAME, GB_T_STRING},
{ NULL }
};
static MYSQL *_options_conn;
static void add_option_value(const char *key, GB_VALUE *value)
{
DB_MYSQL_OPTION *p;
union {
unsigned int _uint;
unsigned long _ulong;
} tmp;
char *sval;
for (p = _options;; p++)
{
if (!p->key)
return;
if (!strcasecmp(p->key, key))
break;
}
if (GB.Conv(value, p->type))
return;
switch(p->cst)
{
case MYSQL_OPT_PROTOCOL:
sval = value->_string.value.addr;
if (!strcasecmp(sval, "DEFAULT"))
tmp._uint = MYSQL_PROTOCOL_DEFAULT;
else if (!strcasecmp(sval, "TCP"))
tmp._uint = MYSQL_PROTOCOL_TCP;
else if (!strcasecmp(sval, "SOCKET"))
tmp._uint = MYSQL_PROTOCOL_SOCKET;
else if (!strcasecmp(sval, "PIPE"))
tmp._uint = MYSQL_PROTOCOL_PIPE;
else if (!strcasecmp(sval, "MEMORY"))
tmp._uint = MYSQL_PROTOCOL_MEMORY;
else
return;
mysql_options(_options_conn, p->cst, &tmp._uint);
break;
case MYSQL_OPT_LOCAL_INFILE:
tmp._uint = value->_boolean.value;
mysql_options(_options_conn, p->cst, &tmp._uint);
break;
case MYSQL_OPT_MAX_ALLOWED_PACKET:
case MYSQL_OPT_NET_BUFFER_LENGTH:
tmp._ulong = value->_integer.value;
mysql_options(_options_conn, p->cst, &tmp._ulong);
break;
case MYSQL_OPT_SSL_FIPS_MODE:
sval = value->_string.value.addr;
if (!strcasecmp(sval, "OFF"))
tmp._uint = SSL_FIPS_MODE_OFF;
else if (!strcasecmp(sval, "ON"))
tmp._uint = SSL_FIPS_MODE_ON;
else if (!strcasecmp(sval, "STRICT"))
tmp._uint = SSL_FIPS_MODE_STRICT;
else
return;
mysql_options(_options_conn, p->cst, &tmp._uint);
break;
case MYSQL_OPT_SSL_MODE:
sval = value->_string.value.addr;
if (!strcasecmp(sval, "DISABLED"))
tmp._uint = SSL_MODE_DISABLED;
else if (!strcasecmp(sval, "PREFERRED"))
tmp._uint = SSL_MODE_PREFERRED;
else if (!strcasecmp(sval, "REQUIRED"))
tmp._uint = SSL_MODE_REQUIRED;
else if (!strcasecmp(sval, "VERIFY_CA"))
tmp._uint = SSL_MODE_VERIFY_CA;
else if (!strcasecmp(sval, "VERIFY_IDENTITY"))
tmp._uint = SSL_MODE_VERIFY_IDENTITY;
else
return;
mysql_options(_options_conn, p->cst, &tmp._uint);
break;
default:
if (p->type == GB_T_BOOLEAN)
mysql_options(_options_conn, p->cst, &value->_boolean.value);
else if (p->type == GB_T_INTEGER)
mysql_options(_options_conn, p->cst, &value->_integer.value);
else if (p->type == GB_T_STRING)
mysql_options(_options_conn, p->cst, value->_string.value.addr);
}
}
static void set_character_set(DB_DATABASE *db)
{
MYSQL_RES *res;
@ -771,6 +916,10 @@ static int open_database(DB_DESC *desc, DB_DATABASE *db)
timeout = db->timeout;
mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
_options_conn = conn;
DB.GetOptions(add_option_value);
env = getenv("GB_DB_MYSQL_NOSSL");
if (env && strcmp(env, "0"))
{

View file

@ -1,23 +1,23 @@
/***************************************************************************
main.h
main.h
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
@ -35,4 +35,12 @@ extern DB_INTERFACE DB;
#define QUOTE_STRING "`"
typedef
struct {
const char *key;
int cst;
int type;
}
DB_MYSQL_OPTION;
#endif /* __MAIN_H */

View file

@ -713,16 +713,18 @@ void GetConnectedDBName(DB_DESC *desc, ODBC_CONN *odbc)
}
/*****************************************************************************
*
open_database()
Connect to a database.
<desc> points at a structure describing each connection parameter.
<db> points at the DB_DATABASE structure that must be initialized.
This function must return TRUE if the connection has failed.
The name of the database can be NULL, meaning a default database.
This function must return a database handle, or NULL if the connection
has failed.
*****************************************************************************/
static int open_database(DB_DESC *desc, DB_DATABASE *db)

View file

@ -703,6 +703,23 @@ static const char *get_quote(void)
*****************************************************************************/
static const char **_options_keys;
static const char **_options_values;
static void add_option(const char *key, const char *value)
{
*(const char **)GB.Add(&_options_keys) = key;
*(const char **)GB.Add(&_options_values) = value;
}
static void add_option_value(const char *key, GB_VALUE *value)
{
if (GB.Conv(value, GB_T_STRING))
return;
add_option(key, value->_string.value.addr);
}
static int open_database(DB_DESC *desc, DB_DATABASE *db)
{
const char *query =
@ -712,22 +729,34 @@ static int open_database(DB_DESC *desc, DB_DATABASE *db)
PGresult *res;
int status;
char *name;
char dbname[512];
char buffer[16];
if (desc->name)
name = desc->name;
else
name = "template1";
if (snprintf(dbname, sizeof(dbname), "dbname='%s' connect_timeout=%d", get_quote_string(name, strlen(name), '\''), db->timeout) >= sizeof(dbname))
{
GB.Error("Cannot open database: database name too long");
return TRUE;
}
//fprintf(stderr, "gb.db.postgresql: host = `%s` port = `%s` dbnname = `%s` user = `%s` password = `%s`\n", desc->host, desc->port, dbname, desc->user, desc->password);
conn = PQsetdbLogin(desc->host, desc->port, NULL, NULL, dbname, desc->user, desc->password);
GB.NewArray(&_options_keys, sizeof(char *), 0);
GB.NewArray(&_options_values, sizeof(char *), 0);
add_option("host", desc->host);
add_option("port", desc->port);
add_option("dbname", name);
add_option("user", desc->user);
add_option("password", desc->password);
sprintf(buffer, "%d", db->timeout);
add_option("connect_timeout", buffer);
DB.GetOptions(add_option_value);
add_option(NULL, NULL);
conn = PQconnectdbParams((const char *const *)_options_keys, (const char *const *)_options_values, FALSE);
GB.FreeArray(&_options_keys);
GB.FreeArray(&_options_values);
if (!conn)
{

View file

@ -508,6 +508,7 @@ static const char *get_quote(void)
return QUOTE_STRING;
}
/*****************************************************************************
open_database()
@ -515,13 +516,15 @@ static const char *get_quote(void)
Connect to a database.
<desc> points at a structure describing each connection parameter.
<db> points at the DB_DATABASE structure that must be initialized.
This function must return TRUE if the connection has failed.
The name of the database can be NULL, meaning a default database.
In Sqlite, there is no such thing as a host. If this is set then check
to see whether this is actually a path to a home area. NG 01/04/04
This function must return a database handle, or NULL if the connection
has failed.
*****************************************************************************/
static int open_database(DB_DESC *desc, DB_DATABASE *db)

View file

@ -547,13 +547,15 @@ static const char *get_quote(void)
Connect to a database.
<desc> points at a structure describing each connection parameter.
<db> points at the DB_DATABASE structure that must be initialized.
This function must return TRUE if the connection has failed.
The name of the database can be NULL, meaning a default database.
In Sqlite, there is no such thing as a host. If this is set then check
to see whether this is actually a path to a home area. NG 01/04/04
This function must return a database handle, or NULL if the connection
has failed.
*****************************************************************************/
static int open_database(DB_DESC *desc, DB_DATABASE *db)